2016-03-15 03:41 AM
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:
#include ''mbed.h''
#include ''mbed_rpc.h''
#include <numeric>
#define SIZE_BUFF 40*42 // ADC nof samples
#define NOF_CLOCK_CYCLES 2*SIZE_BUFF
AnalogIn analog_pin4(PC_1);
DigitalOut CLK(PA_5);
uint32_t sample_buffer[SIZE_BUFF];
// adc sampling buffer
int
clock_switch_counter = 0;
// counter on the nof clk switches
void
RCC_Configuration(
void
){
__HAL_RCC_DMA2_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_TIM2_CLK_ENABLE();
}
ADC_HandleTypeDef g_AdcHandle;
void
ConfigureADC(){
GPIO_InitTypeDef gpioInit;
gpioInit.Pin = PC_1;
gpioInit.Mode = GPIO_MODE_ANALOG;
gpioInit.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &gpioInit);
HAL_NVIC_SetPriority(ADC_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(ADC_IRQn);
ADC_ChannelConfTypeDef adcChannel;
g_AdcHandle.Instance = ADC1;
g_AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
g_AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
g_AdcHandle.Init.ScanConvMode = DISABLE;
g_AdcHandle.Init.ContinuousConvMode = ENABLE;
// DISABLE
g_AdcHandle.Init.DiscontinuousConvMode = DISABLE;
g_AdcHandle.Init.NbrOfDiscConversion = 0;
g_AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_FALLING;
g_AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START;
//ADC_EXTERNALTRIGCONV_T2_TRGO;
g_AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
g_AdcHandle.Init.NbrOfConversion = 1;
g_AdcHandle.Init.DMAContinuousRequests = ENABLE;
//DISABLE;
g_AdcHandle.Init.EOCSelection = DISABLE;
HAL_ADC_Init(&g_AdcHandle);
adcChannel.Channel = ADC_CHANNEL_11;
adcChannel.Rank = 1;
adcChannel.SamplingTime = ADC_SAMPLETIME_3CYCLES;
adcChannel.Offset = 0;
if
(HAL_ADC_ConfigChannel(&g_AdcHandle, &adcChannel) != HAL_OK)
{
asm(
''bkpt 255''
);
}
}
DMA_HandleTypeDef g_DmaHandle;
void
ConfigureDMA(){
__DMA2_CLK_ENABLE();
g_DmaHandle.Instance = DMA2_Stream4;
g_DmaHandle.Init.Channel = DMA_CHANNEL_0;
g_DmaHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
g_DmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;
g_DmaHandle.Init.MemInc = DMA_MINC_ENABLE;
g_DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
g_DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
g_DmaHandle.Init.Mode = DMA_NORMAL;
g_DmaHandle.Init.Priority = DMA_PRIORITY_HIGH;
g_DmaHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
g_DmaHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
g_DmaHandle.Init.MemBurst = DMA_MBURST_SINGLE;
g_DmaHandle.Init.PeriphBurst = DMA_PBURST_SINGLE;
HAL_DMA_Init(&g_DmaHandle);
__HAL_LINKDMA(&g_AdcHandle, DMA_Handle, g_DmaHandle);
HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 0, 2);
HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);
}
TIM_HandleTypeDef htim2;
void
TIM2_Configuration(
void
){
TIM_Base_InitTypeDef TIM_TimeBaseStructure;
// Time base configuration
TIM_TimeBaseStructure.Prescaler = 0;
TIM_TimeBaseStructure.Period = (84000000 / 42000000) - 1;
TIM_TimeBaseStructure.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TIM_TimeBaseStructure.CounterMode = TIM_COUNTERMODE_UP;
htim2.Instance = TIM2;
htim2.Init = TIM_TimeBaseStructure;
HAL_TIM_Base_MspInit(&htim2);
__TIM2_CLK_ENABLE();
HAL_TIM_Base_Init(&htim2);
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_TIM_Base_Start_IT(&htim2);
}
extern
''C''
{
void
HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if
(clock_switch_counter++ < NOF_CLOCK_CYCLES){
if
(CLK == 0)
CLK = 1;
else
CLK = 0;
}
else
{
HAL_NVIC_DisableIRQ(TIM2_IRQn);
}
}
void
TIM2_IRQHandler(
void
){
HAL_TIM_IRQHandler(&htim2);
}
void
HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle){
HAL_ADC_Stop_DMA(&g_AdcHandle);
}
void
DMA2_Stream4_IRQHandler(){
HAL_DMA_IRQHandler(&g_DmaHandle);
}
void
ADC_IRQHandler(){
HAL_ADC_IRQHandler(&g_AdcHandle);
}
}
int
main(
void
)
{
RCC_Configuration();
ConfigureADC();
ConfigureDMA();
TIM2_Configuration();
// initialize output clock
CLK = 0;
HAL_ADC_Start_DMA(&g_AdcHandle, sample_buffer, SIZE_BUFF);
// start ADC configured on DMA
HAL_NVIC_EnableIRQ(TIM2_IRQn);
// start Timer
while
(1) {}
}
#adc-dma-tim-hal
2016-03-15 08:05 AM
No need to use interrupts here. Have the ADC be triggered off of the TIM directly, by using the TRGO signal.
Set the TIM period to whatever you want.Set the ADC to be triggered off of that, using DMA.2016-03-16 06:38 AM
Hi,
Thanks for your answer. However, although I think I understand what you mean from a conceptual point of view, I have a hard time translating that into code. May I kindly ask for your help about translating what you said into code instructions ? Thanks!2016-03-21 02:30 AM
Does anyone have a suggestion ?
It would be very much appreciated.