STM32F4: ADC1 + EXTI11 binding problem
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2014-12-05 8:27 AM
Dear all,
I need to use the external trigger with ADC1 but I am not able to do it. I have done my code in step. I did make work my ADC1 with TIM2 as internal triggered. That worked well. Then I have I have generated a PWM on port PB7 with timer 4 , that worked well. I used the pin PC11 as input and use the PWM to trigger the interrupt routine correctly. Now , I need to use that trigger as input trigger for my ADC1 but I cannot can get it work properly. I must missed a configuration step to link the two together. I put my code below to see if you can pointed it out. Note that I am using also the DMA to acquire 2048 converted values. (that is working well with the internal timer trigger) Thanks in advance to all.void DoADCConversion (void)
{
//ADC Conversion
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
uint32_t PeriodCounter = (90000000 / 1500000); 1.5 MHz based on 90MHz
//Clock Enable
//Ouput IO for timing PA & PG
//Analog Input and DMA2
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB |
RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA2 |
RCC_AHB1Periph_GPIOG, ENABLE);
//ADC1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
//TIMER4
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
/* Configure PG6 in output pushpull mode */
/* Global Acquisition Time */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOG, &GPIO_InitStructure);
/* Conversion Time */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Configure ADC3 Channel13 pin as analog input
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//PC11 for external trigger
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource11);
//EXTI Configuration Line 11
EXTI_DeInit();
EXTI_StructInit(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = EXTI_Line11;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
//PWM
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_TIM4);
//Time base configuration
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = (PeriodCounter- 1);
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
// PWM1 Mode configuration: Timer 4 Channel 2
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = ((PeriodCounter / 2) - 1);
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM4, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);
// TIM2 enable counter
TIM_Cmd(TIM4, ENABLE);
// DMA2 Stream0 channel2 configuration
DMA_DeInit(DMA2_Stream0); //Reset DMA to default values
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCxConvertedValue[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 2140;
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_Normal;
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_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA2_Stream0, ENABLE);
//ADC Common Init
ADC_CommunStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommunStructure.ADC_Mode = ADC_Mode_Independent;
//DMA Mode for multi ADC
ADC_CommunStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
//Delay in between two sampling
ADC_CommunStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommunStructure);
//Init ADC1
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
//Group channel scan
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
//Single or Continuous
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_RisingFalling;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_Ext_IT11;;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
//Number of conversion in group
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// Enable ADC1 DMA
ADC_DMACmd(ADC1, ENABLE);
// ADC1 regular channel3 configuration
ADC_RegularChannelConfig(ADC1, ADCx_CHANNEL, 1, ADC_SampleTime_3Cycles);
// Enable DMA request after last transfer (Single-ADC mode)
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
GPIOG->BSRRL = GPIO_Pin_6;
ADC_SoftwareStartConv(ADC1);
//Wait for end of transfer
while(DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0) == RESET);
GPIOG->BSRRH = GPIO_Pin_6;
DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0);
return;
}
#stm32f4-adc-exti11
- Labels:
-
ADC
-
GPIO-EXTI
-
STM32F4 Series
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2014-12-05 8:45 AM
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigInjecConvEdge_RisingFalling;
Injected? you sure?
Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2014-12-05 8:53 AM
I had to say, you have the eye !
I did some changes regarding the EXTI_Mode too , used EXTI_Mode_Interrupt instead to EXTI_Mode_Event.But once I changed for the right value for ADC_ExternalTrigConvEdge , it worked as expected.Thanks a lot would have take some time to see that .Keaven- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2014-12-05 1:01 PM
Quick question.
The code run great on one pass. I tried to spit it so I can start a single acquisition on a function call. My assumption was to only take out this part ..ADC_Cmd(ADC1, ENABLE);
GPIOG->BSRRL = GPIO_Pin_6;
ADC_SoftwareStartConv(ADC1);
//Wait for end of transfer
while(DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0) == RESET);
GPIOG->BSRRH = GPIO_Pin_6;
DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0);
Looks like I am wrong because the DMA Flag is not raised on the second pass but I cleared it. Which other command I need to call each time?
Thank you
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2014-12-05 1:46 PM
I've got a rather narrow field of view on this code, I would generally double the buffer size and use the HT and TC DMA interrupts to manage alternating halves of the buffer.
DMA_InitStructure.DMA_BufferSize = 2140;
Was this supposed to be 2048 samples?
I don't tend to sit in loops polling DMA status, and generally would set up the ADC and DMA once, and then leave it alone.
Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2014-12-08 6:55 AM
Clive1,
No my buffer was exactly the same size of the data required. This is a CCD sensor . I understand it is better to let it run but I need to synchronize the the DMA transfer in time. So to understand well the process, I did it by polling the flag and try to do on request with a press of the button.My question is now what is required to end properly the process and restart it? Even, if I let run my transfer/conversion I will have to synchronize the data convert/transfert at exactly every 1 ms once requested randomly in time.Thanks- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2014-12-08 2:33 PM
Here is how I fixed my problem.
1- I changed the DMA_mode to DMA_Mode_Circular2- Include ADC_DMACmd(ADC1, ENABLE) inside my function to do a capture3- Include ADC_DMACmd(ADC1, DISABLE) after clearing my DMA_FLAG_TCIF0 flag to keep my buffer intact.Add a call to my function on the user button and it works correctly.Thanks for your help