yusefkarim / make-stm32-blinky

Repository to host source for the tutorial I made on Hackster.io
MIT License
1 stars 0 forks source link

Porting to a different board #1

Closed davidedelvento closed 1 year ago

davidedelvento commented 1 year ago

Thanks for making this terrific project. Wonderful way to get started with the toolchain without the CubeIDE!

In your blog post about it at https://www.hackster.io/yusefkarim/upload-code-to-stm32l4-using-linux-gnu-make-and-openocd-a3d4de you wrote

If you are using a different board, this tutorial can still provide all the steps needed to do the same on your board, you will just have to make some small changes to make sure you are targeting your board.

I am using STM32H743. I found (details later) all that I needed for that board, but the problem is the init.c file. It includes a lot of board specific initializations that I found it impossible to port. Perhaps I am doing something wrong? The way that I am attempting it is by comparing the "original" CMSIS/inc/stm32l476xx.h included in your project with the CMSIS/inc/stm32h743xx.h I replaced it with. Really too much changes. A small excertp:

$ make                                                                                                                                                          
arm-none-eabi-gcc -g -Wall -T../CMSIS/STM32L476RG.ld -mlittle-endian -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 --specs=nosys.specs -Iinc -I../CMSIS/inc -o blinky.elf src/init.c src/main.c ../CMS
IS/src/system_stm32h7xx.c ../CMSIS/src/startup_stm32h743xx.s                                                                                                                                                       
src/init.c: In function 'System_Clock_80MHz_Init':                                                                                                                                                                 
src/init.c:25:21: error: 'RCC_PLLCFGR_PLL2RGE_HSI' undeclared (first use in this function); did you mean 'RCC_PLLCFGR_PLL2RGE_0'?                                                                                  
   25 |     RCC->PLLCFGR |= RCC_PLLCFGR_PLL2RGE_HSI;                                                                                                                                                               
      |                     ^~~~~~~~~~~~~~~~~~~~~~~                                                                                                                                                                
      |                     RCC_PLLCFGR_PLL2RGE_0                                                                                                                                                                  
src/init.c:25:21: note: each undeclared identifier is reported only once for each function it appears in                                                                                                           
src/init.c:30:22: error: 'RCC_PLLCFGR_PLLN' undeclared (first use in this function); did you mean 'RCC_PLLCFGR_PLL2RGE'?                                                                                           
   30 |     RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN;                                                                                                                                                                     
      |                      ^~~~~~~~~~~~~~~~                                                                                                                                                                      
      |                      RCC_PLLCFGR_PLL2RGE                                                                                                                                                                   
src/init.c:31:21: error: 'RCC_PLLCFGR_PLLN_4' undeclared (first use in this function); did you mean 'RCC_PLLCFGR_PLL2RGE'?                                                                                         
   31 |     RCC->PLLCFGR |= RCC_PLLCFGR_PLLN_4 | RCC_PLLCFGR_PLLN_2;                                                                                                                                               
      |                     ^~~~~~~~~~~~~~~~~~                                                                                                                                                                     
      |                     RCC_PLLCFGR_PLL2RGE                     

Is there a better way to do this port?

davidedelvento commented 1 year ago

Steps performed to find the appropriate CMSIS files

Linker: find ~/STM32* -name STM32H743ZI*.ld | grep CMSIS (too many without the grep)

Includes: find ~/STM32* -name core_cm7.h

Sources: find ~/STM32* -name system_stm32h7xx.c | grep CMSIS (too many without the grep)

Assembler: find ~/STM32* -name startup_stm32h743xx.s | grep CMSIS (too many without the grep)

So this is how I copied

cp ~/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Projects/NUCLEO-H743ZI/Templates/SW4STM32/STM32H743ZI-Nucleo/STM32H743ZITx_FLASH_RAM_D1.ld CMSIS
cp /home/davide/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Drivers/CMSIS/Device/ST/STM32H7xx/Include/stm32h743xx.h      CMSIS/inc/
cp /home/davide/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Drivers/CMSIS/Device/ST/STM32H7xx/Include/system_stm32h7xx.h CMSIS/inc/
cp /home/davide/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Drivers/CMSIS/Core/Include/core_cm7.h                        CMSIS/inc/
cp /home/davide/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Drivers/CMSIS/Core/Include/cmsis_version.h                   CMSIS/inc/
cp /home/davide/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Drivers/CMSIS/Core/Include/cmsis_compiler.h                  CMSIS/inc/     # there is also a *different* Core_A
cp /home/davide/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Drivers/CMSIS/Core/Include/cmsis_gcc.h                       CMSIS/inc/     # there is also a *different* Core_A
cp /home/davide/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Drivers/CMSIS/Core/Include/mpu_armv7.h                       CMSIS/inc/
cp /home/davide/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Drivers/CMSIS/Device/ST/STM32H7xx/Include/stm32h7xx.h        CMSIS/inc/
cp /home/davide/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Drivers/CMSIS/Device/ST/STM32H7xx/Source/Templates/gcc/startup_stm32h743xx.s      CMSIS/src    # there is also a arm and a iar
cp /home/davide/STM32Cube/Repository/STM32Cube_FW_H7_V1.10.0/Drivers/CMSIS/Device/ST/STM32H7xx/Source/Templates/system_stm32h7xx.c             CMSIS/src
davidedelvento commented 1 year ago

Is there a better way to do this port?

Perhaps I need to re-generate the init.c file with Cube? If so, how?

yusefkarim commented 1 year ago

Hi @davidedelvento, I'm glad you found the tutorial helpful! I wrote that post quite sometime ago, when I was young and somewhat inexperienced (I still am not much more experienced). That being said, you are right; init.c really is a show stopper for porting to a new board. We are seeing first hand the utility of HALs (hardware abstraction layers) that would abstract all the underlying details you see in init.c to make it much more portable.

I wrote init.c by hand, but maybe Cube could generate something similar? Not sure. If you are really motivated, it is possible to port by hand (but it will be some effort)! You would have to get familiar with the reference manual for your board:

You could start simple, for example, by just implementing simplified versions of LED2_Init() and User_Button1_Init() (e.g., without interrupts). You can skip System_Clock_80MHz_Init entirely really, you will just get stuck with the default clock configuration for your board without it (I think Figure 42 in the above mentioned manual explains the clock and its configuration).

One last note: if you are looking to learn things at a low level like this then moving to higher-level abstractions without getting stuck with stupid CubeIDE, I personally would recommend skipping C and going to Rust! This is a personal opinion, but I think Rust is muuuuch better for (reliable and secure?) embedded programming. I have some code examples here: yusefkarim/stm32f4-playground. It might be somewhat outdated now. You can also find an immense number of resources here: awesome-embedded-rust.

All the best!

davidedelvento commented 1 year ago

Thanks for the comments and suggestions.

FWIW, regarding Rust, in a vacuum I would do that (as I would pure Makefiles and gcc). Problem is, as you have said, there are so many details than one has to learn about a board, that basically one is forced to use stupid CubeIDE to "generate" the code in cryptic ways. Even so, trying to change small details often break things. For example, I have two projects which are exactly identical as files are concerned, but one works and the other doesn't. One was automatically generated by CubeIDE, the other was created by me copying all files. Why doesn't that work? After countless tests, I gave up trying to understand. If ST had made example repositories and documentation with the relevant files which one could manually cherrypick as appropriate, then the situation would have been different, but they decided to make it "easy" instead :( Alright, thanks again and sorry for the rant.