Timer1 only works when handle is on stack vs. static memory on STM32F1x - Page 1
Forum section: electronics / general

author: uer166
author_rank: Super Contributor
timestamp: August 22, 2018, 07:31:26 am
content: Consider setup code for timer1 + PWM:if TIM_HandleTypeDef (first line in function) is allocated as static, or outside the function, the complementary output stops working, wtf??Code:void setup_timer(){TIM_HandleTypeDef TIM_HandleStruct;TIM_OC_InitTypeDef TIM_OC_InitStruct;GPIO_InitTypeDef GPIO_InitStruct;TIM_BreakDeadTimeConfigTypeDef TIM_DeadTimeStruct;TIM_HandleStruct.Instance = TIM1;TIM_HandleStruct.Channel = HAL_TIM_ACTIVE_CHANNEL_1;TIM_HandleStruct.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;TIM_HandleStruct.Init.Prescaler = 31;// 2.064516 MHzTIM_HandleStruct.Init.CounterMode = TIM_COUNTERMODE_UP;TIM_HandleStruct.Init.Period = 255;// more or less 8 bit PWMTIM_HandleStruct.Init.RepetitionCounter = 0;TIM_HandleStruct.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if(HAL_TIM_PWM_Init(&TIM_HandleStruct) != HAL_OK){asm("bkpt 255");}TIM_OC_InitStruct.OCMode = TIM_OCMODE_PWM1;TIM_OC_InitStruct.Pulse = 10;TIM_OC_InitStruct.OCPolarity = TIM_OCPOLARITY_HIGH;TIM_OC_InitStruct.OCNPolarity = TIM_OCNPOLARITY_HIGH;TIM_OC_InitStruct.OCIdleState = TIM_OCIDLESTATE_RESET;TIM_OC_InitStruct.OCNIdleState = TIM_OCNIDLESTATE_RESET;if(HAL_TIM_PWM_ConfigChannel(&TIM_HandleStruct, &TIM_OC_InitStruct, TIM_CHANNEL_1) != HAL_OK){asm("bkpt 255");}GPIO_InitStruct.Pin = GPIO_PIN_13;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_8;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);if(HAL_TIM_Base_Start(&TIM_HandleStruct) != HAL_OK){asm("bkpt 255");}TIM_DeadTimeStruct.DeadTime = 70;if(HAL_TIMEx_ConfigBreakDeadTime(&TIM_HandleStruct, &TIM_DeadTimeStruct) != HAL_OK){asm("bkpt 255");}if(HAL_TIM_PWM_Start(&TIM_HandleStruct, TIM_CHANNEL_1) != HAL_OK){asm("bkpt 255");}if(HAL_TIMEx_PWMN_Start(&TIM_HandleStruct, TIM_CHANNEL_1) != HAL_OK){asm("bkpt 255");}__HAL_TIM_SET_COMPARE(&TIM_HandleStruct, TIM_CHANNEL_1, 240);}

author: Psi
author_rank: Super Contributor
timestamp: August 22, 2018, 07:35:12 am
content: This doesnt surprise me much.The standard peripheral library is a POS.It does nothing except make things harder.

author: AndyC_772
author_rank: Super Contributor
timestamp: August 22, 2018, 07:40:19 am
content: I'm afraid I have to agree, ST's HAL performs obfuscation, not abstraction.Nevertheless, if the code works (or not) depending on how variables are allocated, then you should be able to see a difference in the disassembly.I don't really see an alternative to going through the assembly code to see what is actually going on when you call the various HAL functions, and see what's getting set incorrectly and where.You might possibly get closer to the problem sooner by examining the contents of the timer registers in each of the two cases, and just exploring the code that sets whichever register(s) end up different in the working vs non-working cases.

author: uer166
author_rank: Super Contributor
timestamp: August 22, 2018, 07:58:22 am
content: Ah! This is strictly my screw-up. On the stack the handle struct happened to initialize to 0 on all fields. I unknowingly didn't initialize all fields, and was relying on the 0 initial state. When put in static memory it wasn't zeroed-out, and had some random crap, breaking it.@Andy, found thanks to advice of checking all registers (or in this case the struct at initialization).

author: andersm
author_rank: Super Contributor
timestamp: August 22, 2018, 08:33:25 am
content: Quote from: uer166 on August 22, 2018, 07:58:22 amMemory allocated on stackisn'timplicitly initialized. If it happened to work, it was purely by chance. Statically allocated memory, on the other hand,isinitialized to all zeroes, unless you are using some horribly broken compiler.

author: JPortici
author_rank: Super Contributor
timestamp: August 22, 2018, 08:54:41 am
content: Quote from: andersm on August 22, 2018, 08:33:25 amLatest Embedded Muse newlsletter addressed thisQuote from:http://www.ganssle.com/tem/tem356.htmlThen i suppose it depends, on the compiler.For example, XC16 (which is GCC) has a linker option to initialize data sections (variables in use) whereas XC8 (which is not GCC, and its targets are 8bit PIC with relatively low ram) has a linker option to initialize bss and/or the rest data memory, so everything.When selected, variables that are explicitely initialized are initialized to their values, variables that are not explicitely initialized are initialized to zero.Local variables that are in the CPU registers arenotinitialized, elements added to the stack arenotinitialized. The initialization only happens at startup, when static memory is allocated

author: Siwastaja
author_rank: Super Contributor
timestamp: August 22, 2018, 09:01:21 am
content: Initializing this trivial timer/PWM "by hand" is maybe 4 to 5 lines of simple code with no stack variables nor static variables required at all, so much less footprint for mistakes like that.This code is obfuscated beyond readable and indeed prone to mistakes.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: August 22, 2018, 01:35:09 pm
content: put aCode:memset(&TIM_HandleStruct, 0, sizeof(TIM_HandleTypeDef ));in the function an you'll know if its an initialization issue.

author: nano
author_rank: Contributor
timestamp: August 22, 2018, 02:35:49 pm
content: Quote from: andersm on August 22, 2018, 08:33:25 amExactly!Just as an additional information: For Cortex-M processors it’s not actually the compilers responsibility.You have to make sure to include the proper CMSIS startup files (as supplied by the chip manufacturer) in your projects.

author: newbrain
author_rank: Super Contributor
timestamp: August 22, 2018, 02:59:29 pm
content: Quote from: JPortici on August 22, 2018, 08:54:41 amYes, maybe too quickly. I would not have expected this from him...From theC99 draft(not changed in the standard AFAICR), ch 6.7.8, clause 10 in "Semantics":QuoteOf course, in an embedded environment the zeroing and initializing task is carried out by the startup code, as nano correctly points out.