Adding a new target to BF shouldn't be too hard if the new target is similar to an already existing target - right? Let's see what we have
- STM32H743: a bit older
- STM32H730: somewhat special, because:
- This chip uses external memory to store the application
- but it shares a reference manual with H723, H725, H733, and H735
- STM32H723: as far as I know, this was just a draft and never actually worked.
Let's take a closer look at the H743.
Memory areas
BF's H743 target uses a slightly customized layout that reserves flash for the reset handler and an emulated eeprom. Both BF and CubeIDE define areas in ITCM and DTCM for critical functions and data. Here's a table that compares BF's H743 memory areas with CubeIDE's H725/H735 standard:
BF H743 | CubeIDE H725/H735 |
---|---|
FLASH (reset handler) | FLASH |
FLASH_CONFIG (emulated EEPROM) | |
FLASH1 (application and constants) | |
ITCM_RAM | ITCMRAM |
DTCM_RAM | DTCMRAM |
RAM | RAM_D1 |
D2_RAM | RAM_D2 |
MEMORY_B1 (*) | RAM_D3 (**) |
*) external memory, can only be used if there's actually some external memory connected to the MCU
**) not used by BF so we can hopefully remove that. Or not, since simply having a memory area in a linker script doesn't hurt.
The BF linker script also defines two aliases:
REGION_ALIAS("STACKRAM", DTCM_RAM) REGION_ALIAS("FASTRAM", DTCM_RAM)
The memory area names are a bit different between BF and CubeIDE but that's not a problem because these are only used within the linker script. A little understanding surely doesn't hurt so let's also have a look at the system architecture diagram for the H725. I've already marked the memories used:
- Top left: ITCM and DTCM are tightly coupled with the core for fast access.
- Center: Flash and SRAM in D1 domain via AXI
- Right: SRAM1 and SRAM2 in D2 domain via AXI and D1-to-D2 AHB
- Bottom: SRAM4 in D3 domain via AXI and D1-to-D3 AHB; not used by BF
The two DMA blocks in D2 domain (DMA1 and DMA2) allow for fast transfers between memory and peripherals within that domain, and we see something similar for BDMA (basic DMA) in D3 domain. The MDMA controller also has access to blocks in D2 domain, but that's somewhat convoluted. So we do see why it make sense to deliberately place certain I/O buffers in D2 memory ("D2_RAM" or "RAM_D2" in the table above).
Now we'd like to bring BF's memory areas over to the CubeIDE project. Turns out we can pretty much copy and paste them, as long as everything remains consistent within the linker script. A quick test reveals that the dev board still runs blinky after doing that. Great!
Memory Sections
The linker script further defines a number of memory sections. For plain old C we typically see
- ".text" (instructions),
- ".data" (initialized variables) and
- ".bss" (uninitialized variables)
But there's a lot more, because we need to place certain instructions in certain locations: reset handler and other ISRs need to be placed correctly in flash, and there has to be a section in ITCM that we can used to properly place functions that are supposed to be executed faster than others. Similarly, certain variables go into DTCM and I/O buffers into SRAM in D2 domain. And thus we end up with something like this:
BF H743 | CubeIDE H735 |
---|---|
.isr_vector >FLASH | .isr_vector >FLASH |
.text >FLASH1 | .text >FLASH |
.rodata >FLASH | |
.tcm_code >ITCM_RAM AT >FLASH1 | |
.ARM.extab >FLASH1 | .ARM.extab >FLASH |
.ARM >FLASH1 | .ARM >FLASH |
.pg_registry >FLASH1 | |
.pg_resetdata >FLASH1 | |
.preinit_array >FLASH | |
.init_array >FLASH | |
.fini_array >FLASH | |
.data >RAM AT >FLASH1 | .data >RAM_D1 AT >FLASH |
.bss >RAM | .bss > RAM_D1 |
.sram2 >RAM | |
.fastram_data >FASTRAM AT >FLASH1 | |
.fastram_bss >FASTRAM | |
.dmaram_data >RAM AT >FLASH1 | |
.dmaram_bss >RAM | |
.DMA_RAM >RAM | |
.DMA_RW_D2 >D2_RAM | |
.DMA_RW_AXI >RAM | |
.persistent_data >RAM | |
._user_heap_stack >STACKRAM = 0xa5 | ._user_heap_stack >RAM_D1 |
.memory_b1_text >MEMORY_B1 |
Let's take a look at the similarities first: All "basic" sections have identical names (.isr_vector, .text, .data, ._user_heap_stack) and end up in similar memories. The purpose of some of the additional sections defined In BF's linker script isn't too obvious to me, but let's try:
- .tcm_code: a section for code that will be copied to ITCM for fast execution. This needs to be stored in flash as well, so that it can be copied during startup.
- .pg_registry: no clue.
- .pg_resetdata: same!
- .sram2: ends up in RAM, might be a leftover from older targets? I don't know.
- .fastram_data and .fastram_bss: these go into DTCM
- .dmaram_data and .dmaram_bss: my guess: some of BF's old code might have been written for MCUs that can't use DMA in all RAM locations. For those, it would have been required to explicitly locate DMA-able variables in DMA-able memory.
- .DMA_RAM: my guess is that the purpose of this section is similar to that of dmaram_data and dmaram_bss, and whoever introduced it couldn't find those sections.
- .persistent_data: seems a bit weird here as it's simply placed in RAM. There would be battery backed RAM available (see system architecture diagram above, D3 domain), but it's not used. Maybe some MCUs also have RAM areas that aren't altered by some reset sources. Let's ignore this one.
- .memory_b1_text: used in other targets that actually have external memory.
On the other side we have some extras in CubeIDE's linker script:
- .rodata: constants stored in flash, nothing special. Would otherwise end up in .text
- .preinit_array, .init_array and .fini_array: Used for C++ constructor and destructors. Not relevant in a simple C application
Transferring all of BF's memory sections to my CubeIDE blinky project and removing the C++ constructor/destructor sections from it didn't break anything. It still blinks!
Next I'll try to alter the CubeIDE project's startup code to do more of what BF is doing. After that, and if it's still not broken then, it might make sense to transfer things back to betaflight.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.