AnsweredAssumed Answered

Fails in triggering ADC with TIM + DMA transfer (HAL lib)

Question asked by ernotte.thibaud on Mar 15, 2016
Latest reply on Mar 21, 2016 by ernotte.thibaud
Hi everyone,

I am currently working with a nucleo board f401re (featuring an stm32f401re micro).

From a conceptual point of view, my challenge is simple: I need to output a CLK signal as fast as possible (500kHz would be great), and on a every falling edge of CLK, I need to trigger the ADC on 1 Analog Input pin.
I need to do this for 40*42 = 1680 consecutive times (i.e. that corresponds to the number of periods of the CLK signal, or equivalently, to the number of samplings done by the adc)

So far, I managed to output CLK at 125kHz via an interrupt on timer TIM2. At the same time, I managed to have the ADC working with DMA, and able to reach 2.6MS/s. The problem is that the conversions are done "continuously", so as fast as possible according to the configuration, and thus not synchronized with the falling edges of CLK.
This configuration is represented by the code below.

So, my wish is now to synchronize the ADC sampling on the CLK falling edges. In order to do that, I was thinking of 2 solutions:
       
  1. Have the ADC triggered by TIM2, but still readout via DMA (I need it for     efficiency). I already attempted to do so, but as a matter of fact, the     ADC did not sample anything. This attempt corresponds to the code     below, with all comments applied in function ConfigureADC().
  2.    
  3. Output the CLK using PWM, connect this output pin to an input pin, and have the ADC triggered on the falling edges of this pin.
My questions are:
- Is this challenge achievable ?
- What is wrong with solution 1. (i.e with the modif. in comment applied)
- Which solution would be preferable, 1. or 2. ?

P.s: I already went through a lot of topics on this forum, unfortunately I cannot use the libraries that most of people use on the discovery boards, so I am "stuck" with the HAL drivers. I use the mbed online compiler.

Thanks a lot for your time !

BR,

Thibaud
001.#include "mbed.h"
002.#include "mbed_rpc.h"
003.#include <numeric>
004. 
005.#define SIZE_BUFF 40*42                // ADC nof samples
006.#define NOF_CLOCK_CYCLES 2*SIZE_BUFF
007. 
008.AnalogIn analog_pin4(PC_1);
009.DigitalOut CLK(PA_5);
010. 
011.uint32_t sample_buffer[SIZE_BUFF]; // adc sampling buffer
012.int clock_switch_counter = 0;       // counter on the nof clk switches
013. 
014.void RCC_Configuration(void){
015.    __HAL_RCC_DMA2_CLK_ENABLE();
016.    __HAL_RCC_GPIOC_CLK_ENABLE();
017.    __HAL_RCC_ADC1_CLK_ENABLE();
018.    __HAL_RCC_TIM2_CLK_ENABLE();
019.}
020. 
021.ADC_HandleTypeDef g_AdcHandle;
022.void ConfigureADC(){
023.    GPIO_InitTypeDef gpioInit;
024. 
025.    gpioInit.Pin = PC_1;
026.    gpioInit.Mode = GPIO_MODE_ANALOG;
027.    gpioInit.Pull = GPIO_NOPULL;
028.    HAL_GPIO_Init(GPIOC, &gpioInit);
029.  
030.    HAL_NVIC_SetPriority(ADC_IRQn, 0, 1);
031.    HAL_NVIC_EnableIRQ(ADC_IRQn);
032.  
033.    ADC_ChannelConfTypeDef adcChannel;
034.  
035.    g_AdcHandle.Instance = ADC1;
036.  
037.    g_AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
038.    g_AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
039.    g_AdcHandle.Init.ScanConvMode = DISABLE;
040.    g_AdcHandle.Init.ContinuousConvMode = ENABLE; // DISABLE
041.    g_AdcHandle.Init.DiscontinuousConvMode = DISABLE;
042.    g_AdcHandle.Init.NbrOfDiscConversion = 0;
043.    g_AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_FALLING;
044.    g_AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START;//ADC_EXTERNALTRIGCONV_T2_TRGO;
045.    g_AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
046.    g_AdcHandle.Init.NbrOfConversion = 1;
047.    g_AdcHandle.Init.DMAContinuousRequests = ENABLE;//DISABLE;
048.    g_AdcHandle.Init.EOCSelection = DISABLE;
049.  
050.    HAL_ADC_Init(&g_AdcHandle);
051. 
052.    adcChannel.Channel = ADC_CHANNEL_11;
053.    adcChannel.Rank = 1;
054.    adcChannel.SamplingTime = ADC_SAMPLETIME_3CYCLES;
055.    adcChannel.Offset = 0;
056.  
057.    if (HAL_ADC_ConfigChannel(&g_AdcHandle, &adcChannel) != HAL_OK)
058.    {
059.        asm("bkpt 255");
060.    }
061.}
062. 
063.DMA_HandleTypeDef  g_DmaHandle;
064.void ConfigureDMA(){
065.    __DMA2_CLK_ENABLE();
066.     
067.    g_DmaHandle.Instance = DMA2_Stream4;
068.    g_DmaHandle.Init.Channel  = DMA_CHANNEL_0;
069.    g_DmaHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
070.    g_DmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;
071.    g_DmaHandle.Init.MemInc = DMA_MINC_ENABLE;
072.    g_DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
073.    g_DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
074.    g_DmaHandle.Init.Mode = DMA_NORMAL;
075.    g_DmaHandle.Init.Priority = DMA_PRIORITY_HIGH;
076.    g_DmaHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;        
077.    g_DmaHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
078.    g_DmaHandle.Init.MemBurst = DMA_MBURST_SINGLE;
079.    g_DmaHandle.Init.PeriphBurst = DMA_PBURST_SINGLE;
080.     
081.    HAL_DMA_Init(&g_DmaHandle);
082.     
083.    __HAL_LINKDMA(&g_AdcHandle, DMA_Handle, g_DmaHandle);
084.  
085.    HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 0, 2);  
086.    HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);
087.}
088. 
089. 
090.TIM_HandleTypeDef htim2;
091.void TIM2_Configuration(void){
092.    TIM_Base_InitTypeDef TIM_TimeBaseStructure;
093.  
094.    // Time base configuration
095.    TIM_TimeBaseStructure.Prescaler = 0;
096.    TIM_TimeBaseStructure.Period = (84000000 / 42000000) - 1;
097.    TIM_TimeBaseStructure.ClockDivision = TIM_CLOCKDIVISION_DIV1;
098.    TIM_TimeBaseStructure.CounterMode = TIM_COUNTERMODE_UP;
099.   
100.    htim2.Instance = TIM2;
101.    htim2.Init = TIM_TimeBaseStructure;
102.    HAL_TIM_Base_MspInit(&htim2);
103.     
104.    __TIM2_CLK_ENABLE();
105.    HAL_TIM_Base_Init(&htim2);
106.     
107.    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
108.    HAL_TIM_Base_Start_IT(&htim2);
109.}
110. 
111.extern "C"
112.{
113.    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
114.        if (clock_switch_counter++ < NOF_CLOCK_CYCLES){
115.            if (CLK == 0)
116.                CLK = 1;
117.            else
118.                CLK = 0;
119.        }
120.        else{
121.            HAL_NVIC_DisableIRQ(TIM2_IRQn);
122.        }
123.    }
124.     
125.    void TIM2_IRQHandler(void){
126.        HAL_TIM_IRQHandler(&htim2); 
127.    }
128.     
129.    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle){
130.        HAL_ADC_Stop_DMA(&g_AdcHandle);
131.    }
132.     
133.    void DMA2_Stream4_IRQHandler(){
134.        HAL_DMA_IRQHandler(&g_DmaHandle);
135.    }       
136. 
137.    void ADC_IRQHandler(){
138.        HAL_ADC_IRQHandler(&g_AdcHandle);
139.    }
140.}
141. 
142. 
143.int main(void)
144.{   
145.    RCC_Configuration();
146.    ConfigureADC();
147.    ConfigureDMA();
148.    TIM2_Configuration();
149.     
150.    // initialize  output clock
151.    CLK = 0;
152. 
153.    HAL_ADC_Start_DMA(&g_AdcHandle, sample_buffer, SIZE_BUFF); // start ADC configured on DMA
154.    HAL_NVIC_EnableIRQ(TIM2_IRQn);                             // start Timer
155.     
156.    while(1) {}
157.}



Outcomes