A simple demonstration of using D to bare-metal program an STM32F29I Discovery Board
- It works!
- No CRT startup files, libgcc, libc, or vendor's C peripheral libraries were used. EVERYTHING is in D.
- [Compile-time enforcement of register/bitfield mutability] (https://github.com/JinShil/stm32f42_discovery_demo/blob/master/source/stm32f42/mmio.d#L346-L456)
- Compile-time optimization of MMIO register access by turning byte- and half-word-aligned accesses into single, atomic reads/writes. Single-bit bitfields are optimized at compile time to use ARM's bitbanding feature for atomic access. This increases performance, reduces code size, and is all abstracted from the user.
- [Setting multiple bit fields in a register with a single read-modify-write] (https://github.com/JinShil/stm32f42_discovery_demo/blob/master/source/stm32f42/mmio.d#L610-L616)
with(GPIOA.MODER)
{
setValue
!(
MODER3, 0b10 // Alternate function mode
, MODER4, 0b10
, MODER6, 0b10
, MODER11, 0b10
, MODER12, 0b10
);
}
- Seems to be pretty fast, but I still need to verify the generated code to ensure optimizations are being performed properly
- Small Code Size (6k). The data in the BSS segment is my LCD's frame buffer, so that really doesn't count.
text data bss dec hex filename
6200 0 153600 159800 27038 binary/firmware
- The code resembles the register descriptions in the STM32 reference manual for easy cross-referencing.
- Good integration with tooling. e.g Register descriptions in DDoc popups, and register layout in outline and code completion windows. In other words, the code is the datasheet.
- The implementation of D runtime is minimal, and therefore very incomplete. Many features of D are not usable.
volatileLoad
/volatileStore
were added in 2.067.0, but that has not yet been merged into GDC. For now, I'm misusing GDC'sshared
bug as a feature. See code.- Due to bug 12496, I can't enforce that a
Bitfield
belongs to aRegister
when using thesetValue
template. - Really long build times (Nearly 2 minutes to generate a 6k binary!). I suspect that is due to my liberal use of D's metaprogramming and compile-time features.
- I didn't put much diligence and care into some of the code, because I was anxious to just get something to appear on the LCD screen. There are a lot of magic numbers that should be enums, and there is no hardware abstraction layer - the program directly manipulates the memory-mapped IO registers.
- TypeInfo faking. Potential solution
- The compiler generates a
TypeInfo.name
string for each and every bitfield in my code, and puts it in therodata
segment. Due to GCC bug 192,-fdata-sections
doesn't put this data in its own section, so my binary becomes more than 400k. See this discussion for details. So, I added a sed hack to my build script put these strings in their own sections, and that brings my binary down to around 5-6k. But it's not perfect and sometimes results in removing strings that are needed. - Using an unimplemented druntime feature will result in a linker error, at best, instead of a compiler error. Potential solution.
- I have to put a
.value
every time I want to access a memory-mapped IO bitfield. This is because there is nostatic alias x this;
in D'sstatic opAssign
isn't symetric. I think if I were to do this again, I would use a different pattern altogether.