Sprocket Boards

This is the documentation repo for sprocket boards. Sprocket boards are not commercially available at the moment.

See the GitHub Organization for more information and source.

The Sprocket-G031

Sprocket Board Renders

This is a breakout board for the STM32G031. Each board is 15.0x47.0mm.

Each board costs under 2.00 EUR/ea at 100 units.

I documented the design process here:

And streamed most of the original design on YouTube here:

The Board

It has:

  • A 28-pin STM32G031
    • 64MHz Cortex M0+
    • 8KiB RAM
    • 64KiB Flash
  • Two WS2812b-style Smartleds
  • Two User buttons
  • Reverse Protection Diode
  • One Power LED (always on)
  • Two User LEDs
  • 3.3v LDO
  • Four QWIIC connectors
  • Three main connectors:
    • One with 8 GPIOs, all with PWM, six with ADC channels and Power
    • One with I2C, SPI, UART, and Power
    • One with SWD connectors, reset pin, and power

The board is meant to be brick mount compatible, and is the same size as a LEGO 2x6 Plate.

The four mounting pins each electrically connect to:

  • +5V0
  • Ground
  • SDA (3v3)
  • SCL (3v3)

These connectors are intended for use with a testing, programming, or configuration jig.

Compatible Add-On Boards

I don't know if I'll make a lot of accessories, but I'll certainly make some.

clink board render

This board is intended to take PWM as inputs (on up to eight channels). The PWM signal is buffered by a TI 74HC244D, and sent through an RC circuit, taken from the Raspberry Pi 3B+ Audio.

I don't expect Hi-Fi audio, but might be useful to make appropriate bleep-bloops.

The board also contains it's own 5V LDO to reduce signal noise.

Hardware

This is where I put information about the hardware

Image overview

TODO: Do an ifixit/adafruit style highlighted picture

Pins by Package Number

UQFPN-28 NumberPin NameSPROCKET USEPWMADC
1PC14-OSC32_INBUTTON1NoNo
2PC15-OSC32_OUTBUTTON2NoNo
3VDD/VDDASupplyNoNo
4VSS/VSSASupplyNoNo
5PF2-NRSTSWDNoNo
6PA0LED1YesADC0
7PA1GPIO1YesADC1
8PA2UART-TXYesADC2
9PA3UART-RXYesADC3
10PA4SmartLED (SPI2_MOSI)YesADC4
11PA5GPIO2YesADC5
12PA6GPIO3YesADC6
13PA7GPIO4YesADC7
14PB0GPIO5YesADC8
15PB1GPIO6YesADC9
16PA8GPIO7YesNo
17PC6GPIOYesNo
18PA11/PA9I2C2-SCLYesADC15
19PA12/PA10I2C2-SDAMaybe?ADC16
20PA13SWDIONoADC17
21PA14-BOOT0SWCLKMaybe?ADC18
22PA15SPI-CSnMaybe?No
23PB3SPI-SCKYesNo
24PB4SPI-CIPOYesNo
25PB5SPI-COPIYesNo
26PB6I2C1-SCLYesNo
27PB7I2C1-SDAMaybe?ADC11
28PB8LED2YesNo
Complete Pinout Table
PIN NumberPin NamePIN TYPEIO CapabilitiesNOTESSPROCKET USEALT FUNCSADD'L FUNC
1PC14-OSC32_INI/OFT1, 2BUTTON1TIM1_BK2OSC32_IN, OSC_IN
2PC15-OSC32_OUTI/OFT1, 2BUTTON2OSC32_EN, OSC_ENOSC32_OUT
3VDD/VDDASSupply
4VSS/VSSASSupply
5PF2-NRSTI/O--SWDMCONRST
6PA0I/OFT_a-LED1SPI2_SCK, USART2_CTS, TIM2_CH1_ETR, LPTIM1_OUTADC_IN0, TAMP_IN2, WKUP1
7PA1I/OFT_ea-GPIO1SPI1_SCK, I2S1_CK, USART2_RTS_DE_CK, TIM2_CH2, I2C1_SMBA, EVENTOUTADC_IN1
8PA2I/OFT_a-UART-TXSPI1_MOSI, I2S1_SD, USART2_TX, TIM2_CH3, LPUART1_TXADC_IN2, WKUP4, LSCO
9PA3I/OFT_ea-UART-RXSPI2_MISO, USART2_RX, TIM2_CH4, LPUART1_RX, EVENTOUTADC_IN3
10PA4I/OFT_a-SmartLED (SPI2_MOSI)SPI1_NSS, I2S1_WS, SPI2_MOSI, TIM14_CH1, LPTIM2_OUT, EVENTOUTADC_IN4, TAMP_IN1, RTC_TS, RTC_OUT1, WKUP2
11PA5I/OFT_ea-GPIO2SPI1_SCK, I2S1_CK, TIM2_CH1_ETR, LPTIM2_ETR, EVENTOUTADC_IN5
12PA6I/OFT_ea-GPIO3SPI1_MISO, I2S1_MCK, TIM3_CH1, TIM1_BK, TIM16_CH1, LPUART1_CTSADC_IN6
13PA7I/OFT_a-GPIO4SPI1_MOSI, I2S1_SD, TIM3_CH2, TIM1_CH1N, TIM14_CH1, TIM17_CH1ADC_IN7
14PB0I/OFT_ea-GPIO5SPI1_NSS, I2S1_WS, TIM3_CH3, TIM1_CH2N, LPTIM1_OUTADC_IN8
15PB1I/OFT_ea-GPIO6TIM14_CH1, TIM3_CH4, TIM1_CH3N, LPTIM2_IN1, LPUART1_RTS_DE, EVENTOUTADC_IN9
16PA8I/OFT-GPIO7MCO, SPI2_NSS, TIM1_CH1, LPTIM2_OUT, EVENTOUT-
17PC6I/OFT-GPIOTIM3_CH1, TIM2_CH3-
18PA11/PA9I/OFT_fa3I2C2-SCLSPI1_MISO, I2S1_MCK, USART1_CTS, TIM1_CH4, TIM1_BK2, I2C2_SCLADC_IN15
19PA12/PA10I/OFT_fa3I2C2-SDASPI1_MOSI, I2S1_SD, USART1_RTS_DE_CK, TIM1_ETR, I2S_CKIN, I2C2_SDAADC_IN16
20PA13I/OFT_ea4SWDIOSWDIO, IR_OUT, EVENTOUTADC_IN17
21PA14-BOOT0I/OFT_a4SWCLKSWCLK, USART2_TX, EVENTOUTADC_IN18, BOOT0
22PA15I/OFT-SPI-CSnSPI1_NSS, I2S1_WS, USART2_RX, TIM2_CH1_ETR, EVENTOUT-
23PB3I/OFT-SPI-SCKSPI1_SCK, I2S1_CK, TIM1_CH2, TIM2_CH2, USART1_RTS_DE_CK, EVENTOUT-
24PB4I/OFT-SPI-CIPOSPI1_MISO, I2S1_MCK, TIM3_CH1, USART1_CTS, TIM17_BK, EVENTOUT-
25PB5I/OFT-SPI-COPISPI1_MOSI, I2S1_SD, TIM3_CH2, TIM16_BK, LPTIM1_IN1, I2C1_SMBAWKP6
26PB6I/OFT_f-I2C1-SCLUSART1_TX, TIM1_CH3, TIM16_CH1N, SPI2_MISO, LPTIM1_ETR, I2C1_SCL, EVENTOUT-
27PB7I/OFT_fa-I2C1-SDAUSART1_RX, SPI2_MOSI, TIM17_CH1N, LPTIM1_IN2, I2C1_SDA, EVENTOUTADC_IN11, PVD_IN
28PB8I/OFT_f-LED2SPI2_SCK, TIM16_CH1, I2C1_SCL, EVENTOUT-
NOTESMeaning
1<= 2MHz, max load 30pF, only sinks 3mA (collectively?)
2RTC domain relevant, see RM0444
3pins are remappable to swap between IOs using SYSCFG_CFGR1
4SWD on reset, PA13 Pull-Up, PA14 Pull-down internally
FT5V tolerant I/O
_fFm+ capable
_aanalog switch function
_eswitchable diode to Vdd
PVDProgrammable Voltage Detector
MCOMicrocontroller Clock Output
LSCOLow Speed Clock Output

Board Pinout

Col 1Col 2Col 3Col 4Col 5
Row 1GPIO1GPIO5SWDIOCOPICSn
Row 2GPIO2GPIO6GNDSCKCIPO
Row 3GPIO3GPIO7SWCLKSDASCL
Row 4GPIO4GPIO83v33v35v0
Row 5GNDGNDNRSTGNDGND
Row 63v35v05v0+RXTX

"5v0" pins are post-protection diode. "5v0+" are pre-protection diode.

Bootloader

The bootloader for the sprocket is sprocket-boot. It is written in Rust.

Installing

Build sprocket-boot with a nightly compiler, and flash with probe-run or however you flash binaries using an SWD adapter. In the future, I plan to build an application that can be used to update the bootloader without a debugger.

Memory Layout

NOTE: Both the application and the bootloader must respect these regions.

RegionDeviceStart AddrSizeUsage
ApplicationFLASH0x0800_000058KiBUser Application and Vector Table
SettingsFLASH0x0800_E8002KiBBootloader/Application Settings
BootloaderFLASH0x0800_F0004KiBBootloader Code
RAM FlagsRAM0x2000_0000128 BytesMessage passing between BL/APP
User MemoryRAM0x2000_00808064 BytesGeneral Purpose RAM

How it works

Sprocket boot doesn't actually relocate the vector table, or own the vector table itself. It depends on the reset vector and MSP of the application to contain the reset address and stack address of the bootloader.

This is achieved by hot-patching the application image when bootloading with the proper bootloader information. It then stores the Application's reset vector and MSP in the Settings page.

This means that if you use SWD (or some other means, like DFU), you will likely break the bootloader, unless you manually apply these changes. It also means that the bootloader cannot use interrupts (or frameworks like RTIC) at all.

The STM32G031 does (I think?) support the use of the VTOR, so I may remove this hot-patching limitation/innovation/hack in the future.

The boot sequence

This is a distilled version of how the boot sequence works:

  • The system boots directly to the bootloader
  • The bootloader checks:
    • The Settings Page
    • The RAM Flags Segment
    • The Reset Vector/MSP of the Application
    • The state of the buttons
  • If the buttons are pressed, the system stays in bootloader
  • If the "stay in bootloader" RAM flag has been set, the system stays in bootloader
  • If the Settings or Application data looks bad, the system stays in bootloader
  • Otherwise the bootloader jumps to the application
  • If the system is stayig in bootloader, it starts listening as an I2C Peripheral

Pages and Subpages

The FLASH is broken up into two main chunks:

  • PAGES, which are always 2KiB, and are the minimum erasable size on the STM32G031.
  • SUBPAGES, which are currently defined as 256 bytes. This number was chosen arbitrarily
  • Typically, a PAGE is erased, and then each SUBPAGE is written with new data.

Bootloader I2C Commands

The Bootloader acts as an I2C peripheral, and can be clocked (theoretically) up to 1mbps with appropriate pullups and cable length, though clock rates higher than 400kHz are not currently reliable. A clock rate of 100kHz-400kHz is recommended. Clock stretching is probably required at the moment, but I am open to removing that requirement.

There are two kinds of I2C communications from a Controller perspective:

  • Writes

  • Writes-then-Reads

  • For Writes:

    • Send the I2C address - Write
    • then a 1-byte register ID
    • then write the contents of the register
    • then a STOP
  • For Writes-then-Reads:

    • Send the I2C Address - Write
    • Then a 1-byte register ID
    • Then a STOP
    • Send the I2C Address - Read
    • Then read the contents of the register
    • Then a stop
RegisterDirectionLengthUsage
0x10WR-TH-RD16Bootloader Image Name
0x40WRITE5Start Bootload
0x41WRITE261Write Subpage
0x42WRITE0Complete and Reboot
0x45WRITE1Set I2C Address

At the moment, any other read/write will cause the bootloader to panic. Also Note: The Length in this table does not count the 1 byte register address.

0x10 - Bootloader Image Name

At the moment, the device responds with a constant b"sprocket boot!!!". This register can be used to verify bootloader communications.

0x40 - Start Bootload

Before writing subpages, a bootload must be started. This message should contain:

  • 4 bytes - total checksum (later crc32), little endian
  • 1 byte - total subpages to write

0x41 - Write Subpage

Before writing subpages, a bootload must be started. On the first write of each page, the page will be erased.

For now, Page 0 + Subpage 0 must be the LAST subpage written. When writing this subpage, the reset vector and stack pointer will be overwritten and stored to the Settings page.

Write Subpage messages contain:

  • 1 byte: Page/Subpage - 0bPPPPP_SSS
    • max 32 pages
    • 8 sub-pages per page
  • 256: subpage contents
  • 4 byte: For now: 32-bit checksum. Later, CRC32 or similar

0x42 - Complete and Reboot

This command will reboot to the application if:

  • No subpages have been written, or a bootload was never started
  • ALL subpages have been written, after a bootload was started

The device will wait for the I2C STOP command, then reboot.

0x45 - Set I2C address

After starting a bootload, a new I2C address can be set. This address will always be used by the bootloader, and may be used by the application as well.

This I2C address will only be used after a reboot, and is written to the settings page when a "Complete and Reboot" command is sent.

Board Support Crate

I plan to write a board support crate for the sprocket. TODO.

I2C Protocol

TODO: Document. For now, see the Bootloader Section for more detail on currently implemented I2C commands.

Control Station