2014-03-27 07:55 AM
Hi,
I have been playing with ADC of stm32f4, i triggered ADC with TIM4_CC4 event to sample at 8Khz, using DMA. All individual components are working well but once combined i get alternate samples missing, i observe it using debugger. Data is correct as i am giving sinusoidal signal and data values seems to be correct but every alternate sample is simply 0. I am posting my code if anyone could guide, it would be great help.ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; /* RCC clock settings and GPIO settings for ADC3 channel 11 */ RCC_Configuration_ADC3(); GPIO_Configuration_ADC3(); TIM4_Configuration(); // set at 8KHz /* NVIC interrupt enable for DMA2 Stream0 */ ADC3_DMA2_Stream0_Interrupt_Enable(); /* RCC clock settings for DMA2 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); /* DMA2 Stream0 channel2 configuration **************************************/ DMA_InitStructure.DMA_Channel = DMA_Channel_2; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCRxBuffer1; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 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_Init(DMA2_Stream0, &DMA_InitStructure); /* Enable Double Buffer Mode */ DMA_DoubleBufferModeConfig(DMA2_Stream0,(uint32_t)&ADCRxBuffer2,DMA_Memory_0); /* Clear Transfer Complete flag bit for DMA2_Stream0 transfer Complete */ DMA_ClearITPendingBit(DMA2_Stream0,DMA_FLAG_TCIF0); DMA_DoubleBufferModeCmd(DMA2_Stream0,ENABLE); DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE); DMA_Cmd(DMA2_Stream0, ENABLE); /* ADC Common Init **********************************************************/ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); /* ADC3 Init ****************************************************************/ ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC3, &ADC_InitStructure); /* ADC3 regular channel11 configuration *************************************/ ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 1, ADC_SampleTime_3Cycles); /* Enable DMA request after last transfer (Single-ADC mode) */ ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); /* Enable ADC3 DMA */ ADC_DMACmd(ADC3, ENABLE); /* Enable ADC3 */ ADC_Cmd(ADC3, ENABLE); #stm32f4 #stm32 #discovery #selective-cut-n-paste #adc-and-dma2014-03-27 05:35 PM
It's incomplete so really hard to do much analysis. I don't think you've got the secondary memory buffer defined properly. Your description of the corruption isn't particularly clear, the way it's explained Sample[0], Sample[2] are good, Sample[1], Sample[3] are bad? Or does it mean the Ping buffer is good, and the Pong buffer is bad? Lacking any example data it's hard to tell.
The debugger does not stop DMA, it might stop a suitably configured timer. At 8 KHz a sample time of 3 would seem to be very short, and likely given pretty awful readings.2014-03-27 11:43 PM
Hi clive,
sample_buffer_ping[0] &[2] is correct, sample_buffer_ping[1] & [3] = 0 and so on...sample_buffer_pong[0] &[2] is correct, sample_buffer_pong[1] & [3] = 0 and so on...same behavior is observed for both the buffers... i used the same DMA double buffer configuration for duplex I2S interface and it was working good. have increased sample time still no success.As i am giving sinusoidal signal and correct data [0] & [2] seems to be making sinusoidal signal.Each buffer size is 1024, and it is taking 128ms for each buffer to fill completely which is correct for 8kHz sampling time. example data :buffer1 = {2722, 0, 2162, 0, 1535, 0, 1226, 0, 1453, 0, 2049, 0, 2647, 0, 2869, 0, 2576, 0, 1962, 0, 1400, 0, 1240, 0, 1610,.....}buffer 2 = {1242, 0, 1380, 0, 1933, 0, 2571, 0, 2865, 0, 2656, 0, 2049, 0, 1458, 0, 1231, 0, 1526, 0, 2125, 0, 2707, 0, 2868,.....}2014-03-27 11:44 PM
/*
HCLK = 168MHz TIM4_CLK = 84MHz*/Tim4_configuration(){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; /* TIM4 clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); /* TIM4 configuration ------------------------------------------------------*/ /* Time Base configuration */ TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = 10500; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); /* TIM4 channel4 configuration in PWM mode */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0x7F; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OC4Init(TIM4, &TIM_OCInitStructure); TIM_Cmd(TIM4,ENABLE);}2014-03-28 12:38 AM
Again completeness seems to allude us, please refer to the examples I post to understand what I'm asking for. It means the solution must be free standing, and compilable.
Based on the description, I'm going to guess you're not reading the right values via DMA, and whatever you've define ADC3_DR_ADDRESS is incorrect. Change :DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;
toDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC3->DR;
2014-03-28 02:17 AM
#define BUFFER_SIZE 1024
/* Double Buffer Memory */__IO uint16_t ADCRxBuffer1[BUFFER_SIZE]; /* Memory 0 */__IO uint16_t ADCRxBuffer2[BUFFER_SIZE]; /* Memory 1 */void DMA2_Stream0_IRQHandler()
{
if(DMA_GetFlagStatus(DMA2_Stream0,DMA_FLAG_TCIF0) == SET)
{
if(DMA_GetCurrentMemoryTarget(DMA2_Stream0) == 0)
{
/* Turn on-board LEDs ON */
}
else if(DMA_GetCurrentMemoryTarget(DMA2_Stream0) == 1)
{
/* Turn on-board LEDs OFF */
}
}
DMA_ClearITPendingBit(DMA2_Stream0,DMA_FLAG_TCIF0);
}
int main(void)
{ SystemInit(); ADC3_CH11_DMA_Configuration(); while(1) { }}void ADC3_CH11_DMA_Configuration(void){ ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; /* RCC clock settings and GPIO settings for ADC3 channel 11 */ RCC_Configuration_ADC3(); GPIO_Configuration_ADC3(); TIM4_Configuration(); /* NVIC interrupt enable for DMA2 Stream0 */ ADC3_DMA2_Stream0_Interrupt_Enable(); /* RCC clock settings for DMA2 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); /* DMA2 Stream0 channel2 configuration **************************************/ DMA_InitStructure.DMA_Channel = DMA_Channel_2; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC3->DR; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCRxBuffer1; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 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_Init(DMA2_Stream0, &DMA_InitStructure); /* Enable Double Buffer Mode */ DMA_DoubleBufferModeConfig(DMA2_Stream0,(uint32_t)&ADCRxBuffer2,DMA_Memory_0); /* Clear Transfer Complete flag bit for DMA2_Stream0 transfer Complete */ DMA_ClearITPendingBit(DMA2_Stream0,DMA_FLAG_TCIF0); DMA_DoubleBufferModeCmd(DMA2_Stream0,ENABLE); DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE); DMA_Cmd(DMA2_Stream0, ENABLE); /* ADC Common Init **********************************************************/ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); /* ADC3 Init ****************************************************************/ ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Falling; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC3, &ADC_InitStructure); /* ADC3 regular channel11 configuration *************************************/ ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 1, ADC_SampleTime_15Cycles); /* Enable DMA request after last transfer (Single-ADC mode) */ ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); /* Enable ADC3 DMA */ ADC_DMACmd(ADC3, ENABLE); /* Enable ADC3 */ ADC_Cmd(ADC3, ENABLE);}void ADC3_DMA2_Stream0_Interrupt_Enable(void){ NVIC_InitTypeDef NVIC_InitStructure; /* Enable the DMA2_Stream0 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);}void TIM4_Configuration(void)
{ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; /* TIM4 clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); /* TIM4 configuration ------------------------------------------------------*/ /* Time Base configuration */ TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = 10500; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); /* TIM4 channel4 configuration in PWM mode */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0xf; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC4Init(TIM4, &TIM_OCInitStructure); TIM_Cmd(TIM4,ENABLE);}void RCC_Configuration_ADC3(void){ //for ADC3 on PC1 using IN11 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);}void GPIO_Configuration_ADC3(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_StructInit(&GPIO_InitStructure); //for ADC3 on PC1 using IN10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOC, &GPIO_InitStructure);}2014-03-28 02:21 AM
Hi clive,
Thanks for your response, i have posted compilable version of complete code. kindly have a look.Change :
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;
to
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC3->DR;
also not solved the problem, ADC3_DR_ADDRESS = 0x4001224C which is the actual address of ADC3 data register.2014-03-28 09:14 AM
Seems to work fine for me, what are you debugging with? CooCox?
2014-03-29 04:31 AM
Thanks alot clive for your support, my problem is solved now. I was indeed debugging with coocox. Problem was a ridiculous mistake on my end. Now i am able to make ADC & DAC to work at 8kHz with double buffer DMA at both ends. Thanks again.
2015-07-13 02:58 AM
Hi Mr. Clive, I have just started to work on STM32F4 board and I am using COOCOX software, Is this a bad choice? I should work on ADC DMA and CAN peripherals, Where can i get best examples for DMA and CAN? Is it COOCOX or something else, Thank You Sir