Recent Posts

How to be nervous (about writing)

I’ve tried and failed to resurrect my writing hobby these past 5 years. I published several of those attempts, but something always gnawed at me. Scratch scratch, unpublish, delete. Back to wishing I’d start again.

That’s not to say I haven’t written things, but writing for myself hasn’t happened. Something about the need to craft an idealistic returnal narrative, some impossible grammatic masterpiece to vindicate myself. What am I apologizing for anyway? Who am I trying to convince?

Whatever, it’s been 5 years. Shut up and write.

I can’t help but feel weird though. I thought I embraced weird? Why am I fighting weird?

Nerves

Nervous! Yes! I am nervous! Why am I nervous?

My stupid ego is mistakenly believes my previous writings were superior, well-written, and insightful, just don’t ask me to actually check. I’m comparing myself to a fiction; A fiction built on reverence, and how much writing has meant to me. Like I’m trying to recapture something I’ve lost, but never was.

I’ve grown, matured, even wed since I last wrote regularly. By definition I should be more insightful. Why then am I so nervous to write? To share?

Being gracefully wrong

A decade ago, I switched my blogging style to something closer to note-taking. That was sensible, as I’m really into learning. That’s not to say I wont continue to do this, but something about it worried me.

“Confidently wrong” is a phrase that comes up often. Good writing exudes confidence, or we think it does. My note taking tends to come off as a “matter of fact” style of writing. I will include brief snippets of my current understanding in the notes; Brevity looks like confidence, but it isn’t thorough.

And I suspect that is my bugbear.

It’s not that I can’t write confidently, it’s that sometimes I don’t believe it. Out of necessity I’ll choose a side for the sake of momentum, then find myself in situations where I need to defend or rationalize something I don’t feel strongly about. It can be difficult to gracefully communicate ambivilance in an effective way. Have a conversation with someone, be openly scatterbrained, and they walk away feeling regretful.

I hate this.

I don’t hate that I’m not confident, but I hate that being indecisive isn’t okay. Confidence builds trust; It gives comfort, and everyone wants comfort. While I don’t thrive in indecision, I’m not uncomfortable in it. Call this a personal AuDHD’ism, but it’s not enough for me to be told something is true to believe it; I need to see it or prove it myself to be truly satisfied.

By conventional standards I could be considered an expert on many subjects, but to me I just have a larger foundation. I worry, sometimes dread, about what that foundation is built upon. But the social expectation is that I must exude confidence, and I understand why, as I too haven’t come up with a better way to make others comfortable.

I hate this social norm. I hate this normalized lying.

The enemy of done

I could rattle off the technical reasons why returning to write was so difficult (unhappiness with software, workflow, design), but fundamentally it’s just stupid perfectionism. Dwelling on what’s broken, unfinished, or unported is fruitless if nobody is watching. And nobody can watch if you can’t finish.

Maybe it’s okay to be confidently wrong. “Wrong but done” does beat “unfinished unpublished perfection”, but the desire for right forever haunts.

Whatever. Click save, git push, moving on.

Rust Setup

Installation

bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Updating Rust Version

bash
rustup update

Hello World

https://rust-lang.org/learn/get-started/

bash
cargo new hello # hello/ # .gitignore # Cargo.toml # src/ # main.rs

Cargo.toml

toml
[package] name = "hello" version = "0.1.0" edition = "2024" [dependencies]

main.rs

rust
fn main() { println!("Hello, world!"); }

Build and run

bash
cargo build # Compiling hello v0.1.0 (/home/mike/Work/science/hello) # Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.68s cargo run # Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.03s # Running `target/debug/hello` # Hello, world! ./target/debug/hello # Hello, world! cargo build -r cargo build --release # Compiling hello v0.1.0 (/home/mike/Work/science/hello) # Finished `release` profile [optimized] target(s) in 0.16s cargo run -r cargo run --release # Finished `release` profile [optimized] target(s) in 0.01s # Running `target/release/hello` # Hello, world! ./target/release/hello # Hello, world! find . -name 'hello' -print0 | xargs -0 ls -lhS # 3.8M ./target/debug/hello # 439K ./target/release/hello

Generating a smaller binary

Cargo.toml

toml
[package] name = "hello" version = "0.1.0" edition = "2024" [dependencies] [profile.release] opt-level = "z" # Optimize for size strip = true # Strip symbols lto = true # Link-time optimizations codegen-units = 1 # Certain optimizations only work if parallel code generation is disabled panic = "abort" # Don't generate helpful backtraces on panic!()

More here: https://github.com/johnthagen/min-sized-rust

Using Crates

https://crates.io/crates/ferris-says

Via Cargo (no need to lookup version number):

bash
cargo add ferris-says # Updating crates.io index # Adding ferris-says v0.3.2 to dependencies # Features: # - clippy # Updating crates.io index # Locking 12 packages to latest Rust 1.90.0 compatible versions # Adding aho-corasick v1.1.3 # Adding ferris-says v0.3.2 # Adding memchr v2.7.6 # Adding regex v1.12.2 # Adding regex-automata v0.4.13 # Adding regex-syntax v0.8.8 # Adding smallvec v1.15.1 # Adding smawk v0.3.2 # Adding textwrap v0.16.2 # Adding unicode-linebreak v0.1.5 # Adding unicode-width v0.1.14 # Adding unicode-width v0.2.2 cargo update ferris-says # Updating crates.io index # Locking 0 packages to latest Rust 1.90.0 compatible versions

Or by editing Cargo.toml:

Cargo.toml

toml
[package] name = "hello" version = "0.1.0" edition = "2024" [dependencies] ferris-says = "0.3.2"

Cargo.toml

[dependencies] section

https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html

Versions are considered compatible if their left-most non-zero major/minor/patch component is the same. This is different from SemVer which considers all pre-1.0.0 packages to be incompatible.

toml
# Lets say latest version is 0.3.2 ferris-says = "0.3.2" # 0.3.2 ferris-says = "0.3.1" # 0.3.2 ferris-says = "^0.3.1" # 0.3.2 ferris-says = "0.3" # 0.3.2 ferris-says = "0" # 0.3.2 # https://crates.io/crates/ftml # Lets say latest version is 1.36.1 ftml = "1.36.1" # 1.36.1 ftml = "1.36" # 1.36.1 ftml = "1" # 1.36.1 ftml = "1.12.3" # 1.36.1 ftml = "0" # 0.10.2 ftml = "0.5" # 0.5.0 ftml = "~1.12.3" # 1.12.6 ftml = "~1.12" # 1.12.6 ftml = "~1" # 1.36.1 ftml = "~1.22.1" # 1.22.2 ftml = "= 1.22.1" # 1.22.1 ftml = "0.*" # 0.10.2 ftml = "*" # crates.io error # Specified via a Git repository regex = { git = "https://github.com/rust-lang/regex.git" } regex-lite = { git = "https://github.com/rust-lang/regex.git" } regex-syntax = { git = "https://github.com/rust-lang/regex.git" } # Specified via path (after running `cargo new hello_utils`) hello_utils = { path = "hello_utils" } # Paths must be exact, unlike git that will search the repo for a matching `Cargo.toml` file regex-lite = { path = "../regex/regex-lite" } regex-syntax = { path = "../regex/regex-syntax" } # path or git will be used when built locally. # When THIS crate is published to crates.io, the matching version will be used instead bitflags = { path = "my-bitflags", version = "1.0" } smallvec = { git = "https://github.com/servo/rust-smallvec.git", version = "1.0" } # Platform or architecture specific dependencies [target.'cfg(windows)'.dependencies] winhttp = "0.4.0" [target.'cfg(unix)'.dependencies] openssl = "1.0.1" [target.'cfg(target_arch = "x86")'.dependencies] native-i686 = { path = "native/i686" } [target.'cfg(target_arch = "x86_64")'.dependencies] native-x86_64 = { path = "native/x86_64" }

[features] section

https://doc.rust-lang.org/cargo/reference/features.html

Cargo “features” provide a mechanism to express conditional compilation and optional dependencies. A package defines a set of named features in the [features] table of Cargo.toml, and each feature can either be enabled or disabled.

Cargo.toml

toml
[features] default = ["png", "webp"] # What features to enable by default bmp = [] png = [] ico = ["bmp", "png"] # ico requires the bmp and png features webp = [] # webp does not enable any other features
bash
cargo build --features bmp # builds with default and all specified features

lib.rs

rust
#[cfg(feature = "webp")] pub mod webp; #[cfg(feature = "webp")] pub fn function_that_uses_webp_module() { // ... }

Optional Dependencies

Cargo.toml

toml
[dependencies] gif = { version = "0.11.1", optional = true } # The above implies this [features] gif = ["dep:gif"]
bash
cargo build --features gif

Modules (Libraries)

bash
cargo new mylib --lib # Creating library `mylib` package # mylib/ # Cargo.toml # src/ # lib.rs

Cargo.toml

toml
[package] name = "mylib" version = "0.1.0" edition = "2024" [dependencies]

lib.rs

rust
pub fn add(left: u64, right: u64) -> u64 { left + right } #[cfg(test)] mod tests { use super::*; #[test] fn it_works() { let result = add(2, 2); assert_eq!(result, 4); } }

NOTE: Because libraries aren’t run directly, the template creates a test

bash
cargo test # Compiling mylib v0.1.0 (/home/mike/Work/science/hello/mylib) # Finished `test` profile [unoptimized + debuginfo] target(s) in 0.37s # Running unittests src/lib.rs (target/debug/deps/mylib-adba83cfc6455e3f) # # running 1 test # test tests::it_works ... ok # # test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s # # Doc-tests mylib # # running 0 tests # # test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

WCH RISC-V Microcontrollers

Noteworthy chips (IMO)

ChipArchSpeedSRAMFlashPowerNotes
CH32V003V2A48MHz2KB16KB??
CH32V002V2C48MHz4KB16KB2-5VPin compatible with V003
CH32V006V2C48MHz8KB16KB2-5V
CH32V203V4B144MHz20KB??KB3.3VNo PMP, Slow DIV opcode
CH32V305V4F144MHz32KB??KB3.3VFPU
CH32V307V4F144MHz64KB??KB3.3VFPU, Ethernet

More here: https://github.com/ch32-rs/ch32-data#Families

Flashing devices

Via WCH-LinkE (Dongle with CH32V305)

This is the method you want to program bare chips (or modules without a USB port and/or buttons).

Connect the 3.3V, GND, SDIO, and optionally the SDCLK pins to the microcontroller (NOTE: chips with 16 pins or less don’t have a SDCLK pin). These pins are typically found on the backside of the dongle.

Then use wlink.

bash
# list connected wlink status wlink flash myprogram.elf

IMPORTANT: Unless you’re programming an older chip like the CH32V2003, your WCH-LinkE probably needs a firmware update. wlink status will report the current firmware version. Newer chips are supported by newer firmwares. At the time of this writing v2.18 is the current version, supporting the CH32V006 family of chips and the CH32V317.

Until wlink adds firmware upgrade support, you can use a separate tool:

https://github.com/cjacker/wlink-iap

The latest firmwares can be found in the WCH-LinkUtility package provided by WCH. For the WCH-LinkE, you want FIRMWARE_CH32V305.bin.

bash
wlink-iap -f ../Firmware_Link/FIRMWARE_CH32V305.bin

The wlink-iap tool will automatically switch to IAP mode, so upgrading firmwares only requires that you do the above.

Via bootloader (ISP/IAP)

You can flash a device using the wchisp tool (link).

NOTE: Uploading data via the booloader is slower than a WCH-LinkE. Also, you can’t dump binaries using the bootloader. More information here.

Installing wchisp

NOTE: You should add udev rules first, otherwise you’ll have to sudo to do anything with the devices.

/etc/udev/rules.d/50-wchisp.rules

udev
SUBSYSTEM=="usb", ATTRS{idVendor}=="4348", ATTRS{idProduct}=="55e0", MODE="0666"
# or replace MODE="0666" with GROUP="plugdev" or something else
bash
# Paste the above in this file sudo nano /etc/udev/rules.d/50-wchisp.rules # Reload udev sudo udevadm control --reload sudo udevadm trigger

To install wchisp using Cargo:

bash
cargo install wchisp --git https://github.com/ch32-rs/wchisp

Other methods can be found on the wchisp github page.

Running wchisp

If the module has a boot button, hold it while the device powers on (by plugging it in or by pushing reset). You can confirm the device is in bootloadr mode with lsusb.

bash
lsusb # ... # Bus 001 Device 005: ID 4348:55e0 WinChipHead # ...

You can now use wchisp to retrieve information about the attached device.

bash
wchisp info # 00:28:26 [INFO] Opening USB device #0 # 00:28:26 [INFO] Chip: CH32V203C8T6[0x3119] (Code Flash: 64KiB) # 00:28:26 [INFO] Chip UID: CD-AB-58-CF-F1-BC-16-38 # 00:28:26 [INFO] BTVER(bootloader ver): 02.70 # 00:28:26 [INFO] Code Flash protected: true # 00:28:26 [INFO] Current config registers: ff003fc000ff00ffffffffff00020700cdab58cff1bc1638 # RDPR_USER: 0xC03F00FF # [7:0] RDPR 0xFF (0b11111111) # `- Protected # [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 0x0 (0b0) # `- CODE-192KB + RAM-128KB / CODE-128KB + RAM-64KB depending on the chip # DATA: 0xFF00FF00 # [7:0] DATA0 0x0 (0b0) # [23:16] DATA1 0x0 (0b0) # WRP: 0xFFFFFFFF # `- Unprotected

To flash:

bash
wchisp flash ./path/to/firmware.{bin,hex,elf}

Again, more information can be found on the wchisp github page.

Via probe-rs

??

Need to see if this is even Useful

Creating a binary

Start with this.

https://github.com/cjacker/ch32v_evt_makefile_gcc_project_template

It provides a simple script for generating a basic project (NOTE: when I tried it, it was a broken blinky app).

Depending on your chip, this sample project will need to be changed to use an available PIN. The default is D0, which the CH32V002 does not have, so I made mine use D4. Take note of the init code that sets the pin to PP mode (push-pull).