all: Add the Morse Micro Wi-Fi HaLow driver. - #1
Conversation
|
Looks great! I'd like to add more CI: code formatting (C and Python), code spell, building under clang. And putting CI related functions in |
|
I can add. Give me a second. |
|
Almost done, adding a QEMU build for the device and not the host. |
|
No such thing as too much CI 😂 |
|
The CI added here doesn't seem to be running and I'm not sure why. It should work... |
df960ad to
cbba856
Compare
|
@dpgeorge - Okay, finished. I think the PR needs to be merged first, as the CI for the PR doesn't run on itself. Break this PR into CI edits and code? |
I'm quite certain it should run here... |
|
I checked github settings and the actions are enabled. Not sure what's wrong.
Yes, please open a separate PR in this repo to add just the code formatting and spelling workflows. Then I'll merge that first. |
cf788cc to
8422aef
Compare
|
Rebased |
|
Wait, sending CI stuff, AI just decided to drop it for no reason. Readding... |
af156dd to
33c722a
Compare
|
@dpgeorge - Ready |
|
CI is working, nice! |
| # | ||
| # make build + run | ||
| # make asan build + run under ASan/UBSan (catches what the checks miss) | ||
| CC ?= gcc |
There was a problem hiding this comment.
This line does nothing because CC is set by make to the default value of cc. So maybe just remove this line.
| # Cortex-M55 needs arm-none-eabi-gcc 14 or newer (Ubuntu 24.04 ships 13.2, | ||
| # which rejects -mcpu=cortex-m55 with hard float). Override CC to point at a | ||
| # suitable toolchain if the default is too old. | ||
| CC ?= arm-none-eabi-gcc |
There was a problem hiding this comment.
This line does nothing: building with just make doesn't work because CC defaults to cc and is not overridden by this line.
Suggest making this (and the GCC variable below) and unconditional =:
CC = arm-none-eabi-gcc
That gets make working. And still allows overriding it via make CC=foo.
| CC ?= gcc | ||
| HALOW := ../../src | ||
| SDK := ../../lib/mm-iot-sdk/framework/morselib/include | ||
| CFLAGS := -m32 -std=c11 -Wall -Wextra -Werror -g -O1 \ |
There was a problem hiding this comment.
I think these call all just use = (no need for :=).
| CFLAGS := $(ARCH) -std=c11 -Wall -Wextra -Werror -Wno-unused-parameter -Og -g \ | ||
| -ffreestanding -fno-common \ | ||
| -Istub -I$(HALOW) -I../../lib/mm-iot-sdk/framework/morselib/include | ||
| LDFLAGS := $(ARCH) -T$(LDSCRIPT) -nostartfiles -Wl,--gc-sections \ |
There was a problem hiding this comment.
I think these (and others in this file) can all use = instead of :=.
| @@ -0,0 +1,14 @@ | |||
| // Host-test stub: halow.h embeds these by value, so they need to be complete | |||
| // (the driver task and the UMAC event loop), plus one more for the SDIO/SPI IRQ | ||
| // task when the SDIO transport is in use. | ||
| #ifndef MM_HALOW_MAX_TASKS | ||
| #define MM_HALOW_MAX_TASKS (4) |
There was a problem hiding this comment.
Suggest renaming this option to MM_HALOW_SCHED_MAX_TASKS`.
| // Task turns per mm_halow_sched_run() call. | ||
| // Ceiling on any single wait, however long the caller asked for. | ||
| #ifndef MM_HALOW_WAIT_MAX_MS | ||
| #define MM_HALOW_WAIT_MAX_MS (10000) |
There was a problem hiding this comment.
Suggest renaming this option to MM_HALOW_SCHED_WAIT_MAX_MS.
| // an unevenly-dividing request yields a *faster* bus (40MHz becomes 50MHz on a | ||
| // 200MHz AHB). Check the rate you got. | ||
| #ifndef MM_HALOW_SPI_BAUDRATE | ||
| #define MM_HALOW_SPI_BAUDRATE (12 * 1000 * 1000) |
| // Set by boards that invert the transceiver's BUSY output before it reaches the | ||
| // MCU. RESET_N is active low at the transceiver and is not configurable. | ||
| #ifndef MM_HALOW_BUSY_INVERTED | ||
| #define MM_HALOW_BUSY_INVERTED (0) |
| * its own heap, so nothing else needs it. morselib never calls these at run | ||
| * time, so the stubs only exist to satisfy the link, and _sbrk deliberately | ||
| * fails rather than hand out any of MicroPython's memory. They are weak so that | ||
| * a port supplying real implementations takes precedence. |
There was a problem hiding this comment.
IMO this file does not belong in this driver. It is unfortunate that the mm-iot-sdk links against these, but it will need to be up to the host system (eg MicroPython) to provide them (and at least alif already does).
Instead I suggest removing this file, and moving this comment into the README, under the "Integrating" section.
Otherwise, it might be very confusing when someone integrates this driver, starts calling libc functions and finds they all fail (due to these weak stubs being pulled in behind the scenes).
There was a problem hiding this comment.
Claude: osal.c still carries two weak libc stubs (_kill/_getpid) of the same kind as the removed file. I left them since only mm_halow_libc.c was flagged, but they're the same principle — I can pull those out too if the driver needs to carry none.
There was a problem hiding this comment.
I suggest removing both those _kill and _getpid stubs. According to the comments they aren't even used.
| # The transceiver firmware, and optionally a board configuration file holding | ||
| # calibration data, are linked in as binary blobs. A board picks its BCF by | ||
| # name with MM_HALOW_BCF; the SDK keeps them per chip under morsefirmware. | ||
| MM_HALOW_CHIP ?= mm8108 |
There was a problem hiding this comment.
might also need to be changed to MM_HALOW_CHIPSET to match the C-level config
84c71cd to
3d9ddd7
Compare
dpgeorge
left a comment
There was a problem hiding this comment.
Thanks for updating. Just a few more comments and it should be good to merge.
| This is a driver for the Morse Micro MM6108/MM8108 802.11ah (Wi-Fi HaLow) transceivers. | ||
| A portable driver for the Morse Micro MM6108/MM8108 802.11ah (Wi-Fi HaLow) | ||
| transceivers, modelled on the structure of | ||
| [cyw43-driver](https://github.com/georgerobotics/cyw43-driver): the driver is |
There was a problem hiding this comment.
suggest removing all references to cyw43-driver. the fact it's based on that is just to get a good head-start, it's not something that needs to stay in the docs/code
| // mm_halow_ticks_ms() -> uint32_t | ||
| // A free-running millisecond tick counter. | ||
| #ifndef mm_halow_ticks_ms | ||
| #error "port must define mm_halow_ticks_ms" |
There was a problem hiding this comment.
This doesn't need to be a macro. It could instead be just declared here as:
uint32_t mm_halow_ticks_ms(void);and then a port can define it as inline:
static inline uint32_t mm_halow_ticks_ms(void) {
return ...
}
The benefit of that way is it gives a clear signature for the function, and prevents use of macros which can lead to surprising outcomes.
(This should work fine, you can define a static inline function (done in mm_halow_configport.h prior to defining it as non-static (but not the other way around).)
| // Pin accessors, applied to the MM_HALOW_CS/RESET/WAKE/BUSY/IRQ pin values | ||
| // defined by the port. | ||
| #ifndef mm_halow_hal_pin_write | ||
| #error "port must define the mm_halow_hal_pin_read/write/input/output accessors" |
There was a problem hiding this comment.
As above, suggest defining these as proper C function declarations instead.
|
|
||
| // mm_halow_in_irq() -> bool | ||
| // True when executing in interrupt context (on Cortex-M: IPSR != 0). | ||
| #ifndef mm_halow_in_irq |
There was a problem hiding this comment.
As above, a proper C declaration.
| #endif | ||
|
|
||
| /*******************************************************************************/ | ||
| // Functions the port must implement (see README.md). |
There was a problem hiding this comment.
These could arguably be declared in a separate header eg mm_halow_port.h. But keeping them here (for now) is a reasonable pragmatic solution.
| // Called when the driver hits an unrecoverable internal failure (a morselib | ||
| // assertion). The port routes this to its own assert/fatal-error handling; it | ||
| // must not return. | ||
| void mm_halow_assert_fail(void); |
There was a problem hiding this comment.
Suggest mm_halow_port_assert_fail() to match other naming here.
A portable driver for the Morse Micro MM6108/MM8108 802.11ah (Wi-Fi HaLow) transceivers, extracted from the MicroPython network.HALOW pull request and reorganised along the lines of cyw43-driver: - src/ holds the driver: the SD-over-SPI transport to the transceiver mapped onto a small mm_halow_port_* interface, an lwIP netif, a packet-memory pool, and an OSAL/scheduler shim that runs the vendor library (morselib) cooperatively off the host's scheduler with no vendor RTOS. - mm_halow_config.h defines the host integration contract; the embedder provides mm_halow_configport.h (or MM_HALOW_CONFIG_FILE) with atomic sections, a millisecond tick, pin accessors, interrupt-context detection, and the port functions (SPI, private heap backing, hardware RNG, fallback MAC, optional edge IRQ). - lib/mm-iot-sdk is the Morse Micro MM-IoT-SDK submodule, providing the prebuilt morselib and the transceiver firmware/BCF blobs; mm_halow.mk is a build fragment for make-based embedders covering morselib's newlib linkage, the blob embedding, and fetching the mm-iot-sdk submodule on demand. - tests/host compiles the real allocator natively (233 checks, plus an ASan/UBSan variant); tests/qemu runs the real scheduler, whose context switch is naked asm, on a Cortex-M55 under QEMU (51 checks); tests/hardware carries the on-device throughput soak harness the driver was validated with. Everything the driver needs from MicroPython in the original pull request now arrives through the configuration contract: MICROPY_* macros became MM_HALOW_*, the halow_* API became mm_halow_*, and the machine-SPI, GC-heap and pin-interrupt couplings became port hooks. Tested: both test suites pass locally (host: gcc -m32 + ASan; qemu: arm-none-eabi-gcc 14.3.1 on mps3-an547). Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Extends tools/ci.sh (added with the formatting and spelling CI) with the test entry points, and wires them up: - tests.yml runs the host allocator tests (plus ASan) and the QEMU Cortex-M55 scheduler test. - tests_clang.yml builds and runs both with clang too; the QEMU test cross-compiles the sources with clang and links with GCC, so clang also covers mm_halow_sched.c, which the host tests do not build. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
3d9ddd7 to
e2c5154
Compare
dpgeorge
left a comment
There was a problem hiding this comment.
Looks good, let's get this in.
micropython/mm-halow-driver#1 has merged, so re-pin the submodule to the merged commit and follow the driver's reviewed integration contract: - The tunable options were renamed: MM_HALOW_AP -> MM_HALOW_ENABLE_AP, MM_HALOW_PIN_IRQ -> MM_HALOW_ENABLE_PIN_IRQ, MM_HALOW_CHIP -> MM_HALOW_CHIPSET, MM_HALOW_MAX_TASKS -> MM_HALOW_SCHED_MAX_TASKS. - The tick, interrupt-context and pin hooks are now C function declarations rather than macros, so the configport provides them as static inline functions and defines mm_halow_pin_t. - The driver's assert hook is mm_halow_port_assert_fail(), provided here. - The driver no longer ships newlib syscall stubs (mm_halow_libc.c was removed), so the port provides the weak back-end morselib links against, and extmod.mk drops mm_halow_libc.c from the source list. Builds green for OPENMV_N6 and OPENMV_AE3 (M55_DUAL). Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Summary
The
drivers/halow/content from micropython/micropython#19617, reorganisedalong the lines of cyw43-driver as discussed there:
src/-- the driver, with the C API renamedmm_halow_*and allconfiguration macros
MM_HALOW_*. Everything the driver previously tookfrom MicroPython (machine-SPI, the GC-heap root for its private heap, the
pin-interrupt callback, atomics/ticks/errnos/printf) now arrives through
the
mm_halow_config.h/mm_halow_configport.hcontract: the embeddersupplies atomic sections, a millisecond tick, pin accessors,
interrupt-context detection, and the
mm_halow_port_*functions (SPItransport, heap backing, hardware RNG, fallback MAC, optional edge IRQ).
mmport.hkeeps its name -- morselib's own headers include it.lib/mm-iot-sdk-- the Morse Micro MM-IoT-SDK as a submodule, pinned tothe exact version the hardware numbers in the MicroPython PR were measured
with (2.12.3).
mm_halow.mk-- build fragment for make-based embedders: prebuilt-morseliblinkage (grouped with the target multilib's libc/libm for
-nostdlibhosts) and firmware/BCF blob embedding.
tests/host-- the allocator suite compiled natively from the realsources (233 checks), plus an ASan/UBSan variant.
tests/qemu-- the scheduler suite on a Cortex-M55 under QEMU (51checks); the context switch is naked asm, so it can't run on the host.
tests/hardware-- the on-device throughput/soak harness the driver wasvalidated with (20-minute TCP/UDP soaks against a HaLow AP), run by hand.
.github/workflows/test.yml-- runs the host and QEMU suites in CI.Testing
Both suites pass locally: host with gcc
-m32and under ASan/UBSan, QEMUwith arm-none-eabi-gcc 14.3.1 on mps3-an547 (Cortex-M55 needs GCC >= 14).
The MicroPython-side integration (submodule + configport + port glue) is the
follow-up, after which the N6/AE3/RT1062 hardware gauntlet re-runs.