cancel
Showing results for 
Search instead for 
Did you mean: 

Timer triggers the ADC to work

sherif
Associate II
Posted on June 30, 2013 at 17:27

I'm using TIM1 to generate a PWM signal of period 1 sec and a varying pulse duty.

This pulse undergoes some signal conditioning and then entered to the ADC, worth to mention that nothing happens to the signal's period nor the pulse width.

How i make the ADC reads only this value? i want something like triggering the ADC to start the conversion.

#adc #stm32 #timers
17 REPLIES 17
sherif
Associate II
Posted on June 30, 2013 at 17:29

Tried to use this

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;

But i'm sure there's something i already miss and it's not that simple!
Posted on June 30, 2013 at 18:55

Pacing the ADC with a timer is a pretty straight forward task. Here's an example on the STM32F4

[DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/stm32f207%20ADC%2BTIMER%2BDMA%20%20Poor%20Peripheral%20Library%20Examples&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=223]https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex_mx_stm32%2Fstm32f207%20ADC%2BTIMER%2BDMA%20%20Poor%20Peripheral%20Library%20Examples&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=223
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
sherif
Associate II
Posted on July 01, 2013 at 18:19

Thanks a lot for your reply.

I'm not using the DMA so i'm going to cross it out. Here's my code, it didn't anyway!

void Initializations(void)
{
/* CLocks and GPIOs configurations */
HW_Init();
/* ADC configuration */
ADC_Config();
/* Timers configurations */
Timers_Config();
/* NVIC configuration */
NVIC_Config();
}
void ADC_Config(void)
{
/* Initialize the ADC1 according to the ADC_InitStructure members */
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; /* Single Channel */
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; 
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* Configures ADC1 (ADC) Channel3 as: second converted channel with a 7.5 cycles sample time */
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_239Cycles5);
/*Enable the start of conversion for ADC1 through external trigger */
ADC_ExternalTrigConvCmd(ADC1, ENABLE);
/* Enable ADC1 EOC interrupt */
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE); /* EOC = End Of Conversion */
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Reset the ADC1 Calibration registers */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* It is recommended to start calibration for the ADC after each power up */
/* Start the ADC1 Calibration */
ADC_StartCalibration(ADC1);
/* Get the ADC1 calibration status */
while(ADC_GetCalibrationStatus(ADC1));
/* Start by software the ADC1 Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
void Timers_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructInit;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* Selects the internal clock for TIM1 */
TIM_InternalClockConfig(TIM1);
TIM_TimeBaseStructInit.TIM_Period = Pulse_Period;
TIM_TimeBaseStructInit.TIM_Prescaler = Pulse_Prescaler;
TIM_TimeBaseStructInit.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructInit.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructInit.TIM_RepetitionCounter = 0x00;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructInit);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStructure.TIM_Pulse = Pulse_Duty;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; 
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
/* Enables the TIM1 Preload on CC1 Register */
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //OCxPE bit in the TIMx_CCMRx register
/* Enables the TIM1 Preload on ARR Register */
TIM_ARRPreloadConfig(TIM1, ENABLE); //ARPE bit in the TIMx_CR1 register
/* Sets the TIM1 new Autoreload value ARR */
TIM_SetAutoreload(TIM1, Pulse_Period); //Autoreload register sets the period
/* Sets the new TIM1 Capture Compare 1 value */
TIM_SetCompare1(TIM1, Pulse_Duty); //Capture Compare register sets the duty cycle
/* Selects the OC1 event as TRGO for TIM1 */
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_OC1);
/* Enables the TIM1 counter */
TIM_Cmd(TIM1, ENABLE);
/* Enables the TIM1 peripheral Main Outputs */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
void NVIC_Config(void)
{
/* The following example illustrates how to initialize a NVIC_InitTypeDef structure */
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = ADC1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
int main(void)
{
/* All needed initializations */
Initializations();
while(1);
}
void __attribute__ ((interrupt)) __cs3_isr_adc1_2 (void)
{
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
ConvertedValue = ADC_GetConversionValue(ADC1);
}

sherif
Associate II
Posted on July 01, 2013 at 18:21

Why do i see it's not working? Because the Convertedvalue variable reads zero for the most of the time. So it doesn't really fire at the start of the pulse!

Posted on July 01, 2013 at 20:09

It's not sufficiently complete for me to spend time reviewing.

I'll assume you modified ADC1_2_IRQHandler() in the vector table, and have the clocks enabled.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
sherif
Associate II
Posted on July 03, 2013 at 13:56

I used that handler structure as to cope with the interrupt vector comes already with the Codesourcery IDE.

void HW_Init(void)
{
/* System Clocks configuration */
RCC_Config();
/* GPIO configuration */
IO_Config();
}
void RCC_Config(void)
{
FlagStatus HSIStatus;
/* Enable Internal High Speed oscillator */
RCC_HSICmd(ENABLE);
HSIStatus = RCC_GetFlagStatus(RCC_FLAG_HSIRDY);
while(!HSIStatus)
{}
/* Set PLL clock output to 24MHz using HSI (8MHz) as entry clock */
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_6);
/* Select the PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
volatile u8 i;
for(i=0; i<=10; ++i)
{;}
/* Enable the PLL */
RCC_PLLCmd(ENABLE);
/* Configure HCLK such as HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* Configure PCLK1 such as PCLK1 = HCLK/2 */
RCC_PCLK1Config(RCC_HCLK_Div1);
/* Configure PCLK2 such as PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* Configure ADCCLK such as ADCCLK = PCLK2/2 */
RCC_ADCCLKConfig(RCC_PCLK2_Div2);
/* Enable peripheral clocks */
/* Enable GPIOA, TIM1, ADC1, AFIO clocks */
RCC_APB2PeriphClockCmd((RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO), ENABLE);

}

void IO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_3);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //Analog Input
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_8);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //Push-Pull Output Alternate-Function
GPIO_Init(GPIOA, &GPIO_InitStructure);
}

Posted on July 03, 2013 at 17:41

CodeSourcery must be using a hideously old firmware library (v2.x.x prior to CMSIS)

I really don't like how you're enabling and switching to the PLL The following has a more reasonable flow, and checks for the PLL lock before switching to it, and waits for the switch over to occur.

void RCC_Config(void)
{
/* RCC system reset(for debug purpose) */
RCC_DeInit();
/* HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK2 = HCLK/1 */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK/1 */
RCC_PCLK1Config(RCC_HCLK_Div1);
/* ADCCLK = PCLK2/2 */
RCC_ADCCLKConfig(RCC_PCLK2_Div2);
/* PLLCLK = 8MHz / 2 * 6 = 24 MHz */
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_6);
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while(RCC_GetSYSCLKSource() != 0x08);
/* Enable peripheral clocks --------------------------------------------------*/
/* Enable TIM1, ADC1, AFIO and GPIOA clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_ADC1 |
RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
sherif
Associate II
Posted on July 03, 2013 at 18:15

Would it be worth mentioning that the clock is working just fine? I tested the MCO pin and the 24MHz is out.

And why did you omit the part where the HSI should be enabled?

Thidly: i tried to use the while  loop to check for the lock of the PLL, but it doesn't come out, that's why i used the for loop instead.

Thanks so much for your help!