I have a fairly large firmware project on the bench at the moment. The hardware doesn't exist yet. A lot of the code relates to the process above the peripherals.
So, instead of using CubeIDE and writing for a dev board, I created a basic Unix C project. Added unit tests and started down that route, more like I would in work.
I was fairly surprised to write a custom fifo module. Then write a full suite of unit tests for it and ... it worked first time with one minor bug. My "design" expected if you call "take" on an empty fifo you get the last entry and the pointers dont move. Of course the pointer has already moved and points at head, so instead of working out what that will be, i just replaced it with "Undefined". URUN is set though.
I then moved to the "Bus Interface". The part of code which handles the external bus communications.
Here it introduces the concept of test surrrogates. The bus_interface requires a GPIO API. So, again, rather than jump to an actual MCU, I wrote an interface. Classic C, no fancy abstractions. gpio.c doesn't exist yet, but gpio_test_stub.c does.
I implemented functions as "What I need from here". "read_address", "read_select", "isEnabled()" read/write_data and so on. "release_data" "drive_data" of course.
The gpio_test_stub has extra static methods the unit test can "extern" in, which allow it to "prime it" with test data. When the actual bus_interface calls "read_address" a test address is returned.
I am still curious as to how far I can take this before it meets the micro and ... how much good it did me in terms of bugs and struggles.
The hardware arrived as a PCB blank yesterday, so it will be a while and for it's first few days I don't expect it will be running real firmware, rather debug and diagnostics firmware to prove out the hardware.
Anyone else use TDD (Test driven development). Basically you isolate out code away from the hardware, so you can write tests even before you write the code, or in parallel with 2 people (1 and an AI).
The "interface" here is a very low level and very old one, I doubt any of it will survive the compile optimisation in the wild. Using swapped "implement.c" files for headers is a standard C feature and there should be very little other "glue" around when its deployed for real.
For context. The firmware - this version - exposes an STM32 CDC peripheral on the 68000 parallel "8x8" IO Bus. 8 address, 8 data, ctl. Because the STM32 - in my hands anyway - is not going to be comfortably fast enough for various portions of the bus cycle, I used up an FPGA I had in stock as "Bus Controller". It treats the STM32 like a peripheral IC. Give it an ENABLE line, an IO_ACK line and choreographs the databus and data_ack dance at nano second speeds. It itself is not written yet. Well, it's "drafted" in Verilog and the simulation "looks right". Buts that only 10% the hurdle.
The entire chain for "Hello world" here is custom from 68k ASM, FPGA Verilog bus control, STM32 C code peripheral facade... the more I can test in advance the better! All of it has to work right for it to say "Hello".
The firmware model has two sides. The hot looped "in thread" bus facing portion and the interrupt and flag signalled back end actual peripherals. The touch in careful places only. For this first version the fifos are the interface between them. The plan is to just shut interrupts off while a bus transaction is in flight. Signal by flags things like "TX_START" for an empty fifo transitioning to not empty for example.