This page has some ideas and other things I found that could be useful in the future.
--print-memory-usage: Printing memory usage by section from GCC
It turns out that GCC has a flag that works similarly to our pretty_size.sh
. If you add -Wl,--print-memory-usage
to the stm32f0xx linker flags via adding it to LDFLAGS
in platform/stm32f0xx/platform.mk, you get output like this at the end of the make build
output:
Building power_distribution.elf for stm32f0xx Memory region Used Size Region Size %age Used FLASH: 28712 B 128 KB 21.91% RAM: 7736 B 16 KB 47.22%
It looks like GCC uses the memory sections defined in the linker script (our stm32f0discovery_def.ld
) to determine how much of each memory section we used.
See https://embeddedartistry.com/blog/2020/08/17/three-gcc-flags-for-analyzing-memory-usage/, also https://blog.thea.codes/the-most-thoroughly-commented-linker-script/ for some linker script resources.
Generic GPIO
We have a few different kinds of GPIO pins in MSXIV: there are the native GPIO pins on the STM32, accessible via the gpio
library, and a few types of I2C IO expanders accessible via their driver (MCP3427 with mcp3427_gpio_expander
, PCA9539R with pca9539r_gpio_expander
).
All of these drivers/libraries implement the same basic interface for each pin – init_pin
, set_state
, toggle_state
, and get_state
– but they’re entirely incompatible at the moment, so you can’t mix and match GPIO types. This leads to awkward situations like in the bts_7200_load_switch
and bts_7040_load_switch
drivers, where there are two separate init functions and a whole ton of duplication where the only change is whether one pin is a native STM32 GPIO pin or a PCA9539R IO expander pin.
In any remotely object-oriented language, this problem is solved by having each driver’s GpioAddress
class inherit from a base AbstractGpioAddress
class or implement an IGpioAddress
interface; then libraries that need to manipulate GPIO pins but don’t need to care about what they are can pass around AbstractGpioAddress
instances and call set_state
on them, and dynamic dispatch will be used to route the call to the appropriate driver. Unfortunately, C is not remotely object-oriented, so we have to implement it ourselves.
I don’t have a precise design for this, but we could possibly use a form of virtual method table - have the GpioAddress
-type structs contain a pointer to a vtable
struct which contains function pointers for each virtual function (init_pin
, set_state
, etc). The vtable
struct would be a global constant for each type. See https://stackoverflow.com/a/8194632.