Posts

Showing posts from January, 2023

CH32V307 : tinyUsb

Image
One of the last big chunk of support for the CH32V3x is now working : Usb TinyUSB  has just received a driver for the CH32V307, which was merged in lnArduino I modified the driver a bit so it fits better within lnArduino. Within lnArduino both high speed and full-speed work, while inside tinyUsb only high speed is working?

CH32V307 : FPU + FreeRTOS

Toolchain/Clang  Time to enable the FPU! I've modified the   LLVM-embedded-toolchain-for-rv32  so that it builds both soft-ftp and hard-fp clang runtimes (it is a bit clunky but works). FreeRTOS WCH implementation The FreeRTOS implementation saves this on the task stack :  MEPC [FPU] Normal regs MStatus [FPU] depends on a compilation switch.  It contains either all the FPU registers (the 32 of them) or nothing. Always. This is problematic. Saving all those registers is hitting the stack hard and it takes time. Furthermore, that happens for all task switches  even if the FPU is not used. Conversely, if you dont save the FPU registers and use the FPU in 2 different tasks, you'll get data corruption. Naive improvement I implemented a very naive change using the FS bits in mstatus. These FS bits can have 2 interesting values :  FPU never used (Off, original, clean) FPU dirty (i.e. used at some point). So, when the FS bits are "not used", you can skip saving/restoring the

CH32V307 : Rust + I2C + Clang

Image
 I2C is still  a bit unstable but here we go : CH32V307+SSD1306 + rust + clang ! This is a pic of the simplerSSD1306 rust driver running on the CH32V307 + rnArduino NB: The code seems to be significantly larger than the exact same thing built for bluepill / Arm cortex m3 though. NB: Seems the rust target riscv32-imafc does not exist as of today. So no FPU with rust!

CH32V307 : SPI & LCD

Image
After tackling some riscv/clang issues, i can now say that the compatibility of the CH32V307 with the good old STM32F103 is pretty good.  lnArduino works quite well so far,  the associated sample code is running okay-ish. There are still some stuff to work on though : - i2c is unstable - the init code/linker script does not seem to be 100% correct - rust binaries are really huge (they should be ~ 60 kB, they end up being 300kB, like if the clang LTO was not working). - so called hardware fast interrupt seems to be doing nothing at all - i still have to figure out how to enable the fpu without hammering the stack on interrupt/context switch Overall, the CH323V307 seems to be a valid replacement for the GD32VF103 (which is going into oblivion or so it seems). Mandatory pic-or-it-didnt-happen (the exact same driver/code is running also on stm32f103):  

CH32V307 : Full llvm/clang toolchain

 Clang /LLVM can be a bit complicated to build especially if you want to use it with riscv32+picolibc. There is an   arm toolchain build project  to build it for arm cores,. Fortunately,  it is easy to patch to build for rv32imac. I posted the patched version on  github Checkout the project then ln -s $PWD/build/_deps/llvmproject-src/llvm/lib lib then mkdir build && cd build &&  cmake  -G Ninja .. && ninja &&  ninja package-llvm-toolchain You end up with a full blown LLVM C/C++ toolchain in LLVM.....tar.gz

CH32V307 Picolibc to the rescue

  With our shiny new risv32 gcc, let's look at the generated code size. The demo is a small graphic demo using a SSD1306 With vanilla libc build with our shiny riscv32gcc : Code = 50 kB Let's build and install  picolibc In order to do so, create a cross.txt containing : [binaries] c = 'riscv64-unknown-elf-gcc' ar = 'riscv64-unknown-elf-ar' as = 'riscv64-unknown-elf-as' ld = 'riscv64-unknown-elf-ld' strip = 'riscv64-unknown-elf-strip' [host_machine] system = 'unknown' cpu_family = 'riscv' cpu = 'riscv' endian = 'little' [properties] c_args = [ '-nostdlib', '-msave-restore', '-fno-common' ] # default multilib is 64 bit c_args_ = [ '-march=rv32imac', '-mabi=ilp32'] needs_exe_wrapper = true skip_sanity_check = true make sure our shiny new riscv gcc is in your path, then mkdir build && cd build &&  meson --cross-file ../cross.txt .. && ninja &

CH32V307 : Using a newer riscv toolchain

 The CH32V307 (and siblings) has a nice interrupt extension : Fast Interrupt As the name implies, it saves/restores  more registers automatically before  executing the actual interrupt. It is, of course much faster than doing it manually. It is used internally by SysTick (maybe SW_Handler too) To use it, WCH has  modified their GCC 8.2 to add a new attribute :    __attribute__((interrupt("WCH-Interrupt-fast"))) For example :   void SysTick_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); It is easy to use, but forces you to use the gcc 8.1 based wch compiler (or another compiler that merged the patch) and is causing problem with random gcc and/or clang. NB : Clang is a better choice, if you use rust, else no LTO for you. After looking into it, it appears that WCH-Interrupt-fast is about the same as using __attribute__((interrupt(naked))) + exiting the function with "mret" Doing that,  we can use any gcc and it works (or seems to). Regarding

CH32V307 : Debugging with vscode

 This is derived from  https://www.justinmklam.com/posts/2017/10/vscode-debugger-setup 1- Install native debugging plugin gdb/... within vscode 2- Add (and change) the following line to your settings.json pointing to the toolchain binaries (especially the riscv gdb) and the wch-openocd bin folder : "riscv_openocd_path" : "/opt/wch/MounRiver_Studio_Community_Linux_x64_V130/MRS_Community/toolchain/OpenOCD/bin" , "riscv_gdb_path" : "/opt/wch/MRS_Toolchain_Linux_x64_V1.60/RISC-V Embedded GCC/bin/" 3- Create the launch.json file, adapt the name to your project  { "version": "0.2.0", "configurations": [       { "name": "riscv_GDB", "type": "gdb", "request": "launch", "cwd": "${workspaceRoot}", "target": "${workspaceRoot}/build/lnPowerSupply_CH32V3x_72M.elf", "gdbpath" : "${config:riscv_gdb_pa