2022-07-18 10:58 AM
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 */
}
2022-07-18 05:17 PM
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?
JW
2022-07-18 06:35 PM
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
2022-07-18 06:36 PM
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)
2022-07-19 02:11 AM
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).
JW
2022-07-19 07:05 AM
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?
2022-07-19 02:48 PM
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.
2022-07-19 06:04 PM
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?
2022-07-20 01:37 AM
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_AHB1ENR_GPIOAEN
| RCC_AHB1ENR_GPIODEN
;
RCC->APB1ENR |= 0
| RCC_APB1ENR_TIM4EN
;
RCC->APB2ENR |= 0
| RCC_APB2ENR_TIM1EN
;
// 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
;
LoopDelay(DELAY_CONSTANT);
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
;
LoopDelay(DELAY_CONSTANT);
}
}
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
Nothing else.
JW