cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with ADC in Nucleo-C31C06 with Low Level drivers

rnicolas
Associate

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.

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar