A step-by-step guide to toggling an LED on the WCH CH32L103 RISC-V MCU by directly manipulating clock, GPIO configuration, and output registers.
Three registers do the work
Turning an LED on or off is ultimately a matter of three register-level actions:On CH32L103, the registers are:
Enable the GPIOB clock
Before any pin on port B responds, the clock to that peripheral must be turned on. In the reference manual this is described as RCC_PB2PCENR, bit 3.RCC->PB2PCENR |= (1 << 3);
Configure PB0..PB7 as push-pull outputsGPIOB_CFGLR is a 32-bit register. Each pin uses 4 bits: the lower 2 bits select input or output mode, and the upper 2 bits select the output type. For a general-purpose push-pull output, write 0x3 for each pin.
GPIOB->CFGLR = 0x33333333;Drive the pins
GPIOB_OUTDR holds the 16-bit output value for the whole port. Writing 0xFFFF turns pins high; writing 0x0 turns them low. On the evaluation board used in the original tutorial, the LED cathode is connected to PB5, so a low output lights the LED.GPIOB->OUTDR = 0x0000;
Complete example#include "ch32l103.h"
int main(void) { RCC->PB2PCENR |= (1 << 3); GPIOB->CFGLR = 0x33333333; GPIOB->OUTDR = 0x0000; while (1); }Target a single pin
If you only want PB5, clear its 4-bit field first, then set it to output mode: GPIOB->CFGLR &= ~(0xF << (4 * 5)); GPIOB->CFGLR |= (0x3 << (4 * 5)); GPIOB->OUTDR &= ~(1 << 5);Direct address version
For the truly minimalist version, use the addresses directly. This is useful when you want to see exactly what the hardware sees: ((volatile unsigned int )0x40021018) |= (1 << 3); ((volatile unsigned int )0x40010C00) = 0x33333333; ((volatile unsigned int )0x40010C0C) = 0xFFFF;Comparison with STM32F103
The same logic maps cleanly to STM32F103 with only register-name changes:This makes CH32L103 a comfortable drop-in alternative for anyone already used to direct register programming on Cortex-M3.
Takeaways