STM32CubeMX code generation -- any other traps? - Page 1
Forum section: electronics / general

author: ebastler
author_rank: Super Contributor
timestamp: October 18, 2019, 06:51:06 am
content: After a bit of a false start a couple of months ago, I have finally begun to get up to speed with the STM32 family. I am using the STM32CubeIDE, and its CubeMX component to configure the I/O and peripherals and generate initialization code. Starting small, with an STM32F103 processor (on a "Blue Pill" board).Spent a looong evening yesterday trying to figure out why my first attempt at a timer interrupt handler didn't seem to work. To make a long story short -- I eventually realized that after 216clock cycles, the SysTick interrupt kicked in for the first time, and encountered an undefined interrupt vector. While the SysTick interrupt is non-maskable and apparently always activated, the CubeMX code generator had not bothered to generate a default handler for it. Once I added an empty SysTick_Handler function to stm32f1xx_it.c, everything worked.My question: Are there further, similar traps for the uninitiated? Any other things I need to manually initialize or define even though I don't use them?(More complaining: It also took me a while to figure out that I need to manually start the time base for by timer. The automatically generated initalization code does not include the call to HAL_TIM_Base_Start_IT. Why not?!)

author: ebastler
author_rank: Super Contributor
timestamp: October 18, 2019, 09:52:32 am
content: To partly answer my own question: Looks like CubeMXdoeshave the ability to generate IRQ handlers. There are checkboxes for this on the "code generation" tab of the NVIC configuration window -- section 4.4.14 and fig. 67 of the CubeMX manual. So I'll reword my complaint on that front to: "Why aren't these enabled by default, for the always-enabled interrupts like SysTick?"The basic question remains: Any other traps I should be aware of? Things like: "You definitely need to configure/enable/write code forthis, even if you are not actively using it."Thanks!

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 18, 2019, 03:01:52 pm
content: Don't use these generators. Start with the HAL examples directly (Projects subdirectory of the Cube SDK). You'll waste a lot less time IMO.

author: mark03
author_rank: Frequent Contributor
timestamp: October 18, 2019, 03:31:50 pm
content: Or, if you want to waste even less time, try ditching the HAL too and just program directly using the register structs defined in the CMSIS header file. Reference manual open on one screen, code editor on the other.

author: thm_w
author_rank: Super Contributor
timestamp: October 18, 2019, 10:05:29 pm
content: I already had a SysTick function implemented and I didn't check anything off, but I'm using the standalone app so perhaps there is a bug somewhere:Code:/*** @brief This function handles System tick timer.*/void SysTick_Handler(void){/* USER CODE BEGIN SysTick_IRQn 0 *//* USER CODE END SysTick_IRQn 0 */HAL_IncTick();/* USER CODE BEGIN SysTick_IRQn 1 *//* USER CODE END SysTick_IRQn 1 */}You also need to combine the generated code with the HAL examples to get an idea of what is necessary. Often the "startup" is more complicated than just calling start, so they leave that code out as it would not make too much sense to generate it. Sort of what SiliconWizard is suggesting.Are you using SWD debugging?

author: MT
author_rank: Super Contributor
timestamp: October 18, 2019, 10:25:49 pm
content: Quote from: ebastler on October 18, 2019, 09:52:32 amSystick can be turned off in the Systick register, but does have higher priority then other timer interruptsand can delay other interrupts.For example i do like this in "bare metall" to use a Timer as interrupt but i'm a gardener not a software dudeIRQ config calls a tiny 2 or3 line function in core_cm4.h who do the actual priority setting:/******************* NVIC TIM7 IRQ config *************************************/NVIC_ClearPendingIRQ(TIM7_DAC2_IRQn); //Clear Pending TIM7 IRQn bitNVIC_SetPriority(TIM7_DAC2_IRQn,4); //TIM7 IRQn have priority level 4NVIC_EnableIRQ(TIM7_DAC2_IRQn); //Enable interrupt from TIM7 UP global/********************** TIM7 Interrupt request generation ************************/TIM7->DIER |= TIM_DIER_UIE; //UPdate signal as Interrupt requestTIM7->CR1 |= TIM_CR1_CEN; //Tim7 enabledThen i do this in Main:/************* TIM7_IRQ for Bananas ***************************/void TIM7_DAC2_IRQHandler(void){TIM7->SR = 0b00; //Clear CCIE and UIE, necessary else ISR in endless loopbananas(); //Run Bananas function}

author: ebastler
author_rank: Super Contributor
timestamp: October 19, 2019, 05:51:51 am
content: Thank you, guys -- very helpful!@siliconwizard, @mark03: Yes, I am tempted to move away from the HAL and maybe from CubeMX for the time being. Abstraction and automated code generation are great, but during the learning phase they add two more layers to get ones's arms around, and if something does not work as expected, it tends to be unclear in which layer the problem lies.Unfortunately, most of the examples and forum discussions out there seem to use the HAL, so it's not easy to get started on the low-level/CMSIS layer either. Got stuck the other night just figuring out what the ISRs are called...I did realize that CubeMX can generate low-level initialization code insted of HAL calls; I might use that approach for the next steps.@MT: Thanks for the code example, and for pointing out the possible SysTick interrupt priority issue. In my first STM32 application I definitely need SysTick interrupts at a lower priority than the (130 kHz) timer interrupt I plan to use! I have not tried this, but it sems one can assign priorities to all interrupts including SysTick as needed, right? Or I can disable SysTick entirely; don't think I will need it.@thm_w: Fully agree -- one needs to look at code examples. Assuming that I could just add my user functionality to the CubeMX-generated startup code and be done with it was essentially the trap I fell into at first. I did eventually find the "official" STM code examples, in the depths of the CubeIDE directory trees...Also got SWD debugging to work eventually. Things are complicated by the fact that the CPU on my "Blue Pill" actually isn't a genuine STM chip, but a China clone (labelled as an STM32!). There is an older thread in the Beginners section which dicusses the necessary work-arounds to get the OpenOCD debugger working.So overall, I am making progress, slowly. Now that I have adjusted my expectations regarding the initial rate of progress, it's even fun again!

author: T3sl4co1l
author_rank: Super Contributor
timestamp: October 19, 2019, 06:06:33 am
content: Disclaimer: haven't worked with it personally. Have seen it used, and picked/traced through a little code.It's very verbose. Kinda has to be to be flexible enough, but it's not implemented just in headers as compile-time hooks, it's part that, part generated files, part runtime. So the code is massive (like 10 or 20kB to start with), and the performance is much slower than working with the hardware directly.ISRs for example are implemented as callbacks. The ISR is a generic handler which calls a function set up by the init. Interesting side effect: if you ever want to change handlers at run time, you can. (No idea how well this is documented, if they suggest it at all?) So, there's a lot of overhead, probably a hundred CPU cycles (or more?) for that, plus several words of memory (not that a few words here and there will be missed, but the whole thing is like this).I forget if every interrupt is implemented out-of-the-box and only the used ones have non-null callbacks, or if only the used ones are linked at all and the rest default to a dummy ISR. Oh, or if they all go through the identical ISR but check the interrupt ID and look it up in a callback table or something.Code is also repeated many times, between init and drivers and config functions. Headers or functions are NOT generated to coalesce these operations. This makes maintenance a pain, once the project has evolved beyond Cube's scope. And again, wasteful of Flash.Think of it as a mfg-brand Arduino. It's fast to get started, and can definitely be used for real work, but be very mindful of its limitations, and never be afraid to look at the sausage getting made. Trace the chains of function calls, see how it's implemented. Never take it at face value that it's doing something, always verify that it's generated what it's supposed to have generated. It is a poor craftsman who blames their tools, etc.Tim

author: techman-001
author_rank: Frequent Contributor
timestamp: October 19, 2019, 12:02:41 pm
content: Quote from: ebastler on October 19, 2019, 05:51:51 amI was lucky and started with a STM32F0 Discovery board in 2014, they're only about $10 - $15 and include a swdusb interface that works, the mcu is brand new from the STM factory, in other words, no clones or fakes.The other Blue Pill problem is that the STM32F103 GPIO's are anightmareto configure compared to the later STM32F0 or STM32F0+ mcus.To a Arduino MEGA user the Blue Pill probably seems like advanced alien tech, but it's not. This was STM's first Cortex-M3 in 2011 and the age is really showing.I recommend that you ditch the Blue Pill and get a proper STM32 Discovery or Nucleo board with a more modern MCU because it will make your learning curve a LOT easier.I really don't get why people keep buying this Chinese Blue Pill junk, here in Australia a cup of Coffee costs more than a Blue Pill !

author: Boscoe
author_rank: Frequent Contributor
timestamp: October 19, 2019, 12:13:05 pm
content: I’ve been using the HAL for a few years now and it isn’t perfect but it is good. There are some issues I’ve come across like the SPI read for the STM32F103VB will always read one more byte than you request but you can fix it. Writing your own HAL is an option but it’s a lot of work and lines of code. How do you know you won’t make more mistakes than ST?

author: MT
author_rank: Super Contributor
timestamp: October 19, 2019, 04:17:36 pm
content: Quote from: ebastler on October 19, 2019, 05:51:51 amSome peripherals are fixed priority but many are settable. The NVIC is not an easy thing to comprehend when it comes to how the level and priority works pre-emption priority and subpriority,You have from 0 to 15 preemption priority then each one can be divided into a sub priority apparently a low level interrupt can block a high level one and everything becomes very complicated so i try to keep the interupt priorities as simple and clear as possible. Anyho you should be able to change Systick priority position. But i have to read up on this NVIC yet again!https://embeddedgurus.com/state-space/2014/02/cutting-through-the-confusion-with-arm-cortex-m-interrupt-priorities/https://community.arm.com/developer/ip-products/system/b/embedded-blog/posts/cutting-through-the-confusion-with-arm-cortex-m-interrupt-prioritiesAs others have recommended, swap to a newer ST device instead of various "old pills"! I boldly suggest you go full bananas, H750/H743 since its easier to traverse down to simpler models then upwards, you kinda learnt the complex stuff the better way so to speak.Not many lines are needed to enable Systick as interrupt gen, e.g F3xx in baremetal is:/***************** Systick frequency ****************************************/SysTick->CTRL |= SysTick_CTRL_CLKSOURCE; //AHB 72Mhz clk (mask if AHB/8)SysTick->VAL = 0; //Clears counter and Flag register to 0SysTick->LOAD |= 2194315; //33Hz systick for Sysclk of = 72Mhz/********************* Systick Exeption Interupt ****************************/SysTick->CTRL |= SysTick_CTRL_TICKINT; //Enable SysTick Exception request at count 0SysTick->CTRL |= SysTick_CTRL_ENABLE; //Enable SysTick timer.In main are:/********************* Systick GPIO pinjerk ********************/void SysTick_Handler(void){pinjerk(); //Run GPIO pinjerk'ing function on every 33hz SYS Tick}

author: ebastler
author_rank: Super Contributor
timestamp: October 19, 2019, 07:42:46 pm
content: Quote from: techman-001 on October 19, 2019, 12:02:41 pmPersonally, I didn't select the Blue Pill for its low price, but for the form factor. It does have a nice balance of compact format and a decent number of available I/Os, and I like integrating compact off-the-shelf µC boards for one-off projects. But realizing that one apparently can't be sure anymore of getting a genuine CPU has largely spoilt that particular board for me.Just came across this one:https://robotdyn.com/stm32f303cct6-256-kb-flash-stm32-arm-cortexr-m4-mini-system-dev-board-3326a9dd-3c19-11e9-910a-901b0ebb3621.htmlA Cortex M4, with twice the flash and RAM capacity, in the exact same form factor and pinout. And since it is less popular than the Blue Pill, and to my knowledge no Chinese clone of the STM32F303 CPU exists, it will hopefully be a safer bet to buy. I have ordered a couple.

author: thm_w
author_rank: Super Contributor
timestamp: October 21, 2019, 09:47:52 pm
content: Quote from: ebastler on October 19, 2019, 07:42:46 pmGood choice, thats a reasonable price considering its about the same as buying 1,000pc quantities from digikey.There should be no functionally equivalent clones, quite a few differences over the F103 (ADC/DACs/PGA etc).Quote from: Boscoe on October 19, 2019, 12:13:05 pmOh I'm 100% certain my code would have more bugs in it than ST