STM32CubeIDE / CubeMX Workflow Tips and Tricks? - Page 1
Forum section: electronics / general

author: randyyork
author_rank: Newbie
timestamp: November 18, 2019, 05:31:00 pm
content: Pardon the vague talking points. I was hoping to get some conversation going in hopes of picking up tips and tricks regarding how to efficiently use STM32CubeIDE with CubeMX integration. Things like managing workflow, keeping code clean, etc.Growing pains / bugs / quirks aside, there doesn't seem to be a cohesive guide for how to actually use the ecosystem to go from "I have this ST part -> I need to get this peripheral up and running -> Here are the steps I need to do within the Cube environment". Are there any supporting documents that can explain what HAL code and Cube settings must be set to enable a particular operating configuration? It seems like this is something missing. For example, enabling the USB peripheral doesn't automatically (always) enable the USB OTG interrupt, and it seems anybody's guess why this has to be selected for certain parts and not for others.In the past, before this integrated environment was available, I'd find myself meticulously avoiding the HAL layers and rewriting tight code following the device-specific programming manuals for each peripheral component. This worked well for personal projects, but this doesn't seem to be appropriate for production-ready designs where being able to switch to different parts and having multiple people understand code is beneficial. Given that peripherals are getting more complex, it makes sense to use HAL interfaces, but these seem to be half-baked. In the unhappy case of quirks that you stumble upon, you are SOL unless you can get a hold of support.Another gripe that I'm facing is that the Cube-generated code is rather ugly. It is hard to fit everything in with existing coding standards, especially when trying to code within the templates / blocks that are predefined within the Cube environment.In general, I'm wondering what the gurus are doing these days when using these parts outside of hobby projects...Thanks!

author: JohnnyBerg
author_rank: Frequent Contributor
timestamp: November 18, 2019, 06:28:50 pm
content: been there .. done thatLast week I went the same route. As you said, the generated code looks horrible. I did not like the project structure. Coding against HAL is difficult, and hard to port to a different controller. I did not manage simple read from the ADC.Not up to my coding standards. The IDE is a remake of Atollic Studio and Eclipsed based. You have t be a fanboy for that. I don't like it.The only thing I liked was the makefile.Then I looked at mbed. I liked the coding, with a few line one can build something. I did not like the online IDE, the lack of a debugger and intellisense. The offline CLI is python, and very minimalistic. But the biggest deal-breaker is code size. The simplest program needs about 70kB flash, because of the linked RTOS. With a microcontroller having 16 or 32 kB flash a no go. mbed was out.Next Arduino. I liked the coding, just as mbed. Code size is also ok. But the IDE has no intellisense, no debugger. Just like mbed, for small projects ok, but when you build something bigger, perhaps even in a team, it gets unworkable very fast.I ended up with Visual Studio Code, the STM32Duino code base, and a toolchain. This has everything I wanted: intellisense, debugger, small code size, Makefile and everything very flexible and configurable.I posted my skeleton onGithub, for everyone to use and adapt.My 2 cents ..

author: jhpadjustable
author_rank: Frequent Contributor
timestamp: November 18, 2019, 06:35:30 pm
content: libopencm3 is fairly complete for many targets including several non-ST ones. If you want to switch targets, it's not much harder than switching under Cube. It's licensed under the LGPL, which effectively reduces to the MIT license as long as you don't modify the libopencm3 code itself. (EDIT: apparently not, you have to provide a link kit of some sort, like the old Unices.)I'm in the process of porting an application out of HAL because their code generation did no favors for my cheerful disposition.

author: newbrain
author_rank: Super Contributor
timestamp: November 18, 2019, 08:44:27 pm
content: Quote from: jhpadjustable on November 18, 2019, 06:35:30 pmSorry, but this is just misleading.For the embedded world, where libraries are almost exclusively statically linked, section 4 "Combined Works" apply.In particular,check point d) 0).There's no way this can be assimilated to the MIT license, even if the library is unmodified:one has to convey what is needed to rebuild the application (objects, minimal sources and possibly tools/scripts) and link it with a different library version.That said, parts of the HAL and "Middleware" from ST went from a very liberal, BSD/MIT-like license, to a liberalbut ambiguously wordedone: just choose your poison!

author: robint91
author_rank: Contributor
timestamp: November 18, 2019, 10:30:33 pm
content: In all honest opninion the STM32 cube isn't that bad. Nordic has in my opinion a bad structure. My and yours time is precious. These microcontrollers are too big to solely rely on the ref manual. This is also true for the other manufacturers. We are trading flexibility with complexity.I use mainly STM32's for my day job. A basic project start as follows, what does it need to, which external components do i need. Then starts the fun selecting a microcontroller. The cube tool is excellent for that. But most of the time i have an idea which family. Mainly F411, L45x, F746 or F071. Then you start pin planning , you give the pin aliasses this will help in the software later. After that schematic, pcb. Maybe a few iterations on the pinplanning to optimize the routing. Build prototypes and generate software. A fairly painless experience in my honest opinion.The cube configures the clock, uarts, timers, gpio,...Basic stuff where I can't be bothered with looking it up in the datasheets. I just don't want to spend time reading basic stuff in the datasheets. Cube is the perfect tool for that.And for the more specialized stuff i will look into the datasheet. For example the hrtim, dfsdm,....I would touch stm32duino and libopencm3 with a 1000m pole. LGPL and only being depended on the community is a problem when using the in commercial applications.

author: thm_w
author_rank: Super Contributor
timestamp: November 19, 2019, 12:16:25 am
content: Quote from: JohnnyBerg on November 18, 2019, 06:28:50 pmDid you use the option "Generate a pair of .c/.h files per peripheral"?That cleans up a lot of the mess and keeps functionality segmented, it also can help if you go back to update the original settings to keep the changes within one area (somewhat).Reading from ADCshouldbe as simple as enabling the specific ADC channel in cubemx, then adding this to your main:Code:HAL_ADC_PollForConversion(&hadc1, 10)ADCValue = HAL_ADC_GetValue(&hadc1);But there are some gotchas, sometimes the Cube values are set to really weird defaults (like the timer count maximum of 0..). Also if you are using multiple ADC channels, due to how the internal scan conversion works it can take some time to process.We discussed in the other thread always use example code as well, to know right away which function is needed.

author: JohnnyBerg
author_rank: Frequent Contributor
timestamp: November 19, 2019, 06:27:58 am
content: Quote from: thm_w on November 19, 2019, 12:16:25 amSure I did, but that did not turn the ugly code in something beautiful.QuoteI tried .. but I did not get it to work. The biggest problem was selecting the port, from where to read.Code:value1 = analogRead(PA4);value2 = analogRead(PC2);This i can read understand and maintain ..

author: tmadness
author_rank: Regular Contributor
timestamp: November 19, 2019, 07:54:14 pm
content: I've been through this recently. The path I chose is CubeMX for generating the makefile+initialization code and used LL drivers. LL code is easier to understand for me and I don't need to deal with the HAL bloat, or trying to read deep within HAL APIs to figure out whats happening. BTW RM0090 reference manual for F4 helped out a bunch, look for a reference manual specific to your MCU line. The LL API command for ADC read, assuming a simple setup, would be LL_ADC_REG_ReadConversionData12(ADC1) where ADC1 is just a memory address define inside of the LL library

author: thm_w
author_rank: Super Contributor
timestamp: November 19, 2019, 11:20:51 pm
content: Quote from: JohnnyBerg on November 19, 2019, 06:27:58 amAh understand.QuoteYeah, totally get why this would be an issue, it took me a while to grasp. The way their whole ADC system is setup is not "traditional" like this. Probably they thought most people want to use interrupt/dma based reads, so you can have the ADC constantly churning away in the background (a lot of their parts have multiple ADCs as well).One way to do this is make a wrapper function "analogRead", which would configure ADC with a specific channel, perform the HAL poll for conversion, then return the result.Or of course use stm32 arduino library, or maybe one of the other HAL's that are oriented in that way.

author: lawrence11
author_rank: Frequent Contributor
timestamp: November 21, 2019, 05:56:42 pm
content: Quote from: tmadness on November 19, 2019, 07:54:14 pmI also feel like doing this, what IDE do you use.

author: tmadness
author_rank: Regular Contributor
timestamp: November 26, 2019, 12:52:19 am
content: I use VS Code for most of my development, but i use CubeMX IDE (Yuck!) for debugging and uploading. I could configure VS Code for debugging but my current project's timeline is constrained and I have to put out a solution soon. I think the latest video on EEVBlog with David and David talks about configuring VS Code for full STM32 development. Its a bit time consuming but damn the javascript devs know how to build and maintain a good editor. VS code is is just so customizable, ya it runs electron, ya its built by the evil Microsoft, but damn is it good.For my current setup I just installed the C/C++ plugin and and pointed VS Code to the generated source from CUBEMX, and intellisence just worked.

author: lawrence11
author_rank: Frequent Contributor
timestamp: November 26, 2019, 02:36:43 am
content: well thats weird, because its the debugging that actually sux due to gdb and eclipse bloat.The best answer would be something like roelwy or segger but they dont permit stlink-v3

author: JohnnyBerg
author_rank: Frequent Contributor
timestamp: November 26, 2019, 08:00:07 am
content: Quote from: tmadness on November 26, 2019, 12:52:19 amI use this setup for quite some time, and intellisense stopped working yesterday. After a few hours of digging, I found that there is a possibility to reset the intellisense database. After the reset, everything worked again.

author: tmadness
author_rank: Regular Contributor
timestamp: November 26, 2019, 06:16:37 pm
content: Quote from: lawrence11 on November 26, 2019, 02:36:43 amHey like I said, I'm only using CubeMX because I have to devote my resources elsewhere. Previously I've used the stlink utility to upload the binary but I needed debugging for this project. VSCode can be configured to run openocd+gdb but i've never explored that rout and I doubt my manager would be happy if spent half a day figuring that out.

author: JohnnyBerg
author_rank: Frequent Contributor
timestamp: November 30, 2019, 02:20:14 pm
content: Found out that CubeMX also can generate LL(Low Level) code, and that is considerable smaller then HAL. For an experiment, I used that code as a basis for a C++ project. Blinking a led fits in 1068 bytes flash, and uses 8 bytes of RAM. The C version needs 1044 byes, so overhead for C++ is only 24 bytes. I disabled rtti en error propagation.What a did was configuring the clocks, IO etc in CubeMX and then generate code with all the libraries included. Then I used the linker script, the startup_xx.s and the drivers as a basis for a new project, with my own structure and makefile.This is my main:Code:int main(){Pin LED(GPIOA, LL_GPIO_PIN_4);while (1){LED.reset();delay(500);LED.set();delay(500);}}Size:Code:arm-none-eabi-size build/firmware.elftext data bss dec hex filename1068 8 1568 2644 a54 build/firmware.elf

author: tmadness
author_rank: Regular Contributor
timestamp: December 01, 2019, 06:34:18 pm
content: Interesting stuff. The small overhead coincides with what I've seen elsewhere on the interwebs. Most people tend to be touchy about using c++ on uCs, truth be told uCs with >512 kB of flash are pretty common and are reasonably priced. If such a higher capability uC is suitable for your application using c++ could be a lifesaver. But just out of curiosity how much of the latest standard of c++ (say c++ 17 or 20) do the arm-gcc compilers support?

author: mark03
author_rank: Frequent Contributor
timestamp: December 01, 2019, 08:17:36 pm
content: There is really no justifiable reason for avoiding C++ in embedded work. Well, maybe one: A client once insisted that we use C when developing a driver framework, because after the work was transferred to his own SW team, he couldn't guarantee that less-experienced engineers wouldn't try to use features like multiple inheritance or the STL. His "firewall" was forcing them to use C so those things wouldn't be possible. Sad if you ask me, but you can't really argue with the logic.The fact is, C++ code should be more readable and easier to maintain, without adding any code bloat whatsoever. Classes, namespaces, and const are powerful organizational features; just don't do anything that is going to add run-time overhead. Don't use exceptions. Don't use the STL. This should be common sense.If anyone disputes this, I will rub their nose in the Kvasir project, which shows that C++ can actually enable *more* efficient code than C. Admittedly it takes some ugly template metaprogramming to get there, and I don't really recommend it. Parity with C is good enough. No need to make the "C forever!!" people feel bad by beating them with even more efficient C++ code

author: splin
author_rank: Frequent Contributor
timestamp: December 02, 2019, 12:11:37 am
content: Quote from: mark03 on December 01, 2019, 08:17:36 pmExactly. I seem to remember it said in the early days of ADA that it was such a huge language, with countless different ways to code a solution, that you could have a dozen different projects written by different teams each using a subset of the language that they had learned or felt comfortable with, such that no team could understand any of any other team's code.I've probably exagerated that a bit... but it also applies to C++. Sure you can try to limit the allowed subset of C++ features used but there's always some smart-arse determined to make the code 'better' by pushing the boundaries. And not so smart-arses who step over the boundaries because they had no idea what they were or where they were.I haven't used C++ for some time but one of the wost aspects were the WTF moments - you know when you're single stepping through an innocuous piece of intiialization code, a few perfectly simple assignments, when the lights go out with a big bang; when the smoke clears you find yourself in some parallel universe.... 'Toto, I've a feeling we're not in Kansas anymore.' Slip on your ruby slippers and tap your heels (stack trace) and realise you fell through a one way wormhole into hell.Like when, your using Eclipse and your fingers stumble on the keyboard;suddenlyeventually its refactored your entire codebase to align with the latest holy order of the 'one true programming methodology because all others are the spawn of the devil and you will burn in hell if you don't use 11 space tabs interspersed with regular spaces in an apparently pseudo-random order, but actually to a cunningly crafted formula only revealed to the high priests'. Your code has been transposed into COBOL, your menus are now in Sanskrit, the IDE has changed to a set of windows you've never seen before with a dark grey typeface on slightly darker grey backgrounds and you've been signed up to a lifetime's subscription of 'Geriatric Russian ex-wrestlers dirty underpants rune-readers monthly'. (Other nation's ex-wrestlers are available).You know you pressed a <ctrl> <alt> <shift> <alphnumeric> ish combo but have no idea which one or how to get back. You try typing PLUGH and end up in a maze of twisty little passages all alike...I've probably exagerated that a bit...Abstraction is a godsend or a curse - great when you're writing the code and understand how it's pieced together but potentially a nightmare when trying to review or maintain code where every sequence point could trigger a landmine of templated-polymorphic-over-ridden 'goodness'.QuoteThe fact is, C++ code can be more readable and easier to maintain, without adding any code bloat whatsoever. It can be more readable and much harder to maintain, whilst adding lots of unexpectedthings lurking in dark corners. I understand the language has evolved considerably in the years since I used it so it's lots 'better-er'. Or to paraphrase, beyond my ability to understand more than a small fraction of it.QuoteTrouble is there's no internationally agreed standard for 'commom sense'. Try asking Donald.

author: JohnnyBerg
author_rank: Frequent Contributor
timestamp: December 02, 2019, 10:25:14 am
content: Back to the topic starter question, this is a strategie I used in a project.1. In CubeMx set everything up, mcu, clock config, IO, ADC etc.2. Save the project in a temporary folder.3. Generate code, using LL drivers (and not HAL), as a Makefile project.4. Create the folder structure for the project, mine is like this:- In .vscode there is a config to work easy with VSCode. The C++ extension is setup, Cortex Dug configured for debugging, some tasks for clean, build etc.- The build folder is generated by make, and removed by make clean- doc contains the reference guide, datasheet etc. from the mcu- Drives is copied 1 to 1 from the CubeMx project, containing all mcu specific stuff, drivers etc.- src contains my source files, every file in this folder is auto compiled by make.- Makefile is my generic Makefile to build C++ projects, with some changes to work easy with STM32 stuff- startup_*.s is copied from the CubeMx project- the svd file comes from the internet (forgot source, just google). This gives a nice view of the registers of the mcu during debug.- the .ld (linker file) is copied from the CubeMx projectThe source folder looks like this:No explanation needed (I think?)The C++ encapsulates the calls the the ST LL libraries, and the classes are small and very readable. Porting to a different mcu should be fairly simple.This is what my main looks like:Code:char msg;unsigned int cnt = 0;int main(){DigitalOut LED(PA4);Adc adc(ADC1);AnalogIn CH0(adc, PA0);AnalogIn CH1(adc, PA1);AnalogIn CH2(adc, PA2);VRef VRef(adc);Temp Temp(adc);Usart SerialPort(PA9, PA10, 115200);while (1){LED = On;uint16_t in0 = CH0.read();uint16_t vref = VRef.read();uint16_t temp = Temp.read();int len = sprintf(msg, "values [%d]: %d %d %d %d %d\r\n", ++cnt, in0, CH1.read(), CH2.read(), temp, vref);SerialPort.send(msg, len);LED = Off;Delay(1000);}}Again, very readable, maintainable and portable. No need to explain what it does, the code tells the story.Building with all debug info in the firmware gives these sizes:Code:arm-none-eabi-size build/firmware.elftext data bss dec hex filename6744 116 1904 8764 223c build/firmware.elfNot bad, considering most of it comes out of the ST LL libraries.

author: tmadness
author_rank: Regular Contributor
timestamp: December 02, 2019, 09:35:43 pm
content: To add to that I got debugging working with the cortex debug plugin and openocd. in the .vscode folder have the following code in a file called launch.json:Code:{"version": "0.2.0","configurations": [{"type": "cortex-debug","request": "launch","servertype": "openocd","cwd": "${workspaceRoot}","executable": "./Debug/uOvenPort.elf","name": "Debug (OpenOCD)","device": "STM32F429","configFiles": ["C:\\EmbeddedTools\\OpenOCD-20191024-0.10.0\\share\\openocd\\scripts\\interface\\stlink.cfg","C:\\EmbeddedTools\\OpenOCD-20191024-0.10.0\\share\\openocd\\scripts\\target\\stm32f4x.cfg"]}]}Obviously modify config files and device to one specific to your mcu and the location under executable to the compiled binary

author: lucazader
author_rank: Regular Contributor
timestamp: December 02, 2019, 10:37:47 pm
content: I also use the cubemx to generate a makefile project and then do the rest of my development in vscode with a similar openocd setup as tmadness.I find that sometime intellisense doesn't quite get all of the click navigation correct.The best way to make sure it gets this correct is to use compiledb. This is a little python script (pip3 install --user compildb) that will generate a compile_commands.json file that vscode can then use to more definitively navigate the project.I also change the makefile to change the ordering of which the objects are built, always building the startup file first. As If you build with LTO, some versions of gcc will error if this is not the first file which is linked (has to do with weak interrupt definitions getting optimistically optimised away too early)To build with lto it's really easy. just change the optimization line "OPT = -Og" to your desired optimisation the add "-flto" eg "OPT = -Os -flto". This usually results in the smallest binary possible (but not always).I also tend to add the -s makeflag to the makefile and then manually print out the file that is being compiled (eg "cc tim.c") so that the build terminal doesn't look so cluttered with all of the build arguments etc.eg the terminal will look like this when buildingCode:cc stm32f3xx_hal_pwr_ex.ccc stm32f3xx_hal_flash.ccc stm32f3xx_hal_flash_ex.ccc stm32f3xx_hal_i2c.ccc stm32f3xx_hal_i2c_ex.ccc system_stm32f3xx.cld application.elftext data bss dec hex filename0 40320 0 40320 9d80 build/release/application.hex(yes i usually print of the size info of the hex file rather than elf, as the hex file size the the actual size that will be taken up in flash. you can print both the elf and hex to then know both the real flash usage and real static ram usage)Below is what the last part of my makefile looks like to do that. you then only have to add "MAKEFLAGS = -s" at the top of your makefile to suppress the usual outputCode:OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))vpath %.s $(sort $(dir $(ASM_SOURCES)))OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))vpath %.c $(sort $(dir $(C_SOURCES)))all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin$(SZ) $(BUILD_DIR)/$(TARGET).elf$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)$(info cc $(notdir $(<:.c=.c)))$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)$(info as $(notdir $(<:.s=.s)))$(AS) -c $(CFLAGS) $< -o $@$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile$(info ld $(TARGET).elf)$(CC) $(OBJECTS) $(LDFLAGS) -o $@$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)$(HEX) $< $@$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)$(BIN) $< $@Hope this helps some people.

author: dkonigs
author_rank: Regular Contributor
timestamp: October 10, 2020, 09:06:20 pm
content: I know this topic has been idle for a while now, but as I'm just getting started with STM32CubeIDE I stumbled across it.Has anyone found any documentation on the project structure that the code generation actually wants you to use for your projects? It seems to follow some sort of design (except when it adds random out-of-place root-level directories like "USB_HOST"), so I'm thinking it may make sense to actually follow it.However, when adding something that falls into the category of "library code", "module of stuff", "device driver/interface code", etc, that's NOT plopped into place by the STM Cube infrastructure, its not always clear exactly where I'm supposed to put it.Its also not yet clear whether it makes more sense to try and code within the structure this tool sets up for you, or whether to simply let the tool give you a "template" project and then just create your own sanely and logically structured real project that pulls in elements where appropriate.General "software engineering" best practices for embedded projects seem to be something that tutorials and simplistic sample projects for all these platforms pretty much never cover in any useful way, so I'm always looking for guidance and real-world example projects that do a better job of that.

author: jnz
author_rank: Frequent Contributor
timestamp: October 12, 2020, 09:14:39 pm
content: FOR ME..... The STM Cube program is really good for selecting chip, seeing a pin out view, seeing which peripherals work on which pins, figuring out clock settings... and then basically not using any of their code.I’ve been using a Nordic for a couple years so I don’t know, did the “LL” drivers ever go anywhere?

author: dkonigs
author_rank: Regular Contributor
timestamp: October 16, 2020, 03:16:26 am
content: Considering that I'm somewhat new to the platform, and that the latest versions of STM32CubeIDE and HAL seem decently fleshed out, I'm strongly tempted to actually try going with that approach directly.Then again, I just found two unrelated cases in the USB_OTG_FS / USB_HOST code generation where the tool produces code that does not work as generated. Sure, the tool has input boxes that, if I could change their values, it would fix the issues. But those are disabled in the Cube UI. So yeah, its a case of "generate code, edit generated code". (one was an interrupt priority level, the other was a GPIO direction setting)That being said, it seems like I have at least 3 different approaches I can take that might meet my needs:Work within the STM32CubeIDE generated code framework, using notes in the "USER CODE" areas (and version control diffs) to make sure I preserve my necessary edits whenever I regenerate.Use an STM32CubeIDE generated-style project as a starting point, but diverge significantly as I clean things up. (Keep a pristine Cube-generated-code project around to diff whenever there are changes/updates, so I can pull them in manually.)Use a completely clean project, with a more sensible directory layout, but do whatever it takes so that I can still build/run/debug from within the STM32CubeIDE tooling. Start from the generated code, but not necessarily the generated directory structure. Probably use a standalone-capable Makefile-style build process. (Also keep a pristine Cube-generated-code project around to diff whenever there are changes/updates, so I can pull them in manually.)

author: tmadness
author_rank: Regular Contributor
timestamp: October 16, 2020, 06:02:14 pm
content: Ive invariably lost code by live editing like described in (1). For my last project I went with approach (3), copying only things I from a skeleton generated project. I'll probably end up using (3) in the future as well. Although I have to say I'm currently cheating on STM32 with NXP, and I don't know if I'll return back in the near future.

author: lucazader
author_rank: Regular Contributor
timestamp: October 17, 2020, 07:08:55 am
content: I have done something more along the lines of a combo between 1 and 3.Generate a makefile project with cubemx. Then insert a single include and single function call in the generated main.c, inside the user code blocks which will call my application code.From there i use the application code to do any extra configuring of peripherals etc that i need that wasn't already done at startup by the cube.This effectively give me an easy to use and re-configurable BSP generated by the cube. and then write my normal application code separately from this.Have been doing development like this for my job for the last 3+ years and have never had any problems of the cube erasing that one include and one function call.It also allows for multiple BSP's to be generated that will call the same application code. and so long as the application code is written well enough it basically 'just works'(tm)

author: dkonigs
author_rank: Regular Contributor
timestamp: October 22, 2020, 09:46:00 pm
content: Quote from: lucazader on October 17, 2020, 07:08:55 amMy main issue with an approach like this is that sometimes I end up with "fill in the blank" (or need-to-fix) code outside of main.c, such as when I'm including fancier "middleware" type things like USB support.So I'm leaning towards either 2 or 3, though I'll need to do more experimentation with the STM32CubeIDE tooling to get a feel for what I find more usable.There's also the bit where I suspect I may eventually actually need to build multiple firmware images for the same board, one to act as a "bootloader" to do end-user firmware updates (off a USB stick) and the other to be the actual device firmware. So having a common pristine "board bring-up" code dump likely helps with that too.

author: dkonigs
author_rank: Regular Contributor
timestamp: December 05, 2020, 03:25:54 am
content: Okay, now that I've finally built the prototype hardware for my project and am getting underway with firmware development, I figured I might as well share what I settled on.Essentially it is a combination of approaches 2 and 3.I setup an isolated project with the IOC file and CubeMX-generated code on my machine, and use a local git repository (just in its directory) to track changes.For the real project, I built an entirely custom (and sensible) directory structure that reorganizes all of the CubeMX-generated code into a layout that actually makes sense. I then took notes (and even wrote a script) to keep track of the mapping. For the build process, I'm still using an Eclipse/STM32CubeIDE managed build (based off the Cube-generated .project/.cproject files). I'm also keeping a copy of the latest IOC file in the "docs" directory of my project repo, simply as a shared reference.On top of all this, the startup/framework code is logically divided into 3 categories:"external" - Everything that comprises the main HAL, CMSIS, anything put in "Middlewares", and anything needlessly put in a top-level project directory. Reorganized into a sensible structure"system" - Selected pieces that were dumped into "Core" and "Core/Startup" that aren't really project-code, but more like framework/platform glue. This is mostly files that still have the MCU part name in them, or implement various system calls. I may actually end up modifying some of this code, but it will be minimal."src" - The actual project source code, including initialization routines. Some of this is based on snippets that CubeMX generated, but the general structure has been completely rewritten as code specific to the project.Going forward, every time I want to change something on the CubeMX side, this will be my process:Make the change in the STM32CubeMX tool, and have it generate codeUse "git diff" to see what changes actually happened to the output (this is where keeping it in a local repo helps)For simple things like peripheral configuration, manually apply equivalent changes in my own code. For more complex things like framework updates, semi-automatically copy the changed files.If you're curious as to my specific layout, here is the quick-and-dirty script I wrote to implement it:https://pastebin.com/7Nd1miGk(Its probably not ideal for ongoing maintenance, but it does get the basic idea across.)All of this solves three huge "issues" I have with using the CubeMX code dump as-is:I hate being told to code between comment guardrails some committee decided to force upon me. I'm not hacking code onto some professor's framework for a college assignment. I don't need to be told "insert code here" or "insert static variables there".I really don't like STM's generated directory structure. It feels like something bestowed by a committee as a corporate policy, then they threw their hands in the air and got careless when adding additional components to it.I'm not a fan of ST slapping their "Ultimate Liberty License" in random places, and want a structure that makes it easier to keep such code at arm's length. This approach limits that to the bowels of the USB host library and portions of FATFS, and keeps it as far as possible from everything else.