cancel
Showing results for 
Search instead for 
Did you mean: 

TIM1 CHxN aren't disabled by setting CCNE bit to 0

veblor
Associate II

Post Edited by ST moderator to apply source code formatting and translate from Chinese to English to comply with the community rule:

Best regards,

Gyessine

Hello everyone, I am trying to implement the 6-Step Trapezoidal Control using the COMG event in STM32F411RE as said in the datasheet.

 

Situation:

I am using 3 half bridges each driven by a single IR2110, IR2110 requires only one input signal to be high at a time to drive each half bridge as planned. I am using TIM1 PWM mode CH1-3 for HINs and CH1N-3N for LINs of each half bridge's IR2110. So in theory, for example, for first commutation, I only need CH1 & CH3N to be active. But as far as my understanding goes, if CH1 is active, I will be getting a complementary signal at CH1N as well. If IR2110 receives signal at HIN and LIN, it might cause overshoot for MOSFETs. There is a dead-time between both signals but, the point is I don't need the signal from CH1N so in my understanding the best way is to set the CC1NE bit to 0. 

 

Problem : When I set CC1NE bit to 0, MCU still outputs the complementary signal although it shouldn't. I suspect this because I set the OSSR bit in BDTR to 1 - which might be keeping the complementary channel active. 

 

The above is all my understanding and analysis. I would love to be corrected. I am pasting my code below.

What am I doing wrong? or it's more about my concept and approach of enabling/disabling channels is wrong? I am not sure how else it could be done. I just don't want the complementary signal to be there when the main channel is active. Out of 6 channels of TIM1, CH1,CH1N,CH2,CH2N,CH3,CH3N, I only want 2 of them active at one time and they must not be from the same channel.

 

timer.c

void TIM1_PWM(void){



 ---------------------- Reset TIM1 ----------------------



RCC->APB2RSTR |= RCC_APB2RSTR_TIM1RST;

RCC->APB2RSTR &= ~RCC_APB2RSTR_TIM1RST;



// ---------------------- TIMER BASE CONFIGURATION ----------------------

TIM1->PSC = 0; // Prescaler = 0 -> Timer clock = 16 MHz (no division)

TIM1->ARR = 800 - 1; // Auto Reload = 799 -> 16 MHz / 800 = 20 kHz PWM frequency

TIM1->CNT = 0; // Clear counter to start from 0



 ---------------------- CHANNEL 1 CONFIGURATION ----------------------

TIM1->CCMR1 &= ~(0b111 << 4); // Clear bits [6:4] to ensure OC1M is empty

TIM1->CCMR1 |= (0b110 << 4); // Set OC1M = 110 (PWM mode 1)

TIM1->CCMR1 |= (1U << 3); // Set OC1PE = 1 (Preload enable)



TIM1->CCER &= ~ (1U << 1); // Clear CC1P = 0 -> Active High

TIM1->CCER |= (1U << 3); // CC1NP = 1 -> Complementary output active low



---------------------- CHANNEL 2 CONFIGURATION ----------------------



TIM1->CCMR1 &= ~(0b111 << 12); // Clear bits [14:12]

TIM1->CCMR1 |= (0b110 << 12); // Set OC2M = 110 (PWM mode 1)

TIM1->CCMR1 |= (1U << 11); // Set OC2PE = 1 (Preload enable)



TIM1->CCER &= ~(1U << 5); // Clear CC2P = 0 -> Active High

TIM1->CCER |= (1U << 7); // CC2NP = 1 -> Complementary output active low



---------------------- CHANNEL 3 CONFIGURATION ------------------------

TIM1->CCMR2 &= ~(0b111 << 4); // Clear bits [6:4]

TIM1->CCMR2 |= (0b110 << 4); // Set OC3M = 110 (PWM mode 1)

TIM1->CCMR2 |= (1U << 3); // Set OC3PE = 1 (Preload enable)



TIM1->CCER &= ~(1U << 9); // Clear CC3P = 0 -> Active High

TIM1->CCER |= (1U << 11); // CC3NP = 1 -> Complementary output active low



---------------------- BDTR CONFIGURATION ----------------------

TIM1->BDTR = 0;

TIM1->BDTR |= (1U << 15);  --Set MOE = 1 (Output signals enabled)

TIM1->BDTR |= (1U << 11); --Set OSSR = 1 (Off-State Selection for Run mode)

TIM1->BDTR |= (0x20 << 0); -- 2µs dead time for 16MHz



// ---------------------- CR1 OPTIONAL SETTINGS ----------------------

TIM1->CR1 &=~ (0b11<<5); // CMS = 00

TIM1->CR1 &=~ (1U<<4);



// ---------------------- CR2 OPTIONAL SETTINGS ----------------------

TIM1->CR2 &= ~(0x3F << 8); // Clear OIS bits [13:8] for CH1–CH3

TIM1->CR2 &= ~ (1U << 8); // OIS1 = 0 -> CH1 idle low

TIM1->CR2 &= ~(1U << 9); // OIS1N = 0 -> CH1N idle low

TIM1->CR2 &= ~(1U << 10); // OIS2 = 0 -> CH2 idle low

TIM1->CR2 &= ~(1U << 11); // OIS2N = 0 -> CH2N idle low

TIM1->CR2 &= ~(1U << 12); // OIS3 = 0 -> CH3 idle low

TIM1->CR2 &= ~(1U << 13); // OIS3N = 0 -> CH3N idle low



TIM1->CR2 |= (1U << 2); // CCUS = 1 -> capture/compare control bits are preloaded

TIM1->CR2 |= (1U << 0); // CCPC = 1 -> CCxE, CCxNE and OCxM bits are preloaded

// ---------------------- SET DUTY CYCLES ----------------------

TIM1->CCR1 = 200; // 20% Duty Cycle for Channel 1

TIM1->CCR2 = 200; // 20% Duty Cycle for Channel 2

TIM1->CCR3 = 200; // 20% Duty Cycle for Channel 3



// ---------------------- FINAL ENABLE SEQUENCE ----------------------





TIM1->CR1 |= (1U << 7); // ARPE = 1 -> Auto-Reload Preload Enable



TIM1->EGR = TIM_EGR_UG; // Generate update to load preload registers



TIM1->CR1 |= (1U << 0); // CEN = 1 -> Enable Counter, start PWM generation



TIM1->SR &= ~TIM_SR_UIF; // Clear the UG Flag in the SR



}
motor.c

 

#define Phase_A_High (TIM_CCER_CC1E)

#define Phase_A_Low (TIM_CCER_CC1NE)

#define Phase_B_High (TIM_CCER_CC2E)

#define Phase_B_Low (TIM_CCER_CC2NE)

#define Phase_C_High (TIM_CCER_CC3E)

#define Phase_C_Low (TIM_CCER_CC3NE)



#define CCER_ENABLE_MASK (Phase_A_High | Phase_A_Low | Phase_B_High | Phase_B_Low | Phase_C_High | Phase_C_Low)





static uint8_t step = 0;



static Step_Configuration config_table[6] = {



// 0. A+, B-

{

.ccer = (Phase_A_High | Phase_B_Low),

//.ccr = {200,200,0},

},



// 1. A+, C-

{

.ccer = Phase_A_High | Phase_C_Low,

//.ccr = {200,0,200},



},

// 2. B+, C-

{

.ccer = Phase_B_High | Phase_C_Low,

//.ccr = {0,200,200},



},

// 3. B+, A-

{

.ccer = Phase_B_High | Phase_A_Low,

//.ccr = {200,200,0},



},

// 4. C+, A-

{

.ccer = Phase_C_High | Phase_A_Low,

//.ccr = {200,0,200},



},

// 5. C+, B-

{

.ccer = Phase_C_High | Phase_B_Low,

//.ccr = {0,200,200},



},



};







void commutation(void){



//Step_Configuration* config = &config_table[step];



TIM1->CCER |= (TIM1->CCER &~ CCER_ENABLE_MASK) | config_table[step].ccer;



// TIM1->CCR1 = config->ccr[0];

// TIM1->CCR2 = config->ccr[1];

// TIM1->CCR3 = config->ccr[2];



TIM1->EGR = TIM_EGR_COMG;



delay_us(10);



step++;



if(step >= 6){ // this is for testing only



step = 4;



}





}



main.c

..... code ....

TIM1_PWM();



while(1){



commutation();



delay_us(100);



}

 

2 REPLIES 2
Gyessine
ST Employee

Hello @veblor 
If I understood your code correctly
I really suspect the problem is due to using the "|=" in

TIM1->CCER |= (TIM1->CCER &~ CCER_ENABLE_MASK) | config_table[step].ccer;

 OR can only turn bits from 0 to 1 or leave it at 0, it can never turn bits from 1 to 0.

can you try  

TIM1->CCER = (TIM1->CCER & ~CCER_ENABLE_MASK) | config_table[step].ccer;

Hope that helped you solve your issue
Gyessine

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi there, thanks for your response. I don't that will work because that resets the polarity bits of the CCER register and only would modify the enable/disable bits for the signal output pins. But I found something what might be the cause of still receiving a signal at the pin. In the data sheet for CCER register it's written: "Bit 2 CC1NE: Capture/Compare 1 complementary output enable 0: Off - OC1N is not active. OC1N level is then function of MOE, OSSI, OSSR, OIS1, OIS1N" 

When CCER is 0, it is then the function of the other bits in the BDTR register. I have set OSSI as 1, that might be driving the pin because I have set CC1NE to 0. That stays there. Next, what I found is that I might be implementing the 6 Step approach in a wrong manner, I looked over the datasheet again and this figure below says that I must also manipulate OCxM bit along with CCxE and CCxNE bits. I am not experienced much to understand this figure, would it be possible if you could give a brief overview of what's happening, I am just confused over the CNT, I mean why does COM event happens in the middle of CNT, after CNT reg has counted fully for 2 cycles before, already? Also for example 2 in the figure below, when OCxREF goes to 0, OCx and OCxN stay as it is. Later in the same example CCxE is set to 0 and CCxNE is set to 1, CCxNE rises but why does CCxE stays at the same level?

Screenshot 2026-01-12 214201.png