cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with ADC in Nucleo-C31C06 with Low Level drivers

rnicolas
Associate II

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 1
Saket_Om
ST Employee

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.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om