CH32V006
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.
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.
Dynamixel 2.0 servo side: implementing Fast Sync/Bulk Read
This post documents what I learned implementing Dynamixel Protocol 2.0 on the servo side. OpenServoCore has since moved to its own wire protocol , but everything below stands on its own if you are building a Dynamixel-compatible device. Fast Sync Read and Fast Bulk Read are the instructions that make a Dynamixel 2.0 bus fast. You send one request and get one shared reply carrying every servo’s data back-to-back. They are also, as far as I can tell, completely undocumented from the servo side. There is plenty written about sending a Fast Sync Read, but nothing about being one of the servos answering it. This is part 2 of a pair. Part 1 covered how a servo detects the moment a packet ends on the wire, and I’ll assume that vocabulary here (wire-end, publish time, jitter, RDT). This article is the build itself. It covers the wire layout, the CRC math, the slot arithmetic, the hardware transmit start, and the CRC patch that races your own transmit DMA, each with the code. The worked example is the CH32V006 ($0.16, 48 MHz, no crystal), and the code comes from the frozen DXL-era tree , trimmed to teaching size. Every mechanism has an equivalent on any small MCU with a timer, DMA, and a UART. If you are new here, the project overview has the full picture.
Dynamixel 2.0 servo side: RX timing on the CH32V006
This post documents what I learned implementing Dynamixel Protocol 2.0 on the servo side. OpenServoCore has since moved to its own wire protocol , but everything below stands on its own if you are building a Dynamixel-compatible device. There is plenty of material online about talking to Dynamixel servos. Host libraries, ROS drivers, GUI tools, you name it. But there is almost nothing about being one. If you are putting a microcontroller inside a servo, building a custom sensor that lives on a Dynamixel bus, or emulating a Dynamixel device (what the Dynamixel2Arduino library calls a Slave), you are mostly on your own. Well, I spent several months being one. This article and the next one document what that took, so you don’t have to rediscover it yourself. This one covers how a servo knows when the host stopped talking. That sounds trivial, but it turns out to be the foundation everything else stands on, and this time I’m going to walk through the actual build. Ring setup, interrupt handlers, formulas, and the code for each. The next one covers Fast Sync/Bulk Read, the protocol’s group-read mode. All examples run on the CH32V006, a $0.16 RISC-V microcontroller, because that’s what OpenServoCore runs on. The code is real, lifted from the frozen DXL-era tree and trimmed down to teaching size, and the recipe transfers to any small chip with a UART, DMA, and a free-running timer. Keep the Dynamixel Protocol 2.0 reference manual handy, I will use its vocabulary (packets, instructions, status replies) without re-explaining it. And if you are new here, the project overview has the full picture.