In this article, I’ll show you the CH32V003 schematic & PCB design steps, explain some of the design decisions that I’ve made, how to prepare the files needed for manufacturing, and how to place the PCB SMT order at JLCPCB who are kindly sponsoring this project as well.
This is a custom CH32V003 development board designed for evaluating the 10 cents RISC-V microcontroller from WCH. This project can serve as a baseline for anyone willing to create his own RISC-V MCU dev board based on the CH32V003 microcontroller.
This Project is Sponsored By JLCPCB
Table of Contents
- CH32V003 Overview & Datasheet
- CH32V003 Dev Board Schematic Design
- Placing PCBA Order @ JLCPCB
- CH32V003 LED Blinking GPIO Example Test
- CH32V003 PWM Example Test
- Conclusion & Upcoming Next
- CH32V003 Schematic + PCB Design Project Video
CH32V003 Overview & Datasheet
The CH32V003 is based on QingKe RISC-V2A core design of industrial-grade general-purpose microcontroller, support 48MHz system main frequency, ADC, DMA, and a handful of other peripherals. Here is a block diagram of the microcontroller’s top-level architecture.
CH32V003 Variants & IC Packages
CH32V003 Datasheet & Reference Manual
CH32V003 Dev Board Schematic Design
This is the schematic design that I came up with for this CH32V003 development board project. Some parts are not mandatory and can be omitted for even more cost optimization if you need.
1. DC PWR In + LDO + USB-UART
There’s a USB-C port that I’m using for power input (+5v) as well as USB-UART bridge (CH340E chip).
The USB +5v input is regulated down to 3.3v using an LDO. The 3.3v is then used to power up the CH32V003 microcontroller.
2. CH32V003 MCU Circuitry
The CH32V003 microcontrollr requires a 3.3v input voltage @ Vdd pin, a 100nF decoupling capacitor, and a 24MHz crystal oscillator.
You can use any crystal oscillator frequency you want, however, it’s necessary to use a 24MHz if you want to run the MCU at its maximum speed @48MHz. This is because the internal PLL is not arbitrarily programmable as in STM32 microcontrollers for example. The internal PLL just multiplies the input clock frequency by 2 and that’s it.
I’ve also added an NRST button to reset the microcontroller when needed.
3. Debug Port
The CH32V003 supports a serial wire debug using only one line if you’re going to use the WCH-Link debugger as the one shown below.
This debugger has an internal USB-UART bridge that you can use instead of the CH340E chip that I’ve added to reduce the size/cost of your dev board, just in case you need to.
4. IO Port + LEDs
Just pinout all the IO pins to one or two headers depending on your desired board shape and layout.
I’ve addd a power indicator LED + 2x user programmable LEDs. I wanted the LEDs to be PWM-controlled, so I made sure they’re hooked to TxCHx pins on the CH32V003 microcontroller.
Placing PCBA Order @ JLCPCB
Finally, we’re ready to generate the fabrication files and send them to JLCPCB for PCB fabrication and assembly. For this task, I use the KiCAD plugin named “Fabrication Toolkit”. With just one button click, you’ll have all manufacturing output files ready in a new folder that’s automatically created for you by the plugin toolkit.
1. Upload Your Gerber File & Check PCB Fab. Options
The next step is to upload your PCB Gerber files and modify the PCB fabrication options as needed in your project. Just keep an eye on the price because some options are not considered as a standard fabrication process, which will end up costing you a bit more and takes a bit more time to get fabricated.
Even if you’re 100% sure that your design & fabrication files are flawless, the online system & JLCPCB or any other fab house can still pick up wrong components orientation or placement. Always double-check the PCB component placement after uploading your files.
2. Upload BOM & CPL Files
The next step is to upload your design’s BOM file and the components positions file (CPL) to JLCPCB and let it check the files and report the stock status and total number of components to be assembled, their cost, and so on.
Check everything and make sure the components are selected correctly from the JLCPCB SMT library. And also double-check the component placements on the next page and correct any wrong rotations in the CPL file. There is a mismatch between the KiCAD output position file & JLCPCB’s system, so it does pick up wrong orientations for some ICs, diodes, etc. Always double-check everything before placing the order.
3. Pay To Place Your Order
The last step to place your order is to pay for the invoice and you can apply any valid discount coupon at this step to reduce the cost.
4. Wait For Delivery & Prepare For Testing!
You should expect to receive your board within 4 days to 1 week depending on where you live.
CH32V003 LED Blinking GPIO Example Test
This is the first test example project in which we’ll blink the onboard 2x LEDs alternatively for half a second each.
Open the MounRiver IDE, create a new project using NoOS Tempelate, and copy the example test code below.
CH32V003 LED Blinking GPIO Example Code
The Application Code For This Example (main.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* * LAB Name: CH32V003 GPIO Test * Author: Khaled Magdy * For More Info Visit: www.DeepBlueMbedded.com */ #include "debug.h" void LEDs_GPIO_Init(void); int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); SystemCoreClockUpdate(); Delay_Init(); LEDs_GPIO_Init(); while(1) { GPIO_SetBits(GPIOC, GPIO_Pin_3); GPIO_ResetBits(GPIOC, GPIO_Pin_4); Delay_Ms(500); GPIO_SetBits(GPIOC, GPIO_Pin_4); GPIO_ResetBits(GPIOC, GPIO_Pin_3); Delay_Ms(500); } } void LEDs_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure={0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE ); // C3 Pin GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_30MHz; GPIO_Init( GPIOC, &GPIO_InitStructure ); // C4 Pin GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_30MHz; GPIO_Init( GPIOC, &GPIO_InitStructure ); } |
Compile & Flash the firmware to the board using the WCH-Link debugger.
LED Blinking Test Result
CH32V003 PWM Example Test
In this test project, we’ll dim the onboard 2x LEDs alternatively using PWM outputs (CH3 & CH4 For LED1 & LED2).
Open the MounRiver IDE, create a new project using NoOS Tempelate, and copy the example test code below.
CH32V003 PWM Example Code
The Application Code For This Example (main.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
/* * LAB Name: CH32V003 PWM Test * Author: Khaled Magdy * For More Info Visit: www.DeepBlueMbedded.com */ #include "debug.h" uint16_t Duty = 0; int Step = 1; void TIM1_PWMOuts_Init(u16, u16, u16); int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); SystemCoreClockUpdate(); Delay_Init(); TIM1_PWMOuts_Init(1024, 0, 0); // Timer1 (CH3 & CH4) while(1) { // Update PWM1-CH3 & CH4 Outputs TIM1->CH3CVR = Duty; // LED 1 fades in TIM1->CH4CVR = 1024 - Duty; // LED 2 fades out Duty += Step; // Reverse direction when reaching max or min brightness if (Duty == 1024 || Duty == 0) { Step = -1*Step; } Delay_Ms(1); } } void TIM1_PWMOuts_Init(u16 arr, u16 psc, u16 ccp) { GPIO_InitTypeDef GPIO_InitStructure={0}; TIM_OCInitTypeDef TIM_OCInitStructure={0}; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0}; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_TIM1, ENABLE ); // C3 Pin GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_30MHz; GPIO_Init( GPIOC, &GPIO_InitStructure ); // C4 Pin GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_30MHz; GPIO_Init( GPIOC, &GPIO_InitStructure ); TIM_TimeBaseInitStructure.TIM_Period = arr; TIM_TimeBaseInitStructure.TIM_Prescaler = psc; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = ccp; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC3Init( TIM1, &TIM_OCInitStructure ); TIM_OC4Init( TIM1, &TIM_OCInitStructure ); TIM_CtrlPWMOutputs(TIM1, ENABLE ); TIM_OC3PreloadConfig( TIM1, TIM_OCPreload_Enable ); TIM_OC4PreloadConfig( TIM1, TIM_OCPreload_Enable ); TIM_ARRPreloadConfig( TIM1, ENABLE ); TIM_Cmd( TIM1, ENABLE ); } |
Compile & Flash the firmware to the board using the WCH-Link debugger.
PWM LED Dimmer Test Result
Conclusion & Upcoming Next
By the end of this, you should have learned how to create your custom CH32V003 dev board or incorporate this microcontroller in your next project if needed.
The intention behind designing this board that I’ve shown you today is to evaluate the possibility of using a cheap MCU like the CH32V003 for touching sensing applications using the CVD algorithm/technique. This could significantly offload the CapTouch sensors sampling task from the main application processor. Here is a sneak peek of what’s coming up next!
Coming Up Next:
- CH32V003 RISC-V CVD Capacitive Touch Sensing
- CH32V003 Minimal DIP Board Replacing Old MCUs
CH32V003 Schematic + PCB Design Project Video
Here is the video for this project on YouTube if you’d like to get more in-depth information and explanation of the design of this CH32V003 PCB project.