A push pull converter uses two drivers that are 180 degrees out of phase.
It is possible to generate PWM on 2 channels that are 180 degrees out of phase in TIM1on a STM8S003. All the register settings are from the reference manual, but you won't find an example.
TIM1 is set up as an up/down counter in Center-aligned mode. This spaces out the 2 phase PWM signal evenly.
Since the timer is counting both up and down in 1 PWM cycle, auto-reload value for TIM1 should be set as 1/2 of the value to generate PWM frequency. I used TIM1_FREQ of 27kHz in my code.
#define CPU_CLOCK 16000000UL
#define TIM1_FREQ 27000L
#define TIM1_PSCR 1
#define TIM1_CLK (CPU_CLOCK/TIM1_PSCR)
#define TIM1_ARR (TIM1_CLK/TIM1_FREQ/2)
#define TIM1_PSCRH ((TIM1_PSCR-1)>>8)
#define TIM1_PSCRL ((TIM1_PSCR-1)&0xff)
#define TIM1_ARRH ((TIM1_ARR)>>8)
#define TIM1_ARRL ((TIM1_ARR)&0xff)
// Clk = 16MHz
CLK->CKDIVR = 0;
TIM1->PSCRH = TIM1_PSCRH;
TIM1->PSCRL = TIM1_PSCRL;
TIM1->ARRH = TIM1_ARRH;
TIM1->ARRL = TIM1_ARRL;
// TIM1 enable, Center-aligned mode 3
TIM1->CR1 = TIM1_CR1_CEN|TIM1_CR1_CMS;
Output enable (and polarity) bits of the corresponding TIM1 channels can be set in TIM1 CCERx. I use CH3 and CH4.
// CH3, CH4 output enable, polarity active high
TIM1->CCER2 = TIM1_CCER2_CC4E|TIM1_CCER2_CC3E;
From the Reference Manual:
110: PWM mode 1 - In up-counting, channel 1 is active as long as TIM1_CNT < TIM1_CCR1, otherwise, the channel is inactive. In down-counting, channel 1 is inactive (OC1REF = 0) as long as TIM1_CNT > TIM1_CCR1, otherwise, the channel is active (OC1REF = 1).
111: PWM mode 2 - In up-counting, channel 1 is inactive as long as TIM1_CNT < TIM1_CCR1, otherwise, the channel is active. In down-counting, channel 1 is active as long as TIM1_CNT > TIM1_CCR1, otherwise, the channel is inactive.
One can generate a PWM signal using a sawtooth wave and a comparator.
PWM generation using analog circuit - Sawtooth wave and a comparator
The modulating signal level is the CCR value, the TIM1 counter is the sawtooth wave. The PWM modes 1 and 2 are just the polarity setting on the comparator.
One of the TIM1 channel (CH3) is set up with PWM Mode 1 while another channel (Ch4) as PWM Mode 2.
// CH3: PWM mode 1, preload, output
TIM1->CCMR3 = (6<<4)|TIM1_CCMR_OCxPE;
// CH4: PWM mode 2, preload, output
TIM1->CCMR4 = (7<<4)|TIM1_CCMR_OCxPE;
Use PWM Mode 1 for one of the channels to center an output around Timer count = 0 and Mode 2 on the other to center around Timer count = ARR. This is how you can generate the 2 phase PWM signals.
The CCR values could be set independently. In some applications, you want them to have the same PWM duty cycles. The granularity of the PWM signal is 2 TIM1 clocks. (125ns in my code)
void Set_PWM(uint16_t Value)
{
Value >>=1;
// CCR3 = n/2
TIM1->CCR3H = Value >>8;
TIM1->CCR3L = Value & 0xff;
// CCR4 = TIM1_ARR - n/2
Value = TIM1_ARR - Value;
TIM1->CCR4H = Value >>8;
TIM1->CCR4L = Value & 0xff;
}
Turn on the MOE (Main Output Enable) bit in TIM1 BKR (Break Register). An external signal can be used to disable the TIM1 outputs in the case of a hardware fault. e.g. over-current or over-temperature condition
// Master output enable
TIM1->BKR = TIM1_BKR_MOE;
This are some the output of PWM waveform at 27kHz captured on my logic analyzer.