Time to solder and I’m not looking forward to it

Dreading placing those SMDs… I need a PnP 😭

u/aq1018 — 6 days ago

Using the CH32V006 SPI block as a DMA-fed CRC16 engine

I'm building a servo controller around the CH32V006, a $0.16 RISC-V chip from WCH. The servo bus runs at 3M baud and every frame is check with CRC-16. My first implementation was the typical LUT-driven loop. But the checksum was eating about a fifth of the CPU during traffic. This chip also has to handle a realtime motor control loop, so I need to do this asynchronously without blocking the cpu.

The V006 has no CRC peripheral. But while digging through the SPI chapter of the datasheet, I found three interesting registers, a CRC polynomial register, a TX CRC register, and an RX CRC register. The block has a CRC-16 engine built in, meant for checksumming SPI transfers. And here is the fun part. The TX CRC unit checksums everything the shifter sends, and the SPI peripheral can be configured to run without being tied to any pins.

So you can run it like this:

  • set the block to master mode, so it clocks itself
  • use software chip select (SSM + SSI), so it needs no select pin
  • route no SPI signals to any pin
  • enable TX DMA and point a channel at the data register

Now you have a CRC coprocessor that eats a DMA stream straight out of RAM. About 0.36 µs per byte of wall time on my setup, and the CPU's whole involvement is a handful of register writes per frame. The only gotcha is the CRC result is bit reversed and you will need to reverse it in software.

As far as I know, all CH32 chips have the same SPI IP, so this method will work on CH32V003 and other chips as well. The WCH SPI block is also an obvious clone of the STM32F family chips, which carries the same CRC registers, so this likely works beyond WCH. I have only tested on CH32V006 and CH32V203 parts though. Has anyone used the SPI CRC unit like this on ST silicon?

I have a full writeup that details the ring buffer feeding tricks, the bench numbers, and some gotchas. The production code is in the OpenServoCore repo if you want the real thing.

reddit.com
u/aq1018 — 8 days ago
▲ 309 r/PCBWayOfficial+1 crossposts

CH32V006 servo controller dev board

If you fancy a CH32V006-based servo controller dev board, you can now just fabricate it with this design. Rev B of the OpenServoCore dev board is bring-up-validated, files are GitHub, and there's a one-click PCBWay community project if you don't want to deal with KiCad yourself.

A CH32V006 (48 MHz RISC-V, 62 KB flash, 8 KB RAM) breakout designed for bringing up smart-servo firmware. Accepts any gutted hobby servo, USB-C / 1S-2S LiPo / WCH-LinkE power, full edge test-point fanout for current sense, motor PWM, DATA bus, and debug. The broader project (OpenServoCore) is open hardware + firmware for turning cheap SG90/MG90S-class hobby servos into DXL-style smart actuators — position feedback, current sensing, bus-addressable. The dev board is the firmware development platform.

PCBWay sponsored both Rev A and Rev B fabs (assembled too). Ten boards across two runs and no fab issues on any of them. They caught a pad clearance issue on Rev A during the pre-fab review before it went out, and the tiny "O" in the OSC logo (which has a little encoder disk inside it) came out crisp on Rev B even at that size. Honestly a huge help for a solo project — sourcing BOM and hand-assembling these myself would slow everything down a lot.

Bring-up writeup with photos, the bootstrap quirk on fresh chips, and the in-rev SB1 patch that fixes it:

https://aaronqian.com/log/2026-06-08-osc-dev-v006-rev-b-bring-up/

u/aq1018 — 2 months ago
▲ 27 r/PCBWayOfficial+1 crossposts

OSC Dev V006 Rev B validated, anyone can make it now

Hello everybody,

Continuing from the Rev B Sneak Peak I posted a few weeks ago, Rev B boards are back from the fab, bring-up is done, and the design is validated. If you fancy a CH32V006 based servo controller board, you can now just fabricate your own.

What's new this round:

  • Works without board surgery (lol)
  • The shared nRST / OPN2 pin issue from Rev A is fixed (Well, sort of. There's a one-time bootstrap quirk on fresh chips, covered in the writeup below).
  • Edge test-point fanout silkscreen cleaned up.
  • A small in-rev patch (SB1 solder bridge) added for the bootstrap quirk so you don't have to do the rework I did on my sponsored boards.
  • Files published in the repo; reference design also up as a one-click PCBWay community project if you want to skip dealing with KiCad.

The full bring-up writeup, including the surgery I had to do on the five sponsored Rev B boards before SB1 existed, photos, and the ENIG-vs-HASL gotcha I hit on surface finish, is here:

https://aaronqian.com/projects/open-servo-core/logs/2026-06-08-osc-dev-v006-rev-b-bring-up/

Repo (KiCad + firmware-in-progress): https://github.com/OpenServoCore/open-servo-core

PCBWay community project (one-click order): https://www.pcbway.com/project/shareproject/OSC_Dev_V006_Rev_B_OpenServoCore_Development_Board_CH32V006_0f6621d7.html

PCBWay has now sponsored both the Rev A and Rev B fabs for this project, which has been a great help for me. They take the assembly, BOM sourcing, and build-quality second-guessing all off my plate so I can focus on the firmware rewrite (DXL 2.0 + FAST 3M comms, currently working on the bench). The build quality is really solid. I didn't encounter any issues with their boards. (well, other than my own design mistakes...)

Firmware v2 is coming soon. I'm currently working on the DXL RX/TX timing architecture (software-timed → TIM2 hardware capture + hardware-fired TX). More articles on that landing over the next few weeks.

Happy to answer questions in the thread.

u/Aran_PCBWAY — 2 months ago

What is this black cylinder looking thing next to the glass fuse?

Trying to fix a washing machine control board. The fuse is closed, but the black cylinder thing is open. The black surface feels like fabric / carbon fiber.

Sorry about the blurry photos. I can't seem to get my phone to focus somehow...

u/aq1018 — 3 months ago
▲ 10 r/arduino

Hello everybody,

As many of you might have seen my previous posts about the OpenServoCore project, I have been busy validating the Rev. A dev board since it was shipped. Now I have finally completed the validation and produced Rev. B design, and I am planning to ship the design to the fabs this week.

But before I ship, wait for a few weeks for it to arrive and test it out, I just wanted to share with you what it looks like right now.

References here:

u/aq1018 — 4 months ago
▲ 2 r/PCB

Hello everybody,

This is a firmware development / system ID board that I designed for the OpenServoCore project, an open-hardware, open-firmware smart-servo platform built around the CH32V006 RISC-V MCU. The project is in early development phase. The entire board is designed in KiCad and is fully open source.

Planning to fabricate it this week, and before I ship it, really appreciate a second pair of eyes. Please feel free to clone and help review the whole design. Any critique or suggestions are very welcome.

The KidCad files and README is here: https://github.com/OpenServoCore/open-servo-core/tree/main/hardware/boards/osc-dev-v006

u/aq1018 — 4 months ago
▲ 47 r/arduino

Edit. I botch'ed the title. It should be "A hardware debug story", sorry...

If you saw my last post about accidentally frying my CH32V006 dev board into a working state, this is the next chapter of that mess.

Quick recap: I'm building a custom CH32V006 dev board for OpenServoCore, my project to turn cheap MG90S-class servos into smart actuators with a Dynamixel-style single-wire UART. After the 0.84V rail saga, I had a working board. Time to bring up the Rust bootloader (tinyboot) over UART.

Except UART didn't work.

Specifically, TX worked perfectly. I could blast "Hello world" out of the chip all day. But sending anything into the MCU? Total silence. The HAL driver is essentially the same as the V003, which works fine, so I was pretty sure this was hardware, not firmware.

I scoped the RX line while shoving a stream of 0x55 (UUUUUU…) into it from the host. Quick one-liner if you've never used it:

yes U | tr -d '\n' > /dev/ttyACM0

Alternating 1s and 0s, perfect for scoping.

What I expected: a clean 0V to 3.3V square wave. What I got: a 180 mV ripple sitting on top of 3.3V. Min 3.20, max 3.38. The line was being held high so hard that my USB UART adapter could only sag it by a couple hundred millivolts when it tried to send a zero. Touching RX directly to ground snapped it cleanly to 0V, so the wiring was fine. The driver just couldn't drag it all the way down.

Back to the schematic. The RX line passes through a 74LVC2G241 tri-state buffer that handles the half-duplex direction switching. TX_EN low = listen (DATA -> RX), TX_EN high = talk (TX -> DATA). I'd been picturing this buffer as a passive switch, like a piece of wire that conditionally connects two nets.

By now you electronics gods here probably already figured out what's the issue by now, but I didn't...

Anyways, when TX_EN is low, that buffer is actively driving RX with whatever it sees on DATA. And DATA sits at 3.3V via its own 10K pullup when the bus is idle. So the buffer was reading 3.3V on DATA and pushing 3.3V back out of its high-side MOSFET onto RX with ~24 mA of drive and very low R_DS(on). I was fighting a CMOS push-pull output stage with a USB UART chip. The buffer won. Always.

The firmware workaround is to assert TX_EN while reading. That disables the DATA -> RX path and lets RX fall back to its own pullup, which the host can actually drive. Confirmed it live by poking 3.3V onto the TX_EN pad and watching the ripple snap into a clean rail-to-rail square wave. It's such a satisfying flip on the scope.

The real takeaway, however, is thatTX_EN isn't really a transmit enable. From firmware's view it looks like one, but electrically it's a mux select that picks which buffer drives the bus. Calling it "transmit enable" is what put me in this mental hole in the first place.

For Rev B, the actual fix is a hardware jumper that lets RX bypass the buffer for plain UART mode. Why hardware and not just firmware? Because tools like wchisp use the UART to read/write the CH32's Option Bytes outside of any firmware I control. If my UART depends on my firmware to function, a fresh chip or a half-flashed bootloader can lock me out of recovery. Recovery-path peripherals shouldn't depend on firmware to work.

If you want a more details with scope photos, the schematic, a video of the workaround in action, here is the full writeup.

u/aq1018 — 4 months ago