AnsweredAssumed Answered

STM32F407 ADC DMA TIM interrupts

Question asked by PeterK on May 31, 2014
Latest reply on Jun 2, 2014 by Clive One
Hi, I need your advise
I read pixels from line scan camera and send it to PC using STM32F4 discovery board. It could be done in many different ways. I describe my solution and I'd like to know if there is a better way to program it.
I use ADC and DMA to store pixel value in the memory. ADC conversion is triggered using TIM3. DMA transfers data to memory after conversion. Then, I send data to PC on DMA request after last transfer - pixel by pixel.
Camera needs proper timing to work. I configured three timers, TIM2 TIM3 TIM5, to get necessary clocks. TIM2 in main camera clock and acts as a master timer for synchronisation of the other two timers. TIM3 data clock - pixel value is read after rising edge. TIM5 is a frame clock - next line sign is sent after rising edge.

I don't know why, but I get only half of the pixels (camera has 1024 pixels). It seems that DMA transfers every second pixel. ADC conversion is triggered using TIM3. Iv'e checked timings and there is 1024 cycles in every frame, so it looks fine. DMA FIFO/direct mode configuration influences on data transfer. FIFO with 1 quarter threshold gives 512 pixels - the best what I've obtained when tried other thresholds and direct mode. As I remember, 128 pixels for full FIFO threshold. There are some synchronisation problems in direct mode. I've left it, because I don't know what happens there. Next line character is sent in TIM5 interrupt. Do you have any ideas where are missing pixels?

There is few options to control flow of data:
- transfer pixel by pixel after DMA interrupt and new line character in TIM5 interrupt,
- transfer pixel by pixel after TIM3 interrupt and new line character in TIM5 interrupt,
- stream DMA directly into USART and transfer new line character in TIM5 interrupt,
- transfer one line in DMA interrupt (need a buffer for 1024 values),
- read pixel value without DMA, in TIM3 interrupt

I didn't try every approach. Currently, I use the first one. I've tried the last one, but I've got problem with TIM3 interrupt. It seems to stop when I enable it (lines 89-93 and 197). I don't see problems with configuration. Camera takes 50 lines per second (prefereably I would , 50*1024=51200 bytes (409600 bits) have to be transferred. I use printf function so there is more bytes to send every second. Do you think this problem with interrupt is connected with transfer speed? I pasted important part of the code below. I will paste full code if necessary.


001.static void ADC_Config(void)
002.{
003.  ADC_InitTypeDef       ADC_InitStructure;
004.  ADC_CommonInitTypeDef ADC_CommonInitStructure;
005.  DMA_InitTypeDef       DMA_InitStructure;
006.  GPIO_InitTypeDef      GPIO_InitStructure;
007. 
008.  /* Enable ADC3, DMA and GPIO clocks ****************************************/
009.  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
010.  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
011.  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
012. 
013.  /* DMA2 Stream0 channel2 configuration **************************************/
014.  DMA_InitStructure.DMA_Channel = DMA_Channel_2;
015.  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(ADC3_BASE+0x004C);
016.  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&lineBuffer;
017.  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
018.  DMA_InitStructure.DMA_BufferSize = (uint8_t)sizeof(lineBuffer);
019.  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
020.  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
021.  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
022.  DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
023.  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
024.  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
025.  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
026.  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
027.  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
028.  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
029.  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
030. 
031.  /* Enable DMA Stream Half / Transfer Complete interrupt */
032.  DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
033. 
034.  /* Configure ADC3 Channel1 pin as analog input ******************************/
035.  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
036.  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
037.  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
038.  GPIO_Init(GPIOC, &GPIO_InitStructure);
039. 
040.  /* ADC Common Init **********************************************************/
041.  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
042.  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
043.  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
044.  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
045.  ADC_CommonInit(&ADC_CommonInitStructure);
046. 
047.  /* ADC3 Init ****************************************************************/
048.  ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
049.  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
050.  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
051.  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
052.  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;
053.  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
054.  ADC_InitStructure.ADC_NbrOfConversion = 1;
055.  ADC_Init(ADC3, &ADC_InitStructure);
056. 
057.  /* ADC3 regular channel1 configuration *************************************/
058.  ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 1, ADC_SampleTime_84Cycles);
059. 
060. /* Enable DMA request after last transfer (Single-ADC mode) */
061.  ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
062. 
063.  /* Enable ADC3 DMA */
064.  ADC_DMACmd(ADC3, ENABLE);
065. 
066.  /* Enable ADC3 */
067.  ADC_Cmd(ADC3, ENABLE);
068.}
069. 
070.void NVIC_Configuration(void)
071.{
072.  NVIC_InitTypeDef NVIC_InitStructure;
073. 
074.  /* Enable the DMA Stream IRQ Channel */
075.  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
076.  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
077.  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
078.  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
079.  NVIC_Init(&NVIC_InitStructure);
080. 
081.  /* Enable the TIM5 global Interrupt */
082.  NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
083.  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
084.  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
085.  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
086.  NVIC_Init(&NVIC_InitStructure);
087. 
088.//  /* Enable the TIM3 global Interrupt */
089.//  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
090.//  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
091.//  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
092.//  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
093.//  NVIC_Init(&NVIC_InitStructure);
094.}
095. 
096.void TIM5_IRQHandler(void)
097.{
098.    printf("\n");
099.    TIM_ClearITPendingBit(TIM5, TIM_IT_CC2);
100.}
101. 
102.void TIM3_IRQHandler(void)
103.{
104.    printf("%d",val);
105.    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
106.}
107. 
108.void DMA2_Stream0_IRQHandler(void)
109.{
110.    /* Clear DMA Stream Transfer Complete interrupt pending bit */
111.    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
112.    for ( txCount = 0; txCount < LINEWIDTH; txCount++)
113.    {
114.        printf("%d ",lineBuffer[txCount]);
115.    }
116.}
117. 
118.void TIM_Config(void)
119.{
120.  GPIO_InitTypeDef GPIO_InitStructure;
121. 
122.  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3 | RCC_APB1Periph_TIM5, ENABLE);
123.  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);
124. 
125.  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_6 | GPIO_Pin_7;
126.  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
127.  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
128.  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
129.  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
130.  GPIO_Init(GPIOA, &GPIO_InitStructure);
131. 
132.  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_9;
133.  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
134.  GPIO_Init(GPIOA, &GPIO_InitStructure);
135. 
136.  GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM2);
137.  GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM5);
138.  GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_TIM3);
139.  GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_TIM3);
140.//==========================================================================
141.  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
142.  TIM_OCInitTypeDef  TIM_OCInitStructure;
143. 
144.  TIM_TimeBaseStructure.TIM_Period = 399;
145.  TIM_TimeBaseStructure.TIM_Prescaler = 0;
146.  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
147.  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
148.  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
149. 
150.  TIM_TimeBaseStructure.TIM_Period = 4*MULTIPLIER-1;
151.  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
152. 
153.  TIM_TimeBaseStructure.TIM_Period = 4*2048*MULTIPLIER-1; //Update 1024 resolution
154.  TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
155. 
156. 
157.   /* Master Configuration in PWM1 Mode */
158.  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
159.  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
160.  TIM_OCInitStructure.TIM_Pulse = 200;
161.  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
162.  TIM_OC1Init(TIM2, &TIM_OCInitStructure);
163. 
164.  /* Select the Master Slave Mode */
165.  TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);
166.  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
167. 
168.  /* Slaves Configuration: PWM1 Mode */
169.  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
170.  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
171.  TIM_OCInitStructure.TIM_Pulse = 4*MULTIPLIER;
172.  TIM_OC2Init(TIM5, &TIM_OCInitStructure);
173. 
174.  /* Slave Mode selection: TIM5 */
175.  TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Gated);
176.  TIM_SelectInputTrigger(TIM5, TIM_TS_ITR0);
177. 
178.  /* Slaves Configuration: PWM1 Mode */
179.  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
180.  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
181.  TIM_OCInitStructure.TIM_Pulse = 1;
182.  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
183.  TIM_OC1Init(TIM3, &TIM_OCInitStructure);
184. 
185.  TIM_OCInitStructure.TIM_Pulse = 1;
186.  TIM_OC2Init(TIM3, &TIM_OCInitStructure);
187. 
188.  /* Slave Mode selection: TIM3 */
189.  TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Gated);
190.  TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1);
191.  TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_OC1);
192. 
193.  /* TIM Interrupts enable */
194.   TIM_ITConfig(TIM5, TIM_IT_CC2, ENABLE);
195. 
196.   /* TIM Interrupts enable */
197.//   TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
198. 
199.  /* TIM enable counter */
200.  TIM_Cmd(TIM2, ENABLE);
201.  TIM_Cmd(TIM3, ENABLE);
202.  TIM_Cmd(TIM5, ENABLE);
203.}

Thank you for any help and ideas

Outcomes