0

The goal is to read multiple ADC channels by polling. It does not need to be fast - the idea is to read the voltages from different batteries that are attached. I have a STM32L071 microcontroller. The programming is a bit different compared to the STM32F0 model. I am using platformio.

I found already very helpful information here:

However, unfortunately I cannot read out multiple channels. The problems are probably related to HAL_ADC_Init and HAL_ADC_ConfigChannel.

Here is a minimal code example:

#include <Arduino.h>
#include <STM32IntRef.h>

uint32_t a1=0, a2=0;

#define HAL_ADC_MODULE_ENABLED
ADC_HandleTypeDef hadc1;

void displaying(){
    Serial.println("values:");
    Serial.println("-------");
    Serial.print("ch1 - ");
    Serial.println(a1);
    Serial.print("ch2 - ");
    Serial.println(a2);
    Serial.println("");
}

void config_ext_channel_ADC(uint32_t channel, bool val) {
  hadc1.Instance = ADC1;
  hadc1.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;
  HAL_ADC_Init(&hadc1);
  
  ADC_ChannelConfTypeDef sConfig;
  sConfig.Channel = channel;
  if (val == true)  {
    sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  } else {
    sConfig.Rank = ADC_RANK_NONE;
  }
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
        Serial.println("Error ADC Config Channel");
        //Error_Handler();
  }
}

uint32_t r_single_ext_channel_ADC(uint32_t channel) {
  /* read the ADC and output result */
  uint32_t digital_result;
  config_ext_channel_ADC(channel, true);
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
  HAL_ADC_Start(&hadc1);
  HAL_ADC_PollForConversion(&hadc1, 1000);
  digital_result = HAL_ADC_GetValue(&hadc1);
  HAL_ADC_Stop(&hadc1);
  config_ext_channel_ADC(channel, false);
  return digital_result;
}

void readBat() {
  /* read voltages */
  a1 = r_single_ext_channel_ADC(1);
  a2 = r_single_ext_channel_ADC(PA2);
}

void setup() {
  // put your setup code here, to run once:
  // Serial monitor
  Serial.begin(9600);
  Serial.println(F("Starting now"));
  // initialize pins for ADC
  analogReadResolution(ADC_RESOLUTION);
  pinMode(PA1, INPUT);
  //pinMode(BATTERY_SENSE_PIN2, INPUT);
  pinMode(PA2, INPUT_ANALOG);
}

void loop() {
  // put your main code here, to run repeatedly:
  readBat();
  displaying();
  delay(2000);
}

The output is:

values:
-------
ch1 - 0
ch2 - 140

Sounds reasonable, but applying some voltages at the pins does not change the values.

Could somebody please provide me some advice, ideas?

dda
  • 6,030
  • 2
  • 25
  • 34
pallago
  • 419
  • 1
  • 4
  • 12

3 Answers3

1

Code to read different ADC channels (here ADC2 with 2 channels) separetly (Generated By CubeMX):

Note: We have to use ScanConvMode plus DiscontinuousConvMode and NO ContinuousConvMode.


/* ADC2 init function */
void MX_ADC2_Init(void)
{

  /* USER CODE BEGIN ADC2_Init 0 */

  /* USER CODE END ADC2_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC2_Init 1 */

  /* USER CODE END ADC2_Init 1 */
  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.ScanConvMode = ENABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.DiscontinuousConvMode = ENABLE;
  hadc2.Init.NbrOfDiscConversion = 1;
  hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.NbrOfConversion = 2;
  hadc2.Init.DMAContinuousRequests = DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_8;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_9;
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC2_Init 2 */

  /* USER CODE END ADC2_Init 2 */

}

Now, to read:


void readChannel(){
    //read the next channel
    HAL_ADC_Start(&hadc2);
    uint8_t ret = HAL_ADC_PollForConversion(&hadc2, 1000 /*timeout*/);
    uint16_t value = HAL_ADC_GetValue(hadc);
    printf("HAL_ADC_PollForConversion status: %d, VALLLL: %d\n", ret, value);
}


int main(){
    while(1){
        //Automatically read the first channel (channel 8):
        readChannel();
        HAL_Delay(100);
        
        //Automatically read the second channel (channel 9):
        readChannel();
        HAL_Delay(100);
        
    }
}
Mohammad Kholghi
  • 533
  • 2
  • 7
  • 21
0

Did you miss to set the io to analog in mode? It should be something like this somewhere (usually in your hal msp file, adc_init func).

GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

edit => you missed it for ch1

analogReadResolution(ADC_RESOLUTION);
pinMode(PA1, INPUT);
//pinMode(BATTERY_SENSE_PIN2, INPUT);
pinMode(PA2, INPUT_ANALOG);

It should be the same as PA2, input is "digital mode".

dda
  • 6,030
  • 2
  • 25
  • 34
Michel Sanches
  • 428
  • 3
  • 9
  • Thanks. I put PA1 and PA2 to INPUT_ANALOG. In the meantime, I got it running, i.e. I can see different ADU values depening on the voltage. But the problem remains, that the neighboring ADU channel is affected. This means; if I apply 3.3V at PA1 (4095 ADU); I see around 1400 ADU at PA2. – pallago Mar 20 '22 at 20:13
0

Okay, in the meantime I found the problem. The software is fine; I took the Arduino framework and used analogRead().

I needed to clean all the solder flux from the PCB which caused some contacts between the pins. Moreover, if one wants to use address the HAL directly, one should set the ClockDivider such that the ADC samples below 1 MHz.

pallago
  • 419
  • 1
  • 4
  • 12