Migrating from AVR to STM32 - Page 1
Forum section: electronics / general

author: Sudo_apt-get_install_yum
author_rank: Regular Contributor
timestamp: January 28, 2021, 01:39:41 pm
content: Hi folks!Like the title says, I’m moving away from AVR microcontroller series to the STM32 family.I’m doing this because the STM32XX provides better performance, power use, cost and peripheral support over the old 8-bit AVR family.I also see it as a big bonus, understanding the more modern processor cores.I’m quite comfortable with the low level AVR things, written a lot of code in ASM and C/C++ but I’ve never used ASF. I always felt it to be unnecessary and add too much overhead for most things you could do on an 8-bit MCU.I made a breakout board for the STM32L010K4 and have programmed it through STM32Cube-IDE and got a "blink" program up and running. The blink code i wrote was configured through CubeMX and uses HAL, their alternative to ASF.The code uses 80.5% RAM(1.6 of 2K) and 54.5% FLASH(8.7 of 16K) and it makes me angry, so much waste.Is it normal to have this much memory overhead?I’m used to configuring registers/ peripherals myself and seeing 32K FLASH as infinite storage and 2K RAM as more than enough.Have some I/O input, use the T/C, sample something with the ADC and send it somewhere over a protocol.This would result in a few percent of what this blink sketch is using.Im aware that the STM32L010K4 (cortex M0+) is more complicated and requires more configuration but this is crazy.Everyone on the web seems to use HAL. I would be more than happy to configure peripherals myself, maybe use HAL for more complicated things but I’m having a hard time starting out.Does anybody have good appnotes, books or blogs with getting started with STM32 without the bloated abstraction layer.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: January 28, 2021, 01:53:04 pm
content: My first dip into STM32 was with the Pandafruits STM32 primer:It's a very short introduction about the really low level stuff, such as fiddling a bit with linker scripts.http://pandafruits.com/stm32_primer/stm32_primer_hardware.phpA book I like very much is:STM32_Beginning_Developing_with_FreeRTOS_libopencm3_and_GCCISBN-13 (pbk): 978-1-4842-3623-9ISBN-13 (electronic): 978-1-4842-3624-6Hackaday has some recent articles about STM32.(Avoid the "Blue Pills", the "Black Pills" are probably still good for as long as it lasts).And of course, sites like github and gitlab have loads of "example" projects, working with different frameworks. (or none at all)I have used serial sathosimn (which exposes all 3 UARTS of an STM32F103C8T6 over USB as CDC (slightly tested on my linux box. It worked for me).I've also put one of the GRBL ports for STM32 in such a chip and it also works

author: newbrain
author_rank: Super Contributor
timestamp: January 28, 2021, 02:51:41 pm
content: Something is not quite right with your project:Code:------------------- Memory utilization report -------------------Used FLASH: 5576 bytes out of 16KB (34%)Used SRAM: 44 bytes out of 2048 bytes (2%)========== Project Build Summary ==========TestL0 built in 00:01========== Build: 1 Succeeded, 0 Failed, 0 Skipped ==========Yes, FLASH occupation is not trivial, but this is without any kind of optimization.-O3 (speed):Code:------------------- Memory utilization report -------------------Used FLASH: 3920 bytes out of 16KB (23%)Used SRAM: 44 bytes out of 2048 bytes (2%)Still a lot, but more tolerable.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 28, 2021, 02:56:00 pm
content: Skip all the HAL and other crap. You'll thank yourself later for being able to actually do projects instead of debugging broken and limited libraries.You'll have the advantage of knowing how to do it on AVR. The same methodology works for STM32.Yes, porting between different chips is always some work. This is equally true when using the STM32 HAL, since it doesn't really completely abstract the hardware away (that would be impossible to do). Real projects tend to use significant part of the resources of the MCU, meaning there is the task of mapping your application to the resources, no one has automated it for you.

author: capt bullshot
author_rank: Super Contributor
timestamp: January 28, 2021, 03:05:25 pm
content: Quote from: Sudo_apt-get_install_yum on January 28, 2021, 01:39:41 pmWelcome to another world.One doesn't care too much about Flash / RAM use here, just don't use the smallest derivative. A reasonable starting point would be a derivative with 128k Flash and 20k RAM.The modern STM HAL is bloated indeed, old versions of the STM32 STDFW just did the GPIO and some basic peripheral initializations and that's it. Long time gone, and no useful way back. You might want to check the LL api instead of HAL. Or just switch over to something completely different, e.g. using the drivers etc. that come with ChibiOs, this is a real time OS that'll come in handy at some point anyway. Most of my projects use an RTOS today.

author: Tagli
author_rank: Contributor
timestamp: January 28, 2021, 03:54:33 pm
content: I prefer to avoid using HAL. You need to study reference manual anyways in order to use STM32 effectively. So, in reality, HAL can't abstract you from the hardware unlike its name suggests. Without the full knowledge of the reference manual, you just find yourself fighting with HAL, trying to understand the meaning of options & settings in CubeMX (or CubeIDE). The reference manual is all you need to know, so there is no point of learning the working details of some weird framework IMO.It's true that there are some variations among the hardwares belonging to different families of STM32. But they are not many or hard to learn. They are the same more or less. For example, GPIO configuration was different in old F1 series, but then it remains same in other families. Or DMA configuration was a little bit different between F1 & F4. But you will get used to it, don't worry. You already have the experience of register level programming.But I still recommend using CubeMX to see pin configurations and clock tree settings. Once you know which pins to use for hardware modules and the values needed for clock prescalers, you can easily use these settings in your register level code.I have switched to C++ (from C) recently and started to create some thin hardware wrapper classes to make it easier to configure hardware modules. I think, after spending some time in register level programming, you will end up with your own libraries and everything will become easier.

author: Sudo_apt-get_install_yum
author_rank: Regular Contributor
timestamp: January 28, 2021, 04:32:05 pm
content: Quote from: Siwastaja on January 28, 2021, 02:56:00 pmQuote from: Tagli on January 28, 2021, 03:54:33 pmI’m lumping your post together since you have a similar outlook on this.I’m not to concerned with the portability of the code between processors. Most of my projects are self-contained and I rarely switch processor mid project. I always write some sort of an abstraction layer when writing drivers and make them self-contained.What would be a typical workflow? I don’t have any fancy environment like Keil or AIR so will be using CubeIDE combined with CubeMX.Do i generate the base of the project in CubeMX or do I start from scratch, setting up the linker and all config files on my own?Is there a way to split all the generated functions and add them in a separate file instead of having a huge main file?Is there any way to prevent the generator from constantly removing my user code? I have checked the box "Keep User Code when re-generating" but it doesn’t seem to do anything.Below is my simple but large code. I made a fresh project and removed the minimum heap & stack size.

author: Tagli
author_rank: Contributor
timestamp: January 28, 2021, 04:50:59 pm
content: I use STM32CubeIDE and create anemptyC++ project. But it needs some work after that. I download CMSIS & ST's Cube package, (just for the up-to-date device headers), from their websites. After copying them into my project directory, I include them in the compiler settings by showing the folders as the include directories.ST's Cube packages actually include a version of CMSIS, so you don't need to download it separately unless you want the latest version.When creating the new project, STM32CubeIDE creates the linker script and startup files automatically. I'm not sure but IDE may skip creating some of them. But you can find them also in CMSIS and Cube packages.Here are my example Blinky projects for STM32F103C8 in STM32CubeIDE, in C & C++:https://bitbucket.org/tagli/blinky.cube/src/master/https://bitbucket.org/tagli/blinkypp.cube/src/master/Some of the header files in these example projects aren't necessary as they are related with other devices. But I didn't bother cleaning them. You will probably need to change the GPIO settings, because they are somewhat unique to old F1 series.

author: Kleinstein
author_rank: Super Contributor
timestamp: January 28, 2021, 05:17:48 pm
content: One can use cubeMX and the graphical environment to create code for the initialization and can still decide of one wants to than use HAL, the less documented LL libs or direct register access. One can add the code directly to the main.c file or use include to have moast of your own code in deparate files.The register naming is a little different from the µC documentation. If in doubt look in the CMSIS include files for the register and constant names.When using HAL one ideally does no longer needs the direct register access, but there are quite a few routines and constants for the settings one essentially has to look up everytime.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 28, 2021, 06:34:35 pm
content: For STM32, an alternative to the full HAL that is less bloated is the LL library. Lower level, but still makes portability to other STM32 MCUs easier.

author: techman-001
author_rank: Frequent Contributor
timestamp: January 30, 2021, 05:02:26 am
content: Quote from: Sudo_apt-get_install_yum on January 28, 2021, 01:39:41 pmHow about a bootable blinky binary that is only 76 bytes ?Code:@ blink.s@ Assembly language Blinky example for stm32f051 mcu@ Board: https://mecrisp-stellaris-folkdoc.sourceforge.io/stm32-boards.html?highlight=green%20pill#why-not-make-your-own-green-pill@ led: PB-8 pin 32@ Copyright 2020 <terry@tjporter.com.au> Released under BSD License, see COPYING.TXT.cpu cortex-m0@ Tell the assembler what model of Cortex-M this is for.thumb@ Cortex micros only understand thumb(1) code.include "gpio-equates.s"@ GPIO action labels.include "bitposn-equates.s"@ A list of ".equ BIT0, 0x00000001", " etc.include "STM32F0xx-tp1.svd.equates.s" @ Every register and bitfield equate from Svd2Forth.syntax unified@ Use newer style instructions.global main@ Makes the symbol visible to ldVector_Table:.word 0x20000000 @ Atack pointer value when stack is empty 0x20000000ResetVector: .word main + 1 @ Reset Handler.text @ what follows is codemain:ldr r1, = RCC_AHBENR@ AHB Peripheral Clock enable register @ 0x40021014ldr r2, = RCC_AHBENR_IOPBEN @ I/O port B clock enable = 0x40000str r2, ldr r1, = GPIOB_MODER@ GPIOB port mode register @ 0x48000400ldr r3, = OUTPUT << GPIOB_MODER_MODER8@ Set PB-8 bit as output = 0x10000str r3, ldr r1, = GPIOB_BSRR@ GPIOB bit set/reset register @ 0x48000418ldr r4, = GPIOB_BSRR_BS8 @ PB-8 on = 0x100ldr r5, = GPIOB_BSRR_BR8 @ PB-8 off = 0x1000000led_on:str r4, bl delayled_off:str r5, bl delayb led_ondelay:lsls r0,r4, #12 @ r4 = 0x100 shifted left 12 times = 0x100000. Delay about 1 second @ 8MHz clockloop:subs r0,r0,#1bne loopend:bx lr@ return to caller@ binary = 76 bytesI agree with Siwastaja and others who said words to this effect, "Skip all the HAL and other crap. You'll thank yourself later for being able to actually do projects instead of debugging broken and limited libraries."They may not have been thinking of Assembly Language at the time, but really, how hard does the above source look ?My code is very pedestrian (I'm an electronics tech), I always go for readability and maintainability over everything else, but I have a Blinky written by Matthias Koch that is only 28 bytes on the same STM32F051 MCU.

author: Sudo_apt-get_install_yum
author_rank: Regular Contributor
timestamp: January 30, 2021, 03:06:45 pm
content: Nice seeing a small binary for the STM32, not a common sight when scouring the internet!Like i said in the post, id gladly skip HAL. I never liked ASF and feel the same with HAL from my limited experience with STM32 MCU's.I’m comfortable with writing assembly for AVR, had a few collage courses in it and have written a few projects in it.I’m not really interested in writing assembly for ARM processors, il probably continue writing ASM for simpler AVR projects but keep to C or C++ for the STM32’s.I’m determined to learn the actual underlying architecture but I’m having a hard time getting started. There is a lot of recourses on the internet but most talk about HAL.Can you recommend any books, blogs or papers?How do I set up the environment in a proper way, without using the configuration tools?

author: Siwastaja
author_rank: Super Contributor
timestamp: January 30, 2021, 03:24:45 pm
content: There is not much "environment" to set up, that's the whole point, IMHO.Gethttps://launchpad.net/gcc-arm-embeddedThe hardest part, IMHO, is to come up with a linker script. On avr-gcc, that is autogenerated / included from somewhere behind your back. Try to google STM32 linker script, I'm sure you'll find examples.Startup code is easier to understand, basically just get the addresses from the linker script and run simple loops to zero .bss and copy .data. I'm sure examples are available.Then just start writing code, including the ARM/STM32 headers only so you have #defines and struct typedefs for accessing the peripheral registers with the names given in the reference manual.I really haven't seen a proper tutorial. I've been thinking about writing one but have better things to do... Finding out everything by trial and error is time consuming, the bright side is it forces you to learn. When I come from AVR, I used a helpful tutorial made by some Swedish Ubuntu fan but can't find that from the 'net anymore. In any case, it had a few catastrophic small mistakes that made me lose a lot of time. Namely the stack pointer was initialized incorrectly, preventinga fewopcodes and most library functions from working yet worked OK much of the time.Using bare gnu tools and understanding the computer science basics has the significant advantage that it stays the samefor decadesto come, and also between different manufacturers!

author: Jeroen3
author_rank: Super Contributor
timestamp: January 30, 2021, 03:25:31 pm
content: Quote from: Sudo_apt-get_install_yum on January 28, 2021, 01:39:41 pmHow long did this blinky take you?Quote from: techman-001 on January 30, 2021, 05:02:26 amHow long did that take you?The code generation and hal can be quite useful. Not for a blinky, but other things. Being able to setup via a gui is nice.Not having to worry about inter-chip differences, just spin up a new project, link to the application code that is somewhere else.Eg: setup ADC with DMA and just call yourdata_frame_input(struct *, size_t samples)without worrying about any details in code, only gui, is very fast!The HAL also doesn't block you from going to registers yourself. For example, I use TIM3 in a library, so just tick "enable" in the config and call the lib not the HAL_TIMx....Learn to respect the abstraction it offers. It's useful. And it also tells your when you're doing it wrong with the asserts.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 30, 2021, 03:31:14 pm
content: Abstraction is also a limitation.Someone's else abstraction needs to be put under scrutiny; is it the right tool for the job?Writing your own abstraction layer has the advantage of being very lean because you know what you need.I think I haveneverused an ADC in such a way that I could just call a function to initialize a fixed-length transaction to a buffer, not even once. No; I may sync it to the timers, I generate interrupts, I utilize injected measurements, and so on.If I want a computer, I use a computer, like a Raspberry Pi. Then I can run linux and have astandardizedand fairly consistent and capable POSIX interface to high-level functionality.But when I design in a microcontroller, I tend to do timing-critical control, something the software can't do alone, and something where the peripherals tend to be used beyond the "trivial" example use case. Most of my applications require at least some HW feature of some peripheral that simply can't be accessed or used through the STM32 HAL library (at least not easily / in a portable manner). Simple as that. I either don't use HAL at all, or create a strange mix of code where it is used in some places, and not used somewhere else, and where I need to write code twice (once with HAL, then without when I hit the limitations), or I could of course give up and not do the project at all.Often the peripheral access itself is some 2-3 lines of code. I may abstract it behind my own function for easy maintainability or portability.But I'm sure HAL is fine when you are mostly doing simple applications and are ready to call in an expert when you hit the wall.And quite frankly, it tends to go in such a way that when others are starting the discussion about the merits of all the fine layers of abstraction (including STM32 HAL, code autogeneration, RTOS...) and how they should be used, I have already finished the project without. I have my own 71 lines-of-code long helper header to abstract the most widely used STM32 peripheral operations such as playing around with GPIO and DMA, makes code more readable.When did it become a matter of pride to reveal you prefer a point-and-click interface instead of writing code? I mean, that's fine if it floats your boat, but really, if you want to work on actual projects and get some work done you should be confident writing code. If that feels difficult in comparison to point&click, you are writing the code wrong. And I don't blame you, many of the STM32 examples around the 'net need like 20 lines of code to toggle an IO. Really it should be an oneliner. If you struggle with code, my hint is, look for better ways to write that code (you can stay in C language, trust me, it's not the problem) instead of replacing it with a GUI autogenerating a horrible piece of spaghetti mess.

author: techman-001
author_rank: Frequent Contributor
timestamp: January 30, 2021, 11:05:29 pm
content: Quote from: Sudo_apt-get_install_yum on January 30, 2021, 03:06:45 pmI recommend the Reference Manual "RM0451" and suggest that you read the 774 pages. Luckily for you this is a among the simpler STM32's, but not the simplest due to all the low power features of the STM32L010K4. Then I recommend that you make a project using one peripheral, then when you have a working knowledge of that peripheral, move on to the next.As you plan to use C, look at the end of "RM0451" where you will find "Appendix A Code examples" for most peripherals.https://www.st.com/resource/en/reference_manual/dm00443854-ultralowpower-stm32l0x0-advanced-armbased-32bit-mcus-stmicroelectronics.pdfIf you do this, then you will have the kind of knowledge to actually use the chip to it's capabilities.Environment------------------The environment set up is entirely dependent on the programming language you plan to use and they all have their own peculiarities.If you roll your own, you'll be swimming in linker scripts as Siwastaja said, and he's not kidding. Read the GNU Linker manual and you'll appreciate that this is a 16 headed monster.You'll need a 'library' of some sort, perhapshttps://libopencm3.org/or the CMSIS library in the Keil packs ...Happy building!

author: westfw
author_rank: Super Contributor
timestamp: January 31, 2021, 01:39:40 am
content: A few years ago, there was a big discussion here on "minimal ARM programming."Some of the results, and discussion, and pointers to the discussion here, can be found athttps://github.com/WestfW/Minimal-ARM(programming an ARM in assembler is unpleasant, mostly because the peripheral definitions are not provided in a form that supports assembly. It's also quite unnecessary.)Additional "smaller than ASF" ARM experiments (for Atmel SAMD10 here:https://github.com/WestfW/SAMD10-experiments)I agree with the recommendations to ignore HAL/ASF/etc packages. They'll typically take something like 1k of code just to initialize the clock :-( (Note that for trivial programs, you probably don't NEED to "initialize the clock" at all.)I keep hearing that newer replacements (Atmel Start, ST LL Library) are "better", but my initial experiences were so bad that I haven't looked.As for BlueSkull's recomendationsFORHAL... You can do a better job writing abstracted and portable functions/macros on your own, for almost all common peripherals.I keep getting facebook ads for a freehttps://stm32.embeddedexpert.io/stm32_ebook"Bare-Metal Embedded C Driver Cookbook", and eventually succumbed. It's pretty sparse, but also useful, consisting of of cookbook-style short C programs with comments and references to the datasheet. Their "toggle IO pin" example reads like:Code:/*1. Enable GPIOA clock *//*2. Set PA5 to output mode *//*3. Turn on bit *//*4. Delay for some time*//*5. Turn off bit */Which is nice, because it points out that important "enable clock" part, and provides the reference.

author: techman-001
author_rank: Frequent Contributor
timestamp: January 31, 2021, 03:54:47 am
content: Quote from: westfw on January 31, 2021, 01:39:40 amwestfw, I'm devastated that you didn't read my code, does this look like the peripheral definitions are not supported, or not cmsis-svd compliant to you ?;-)It's all automatic for me being transformed from the SVD. The hard work was the HEX in the comments which is only there as it's a teaching example.Code:main:ldr r1, = RCC_AHBENR@ AHB Peripheral Clock enable register @ 0x40021014ldr r2, = RCC_AHBENR_IOPBEN @ I/O port B clock enable = 0x40000str r2, ldr r1, = GPIOB_MODER@ GPIOB port mode register @ 0x48000400ldr r3, = OUTPUT << GPIOB_MODER_MODER8@ Set PB-8 bit as output = 0x10000str r3, ldr r1, = GPIOB_BSRR@ GPIOB bit set/reset register @ 0x48000418ldr r4, = GPIOB_BSRR_BS8 @ PB-8 on = 0x100ldr r5, = GPIOB_BSRR_BR8 @ PB-8 off = 0x1000000I also like their "toggle IO pin" example as there is absolutely no reason to use C or any other programming language to explain a peripheral config.

author: westfw
author_rank: Super Contributor
timestamp: January 31, 2021, 11:01:23 am
content: QuoteYes.Having a separate symbol for every register in the device is horribly bogus.I want it to have offsets for fields and generic pointers; definitions which (AFAIK) are only provided hidden in C structure definitions (I suppose that they COULD be decoded from the .svd files...)Code:ldr r1, = GPIOBldr r3, = OUTPUT << GPIOB_MODER_MODER8@ Set PB-8 bit as output = 0x10000str r3, [r1, #BSRR]

author: Sudo_apt-get_install_yum
author_rank: Regular Contributor
timestamp: January 31, 2021, 12:59:24 pm
content: I just wanted to say thanks to all of you who wrote extensive replies. I’ve been reading through them and tried to get a bare metal version of my previous code working. So, my apologies for the slow replies!I’ve setup a blank C/C++ project in STM32CubeIDE and used CMSIS, I’m not sure I actually need it since I’m directly writing to the registers of the processor. My understanding is that CMSIS is a small abstraction layer to keep some sort of standardization between different ARM manufacturers.I’m able to build the project and get no errors or warnings but I’m not able to actually run the program. Se the image below for the error, I don’t really understand the error so any input would be appreciated!The "Bare metal STM32 cookbook" was very helpful, it reminds me a lot of regular AVR programming and what steps i need to take in order to enable a peripheral and so on, so huge thanks!Error when running.CodeMemoryProject setup

author: Yansi
author_rank: Super Contributor
timestamp: January 31, 2021, 01:04:52 pm
content: Quote from: blueskull on January 28, 2021, 02:02:09 pmIts absurd use of resources is exactly why using the HAL shit should be avoided like a covid.Especially with ultrasmall ST32 MCUs like the STM32L011, it makes absolutely 0.00 sense to use HAL on that. Use the registers, otherwise you won't fit anything inside, past the HAL initialization.Same goes with for example STM32F042. Nice 20 pin ARM chip with a USB peripheral. Use the Cub/HAL with USB on that and you have barely any FLASH left to do the useful stuff.

author: Yansi
author_rank: Super Contributor
timestamp: January 31, 2021, 01:09:23 pm
content: Quote from: Sudo_apt-get_install_yum on January 31, 2021, 12:59:24 pmDo NOT use the magic numbers in your code. There is metric shit ton of human readable aliases for all that stuff.instead ofQuoteuse for example:Code:RCC->IOPENR |= RCC_IOPENR_IOPBEN | RCC_IOPENR_IOPHEN ;And btw, use of the double pipe || in your code is an error!

author: Sudo_apt-get_install_yum
author_rank: Regular Contributor
timestamp: January 31, 2021, 01:22:06 pm
content: You are completely right, should have used "single pipe" in this case!Regarding the magic numbers, I hate it as much as anyone else. I could not find the correct alias names so just used the magic numbers for testing.

author: Yansi
author_rank: Super Contributor
timestamp: January 31, 2021, 01:36:31 pm
content: The aliases are really simple and consistent. It is aPERIPHERAL_REGISTER_BITnotation. Gives the exact bit set to 1.There are also a bit position macros (add_Posat the end) returning the bit number (0..31) and a bit mask macros (add_Mskat the end) when applicable.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 31, 2021, 01:51:34 pm
content: I don't like copy-pasting or manually rewriting, orreadingfor that matter, things likePERIPHERAL_X_CONFIG_REG = PERIPHERAL_X_CONFIG_REG_ASDFG | PERIPHERAL_X_CONFIG_REG_QWER | PERIPHERAL_X_CONFIG_REG_XYZ;even if it's simple and logical.First, it's a lot to read and write.Second, because the SNR is so poor, a small one-letter mistake easily sneaks in and is hard to find.Finally, it provides absolutely no documentation about what ASDFG, QWER or XYZ mean or do, so they are not any different from magic numbers. They are hard-to-understand abbreviations from the reference manual. You need to either look them up, or remember them by heart.So the only way to write / read this is to open the relevant manual page describing those bits. Which is what you, realistically speaking, need to do anyway! So basically, at some point, I accepted this, and stopped playing those "let's pretend this has no magic numbers and is maintainable" games, removing one extra layer of nomenclature.My assumption hence is, anyone who questions that line of the code (someone else, or me later), can't do that without opening the refman description anyway, they need to see the longer description than some ARPE to understand what a config bit actually does. Now, the reference manual documentation refers to the bits using bit numbers, directly, so why not use them.Hence, ASDFG and 5 are similarly magical. Both require lookup. I prefer 5 to get rid of one layer of excess abstraction (that does not add anything). Ireplacethe tedious WRITE_THIS_PART_TEN_TIMES_WITHOUT_ADDING_INFORMATION by adding a /* in-line comment */ describing what the configuration bitactuallydoes.An example:Code:TIM2->CR1 = 1UL<<3 /* one pulse mode */ | 1UL<<2 /*only overflow and underflow generate update interrupt*/;is IMHO more descriptive thanCode:TIM2->CR1 = TIM_CR1_OPM | TIM_CR1_URS;But I won't be pushing this notation. Just saying there are options to do it differently.

author: Yansi
author_rank: Super Contributor
timestamp: January 31, 2021, 02:10:27 pm
content: Your option without the additional human readable comments is also next to useless, regarding readability.So then don't tell us, there is "a lot to write", especially, if any half decent IDE has the code autocomplete on ctrl+space ready and your commented line has twice the length.If one wants to make any outcomes of all that, all comes to writing the code such way, it is easily readable and understandable.Using magic number is certainly not going to make code readable and easy to understand.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 31, 2021, 02:15:08 pm
content: Autocompleting too-long-to-write code screams a risk of accidentally autocompleting to something you didn't mean.There is nothing wrong with having to write and read a long piece of code if the extra work provides information about what it does, it's all about the SNR. Copypasting the obvious over and over again is called boilerplate, I understand it's needed because of the lack of namespaces in C, but it's still unwanted boilerplate, nothing to do with readability or maintainability.I agree a number like 5 does not make the code readable, but neither does COPYPASTE_COPYPASTE_ASDF. What is ASDF? So in both cases, you need to add a comment. Unless you lull yourself into thinking COPYPASTE_COPYPASTE_ASDF is "readable" so you don't need to add the comment. Besides, writing a comment is less appealing when the line is already long with the long copy-paste name, so you need to add another full-line comment before that line.They areequally unreadable, and the only reason they work is you cross-reference to the manual while writing, and while reading. Or, you write enough comments to replicate the key points of the manual.You are not wrong using that very traditional and established way of doing it, I also do it time-to-time, but you are wrong claiming it is more readable and maintainable than literals + comments.It seems you are so accustomed to the established way that you are certain it has to be better and utilize terms like "readability" and "understandability" to describe the result without really thinking about it.The usual hint to avoid literal numbers in code, which I completely agree with, relates to the fact that by using macros or constants instead, you can add configurability to the code (i.e., change the #define value in one place), and/or, come up with a really descriptive name for the const / macro. #define NUM_PARTICIPANTS 42 does both.The register bit masks in header files supplied by the MCU manufacturer do neither.This isn't too important, the way you show it is widely used and OK to me. Just sayin' it's not perfect and there are alternatives which have different strengths and weaknesses.

author: Yansi
author_rank: Super Contributor
timestamp: January 31, 2021, 02:24:51 pm
content: Your argumentation is weak.If you are afraid of accidentally autocompleting something else, I am as well afraid you can't count the bits and make a mistake in your magic numbers. And to be honest, that is much more likely, than using a bit of boilerplate, that has an obvious meaning and can be checked for validity even without having to sift trough the reference manual to see if the numbers you have used are correct.It is way less likely, that the header file with the machine generated bit macros has an error inside.Don't know what ASDF is, but sure anyone with at least a bit of knowledge of the STM32 can tell what is HSEON, LSIRDY, IOPAEN, etc.And you are also very wrong, that your set of magic numbers is more easy to maintain. It is exactly the opposite!//Anyway, we are starting to drift a bit offtopic. Make another thread and there try explaining, why set of magic numbers is in any way better than using aliases.

author: Sudo_apt-get_install_yum
author_rank: Regular Contributor
timestamp: January 31, 2021, 02:32:34 pm
content: Guys, i understand both your views but you’re steering quite off topic. You can start a new thread about best code practices but please keep to the topicDo any of you know why I’m not able to run my code on my STM32, the error message doesn’t help at all "Error starting process.Cannot run program".I’m able to compile the code without any issues.I appreciate the help so far!

author: Siwastaja
author_rank: Super Contributor
timestamp: January 31, 2021, 02:39:59 pm
content: Whatis making that error message?Regarding the readability discussion, I have made my point, it's up to the reader to choose if they want to give it a thought or not, there is no need to discuss it any further, and it's not fundamental enough to fight about.

author: Sudo_apt-get_install_yum
author_rank: Regular Contributor
timestamp: January 31, 2021, 02:44:14 pm
content: Pressing the run button to run it on the connected STM32L010K4 via a STLink V2I’m able to build the program without a problem. Im not sure what I haven’t correctly configured, the error message isn’t being vey helpful.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 31, 2021, 02:50:33 pm
content: The next step after compiling isflashingoruploadingit to the MCU.Whatever that IDE is trying to do (run the firmware image on your PC, which obviously won't work? Trying to run the programmer - what programmer - in the wrong way?) clearly doesn't work. The first step is to not use the IDE.Flashing through UART using the UART bootloader is the simplest way to get an LED blink. You can also flash with OpenOCD through the ST/LINK.Example of OpenOCD usage:Code:openocd -f board/stm32f7discovery.cfg -c "program main.elf verify reset exit"

author: Yansi
author_rank: Super Contributor
timestamp: January 31, 2021, 03:11:14 pm
content: Quote from: Siwastaja on January 31, 2021, 02:50:33 pmUse of the UART bootloader should be kept only to production programming or arduino folks, that do not know any better.If you have the STLINK programmer handy, use that one. You can either program the target MCU with the generated hex file using an STLink Utility (or STM32CubeProgrammer, if you like wrestling with java shit), or by using openocd as Siwastaja recommends.There are many ways, pick what you like. But I'd recommend learning to use a proper programmer/debugger through your IDE, as sooner or later you will run into stuff that can't be solved by just repeatedly flashing the software in the micro and observing "y u no work" as the arduino folks do.The CubeIDE you have already should program via STLINK/SWD interface by default, by pressing the green arrow on the screenshot from Siwastaja.The green button should start the programming process. If it is not a workie, lets check a few things:How have you connected the STLINK debugger to the target MCU? (for starters, I strongly recommend getting a few of the discovery/nucleo board ST is offering, so you have a solid working HW to begin with).//EDIT: Typos.

author: Sudo_apt-get_install_yum
author_rank: Regular Contributor
timestamp: January 31, 2021, 03:28:45 pm
content: Quote from: Yansi on January 31, 2021, 03:11:14 pmI’ve only been using the STM32 for a few days by now. It only took me an hour to get all the CubeIDE/MX things up and running on my hardware including setting up the I/O, ADC and timers.Was able to use the debugging functions, single step and read register/variable content. The reason I started this thread was that HAL used an insane amount of memory for initialization and I wanted to learn ARM for real.I use the Atmel ICE when programming AVR's so I’m used to using a debugger instead of printing things to the terminal in hopes of solving the problem. So, I’d prefer to continue to use a debugger.The hardware I’m using is just a simple breakout board and works fine when programming it through CubeIDE when the project is configured through their configuration tool (MX). I’m pretty sure that I’ve made an error when configuring this "raw" project but can’t figure it out since the error message isn’t saying much.

author: Yansi
author_rank: Super Contributor
timestamp: January 31, 2021, 03:45:33 pm
content: Well, in the eclipse based ide, trying to setup bare project is beyond painful even when you know what ya doin'.Better approach would likely be make it a bog standard CubeMx project and delete the shit out of the Cube/HAL stuff.Can't give any more specialized recommendation, as I have not used the CubeIDE, I have been using different eclipse flavor configured manually to support multiple vendors (ST and Nordic), but boy was it a pain.Clipping the Cube/HAL off is likely the easier way to do so, than trying to create a bare project without an eclipse expertise.Also, you can always switch from the HAL libraries to using LL ("low level"). They are mostly bunch of simple macros, no high level stuff. (But I have never stuck with those. Either the old SPL library, or direct register access. On rare occasions the HAL, where resource use was not a concern).

author: Siwastaja
author_rank: Super Contributor
timestamp: January 31, 2021, 04:24:53 pm
content: IMHO, if you don't know what software is running on your computer and what it does, something's wrong. This isn't rocket science and there are no black boxes, it's all decades old computer science with just a few tools.This is all I need:Code:arm-none-eabi-gcc -Os -fno-common -ffreestanding -fno-builtin -mthumb -mcpu=cortex-m7 -specs=nano.specs -Wall -Winline -DSTM32H750xx -mfloat-abi=hard -mfpu=fpv5-d16 -fno-strict-aliasing -Wno-discarded-qualifiers test.c -o test.oarm-none-eabi-gcc -Tlinker.ld -mcpu=cortex-m7 -mthumb -nostartfiles -mfloat-abi=hard -mfpu=fpv5-d16 -specs=nano.specs -o main.elf test.o -lmopenocd -f board/stm32f7discovery.cfg -c "program main.elf verify reset exit"You usually automate this using a makefile but wanted to post this to show this is literally the complete toolchain. There are a few flags you likely don't understand but just copypaste from somewhere, also you need to know how to write (or download & modify) the linker script, so this is not a zero effort thing but I like to minimize the number of moving parts and maximize the insight.Compiler: .c -> .oLinker: .o -> .elf(Optionally, objcopy .elf -> .bin for custom bootloaders etc.)Programmer: .elf (or .bin) to device flash(Optionally, gdb to debug. Here I admit graphical interfaces present in IDEs make it easier.)I'm fine with the uart bootloader. I do small/simple projects with it only. I started with it only. Larger projects tend to require application specific bootloaders/flashers with application-specific remote telemetry/debug procedures anyway, I'm fine writing them, they perform better and log actual incidents in prototypes/production systems than using general purpose "lab" debug tools. Last year I started up the bog-standard debugger only once I think. I almost never single-step code, I think it's fundamentally wrong and inefficient way to develop but OTOH if you are grown to do that then it likely floats your boat and there's no reason to stop doing that if it works for you. Not single-stepping your code in debugger has nothing to do with Arduino. I think Linus Torvalds has interesting comments about debuggers:https://lkml.org/lkml/2000/9/6/65

author: Kleinstein
author_rank: Super Contributor
timestamp: January 31, 2021, 04:31:48 pm
content: Single stepping is quite a nice way if one has trouble with a program. It is especially nice with the AVR simulator, as one does not even need real HW. Later with more experience one would not use it as much as for the start.So I kind of miss a good simulator for the ARMs.I would not worry too much about the little extra memory needed for the init code generated by CubeMX - it is one time and 1 K is still only some 3% of a small 32 kB µC.So it is unlikely one would habe a problem because 1 K is missing.The bootloader is more of a hassel if you want a debugger connection anyway.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 31, 2021, 04:39:36 pm
content: Single stepping in a debugger reveals some "interesting" sources of issues such as some RAM regions or register values not updating because some clock signal isn't enabled. Without a debugger, though, you'll find the same out, it takes a bit longer though as you are responsible for writing code to read out the registers in some way. It's a "takes 10 seconds" vs. "takes 60 seconds" type of thing. For a beginner, the difference may be a lot bigger initially, in favor of debugger.This being said, after a bit of learning curve, such problems are almost non existent. You learn to turn those clocks on, and you learn to write handlers that dump out all relevant peripheral status registers on every your_own_assert().Debugger also gives you that warm fuzzy feeling when you are unsure what you are doing, I used it last year when writing a cycle-accurate, larger piece of assembly and interfacing it from C; I mostly just use C and wasn't so experienced in the M7 instruction set and its behavior. Debugger was a bit like those training wheels.Single stepping the code logic is very ineffective on a remote target like microcontroller. I prefer even very rudimentary "unit tests" on PC, for example to check how numerical ranges with different input values behave, with small modules I can run through all the input combinations and verify the output.To give a practical example, without a debugger, you'd be writing a hardfault handler which dumps the stack content to whatever interface you have available, then look at that data to find the source of issue. Yes, it's more work initially, but the bright side is, you can log it on the field, very handy when the problem rarely pops up, you get an actual bug report instead of hoping you'd have had that unit on your table, with the SWD cable connected.For example, one system I have beeps the error code through a speaker and spams more information on UART every 10 seconds or so. The system is always connected to a computer with UART, so the customer can get the UART dump and email it to me. I don't have to drive there, attach the SWD cable, run a debugger and hope I can reproduce the bug.

author: Yansi
author_rank: Super Contributor
timestamp: January 31, 2021, 05:00:46 pm
content: Quote from: Kleinstein on January 31, 2021, 04:31:48 pmDownload the Keil uVision free edition. There should be a working ARM simulator.Problem is, that the HAL init (of course depending on specific case, but mostly will NOT) fit within just 1K of code. And the other problem is, that the L011 he has, is not a 32k uC, it is just a 16K maximum. (He may have even just the 8K version - Sudo_apt-get_install_yum didn't specify the full part number, only just he has the L011 which comes in these two very small flavors).Considering professional use, low power stuff (which L011 is part of) is rarely coded in high abstraction level libraries. Mostly just bare metal registers and optimized for time. Otherwise you won't last long with your batteria!//Sidenote: If the OP wants just some cheap STM32 that also comes in a small package (low pin count easy t osolder) to toy around, look also at F030, F042 or the new fancy G0 series. These have variants with >16K FLASH so you don't have to worry about FLASH/RAM use that much in the beginning. You can learn to optimize later. //

author: Siwastaja
author_rank: Super Contributor
timestamp: January 31, 2021, 05:38:52 pm
content: OTOH, when coming from AVR, the OP likely already knows the ideas how to write small and efficient. The same principles apply 1:1. The trap you can fall into is thinking you "need" to go to the bloat libraries and I think we have already prevented the OP from falling to that trap.It was the same for me, I started with AVR when it was a brand new thing in 1990's (and I was a kid who understood nothing) and pretty much completely migrated to STM32 in early 2010's.

author: Silenos
author_rank: Regular Contributor
timestamp: January 31, 2021, 05:42:24 pm
content: From my experience:- forget the HAL or w/e, it works,sometimes. Once you get some project running without any HAL, you are already ahead.- I had to use keil IDE (nice tools, debugger, HORRIBLE editor), ultimately rebelled and switched to VSC with gcc. I've done 2 shortcuts to build makefile and download the program (that STM32programmer in CLI, actually it is usable) and it is a breeze. Did the toolchain from scratch, not difficult, but always something new to learn. Just used initial startup with vector table and default linker script from cube. And checked their compiler flags for specific device.- about VSC: maybe could have been better done with VSC but there are some strange issues with multiple tasks binding and what not, which I do not fully comprehend. I read some hot demagogic discussion on their trackers that the editor is not supposed to produce programs "which are not run on virtualized hardware". So I don't even bother with gui debuging on it (memory, registers views). Maybe now it is different.- dropped the debbuging entirely: the thing is, especially with newer stms, that there are peripherals which switch state upon accessing their registers. Like fifos on spi or usb. Spurious buses traffic from probe messes crap out, I got burnt by it the hard way. Although I must say debuging is usable to probe registers while stepping some asm prototyping. If I need probing, I just printf log into buffers. And after the cue, I dma the buffers through uarts with 1 Mbaud.- eclipse? NO.- assembly - it is actually enjoyable on ARMs. Though I used it only on: context switching routine, some algorithms, more algorithms using specific instructions like Count Leading Zeros (binary tree search) or saturation math (fixed point), all called from C anyway. Imo it may teach how to write C code with minimal stack shuffling, as well as common CS knowledge - how to link differently written pieces of software, how to call C function from asm, and viceversa, (now you have no issues to throw C++ or Ada or w/e into a project)... any experience with toolchain scheming is valuable experience.- simulators? Fat chance they work on current ARM-ST-Microchip-Synopsys-whatever clusters of ips.

author: Yansi
author_rank: Super Contributor
timestamp: January 31, 2021, 06:53:08 pm
content: Quote from: Siwastaja on January 31, 2021, 05:38:52 pmNothing wrong with that. I started with assembly on x51 MCUs. Those good old days...Yes I need to do the "do not bloat stuff" to death and repeat it every time with a lot of exaggeration. I am tired of bloated shit that always wants to eat my whole computer just to do even the simplest stuff. (Yes, I am pointing also at you, java!)Quote from: Silenos on January 31, 2021, 05:42:24 pmI'll just add: On ARM you sure rarely do need to write in assembly. You can, of course, but there are only few niche cases that require it. For the rest of the stuff, calling a special instruction here or there thats where ARM intrinsics is what gets the job done. Just call the required instruction directly from your C source code using its related macro. Usually only needed for some bit or byte swapping, SIMD and other computation-related instruction (for example invoking the HW square root, if you happen to have a CM4F with the FPU), etc.

author: techman-001
author_rank: Frequent Contributor
timestamp: January 31, 2021, 07:48:13 pm
content: Quote from: Yansi on January 31, 2021, 02:24:51 pmYansi, please do start another thread, I know I'd like to discuss this more.

author: mino-fm
author_rank: Regular Contributor
timestamp: February 01, 2021, 12:09:06 pm
content: For a quick start of a new STM32 MPU I like to run CubeMX to setup clock-tree (ext. crystal+max. clock frequency), ISR-priority (no sub-priority), default error-handlers and enable caches for max. speed.After that I like to run code generator: copy only necessary library files, IAR EWARM toolchain. This IDE is a little bit buggy but free up to 32 KB code. You don't have to care about make or linker scripts/flags. Main.c initializes caches, HAL (never used at all), HSE-clock and some error-handlers.Following this, MPU should start running at max. speed and you are free to programm your application: programming registers directly as many other users suggested before. No HAL!You'll find all necessary definitions in 'STM32(MPU)xx.h'. If possible, don't use magic numbers. Newer MPUs can have changed bit-positions!For me, main reason to use IAR is it's debugger. With 'View->Live Watch' you are able to watch varibales/registers and change them without stopping the running program! (Keil IDE has similar function). For beginners it's very useful and can help to get/see timers running, see flags of DMA or setting GPIOx-pin or MODER directly if forgotten to initialize.At last you (mostly) can import your project to your selected IDE.

author: capt bullshot
author_rank: Super Contributor
timestamp: February 01, 2021, 03:24:49 pm
content: Quote from: mino-fm on February 01, 2021, 12:09:06 pmAFAIK, the recent Atollic (now STM branded) free IDEs for STM can do that too. Anyway, it's still gdb behind an eclipse extension, so Keil or IAR still might have better user experience with debugging and this particular feature. Can't tell much about it, since "printf" is my favourite debugger, single stepping etc. found only useful in rather basic and simple projects. A working and easy to use live view can be really helpful.As I prefer free (as in OSS, not constrained "free" versions of commercial stuff) tools, I've found my way without these fancy debuggers.

author: NorthGuy
author_rank: Super Contributor
timestamp: February 01, 2021, 07:31:01 pm
content: Quote from: mino-fm on February 01, 2021, 12:09:06 pmI personally cannot watch things as fast as they usually change in the MCU.

author: Yansi
author_rank: Super Contributor
timestamp: February 01, 2021, 09:14:08 pm
content: Then you should probably learn to do so, otherwise tuning realtime stuff is difficult to do. You can not halt the MCU, when controlling a motor controller power stage, SMPS or similar.There are also nice tools like the STM Studio, which can graph variables pretty fast (although, there are some obvious (or less obvious) limitations, some of them being just stupid design of the STLINK debugger, which is unfortunately the only thing it works with).https://www.st.com/en/development-tools/stm-studio-stm32.html

author: Sudo_apt-get_install_yum
author_rank: Regular Contributor
timestamp: February 02, 2021, 11:13:29 am
content: Ok, so I feel like I am making progress and I’m finally able to code things bear metal.I’m using CubeIDE combined with CubeMX to generate the project files and then deleting all HAL related files.I will migrate to a more streamlined project configuration in the future, but this approach works fine for an ARM beginner like me.I got stuck on enabling the GPIOx clocks, for some reason the "RCC_IOPENR_IOPAEN" macros seem to have an incorrect offset.The "RCC_IOPENR_IOPAEN" corresponds to bit 1 instead of bit 0 and "RCC_IOPENR_IOPBEN" corresponds to bit 2 instead of bit 1.I’m not sure if this is an error from my part but the clock enabling works fine when just using "magic numbers".Code:RCC->IOPENR |= (1U<<RCC_IOPENR_IOPBEN) | (1U<<RCC_IOPENR_IOPAEN); // Enable clock for Port A & B (Enables B and C for some reason)RCC->IOPENR |= (1U<<1) | (1U<<0);// Enable clock for Port A & BI wouldn’t have noticed this as fast as I did if I hadn’t used the debugger, set a break point after the line and check the IOPENR register.Thanks for the help everyone!

author: newbrain
author_rank: Super Contributor
timestamp: February 02, 2021, 11:43:34 am
content: Quote from: Sudo_apt-get_install_yum on February 02, 2021, 11:13:29 amThat's because those macros are thebitmacros (equivalent, in this case, to the _Msk ones), not the position ones.E.g., if you look at RCC_IOPENR_IOPCEN, it will be 4.Just remove the shifts (1<<) and you're all set.Code:RCC->IOPENR |= RCC_IOPENR_IOPBEN | RCC_IOPENR_IOPAEN; // Enable clock for Port A & B (Enables B and C for some reason)RCC->IOPENR |= (1U<<1) | (1U<<0);// Enable clock for Port A & BEtA: Oh, did you manage to run your test from inside STM32CubeIDE in the end?The problem there is the idiotic way Eclipse works/it's integrated with vendor parts (exactly the same happens on e.g. MCUxpresso, another Eclipse based instrument of torture).That button is trying to run the .elf file on your PC, not on the target.The easiest way is to define a debug configuration (that's pretty much 100% automatic usually) and use that.

author: Tagli
author_rank: Contributor
timestamp: February 02, 2021, 12:53:20 pm
content: You can use_Possuffix for shifting operations, (1U << RCC_IOPENR_IOPBEN_Pos) for example, but using the bit mask value directly is easier unless the definition involves multiple bits.

author: Yansi
author_rank: Super Contributor
timestamp: February 02, 2021, 02:08:32 pm
content: Quote from: Yansi on January 31, 2021, 01:36:31 pmTo the OP: I have explained this on the first page of the thread.