Size of STM32Cube generated code - Page 1
Forum section: electronics / general

author: jyrgen
author_rank: Contributor
timestamp: January 11, 2018, 01:04:26 pm
content: Hi, I have previously made a PCB with an 8-bit AVR using some basic functionality (GPIO, ADC, I2C, SPI, Timer, USART). The final compiled code for the entire application is ~8Kb(text). I now want to do a new version of the board with the same functionality and have changed the MCU to a STM32L0. Since this is my first project I'm using STM32Cube to setup the pin functions and generate that code. When I compile this generated code using System workbench and optimize for size, the size is ~10Kb(text). I'm a beginner on these kind of processors, but is it normal that a code that just sets up the ADC, I2C, SPI, DAC, Timer and USART and does not do anything else is that large?

author: Jeroen3
author_rank: Super Contributor
timestamp: January 11, 2018, 01:33:29 pm
content: Yes. Vendor library code is always bloated (size penalty) and abstracted (speed penalty) that it isn't compact anymore.It was never intended to be that way, it's a library with no guarantees whatsoever, made as application example or quick prototyping to get going on today's vastly complicated microcontrollers.Code will be quicker and mode compact if you cherry-pick the useful bits from the example code.

author: dgtl
author_rank: Regular Contributor
timestamp: January 11, 2018, 02:12:13 pm
content: Yes, ST HAL is large.For smaller and faster code, write directly to registers as you probably did for AVR. Or just accept the waste of flash space and go on, if the rest of your functionality fits in the flash. (usually the onboard flash sizes are much larger than on AVRs). Also, ARM Thumb2 binary code is not so compact as AVR for a lot of use cases, so don't expect too much. In addition, some flash is wasted on larger IRQ tables etc.If you go the without-HAL route, the parts you want to take from generated project are:* cmsis. A couple of headers having your cortex-m cpu specific macros, NVIC irq controller definitions etc.* startup. Either C or ASM file having interrupt vector table with weak functions mapped to default handler; memory clear and flash to ram variable copy loop.* linker map. LD file, which sets up the flash and ram memory layout.* peripheral register header.Having these, you can compile a simple program that runs your code in main().The next step would be setting up the clocks. The simplest way would be to copy the required parts of code from ST HAL. AVR configured the clocks with fuse bits, for ARM processors, typically the CPU wakes up with internal oscillator and your code can configure the clocks as you want in runtime. Typical sequence is following: Start external high-speed osc (HSE), wait until it starts up, configure PLL, set PLL input to HSE, wait for PLL to lock, configure bus clock dividers (to avoid overclocking busses on clock switch), set up correct flash latency, switch to PLL clock.Also, check the end of your uc reference manual. Some ST controller reference manuals have useful code examples there.

author: ogden
author_rank: Super Contributor
timestamp: January 11, 2018, 02:27:54 pm
content: Quote from: jyrgen on January 11, 2018, 01:04:26 pmStm32Cube is useful tool to quickly get code running - for a price obviously. When you are set with pins and peripherals, then you can use your knowledge obtained and (re)write clean & compact initialization code based onhttp://www.st.com/en/embedded-software/stm32snippetsl0.html. There's also stm32f0 snippets. For big projects having plenty of performance/flash/ram it depends - you can stick with Stm32Cube as well.

author: Kjelt
author_rank: Super Contributor
timestamp: January 11, 2018, 02:49:34 pm
content: Besides the points already made I would like to add that setting up a 32 bit micro as the STM32 with more and larger peripherals , clock routing and DMA stuff, even if done by the same SW engineer (so without the automated Cube/HAL bloat) will result in a three to four time larger code than an 8 bit STM8.There is just way more to configure unless you skip configuring all unused peripherals and only use a few.

author: lucazader
author_rank: Regular Contributor
timestamp: January 18, 2018, 05:31:40 am
content: A few extra things to consider:There are quite a few things that the Cube generated projects enable by default, that you may not use in your project.A good example for this is the HAL will sometimes enable and use IRQ handlers what you may not explicitly use in your project. Quite often these can be removed with no impact on functionality, but a noticable reduction in code size.By default your code will likely be setup to compile with little optimizations turned on. eg -Og.If you instead use -Os (optimize for size) and especially LTO (link time optimization) you can greatly reduce code size.In a current project of mine using an STM32F3 the debug build has a compile bin size of ~38KB. The release build (using Os and lto) is only ~26KB.Another option for certain peripherals is to use the LL libraries that st has recently put out. These are lower level libraries that should result in smaller code size. They will offer less customization etc, but this may be a good trade off between development ease and code size for your application.

author: pkplex
author_rank: Contributor
timestamp: January 27, 2018, 09:48:45 am
content: I recently threw a hissy fit and ditched both the normal HAL and system workbench. Switched to the LL drivers, Makefile, and Sublime Text. Had to spend a while altering the Makefile to make it work with C++ and fix a few problems in it, add a flash target, etc. But I found switching from HAL to LL reduced the code size by about 300%. I think a very basic no additional code using HAL was ~6K, and the LL was ~2k.

author: Warhawk
author_rank: Frequent Contributor
timestamp: January 27, 2018, 11:30:23 am
content: I've started with STM32F0 recently, tried HAL, SPL, LL and ended up with CMISS. I really want to know what my MCU does. It also turned out that many things in libraries differ from version to version. If you want a professional and code-efficient code, stick with register access (CMISS). Code snippets from ST are great.It may simply happen that bloatware libraries reduce code execution down to properly written code on 8-b.Just my two cents.

author: Kjelt
author_rank: Super Contributor
timestamp: January 27, 2018, 03:11:40 pm
content: Quote from: Warhawk on January 27, 2018, 11:30:23 amWhat is CMISS ? You mean CMSIS (Cortex Microcontroller Software Interface Standard) ?AFAIK that is good for the Arm cortex core and RTOS interfacing but not for the HAL interfacing, although some extra ports are available but not generic for all ST processor AFAIK ?

author: Siwastaja
author_rank: Super Contributor
timestamp: January 27, 2018, 03:21:34 pm
content: Write it like you do with AVR. All the registers are documented in the Reference Manual. The code size will be small, and code will be more readable. The STM32 peripheral library is just pure horror, not only for bloated size, but it's buggy, hard to use and unreadable as well.Some extra brainwork is needed, for example, you need to remember to enable GPIO clocks from the RCC peripheral, but catches like this exist in the AVR as well. Some peripherals are more capable and hence, slightly more complex to initialize compared to an AVR, but nothing too shocking going on typically.For autogenerated stuff, why not, as long as it does the job easily and in no time; but since you are asking about it, the chances are: just ditch autogenerated shit and get some work done.

author: Warhawk
author_rank: Frequent Contributor
timestamp: January 27, 2018, 05:00:53 pm
content: Quote from: Kjelt on January 27, 2018, 03:11:40 pmCorrect, I meant CMSIS

author: julianhigginson
author_rank: Frequent Contributor
timestamp: February 03, 2018, 04:56:06 am
content: Stm32 HAL is pretty heavy going, but the whole point is, you can use it a lot of ways (learning ADC HAL recently was HELL) and, well, it does mostly work... Then in future you can take a project targeted to one STM32 and map it to a new one... And it should work.. even across series.The biggest problem with stm32cube and HAL and LL libraries, is that they give you all this power to define and setup things in so many ways, but cube in particular gives you no pointers as to what things make sense, and what things plain won't work.. but really that's a common issue with all their documentation, too.. it drowns you in information, but gives no pointers at all on how to combine the information to do anything useful.The best they do is give you some example projects, but those are trivial to the point of being useless most of the time..

author: andyturk
author_rank: Frequent Contributor
timestamp: February 06, 2018, 12:45:18 am
content: Quote from: julianhigginson on February 03, 2018, 04:56:06 amAgreed. It's a problem that's not unique to STM32.Most OEM libraries are designed include APIs for all the functionality offered by the hardware. That's usually a lot of stuff to jam into one API (on modern mcu, anyway), and the biggest reason (IMO) why OEM libraries are unwieldy. In the case of the STM32 ADC, the HAL layer for that is super complex because the ADC is super complex.I've had good luck just going right to the registers with the ADC because I only need a few specific things done.

author: Siwastaja
author_rank: Super Contributor
timestamp: February 07, 2018, 09:02:37 am
content: Theactualproblem with STM32 libraries is that they do not provide any encapsulation or abstraction whatsoever - so you just need to somehow "know" each and every bit and piece you need to do to initialize a device. And inaddition, you need to know how to handle the library overhead, which is typically around 1000%.So what you end up with is either of these two:1) you copypaste other's code2) you use an autogeneration toolAt this point, you could have just as well copypasted (or autogenerated) a more compact, robust, and readable codewithoutthe extra overhead from the "library".And guess what, after copypasting readable, meaningful, compact and efficient code for a few times, you start learning, and need less copypasting in the future.The complex library also gives the false impression that everything underneath must be "super complex". For example, the STM32 ADCs are far from super complex - initializing it properly is around 5-6 lines of code, no big catches, nothing strange going on - only a few more operations than on a comparable AVR (around 3 lines). Sure, when you do it through thelibrary, it's so many lines (typ. 20-30), full of long names, that the only way around is copypasting or autogenerating.In fact, looking at the ADC initialization code now, it's not much different from the AVR ADC at all. The only "extras" are that you need to enable the ADC from the RCC registers first, and change the input pin to analog mode ("11" in MODER bits, similar to DDR in AVR, but two bits per pin because of more functionality). Then you need to set the ADC prescaler, channel(s) you want to convert, enable the ADC and give a start trigger, just like in AVR. If you want DMA, it's 7 lines of initialization more, but saves it back elsewhere since you don't need interrupts nor polling at all, often not any kind of ADC control code after the init!A proper library would have an usable interface and would deal with register-level stuff internally. In STM32, they mostly wrap each and every register operation for you to make inefficiently.The solution is simple: don't use those libraries. The "AVR-like" traditional access is, in almost all cases:1) definitely easier than using the libraries, by an order of magnitude2) easy enough that you can stop resorting to copypasting/autogenerating after gaining a bit of experience (100% impossible to do with the libraries - even if you actually learned each character needed by heart, justtypingeverything out would take too long!)If you need complex network or USB filesystem stacks, etc., that would be different.