### ADC Analog-to-Digital Conversion Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Configures ADC peripherals for reading analog voltages with configurable sample time and resolution. This example demonstrates reading analog input pins and converting the raw ADC values to millivolts. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use stm32f4xx_hal::{ pac, prelude::*, adc::{Adc, config::{AdcConfig, SampleTime}}, }; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let cp = cortex_m::peripheral::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); let gpioa = dp.GPIOA.split(&mut rcc); let gpiob = dp.GPIOB.split(&mut rcc); // Configure analog input pins let adc_pin = gpioa.pa0.into_analog(); let adc_pin2 = gpiob.pb1.into_analog(); // Create ADC with default configuration let mut adc = Adc::new(dp.ADC1, true, AdcConfig::default(), &mut rcc); // Get conversion function for millivolts let sample_to_mv = adc.make_sample_to_millivolts(); let mut delay = cp.SYST.delay(&rcc.clocks); loop { // Read raw ADC value (12-bit, 0-4095) let raw_value: u16 = adc.convert(&adc_pin, SampleTime::Cycles_480); // Convert to millivolts let millivolts = sample_to_mv(raw_value); // Read another channel let raw_value2: u16 = adc.convert(&adc_pin2, SampleTime::Cycles_480); // Read internal temperature sensor // adc.enable_temperature_and_vref(); // let temp_raw = adc.convert(&Temperature, SampleTime::Cycles_480); delay.delay_ms(100_u32); } } ``` -------------------------------- ### Configure and Feed Independent Watchdog Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Initializes the IWDG with a 1-second timeout and demonstrates the feed pattern within a main loop. Note that the watchdog cannot be stopped once started. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use stm32f4xx_hal::{pac, prelude::*, watchdog::IndependentWatchdog}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let cp = cortex_m::peripheral::Peripherals::take().unwrap(); let rcc = dp.RCC.constrain(); let gpioa = dp.GPIOA.split(&rcc); let mut led = gpioa.pa5.into_push_pull_output(); let mut delay = cp.SYST.delay(&rcc.clocks); // Create watchdog with 1 second timeout let mut watchdog = IndependentWatchdog::new(dp.IWDG); watchdog.start(1000.millis()); // Note: Once started, watchdog cannot be stopped! // System will reset if not fed within timeout period loop { led.toggle(); delay.delay_ms(200_u32); // Feed the watchdog to prevent reset watchdog.feed(); // If this line is commented out, system will reset after 1 second } } ``` -------------------------------- ### Configure SDIO for SD Card Interface Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Initializes the SDIO peripheral and an SD card for reading and writing. Requires the `sdio-host` feature. Ensure the SDIO peripheral is clocked at 48MHz. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use stm32f4xx_hal::{ pac, prelude::*, rcc::Config, sdio::{ClockFreq, SdCard, Sdio}, }; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let cp = cortex_m::peripheral::Peripherals::take().unwrap(); let mut rcc = dp.RCC.freeze( Config::hse(12.MHz()) .require_pll48clk() // SDIO requires 48MHz clock .sysclk(168.MHz()) ); let mut delay = cp.SYST.delay(&rcc.clocks); let gpioc = dp.GPIOC.split(&mut rcc); let gpiod = dp.GPIOD.split(&mut rcc); // Configure SDIO pins with internal pull-ups let d0 = gpioc.pc8.internal_pull_up(true); let d1 = gpioc.pc9.internal_pull_up(true); let d2 = gpioc.pc10.internal_pull_up(true); let d3 = gpioc.pc11.internal_pull_up(true); let clk = gpioc.pc12; let cmd = gpiod.pd2.internal_pull_up(true); // Create SDIO instance let mut sdio: Sdio = Sdio::new( dp.SDIO, (clk, cmd, d0, d1, d2, d3), &mut rcc ); // Initialize card (retry until card detected) loop { match sdio.init(ClockFreq::F24Mhz) { Ok(_) => break, Err(_) => delay.delay_ms(100_u32), } } // Get card info if let Some(card) = sdio.card() { let _blocks = card.block_count(); } // Read block 0 (boot sector) let mut buffer = [0u8; 512]; sdio.read_block(0, &mut buffer).ok(); // Write block (be careful with block 0!) // let write_data = [0xAAu8; 512]; // sdio.write_block(1, &write_data).ok(); loop {} } ``` -------------------------------- ### Dynamically Change GPIO Pin Modes Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Demonstrates changing GPIO pin modes at runtime between input and output. Uses a system timer for delays and requires `nb::block` for waiting. ```rust #![no_std] #![no_main] use panic_halt as _; use nb::block; use cortex_m_rt::entry; use stm32f4xx_hal::{pac, prelude::*, gpio::PinState, timer::Timer}; #[entry] fn main() -> ! { let cp = cortex_m::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); let gpioc = dp.GPIOC.split(&mut rcc); // Create dynamic pin (mode can change at runtime) let mut pin = gpioc.pc13.into_dynamic(); let mut timer = Timer::syst(cp.SYST, &rcc.clocks).counter_us(); timer.start(1.secs()).unwrap(); loop { // Switch to input mode and read pin.make_floating_input(); block!(timer.wait()).unwrap(); let _is_high = pin.is_high().unwrap(); // Switch to output mode pin.make_push_pull_output_in_state(PinState::High); block!(timer.wait()).unwrap(); pin.set_low().unwrap(); block!(timer.wait()).unwrap(); // Can also use pull-up/pull-down inputs pin.make_pull_up_input(); block!(timer.wait()).unwrap(); } } ``` -------------------------------- ### Configure GPIO Pins and Basic LED Blinking Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Configures GPIO pins for input/output operations and demonstrates basic LED control. Use for general-purpose input/output tasks and simple blinking patterns. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use stm32f4xx_hal::{pac, prelude::*}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); // Split GPIO port into individual pins let gpioc = dp.GPIOC.split(&mut rcc); let gpioa = dp.GPIOA.split(&mut rcc); // Configure PC13 as push-pull output (common LED pin) let mut led = gpioc.pc13.into_push_pull_output(); // Configure PA0 as floating input let button = gpioa.pa0.into_floating_input(); // Configure PA1 as input with internal pull-up let _input_pullup = gpioa.pa1.into_pull_up_input(); loop { // Read button state and control LED if button.is_high() { led.set_high(); } else { led.set_low(); } // Alternative: use toggle led.toggle(); for _ in 0..100_000 { cortex_m::asm::nop(); } } } ``` -------------------------------- ### Generate New Project with Template Source: https://github.com/stm32-rs/stm32f4xx-hal/blob/master/README.md Use the 'cargo generate' command with the stm32-template repository to quickly create a new Rust project for STM32 development. You will need to know the full name of your target chip. ```bash $ cargo generate --git https://github.com/burrbull/stm32-template/ ``` -------------------------------- ### Add Dependencies to Cargo.toml Source: https://github.com/stm32-rs/stm32f4xx-hal/blob/master/README.md Include these dependencies in your Cargo.toml file to set up your project for stm32f4xx-hal development. Ensure the 'stm32f4xx-hal' version and features match your microcontroller and requirements. ```toml [dependencies] embedded-hal = "1.0" b = "1" cortex-m = "0.7" cortex-m-rt = "0.7" # Panic behaviour, see https://crates.io/keywords/panic-impl for alternatives panic-halt = "1.0" [dependencies.stm32f4xx-hal] version = "0.23.0" features = ["stm32f407"] # replace the model of your microcontroller here # and add other required features ``` -------------------------------- ### Configure DMA Transfers for SPI Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Initializes DMA streams for memory-to-peripheral data transfer. Uses a static buffer and configures SPI pins for high-speed operation. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use embedded_hal_02::spi::{Mode, Phase, Polarity}; use stm32f4xx_hal::{ pac, prelude::*, gpio::Speed, spi::Spi, dma::{config::DmaConfig, MemoryToPeripheral, StreamsTuple, Transfer}, }; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); // Initialize DMA streams let dma_streams = StreamsTuple::new(dp.DMA1, &mut rcc); let stream = dma_streams.4; // DMA1 Stream 4 let gpiob = dp.GPIOB.split(&mut rcc); // Configure SPI pins let mosi = gpiob.pb15.into_alternate().speed(Speed::VeryHigh); let sck = gpiob.pb13.into_alternate().speed(Speed::VeryHigh); let mode = Mode { polarity: Polarity::IdleLow, phase: Phase::CaptureOnFirstTransition, }; let spi = Spi::new( dp.SPI2, (Some(sck), stm32f4xx_hal::pac::SPI2::NoMiso, Some(mosi)), mode, 3.MHz(), &mut rcc, ); // Get SPI TX for DMA let tx = spi.use_dma().tx(); // Create static buffer for DMA let buffer = cortex_m::singleton!(: [u8; 100] = [0; 100]).unwrap(); for (i, b) in buffer.iter_mut().enumerate() { *b = i as u8; } // Configure DMA transfer let dma_config = DmaConfig::default() .memory_increment(true) .fifo_enable(true) .transfer_complete_interrupt(true); let mut transfer = Transfer::init_memory_to_peripheral( stream, tx, buffer, None, dma_config, ); // Start DMA transfer transfer.start(|_tx| {}); // Wait for transfer completion while !transfer.flags().is_transfer_complete() { cortex_m::asm::nop(); } loop {} } ``` -------------------------------- ### Configure USB CDC Serial Communication Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Sets up the USB OTG peripheral for virtual COM port communication. Requires the usb_fs feature and static memory allocation for USB endpoints. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use static_cell::ConstStaticCell; use stm32f4xx_hal::{ pac, prelude::*, rcc::Config, otg_fs::{UsbBus, USB}, }; use usb_device::prelude::*; // USB endpoint memory (must be static) static EP_MEMORY: ConstStaticCell<[u32; 1024]> = ConstStaticCell::new([0; 1024]); #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); // USB requires 48MHz clock from PLL let mut rcc = dp.RCC.freeze( Config::hse(25.MHz()) .sysclk(48.MHz()) .require_pll48clk() ); let gpioa = dp.GPIOA.split(&mut rcc); // Configure USB peripheral (PA11=DM, PA12=DP) let usb = USB::new( (dp.OTG_FS_GLOBAL, dp.OTG_FS_DEVICE, dp.OTG_FS_PWRCLK), (gpioa.pa11, gpioa.pa12), &rcc.clocks, ); let usb_bus = UsbBus::new(usb, EP_MEMORY.take()); // Create CDC-ACM serial port let mut serial = usbd_serial::SerialPort::new(&usb_bus); // Build USB device let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) .device_class(usbd_serial::USB_CLASS_CDC) .strings(&[StringDescriptors::default() .manufacturer("My Company") .product("Serial Port") .serial_number("001")]) .unwrap() .build(); let mut buf = [0u8; 64]; loop { // Poll USB device if !usb_dev.poll(&mut [&mut serial]) { continue; } // Read data from host match serial.read(&mut buf) { Ok(count) if count > 0 => { // Echo back (convert to uppercase) for c in buf[0..count].iter_mut() { if *c >= b'a' && *c <= b'z' { *c -= 32; } } serial.write(&buf[0..count]).ok(); } _ => {} } } } ``` -------------------------------- ### Configure RTC for Timekeeping Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Initializes the RTC peripheral and sets the date and time. Requires the PWR peripheral to be passed during initialization. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use stm32f4xx_hal::{pac, prelude::*, rtc::Rtc}; use time::{Date, Time, PrimitiveDateTime, Month}; #[entry] fn main() -> ! { let mut dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); // Initialize RTC (requires PWR peripheral) let mut rtc = Rtc::new(dp.RTC, &mut rcc, &mut dp.PWR); let mut delay = dp.TIM5.delay_us(&mut rcc); // Set date and time let date = Date::from_calendar_date(2024, Month::January, 15).unwrap(); let time = Time::from_hms(14, 30, 0).unwrap(); let datetime = PrimitiveDateTime::new(date, time); rtc.set_datetime(&datetime).unwrap(); // Alternative: set individual components // rtc.set_year(2024).unwrap(); // rtc.set_month(1).unwrap(); // rtc.set_day(15).unwrap(); // rtc.set_hours(14).unwrap(); // rtc.set_minutes(30).unwrap(); // rtc.set_seconds(0).unwrap(); loop { // Read current date/time let current = rtc.get_datetime(); // Access individual components // let hours = current.hour(); // let minutes = current.minute(); // let seconds = current.second(); delay.delay(1.secs()); } } ``` -------------------------------- ### Configure SPI for Synchronous Serial Communication Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Sets up an SPI peripheral for synchronous serial communication. Configurable for clock polarity, phase, and speed. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use embedded_hal_02::spi::{Mode, Phase, Polarity}; use stm32f4xx_hal::{pac, prelude::*, gpio::Speed, spi::Spi}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); let gpiob = dp.GPIOB.split(&mut rcc); // Configure SPI pins with appropriate speed let sck = gpiob.pb13.into_alternate().speed(Speed::VeryHigh); let miso = gpiob.pb14.into_alternate().speed(Speed::VeryHigh); let mosi = gpiob.pb15.into_alternate().speed(Speed::VeryHigh); // Optional: chip select pin let mut cs = gpiob.pb12.into_push_pull_output(); cs.set_high(); // Deselect device let mode = Mode { polarity: Polarity::IdleLow, phase: Phase::CaptureOnFirstTransition, }; // Create SPI instance let mut spi = Spi::new( dp.SPI2, (Some(sck), Some(miso), Some(mosi)), mode, 3.MHz(), &mut rcc, ); let tx_buffer: [u8; 4] = [0x01, 0x02, 0x03, 0x04]; let mut rx_buffer: [u8; 4] = [0; 4]; loop { cs.set_low(); // Select device // Transfer data (simultaneous read/write) spi.transfer(&mut rx_buffer, &tx_buffer).ok(); cs.set_high(); // Deselect device for _ in 0..100_000 { cortex_m::asm::nop(); } } } ``` -------------------------------- ### Configure PWM Output Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Configures timer channels for PWM output with adjustable frequency and duty cycle. Ensure the correct timer and GPIO pins are selected for your target microcontroller. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use stm32f4xx_hal::{pac, prelude::*}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); let gpioa = dp.GPIOA.split(&mut rcc); // Configure PWM with period of 100 microseconds (10kHz) let (_, (ch1, ch2, ..)) = dp.TIM1.pwm_us(100.micros(), &mut rcc); // Attach pins to PWM channels let mut pwm_ch1 = ch1.with(gpioa.pa8); let mut pwm_ch2 = ch2.with(gpioa.pa9); // Get maximum duty cycle value let max_duty = pwm_ch1.get_max_duty(); // Set 50% duty cycle pwm_ch1.set_duty(max_duty / 2); // Set 25% duty cycle on channel 2 pwm_ch2.set_duty(max_duty / 4); // Enable PWM output pwm_ch1.enable(); pwm_ch2.enable(); // Vary duty cycle for LED dimming effect loop { for duty in (0..=max_duty).step_by(100) { pwm_ch1.set_duty(duty); for _ in 0..10_000 { cortex_m::asm::nop(); } } for duty in (0..=max_duty).rev().step_by(100) { pwm_ch1.set_duty(duty); for _ in 0..10_000 { cortex_m::asm::nop(); } } } } ``` -------------------------------- ### Configure I2C for Inter-Integrated Circuit Communication Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Sets up an I2C peripheral for communication. Supports standard (100kHz) and fast (400kHz) speed modes for reading and writing data to devices. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use stm32f4xx_hal::{pac, prelude::*, i2c::I2c}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); let gpiob = dp.GPIOB.split(&mut rcc); // Configure I2C pins let scl = gpiob.pb8; // I2C1 SCL let sda = gpiob.pb7; // I2C1 SDA // Create I2C instance with standard mode (100kHz) let mut i2c = I2c::new( dp.I2C1, (scl, sda), stm32f4xx_hal::i2c::Mode::standard(100.kHz()), &mut rcc, ); // For fast mode (400kHz): // let mut i2c = I2c::new( // dp.I2C1, // (scl, sda), // stm32f4xx_hal::i2c::Mode::fast(400.kHz()), // &mut rcc, // ); const DEVICE_ADDR: u8 = 0x50; // Example EEPROM address // Write data to device let write_data: [u8; 3] = [0x00, 0x01, 0x02]; // Address + data i2c.write(DEVICE_ADDR, &write_data).ok(); // Read data from device let mut read_buffer: [u8; 2] = [0; 2]; i2c.read(DEVICE_ADDR, &mut read_buffer).ok(); // Write then read (write register address, read data) let reg_addr: [u8; 1] = [0x00]; i2c.write_read(DEVICE_ADDR, ®_addr, &mut read_buffer).ok(); // I2C scanner - detect devices on bus for addr in 0x08_u8..0x78 { let probe: [u8; 1] = [0]; if i2c.write(addr, &probe).is_ok() { // Device found at addr } } loop {} } ``` -------------------------------- ### Read Rotary Encoder with QEI Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Configures a timer as a Quadrature Encoder Interface to track rotation direction and position. Uses the embedded-hal Direction enum to determine rotation. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use embedded_hal_02::Direction; use stm32f4xx_hal::{pac, prelude::*, qei::Qei}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let cp = cortex_m::peripheral::Peripherals::take().unwrap(); let mut rcc = dp.RCC.constrain(); let gpioa = dp.GPIOA.split(&mut rcc); let gpioc = dp.GPIOC.split(&mut rcc); let mut led = gpioc.pc13.into_push_pull_output(); let mut delay = cp.SYST.delay(&rcc.clocks); // Connect rotary encoder to PA0 (A) and PA1 (B) let encoder_pins = (gpioa.pa0, gpioa.pa1); // Create QEI instance using TIM2 let encoder = Qei::new(dp.TIM2, encoder_pins, &mut rcc); let mut last_count = encoder.count(); loop { let current_count = encoder.count(); if current_count != last_count { // Position changed let _diff = current_count.wrapping_sub(last_count) as i16; // Check rotation direction match encoder.direction() { Direction::Upcounting => led.set_low(), // Clockwise Direction::Downcounting => led.set_high(), // Counter-clockwise } last_count = current_count; } delay.delay_ms(10_u32); } } ``` -------------------------------- ### Configure UART for Serial Communication Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Sets up a UART peripheral for serial communication with a configurable baud rate. Supports both transmit-only and full-duplex modes. ```rust #![no_std] #![no_main] use panic_halt as _; use core::fmt::Write; use cortex_m_rt::entry; use stm32f4xx_hal::{pac, prelude::*, rcc::Config}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.freeze(Config::hse(25.MHz())); let gpioa = dp.GPIOA.split(&mut rcc); let mut delay = dp.TIM1.delay_ms(&mut rcc); // Configure TX pin (PA9 for USART1) let tx_pin = gpioa.pa9; let rx_pin = gpioa.pa10; // Create TX-only serial port let mut tx = dp.USART1.tx(tx_pin, 115200.bps(), &mut rcc).unwrap(); // Or create full duplex serial let mut serial = dp.USART1.serial( (tx_pin, rx_pin), 115200.bps(), &mut rcc ).unwrap(); let mut counter: u8 = 0; loop { // Write formatted output writeln!(tx, "Counter: \r", counter).unwrap(); // Write raw bytes tx.write_byte(0x41).ok(); // Write 'A' // Read with serial (blocking) // if let Ok(byte) = nb::block!(serial.read()) { // nb::block!(serial.write(byte)).ok(); // } counter = counter.wrapping_add(1); delay.delay(1.secs()); } } ``` -------------------------------- ### Communicate via CAN Bus Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Sets up CAN peripheral communication using the bxcan crate. Requires an external crystal for clock accuracy and specific bit timing configuration. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use bxcan::{filter::Mask32, Fifo, Frame, StandardId}; use nb::block; use stm32f4xx_hal::{pac, prelude::*, rcc::Config}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); // CAN requires external crystal for clock accuracy let mut rcc = dp.RCC.freeze(Config::hse(8.MHz())); let gpiob = dp.GPIOB.split(&mut rcc); // Configure CAN1 pins (PB8=RX, PB9=TX) let rx = gpiob.pb8; let tx = gpiob.pb9; // Initialize CAN peripheral let can = dp.CAN1.can((tx, rx), &mut rcc); // Configure and enable CAN let mut can = bxcan::Can::builder(can) // Bit timing for 500kbit/s at 8MHz APB1 // Calculate at http://www.bittiming.can-wiki.info/ .set_bit_timing(0x001c_0000) .enable(); // Configure acceptance filters let mut filters = can.modify_filters(); filters.enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); drop(filters); let mut data: [u8; 8] = [0; 8]; let id: u16 = 0x500; loop { // Create and send CAN frame data[0] = data[0].wrapping_add(1); let frame = Frame::new_data(StandardId::new(id).unwrap(), data); block!(can.transmit(&frame)).unwrap(); // Receive frames // if let Ok(frame) = can.receive() { // // Process received frame // } for _ in 0..100_000 { cortex_m::asm::nop(); } } } ``` -------------------------------- ### Create Blocking Delays Using Timers Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Implements blocking delays using the SysTick timer or hardware timers. Useful for creating precise timing intervals in embedded applications. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use stm32f4xx_hal::{pac, prelude::*, rcc::Config}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let cp = cortex_m::peripheral::Peripherals::take().unwrap(); let mut rcc = dp.RCC.freeze(Config::hsi().sysclk(48.MHz())); let gpioa = dp.GPIOA.split(&mut rcc); let mut led = gpioa.pa5.into_push_pull_output(); // Create delay using SysTick let mut delay = cp.SYST.delay(&rcc.clocks); // Alternative: use hardware timer for delay let mut timer_delay = dp.TIM1.delay_ms(&mut rcc); loop { led.toggle(); delay.delay_ms(500_u32); // 500ms delay led.toggle(); delay.delay_us(100_000_u32); // 100ms in microseconds // Using hardware timer delay timer_delay.delay(1.secs()); } } ``` -------------------------------- ### Configure Timer Interrupts Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Configures hardware timers to generate periodic interrupts for time-critical operations. Global mutable static variables are used to share peripherals between the main function and the interrupt handler, protected by mutexes. ```rust #![no_std] #![no_main] use panic_halt as _; use core::cell::RefCell; use cortex_m::interrupt::Mutex; use cortex_m_rt::entry; use stm32f4xx_hal::{ pac::{self, interrupt, Interrupt, TIM2}, prelude::*, rcc::Config, gpio::{Output, PushPull, PA5}, timer::{CounterUs, Event}, }; // Global state protected by mutex static G_LED: Mutex>>>> = Mutex::new(RefCell::new(None)); static G_TIM: Mutex>>> = Mutex::new(RefCell::new(None)); #[interrupt] fn TIM2() { static mut LED: Option>> = None; static mut TIM: Option> = None; let led = LED.get_or_insert_with(|| { cortex_m::interrupt::free(|cs| G_LED.borrow(cs).replace(None).unwrap()) }); let tim = TIM.get_or_insert_with(|| { cortex_m::interrupt::free(|cs| G_TIM.borrow(cs).replace(None).unwrap()) }); led.toggle(); let _ = tim.wait(); // Clear interrupt flag } #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let mut rcc = dp.RCC.freeze(Config::hsi().sysclk(16.MHz()).pclk1(8.MHz())); let gpioa = dp.GPIOA.split(&mut rcc); let led = gpioa.pa5.into_push_pull_output(); // Move LED to global storage cortex_m::interrupt::free(|cs| *G_LED.borrow(cs).borrow_mut() = Some(led)); // Configure timer for 1 second period let mut timer = dp.TIM2.counter(&mut rcc); timer.start(1.secs()).unwrap(); timer.listen(Event::Update); // Enable update interrupt // Move timer to global storage cortex_m::interrupt::free(|cs| *G_TIM.borrow(cs).borrow_mut() = Some(timer)); // Enable TIM2 interrupt in NVIC unsafe { cortex_m::peripheral::NVIC::unmask(Interrupt::TIM2); } loop { cortex_m::asm::wfi(); // Wait for interrupt } } ``` -------------------------------- ### Configure RCC Clock System Source: https://context7.com/stm32-rs/stm32f4xx-hal/llms.txt Configures the Reset and Clock Control (RCC) system for various clock sources and frequencies. Use to set up the system clock, including options for HSI, HSE, and PLL configurations. ```rust #![no_std] #![no_main] use panic_halt as _; use cortex_m_rt::entry; use stm32f4xx_hal::{pac, prelude::*, rcc::Config}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); // Option 1: Use HSI (internal) oscillator with default settings let mut rcc = dp.RCC.constrain(); // Option 2: Configure HSI with specific system clock let mut rcc = dp.RCC.freeze(Config::hsi().sysclk(48.MHz())); // Option 3: Use HSE (external) oscillator (e.g., 25MHz crystal) let mut rcc = dp.RCC.freeze(Config::hse(25.MHz())); // Option 4: Full configuration with PLL let mut rcc = dp.RCC.freeze( Config::hse(25.MHz()) .sysclk(168.MHz()) .hclk(168.MHz()) .pclk1(42.MHz()) .pclk2(84.MHz()) .require_pll48clk() // Required for USB/SDIO ); // Access clock frequencies let _sysclk = rcc.clocks.sysclk(); let _pclk1 = rcc.clocks.pclk1(); loop {} } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.