Skip to the content
PCBKitNew board
2 layers26 × 79.5 mmSensaor, the printed circuit board in 3D

Sensor SAO for Hackaday Supercon 2024

Size
26 × 79.5 mm
Copper layers
2
Thickness
1.6 mm
Parts
17
Nets
31
Pads
79
Tracks, vias
129, 9
Pours
2
Routed
Yes
KiCad
KiCad 8.0 (file 20240108)
Created
4 Sep 2024
Updated
2 Nov 2024

Overview

Sensaor is an open-source printed circuit board by bwasserm, from the bwasserm/sensaor repository on GitHub. It is a 2-layer board of 26 × 79.5 mm with 17 parts on 31 nets, routed with 129 tracks and 9 vias.

It is built around the WS2812B and WS2812. Its parts include 10 connectors, 3 diodes, 2 resistors, 1 capacitor and 1 IC. It belongs with the sensors and measurement boards and the RISC-V boards of this library.

Main components

2

README

README.md

senSAOr - a sensor SAO

A Simple Add-On (SAO) for a conference badge with a modular sensor port and a reactive multicolor LED.

Project Goals

  • Design and make an SAO in time for Hackaday Supercon 2024
  • Make it inexpensive enough and simple enough to make a bunch and trade with others
  • Blinky, but more interesting than only blinky
  • Cool design
  • If writing firmware, write it in Rust
  • If using a microcontroller, use RISC-V

High Level Design

SAO is a microcontroller that reads a sensor from an input pin, and uses the measured voltage to drive the color/brightness/pattern of an LED. Create ports for multiple different sensors to be used, with the ability to solder in different signal conditioning. Use ID pins or a solderable resistors to tell firmware how to "read" the sensor and drive the LED in response.

Expected Behaviors

The inputs are read to set the color of the bottom LED. Every cycle, the colors are clocked one LED up the board, and potentially out to an attached strand of addition WS2812s attached at the top. All inputs are read in [0V, 3.3V] as low to high.

Red/Green/Blue

These inputs are read to set the base intensity of the LEDs accordingly.

Speed

This sets the delay between update cycles from fast (low) to slow (high). Full low has no added delay between cycles, and full high has about 1s between cycles.

Shape

This is the mixture ration between setting the output intensity of the colors based directly on the input (low) vs also mixing in a sine wave (high) to the brightness (off to the intensity set by the color input).

Phase

When mixing in the sine wave, this delays the mix of the sine wave applied to green and blue relative to red. Low is the same phase of sine wave is applied to all three colors, and high is about 120 degrees of delay to green and 240 degrees of delay to blue.

ID pins

Currently unused

I2C

Currently unused. Set as high impedance inputs.

GPIO[12]

Currently unused. Set as high impedance inputs.

More WS2812

Connect more Neopixels here to continue clocking out colors beyond the three on the SAO.

SAOAO

Hopefully "standard" SAOAO port to connect an SAOAO.

Resources

Implementation blog

Getting rust to build

Getting rust to compile was mostly following the Rust on the CH32V003 blog, with some off-roading. LLVM had already picked up the support for rv32ec (the e extension is the core i architecture, but with 16 registers instead of 32 for smaller silicon), but rustc didn't know the riscv32ec-unknown-none-elf target. Eventually I figured out I didn't need to make the hack to rustc either, if I provided a target .json file to build against. However, having a local copy of llvm and the binary tools was useful, such as for llvm-objdump.

Eventually I found that much of the work on the blog was "done" in the CH32V00X-hal project, so I cloned that next to this project. To avoid copying files, I hacked this to link to it. .cargo/config.toml points the target to ch32v00x-hal/riscv32ec-unknown-none-elf.json. The target json I copied from the noxim blog is included for good measure.

I also found that the -Tmemory.x and -Tlink.x arguments got redundant with the CH32V00X-hal repo and build.rs (adding that repo as a Cargo dep changes things), so it may require some experimentation.

Note on memory.x: Looking at the memory map, it appears that program flash is a 16KB block starting at address 0x0800 0000. However, ch32v00x-hal and the noxim blog both define FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 16K at address 0x0000 0000, which is the Aliased to Flash or system memory depending on software configuration block of a much larger size. This block defaults to flash, and the program counter (pc) will default to address 0x0000 0000 when the chip boots. So even though it seems unintuitive, set the FLASH address in memory.x to be 0x0.

I went down an exploratory path using ch32v00x-hal/link-qkv2.x instead of finding link.x, which required modifying INCLUDE device.x to become INCLUDE svd2rs/device.x, after also cargo install svd2rust, and running it on cj32v003.svd to generate device.x. However, after adding in CH32V00X-hal, I found I didn't need this.

Getting blinky to run

I'm playing with the CH32V003F4P6-R0 dev board, pictured here, and referencing the schematic as well was super handy. Especially because I tried using PA1 as an arbitrary GPIO pin choice, but it is already tied to the oscillator.

I used the wlink application with the WLinkE . It turned out to be surprisingly easy to run and use to dump registers and flash. It's not even necessary to convert the elf file produced by cargo/rustc into an Intel Hex file or a bin first.

text
cargo install wlink
  • Programming command: sudo ~/.cargo/bin/wlink -v --chip ch32v003 flash target/riscv32ec-unknown-none-elf/debug/sensaor
  • Get registers command: sudo ~/.cargo/bin/wlink -v --chip ch32v003 regs
  • Dump the beginning of program flash: sudo ~/.cargo/bin/wlink -v --chip ch32v003 dump 0x00000000 400

The sudo is becuase I'm too lazy to figure out which group to add myself to to get permissions to talk to the programmer.

wlink also has a serial terminal functionality that works with the WLinkE debugger I'm using. However, my WLinkE isn't showing up as a serial device (/dev/ttyASM0 or similar), so I can't connect to that. I'm guessing it's a udev rule I need to update, since lsusb indicates multiple modem/serial interfaces on the USB device. Probably an Arch (BTW) config issue on my end.

Using the LEDs on the dev board, it's important to set the GPIO pins into open drain mode, not push-pull. With the extra resistors from push-pull, not enough current flows to turn on the LEDs (since they already have resistors installed inline).

WLink on Windows

On my Windows 10/11 machines, I was getting Error: USB error: Entity not found errors when trying to run wlink status. This is because the wlink doesn't activate the correct drivers by default.

  • See this github issue for an example
  • Install zadig
  • Select WCH-Link (Interface 0) and install the driver WinUSB.

Reading the ADC to modify the blink

First, I moved the binaries into src/bin/ so I could build multiple at once, and therefore make things easier to have multiple apps in work.

The greatest challenge reading the ADC was finding the right part of the HAL to use. Eventually I found ch32v00x-hal/src/adc.rs OneShot::read(), but due to not knowing rust's import system well enough, spent way too long getting it to build. Through help, the answer is adding embedded-hal-02 as a dependency, and use embedded_hal_02::adc::OneShot;. While I don't have a great analog source yet, the blink rate does apear to change when I touch the input pin, so I think it might be working.

Driving the Neopixels

I wanted to use a Neopixel (WS2811/WS2812) library to drive them, but those rely on a timer or SPI implementation for the chip. The hal I'm using for the CH32V003 doesn't implement SPI. After getting annoyed with the traits required to get the existing timer library to work, I figured implementing enough of SPI to write would be easier. With enough time with the manual, and some C examples of setting up SPI on this chip to compare which bits are set in the control registers, I got my neopixel string to change colors.

Programming tips

Including any println!() calls without having the debugger connected and watching the serial port will cause the application to block upon a print.

With serial console:

text
cargo b --release; wlink -v --chip ch32v003 flash .\target\riscv32ec-unknown-none-elf\release\sao --enable-sdi-print --watch-serial

Without serial console:

text
cargo b --release; wlink -v --chip ch32v003 flash .\target\riscv32ec-unknown-none-elf\release\sao

Note that using println!() when sdi print is not enabled or the debugger is not watching serial will cause the program to lock up at the first println!().

Parts

17
QtyValueFootprintReferences
6Conn_01x05_PinConnector_PinHeader_2.54mm:PinHeader_1x05_P2.54mm_VerticalJ3, J4, J5, J7, J8, J9
3WS2812BLED_SMD:LED_WS2812B_PLCC4_5.0x5.0mm_P3.2mmD1, D2, D3
1CCapacitor_SMD:C_0603_1608Metric_Pad1.08x0.95mm_HandSolderC1
1CH32V003AxMxPackage_SO:SOP-16_3.9x9.9mm_P1.27mmU1
1ID0Capacitor_SMD:C_0402_1005Metric_Pad0.74x0.62mm_HandSolderR1
1ID1Capacitor_SMD:C_0402_1005Metric_Pad0.74x0.62mm_HandSolderR2
1ProgrammingConnector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_VerticalJ6
1SAOConnector_IDC:IDC-Header_2x03_P2.54mm_VerticalJ1
1SAOAOConnector_PinHeader_1.27mm:PinHeader_1x03_P1.27mm_VerticalJ10
1WS2812Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_VerticalJ2

Questions

How big is the Sensaor PCB?

It measures 26 × 79.5 mm and has 2 copper layers, 1.6 mm thick.

What parts does the Sensaor use?

17 parts, built around the WS2812B and WS2812. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Sensaor KiCad files?

From the bwasserm/sensaor repository on GitHub, at the commit this page was made from: the board is pcba/sensaor/sensaor.kicad_pcb and its schematic pcba/sensaor/sensaor.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Sensaor design in my own project?

Its repository states no licence, so its author keeps all rights: ask bwasserm before reusing the design.

Similar boards

  • 2 layers230.5 × 82 mmVitamins included, the printed circuit board in 3D

    Vitamins included

    Duckle29/Vitamins-included

    This repo holds a variation of the lets split. This board requires no soldering

    214 parts49BSD-3-Clause
  • 4 layers61 × 100 mmBigCore, the printed circuit board in 3D

    BigCore

    Dschadu/Geistwerk-BigCore

    An ESP32-based open hardware control board designed for Bottango-powered animatronic and motion projects.

    152 parts4CERN-OHL-W-2.0
  • 2 layers197.6 × 173.1 mmErgodoxer, the printed circuit board in 3D

    Ergodoxer

    TheZoq2/ergodoxer

    An ergodox inspired split keyboard with more keys than a standard ergodox

    167 parts
  • 2 layers131.5 × 95 mmClarinoid devboard, the printed circuit board in 3D

    Clarinoid devboard

    thenfour/Clarinoid

    an electronic wind instrument / clarinet / flute / not sure

    121 parts4
  • 2 layers308.8 × 130.3 mmCyberKeeb2040, the printed circuit board in 3D

    CyberKeeb2040

    zli117/CyberKeeb2040

    Hardware design for a mechanical keyboard based on RP2040 that also has a Pi Zero onboard.

    182 parts98CC-BY-SA-4.0
  • 2 layers99.1 × 99.1 mmTangNanoDCJ11MEM, the printed circuit board in 3D

    TangNanoDCJ11MEM

    ryomuk/TangNanoDCJ11MEM

    Memory system and UART implemented on Tang Nano 20K for DEC DCJ11 PDP-11 Processor

    45 parts86MIT
  • 2 layers49.5 × 30 mmAirpcb smd old, the printed circuit board in 3D

    Airpcb smd old

    issalig/toshiba_air_cond

    AB protocol decoder for toshiba air conditioners

    30 parts65
  • 4 layers50 × 50 mmHSCanT, the printed circuit board in 3D

    HSCanT

    cherry-embedded/HSCanT-hardware

    HSCanT is a USB to 4-channel CAN FD tool designed based on the HPM5321 chip.

    130 parts52Apache-2.0