I think I made a mistake. I wanted LoRa support for my Zig based PinePhone bare-metal OS project, but they have discontinued the LoRa back-plate So I’ve ordered a nRF52840 based gadget, but just realised it only has 256KB RAM, gulp!
Has anyone targeted Zig on such small SoCs here? any advice/tips please?
I’m still on ‘skinny Zig’ aka 0.15.2, and it looks like an Arm M4 32bit SoC, but I also saw something about thumb. So it would be especially good to know what my .target might look like please. I see both M4 and thumb listed in Zig targets, but there seem to be a few options there.
I can strip fonts and framebuffers from my OS (already removed std lib), but MMU is 64KB before I start. 256KB feels more like a serial-buffer compared to the 2GB RAM I have now
I also currently use .bin via objcpy as by image to boot, but from what I can see this chip is using uf2, is that something I can target directly from Zig?
There is the awesome microzig project by the ZigEmbeddedGroup, which should support many targets (as far as I know, it also supports the Arm Cortex M4).
And then, the rule of thumb (pun intended) is to ALWAYS build in ReleaseSmall modes. \
I never did things on a chip with 256KB of RAM, but I did do things on the Raspberry Pi Pico 2 (which has 520KB of ram, “only” a little bit more than double that).
So it is possible.
I have a really simple application written in Zig running on an MSP432P401R (Cortex-M4 with 64KB RAM, 256KB Flash). If you’re building in Debug mode, your program probably won’t fit in flash. Thanks to others on this forum, I’ve found a decent starting set of options to better control the output file size.
Some module options to enable to help reduce the size of your program:
.strip = true
.sanitize_c = .trap (can also disable completely with .off)
.valgrind = false
Some linker options to help reduce size:
link_gc_sections = true
link_function_sections = true
link_data_sections = true
lto = .full
With these, I was able to get the size down enough to run in Debug mode.
I’m not sure if you’re running an RTOS or Linux. An RTOS would run on these little MCUs, but getting Linux to run on them might be difficult. I’ve never seen it done, personally.
For my project, I use openocd to write an ELF, but have also used a BIN from objcopy. Never used uf2 though, it doesn’t look like the build system supports that currently.
I second the recommendation for MicroZig. I was playing with two small boards, micro:bit and Raspberry Pico W, and in both cases the integration was excellent. No messing around with the build system.
Thanks, that looks like a really useful list. It’s my own OS I’ve been working on, mainly just a hardware extraction layer and the start of an app/UI layer, so I should hopefully be able to strip out quite a lot.
edit: Oh and I hadnt even considered that the code could run from flash, so that gives quite some breathing space too
After the encouragement yesterday (thanks all!), I set about with a chainsaw to my OS today. The good news is that I´m down to 85KB for .elf, and the .bin is now only 20KB!! Probably a year since my OS was that small, quite amazed, and a very positive first step.
I realised I didnt need MMU, and pacman had to go but left serial, timers, gic, gpio, ccu and a few global assembly utilities. And of course flashing LED routines
I´m also down to a single std import, just for the panic handler. Is there an alternative signature I can use that still allows Zig to find it, but doesnt require std import please?
Yes, the std import is required. But Zig is clever and compiles only the parts you need in the std lib (which is only that std.builtin.StackTrace struct).
So you NEED to use it, but it isn’t as bad as you think.
EDIT: shouldn’t have been a reply to WeeBull, but to @whitehexagon.
No. If I’m correct, the OP made a custom panic handler, but for the function signature of his pub fn panic he needs std.builtin.StackTrace, that was what he was asking for.
Of course, that makes sense. I just took out my custom panic override & the last std import, and strangely it didnt change the output binary size. So that one can stay
So I never call my custom panic handler, it was only there for Zig to call (so that I hopefully got a serial console message).
But since I removed the rest of std lib, I guess that too is now redundant, and hence was probably being dropped anyway from my build. Makes sense. Thanks for making me think a bit more about that. So my OS is now officially std free! as long as you only want to flash an LED or two
So I learned about @setRuntimeSafety(true); today, since I wanted to try that, but I only ever build releaseSmall and the panic handler was not triggering. Thank-you.
Please note that stripping debug sections will reduce the size of your binary file, but not what’s flashed to your microcontroller (unless you add it via a linkerscript, but I’ve never seen a reason to, debuggers read the information from the file, not your hardware).