Showing results for 
Search instead for 
Did you mean: 

Setting timer 1 channel 4 high on startup

Associate III

I am using Timer 1 DMA to generate a waveform. The generation part works fine, but the waveform is inverted, so I need to set channel 4 (output of CC4) signal high during initialization.

I have tried a bunch of thing, my latest attempt is below. Whatever I try, the CH4 output stays low. This is only after initialization, after the first DMA the CH4 line stays high.

Any ideas?

void Timer1_Init(void)
    TIM1->CR1 &= ~TIM_CR1_CEN;                              /* Disable the Timer */
    TIM1->CCMR2 = TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_0;      /* Force CH4 high */
    TIM1->CCER = TIM_CCER_CC4E;                             /* Enable CH4 output */
    TIM1->BDTR = TIM_BDTR_MOE;                              /* set master enable */
    TIM1->CNT = 0;                                          /* Set the count to zero */
    TIM1->CR1 |= TIM_CR1_CEN;                               /* Enable the Timer */


Which STM32?

> but the waveform is inverted

What does it mean?

> TIM1->CCMR2 = TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_0; /* Force CH4 high

This should work. How is the rest of TIM1 registers set?


Associate III

CPU is STM32L433

Inverted means the waveform starts with a logic high, and goes back to a logic high when the waveform is complete.

Here are the registers before running the initialization code

TIM1	TIM_TypeDef *	0x40012c00	
	CR1	volatile uint32_t	128	
	CR2	volatile uint32_t	16384	
	SMCR	volatile uint32_t	0	
	DIER	volatile uint32_t	0	
	SR	volatile uint32_t	1	
	EGR	volatile uint32_t	0	
	CCMR1	volatile uint32_t	0	
	CCMR2	volatile uint32_t	12288	
	CCER	volatile uint32_t	0	
	CNT	volatile uint32_t	0	
	PSC	volatile uint32_t	16	
	ARR	volatile uint32_t	65535	
	RCR	volatile uint32_t	0	
	CCR1	volatile uint32_t	0	
	CCR2	volatile uint32_t	0	
	CCR3	volatile uint32_t	0	
	CCR4	volatile uint32_t	65535	
	BDTR	volatile uint32_t	33562624	
	DCR	volatile uint32_t	0	
	DMAR	volatile uint32_t	128	
	OR1	volatile uint32_t	0	
	CCMR3	volatile uint32_t	0	
	CCR5	volatile uint32_t	0	
	CCR6	volatile uint32_t	0	
	OR2	volatile uint32_t	1	
	OR3	volatile uint32_t	1	

Associate III

Here are the registers in hex

TIM1	TIM_TypeDef *	0x40012c00 (Hex)	
	CR1	volatile uint32_t	0x80 (Hex)	
	CR2	volatile uint32_t	0x4000 (Hex)	
	SMCR	volatile uint32_t	0x0 (Hex)	
	DIER	volatile uint32_t	0x0 (Hex)	
	SR	volatile uint32_t	0x1 (Hex)	
	EGR	volatile uint32_t	0x0 (Hex)	
	CCMR1	volatile uint32_t	0x0 (Hex)	
	CCMR2	volatile uint32_t	0x3000 (Hex)	
	CCER	volatile uint32_t	0x0 (Hex)	
	CNT	volatile uint32_t	0x0 (Hex)	
	PSC	volatile uint32_t	0x10 (Hex)	
	ARR	volatile uint32_t	0xffff (Hex)	
	RCR	volatile uint32_t	0x0 (Hex)	
	CCR1	volatile uint32_t	0x0 (Hex)	
	CCR2	volatile uint32_t	0x0 (Hex)	
	CCR3	volatile uint32_t	0x0 (Hex)	
	CCR4	volatile uint32_t	0xffff (Hex)	
	BDTR	volatile uint32_t	0x2002000 (Hex)	
	DCR	volatile uint32_t	0x0 (Hex)	
	DMAR	volatile uint32_t	0x80 (Hex)	
	OR1	volatile uint32_t	0x0 (Hex)	
	CCMR3	volatile uint32_t	0x0 (Hex)	
	CCR5	volatile uint32_t	0x0 (Hex)	
	CCR6	volatile uint32_t	0x0 (Hex)	
	OR2	volatile uint32_t	0x1 (Hex)	
	OR3	volatile uint32_t	0x1 (Hex)	

As long as CCER.CCxE is clear, output is disabled, i.e. Hi-Z.

By setting CCMRx.OCxM to 0b110 i.e. PWM mode 1, setting CCxR to some reasonable value (e.g. half of ARR), enabling given channel by setting CCER.CCxE and setting BDTR.MOE, you should see a waveform which does what you expect, i.e. start high, and after reaching CCxR value going low, after reaching ARR value going up again (and if CR1.OPM is set, remains so).


Associate III

I think you misunderstand my problem. I do not want to generate a waveform. I just want to set the output of Timer1 CH4 high on initialization.

Regarding CCER, I am setting this with the line TIM1->CCER = TIM_CCER_CC4E;

Is there anything else I need to do?

Chief II

You have to set OSSI and/or OSSR bits in BDTR register. Take a careful look at:

RM0394 Rev 4, Table 133. Output control bits for complementary OCx and OCxN channels with break feature.

EDIT: Probably not the problem.

In those register values almost nothing corresponds to the code you showed and what you tell you are doing.

Associate III

As I said in my previous answer the register values are BEFORE the initialization code is run, The values were generated by the tool from the IOC file.

Maybe I made everything too complicated. So here is my question.

Assuming I set GPIO PA11 to the alternate function Timer1 Channel 4, how do I output a high level on this pin?

The following on DiscoF4 produces a "blinking" pulse-train on both PA11=TIM1_CH4 and PD15=TIM4_CH4 (I used PD15 first, as it's connected to the blue LED so I can see the blinking, whereas PA11 is not even brought out to the headers so I had to probe R58 using oscilloscope).

#include "stm32f4xx.h"
// #include "stm32f4xx_augment.h"
// #include "common.h"
// #include "common_gcc.h"
// blinking with blue LED through setting it as TIM4_CH4
Disco F407
4LEDS on PD12..PD15, these are also TIM4_CH1..CH4
#define LED_PORT     GPIOD
#define LED_PIN      15
// BUTTON     PA0, switches to VCC
#define BUTTON_PORT      GPIOA
#define BUTTON_PIN       0
// default HSI 16MHz clock
#define CLOCK_MHZ  16
// -------- utils/frameworks
// trivial loopdelay
static void LoopDelay(volatile uint32_t n) {
	while(n > 0) n--;
#define DELAY_CONSTANT 1000000
// ---------------------------- MAIN ------------------------------
int main(void) {
  RCC->AHB1ENR |= 0
  RCC->APB1ENR |= 0
  RCC->APB2ENR |= 0
// in GPIOA->MODER, PA0 is at default as Input
// and there's also an external pulldown, so no need to switch on the internal one
  GPIOA->MODER = (GPIOA->MODER  // assuming reset value
  ) | (0
    | (0b10 << GPIO_MODER_MODER11_Pos)   // PA11, TIM1_CH4 - OTG_FS_DM, R58
  GPIOA->AFR[1] = GPIOA->AFR[1] | (0
    | (1 << GPIO_AFRH_AFSEL11_Pos)          // TIM1 is AF1
  GPIOD->MODER = (GPIOD->MODER  // assuming reset value
  ) | (0
    | (0b10 << GPIO_MODER_MODER15_Pos)   // blue LED, 0b10 = GPIO_Mode_AF
  GPIOD->AFR[1] = GPIOD->AFR[1] | (0
    | (2 << GPIO_AFRH_AFSEL15_Pos)  // TIM4 is AF2
  TIM4->CCER = 0
    | TIM_CCER_CC4E // enable TIM4_CH4
  TIM1->CCER = 0
    | TIM_CCER_CC4E // enable TIM1_CH4
  TIM1->BDTR = 0
    | TIM_BDTR_MOE // enable TIM1 outputs
  while(1) {
    TIM4->CCMR2 = 0
      | (0b00  << TIM_CCMR2_CC4S_Pos)  // CH4 select 0b00 = output compare
      | (0b101 << TIM_CCMR2_OC4M_Pos)  // 0b101 = Force Active
    TIM1->CCMR2 = 0
      | (0b00  << TIM_CCMR2_CC4S_Pos)  // CH4 select 0b00 = output compare
      | (0b101 << TIM_CCMR2_OC4M_Pos)  // 0b101 = Force Active
    if (BUTTON_PORT->IDR & (1 << BUTTON_PIN)) {
      LoopDelay(3 * DELAY_CONSTANT);
    TIM4->CCMR2 = 0
      | (0b00  << TIM_CCMR2_CC4S_Pos)  // CH4 select 0b00 = output compare
      | (0b100 << TIM_CCMR2_OC4M_Pos)  // 0b100 = Force Inactive
    TIM1->CCMR2 = 0
      | (0b00  << TIM_CCMR2_CC4S_Pos)  // CH4 select 0b00 = output compare
      | (0b100 << TIM_CCMR2_OC4M_Pos)  // 0b100 = Force Inactive

As far as TIM1 is concerned:

In RCC, I enable clock for GPIOA and TIM1.

In GPIOA, I set MODER for pin PA11 to 0b10 = AF, and AFR[1] to 1 (TIM1=AF1).

In TIM1, I set

  • CCER.CC4E = 1
  • BDTR.MOE = 1
  • CCMR2.CC4S = 0b00 (i.e. Output Compare)
  • alternating, CCMR2.OC4M=0b101 (Force Active) and CCMR2.OC4M=0b100 (Force Inactive)

Nothing else.