2008-08-29 07:42 AM
Variable PWM generation
2011-05-17 03:42 AM
of course, the compare registers are optionally shadowed. you get an interrupt at the start of a cycle and you've got full cycle to decide what the duty of the next cycle will be; you just have to program the value before this cycle ends.
2011-05-17 03:42 AM
Is it possible using the TIMx PWM Output Mode to produce a wave with a controllable Duty cycle (as in j1850 PWM)?
Example: Bit 0 represents a wave with a 25% duty cycle |^|____ Bit 1 resresents a wave with a 75% duty cycle. |^^^|_ So if I send 0100101 I would see a wave with a variable duty cycle that changes on each bit I transmit. |^|____|^^^|_|^|____|^|____|^^^|_|^|____|^^^|_ Your help will be very much appreciated2011-05-17 03:42 AM
Thank-you lanchon - your response made me persist. I feel I should post the working code for completeness
void SetUpTimer2(void) { /* Time base configuration */ PWM_TIM_TimeBaseStructure.TIM_Period = 1728; /* 1728 at 72MHz gives us 24us bit time */ PWM_TIM_TimeBaseStructure.TIM_Prescaler = 0; PWM_TIM_TimeBaseStructure.TIM_ClockDivision = 0; PWM_TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &PWM_TIM_TimeBaseStructure); /* PWM1 Mode configuration: Channel1 */ PWM_TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; PWM_TIM_OCInitStructure.TIM_Channel = TIM_Channel_3; PWM_TIM_OCInitStructure.TIM_Pulse = 432; PWM_TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInit(TIM2, &PWM_TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM2, ENABLE); /* TIM enable counter */ TIM_Cmd(TIM2, ENABLE); /* Enable the CC3 Interrupt Request */ TIM_ITConfig(TIM2, TIM_IT_CC3, ENABLE); } Then the interrupt is simply this: void TIM2_IRQHandler(void) { if ( TIM_GetITStatus(TIM2, TIM_IT_CC3)) { /* rising edge detected */ /* Clear TIM2 Capture compare interrupt pending bit */ TIM_ClearITPendingBit(TIM2, TIM_IT_CC3); if (Pulse == 432) Pulse = 1296; /*75% Pulse*/ else Pulse = 432; /*25% Pulse*/ TIM2->CCR3 = Pulse; } } The only slight thing it is doing wrong now is the very first pulse is 1us longer than it should be(the 25% high pulse is 7us rather than 6us). I have no idea why. Thanks again Adam2011-05-17 03:42 AM
you should use the time base periodic int, not the CC3 int. and enable the interrupt before enabling the timer.
> the very first pulse is 1us longer than it should be the PWM output is probably active before you start the time-base 1) make the first PWM cycle have zero width: PWM_TIM_OCInitStructure.TIM_Pulse = 0; // this goes through to the CC reg since preloading is disabled; it'll be active now and during the first PWM cycle. PWM_TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInit(TIM2, &PWM_TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM2, ENABLE); TIM2->CCR3 = 432; // now this sits in the preload and will rule cycle 2. /* TIM enable counter */ TIM_Cmd(TIM2, ENABLE); // note that if this immediately causes a time-base int (I don't think so) then the above statement should be removed (the ISR would set width of the 2nd cycle). } 2) if the 1 cycle delay at the beginning is a problem and you need an accurate first pulse, you need to preset the time base counter with a value near the upper limit so that the first PWM cycle is reduced to one or two time-base clocks.2011-05-17 03:42 AM
Thanks again lanchon - I hope ST pay you for this service.
I did as you said and stopped the long first pulse problem by setting Pulse to 0 initially. I have now successfully transmitted a J1850PWM message this way to a vehicle ECU and received the expected response (seen on a scope). Adam2011-05-17 03:42 AM
glad to hear it worked.
> Thanks again lanchon - I hope ST pay you for this service. ha! in fact ST turned down my most recent sample request...2011-05-17 03:42 AM
I have also face this problem now, could you please give some detailed information? I managed to generate PWM from TIM3_CH3 and the result is good seen on an Oscilloscope, but, i couldn't capture the TIM3 interrupt, code as following:
/* ----------------------------------------------------------------------- TIM3 Configuration: generate PWM signal with duty cycle: TIM3 CLK = 36 MHz, Prescaler = 0x0, TIM3 counter clock = 36 MHz TIM3 ARR Register = 719 => TIM3 Frequency = TIM3 counter clock/(ARR + 1) TIM3 Frequency = 100 KHz. TIM3 Channel1 duty cycle = (TIM3_CCR1/ TIM3_ARR)* 100 = 50% CRRx_Val = 360 TIM3 Channel2 duty cycle = (TIM3_CCR2/ TIM3_ARR)* 100 = 37.5% TIM3 Channel3 duty cycle = (TIM3_CCR3/ TIM3_ARR)* 100 = 25% CRRx_Val = 180 TIM3 Channel4 duty cycle = (TIM3_CCR4/ TIM3_ARR)* 100 = 12.5% ----------------------------------------------------------------------- */ /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = 719; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // Clear TIM2 update pending flag TIM_ClearFlag(TIM3, TIM_FLAG_Update); // Enabel interrupt //TIM_ITConfig(TIM3, TIM_IT_CC3, ENABLE); TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //TIM_UpdateRequestConfig(TIM3,TIM_UpdateSource_Regular); /* PWM1 Mode configuration: Channel3 */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR_Val; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC3Init(TIM3, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //TIM_ARRPreloadConfig(TIM3,DISABLE); TIM_ARRPreloadConfig(TIM3, ENABLE); /* TIM3 enable counter */ TIM_Cmd(TIM3, ENABLE); void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_CC3)!= RESET) { GPIO_WriteBit(GPIO_LED
, GPIO_LED0_PIN, (BitAction)((1-GPIO_ReadOutputDataBit(GPIO_LED, GPIO_LED0_PIN)))); //IC3value = TIM_GetCapture3(TIM3); TIM_ClearITPendingBit(TIM3, TIM_IT_CC3); } } Why doesn't The LED toggle with the TIM interrupt? How can I ''you get an interrupt at the start of a cycle and you've got full cycle to decide what the duty of the next cycle will be'' Thank you advanced.2011-05-17 03:43 AM
Hi liu.zack,
Perhaps you have to uncomment the following line in your code: //TIM_ITConfig(TIM3, TIM_IT_CC3, ENABLE); Regards, be low power, be happy2011-05-17 03:43 AM
I did use the ''TIM_ITConfig(TIM3, TIM_IT_CC3, ENABLE)'' instead of '' TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE)'' and they act as no differece, so that could not be the reason. I just wondering should i take another timer to set as input to cature the interrupt.