Your First Program
This tutorial will guide you through creating and running your first PY32F0xx program using the HAL.
Goal
By the end of this tutorial, you'll have:
- Created a simple LED blinking program
- Built and flashed it to your PY32F0xx device
- Understood the basic structure of a PY32F0xx Rust program
Prerequisites
- Development environment is set up
- Hardware is connected and working
- PY32F0xx device with at least one LED connection
Step 1: Understanding the Basic Structure
Every PY32F0xx Rust program follows this basic pattern:
#![no_main] // We don't use Rust's standard main #![no_std] // No standard library (embedded environment) use panic_halt as _; // Panic handler for embedded use py32f0xx_hal as hal; // Import HAL use crate::hal::{ pac, // Peripheral Access Crate prelude::*, // Common traits and imports rcc::HSIFreq, // Clock configuration }; use cortex_m_rt::entry; // Entry point macro #[entry] // This is our \"main\" function fn main() -> ! { // Hardware setup code goes here loop { // Main program loop } }
Step 2: Create Your First Program
Let's create a simple LED blinky program. Create examples/my_first_program.rs
:
#![no_main] #![no_std] use panic_halt as _; use py32f0xx_hal as hal; use crate::hal::{ pac, prelude::*, rcc::HSIFreq, timer::delay::Delay, }; use cortex_m_rt::entry; #[entry] fn main() -> ! { // Take ownership of device peripherals let mut p = pac::Peripherals::take().unwrap(); let cp = cortex_m::Peripherals::take().unwrap(); // Configure the system clock let rcc = p.RCC .configure() .hsi(HSIFreq::Freq24mhz) // Use 24MHz internal oscillator .sysclk(24.MHz()) // Set system clock to 24MHz .freeze(&mut p.FLASH); // Apply clock configuration // Initialize GPIO port B let gpiob = p.GPIOB.split(); // Configure PB5 as push-pull output (LED pin) let mut led = gpiob.pb5.into_push_pull_output(); // Create a delay timer using the system timer let mut delay = Delay::new(cp.SYST, &rcc.clocks); // Main loop - blink the LED loop { led.set_high(); // Turn LED on delay.delay_ms(500_u16); // Wait 500ms led.set_low(); // Turn LED off delay.delay_ms(500_u16); // Wait 500ms } }
Step 3: Build Your Program
# Build your program
make build EXAMPLE=my_first_program MCU_TYPE=py32f003xx4
# If successful, you should see:
# Compiling my_first_program v0.1.0
# Finished release [optimized] target(s)
Step 4: Flash to Device
# Connect your PY32F0xx device via SWD
# Then flash the program
make flash EXAMPLE=my_first_program MCU_TYPE=py32f003xx4
# You should see PyOCD output:
# 0001735:INFO:board:Target type is py32f003xx4
# 0001736:INFO:flash_loader:Erasing chip...
# 0001750:INFO:flash_loader:Programming...
# 0001755:INFO:flash_loader:Programming completed
Step 5: Verify It Works
After successful flashing:
- LED should start blinking - On for 500ms, off for 500ms
- If using PB5 - Connect LED with 330Ω resistor to GND
- No errors in terminal - Clean flash output indicates success
Understanding the Code
Memory Management
#![allow(unused)] #![no_main] // No standard main function #![no_std] // No heap allocation, stack-based only fn main() { use panic_halt as _; // Simple panic handler - halts on panic }
Hardware Abstraction
#![allow(unused)] fn main() { let mut p = pac::Peripherals::take().unwrap(); // pac::Peripherals gives access to all hardware peripherals // take() ensures only one instance exists (singleton pattern) }
Clock Configuration
#![allow(unused)] fn main() { let rcc = p.RCC .configure() .hsi(HSIFreq::Freq24mhz) // Internal 24MHz oscillator .sysclk(24.MHz()) // System clock frequency .freeze(&mut p.FLASH); // Lock in configuration }
Why 24MHz? This is a proven, stable configuration that works reliably across PY32F0xx devices.
GPIO Setup
#![allow(unused)] fn main() { let gpiob = p.GPIOB.split(); // split() converts raw peripheral to HAL-managed GPIO port let mut led = gpiob.pb5.into_push_pull_output(); // Configure specific pin as output // push_pull = can source and sink current }
Timing
#![allow(unused)] fn main() { let mut delay = Delay::new(cp.SYST, &rcc.clocks); // Uses ARM Cortex-M SysTick timer for delays // Calibrated to the system clock frequency }
Customizing Your Program
Change Blink Rate
#![allow(unused)] fn main() { // Faster blinking led.set_high(); delay.delay_ms(100_u16); // 100ms on led.set_low(); delay.delay_ms(100_u16); // 100ms off // Slower blinking led.set_high(); delay.delay_ms(1000_u16); // 1 second on led.set_low(); delay.delay_ms(1000_u16); // 1 second off }
Use Different LED Pin
#![allow(unused)] fn main() { // For PY32F003 DFN8 package - use PA2 instead let gpioa = p.GPIOA.split(); let mut led = gpioa.pa2.into_push_pull_output(); }
Add Multiple LEDs
#![allow(unused)] fn main() { let mut led1 = gpiob.pb5.into_push_pull_output(); let mut led2 = gpioa.pa2.into_push_pull_output(); loop { led1.set_high(); led2.set_low(); delay.delay_ms(250_u16); led1.set_low(); led2.set_high(); delay.delay_ms(250_u16); } }
Common Issues and Solutions
LED Not Blinking
-
Check wiring:
PB5 → [330Ω resistor] → LED anode LED cathode → GND
-
Verify pin assignment:
- PY32F003I DFN8: Use PB5 (pin 1)
- Check your device pinout
-
Check power supply:
- Should be stable 3.3V
- Measure with multimeter
Build Errors
"error: target 'thumbv6m-none-eabi' not found"
rustup target add thumbv6m-none-eabi
"feature 'py32f003xx4' not found"
# Use correct feature for your device:
make build EXAMPLE=my_first_program MCU_TYPE=py32f030xx4 # for PY32F030
Flash Errors
"No devices found"
# Check SWD connections
pyocd list # Should show your programmer
# Verify wiring:
# SWDIO ↔ PA13
# SWDCK ↔ PA14
# GND ↔ GND
"Flash failed"
# Try different SWD frequency
pyocd flash --frequency 1000000 target/thumbv6m-none-eabi/release/examples/my_first_program
# Or try mass erase first
pyocd erase --chip --target py32f003xx4
Next Steps
Congratulations! You've successfully created, built, and flashed your first PY32F0xx program. Here's what to explore next:
Learn More Peripherals
- Serial Communication - USART communication
- ADC Reading - Analog input measurement
- PWM Output - Generate PWM signals
- Timers - Precise timing control
Explore Examples
# Try the serial echo example
make flash EXAMPLE=serial_echo MCU_TYPE=py32f003xx4
# Or the ADC example
make flash EXAMPLE=serial_adc MCU_TYPE=py32f003xx4
Build Real Projects
- Temperature monitor with serial output
- PWM motor controller
- Data logger with external sensors
- Simple IoT device with serial interface
Advanced Topics
- DMA transfers for high-performance I/O
- Interrupts for responsive systems
- Low power modes for battery applications
- Custom bootloaders for field updates
Reference Links
You're now ready to start building more complex PY32F0xx applications!