JeeH 5.2.0

JeeH 5.2.0

February 12, 2024
News

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):

  1. change to the current development directory: cd example/f439n144/
  2. start a serial port in a new window: pio device monitor
  3. start a compile watcher in a 2nd window: make compile
  4. start Vim (or in my case MacVim) to edit source code files
  5. 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!