2024-11-15 05:42 AM
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);
}
}
2024-11-18 12:59 AM
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.