2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ライトな開発環境である ch32fun を使ってみます。

ch32fun

以前は CH32V003Fun という名前でした。
2024年の記事「ch32v003fun First Try」
https://qiita.com/nanbuwks/items/f7cc5126ee7eea72ba22
では当時の CH32V003Fun を使って、 ch32V003 を搭載した AKBONE2024 に対して試してみました。

その後、2025年2月頃の Commit 392eee7 において、ch32v003fun は ch32fun に変更になり、対応も CH32V系だけではなく、CH32X や CH5系も対応になったようだ。

CH32V203 の対応

2024年時点では、 CH32V203も対応はしていましたが、まだあんまりだった感じ。
今は CH32V203 への対応はどれだけ進んでいるのかな? 試してみました。

環境

  • Ubuntu 22.04 LTS
  • ch32fun
  • wchisp
  • WeActStudio の、BluePill+

インストール

インストールは以下
https://github.com/cnlohr/ch32fun
を参照しながらやっていきますが、書き込みは WCHISP を使ってチップの USB インターフェース経由で書き込むつもりなのでちょっとアレンジ。

準備

ビルドツールをお膳立てします。

$ sudo apt install build-essential libnewlib-dev gcc-riscv64-unknown-elf libusb-1.0-0-dev libudev-dev gdb-multiarch

wchisp

「wchisp を Ubuntu にインストール」
https://qiita.com/nanbuwks/items/b55e12d2ceaac5fffd4c
で導入した wch isp tool を使いました。

ch32fun を使って L チカするまで

$ git clone https://github.com/cnlohr/ch32fun.git
$ cd ch32fun
$ ls
LICENSE        ch32fun         examples_h41x  examples_v10x  examples_x00x  minichlink    platformio.ini
README.md      examples        examples_l103  examples_v20x  examples_x035  misc          projects
build_scripts  examples_ch5xx  examples_usb   examples_v30x  extralibs      package.json

まずはスタンダードな examples を試してみます。

$ cd examples
$ ls
adc_dma_opamp        direct_gpio          mco_clock_output    sysclk_config
adc_fixed_fs         dma_gpio             optionbytes         systick_irq
adc_injection        dma_gpio_mem2mem     optiondata          template
adc_polled           dma_gpio_ws2812      random_numbers      tim1_capture_dma
app_without_flash    dma_scheduled_io     self_modify_code    tim1_capture_dma_pwm_in
bldc_gimbal          dma_spi              spi_24L01_rx        tim1_phase_shifted_pwm
blink                external_crystal     spi_24L01_tx        tim1_pwm
blink_raw            exti_pin_change_isr  spi_dac             tim1_pwm_complementary_outputs
bootload             flashtest            spi_lora_sx126x     tim1_tim2_cascade
branchless_gpio_lib  function_in_ram      spi_lora_sx127x     tim2_encoder
breathe              gpio_and_adc         spi_max7219         tim2_pwm
cap_touch_adc        hc595_demo           spi_oled            tim2_pwm_remap
cap_touch_exti       hsitrim              spi_slave           uart_tx_dma
color_lcd            i2c_oled             standby_autowake    uartdemo
constructors         i2c_slave            standby_btn         usart_dma_rx_circular
cpp_virtual_methods  input_capture        struct_direct_gpio  vector_free_table_irq
debugprintfdemo      iwdg                 struct_gpio         ws2812bdemo

blink を使ってみます。

$ cd blink
$ ls
Makefile  blink.bin  blink.c  funconfig.h
$ cat Makefile
all : flash

TARGET:=blink

TARGET_MCU?=CH32V003
include ../../ch32fun/ch32fun.mk

flash : cv_flash
clean : cv_clean

ということで、TARGET_MCU? を以下に書き換えました。

TARGET_MCU?=CH32V203
$ cat blink.c
#include "ch32fun.h"
#include <stdio.h>

// use defines to make more meaningful names for our GPIO pins
#define PIN_1 PD9
#define PIN_K PD4
#define PIN_BOB PD6
#define PIN_KEVIN PC0

int main()
{
	SystemInit();

	funGpioInitAll(); // Enable GPIOs
	
	funPinMode( PIN_1,     GPIO_Speed_10MHz | GPIO_CNF_OUT_PP ); // Set PIN_1 to output
	funPinMode( PIN_K,     GPIO_Speed_10MHz | GPIO_CNF_OUT_PP ); // Set PIN_K to output
	funPinMode( PIN_BOB,   GPIO_Speed_10MHz | GPIO_CNF_OUT_PP ); // Set PIN_BOB to output
	funPinMode( PIN_KEVIN, GPIO_Speed_10MHz | GPIO_CNF_OUT_PP ); // Set PIN_KEVIN to output

	while(1)
	{
		funDigitalWrite( PIN_1,     FUN_HIGH ); // Turn on PIN_1
		funDigitalWrite( PIN_K,     FUN_HIGH ); // Turn on PIN_K
		funDigitalWrite( PIN_BOB,   FUN_HIGH ); // Turn on PIN_BOB
		funDigitalWrite( PIN_KEVIN, FUN_HIGH ); // Turn on PIN_KEVIN
		Delay_Ms( 250 );
		funDigitalWrite( PIN_1,     FUN_LOW );  // Turn off PIN_1
		funDigitalWrite( PIN_K,     FUN_LOW );  // Turn off PIN_K
		funDigitalWrite( PIN_BOB,   FUN_LOW );  // Turn off PIN_BOB
		funDigitalWrite( PIN_KEVIN, FUN_LOW );  // Turn off PIN_KEVIN
		Delay_Ms( 250 );
	}
}

となっている。 PIN?K とか PIN_BOB PIN_KEVIN ってなんだ?
とりあえず、 PIN_1 を以下のように設定

#define PIN_1 PB2

ビルドします。

$ make
riscv64-unknown-elf-gcc -E -P -x c -DTARGET_MCU=CH32V203 -DMCU_PACKAGE=2 -DTARGET_MCU_LD=2 -DTARGET_MCU_MEMORY_SPLIT= ../../ch32fun//ch32fun.ld > ../../ch32fun//generated_CH32V203F6P6_.ld
riscv64-unknown-elf-gcc -o blink.elf ../../ch32fun//ch32fun.c blink.c   -g -Os -flto -ffunction-sections -fdata-sections -fmessage-length=0 -msmall-data-limit=8 -fno-tree-loop-distribute-patterns -march=rv32imac -mabi=ilp32 -DCH32V20x=1 -static-libgcc -I/usr/include/newlib -I../../ch32fun//../extralibs -I../../ch32fun/ -nostdlib -I. -Wall  -Wl,--print-memory-usage -Wl,-Map=blink.map -lgcc -T ../../ch32fun//generated_CH32V203F6P6_.ld -Wl,--gc-sections
Memory region         Used Size  Region Size  %age Used
           FLASH:         892 B        32 KB      2.72%
             EXT:           0 B       192 KB      0.00%
             RAM:           0 B        10 KB      0.00%
riscv64-unknown-elf-objdump -S blink.elf > blink.lst
riscv64-unknown-elf-objcopy -R .storage  -O binary blink.elf blink.bin
riscv64-unknown-elf-objcopy -j .storage -O binary blink.elf blink_ext.bin
riscv64-unknown-elf-objcopy -O ihex blink.elf blink.hex
../../ch32fun//../minichlink/minichlink -w blink.bin flash -b
minichlink version - eb926174a722040c3c79980d707c169a2c322acd
VID:0x1209, PID:0xb003
Error: Could not initialize any supported programmers
make: *** [../../ch32fun/ch32fun.mk:433: cv_flash] エラー 224

エラーが出ていますが、プログラムを minichlink を使って書こうとしているからです。 .elf ファイルはできているので、書き込んでみます。

$ wchisp flash blink.elf
04:01:25 [INFO] Opening USB device #0
04:01:25 [INFO] Chip: CH32V203C8T6[0x3119] (Code Flash: 64KiB)
04:01:25 [INFO] Chip UID: CD-AB-B2-61-0E-BC-8D-C9
04:01:25 [INFO] BTVER(bootloader ver): 02.70
04:01:25 [INFO] Code Flash protected: false
04:01:25 [INFO] Current config registers: a55aff0000ff00ffffffffff00020700cdabb2610ebc8dc9
RDPR_USER: 0x00FF5AA5
  [7:0]   RDPR 0xA5 (0b10100101)
    `- Unprotected
  [16:16] IWDG_SW 0x1 (0b1)
    `- IWDG enabled by the software, and disabled by hardware
  [17:17] STOP_RST 0x1 (0b1)
    `- Disable
  [18:18] STANDBY_RST 0x1 (0b1)
    `- Disable, entering standby-mode without RST
  [23:22] SRAM_CODE_MODE 0x3 (0b11)
    `- CODE-228KB + RAM-32KB / CODE-160KB + RAM-32KB depending on the chip
DATA: 0xFF00FF00
  [7:0]   DATA0 0x0 (0b0)
  [23:16] DATA1 0x0 (0b0)
WRP: 0xFFFFFFFF
  `- Unprotected
04:01:25 [INFO] Read blink.elf as ELF format
04:01:25 [INFO] Found loadable segment, physical address: 0x00000000, virtual address: 0x00000000, flags: 0x5
04:01:25 [INFO] Section names: [".init", ".text"]
04:01:25 [INFO] Firmware size: 1024
04:01:25 [INFO] Erasing...
04:01:25 [WARN] erase_code: set min number of erased sectors to 8
04:01:25 [INFO] Erased 8 code flash sectors
04:01:26 [INFO] Erase done
04:01:26 [INFO] Writing to code flash...
█████████████████████████████████████████████████████████████████████████████████████████████████████████ 1024/102404:01:26 [INFO] Code flash 1024 bytes written
04:01:27 [INFO] Verifying...
█████████████████████████████████████████████████████████████████████████████████████████████████████████ 1024/102404:01:27 [INFO] Verify OK
04:01:27 [INFO] Now reset device and skip any communication errors
04:01:27 [INFO] Device reset

上手く書き込めて、 blink できました。

割り込み駆動の blink を試す

examples_v20x 中のサンプルプログラムを試してみます。

$ ls
blink debugprintfdemo eth_sfhip exti_blink otg_device spidmatest
canbus_network eth_raw_icmp extendedflash mcotest spi_dma_chain

exti_blink というのは何かな? ExtInterrupt という意味だそうです。試してみます。

$ cd exti_blink
$ cat exti_blink.c 
/*
Short example to demonstrate how to use external interrupts.
When I tested my circuit I made the following connections:
PA10 ---- LED
PA1  ---- Debounced switch that pulls to ground and a pull up resistor.
You can set any pins for LED and switch by editing their defines.
*/
#include "ch32fun.h"

#define LED_PIN PA10
#define INT_PIN PA1

#define RISING_EDGE 1
#define FALLING_EDGE 0

static inline void blinkInterrupt( void );
// Setup all interrupt handlers the same way so we can later enable any of them in code
__attribute__((interrupt)) void EXTI0_IRQHandler( void ) { blinkInterrupt(); }
__attribute__((interrupt)) void EXTI1_IRQHandler( void ) { blinkInterrupt(); }
__attribute__((interrupt)) void EXTI2_IRQHandler( void ) { blinkInterrupt(); }
__attribute__((interrupt)) void EXTI3_IRQHandler( void ) { blinkInterrupt(); }
__attribute__((interrupt)) void EXTI4_IRQHandler( void ) { blinkInterrupt(); }
__attribute__((interrupt)) void EXTI9_5_IRQHandler( void ) { blinkInterrupt(); }
__attribute__((interrupt)) void EXTI15_10_IRQHandler( void ) { blinkInterrupt(); }

// set state of the LED_PIN
int state = 1;

static void setupEXTI( uint8_t pin, uint8_t rising )
{
	uint8_t port = (uint8_t)(pin / 16); // GPIO pin numbers in ch32fun are defined as an integer. Each port adds 16 to the pin number.
	uint8_t exti = (uint8_t)(pin / 4); // There are 4 AFIO->EXTICR registers. And each is responsible for 4 pins out of 16

	AFIO->EXTICR[exti] |= port; // AFIO->EXTICR cares only about enabling certain port for it's corresponding 4 pins

	if (rising) {
		EXTI->RTENR |= 1 << (pin%16); // enable rising edge trigger
		EXTI->FTENR &= ~(1 << (pin%16)); // disable falling edge trigger
	} else {
		EXTI->RTENR &= ~(1 << (pin%16)); // disable rising edge trigger
		EXTI->FTENR |= 1 << (pin%16); // enable falling edge trigger
	}

	// There are 5 separate interrupts for pins 0-4 and two combined interrupts for pins 5-9 and 10-15
	if( (pin%16) < 5 ) NVIC_EnableIRQ( (IRQn_Type)((uint8_t)EXTI0_IRQn + (pin%16)) );
	else if( (pin%16) < 10 ) NVIC_EnableIRQ( EXTI9_5_IRQn );
	else NVIC_EnableIRQ( EXTI15_10_IRQn );

	// And here we are finally enable the pin number. (We enable port previously in AFIO->EXTICR)
	EXTI->INTENR |= 1 << (pin%16); // Enable EXTIx line
}

int main()
{
	SystemInit();

	/*
	The enables that end up being used in this code are
	GPIOx  (GPIO port enable for our pins)
	AFIO   (alternate function enable)
	AFIOEN (alternate function clock enable)
	*/
	funGpioInitAll();

	// configure LED_PIN for output and set it high
	funPinMode( LED_PIN, GPIO_CFGLR_OUT_10Mhz_PP );
	funDigitalWrite( LED_PIN, FUN_HIGH );

	// configure interrupt pin for floating input
	funPinMode( INT_PIN, GPIO_CFGLR_IN_FLOAT );

	// You can also use pull-up/pull-down
	// funPinMode( INT_PIN, GPIO_CFGLR_IN_PUPD );
	// funDigitalWrite( INT_PIN, FUN_LOW );

	// Set all registers needed for external interrupt on INT_PIN
	setupEXTI( INT_PIN, RISING_EDGE );

	while(1)
	{

	}
}

/*
Interrupt code
	Checks if it was set low or high last
	and toggles it based on that info.
*/
static inline void blinkInterrupt( void )
{
	// verify the interrupt flag occured.
	if( EXTI->INTFR & (1<<(INT_PIN%16)) )
	{
		if( state == 0 )
		{
			funDigitalWrite( LED_PIN, FUN_HIGH );
			state = 1;
		} 
		else
		{
			funDigitalWrite( LED_PIN, FUN_LOW );
			state = 0;
		}
		EXTI->INTFR = 1<<(INT_PIN%16); // clear interrupt flag
	}
}

  • User KEY は PA0 、 push で HIGH
  • LED は PB2 、正論理

なので、

#define LED_PIN PB2
#define INT_PIN PA0 

に書き換えて

$ make
$ wchisp flash exti_blink.elf

で動作しました。

CH32V203 への ch32fun の対応

サンプルプログラムは少ないながらも CH32V20x 用のものが増えてきており、もうちょっと深堀してみてもいいかな?

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?