The overview, with examples running, is on the board page.
What it is
The CH32V003 is WCH's cheapest microcontroller: a QingKe V2A core that
implements RV32EC (the RISC-V base with sixteen registers, compressed
instructions and no multiply or divide), clocked at up to 48 MHz from an
internal 24 MHz oscillator and a PLL. The part here is the CH32V003F4P6, the
TSSOP-20 package, on a breakout that brings its pins out to two rows of 0.1
inch holes 0.6 inch apart, so it straddles a breadboard's channel. It has
no user LED and no buttons. VDD is a 3.3 V supply and GND is ground, always
on.
Pins and pin numbers
The twenty pins are named as the openwch Arduino core names them: PA1,
PA2, PC0 to PC7 and PD0 to PD7, plus VDD and GND. A sketch writes
pinMode(PD2, OUTPUT). A bare number is the port times 8 plus the bit, with A
at 0, C at 8 and D at 16, so PD2 is 18.
| Pin | Name | Also |
|---|---|---|
| 1 | PD4 |
A7 |
| 2 | PD5 |
A5, USART1 TX |
| 3 | PD6 |
A6, USART1 RX |
| 4 | PD7 |
a plain GPIO here (see below) |
| 5 | PA1 |
A1 |
| 6 | PA2 |
A0 |
| 7 | GND |
ground |
| 8 | VDD |
3.3 V supply |
| 9 | PC0 |
|
| 10 | PC1 |
I2C SDA on the real chip |
| 11 | PC2 |
I2C SCL on the real chip |
| 12 | PC3 |
|
| 13 | PC4 |
A2 |
| 14 | PC5 |
SPI SCK on the real chip |
| 15 | PC6 |
SPI MOSI on the real chip |
| 16 | PC7 |
SPI MISO on the real chip |
| 17 | PD0 |
|
| 18 | PD1 |
SWIO, the programming pin |
| 19 | PD2 |
A3 |
| 20 | PD3 |
A4 |
On the breakout the left row is pins 1 to 10 from the top and the right row is pins 20 down to 11, as a package is numbered.
A0 to A7 are ADC1 channels 0 to 7. analogRead() returns ten bits, 0 to
1023, against VDD.
The clock, and ports that are switched off
The program sets the clock. After a reset the chip runs from the 24 MHz
oscillator divided by three, 8 MHz; the Mokxi runtime turns on the PLL and
runs at 48 MHz before setup(), as the Arduino core does, and instructions
take 1/48 of a microsecond each. A program that leaves the clock alone runs six
times slower, as it would on the bench.
A port ignores writes until its clock is enabled in RCC_APB2PCENR, and reads
as 0 until then. That is the chip's rule, and the first thing that bites a
program that writes the registers directly. pinMode() enables the clock for
you.
Serial
Serial is USART1, with TX on PD5 and RX on PD6, wired to the serial
monitor. It is polled. There is no receive buffer and no interrupt yet, and
the USART holds one byte, so a second byte that arrives before the first is
read is lost, as it is on the chip with its interrupt off. The Serial example
checks Serial.available() all the time and never waits in delay().
What is modeled
The core as RV32EC at one instruction per clock, the clock tree (HSI, the PLL
and the AHB prescaler), GPIO ports A, C and D with push-pull, open drain,
pull-up, pull-down and analog modes and the clock gating above, USART1 on the
default pins, ADC1 as a software-triggered ten-bit conversion, and SysTick
behind millis(), micros() and delay(). Register addresses and offsets are
the reference manual's; the contract in
docs/plans/ch32v003.md lists the few that are believed rather than checked.
What is not modeled
- Interrupts. The PFIC is not modeled, so SysTick, EXTI and USART interrupts
never fire and
attachInterrupt()does not exist. A program polls. - PWM, so no
analogWrite()ortone(), and I2C and SPI, so noWireorSPI. These are the next version. - USART and AFIO pin remaps, the option bytes, flash programming, the independent watchdog and auto wakeup.
- WCH's XW compressed instructions, and the trap the real core takes on registers x16 and up. A program built with WCH's own compiler that uses XW traps here.
PD7as the reset pin. On a factory chip PD7 can be NRST depending on its option bytes; here it is a plain GPIO.String,Streamand the libraries: 16 KB of flash and 2 KB of RAM do not hold them, so the Arduino library catalog does not apply to this board.
Common mistakes
Writing to a port register before enabling its clock. Nothing happens, on the chip and here.
Expecting delay() to sleep. It is a busy wait on SysTick, so the simulation
runs every instruction of it.
Wiring an LED to the board and expecting LED_BUILTIN. The breakout has none;
wire an LED and a resistor from a pin to GND.
Starter projects
Blink flashes an LED on PD2 through a 330 ohm resistor. Button lights
it while a push button on PC4 is held. Serial prints a count each second
and echoes what you type. Knob reads a potentiometer on PC4 with the ADC.
Related
- The board page: /boards/ch32v003
- A RISC-V neighbor with a lot more room: the ESP32-C3
- The plan and contract for the chip model:
docs/plans/ch32v003.md