Rust
Rust in the OpenServoCore stack — PAC-level drivers, no-std bootloaders, and bare-metal control firmware.
Current
A servo protocol for cheap MCUs: stream processing on the wire
After implementing Dynamixel 2.0 on the servo side , Fast instructions included , I replaced it. OpenServoCore now runs its own wire protocol, designed around what those months taught me about what a cheap microcontroller can and cannot do well. This article documents the design and its measured results. Ping turnaround dropped from 62.8 µs into the 30 to 41 µs band on the same $0.16 chip, and most of the timing machinery the DXL era needed got deleted along the way. The build-by-build numbers are in the Real Numbers section, warts and all. The centerpiece is an idea worth stealing even if you never build a bus protocol. I call it stream processing. Instead of receive everything, verify, parse, then reply, the servo works on the frame while it is still arriving. It decodes early, checksums in hardware in parallel, and starts transmitting the reply before the reply is even finished being built. If your project has any latency-sensitive communication, this is the part you can reuse. Everything here is running, measured code in the OpenServoCore repo , and the project overview has the background.
A chip-agnostic architecture for bare-metal embedded Rust
Embedded Rust has excellent building blocks like HALs, PACs, and async executors. But very little is published about how to structure a serious firmware project on top of them. Most examples stop at blinky with a HAL. What does the architecture look like when you have a real protocol stack, a motor control loop, a dozen interacting peripherals, and the ambition to support more than one chip? And what if you are bare-metal, with no RTOS and no async executor, just interrupt handlers and a main loop? This article documents the architecture OpenServoCore ’s firmware actually uses, in enough detail to build it for your own project. Overview first, then a zoom into every layer with its internal organization and a code example, all the way down to the discrete-event simulation. The architecture has earned some trust the hard way. The firmware’s entire wire protocol was ripped out and replaced mid-project, and the layering held. The logic layers compile and unit-test on a desktop with no hardware attached. And the simulation caught over a dozen real bugs before they ever reached silicon. The code examples are teaching-sized but structurally faithful to the shipping code, and the codebase itself is public if you want the full-scale version. If you are new here, the project overview has the background.
Using the SPI peripheral as a DMA-fed CRC engine
While building the wire protocol for OpenServoCore , I ran into a small problem that was costing a lot of CPU. Every frame on the servo bus carries a CRC-16 checksum, the bus runs at 3 megabaud, and the chip doing the checking is a $0.16 CH32V006 with no CRC peripheral. It does have an SPI block though, and it turns out there is a perfectly good CRC engine hiding inside it. This article is a how-to for commandeering that engine as a DMA-fed CRC coprocessor for data that has nothing to do with SPI. In my case that’s UART frames, but the engine doesn’t care where the bytes came from. Everything below is the current shipping design, verified against the code in the OpenServoCore repo , and as far as I know the trick works on every WCH CH32 chip with an SPI block. If you are new here, the project overview has the background.
HSI trim: calibrating a crystalless MCU over the bus
Cheap microcontrollers run on internal RC oscillators, no crystal. On the CH32V006 that oscillator is called the HSI (High Speed Internal), and the datasheet promises ±1% frequency accuracy. The five chips on my bench measured up to 7,000+ ppm (parts per million) apart from each other. For most firmware that’s irrelevant, but for a servo bus where devices time replies off each other’s transmissions, it’s the difference between a working chain and garbled bytes. This article documents how OpenServoCore calibrates a fleet’s clocks today, using nothing but the bus wire itself. There are no extra pins, no factory calibration step, and no per-chip fixture. It’s the current shipping design, code-verified and bench-measured. There are three pieces, and you can lift each one independently: a broadcast break train for absolute calibration at boot, a differential drift tracker that runs continuously off normal traffic, and the trim loop that turns error into oscillator steps. If you want the background first, the protocol design article covers the bus this runs on, and the project overview has the full picture.
Archived
Part 2 - Persisting Data To Database
This is article is part of a series. They are: Part 1 - Simple GraphQL Server with Juniper And Actix Part 2 - Persisting Data To Database In the previous blog post , we showed how easy it is to create a GraphQL server in Rust. In this post, we will hook it up to a Postgres database. To do this we will use the tokio-postgres package. While it is possible to use an ORM in Rust (the most popular choice being diesel ), that topic is very dense on its own, and even in high level frameworks like Node.js, it is debatable if ORMs are always the best choice .
Part 1 - Simple GraphQL Server with Juniper And Actix
This is article is part of a series. They are: Part 1 - Simple GraphQL Server with Juniper And Actix Part 2 - Persisting Data To Database Rust is an upcoming programming language that is often regarded as a low-level systems language, however it comes with language features that allow it to extend itself into other domains while minimizing the boilerplate you might expect from a systems language. We will be looking at Rust as a GraphQL Server and demonstrating its simplicity when paired with powerful frameworks such as Juniper and Actix Web. Comparisons will be made with Node.js and the Express framework which has undoubtedly had an influence on the entire space.