Skip to main content
Associate II
November 15, 2024
Question

Problem with ADC in Nucleo-C31C06 with Low Level drivers

  • November 15, 2024
  • 1 reply
  • 565 views

I'm trying to write three functions: to start an ADC conversion, wait for it to complete, and retrieve the results based on the low-level drivers from ST. The issue I'm facing is that I can read the first channel (LL_ADC_CHANNEL_0) with the correct value (I've verified this by debugging - the value is 4020 when the channel is connected to VDD, and 0 when connected to GND). However, when I connect the same channel to PA1, I get nothing (it's like the pin is floating), and when I connect it to PA2, I see the data in LL_ADC_CHANNEL_1 instead.

Additionally, I see the EOS (End of Sequence) interrupt triggered after 1-3 conversions, so it's not performing all the conversions that it should. As a result, my code gets stuck checking the conversion complete flag, as it's never able to finish reading all 6 channels. I'm not sure why this is happening, any idea or help will be more than welcome.

 

 

#include "stm32c0xx_ll_adc.h"
#include "stm32c0xx_ll_gpio.h"
#include "stm32c0xx_ll_bus.h"
#include "stm32c0xx_ll_utils.h"

#define MAX_ADC_CHANNELS 6

static volatile uint16_t adcBuffer[MAX_ADC_CHANNELS];
static volatile uint16_t adcIndex = 0;
static volatile uint8_t adcConversionComplete = 0;

void SDK_ADC_InitInterruptMode(void) {
 // Enable ADC clock
 LL_APB1_GRP2_EnableClock(LL_APB2_GRP1_PERIPH_ADC);

 // ADC configuration
 LL_ADC_SetResolution(ADC1, LL_ADC_RESOLUTION_12B);
 LL_ADC_SetDataAlignment(ADC1, LL_ADC_DATA_ALIGN_RIGHT);

 LL_ADC_REG_SetSequencerConfigurable(ADC1, LL_ADC_REG_SEQ_CONFIGURABLE);
 LL_ADC_REG_SetSequencerLength(ADC1, LL_ADC_REG_SEQ_SCAN_ENABLE_6RANKS);

 LL_ADC_REG_SetContinuousMode(ADC1, LL_ADC_REG_CONV_SINGLE);

 LL_ADC_REG_SetDMATransfer(ADC1, LL_ADC_REG_DMA_TRANSFER_NONE);

 // Enable EOC and EOS interrupts
 LL_ADC_EnableIT_EOC(ADC1);
 LL_ADC_EnableIT_EOS(ADC1);
 NVIC_EnableIRQ(ADC1_IRQn);
 NVIC_SetPriority(ADC1_IRQn, 3);

 // Calibration and enabling
 if (LL_ADC_IsEnabled(ADC1)) {
 LL_ADC_Disable(ADC1);
 while (LL_ADC_IsEnabled(ADC1));
 }

 LL_ADC_EnableInternalRegulator(ADC1);
 LL_mDelay(10);

 LL_ADC_StartCalibration(ADC1);
 while (LL_ADC_IsCalibrationOnGoing(ADC1));

 LL_ADC_Enable(ADC1);
 while (!LL_ADC_IsActiveFlag_ADRDY(ADC1));
}

void SDK_ADC_StartConversion(void) {
 adcIndex = 0;
 adcConversionComplete = 0;

 // Configure the ADC channels
 LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_0);
 LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_0, LL_ADC_SAMPLINGTIME_COMMON_1);

 LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_1);
 LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_1, LL_ADC_SAMPLINGTIME_COMMON_1);

 LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_3, LL_ADC_CHANNEL_2);
 LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SAMPLINGTIME_COMMON_1);

 LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_4, LL_ADC_CHANNEL_4);
 LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_4, LL_ADC_SAMPLINGTIME_COMMON_1);

 LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_5, LL_ADC_CHANNEL_VREFINT);
 LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_VREFINT, LL_ADC_SAMPLINGTIME_COMMON_2);

 LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_6, LL_ADC_CHANNEL_TEMPSENSOR);
 LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_COMMON_1);

 LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_79CYCLES_5);
 LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_2, LL_ADC_SAMPLINGTIME_160CYCLES_5);

 // Start the conversion
 LL_ADC_REG_StartConversion(ADC1);
}

uint8_t SDK_ADC_IsConversionComplete(void) {
 return adcConversionComplete;
}

void SDK_ADC_GetConversionResults(uint16_t *buffer, uint16_t size) {
 for (uint16_t i = 0; i < size; i++) {
 buffer[i] = adcBuffer[i];
 }
}

void ADC1_IRQHandler(void) {
 if (LL_ADC_IsActiveFlag_EOC(ADC1)) {
 // Read the converted data for the current channel
 adcBuffer[adcIndex++] = LL_ADC_REG_ReadConversionData12(ADC1);

 // Clear the EOC flag (End of Conversion)
 LL_ADC_ClearFlag_EOC(ADC1);

 // Check if all channels are converted
 if (adcIndex >= MAX_ADC_CHANNELS) {
 adcConversionComplete = 1;
 adcIndex = 0; // Reset index for the next conversion sequence
 }
 }

 if (LL_ADC_IsActiveFlag_EOS(ADC1)) {
 // Clear the EOS flag (End of Sequence)
 LL_ADC_ClearFlag_EOS(ADC1);
 }
}

 

 

 

1 reply

Technical Moderator
November 18, 2024

Hello @rnicolas

Please ensure that the GPIO pins for the ADC channels are correctly configured as analog inputs. You can refer to the LL ADC examples in STM32CubeC0 as a starting point for your project.

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om