JeeH 5.2.0
February 12, 2024
JeeH version 5.2.0 release notes and highlights:
This is the most extensive release so far, with new SDIO and Ethernet drivers. Everything is still highly experimental, but the main pieces of the multitasker puzzle are starting to fit together quite nicely. Using lightweight messages as the main vehicle for communication between tasks and drivers works really well and allows pacing the different pieces of an application.
The driver model helps decouple the different layers, as illustrated by the
eth
driver and net
worker task: neither one needs knowledge of the other
(their code can be included in either order). All the net
worker needs is the
id of the eth
driver to communicate with it. Conversely, the eth
driver
has no knowledge whatsoever of the protocol stack implemented in net
.
A major design puzzle was how to manage buffers between the ethernet driver and
the net worker task. The solution is to let net
allocate and own all packet
buffers, constantly handing as many of them over to eth
as it needs
(determined by the number of read DMA descriptors). This is done via a message
chain, with eth
pulling off what it needs.
Buffer management for packet sends is minimal: there is no logic yet to postpone a packet transmission when the buffer pool is empty. There is also no logic to insert an ARP broadcast query when sending packets to an unknown IP address, nor the logic needed to go through the gateway for destinations outside the subnet.
Many many aspects of networking are still messy, incomplete, or downright lacking. There is proof-of-concept code for the ARP, ICMP, UDP, DHCP, DNS, and TFTP protocols, but TCP – which is really the most important one – is only a stub for now.
But it’s a start: the eth.cpp
demo app for Disco-F750 and Nucleo-F439
sucessfully gets an IP address over DHCP, can perform DNS lookups, respond to
echo “pings”, and fetch a TFTP file.
The other main new code in 5.2.0 is the sdio
device driver, which can read and
write blocks on a (micro-) SD card using DMA. It properly starts in “slow” 1-bit
mode and then switches to full-speed 4-bit wide mode. This works on a small 64
MB µSD card used for testing, but needs a bit more tender care to handle more
sizes. As with all drivers, tasks suspend / resume during I/O.
With DMA-based drivers for UARTs, Ethernet, and SD cards comes a new puzzle: each of them currently uses slightly different conventions for buffer management. This is partly due to their inherent differences: UARTs are byte-oriented, Ethernet is packet oriented (with headers + payload), and SD cards use fixed-size blocks. It’d be nice to find a more uniform approach …
Given JeeH’s fast compile times and small build sizes, it is very
straightforward to adopt a quick edit-run cycle using printf
calls for
debugging (and assertions to catch strange behaviour). The printf
and
snprintf
code is now based on an outf
system call, which means that their
relatively large stack overhead now always takes place in the shared Main Stack
Pointer (MSP) area. Small processes can now use smaller stack areas, even when
using printf’s. When tied to a DMA-UART, printf
relies on system calls, which
prevents its use within driver code, alas.
Much of the recent software development in JeeH was done using STM’s “F7508-DK” Discovery dev-board. For ethernet development, I have now switched to the “F439ZI” Nucleo board, which is sufficient for this and eliminates all CPU / DMA cache issues (only present in Cortex M7).
My development workflow is as follows (in the JeeH
source tree,
https://git.sr.ht/~jcw/jeeh):
- change to the current development directory:
cd example/f439n144/
- start a serial port in a new window:
pio device monitor
- start a compile watcher in a 2nd window:
make compile
- start Vim (or in my case MacVim) to edit source code files
- perform a build + upload in a 3rd window:
pio run -e eth -t upload
And then alternate between 4) and 5) while watching the output of 2) and 3). Poor man’s IDE …
Onwards!