cancel
Showing results for 
Search instead for 
Did you mean: 

Why does TIM_OC1_SetConfig(TIM_TypeDef *TIMx, TIM_OC_InitTypeDef *OC_Config) reset CC1NE always?

YWang.31
Associate II

Hello,

When I was trying to use PWM complementary outputs of TIM1, I used CubeMX to create the C code but was not able to turn on the N output while the P output shows right period and duty cycle but no deadtime inserted.

Tried many CubeMX configs and compared that to the example in "STM32F3xx_HAL_Driver\...\Examples\TIM\TIM_ComplementarySignals", no obvious difference was found. I found later the CCER was always set to 0x1 instead of 0x5 for both Ch1P and Ch1N to operation, ticked CC1NE in CCER, the N output showed up and both P and N had right deadtime.

Digging deeper, I found TIM_OC1_SetConfig() in stm32fxxx_hal_tim.c as below

static void TIM_OC1_SetConfig(TIM_TypeDef *TIMx, TIM_OC_InitTypeDef *OC_Config)

{

 uint32_t tmpccmrx;

 uint32_t tmpccer;

 uint32_t tmpcr2;

 /* Disable the Channel 1: Reset the CC1E Bit */

 TIMx->CCER &= ~TIM_CCER_CC1E;

 /* Get the TIMx CCER register value */

 tmpccer = TIMx->CCER;

 /* Get the TIMx CR2 register value */

 tmpcr2 = TIMx->CR2;

 /* Get the TIMx CCMR1 register value */

 tmpccmrx = TIMx->CCMR1;

 /* Reset the Output Compare Mode Bits */

 tmpccmrx &= ~TIM_CCMR1_OC1M;

 tmpccmrx &= ~TIM_CCMR1_CC1S;

 /* Select the Output Compare Mode */

 tmpccmrx |= OC_Config->OCMode;

 /* Reset the Output Polarity level */

 tmpccer &= ~TIM_CCER_CC1P;

 /* Set the Output Compare Polarity */

 tmpccer |= OC_Config->OCPolarity;

 if (IS_TIM_CCXN_INSTANCE(TIMx, TIM_CHANNEL_1))

 {

  /* Check parameters */

  assert_param(IS_TIM_OCN_POLARITY(OC_Config->OCNPolarity));

  /* Reset the Output N Polarity level */

  tmpccer &= ~TIM_CCER_CC1NP;

  /* Set the Output N Polarity */

  tmpccer |= OC_Config->OCNPolarity;

  /* Reset the Output N State */

  tmpccer &= ~TIM_CCER_CC1NE;

 }

.......

........

}

Here comes to my question, if TIM_CCER_CC1NE is always reset here, how does it respond to the complementary output config? Is there any function to flip this bit?

I set it as htim1.Instance->CCER |= TIM_CCER_CC1E | TIM_CCER_CC1NE, it's not difficult but lost the idea of HAL driver (abstract wrapping).

Why doesn't TIM_OC1_SetConfig() expose the interface for user to control the setting of CC1NE?

I didn't test the "TIM_ComplementarySignals" example because I don't have the exact devices, has anyone tested it? Does it work?

Thank you for finishing reading the long question. Any comments or help are appreciated in advance.

regards,

Yu

5 REPLIES 5

Note that TIM_OC1_SetConfig disables also CC1E.

You are probably supposed to enable the complementary channel using TIM_CCxNChannelCmd() and the "straight" channel using TIM_CCxChannelCmd() (the latter gets called in numerous functions so it gets probably enabled indirectly in usual cases), but who knows what exactly was the abstract intention of the authors. Maybe it's documented somewhere, I don't know. I wouldn't touch Cube/HAL with a stick.

JW

YWang.31
Associate II

Hi, JW,

Thanks for your inputs. I actually realize quite a few HAL abstract wrapping functions (Cube/HAL) have logic issue, obviously not tested well. Cube is good idea, but need to remove the devils in the detail, not just to draw attention for marketing. Brought it up with a hope ST may hear.

YW

> Cube [HAL] is good idea

Maybe it is, for some "typical" applications; but generally for microcontrollers, it's more a drawback than a help, even conceptually.

The concept of hardware abstraction means to find the least common denominator of the used hardware.

Microcontrollers, by their nature, have widely varying hardware.

In particular, as the complementary-output timers are the exception extending the "normal" timers, they in fact are not supposed to work within that abstraction - exactly as you've experienced.

JW

YWang.31
Associate II

Agreed. For Microcontrollers, too many layers of wrapping a lot of time can be confusing and less efficient.

Unless it's "smartly" organized, the "smartness" I mean here is the wrapper will assemble the much lower level functions based on the device and the peripherals config rather than a pre-made wrapper with hope it can fit all.

TDK
Guru

> Why doesn't TIM_OC1_SetConfig() expose the interface for user to control the setting of CC1NE?

The interface is already exposed, the TIMx->CCER register. If that's the level of control you want, have at it.

HAL is fine, but if you want to do something complicated or specific, you're going to need to use the registers. Especially with the TIM peripherals.

If they exposed every little detail in HAL, it would cease to be a simplified abstract interface.

If you feel a post has answered your question, please click "Accept as Solution".