Back in 2014, the RIOT operating system was made usable on the Spark Core in such a way that the bootloader would stay intact with help from this community.
The Particle Xenon is currently well supported in RIOT (with various radio implementations available using the softdevice, the NimBLE stack or an own 6LoWPAN stack, and recently also USB Ethernet), but the current port is flashed using an external programmer and (to the best of my knowledge) overwrites the whole bootloader, making the switch between RIOT and Particle software require a hardware debugger.
I’m working to make RIOT flashable using the Particle bootloader, and (like Christian in the 2014 thread) got to the point where I could run
dfu-util -a 0 -s 0x30000:leave -D bin/particle-xenon/usbus_minimal.bin
but unlike in the case then, I don’t even get five seconds of running time. When I execute that flash, and ever since, my board goes into DFU mode (yellow blinking) right away.
My hypothesis is that the bootloader is verifying that system-part1 and user-part match, or verifying either of those two, and my bare program fails that check – but I did not find those bootloader details yet.
Could you give me a hint as to where to look on?
(For reference, there is a parallel issue in RIOT’s tracker that has more gory details of my journey so far).
I’ve dug through the bootloader code (bootloader/src/main.c) a bit and found no clues as to what would keep the application from starting.
Checks for firmware integrity are still ToDo in the mesh-develop branch (“ToDo add CRC check”), and the application should pass is_application_valid (its first pointer is to RAM where the stack belongs), and all else that’s checked between there and the actual jump into the program is how to configure the watchdog timer, and either way that should give me at least a few seconds of program runtime (whereas, per Linux dmesg, there’s only 0.3s between the :leave induced USB disconnect and the new full speed USB device that is DFU mode again).
One experiment I did was overwriting both system and user partition, flashing system with the device-os version but not flashing user, which does get me into a “blue blinking” state, but that only cuts branches in my further experiments (“OK so I don’t have to make both valid”), and doesn’t get me closer to a startable firmware immediately.
My next steps would involve using a 10-pin debug adapter, but until I get hold of that I’m stalled and hoping for input from you.
Damien George of the MicroPython project found the RIOT issue and offered his notes, where he pointed me to the module_info_t and the checksumming. With that I got images that would be accepted by the bootloader, and after disabling some remaining interrupts, I’ve got applications running.
Still, I’m a bit unsure of how stable the interfaces I’m using are and whether I’m doing it right. So to summarize my assumptions I’d like to have challenged:
The Particle bootloader in mesh generation devices can be used to run non-Particle images, these best fit the “monofirmware” class.
Those can use any flash space between the softdevice and the bootloader without harming the user’s ability to go back to a Particle application using DFU mode. (The cloud-based purple-blinking bootloader mode would require a system image to be present.)
A monofirmware needs to align itself as to have a plausible vector at 0x30000, a module_info_t at 0x30200, and a checksum at whatever is its end. Application-writable flash memory could be allocated behind the checksum, but the application needs to take special care not to write into the bootloader at the top 48k.
When the bootloader enters a monofirmware, it leaves two interrupts (0 (POWER_CLOCK) and 6 (radio)) active. The monofirmware needs to be aware of that and provide adaequate interrupt handlers at its vector, or disable them before setting the VTOR register to the vector it provides at 0x30000. Is that the bootloader’s intention? Is there any other setup the bootloader does that applications may want to undo?
Are those assumptions encoded in the version field of the module_info_t, such that when a newer bootloader (for example) enables new interrupts or needs different memory regions, it will reject a module with that version? Which version should a non-particle monofirmware generally pick?