diff --git a/ch32v203/.cargo/config.toml b/ch32v203/.cargo/config.toml index cf0435f..c9fcca3 100644 --- a/ch32v203/.cargo/config.toml +++ b/ch32v203/.cargo/config.toml @@ -2,8 +2,9 @@ target = "riscv32imc-unknown-none-elf" [target."riscv32imc-unknown-none-elf"] -# runner = "wlink -v flash --enable-sdi-print --watch-serial --erase" -runner = "wchisp flash" +# runner = "wlink flash" +# runner = "wchisp flash" +runner = "./uf2_flash.sh" # runner = "probe-rs run --chip ch32v203" # runner = "arm-none-eabi-size" diff --git a/ch32v203/Cargo.toml b/ch32v203/Cargo.toml index 7076398..7efa4ed 100644 --- a/ch32v203/Cargo.toml +++ b/ch32v203/Cargo.toml @@ -16,6 +16,8 @@ ch32v203k6t6 = ["ch32-hal/ch32v203k6t6"] ch32v203k8t6 = ["ch32-hal/ch32v203k8t6"] ch32v203rbt6 = ["ch32-hal/ch32v203rbt6"] +bootloader = [] + default = ["ch32v203g6u6"] [dependencies] diff --git a/ch32v203/bootloader.elf b/ch32v203/bootloader.elf new file mode 100644 index 0000000..10a7b01 Binary files /dev/null and b/ch32v203/bootloader.elf differ diff --git a/ch32v203/build.rs b/ch32v203/build.rs index 3f57399..035d3f1 100644 --- a/ch32v203/build.rs +++ b/ch32v203/build.rs @@ -1,11 +1,59 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +#[cfg(feature = "bootloader")] +fn linker_data() -> &'static [u8] { + #[cfg(any( + feature = "ch32v203c6t6", + feature = "ch32v203f6p6", + feature = "ch32v203g6u6", + feature = "ch32v203k6t6" + ))] + return include_bytes!("memory-with-bootloader-32k.x"); + #[cfg(any( + feature = "ch32v203c8t6", + feature = "ch32v203c8u6", + feature = "ch32v203f8p6", + feature = "ch32v203f8u6", + feature = "ch32v203g8r6", + feature = "ch32v203k8t6" + ))] + return include_bytes!("memory-with-bootloader-64k.x"); + #[cfg(feature = "ch32v203rbt6")] + return include_bytes!("memory-with-bootloader-128k.x"); +} + fn main() { + #[cfg(feature = "bootloader")] + { + use std::env; + use std::fs::File; + use std::io::Write; + use std::path::PathBuf; + // If we use a bootloader, then we want to alter flash origin to 0x1000 + // We do this by giving the linker a different memory.x file + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(linker_data()) + .unwrap(); + println!("cargo::rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo::rerun-if-changed=memory.x"); + } + // println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); // println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); - - // let out_dir = std::env::var("OUT_DIR").unwrap(); - // let out_dir = std::path::PathBuf::from(out_dir); - // std::fs::write(out_dir.join("memory.x"), include_bytes!("memory.x")).unwrap(); - // println!("cargo:rustc-link-search={}", out_dir.display()); - // println!("cargo:rerun-if-changed=memory.x"); } diff --git a/ch32v203/memory-with-bootloader-128k.x b/ch32v203/memory-with-bootloader-128k.x new file mode 100644 index 0000000..fbaa06a --- /dev/null +++ b/ch32v203/memory-with-bootloader-128k.x @@ -0,0 +1,11 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00001000, LENGTH = 124K + RAM : ORIGIN = 0x20000000, LENGTH = 64K +} +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_RODATA", FLASH); +REGION_ALIAS("REGION_DATA", RAM); +REGION_ALIAS("REGION_BSS", RAM); +REGION_ALIAS("REGION_HEAP", RAM); +REGION_ALIAS("REGION_STACK", RAM); \ No newline at end of file diff --git a/ch32v203/memory-with-bootloader-32k.x b/ch32v203/memory-with-bootloader-32k.x new file mode 100644 index 0000000..336cc4c --- /dev/null +++ b/ch32v203/memory-with-bootloader-32k.x @@ -0,0 +1,11 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00001000, LENGTH = 28K + RAM : ORIGIN = 0x20000000, LENGTH = 10K +} +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_RODATA", FLASH); +REGION_ALIAS("REGION_DATA", RAM); +REGION_ALIAS("REGION_BSS", RAM); +REGION_ALIAS("REGION_HEAP", RAM); +REGION_ALIAS("REGION_STACK", RAM); \ No newline at end of file diff --git a/ch32v203/memory-with-bootloader-64k.x b/ch32v203/memory-with-bootloader-64k.x new file mode 100644 index 0000000..6741502 --- /dev/null +++ b/ch32v203/memory-with-bootloader-64k.x @@ -0,0 +1,11 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00001000, LENGTH = 60K + RAM : ORIGIN = 0x20000000, LENGTH = 20K +} +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_RODATA", FLASH); +REGION_ALIAS("REGION_DATA", RAM); +REGION_ALIAS("REGION_BSS", RAM); +REGION_ALIAS("REGION_HEAP", RAM); +REGION_ALIAS("REGION_STACK", RAM); \ No newline at end of file diff --git a/ch32v203/src/bin/usb_dap.rs b/ch32v203/src/bin/usb_dap.rs index 2955244..b361f8f 100644 --- a/ch32v203/src/bin/usb_dap.rs +++ b/ch32v203/src/bin/usb_dap.rs @@ -35,6 +35,14 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { #[embassy_executor::main(entry = "qingke_rt::entry")] async fn main(spawner: Spawner) { + #[cfg(feature = "bootloader")] + unsafe { + qingke::register::mtvec::write( + 0x00001000, + qingke::register::mtvec::TrapMode::VectoredAddress, + ); + } + let p = hal::init(hal::Config { rcc: hal::rcc::Config::SYSCLK_FREQ_144MHZ_HSI, ..Default::default() diff --git a/ch32v203/src/bin/usb_dap_ppk2_uart.rs b/ch32v203/src/bin/usb_dap_ppk2_uart.rs index f84eabb..b50dc31 100644 --- a/ch32v203/src/bin/usb_dap_ppk2_uart.rs +++ b/ch32v203/src/bin/usb_dap_ppk2_uart.rs @@ -43,6 +43,14 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { #[embassy_executor::main(entry = "qingke_rt::entry")] async fn main(spawner: Spawner) { + #[cfg(feature = "bootloader")] + unsafe { + qingke::register::mtvec::write( + 0x00001000, + qingke::register::mtvec::TrapMode::VectoredAddress, + ); + } + let mut config = hal::Config::default(); config.rcc = hal::rcc::Config::SYSCLK_FREQ_144MHZ_HSI; config.rcc.apb2_pre = ch32_hal::rcc::APBPrescaler::DIV2; diff --git a/ch32v203/src/bin/usb_ppk2.rs b/ch32v203/src/bin/usb_ppk2.rs index 5838544..9028110 100644 --- a/ch32v203/src/bin/usb_ppk2.rs +++ b/ch32v203/src/bin/usb_ppk2.rs @@ -40,7 +40,14 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { #[embassy_executor::main(entry = "qingke_rt::entry")] async fn main(spawner: Spawner) { - hal::debug::SDIPrint::enable(); + #[cfg(feature = "bootloader")] + unsafe { + qingke::register::mtvec::write( + 0x00001000, + qingke::register::mtvec::TrapMode::VectoredAddress, + ); + } + let mut config = hal::Config::default(); config.rcc = hal::rcc::Config::SYSCLK_FREQ_144MHZ_HSI; config.rcc.apb2_pre = ch32_hal::rcc::APBPrescaler::DIV2; diff --git a/ch32v203/src/bin/usb_uart.rs b/ch32v203/src/bin/usb_uart.rs index 8fd28d0..19ce3f2 100644 --- a/ch32v203/src/bin/usb_uart.rs +++ b/ch32v203/src/bin/usb_uart.rs @@ -45,6 +45,14 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { // println will not work without probe. #[embassy_executor::main(entry = "qingke_rt::entry")] async fn main(spawner: Spawner) { + #[cfg(feature = "bootloader")] + unsafe { + qingke::register::mtvec::write( + 0x00001000, + qingke::register::mtvec::TrapMode::VectoredAddress, + ); + } + let p = hal::init(hal::Config { rcc: hal::rcc::Config::SYSCLK_FREQ_144MHZ_HSI, ..Default::default() diff --git a/ch32v203/src/lib.rs b/ch32v203/src/lib.rs index 7a80be2..eddd2e6 100644 --- a/ch32v203/src/lib.rs +++ b/ch32v203/src/lib.rs @@ -12,6 +12,31 @@ macro_rules! my_println { }; } +#[cfg(feature = "bootloader")] +pub unsafe fn enable_backup_registers() { + ch32_hal::pac::RCC.apb1pcenr().modify(|w| { + w.set_pwren(true); + w.set_bkpen(true); + }); + const R32_PWR_CTLR: usize = 0x40007000; + unsafe { + // BDP: Backup domain write enable + *(R32_PWR_CTLR as *mut u32) |= 1 << 8; + } +} + +#[cfg(feature = "bootloader")] +pub unsafe fn enter_bootloader() { + const R16_BKP_DATAR10: usize = 0x40006C28; + unsafe { + // Set R16_BKP_DATAR10 to 0x624c ('bL') to enter bootloader on next boot + *(R16_BKP_DATAR10 as *mut u16) = 0x624c; + } + + // Reset chip to enter bootloader + ch32_hal::pac::PFIC.sctlr().write(|w| w.set_sysreset(true)); +} + pub fn bytes_to_hex<'a>(bytes: &[u8], out: &'a mut [u8]) -> Result<&'a str, ()> { // Need exactly 2 chars per byte if out.len() < bytes.len() * 2 { diff --git a/ch32v203/src/usb_uart_task.rs b/ch32v203/src/usb_uart_task.rs index f9eb0a7..44821ad 100644 --- a/ch32v203/src/usb_uart_task.rs +++ b/ch32v203/src/usb_uart_task.rs @@ -21,6 +21,10 @@ pub async fn usb_tx_uart_rx_task( mut uart_config: UartConfig, ) -> ! { let mut buf = [0; 64]; + #[cfg(feature = "bootloader")] + unsafe { + crate::enable_backup_registers(); + } loop { usb_tx.wait_connection().await; @@ -34,6 +38,10 @@ pub async fn usb_tx_uart_rx_task( { Either::First(_) => { let baud = usb_tx.line_coding().data_rate(); + #[cfg(feature = "bootloader")] + if baud == 1337 { + unsafe { crate::enter_bootloader() } + } println!("Setting baud to: {}", baud); uart_config.baudrate = baud; if let Err(err) = uart_rx.set_config(&uart_config) { diff --git a/ch32v203/uf2_flash.sh b/ch32v203/uf2_flash.sh new file mode 100755 index 0000000..27ec521 --- /dev/null +++ b/ch32v203/uf2_flash.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# Convert ELF to binary +riscv64-unknown-elf-objcopy -O binary $1 target/output.bin +# Convert binary to UF2 using the WCH Family ID +uf2conv -f 0x699b62ec -b 0x08001000 -o target/flash.uf2 target/output.bin +# Copy to the board (assuming it's mounted) +cp target/flash.uf2 /media/$USER/CH32V\ UF2/ \ No newline at end of file