STM32F4 How do you generate complementary PWM Outputs?

How do you generate complementary PWM Outputs?

I would like to generate complementary PWM Outputs with adjustable dead time.

According to the STM32F401RE Microcontroller datasheet

http://www.st.com/web/catalog/mmc/FM141/SC1169/SS1577/LN1810/PF258797,

this is possible with Timer 1 (TIM1).

So far I have attempted to configure the timer myself using information available from the TIM HAL Driver from ST:

http://developer.mbed.org/users/dreschpe/code/mbed-F401/docs/4e95b79aa640/stm32f4xx__hal__tim__ex_8c.html

and looking through an example of someone using the driver:

https://petoknm.wordpress.com/2015/01/05/rotary-encoder-and-stm32/.

Obviously, I do not want to use a HAL sensor, but this is the closest example I can get to someone using the advanced features of the timers.

Thanks!

Damien

Edit: Here is the code I went with in the end:

void ConfigurePWM(float duty_us, float period_us){
    unsigned int value;
    float newVal;

    // Ensure power is turned on
    // Grabbed from lines 54-57 of analogin_api.h, modified for PWM
    // This turns on the clock to Ports A, B, and C
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
    // This turns on the clock to the Time 1:
    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;

    // Set the GPIO Ports properly:
    // PWM1 is connected to  PA_8
    // PWM1N is connected to PA_7

    // Set the PWM outputs to general output pins:
    // This sets the PA_7 and PA_8 pins to Alternate Function Pins
    value = 0x8000 + 0x20000;
    GPIOA->MODER |= value;

    // Set the PWM outputs to high speed:
    value = 0xC000 + 0x30000;
    GPIOA->OSPEEDR |= value;

    // Set PWM as outputs to the pins:
    value = GPIOA->AFR[1];
    // Reset the lowest four bits:
    value &= 0xFFFFFFF0;
    // Configure PA_8 to AF:
    value |= 0x1;
    GPIOA->AFR[1] = value;

    value = GPIOA->AFR[0];
    // Reset the the 4 MSB:
    value &= 0x0FFFFFFF;
    // Configure PA_7 to AF:
    value |= 0x10000000;
    GPIOA->AFR[0] = value;

    // Set pull down resistors to PWM outputs:
    value = GPIOA->PUPDR;
    // Clear the bits:
    value &= ~(GPIO_PUPDR_PUPDR7 | GPIO_PUPDR_PUPDR8);
    // Set to pull down:
    value |= GPIO_PUPDR_PUPDR7_1 | GPIO_PUPDR_PUPDR8_1;
    // Set the register:
    GPIOA ->PUPDR = value;

    // Set the prescale value to 1:
    TIM1->PSC = 0;

    // *** TIM1 control register 1: TIMx_CR1 ***
    value = 0;
    // [9:8] Set CKD bits to zero for clock division of 1
    // [7] TIMx_ARR register is buffered, set the ARPE bit to 1:
    // value |= 0x80;
    // [6:5] Set CMS bits to zero for edge aligned mode
    // [6:5] Set CMS bits to 10 for Center Aligned mode 2, up down mode with flags set when counter reaches the top.
    //value |= TIM_CR1_CMS_1;
    // [4] Set DIR bit to zero for upcounting
    // [3] Set OPM bit to zero so that the counter is not stopped at update event
    // [2] Set URS bit to zero so that anything can create an interrupt
    // [1] Set UDIS bit to zero to generate an update event
    // [0] Set the CEN bit to zero to disable the counter
    // * Set the TIMx_CR1 Register: *
    TIM1->CR1 |= value;

    // *** TIM1 control register 2: TIMx_CR2 ***
    value  = 0;
    // [14] Set OIS4 bit to zero, the idle state of OC4 output
    // [13] Set OIS3N bit to zero, the idle state of OC3N output
    // [12] Set OIS3 bit to zero, the idle state of OC3 output
    // [11] Set OIS2N bit to zero, the idle state of OC2N output
    // [10] Set OIS2 bit to zero, the idle state of OC2 output
    // [9] Set OIS1N bit to zero, the idle state of OC1N output
    // [8] Set OIS1 bit to zero, the idle state of OC1 output
    // [7] Set TI1S bit to zero, connecting only CH1 pin to TI1 input
    // [6:4] Set to 111: The OC4REF signal is used as trigger output (TRGO)
    // value |= TIM_CR2_MMS_2 | TIM_CR2_MMS_1 | TIM_CR2_MMS_0;
    // value |= TIM_CR2_MMS_1 | TIM_CR2_MMS_0;
    // [3] Set CCDS bit to zero, request sent when CCx event occurs
    // [2] Set CCUS bit to 1, capture/compare control bits are updated by setting the COMG bit or when a rising edge occurs on TRGI
    // value |= 0x4;
    // [0] Set CCPC bit to 1, CCxE, CCxNE and OCxM are update on a commutation event, or rising edge on TRGI
    // value |= 0x1;
    // * Set the TIMx_CR2 Register: *
    TIM1->CR2 = value;

    // *** TIM1 Auto Reload Register: ARR ***
    value = 0;
    // [15:0] Set ARR bits to the frequency to be loaded in:
    newVal = ceil(period_us/PWMSTEP_US);
    value = (unsigned int) newVal;
    // * Set the TIMx_ARR Register:
    TIM1->ARR = value;

    // *** TIM1 capture/compare register 1: CCR1 ***
    value = 0;
    // [15:0] Set the capture compare value to the duty cycle:
    newVal = ceil(duty_us/PWMSTEP_US);
    value = (unsigned int) newVal;
    // * Set the TIMx_CCR1 Register:
    TIM1->CCR1 = value;

    // *** TIM1 capture/compare register 4: CCR4 ***
    value = 0;
    // [15:0] Set the capture compare value to the duty cycle:
    newVal = ceil(duty_us/2.0f/PWMSTEP_US);
    value = (unsigned int) newVal;
    // * Set the TIMx_CCR1 Register:
    TIM1->CCR4 = TIM1->ARR - CH4SHIFT;

    // *** TIM1 capture/compare mode register 2: CCMR2
    value = 0;
    // [15] Set OC4CE bit to 0, OC4Ref is not affected by the ETRF input
    // [14-12] Set the OC4M bits to ‘110‘, PWM mode 1, which is what we want I think.
    value |= TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1;
    // [11] Set the OC4PE bit to 1, meaning read/write operations to the preload event require an update event.
    value |= 0x800;
    // [10] Set the OC4FE bit to 0, the output compare fast enable is disabled
    // [9:8] Set the CC4S bits to 0, the channel is configured as an output.
    // * Set the TIMx_CCMR2 Register: *
    TIM1->CCMR2 = value;

    // *** TIM1 capture/compare mode register 1: CCMR1
    value = 0;
    // [7] Set OC1CE bit to 0, OC1Ref is not affected by the ETRF input
    // [6-4] Set the OC1M bits to ‘110‘, PWM mode 1, which is what we want I think.
    value |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1;
    // [3] Set the OC1PE bit to 1, meaning read/write operations to the preload event require an update event.
    value |= 0x8;
    // [2] Set the OC1FE bit to 0, the output compare fast enable is disabled
    // [1:0] Set the CC1S bits to 0, the channel is configured as an output.
    // * Set the TIMx_CCMR1 Register: *
    TIM1->CCMR1 = value;

    // *** TIM1 capture/compare enable register: CCER
    value = 0;
    // [15:4] - Don‘t care:
    // [3] Set CC1NP bit to zero for active high.
    // [2] Set CC1NE bit to 0, to de-activate the OC1N signal
    // value |= 0x4;
    // [1] Set the CC1P bit to zero for active high.
    // [0] Set the CC1E bit to 1, to de-activate the OC1 signal
    // value |= 0x1;
    // * Set the TIM1_CCER Register: *
    TIM1->CCER = value;

    // *** TIM1 break and dead-time register: BDTR
    value = 0;
    // [15] Set MOE bit to 1 to enable the OC and OCN outputs
    value |= 0x8000;
    // [11] Set the OSSR bit such that the ouputs are forced to their idle mode when not running
    //value |= TIM_BDTR_OSSR;
    // [10] Set OSSI bit such that the outputs are forced to their idle mode when MOE = 0
    value |= TIM_BDTR_OSSI;
    // * Set the TIM1_BDTR register:
    TIM1->BDTR = value;

    // *** TIM1 DMA/Interrupt enable register: DIER
    value = 0;
    // [2] Set the CC1IE bit to 1, to trigger an interrupt when counter 1 has a match - which should be half way through the duty cycle.
    value |= TIM_DIER_CC4IE;
    // Set the TIM1_DIER register:
    TIM1->DIER |= value;

    // Set the UG bit in the EGR register to kick things off:
    value = 3;
    TIM1->EGR = value;

    // Configure the interrupt:
    NVIC_SetVector(TIM1_CC_IRQn, (uint32_t)&TIM1_CC_IRQHandler);
    NVIC_EnableIRQ(TIM1_CC_IRQn);

    return;

}
时间: 2024-10-19 19:42:59

STM32F4 How do you generate complementary PWM Outputs?的相关文章

Generate stabilized PWM signals

A standard technique for generating analog voltages using µCs is to use a PWM output and filter the signal with a simple RC filter (Figure 1). The voltage of the PWM signal is directly proportional to the µC's supply voltage, so it is not necessarily

Two PWM outputs from MCU combine to form a monotonic 16-bits DAC

http://www.edn.com/design/analog/4329365/Combine-two-8-bit-outputs-to-make-one-16-bit-DAC

Renesas M16C/6X -- Simple PWM Signal Generation Using DMA

1. Requirements To generate a PWM output, we need to create a train of pulses with constant period and variable duty cycle. The duty cycle, being the modulation is the pulse width. Typically, a timer is used to maintain both the period and duty cycle

how to generate an analog output from a in-built pwm of Atmega 32AVR microcontrloller?

how to generate an analog output from a in-built pwm of Atmega 32AVR microcontrloller? you need a resistor, a capacitor and an opamp. opamp is not really necessary when you are driving a mosfet, but will make life a bit easier. just be aware, that th

STM32 Timer : Base Timer, Input Capture, PWM, Output Compare

http://www.cs.indiana.edu/~geobrown/book.pdf An example of a basic timer is illustrated in Figure 10.1. This timer has four components – a controller, a prescaler (PSC), an “auto-reload” register (ARR) and a counter (CNT). The function of the prescal

STM32学习日志--使用DMA功能自动更新PWM的输出

/******************************************************************************* 编译环境: EWARM V5.30 硬件环境: DZY2.PCB STM32 FW: V3.0.0 作者 : szlihongtao ****************************************************************************** REV : V1.00 DATE : 2011

Make a DAC with a microcontroller's PWM timer

Many embedded-microcontroller applications require generation of analog signals. An integrated or stand-alone DAC fills the role. However, you can often use PWM signals for generating the required analog signals. You can use PWM signals to create bot

Beaglebone Back学习五(PWM测试)

PWM测试 参考链接 1 Enable PWM on BeagleBone with Device Tree overlays 2Using PWM on the Beaglebone Black 3 Beaglebone Coding 101: Buttons and PWM 4 Using PWM outputs 5 beaglebone-black-cpp-PWM 6 Enabling PWM Support in the kernel 7 Beaglebone Back学习五(PWM测试

STM32F103ZET6 用定时器级联方式输出特定数目的PWM(转载)

STM32F103ZET6里共有8个定时器,其中高级定时器有TIM1-TIM5.TIM8,共6个. 这里需要使用定时器的级联功能,ST的RM0008 REV12的P388和P399页上有说明对于特定的定时器,怎么去选择级联功能,参见表86. 我这里输出PWM的定时器是TIM2,空闲的定时器是TIM3.以TIM2为主定时器,TIM3为从定时器对TIM2的输出脉冲数进行计数.查表可知,TIM3为从定时器选择TIM2为触发源,需要配置TS=001,即选择ITR1. 实现通过定时器控制输出PWM个数的功