### SPI Peripheral Initialization and Transfer in Rust Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt Initializes and configures the SPI0 peripheral for master mode communication. It sets up clock polarity, phase, data frame format, and clock divider. Includes a function for transferring a single byte and examples for selecting/deselecting a slave and checking status. ```rust use gd32vf103_pac::Peripherals; let dp = Peripherals::take().unwrap(); let spi0 = dp.SPI0; let rcu = dp.RCU; // Enable SPI0 clock rcu.apb2en.modify(|_, w| w.spi0en().set_bit()); // Configure SPI: Master mode, 8-bit, CPOL=0, CPHA=0, MSB first spi0.ctl0.write(|w| { w.mstmod().set_bit() // Master mode .ckpl().clear_bit() // Clock polarity low .ckph().clear_bit() // Clock phase: first edge .ff16().clear_bit() // 8-bit data frame .lf().clear_bit() // MSB first .swnssen().set_bit() // Software NSS management .swnss().set_bit() // NSS high (not selected) }); // Configure clock divider: fPCLK/8 spi0.ctl0.modify(|_, w| unsafe { w.psc().bits(0b010) }); // Enable SPI spi0.ctl0.modify(|_, w| w.spien().set_bit()); // Transfer a byte fn spi_transfer(spi: &gd32vf103_pac::spi0::RegisterBlock, byte: u8) -> u8 { // Wait for TX buffer empty while spi.stat.read().tbe().bit_is_clear() {} // Write data spi.data.write(|w| unsafe { w.data().bits(byte as u16) }); // Wait for RX buffer not empty while spi.stat.read().rbne().bit_is_clear() {} // Read received data spi.data.read().data().bits() as u8 } // Select slave (active low) spi0.ctl0.modify(|_, w| w.swnss().clear_bit()); // Transfer data let received = spi_transfer(&spi0, 0x55); // Deselect slave spi0.ctl0.modify(|_, w| w.swnss().set_bit()); // Check status let stat = spi0.stat.read(); let busy = stat.trans().bit_is_set(); let overrun = stat.rxorerr().bit_is_set(); ``` -------------------------------- ### Configure and Use TIMER1 for PWM and Interrupts in Rust Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt This snippet demonstrates how to initialize and configure TIMER1 on the GD32VF103 for PWM generation and interrupt handling. It covers clock enabling, prescaler and auto-reload value setup, PWM mode configuration, duty cycle setting, and enabling the counter and interrupts. It also shows how to read the counter and clear interrupt flags. ```rust use gd32vf103_pac::Peripherals; let dp = Peripherals::take().unwrap(); let timer1 = dp.TIMER1; let rcu = dp.RCU; // Enable TIMER1 clock rcu.apb1en.modify(|_, w| w.timer1en().set_bit()); // Configure prescaler: 72MHz / 7200 = 10kHz timer clock timer1.psc.write(|w| w.psc().bits(7199)); // Configure auto-reload value: 10kHz / 1000 = 10Hz (100ms period) timer1.car.write(|w| w.car().bits(999)); // Configure PWM mode on channel 0 timer1.chctl0_output().modify(|_, w| unsafe { w.ch0comctl().bits(0b110) // PWM mode 1 .ch0comsen().set_bit() // Output compare shadow enable }); // Set PWM duty cycle (50%) timer1.ch0cv.write(|w| w.ch0val().bits(500)); // Enable channel 0 output timer1.chctl2.modify(|_, w| w.ch0en().set_bit()); // Enable auto-reload preload timer1.ctl0.modify(|_, w| w.arse().set_bit()); // Generate update event to load prescaler timer1.swevg.write(|w| w.upg().set_bit()); // Enable counter timer1.ctl0.modify(|_, w| w.cen().set_bit()); // Read current counter value let count = timer1.cnt.read().cnt().bits(); // Enable timer interrupt timer1.dmainten.modify(|_, w| w.upie().set_bit()); // Check and clear interrupt flag if timer1.intf.read().upif().bit_is_set() { timer1.intf.modify(|_, w| w.upif().clear_bit()); // Handle timer overflow } ``` -------------------------------- ### Read ECLIC Configuration in Rust with gd32vf103-pac Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt This Rust code snippet shows how to access the Enhanced Core Local Interrupt Controller (ECLIC) using the gd32vf103-pac crate. It demonstrates reading the general ECLIC configuration registers (`cliccfg`, `clicinfo`) and accessing the configuration array for individual interrupt sources (`clicints`). Note that the specific register access for enabling interrupts and setting priorities depends on the interrupt number and is simplified in this example. ```rust use gd32vf103_pac::Peripherals; let dp = Peripherals::take().unwrap(); let eclic = dp.ECLIC; // Read ECLIC configuration let cliccfg = eclic.cliccfg.read().bits(); let clicinfo = eclic.clicinfo.read().bits(); // Configure interrupt source (e.g., interrupt 47 = TIMER1) // Access individual interrupt configuration let int_cfg = &eclic.clicints; // Enable interrupt, set level/priority // Note: Specific register access depends on interrupt number // This is a simplified example showing the pattern // ECLIC provides 4 bits of priority (NVIC_PRIO_BITS = 4) // Configure through the clicints array for each interrupt source ``` -------------------------------- ### Safely Acquire All Peripherals with Peripherals::take() Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt Demonstrates the safe, singleton acquisition of all device peripherals using `Peripherals::take()`. This method ensures that peripherals are accessed only once, preventing data races. It requires the `critical-section` feature to be enabled. ```rust #![no_std] #![no_main] use gd32vf103_pac::Peripherals; fn main() -> ! { // Safely take ownership of all peripherals (requires critical-section feature) let dp = Peripherals::take().unwrap(); // Access individual peripherals let gpioa = dp.GPIOA; let rcu = dp.RCU; let usart0 = dp.USART0; // Peripherals can only be taken once - subsequent calls return None assert!(Peripherals::take().is_none()); loop {} } ``` -------------------------------- ### Configure and Use ADC0 for Conversion and Watchdog in Rust Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt This snippet illustrates the configuration of ADC0 on the GD32VF103 for analog-to-digital conversion and watchdog functionality. It includes steps for enabling the ADC clock, setting the clock prescaler, powering on the ADC, calibration, configuring sampling time, setting up the conversion sequence, triggering a software conversion, and reading the result. It also covers setting watchdog thresholds and enabling related interrupts. ```rust use gd32vf103_pac::Peripherals; let dp = Peripherals::take().unwrap(); let adc0 = dp.ADC0; let rcu = dp.RCU; // Enable ADC0 clock rcu.apb2en.modify(|_, w| w.adc0en().set_bit()); // Configure ADC clock prescaler (max 14MHz for ADC) // APB2 = 72MHz, prescaler /6 = 12MHz rcu.cfg0.modify(|_, w| unsafe { w.adcpsc().bits(0b10) }); // Power on ADC adc0.ctl1.modify(|_, w| w.adcon().set_bit()); // Wait for ADC to stabilize (tSTAB) for _ in 0..1000 { core::hint::spin_loop(); } // Calibrate ADC adc0.ctl1.modify(|_, w| w.rstclb().set_bit()); while adc0.ctl1.read().rstclb().bit_is_set() {} adc0.ctl1.modify(|_, w| w.clb().set_bit()); while adc0.ctl1.read().clb().bit_is_set() {} // Configure sample time for channel 0 (55.5 cycles) adc0.sampt1.modify(|_, w| unsafe { w.spt0().bits(0b101) }); // Configure regular channel sequence: 1 conversion, channel 0 adc0.rsq2.modify(|_, w| unsafe { w.rsq0().bits(0) }); // First conversion: channel 0 adc0.rsq0.modify(|_, w| unsafe { w.rl().bits(0) }); // Sequence length: 1 // Enable software trigger adc0.ctl1.modify(|_, w| w.etsrc().set_bit()); // Software trigger for regular group // Start conversion adc0.ctl1.modify(|_, w| w.swrcst().set_bit()); // Wait for end of conversion while adc0.stat.read().eoc().bit_is_clear() {} // Read result let adc_value = adc0.rdata.read().rdata().bits(); // Clear EOC flag adc0.stat.modify(|_, w| w.eoc().clear_bit()); // Configure watchdog thresholds adc0.wdht.write(|w| unsafe { w.wdht().bits(3000) }); // High threshold adc0.wdlt.write(|w| unsafe { w.wdlt().bits(1000) }); // Low threshold // Enable watchdog on channel 0 adc0.ctl0.modify(|_, w| unsafe { w.wdchsel().bits(0) // Monitor channel 0 .rwden().set_bit() // Enable on regular channels .wdsc().set_bit() // Single channel mode }); // Enable interrupts adc0.ctl0.modify(|_, w| { w.eocie().set_bit() // End of conversion interrupt .wdeie().set_bit() // Watchdog interrupt }); ``` -------------------------------- ### I2C Peripheral Initialization and Transfer in Rust Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt Initializes and configures the I2C0 peripheral for master mode communication. It enables clocks, resets the peripheral, and sets up clock control, rise time, and enables the I2C interface. Includes helper functions for generating start/stop conditions, sending addresses, writing data, and reading data. ```rust use gd32vf103_pac::Peripherals; let dp = Peripherals::take().unwrap(); let i2c0 = dp.I2C0; let rcu = dp.RCU; // Enable I2C0 clock rcu.apb1en.modify(|_, w| w.i2c0en().set_bit()); // Reset I2C rcu.apb1rst.modify(|_, w| w.i2c0rst().set_bit()); rcu.apb1rst.modify(|_, w| w.i2c0rst().clear_bit()); // Configure I2C clock (assuming 36MHz APB1) // For 100kHz: CLKC = fAPB1 / (2 * 100kHz) = 180 i2c0.ckcfg.write(|w| unsafe { w.clkc().bits(180) // Clock control .fast().clear_bit() // Standard mode .dtcy().clear_bit() // Duty cycle 2:1 }); // Set rise time: (1000ns / tPCLK1) + 1 = (1000ns * 36MHz) + 1 = 37 i2c0.rt.write(|w| w.risetime().bits(37)); // Enable I2C i2c0.ctl0.modify(|_, w| w.i2cen().set_bit()); // Generate start condition fn i2c_start(i2c: &gd32vf103_pac::i2c0::RegisterBlock) { i2c.ctl0.modify(|_, w| w.start().set_bit()); while i2c.stat0.read().sbsend().bit_is_clear() {} } // Send address fn i2c_send_addr(i2c: &gd32vf103_pac::i2c0::RegisterBlock, addr: u8, read: bool) { let addr_byte = (addr << 1) | if read { 1 } else { 0 }; i2c.data.write(|w| w.trb().bits(addr_byte)); while i2c.stat0.read().addsend().bit_is_clear() {} // Clear ADDSEND by reading STAT0 then STAT1 let _ = i2c.stat0.read(); let _ = i2c.stat1.read(); } // Write data fn i2c_write(i2c: &gd32vf103_pac::i2c0::RegisterBlock, data: u8) { while i2c.stat0.read().tbe().bit_is_clear() {} i2c.data.write(|w| w.trb().bits(data)); while i2c.stat0.read().btc().bit_is_clear() {} } // Read data fn i2c_read(i2c: &gd32vf103_pac::i2c0::RegisterBlock) -> u8 { while i2c.stat0.read().rbne().bit_is_clear() {} i2c.data.read().trb().bits() } // Generate stop condition fn i2c_stop(i2c: &gd32vf103_pac::i2c0::RegisterBlock) { i2c.ctl0.modify(|_, w| w.stop().set_bit()); } // Example: Write to device at address 0x50 i2c_start(&i2c0); i2c_send_addr(&i2c0, 0x50, false); i2c_write(&i2c0, 0x00); // Register address i2c_write(&i2c0, 0x55); // Data i2c_stop(&i2c0); ``` -------------------------------- ### Configure DMA Memory-to-Memory Transfer in Rust Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt This snippet demonstrates configuring DMA channel 0 for memory-to-memory transfers using the gd32vf103-pac crate. It covers enabling the DMA clock, setting source and destination addresses, transfer count, and configuring transfer parameters like mode, priority, data width, and address increment. It also shows how to check transfer status and clear interrupt flags. ```rust use gd32vf103_pac::Peripherals; let dp = Peripherals::take().unwrap(); let dma0 = dp.DMA0; let rcu = dp.RCU; // Enable DMA0 clock rcu.ahben.modify(|_, w| w.dma0en().set_bit()); // Configure DMA channel 0 for memory-to-memory transfer // Source address dma0.ch0maddr.write(|w| unsafe { w.bits(0x20000000) }); // Destination address dma0.ch0paddr.write(|w| unsafe { w.bits(0x20001000) }); // Number of transfers dma0.ch0cnt.write(|w| w.cnt().bits(256)); // Configure channel: Memory-to-memory, 32-bit, increment both dma0.ch0ctl.write(|w| { w.m2m().set_bit() // Memory-to-memory mode .prio().bits(0b10) // High priority .mwidth().bits(0b10) // Memory: 32-bit .pwidth().bits(0b10) // Peripheral: 32-bit .mnaga().set_bit() // Memory address increment .pnaga().set_bit() // Peripheral address increment .dir().clear_bit() // Read from peripheral (source) .errie().set_bit() // Error interrupt enable .ftfie().set_bit() // Transfer complete interrupt }); // Enable channel dma0.ch0ctl.modify(|_, w| w.chen().set_bit()); // Check status let intf = dma0.intf.read(); let ch0_complete = intf.ftfif0().bit_is_set(); let ch0_error = intf.errif0().bit_is_set(); // Clear flags dma0.intc.write(|w| { w.ftfifc0().set_bit() // Clear transfer complete flag .errifc0().set_bit() // Clear error flag }); ``` -------------------------------- ### Configure RCU Clock System and Peripheral Clocks in Rust Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt This snippet demonstrates how to initialize the Reset and Clock Unit (RCU) on the GD32VF103 microcontroller using Rust. It covers enabling the external crystal oscillator (HXTAL), configuring the PLL for a target frequency, switching the system clock to the PLL, and enabling clocks for various peripherals on the APB1, APB2, and AHB buses. It also shows how to reset a peripheral. ```rust use gd32vf103_pac::Peripherals; let dp = Peripherals::take().unwrap(); let rcu = dp.RCU; // Read current clock control status let ctl_value = rcu.ctl.read(); let hxtal_ready = ctl_value.hxtalstb().bit_is_set(); let pll_ready = ctl_value.pllstb().bit_is_set(); // Enable high-speed external crystal rcu.ctl.modify(|_, w| w.hxtalen().set_bit()); // Wait for HXTAL to stabilize while rcu.ctl.read().hxtalstb().bit_is_clear() {} // Configure clock (example: PLL from HXTAL) rcu.cfg0.modify(|_, w| unsafe { w.pllsel().set_bit() // PLL source: HXTAL .pllmf().bits(0b0111) // PLL multiplier: x9 (8MHz * 9 = 72MHz) .ahbpsc().bits(0b0000) // AHB prescaler: /1 .apb1psc().bits(0b100) // APB1 prescaler: /2 .apb2psc().bits(0b000) // APB2 prescaler: /1 }); // Enable PLL rcu.ctl.modify(|_, w| w.pllen().set_bit()); // Wait for PLL ready while rcu.ctl.read().pllstb().bit_is_clear() {} // Switch system clock to PLL rcu.cfg0.modify(|_, w| unsafe { w.scs().bits(0b10) }); // Enable peripheral clocks on APB2 bus rcu.apb2en.modify(|_, w| { w.paen().set_bit() // GPIOA .pben().set_bit() // GPIOB .afen().set_bit() // AFIO .usart0en().set_bit() // USART0 }); // Enable peripheral clocks on APB1 bus rcu.apb1en.modify(|_, w| { w.timer1en().set_bit() // TIMER1 .i2c0en().set_bit() // I2C0 .spi1en().set_bit() // SPI1 }); // Enable AHB peripherals rcu.ahben.modify(|_, w| { w.dma0en().set_bit() // DMA0 .crcen().set_bit() // CRC unit }); // Reset a peripheral rcu.apb2rst.modify(|_, w| w.usart0rst().set_bit()); rcu.apb2rst.modify(|_, w| w.usart0rst().clear_bit()); ``` -------------------------------- ### GPIO Operations: Clock Enable, Output Configuration, and Register Access Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt This Rust code snippet demonstrates common GPIO operations for the GD32VF103 microcontroller. It covers enabling the clock for a GPIO port (GPIOA) via the RCU, configuring a pin (PA0) as a push-pull output, and interacting with various GPIO registers like `ctl0`, `bop`, `bc`, `istat`, `octl`, and `lock` for setting, clearing, reading, and locking pin states. ```rust use gd32vf103_pac::Peripherals; let dp = Peripherals::take().unwrap(); let gpioa = dp.GPIOA; let rcu = dp.RCU; // Enable GPIOA clock in RCU rcu.apb2en.modify(|_, w| w.paen().set_bit()); // Configure PA0 as push-pull output (50MHz) // CTL0 controls pins 0-7, CTL1 controls pins 8-15 gpioa.ctl0.modify(|_, w| unsafe { w.md0().bits(0b11) // Output mode, 50MHz .ctl0().bits(0b00) // Push-pull output }); // Set PA0 high using bit operate register gpioa.bop.write(|w| w.bop0().set_bit()); // Clear PA0 using bit clear register gpioa.bc.write(|w| w.cr0().set_bit()); // Read input status of all pins let input_state = gpioa.istat.read().bits(); let pa1_state = gpioa.istat.read().istat1().bit_is_set(); // Read/modify/write output register gpioa.octl.modify(|r, w| unsafe { w.bits(r.bits() | 0x01) // Set bit 0 }); // Lock pin configuration (cannot be changed until reset) gpioa.lock.write(|w| w.lk0().set_bit().lkk().set_bit()); ``` -------------------------------- ### Configure and Use USART for Serial Communication in Rust Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt This snippet illustrates how to configure and utilize the USART peripheral for serial communication on the GD32VF103 microcontroller using Rust. It covers enabling the USART clock, setting the baud rate, configuring the data format (8N1), enabling the transmitter and receiver, and implementing functions for sending and receiving bytes. It also shows how to check status flags and enable interrupts. ```rust use gd32vf103_pac::Peripherals; let dp = Peripherals::take().unwrap(); let usart0 = dp.USART0; let rcu = dp.RCU; // Enable USART0 clock rcu.apb2en.modify(|_, w| w.usart0en().set_bit()); // Configure baud rate (assuming 72MHz APB2 clock, 115200 baud) // USARTDIV = fCK / (16 * baud) = 72000000 / (16 * 115200) = 39.0625 // Mantissa = 39, Fraction = 0.0625 * 16 = 1 usart0.baud.write(|w| unsafe { w.bits((39 << 4) | 1) }); // Configure USART: 8N1, TX and RX enabled usart0.ctl0.write(|w| { w.uen().set_bit() // USART enable .ten().set_bit() // Transmitter enable .ren().set_bit() // Receiver enable .wl().clear_bit() // 8-bit word length .pcen().clear_bit() // Parity disabled }); // Configure 1 stop bit usart0.ctl1.write(|w| unsafe { w.stb().bits(0b00) }); // Transmit a byte fn usart_send(usart: &gd32vf103_pac::usart0::RegisterBlock, byte: u8) { // Wait for TX buffer empty while usart.stat.read().tbe().bit_is_clear() {} // Write data usart.data.write(|w| unsafe { w.data().bits(byte as u16) }); } // Receive a byte fn usart_recv(usart: &gd32vf103_pac::usart0::RegisterBlock) -> u8 { // Wait for data available while usart.stat.read().rbne().bit_is_clear() {} // Read data usart.data.read().data().bits() as u8 } // Check status flags let stat = usart0.stat.read(); let tx_complete = stat.tc().bit_is_set(); let rx_not_empty = stat.rbne().bit_is_set(); let overrun_error = stat.orerr().bit_is_set(); let framing_error = stat.ferr().bit_is_set(); // Enable interrupts usart0.ctl0.modify(|_, w| { w.rbneie().set_bit() // RX not empty interrupt .tcie().set_bit() // Transmission complete interrupt }); ``` -------------------------------- ### Define Interrupt Handlers in Rust with gd32vf103-pac Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt This Rust code illustrates how to define interrupt service routines (ISRs) using the `interrupt!` macro provided by the gd32vf103-pac crate when the `rt` feature is enabled. It shows basic interrupt handling for TIMER1 and USART0, including accessing peripherals within the ISR and managing local state for the USART0 handler. It also demonstrates converting an IRQ number to the corresponding Interrupt enum variant. ```rust #![no_std] #![no_main] use gd32vf103_pac::{Peripherals, Interrupt, interrupt}; // Define interrupt handler using the macro interrupt!(TIMER1, timer1_handler); fn timer1_handler() { // Access peripherals unsafely in interrupt context let timer1 = unsafe { &*gd32vf103_pac::TIMER1::ptr() }; // Clear interrupt flag if timer1.intf.read().upif().bit_is_set() { timer1.intf.modify(|_, w| w.upif().clear_bit()); // Handle timer interrupt } } // Handler with local state interrupt!(USART0, usart0_handler, locals: { rx_count: u32 = 0; }); fn usart0_handler(locals: &mut USART0::Locals) { let usart0 = unsafe { &*gd32vf103_pac::USART0::ptr() }; if usart0.stat.read().rbne().bit_is_set() { let _data = usart0.data.read().data().bits(); locals.rx_count += 1; } } // Convert interrupt number to enum fn handle_irq(irq: u8) { match Interrupt::try_from(irq) { Ok(Interrupt::TIMER1) => { /* handle */ }, Ok(Interrupt::USART0) => { /* handle */ }, _ => { /* unknown interrupt */ } } } ``` -------------------------------- ### Add gd32vf103-pac Dependency with Runtime and Critical Section Features Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt This TOML snippet shows how to add the gd32vf103-pac crate to your Cargo.toml file. It includes optional features for runtime support ('rt') and critical sections ('critical-section'), which are often necessary for interrupt handling and safe peripheral access. ```toml # Cargo.toml [dependencies] gd32vf103-pac = "0.5.0" # Enable runtime support for interrupt handlers [dependencies.gd32vf103-pac] version = "0.5.0" features = ["rt", "critical-section"] ``` -------------------------------- ### Unsafe Peripheral Access with Peripherals::steal() and Raw Pointers Source: https://context7.com/riscv-rust/gd32vf103-pac/llms.txt Illustrates unsafe, unchecked access to peripherals using `Peripherals::steal()`. This bypasses the singleton check but requires careful handling to avoid data races. It also shows direct register access via raw pointers obtained from peripheral memory addresses. ```rust use gd32vf103_pac::Peripherals; // Unsafe access when you know what you're doing let dp = unsafe { Peripherals::steal() }; // Access specific peripheral directly via pointer let gpioa_ptr = gd32vf103_pac::GPIOA::ptr(); unsafe { // Direct register access via raw pointer let ctl0 = (*gpioa_ptr).ctl0.read().bits(); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.