Search code examples
stm32adc

STM32L4 ADC not working (multiple channels no DMA)


I am trying to run a code I found some time ago here, that allows to choose an ADC channel from a few channels and to read it individually when necessary. No DMA involved. I use STM32L4R5. My idea is just to confirm proper ADC reading by switching status LEDs on and off if some level is available and it is not working at all so far (status led for is always ON). For input signal source I use a GPIO pin, set to high, that passes through a 1k resistor and a LED so the voltage is about 0.7V. I call __HAL_RCC_ADC_CLK_ENABLE(); and __HAL_RCC_GPIOC_CLK_ENABLE(); in the HAL_ADC_MspInit(). status_led() function is not shown but I use it a lot, no problem with it.

The rest of the code is as follows:

uint32_t pdlvl=0;

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_ADC1_Init();
    MX_TIM1_Init();

    // Test ADC reading voltage input
    //

    while(1){
        pdlvl=read_ADC_channel(ADC_CHANNEL_13);
        if(pdlvl<10){
            status_led(4,1);
            status_led(3,0);
        }
        if(pdlvl>10){
            status_led(3,1);
            status_led(4,0);
        }
    }

} // end of main
static void MX_ADC1_Init(void)
{

  ADC_ChannelConfTypeDef sConfig = {0};

  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_13;
  sConfig.Rank = ADC_RANK_NONE;
  sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_14;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

}

Pin initialization

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  __HAL_RCC_GPIOC_CLK_ENABLE();

  GPIO_InitStruct.Pin = ROUT1_Pin|ROUT2_Pin; // ADC_CHANNEL_13 and ADC_CHANNEL_14
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

}

Now the tricky part with pre-config of channels:


void config_ADC_channel(uint32_t channel, uint8_t val)
{
    ADC_ChannelConfTypeDef sConfig;

    sConfig.Channel = channel;
    sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
    sConfig.SingleDiff = ADC_SINGLE_ENDED;
    sConfig.OffsetNumber = ADC_OFFSET_NONE;

    if(val==1){
        sConfig.Rank = 1;
    }
    else{
        sConfig.Rank = ADC_RANK_NONE;
    }
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

and the reading function

uint32_t read_ADC_channel(uint32_t channel)
{
  uint32_t digital_result;

  config_ADC_channel(channel, 1);

//  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_ADC_channel(channel, 0);

  return digital_result;
}

Any ideas where I am wrong?

Thank you!


Solution

  • I found the problem. I did not set correctly the Periphery clock source (initially generated by CubeMX, and modified source by me later):

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
      PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
      PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
      PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
      PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSE;
      PeriphClkInit.PLLSAI1.PLLSAI1M = 6;
      PeriphClkInit.PLLSAI1.PLLSAI1N = 20;
      PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV2;
      PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
      PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
      PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK;