1

I'm trying to get ADC with DMA working on my STM32F411RE nucleo board. the signal is connected to the PC0 pin (ADC channel 10, DMA2), but whenever I check, the uhADC1ConvertedValue is 0. Am I missing something? Is my config wrong?

__IO uint32_t uhADC1ConvertedValue;

unsigned int getADCVal(){
    return uhADC1ConvertedValue;
}


void ADC2_Init(){
    ADC_InitTypeDef       ADC_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    DMA_InitTypeDef       DMA_InitStructure;
    GPIO_InitTypeDef      GPIO_InitStructure;

    uhADC1ConvertedValue = 1;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&uhADC1ConvertedValue;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = 1;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    DMA_Cmd(DMA2_Stream0, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    ADC_CommonInit(&ADC_CommonInitStructure);

    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);

    ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

    ADC_DMACmd(ADC1, ENABLE);

    ADC_Cmd(ADC1, ENABLE);

    ADC_EOCOnEachRegularChannelCmd(ADC1, ENABLE);


}


int main(void)
{
    int rev = 0;

    uC_Init();


    rev = getADCVal(); //enc28j60getrev();

    simple_server();

    return rev;
}
2
  • 1) If you read an uint32_t you should return an uint32_t. Then you assign the unsigned result to a signed int. Do not change signed-ness unless you have good reason. If you have, change it at the lowest possible abstraction level once. 2) Why do you qualify a normal variable __IO? If you mean volatile, use it! 3) Do not use that bloatware STlib. It is no way standard, but just obfuscates and slows down your code. Commented Jan 10, 2016 at 15:45
  • Hi - i fixed what you suggested, but sadly to no avail - still no reading. At the moment I have to use the STPlib. Commented Jan 10, 2016 at 20:18

1 Answer 1

2

I can't really tell what was wrong with my previous code (probably the part where i didn't start the timer that would start the ADC), but here is a working one (this code keeps ADC doing conversions continously (well, started by a timer) and loads the measured value into a variable):

volatile uint32_t uhADC1ConvertedValue;

uint32_t getADCVal(){
    return uhADC1ConvertedValue;
}
void adc_init(void)
{
    GPIO_InitTypeDef      GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;

    //konfiguracja ADC
    ADC1->CR2 = ADC_CR2_ADON |                          //włącz ADC
                ADC_CR2_EXTEN_0 |                       //wyzwalanie przetwornika zboczem opadającym i narastającym
                ADC_CR2_EXTSEL_3 | ADC_CR2_EXTSEL_0 |   //wyzwalanie przetwornika kanałem 4 timera 4
                ADC_CR2_DDS |                           //kontynuuj przesył DMA po ostatnim przesyle (konieczne dla circular mode)
                ADC_CR2_DMA;                            //włącz DMA dla ADC

    //włączenie skanowania i przerwania dla zakonczonej konwersji
    ADC1->CR1 = ADC_CR1_SCAN; //| ADC_CR1_EOCIE;

    //Ustawienie czasu konwersji na 3 + 12 cykli zegara ADC, zegar ADC == 42MHz częstotliwosć próbkowania ~1Ms
    ADC1->SMPR1 = 0;//ADC_SMPR1_SMP11_1 | ADC_SMPR1_SMP12_1;

    //Ustawienie ilosci kanałów do skanowania
    ADC1->SQR1 = (1)<<20;

    //Ustawienie kanałów 11 i 12 do skanowania
    ADC1->SQR3 = 10<<5;

    //Konfiguracja DMA dla przetwornika ADC1
    DMA2_Stream0->NDTR = 1;                 //ilosc bajtów do przesłania
    DMA2_Stream0->PAR = (uint32_t)&ADC1->DR;
    DMA2_Stream0->M0AR = (uint32_t)&uhADC1ConvertedValue;

    DMA2_Stream0->CR =  DMA_SxCR_PL_1 |     //priority high
                        DMA_SxCR_MSIZE_0 |  //memory size 16bit
                        DMA_SxCR_PSIZE_0 |  //pheriperial size 16bit
                        DMA_SxCR_MINC |     //inkrementuj wskaźnik po stronie pamięci
                        DMA_SxCR_CIRC |     //zapętlenie bufora pamięci
                        DMA_SxCR_EN;        //włączenie kontrolera DMA

    //konfiguracja timera dla przetwornika
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
    TIM4->CR1 = 0;                          //resetowanie rejestru konfiguracji
    TIM4->PSC = 0;                          //prescaller na 0
    TIM4->ARR = 167;                        //reload register na 83
    TIM4->CCR4 = 167;                       //rejesrt compare dla wyzwalania przetwornika
    TIM4->CCMR2 |= TIM_CCMR2_OC4M_0 | TIM_CCMR2_OC4M_1; //przełączanie wyjcia przy compare
    TIM4->CCER |= TIM_CCER_CC4E;            //włączenie wyjcia 4

    //konfiguracja NVIC
    NVIC_EnableIRQ(ADC_IRQn);               //przerwanie od zakonczenia konwersji ADC

    //uruchom przetwornik
    ADC1->CR2 |= ADC_CR2_ADON;

    //uruchom timer
    TIM4->CR1 = TIM_CR1_CEN;


}



int main(void)
{
    uint32_t rev;
    int bb= 0;
    uC_Init();
    //ADC2_Init();
    adc_init();
    rev = uhADC1ConvertedValue;
    rev = uhADC1ConvertedValue;
    rev = uhADC1ConvertedValue;
    for (bb=0; bb< 100000; bb++) // tu dociera i sie wywala
        {;;}

    rev = uhADC1ConvertedValue;
    rev = uhADC1ConvertedValue;
    rev = uhADC1ConvertedValue;
    rev = uhADC1ConvertedValue;

//  rev = 20;

    /**/
    simple_server(); //petla nieskonczona

    return rev;
}
Sign up to request clarification or add additional context in comments.

1 Comment

I found this post while having DMA config issues. Perhaps your DMA clock is not enabled? My issue turned out to be a bug in CubeMX community.st.com/s/question/0D50X0000Bmob3uSQA/…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.