Skip to main content
Associate II
September 20, 2024
Solved

STM32G0 CubeMX Code Incorrect config for Timers (CubeIED V1.16.0)

  • September 20, 2024
  • 3 replies
  • 2401 views

I just spent several days (luckily not full time) failing to get a simple PWM output working.  I could get it working using the HAL drivers, but not able to get it working with the LL drivers.  After spending most of my time assuming it was user error I finally resorted to full register dumps of the Timer registers comparing the HAL code vs the LL code and found the discrepancy.

In the LL-code, somehow the MX_TIM17_Init() generated by CubeMX clears the MOE bit in the BDTR register, disabling outputs even though I have break mode disabled in the UI.  Generating HAL code with exactly the same settings correctly sets the MOE bit.

This seems to be a bug.  After isolating the issue, it was a simple case of adding the call

LL_TIM_EnableAllOutputs(TIM17) ;

 

to my code to enable outputs and all is well.  Double checking all the LL examples, there are no calls to the above routine, so don't think it is expected.

Did I miss something somewhere or is this a CubeMX bug?

will

Best answer by TDK

The LL library assumes you're going to take care of the details. For advanced timers, this means you have to set the MOE bit. If you want everything taken care of for you, that's what HAL is for.

 

> I needed to add that EnableAllOutputs() call to get it to work, something that wasn't in any of the LL example code

It's there when they use an advanced timer. In this case, TIM1:

STM32CubeG0/Projects/NUCLEO-G071RB/Examples_LL/TIM/TIM_BreakAndDeadtime/Src/main.c at 6bb31c8b4b806b5ada182fcff7f3972f587ef922 · STMicroelectronics/STM32CubeG0 (github.com)

3 replies

STTwo-32
Technical Moderator
September 20, 2024

Hello @Will5 

Could you please share your product complete name.

Best Regards.

STTwo-32 

ST Employee
September 20, 2024

Hello @Will5

I cannot see how the  MX_TIM17_Init() is clearing the MOE bit, which instruction? 

Could you share your code sequence to generate a PWM output? 

Otherwise, there are some examples on generating PWM output using LL drivers in STM32CubeG0/Projects/NUCLEO-G071RB/Examples_LL/TIM/TIM_PWMOutput at master · STMicroelectronics/STM32CubeG0 (github.com) 

 

Will5Author
Associate II
September 20, 2024

Thanks for replying Sarra.S!

The full part number I'm generating for is the STM32G031J6.  It is CubeIDE 1.16.0 (yep, just noticed I'm one revision behind).

Here is the TIM17 code generated by CubeMX:

static void MX_TIM17_Init(void)
{

/* USER CODE BEGIN TIM17_Init 0 */

/* USER CODE END TIM17_Init 0 */

LL_TIM_InitTypeDef TIM_InitStruct = {0};
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
LL_TIM_BDTR_InitTypeDef TIM_BDTRInitStruct = {0};

/* Peripheral clock enable */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM17);

/* USER CODE BEGIN TIM17_Init 1 */

/* USER CODE END TIM17_Init 1 */
TIM_InitStruct.Prescaler = 0;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 25;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
TIM_InitStruct.RepetitionCounter = 0;
LL_TIM_Init(TIM17, &TIM_InitStruct);
LL_TIM_DisableARRPreload(TIM17);
LL_TIM_OC_EnablePreload(TIM17, LL_TIM_CHANNEL_CH1);
TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct.CompareValue = 12;
TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
TIM_OC_InitStruct.OCNPolarity = LL_TIM_OCPOLARITY_HIGH;
TIM_OC_InitStruct.OCIdleState = LL_TIM_OCIDLESTATE_LOW;
TIM_OC_InitStruct.OCNIdleState = LL_TIM_OCIDLESTATE_LOW;
LL_TIM_OC_Init(TIM17, LL_TIM_CHANNEL_CH1, &TIM_OC_InitStruct);
LL_TIM_OC_DisableFast(TIM17, LL_TIM_CHANNEL_CH1);
TIM_BDTRInitStruct.OSSRState = LL_TIM_OSSR_DISABLE;
TIM_BDTRInitStruct.OSSIState = LL_TIM_OSSI_DISABLE;
TIM_BDTRInitStruct.LockLevel = LL_TIM_LOCKLEVEL_OFF;
TIM_BDTRInitStruct.DeadTime = 0;
TIM_BDTRInitStruct.BreakState = LL_TIM_BREAK_DISABLE;
TIM_BDTRInitStruct.BreakPolarity = LL_TIM_BREAK_POLARITY_HIGH;
TIM_BDTRInitStruct.BreakFilter = LL_TIM_BREAK_FILTER_FDIV1;
TIM_BDTRInitStruct.AutomaticOutput = LL_TIM_AUTOMATICOUTPUT_DISABLE;
LL_TIM_BDTR_Init(TIM17, &TIM_BDTRInitStruct);
/* USER CODE BEGIN TIM17_Init 2 */

/* USER CODE END TIM17_Init 2 */

}

 

Here is my code: (the call to MX_TIM18_Init() is earlier)

LL_TIM_CC_EnableChannel(TIM17,LL_TIM_CHANNEL_CH1) ;
LL_TIM_EnableAllOutputs(TIM17) ;
LL_TIM_EnableCounter (TIM17) ;

 

I needed to add that EnableAllOutputs() call to get it to work, something that wasn't in any of the LL example code--and yes, I was looking at the examples for the G071 as you mentioned and they didn't have that call, hence why I was confused for so long.

 

Again, I found the issue by resorting to using HAL drivers that worked, stopped the code and did a dump of all the Timer registers, went back to the LL drivers and did the same thing and compared. All register values were identical except for BDTR.  It had a value of 0xa000 with the HAL drivers and 0x2000 with the LL drivers.  The difference was the MOE bit which clearly disabled the outputs!  To my knowledge I'm not doing anything strange.

Attached is a screenshot of the CubeMX config for the Timer.

Hope that helps isolate things.  I'm still open to it being user error of some kind.

 

will

Will5Author
Associate II
September 20, 2024

Sarra.S:

Just in case it matters, I'm using the STM32G0316-DISCO board and used it as the starting point for the project.

 

will

TDK
TDKBest answer
Super User
September 20, 2024

The LL library assumes you're going to take care of the details. For advanced timers, this means you have to set the MOE bit. If you want everything taken care of for you, that's what HAL is for.

 

> I needed to add that EnableAllOutputs() call to get it to work, something that wasn't in any of the LL example code

It's there when they use an advanced timer. In this case, TIM1:

STM32CubeG0/Projects/NUCLEO-G071RB/Examples_LL/TIM/TIM_BreakAndDeadtime/Src/main.c at 6bb31c8b4b806b5ada182fcff7f3972f587ef922 · STMicroelectronics/STM32CubeG0 (github.com)

"If you feel a post has answered your question, please click ""Accept as Solution""."
Will5Author
Associate II
September 20, 2024

TDK:

Ah! OK, it is kinda user error then.  I know LL means you take care of a lot of the details and I rely heavily on the examples to make sure I don't miss anything.  I see now that the example code I was using as a reference wasn't for an advanced timer and I (incorrectly) assumed that the default settings for all the break stuff would be benign if disabled in CubeMX.  They were for HAL, but not for LL.

In fact, the reason I'm going down the LL path on this small project is I do need to do something weird I don't believe the HAL drivers handle.  I'm doing DMA-based PPM modulation.  So need PWM mode, but need the DMAing to be to the Period register, not the Compare register.  I couldn't see how the HAL could do that natively.  I probably could have made some weird macro calls to force it, but going down the LL path to manage things directly seemed a lot easier.

will

TDK
Super User
September 20, 2024

HAL_TIM_Base_Start_DMA will update the ARR register. But it might not like you calling that along with the PWM.

Also consider using direct register access. It's a lot more straightforward than LL in my opinion.

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