### Example 1: Simple LED Blink Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md A basic example demonstrating how to blink an LED on a GD32 microcontroller. ```rust #![no_std] #![no_main] use gd32f1::gd32f130; use cortex_m::asm; use cortex_m_rt::entry; #[entry] fn main() -> ! { let peripherals = gd32f130::Peripherals::take().unwrap(); let gpioa = &peripherals.GPIOA; let rcu = &peripherals.RCU; // Enable GPIO clock rcu.apb2en.modify(|_, w| w.paen().enabled()); // Configure PA0 as output (push-pull, 50MHz) gpioa.ctl.write(|w| w.ctl0().output()); gpioa.omode.write(|w| w.om0().pushpull()); gpioa.ospd.write(|w| w.ospd0().bits(0b11)); // Blink loop loop { // Set pin high gpioa.bop.write(|w| w.bop0().set()); // Delay for _ in 0..1000000 { asm::nop(); } // Set pin low gpioa.bc.write(|w| w.cr0().set()); // Delay for _ in 0..1000000 { asm::nop(); } } } #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { loop { asm::wfe(); } } ``` -------------------------------- ### Installing Targets Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Commands to install necessary Rust toolchain targets for GD32 microcontrollers. ```bash rustup target add thumbv7m-none-eabi rustup target add thumbv8m.base-none-eabi rustup target add thumbv7em-none-eabihf ``` -------------------------------- ### GitHub Actions Workflow Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md An example GitHub Actions workflow for continuous integration, demonstrating how to set up the toolchain and build the project for different GD32 variants. ```yaml name: Build on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable target: thumbv7m-none-eabi - run: cargo build --features gd32f130 - run: cargo build --features gd32f150 - run: cargo build --features gd32f170 - run: cargo build --features gd32f190 ``` -------------------------------- ### _add Directive Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md YAML example demonstrating the _add directive to introduce new fields or register descriptions. ```yaml REGISTER: _add: field_name: description: "New field description" bit_range: [7:0] ``` -------------------------------- ### OpenOCD Command for STLink Debugging Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Shows the command to start OpenOCD for debugging with an ST-Link V2 debugger. ```bash openocd -f interface/stlink-v2.cfg -f target/gd32f1xx.cfg ``` -------------------------------- ### _include Section Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md Example of the `_include` section in a device YAML file for specifying the order of peripheral patch files. ```yaml _include: # Common patches for all F1x0 devices - common_patches/gd32f1x0.yaml # Specific common patches for F130/F150 - common_patches/gd32f130_150.yaml # Peripheral-specific patches - ../peripherals/adc/adc.yaml - ../peripherals/gpio/gpio.yaml - ../peripherals/i2c/i2c.yaml - ../peripherals/rcu/rcu_f1.yaml ``` -------------------------------- ### take() Method Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/peripherals.md Example demonstrating the usage of the `take()` method to obtain exclusive ownership of peripherals. ```rust use gd32f1::gd32f130; let mut peripherals = gd32f130::Peripherals::take().unwrap(); // Now you have exclusive access to all peripherals // Trying again would fail: let second_attempt = gd32f130::Peripherals::take(); // Returns None ``` -------------------------------- ### _delete Section Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md Example of the `_delete` section in a device YAML file for removing non-existent peripherals. ```yaml _delete: - DAC # No DAC in this device - USBD # No USB device interface - TIMER5 # Only has TIMER0-4 ``` -------------------------------- ### Write Method Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/registers-and-fields.md Example demonstrating how to use the `write()` method with a closure to configure and write to registers. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let gpioa = &peripherals.GPIOA; // Set field to enumerated value gpioa.ctl.write(|w| w.ctl0().output()); // Set field to raw bits gpioa.ctl.write(|w| w.ctl0().bits(0b01)); // Configure multiple fields gpioa.ctl.write(|w| w .ctl0().output() .ctl1().input() .ctl2().alternate() ); // Set entire register at once gpioa.odr.write(|w| w.bits(0xAAAA)); ``` -------------------------------- ### ADC Measurement Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Demonstrates how to configure and use the Analog-to-Digital Converter (ADC) to take measurements. ```rust #![no_std] #![no_main] use gd32f1::gd32f130; use cortex_m_rt::entry; #[entry] fn main() -> ! { let peripherals = gd32f130::Peripherals::take().unwrap(); let rcu = &peripherals.RCU; let adc = &peripherals.ADC; // Enable ADC clock rcu.apb2en.modify(|_, w| w.adc0en().enabled()); // Reset ADC rcu.apb2rst.modify(|_, w| w.adc0rst().reset()); rcu.apb2rst.modify(|_, w| w.adc0rst().clear()); // Enable ADC adc.ctl1.modify(|_, w| w.adon().enabled()); // Wait for startup for _ in 0..1000 { cortex_m::asm::nop(); } loop { // Select channel 0 adc.rsq.write(|w| w.bits(0)); // Start conversion adc.ctl1.modify(|_, w| w.swrcst().set_bit()); // Wait for result while !adc.stat.read().eoc().bit() {} // Read result (0-4095 for 12-bit ADC) let _result = adc.rdata.read().bits() & 0xFFF; // Add your processing here } } ``` -------------------------------- ### Release Build Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Create optimized binary for embedded and check its size. ```bash cargo build --release --target thumbv7m-none-eabi --features gd32f130 # Check size arm-none-eabi-size target/thumbv7m-none-eabi/release/binary ``` -------------------------------- ### Baud Rate Calculation Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Provides the formula and an example for calculating the correct baud rate divisor for USART communication, crucial for avoiding communication failures. ```rust // Baud = PCLK / (16 * USART_DIV) // USART_DIV = PCLK / (16 * Baud) // For PCLK=72MHz, Baud=115200: DIV = 72000000/(16*115200) ≈ 39 let usart_div = 72000000 / (16 * 115200); // 39 usart.baud.write(|w| w.bits(usart_div)); ``` -------------------------------- ### LED Blink Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md A complete example demonstrating how to blink an LED using GPIO and a timer on a GD32 microcontroller. ```rust use gd32f1::gd32f130; use cortex_m::asm; fn main() -> ! { let peripherals = gd32f130::Peripherals::take().unwrap(); let gpioa = &peripherals.GPIOA; let timer = &peripherals.TIMER1; let rcu = &peripherals.RCU; // Enable GPIO and TIMER clocks rcu.apb2en.modify(|_, w| w.paen().enabled()); rcu.apb1en.modify(|_, w| w.timer1en().enabled()); // Configure PA0 as output gpioa.ctl.write(|w| w.ctl0().output()); gpioa.omode.write(|w| w.om0().pushpull()); // Configure TIMER1 for 500ms overflow timer.psc.write(|w| w.bits(8000 - 1)); timer.car.write(|w| w.bits(4000 - 1)); timer.ctl0.modify(|_, w| w.cen().enabled()); // Blink LED loop { // Wait for timer overflow while !timer.intf.read().upif().bit() {} timer.intf.write(|w| w.upif().clear()); // Toggle LED gpioa.tg.write(|w| w.tg0().set()); } } ``` -------------------------------- ### Device Takes Ownership Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Illustrates a common issue where attempting to take ownership of peripherals more than once fails, and provides the correct solution of taking ownership once and sharing peripherals by reference. ```rust // This won't work: let p1 = gd32f130::Peripherals::take().unwrap(); let p2 = gd32f130::Peripherals::take().unwrap(); // Returns None ``` ```rust let peripherals = gd32f130::Peripherals::take().unwrap(); let gpioa = &peripherals.GPIOA; let usart = &peripherals.USART0; ``` -------------------------------- ### Debugging with GDB Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Set up debugging with OpenOCD and GDB. ```bash # In one terminal, start OpenOCD openocd -f interface/stlink.cfg -f target/gd32f1xx.cfg # In another terminal, start GDB arm-none-eabi-gdb target/thumbv7m-none-eabi/release/binary # In GDB: (gdb) target remote localhost:3333 (gdb) load (gdb) break main (gdb) continue (gdb) step ``` -------------------------------- ### Using cargo-embed Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Simplified debugging with cargo-embed. ```bash # Install cargo install cargo-embed # Configure Embed.toml [default.general] chip = "gd32f130" # Run with debugging cargo embed --release ``` -------------------------------- ### GPIO Input with Interrupts Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Shows how to configure a GPIO pin as an input with a pull-up resistor and set up an external interrupt to detect button presses. ```rust #![no_std] #![no_main] use gd32f1::gd32f130; use cortex_m_rt::entry; use core::sync::atomic::{AtomicBool, Ordering}; static BUTTON_PRESSED: AtomicBool = AtomicBool::new(false); #[entry] fn main() -> ! { let peripherals = gd32f130::Peripherals::take().unwrap(); let rcu = &peripherals.RCU; let gpioa = &peripherals.GPIOA; let exti = &peripherals.EXTI; let syscfg = &peripherals.SYSCFG; // Enable GPIO and EXTI clocks rcu.apb2en.modify(|_, w| w.paen().enabled().syscfgen().enabled()); rcu.apb1en.modify(|_, w| w.exti0en().enabled()); // Configure PA0 as input with pull-up gpioa.ctl.write(|w| w.ctl0().input()); gpioa.pud.write(|w| w.pud0().pullup()); // Configure EXTI for PA0 syscfg.exticfg0.write(|w| w.exti0_ss().bits(0)); // PA0 -> EXTI0 exti.inten.modify(|_, w| w.inten0().enabled()); // Enable interrupt exti.rten.modify(|_, w| w.rten0().enabled()); // Rising edge unsafe { cortex_m::interrupt::enable(); } loop { if BUTTON_PRESSED.load(Ordering::Relaxed) { BUTTON_PRESSED.store(false, Ordering::Relaxed); // Handle button press } } } #[cortex_m_rt::interrupt] fn EXTI0_1() { let exti = unsafe { &*gd32f130::EXTI::ptr() }; // Clear interrupt flag exti.pd.write(|w| w.pd0().set()); BUTTON_PRESSED.store(true, Ordering::Relaxed); } ``` -------------------------------- ### _delete Directive Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md YAML example showing how to use the _delete directive to remove specific fields from a register. ```yaml TIMER0: SMCFG: _delete: - SCM1 # Remove this field - BRKG # Remove this field ``` -------------------------------- ### Field Value Format Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md YAML example demonstrating the format for single-bit and multi-bit fields, including a note about a skipped value. ```yaml # Single-bit fields CTL: "CTL*": Input: [0, "Input mode"] Output: [1, "Output mode"] # Multi-bit fields OSPD: "OSPD*": Speed2M: [0, "Max 2 MHz"] Speed10M: [1, "Max 10 MHz"] Speed50M: [3, "Max 50 MHz"] # Note: 2 is skipped ``` -------------------------------- ### Documentation Build Configuration Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Example Cargo.toml metadata configuration for docs.rs builds. ```toml [package.metadata.docs.rs] features = ["rt", "gd32f130", "gd32f190"] # Representative devices default-target = "thumbv7m-none-eabi" targets = [] ``` -------------------------------- ### Read Method Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/registers-and-fields.md Example demonstrating how to use the `read()` method to access register values and individual fields. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let gpioa = &peripherals.GPIOA; // Read the entire register value as raw bits let full_value = gpioa.istat.read().bits(); // Read specific field with enumerated values let pin0_is_high = gpioa.istat.read().istat0().bit(); // Read multiple fields let read_proxy = gpioa.ctl.read(); let ctl0_value = read_proxy.ctl0().bits(); let ctl1_value = read_proxy.ctl1().bits(); ``` -------------------------------- ### Building for Target Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Example command to build a project for a specific GD32 target and feature. ```bash cargo build --target thumbv7m-none-eabi --features gd32f130 ``` -------------------------------- ### Parallel Builds Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Example commands for running build targets in parallel using make. ```bash # Use 16 parallel jobs make -j16 form make -j12 check ``` -------------------------------- ### Minimal project setup Cargo.toml Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md A minimal Cargo.toml template for a GD32F1 project. ```toml [package] name = "gd32f1-project" version = "0.1.0" edition = "2021" [dependencies] gd32f1 = { version = "0.9.1", features = ["gd32f130", "rt", "critical-section"] } cortex-m = "0.7.7" cortex-m-rt = "0.7.3" vcell = "0.1.3" [profile.release] opt-level = "z" lto = true ``` -------------------------------- ### USART Communication Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Demonstrates how to set up and use USART for serial communication, including writing and reading bytes and strings. ```rust #![no_std] #![no_main] use gd32f1::gd32f130; use cortex_m_rt::entry; struct Uart { usart: gd32f130::USART0, } impl Uart { fn new(usart: gd32f130::USART0, rcu: &gd32f130::RCU) -> Self { // Enable USART clock rcu.apb2en.modify(|_, w| w.usart0en().enabled()); // Configure baud rate (115200 @ 8MHz) usart.baud.write(|w| w.bits(52)); // Enable USART usart.ctl0.write(|w| w .uen().enabled() .ten().enabled() .ren().enabled() ); Uart { usart } } fn write_byte(&mut self, byte: u8) { while !self.usart.stat.read().tbe().bit() {} self.usart.data.write(|w| w.bits(byte as u32)); } fn write_str(&mut self, s: &str) { for byte in s.bytes() { self.write_byte(byte); } } fn read_byte(&mut self) -> u8 { while !self.usart.stat.read().rbne().bit() {} (self.usart.data.read().bits() & 0xFF) as u8 } } #[entry] fn main() -> ! { let peripherals = gd32f130::Peripherals::take().unwrap(); let rcu = &peripherals.RCU; let mut uart = Uart::new(peripherals.USART0, rcu); uart.write_str("Hello, GD32!\r\n"); loop { let byte = uart.read_byte(); uart.write_byte(byte); // Echo received byte } } ``` -------------------------------- ### Example: Reading Fields Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/registers-and-fields.md Practical example showing how to use the read proxy to extract specific field values and check enumerated types. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let gpioa = &peripherals.GPIOA; let read = gpioa.ctl.read(); // Single-bit field let is_enabled = read.ctl0().bit(); // Returns bool // Multi-bit field as raw value let raw_value = read.ctl0().bits(); // Returns u32 // Check enumerated field let mode = read.ctl0(); // Returns field proxy if mode == gpioa::ctl::CTL0_A::Input { // Pin is in input mode } // Get entire register let all_bits = gpioa.ctl.read().bits(); ``` -------------------------------- ### Target Architecture Installation Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/device-families.md Bash commands to install Rust toolchains for different GD32 device families. ```bash # For GD32C1, GD32E1, GD32F1, GD32F2 rustup target add thumbv7m-none-eabi # For GD32E2 rustup target add thumbv8m.base-none-eabi # For GD32E5 rustup target add thumbv8m.main-none-eabi # For GD32F3 rustup target add thumbv7em-none-eabihf ``` -------------------------------- ### Device YAML Example Structure Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md Example structure of a device YAML file, including copyright, SVD base, modifications, deletions, and included peripheral patches. ```yaml # Copyright header (required) # SPDX-License-Identifier: MIT OR Apache-2.0 # Base SVD file to patch _svd: ../svd/gd32f130.svd # Modify device-level properties _modify: name: "GD32F130" # Delete peripherals not present in this device _delete: - DAC - USBD # Include peripheral patch files _include: - common_patches/gd32f1x0.yaml - common_patches/gd32f130_150.yaml - ../peripherals/adc/adc.yaml - ../peripherals/gpio/gpio.yaml # ... more peripheral patches ``` -------------------------------- ### _modify Directive Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md YAML examples demonstrating the use of the _modify directive to rename registers and fields. ```yaml FMC: STAT: _modify: END: name: "ENDF" # Rename END to ENDF description: "End flag" DMA: "CH*CTL": _modify: TM: name: "DIR" # Rename TM to DIR TAEIE: name: "ERRIE" # Rename TAEIE to ERRIE ``` -------------------------------- ### External Tool Installation Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md Installs necessary external tools for SVD file patching, Rust code generation, and code formatting. ```bash pip install svdtools cargo install svd2rust@0.32.0 cargo install form rustup component add rustfmt ``` -------------------------------- ### gd32c1 crate dependency example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Example of how to add the gd32c1 crate to your Cargo.toml with specific device and runtime features enabled. ```toml [dependencies.gd32c1] version = "0.9.1" features = ["gd32c103", "rt"] ``` -------------------------------- ### Read-Only and Write-Only Fields Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md YAML example illustrating how to define read-only (_read) and write-only (_write) fields within registers. ```yaml INT: "IF*": _read: NotInterrupted: [0, "No interrupt generated"] Interrupted: [1, "Interrupt generated"] "IC*": _write: Clear: [1, "Clear interrupt flag"] ``` -------------------------------- ### _modify Section Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md Example of the `_modify` section in a device YAML file for modifying device-level metadata. ```yaml _modify: name: "GD32F130" # Official device name description: "GD32F130 microcontroller" version: "1.0" ``` -------------------------------- ### Example: Writing Fields Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/registers-and-fields.md A comprehensive example demonstrating various ways to write to registers and fields, including single bit, enumerated fields, chained writes, raw values, and conditional writes. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let gpioa = &peripherals.GPIOA; // Write single bit field gpioa.odr.write(|w| w.odr0().set_bit()); // Write enumerated field gpioa.ctl.write(|w| w.ctl0().output()); // Chain multiple field writes gpioa.ctl.write(|w| w .ctl0().output() .ctl1().input() .ctl2().alternate() ); // Write raw value gpioa.ospd.write(|w| w.ospd0().bits(0b11)); // Set entire register gpioa.odr.write(|w| w.bits(0xFFFF)); // Using if-let with enumerated fields gpioa.ctl.write(|w| { w.ctl0().output(); if condition { w.ctl1().input() } else { w.ctl1().alternate() } }); ``` -------------------------------- ### Peripheral Patch File Example Structure Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md Example structure of a peripheral patch file, showing how to add enumerated values and field descriptions to register definitions. ```yaml # Copyright header # SPDX-License-Identifier: MIT OR Apache-2.0 # Peripheral patterns (globbing supported with *) "GPIO*": # Register name CTL: # Field name pattern "CTL*": # Enumeration values Input: [0, "Input mode (reset state)"] Output: [1, "General purpose output mode"] Alternate: [2, "Alternate function mode"] Analog: [3, "Analog mode"] ``` -------------------------------- ### Printf Debugging Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Using semihosting for debug output. ```rust use cortex_m_semihosting::println; fn main() { println!("Hello from GD32!"); let peripherals = gd32f130::Peripherals::take().unwrap(); println!("Peripherals initialized"); } ``` ```toml cortex-m-semihosting = "0.3" ``` -------------------------------- ### Build Without Runtime Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Test crate compilation without the cortex-m-rt feature. ```bash cargo build --features gd32f130 # Omit rt feature ``` -------------------------------- ### Feature Testing Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Test crate builds with different features enabled. ```bash # Test default build (no features) cargo test --lib # Test with rt feature cargo test --lib --features rt # Test with specific device cargo test --lib --features gd32f190 ``` -------------------------------- ### Checking Crates Compile Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Verify all device crates compile without errors. ```bash cd gd32f1 cargo build --features gd32f130 cargo build --features gd32f150 cargo build --features gd32f170 cargo build --features gd32f190 ``` ```bash cargo build --features gd32f130 cargo build --features gd32f150 cargo build --features gd32f170 cargo build --features gd32f190 ``` -------------------------------- ### lib.rs Generation Structure Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Example structure of an auto-generated lib.rs file for a GD32 crate. ```rust //! Peripheral access API for GD32F1 microcontrollers //! (generated using [svd2rust](https://github.com/rust-embedded/svd2rust) 0.32.0) //! //! For more details see the README here: //! [gd32-rs](https://github.com/gd32-rust/gd32-rs) #![allow(non_camel_case_types)] #![no_std] mod generic; pub use self::generic::*; #[cfg(feature = "gd32f130")] pub mod gd32f130; #[cfg(feature = "gd32f150")] pub mod gd32f150; // ... additional devices ``` -------------------------------- ### Interrupt Deadlocks Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Explains how interrupt deadlocks can occur and the solution, which is to ensure the interrupt flag is cleared as the first step within the interrupt handler. ```rust #[interrupt] fn MY_INTERRUPT() { let peripheral = unsafe { &*PERIPHERAL::ptr() }; // Clear interrupt flag FIRST peripheral.register.write(|w| w.flag().clear()); // Then handle interrupt } ``` -------------------------------- ### Timer with Interrupt Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md This Rust code demonstrates setting up a timer to generate interrupts at a 1kHz frequency (1ms interval) on a GD32 microcontroller. It uses atomic operations for a shared counter updated within the interrupt handler. ```rust #![no_std] #![no_main] use gd32f1::gd32f130; use cortex_m_rt::entry; use core::sync::atomic::{AtomicUsize, Ordering}; static TIMER_COUNTER: AtomicUsize = AtomicUsize::new(0); #[entry] fn main() -> ! { let peripherals = gd32f130::Peripherals::take().unwrap(); let rcu = &peripherals.RCU; let timer = &peripherals.TIMER1; // Enable TIMER1 clock rcu.apb1en.modify(|_, w| w.timer1en().enabled()); // Reset TIMER1 rcu.apb1rst.modify(|_, w| w.timer1rst().reset()); rcu.apb1rst.modify(|_, w| w.timer1rst().clear()); // Configure for 1kHz (1ms) interrupt // Assuming 72MHz APB1 clock timer.psc.write(|w| w.bits(72000 - 1)); // Divide by 72000 timer.car.write(|w| w.bits(1 - 1)); // Count to 1 // Enable update interrupt timer.dmainten.modify(|_, w| w.upie().enabled()); // Enable timer timer.ctl0.modify(|_, w| w.cen().enabled()); unsafe { cortex_m::interrupt::enable(); } loop { let count = TIMER_COUNTER.load(Ordering::Relaxed); // Use count for timing-dependent operations if count % 1000 == 0 { // Every 1 second } } } #[cortex_m_rt::interrupt] fn TIMER1() { let timer = unsafe { &*gd32f130::TIMER1::ptr() }; // Clear interrupt flag timer.intf.write(|w| w.upif().clear()); TIMER_COUNTER.fetch_add(1, Ordering::Relaxed); } ``` -------------------------------- ### Unstable Register Access Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Demonstrates the problem of unstable register access due to stale values and shows the correct approach using the `modify()` method for atomic read-modify-write operations. ```rust // Wrong: reads stale value let current = register.read().bits(); register.write(|w| w.bits(current | 0x01)); // Right: atomic operation register.modify(|r, w| w.bits(r.bits() | 0x01)); ``` -------------------------------- ### Integration Testing Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Test peripheral access during integration testing. ```rust #[test] fn test_blink_initialization() { let peripherals = gd32f130::Peripherals::take().unwrap(); // Verify we can access peripherals let _gpio = &peripherals.GPIOA; let _timer = &peripherals.TIMER0; } ``` -------------------------------- ### Timer Configuration Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example of configuring a general-purpose timer for a specific overflow period. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let timer = &peripherals.TIMER0; let rcu = &peripherals.RCU; // Enable TIMER0 clock rcu.apb1en.modify(|_, w| w.timer0en().enabled()); // Reset TIMER0 rcu.apb1rst.modify(|_, w| w.timer0rst().reset()); rcu.apb1rst.modify(|_, w| w.timer0rst().clear()); // Configure timer for 1ms overflow at 8MHz clock // PSC = 8000 - 1 (divide by 8000 -> 1kHz) // ARR = 1000 - 1 (count to 1000 -> 1ms period) timer.psc.write(|w| w.bits(8000 - 1)); timer.car.write(|w| w.bits(1000 - 1)); // Enable timer timer.ctl0.modify(|_, w| w.cen().enabled()); ``` -------------------------------- ### I2C Configuration Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example code for configuring I2C0 for 100kHz standard mode. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let i2c = &peripherals.I2C0; let rcu = &peripherals.RCU; // Enable I2C0 clock rcu.apb1en.modify(|_, w| w.i2c0en().enabled()); // Configure I2C // For 100kHz standard mode with 8MHz APB clock: i2c.ckcfg.write(|w| w.bits(0x0020)); // Simplified example // Configure timing (address setup, hold time, etc.) i2c.rt.write(|w| w.bits(0x0F)); // Rise/fall time configuration // Enable I2C i2c.ctl0.write(|w| w.i2cen().enabled()); ``` -------------------------------- ### SPI Configuration Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example code for configuring SPI0 as a master in mode 0. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let spi = &peripherals.SPI0; let rcu = &peripherals.RCU; // Enable SPI0 clock rcu.apb2en.modify(|_, w| w.spi0en().enabled()); // Configure SPI as master, mode 0 (CPOL=0, CPHA=0) spi.ctl0.write(|w| w .mstr().enabled() // Master mode .psc().bits(0b010) // Clock prescaler (APB2 / 4) .cpol().idlelow() // CPOL=0 .cpha().firstclkedge() // CPHA=0 .lsb().msbfirst() // MSB first .swnss().enabled() // Software NSS ); // Enable SPI spi.ctl0.modify(|_, w| w.spien().enabled()); ``` -------------------------------- ### Device Feature Not Selected Error Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Example of a common configuration issue and its solution. ```toml features = ["gd32f130"] # Required ``` -------------------------------- ### Peripheral Clock Enable Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example of enabling clocks for GPIO and other peripherals. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let rcu = &peripherals.RCU; // Enable GPIO clocks rcu.apb2en.modify(|_, w| w .paen().enabled() .pben().enabled() .pcen().enabled() ); // Enable peripheral clocks rcu.apb1en.modify(|_, w| w .i2c0en().enabled() .usart1en().enabled() ); rcu.apb2en.modify(|_, w| w .usart0en().enabled() .spi0en().enabled() ); ``` -------------------------------- ### makecrates.py Configuration Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md Python configuration variables used by the makecrates.py script. ```python VERSION = "0.9.1" SVD2RUST_VERSION = "0.32.0" CRATE_DOC_FEATURES = { "gd32f1": ["rt", "gd32f130", "gd32f190"], # Devices to document } CRATE_DOC_TARGETS = { "gd32f1": "thumbv7m-none-eabi", # Documentation target } ``` -------------------------------- ### ADC Configuration Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example code for configuring ADC0 for single conversion on channel 0. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let adc = &peripherals.ADC; let rcu = &peripherals.RCU; // Enable ADC clock rcu.apb2en.modify(|_, w| w.adc0en().enabled()); // Reset ADC rcu.apb2rst.modify(|_, w| w.adc0rst().reset()); rcu.apb2rst.modify(|_, w| w.adc0rst().clear()); // Configure ADC // Select channel 0 for single conversion adc.rsq.write(|w| w.bits(0)); // Channel 0 in regular sequence // Set sample time for channel 0 adc.sampt.write(|w| w.bits(0)); // 12.5 cycles sample time // Enable ADC adc.ctl1.modify(|_, w| w.adon().enabled()); // Wait for ADC to stabilize for _ in 0..100 { } ``` -------------------------------- ### Analog Input (ADC) Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/README.md Code examples for ADC operations including selecting a channel, starting conversion, and reading the result. ```rust // Select channel and start conversion adc.rsq.write(|w| w.bits(0)); adc.ctl1.modify(|_, w| w.swrcst().set_bit()); // Wait and read result while !adc.stat.read().eoc().bit() {} let result = adc.rdata.read().bits() as u16; ``` -------------------------------- ### QEMU Emulation Command Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Provides the command to build a release binary and run it on the GD32 emulator using QEMU. ```bash cargo build --release qemu-system-arm -machine gd32f1xx -kernel target/thumb.../release/binary ``` -------------------------------- ### PWM Output Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example of configuring a timer channel for PWM output and setting the duty cycle. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let timer = &peripherals.TIMER0; let rcu = &peripherals.RCU; // ... configure as above ... // Configure channel 0 for PWM mode 1 timer.chctl0.write(|w| w.ch0ms().bits(0b01) // Channel 0 output mode .ch0comctl().bits(0b110) // PWM mode 1 ); // Enable channel 0 output timer.chctl2.modify(|_, w| w.ch0en().enabled()); // Set initial duty cycle (50%) timer.ch0cv.write(|w| w.bits(500)); // 50% of 1000 // Update duty cycle timer.ch0cv.write(|w| w.bits(750)); // 75% duty cycle ``` -------------------------------- ### Clock Source Selection Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example of selecting the system clock source and waiting for the switch to complete. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let rcu = &peripherals.RCU; // Select clock source rcu.cfg0.modify(|_, w| w.scs().bits(0)); // HSI (internal oscillator) // or w.scs().bits(1); // HXTAL (external oscillator) // or w.scs().bits(2); // PLL // Wait for clock switch complete while rcu.cfg0.read().scss().bits() != rcu.cfg0.read().scs().bits() {} ``` -------------------------------- ### Power Mode Selection Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example of entering sleep mode and configuring for deeper power saving. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let pmu = &peripherals.PMU; // Enable sleep mode cortex_m::asm::wfe(); // Wait for event // Or configure for deeper power saving pmu.ctl.modify(|_, w| w.ldolp().lowpower()); cortex_m::asm::wfe(); // Sleep // Exit power saving mode (via interrupt) ``` -------------------------------- ### Register Access Testing Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Compile-time test to verify register existence and method availability. ```rust #[cfg(test)] mod tests { use gd32f1::gd32f130; #[test] fn test_gpio_register_exists() { // Compile-time test: this code must compile // References GPIO type let _gpio_type = std::any::type_name::(); } #[test] fn test_register_method_exists() { // Verify register has expected method // This is compile-time verification let _method = gd32f130::gpioa::RegisterBlock::istat; } } ``` -------------------------------- ### RCU Enumeration Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/types.md Example of a generated Rust enum for RCU settings from SVD YAML, and how to access it. ```rust // In peripheral YAML: IRC14MEN: ["Off": 0, "On": 1] pub enum IRC14MEN_A { Off = 0, On = 1, } // Accessed as: rcu.ctl1.write(|w| w.irc14men().on()); ``` -------------------------------- ### GPIO Enumeration Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/types.md Example of a generated Rust enum for GPIO control from SVD YAML, and how to access it. ```rust // In peripheral YAML: CTL: [0, "Input mode"] pub enum CTL_A { Input = 0, } // Accessed as: gpio.ctl.write(|w| w.ctl0().input()); ``` -------------------------------- ### Modify Method Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/registers-and-fields.md Example demonstrating the `modify()` method for atomic read-modify-write operations on registers. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let gpioa = &peripherals.GPIOA; // Toggle bit 0 without affecting other bits gpioa.odr.modify(|r, w| { let current = r.bits(); w.bits(current ^ 0x0001) }); // Change one field, leave others unchanged gpioa.ctl.modify(|_, w| w.ctl0().output()); // More complex modification gpioa.ospd.modify(|r, w| { if r.ospd0().bits() == 0 { w.ospd0().bits(0b11) // Set to 50MHz if currently at 2MHz } else { w // Leave unchanged } }); ``` -------------------------------- ### ST-Flash Command for Real Hardware Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/testing-and-examples.md Provides the command to flash a binary file onto real hardware using `st-flash`. ```bash st-flash write binary_file.bin 0x08000000 ``` -------------------------------- ### HTML Documentation Generation Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/build-system.md Generates interactive HTML register references from device YAML files. ```bash python3 scripts/makehtml.py devices/gd32f130.yaml > gd32f130.html ``` -------------------------------- ### Bare metal with runtime support feature combination Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Example of a typical feature combination for a bare metal build with runtime support. ```toml features = ["gd32f130", "rt", "critical-section"] ``` -------------------------------- ### Build System Commands Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Makefile targets for the GD32 Rust build pipeline. ```bash # Extract SVD files from vendor archives make patch # Run svd2rust on patched SVDs make svd2rust # Format generated code make form # Check compilation of all crates make check # Clean build artifacts make clean-rs make clean-patch make clean-svd make clean-html ``` -------------------------------- ### Setting the Target Architecture Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md This snippet shows how to add the correct target architecture for compilation and then build the project with that target. ```bash rustup target add thumbv7m-none-eabi cargo build --target thumbv7m-none-eabi ``` -------------------------------- ### Releasing New Versions Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Commands to publish new versions of GD32 Rust crates. ```bash python3 scripts/makecrates.py devices/ -y cargo publish -p gd32f1 --allow-dirty cargo publish -p gd32e1 --allow-dirty # ... publish each crate ``` -------------------------------- ### Testing Changes Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Commands to build and test changes for a specific GD32 device. ```bash cd gd32f1 cargo build --features gd32f130 cargo test --features gd32f130 ``` -------------------------------- ### Timer Interrupt Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example of enabling timer update interrupts. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let timer = &peripherals.TIMER0; // Enable update interrupt timer.dmainten.modify(|_, w| w.upie().enabled()); // In interrupt handler, clear interrupt flag: // timer.intf.write(|w| w.upif().clear()); ``` -------------------------------- ### build.rs script with rt feature Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Example build.rs script that conditionally copies the device linker script when the 'rt' feature is enabled. ```rust fn main() { if env::var_os("CARGO_FEATURE_RT").is_some() { let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); let device_file = match env::var_os("CARGO_FEATURE_...") { Some(_) => "src/gd32fXXX/device.x", None => panic!("No device feature selected"), }; fs::copy(device_file, out.join("device.x")).unwrap(); } } ``` -------------------------------- ### ADC Conversion Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example of reading a value from an ADC channel. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let adc = &peripherals.ADC; fn adc_read_channel(adc: &gd32f130::adc0::RegisterBlock, channel: u8) -> u16 { // Select channel adc.rsq.write(|w| w.bits(channel as u32)); // Start conversion adc.ctl1.modify(|_, w| w.swrcst().set_bit()); // Wait for conversion complete while !adc.stat.read().eoc().bit() {} // Read result (adc.rdata.read().bits() & 0xFFFF) as u16 } let adc_value = adc_read_channel(&peripherals.ADC, 0); ``` -------------------------------- ### Interrupt/Status Fields Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/types.md Examples of enumerated types for interrupt and status fields. ```rust pub enum STATUS_A { NotActive = 0, Active = 1, } pub enum INTERRUPT_A { NotInterrupted = 0, Interrupted = 1, } pub enum CLEARABLE_A { Clear = 1, // Write 1 to clear (W1C pattern) } ``` -------------------------------- ### Basic Write Example Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/peripherals.md Shows how to write to registers using enumerated values, raw bits, and writing the entire register with a raw value. ```rust // Write with enumerated values gpioa.ctl.write(|w| w.ctl0().output().ctl1().input()); // Write with raw bits gpioa.ctl.write(|w| w.ctl0().bits(0b01).ctl1().bits(0b00)); // Write entire register with raw value gpioa.odr.write(|w| w.bits(0xFFFF)); ``` -------------------------------- ### Oscillator Control Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example of enabling and waiting for stabilization of internal and external oscillators. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let rcu = &peripherals.RCU; // Enable external oscillator (if available) rcu.ctl.modify(|_, w| w.hxtalen().on()); // Wait for oscillator stabilization while !rcu.ctl.read().hxtalstb().bit() {} // Enable internal oscillator rcu.ctl.modify(|_, w| w.irc8men().on()); // Wait for internal oscillator stabilization while !rcu.ctl.read().irc8mstb().bit() {} ``` -------------------------------- ### With only critical section (no runtime) feature combination Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Example of a feature combination with only critical section support, excluding runtime. ```toml features = ["gd32f130", "critical-section"] ``` -------------------------------- ### Minimal build (register access only) feature combination Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/configuration.md Example of a minimal feature combination for register access only. ```toml features = ["gd32f130"] ``` -------------------------------- ### Receiving Data from USART Source: https://github.com/gd32-rust/gd32-rs/blob/main/_autodocs/api-reference/common-peripherals.md Example code for receiving a single byte from USART. ```rust use gd32f1::gd32f130; let peripherals = gd32f130::Peripherals::take().unwrap(); let usart = &peripherals.USART0; fn receive_byte(usart: &gd32f130::usart0::RegisterBlock) -> u8 { // Wait for receive not empty while !usart.stat.read().rbne().bit() {} // Read byte (usart.data.read().bits() & 0xFF) as u8 } let byte = receive_byte(&peripherals.USART0); ```