cancel
Showing results for 
Search instead for 
Did you mean: 

PWM output without using Timer as AF.

nanonikhil
Associate II
Posted on February 10, 2016 at 15:02

I want to generate a PWM output for a GPIO pin without using Timer as the AF.

Is there any other way of accurately doing this? Timers in other modes can be used. Code samples will be helpful.

#output #pwm #discovery #stm32f4 #timers
7 REPLIES 7
Posted on February 10, 2016 at 15:10

Define accurately. Is a couple of micro-seconds sufficient?

You can use interrupts to toggle GPIO, the timer can also toggle a pin in AF mode, and you can advance the CCRx to different point on the time line.

You could use TIM+DMA+GPIO to drive a pattern buffer against some pins at a defined rate.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
nanonikhil
Associate II
Posted on February 10, 2016 at 15:19

I need a frequency of about 25 MHz. The System Clock is at 120 MHz. How to create interrupts using Timers at varying times? How can I alter the interrupt generation time for the next event when it is inside the interrupt for the previous event (while toggling the pin at each event interrupt).

Can you please elaborate?

Posted on February 10, 2016 at 15:48

Interrupts aren't going to be viable beyond a few hundred KHz

At MHz you're going to need to use a TIM via an AF, and adapt your design to allow that if it doesn't accommodate that now.

25 MHz is rather high, consider a CPLD/FGPA. At the very least you'll need the STM32 running at a multiple, due to its use of integer dividers in the timers. You'll have to drive PWM patterns via DMA to decimate the interrupt loading.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
nanonikhil
Associate II
Posted on February 10, 2016 at 16:26

Considering that I have a much lower frequency where interrupts can be used, can you answer my previous question?

Posted on February 10, 2016 at 17:17

Not sure I'm going to sit down and write some arbitrary code.

Review the TIM examples supplied in the firmware library, and those which I've previous provided here on the forum.

Set up a TIM with the timebase/period you want, enable the update interrupt, and toggle/set you GPIO in the interrupt handler. If you need to control phase/duty, then you'll likely want to complement the update with a CCx interrupt.

You can't use the TIM AF pins why exactly? Do you have any code working in that mode that you want to adapt to use different pins?

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
nanonikhil
Associate II
Posted on February 10, 2016 at 19:44

I made a code for 50% duty cycle. Can you verify it?

void TIM2_IRQHandler()
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
}
}
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable and set TIM2 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void InitializeGPIOs()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitTypeDef gpioStructure;
gpioStructure.GPIO_Pin = GPIO_Pin_12;
gpioStructure.GPIO_Mode = GPIO_Mode_OUT;
gpioStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &gpioStructure);
GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_RESET);
}
uint16_t TimerPeriod = 0, Channel1Pulse = 0;
int main(void)
{
int i = 0;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_Config();
InitializeGPIOs();
/* Compute the value to be set in ARR regiter to generate signal frequency at 57 Khz */
TimerPeriod = (SystemCoreClock / 17570 ) - 1;
/* Compute CCR1 value to generate a duty cycle at 50% for channel 1 and 1N */
Channel1Pulse = (uint16_t) (((uint32_t) 5 * (TimerPeriod - 1)) / 10);
/* Time base default values configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
/* Output compare default values configuration */
TIM_OCStructInit(&TIM_OCInitStructure);
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
/* Time Base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = TimerPeriod;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* Output Compare Active Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
TIM_ARRPreloadConfig(TIM2, DISABLE);
TIM_Cmd(TIM2, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
TIM_GenerateEvent(TIM2, TIM_EventSource_Update);
/* Infinite loop */
while (1)
{
i++;
}
}

Posted on February 10, 2016 at 21:15

Channel1Pulse = (uint16_t) (((uint32_t) 5 * (TimerPeriod - 1)) / 10);

That would need to be TimerPeriod + 1, you're trying to back off the subtraction you did to the period, not double down on it. You might want to use a Set and Clear rather than a Toggle, that would ensure the polarity. This might be a better setup

Period and pulse are 32-bit for TIM2 on the STM32F4, and APB1 clock is DIV4, so DIV2 on the SystemCoreClock
/* Compute the value to be set in ARR regiter to generate signal frequency at 57 Khz */
TimerPeriod = ((SystemCoreClock / 2) / 17570);
/* Compute CCR1 value to generate a duty cycle at 50% for channel 1 and 1N */
Channel1Pulse = ((50 * TimerPeriod) / 100);
..
TIM_TimeBaseStructure.TIM_Period = TimerPeriod - 1; // Deal with N-1 here

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..