Fixed Rust drivers

This commit is contained in:
Kevin Thomas
2026-04-02 11:36:06 -04:00
parent 2792583302
commit 9834d5c96c
245 changed files with 1110 additions and 650 deletions
+32
View File
@@ -31,6 +31,9 @@ use rp235x_hal as hal;
#[cfg(rp2040)]
use rp2040_hal as hal;
// UART driver for echo demo
use crate::uart;
/// External crystal frequency in Hz (12 MHz).
pub(crate) const XTAL_FREQ_HZ: u32 = 12_000_000u32;
@@ -91,4 +94,33 @@ pub(crate) fn init_pins(
hal::gpio::Pins::new(io_bank0, pads_bank0, sio.gpio_bank0, resets)
}
/// Initialise all peripherals and run the UART echo demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let mut drv = uart::UartDriver::init(pac.UART0, pins.gpio0, pins.gpio1, UART_BAUD, &mut pac.RESETS, &clocks);
drv.puts(b"UART driver ready (115200 8N1)\r\n");
drv.puts(b"Type characters to echo them back in UPPERCASE:\r\n");
echo_loop(&mut drv)
}
/// Run the uppercase echo loop forever.
///
/// # Arguments
///
/// * `drv` - Mutable reference to the UART driver.
fn echo_loop(drv: &mut uart::UartDriver) -> ! {
loop {
if drv.is_readable() {
let c = drv.getchar();
drv.putchar(uart::UartDriver::to_upper(c));
}
}
}
// End of file
+1 -25
View File
@@ -76,33 +76,9 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the UART uppercase echo demo.
///
/// Initializes UART0 and enters an infinite loop that reads incoming
/// characters, converts them to uppercase, and echoes them back.
///
/// # Returns
///
/// Does not return.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut watchdog,
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let mut drv = uart::UartDriver::init(
pac.UART0, pins.gpio0, pins.gpio1, board::UART_BAUD, &mut pac.RESETS, &clocks,
);
drv.puts(b"UART driver ready (115200 8N1)\r\n");
drv.puts(b"Type characters to echo them back in UPPERCASE:\r\n");
loop {
if drv.is_readable() {
let c = drv.getchar();
let upper = uart::UartDriver::to_upper(c);
drv.putchar(upper);
}
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+40 -1
View File
@@ -30,7 +30,7 @@ use fugit::RateExtU32;
// Clock trait for accessing system clock frequency
use hal::Clock;
// GPIO pin types and function selectors
use hal::gpio::{FunctionNull, FunctionUart, Pin, PullDown, PullNone};
use hal::gpio::{FunctionNull, FunctionSioOutput, FunctionUart, Pin, PullDown, PullNone};
// UART configuration and peripheral types
use hal::uart::{DataBits, Enabled, StopBits, UartConfig, UartPeripheral};
@@ -170,4 +170,43 @@ pub(crate) fn init_delay(clocks: &hal::clocks::ClocksManager) -> cortex_m::delay
cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz())
}
/// Type alias for the onboard LED pin configured as push-pull output.
type LedPin = Pin<hal::gpio::bank0::Gpio25, FunctionSioOutput, PullDown>;
/// Initialise all peripherals and run the blink demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = init_delay(&clocks);
let mut led = crate::blink::BlinkDriver::init(pins.gpio25.into_push_pull_output());
uart.write_full_blocking(b"Blink driver initialized on GPIO 25\r\n");
blink_loop(&uart, &mut delay, &mut led)
}
/// Toggle LED, report state, and delay in a loop forever.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
/// * `delay` - Mutable reference to the blocking delay provider.
/// * `led` - Mutable reference to the blink driver.
fn blink_loop(
uart: &EnabledUart,
delay: &mut cortex_m::delay::Delay,
led: &mut crate::blink::BlinkDriver<LedPin>,
) -> ! {
loop {
led.toggle();
let msg = if led.get_state() { b"LED: ON\r\n" as &[u8] } else { b"LED: OFF\r\n" };
uart.write_full_blocking(msg);
delay.delay_ms(BLINK_DELAY_MS);
}
}
// End of file
+1 -26
View File
@@ -74,34 +74,9 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the LED blink demo.
///
/// Initializes the onboard LED and enters an infinite loop that
/// toggles the LED state every BLINK_DELAY_MS milliseconds.
///
/// # Returns
///
/// Does not return.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = board::init_delay(&clocks);
let mut led = blink::BlinkDriver::init(pins.gpio25.into_push_pull_output());
uart.write_full_blocking(b"Blink driver initialized on GPIO 25\r\n");
loop {
led.toggle();
if led.get_state() {
uart.write_full_blocking(b"LED: ON\r\n");
} else {
uart.write_full_blocking(b"LED: OFF\r\n");
}
delay.delay_ms(board::BLINK_DELAY_MS);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+79 -1
View File
@@ -25,12 +25,14 @@
//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//! SOFTWARE.
// Interior mutability for shared delay access
use core::cell::RefCell;
// Rate extension trait for .Hz() baud rate construction
use fugit::RateExtU32;
// Clock trait for accessing system clock frequency
use hal::Clock;
// GPIO pin types and function selectors
use hal::gpio::{FunctionNull, FunctionUart, Pin, PullDown, PullNone};
use hal::gpio::{FunctionNull, FunctionSioInput, FunctionSioOutput, FunctionUart, Pin, PullDown, PullNone, PullUp};
// UART configuration and peripheral types
use hal::uart::{DataBits, Enabled, StopBits, UartConfig, UartPeripheral};
@@ -173,4 +175,80 @@ pub(crate) fn init_delay(clocks: &hal::clocks::ClocksManager) -> cortex_m::delay
cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz())
}
/// Type alias for the button input pin (GPIO 15, pull-up).
type BtnPin = Pin<hal::gpio::bank0::Gpio15, FunctionSioInput, PullUp>;
/// Type alias for the LED output pin (GPIO 25, push-pull).
type LedPin = Pin<hal::gpio::bank0::Gpio25, FunctionSioOutput, PullDown>;
/// Initialise all peripherals and run the button debounce demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let delay = RefCell::new(init_delay(&clocks));
uart.write_full_blocking(b"Button driver initialized: button=GPIO15 led=GPIO25\r\n");
button_demo(&uart, pins.gpio15, pins.gpio25, &delay)
}
/// Create button and LED drivers, then run the polling loop.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
/// * `btn_pin` - Default GPIO 15 pin for the button input.
/// * `led_pin` - Default GPIO 25 pin for the LED output.
/// * `delay` - Shared reference to the delay provider.
fn button_demo(
uart: &EnabledUart,
btn_pin: Pin<hal::gpio::bank0::Gpio15, FunctionNull, PullDown>,
led_pin: Pin<hal::gpio::bank0::Gpio25, FunctionNull, PullDown>,
delay: &RefCell<cortex_m::delay::Delay>,
) -> ! {
let mut btn = crate::button::ButtonDriver::init(
btn_pin.into_pull_up_input(), DEBOUNCE_MS, |ms| delay.borrow_mut().delay_ms(ms),
);
let mut led = crate::button::ButtonLed::init(led_pin.into_push_pull_output());
let mut last = false;
loop { poll_button(uart, &mut btn, &mut led, &mut last, delay); }
}
/// Poll button state, update LED, and report edge transitions.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
/// * `btn` - Mutable reference to the button driver.
/// * `led` - Mutable reference to the LED driver.
/// * `last` - Mutable reference to the previous button state.
/// * `delay` - Shared reference to the delay provider.
fn poll_button<F: Fn(u32)>(
uart: &EnabledUart,
btn: &mut crate::button::ButtonDriver<BtnPin, F>,
led: &mut crate::button::ButtonLed<LedPin>,
last: &mut bool,
delay: &RefCell<cortex_m::delay::Delay>,
) {
let pressed = btn.is_pressed();
led.set(pressed);
if pressed != *last { report_edge(uart, pressed); *last = pressed; }
delay.borrow_mut().delay_ms(POLL_MS);
}
/// Print button press/release message over UART.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
/// * `pressed` - `true` if the button is pressed, `false` if released.
fn report_edge(uart: &EnabledUart, pressed: bool) {
let msg = if pressed { b"Button: PRESSED\r\n" as &[u8] } else { b"Button: RELEASED\r\n" };
uart.write_full_blocking(msg);
}
// End of file
+1 -38
View File
@@ -54,8 +54,6 @@ use panic_halt as _;
#[cfg(target_arch = "arm")]
use panic_probe as _;
// Interior mutability for shared peripheral access
use core::cell::RefCell;
// HAL entry-point macro
use hal::entry;
@@ -78,44 +76,9 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the button debounce demo.
///
/// Initializes button and LED, then continuously polls button state
/// and mirrors it to the LED with UART reporting on edge transitions.
///
/// # Returns
///
/// Does not return.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let delay = RefCell::new(board::init_delay(&clocks));
let btn_pin = pins.gpio15.into_pull_up_input();
let led_pin = pins.gpio25.into_push_pull_output();
let mut btn = button::ButtonDriver::init(btn_pin, board::DEBOUNCE_MS, |ms| {
delay.borrow_mut().delay_ms(ms);
});
let mut led = button::ButtonLed::init(led_pin);
uart.write_full_blocking(b"Button driver initialized: button=GPIO15 led=GPIO25\r\n");
let mut last_state = false;
loop {
let pressed = btn.is_pressed();
led.set(pressed);
if pressed != last_state {
if pressed {
uart.write_full_blocking(b"Button: PRESSED\r\n");
} else {
uart.write_full_blocking(b"Button: RELEASED\r\n");
}
last_state = pressed;
}
delay.borrow_mut().delay_ms(board::POLL_MS);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+106 -25
View File
@@ -186,28 +186,27 @@ pub(crate) fn init_delay(clocks: &hal::clocks::ClocksManager) -> cortex_m::delay
///
/// Number of bytes written into the buffer.
pub(crate) fn format_duty(buf: &mut [u8], duty: u8) -> usize {
let prefix = b"Duty: ";
buf[..6].copy_from_slice(prefix);
buf[..6].copy_from_slice(b"Duty: ");
let mut pos = 6;
if duty >= 100 {
buf[pos] = b'1'; pos += 1;
buf[pos] = b'0'; pos += 1;
buf[pos] = b'0'; pos += 1;
} else if duty >= 10 {
buf[pos] = b' '; pos += 1;
buf[pos] = b'0' + duty / 10; pos += 1;
buf[pos] = b'0' + duty % 10; pos += 1;
} else {
buf[pos] = b' '; pos += 1;
buf[pos] = b' '; pos += 1;
buf[pos] = b'0' + duty; pos += 1;
}
pos += write_duty_digits(&mut buf[pos..], duty);
buf[pos] = b'%'; pos += 1;
buf[pos] = b'\r'; pos += 1;
buf[pos] = b'\n'; pos += 1;
pos
}
/// Write the 3-character right-justified duty digits into `buf`.
fn write_duty_digits(buf: &mut [u8], duty: u8) -> usize {
if duty >= 100 {
buf[0] = b'1'; buf[1] = b'0'; buf[2] = b'0';
} else if duty >= 10 {
buf[0] = b' '; buf[1] = b'0' + duty / 10; buf[2] = b'0' + duty % 10;
} else {
buf[0] = b' '; buf[1] = b' '; buf[2] = b'0' + duty;
}
3
}
/// Sweep the PWM duty cycle from 0% to 100% in steps of 5.
///
/// # Arguments
@@ -224,11 +223,7 @@ pub(crate) fn sweep_up(
) {
let mut duty: u8 = 0;
while duty <= 100 {
let level = crate::pwm::duty_to_level(duty, PWM_WRAP) as u16;
channel.set_duty_cycle(level).ok();
let n = format_duty(buf, duty);
uart.write_full_blocking(&buf[..n]);
delay.delay_ms(50u32);
apply_duty(uart, channel, delay, buf, duty);
duty += 5;
}
}
@@ -249,13 +244,99 @@ pub(crate) fn sweep_down(
) {
let mut duty: i8 = 100;
while duty >= 0 {
let level = crate::pwm::duty_to_level(duty as u8, PWM_WRAP) as u16;
channel.set_duty_cycle(level).ok();
let n = format_duty(buf, duty as u8);
uart.write_full_blocking(&buf[..n]);
delay.delay_ms(50u32);
apply_duty(uart, channel, delay, buf, duty as u8);
duty -= 5;
}
}
/// Apply a single duty step: set PWM level, format, print, and delay.
fn apply_duty(
uart: &EnabledUart,
channel: &mut impl SetDutyCycle,
delay: &mut cortex_m::delay::Delay,
buf: &mut [u8; 16],
duty: u8,
) {
let level = crate::pwm::duty_to_level(duty, PWM_WRAP) as u16;
channel.set_duty_cycle(level).ok();
let n = format_duty(buf, duty);
uart.write_full_blocking(&buf[..n]);
delay.delay_ms(50u32);
}
/// Type alias for PWM slice 4 (onboard LED, GPIO 25).
type PwmSlice4 = hal::pwm::Slice<hal::pwm::Pwm4, hal::pwm::FreeRunning>;
/// Initialise all peripherals and run the PWM breathing demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = init_delay(&clocks);
let mut pwm = init_pwm(pac.PWM, &mut pac.RESETS, &clocks, pins.gpio25);
uart.write_full_blocking(b"PWM initialized: GPIO25 @ 1000 Hz\r\n");
pwm_loop(&uart, &mut pwm, &mut delay)
}
/// Configure PWM slice 4 for 1 kHz output on channel B (GPIO 25).
///
/// # Arguments
///
/// * `pwm_pac` - PAC PWM peripheral singleton.
/// * `resets` - Mutable reference to the RESETS peripheral.
/// * `clocks` - Reference to the initialised clock configuration.
/// * `led_pin` - Default GPIO 25 pin to bind to PWM channel B.
///
/// # Returns
///
/// Configured PWM slice 4 in free-running mode.
fn init_pwm(
pwm_pac: hal::pac::PWM,
resets: &mut hal::pac::RESETS,
clocks: &hal::clocks::ClocksManager,
led_pin: Pin<hal::gpio::bank0::Gpio25, FunctionNull, PullDown>,
) -> PwmSlice4 {
let slices = hal::pwm::Slices::new(pwm_pac, resets);
let mut slice = slices.pwm4;
configure_pwm_div(&mut slice, clocks);
slice.set_top(PWM_WRAP as u16);
slice.enable();
slice.channel_b.output_to(led_pin);
slice
}
/// Set the clock divider for a PWM slice based on the system clock.
///
/// # Arguments
///
/// * `slice` - Mutable reference to the PWM slice to configure.
/// * `clocks` - Reference to the initialised clock configuration.
fn configure_pwm_div(slice: &mut PwmSlice4, clocks: &hal::clocks::ClocksManager) {
let sys_hz = clocks.system_clock.freq().to_Hz();
let div = crate::pwm::calc_clk_div(sys_hz, PWM_FREQ_HZ, PWM_WRAP);
let div_int = div as u8;
slice.set_div_int(div_int);
slice.set_div_frac((((div - div_int as f32) * 16.0) as u8).min(15));
}
/// Run the PWM duty-cycle sweep loop forever.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
/// * `pwm` - Mutable reference to the configured PWM slice.
/// * `delay` - Mutable reference to the blocking delay provider.
fn pwm_loop(uart: &EnabledUart, pwm: &mut PwmSlice4, delay: &mut cortex_m::delay::Delay) -> ! {
let mut buf = [0u8; 16];
loop {
sweep_up(uart, &mut pwm.channel_b, delay, &mut buf);
sweep_down(uart, &mut pwm.channel_b, delay, &mut buf);
}
}
// End of file
+1 -32
View File
@@ -79,40 +79,9 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the PWM LED breathing demo.
///
/// Initializes PWM at 1 kHz on the onboard LED and enters an infinite
/// loop that sweeps the duty cycle up and down to produce a smooth
/// breathing effect, reporting each step over UART.
///
/// # Returns
///
/// Does not return.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = board::init_delay(&clocks);
uart.write_full_blocking(b"PWM initialized: GPIO25 @ 1000 Hz\r\n");
let pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS);
let mut pwm_slice = pwm_slices.pwm4;
let sys_hz = clocks.system_clock.freq().to_Hz();
let div = pwm::calc_clk_div(sys_hz, board::PWM_FREQ_HZ, board::PWM_WRAP);
let div_int = div as u8;
pwm_slice.set_div_int(div_int);
pwm_slice.set_div_frac((((div - div_int as f32) * 16.0) as u8).min(15));
pwm_slice.set_top(board::PWM_WRAP as u16);
pwm_slice.enable();
pwm_slice.channel_b.output_to(pins.gpio25);
let mut buf = [0u8; 16];
loop {
board::sweep_up(&uart, &mut pwm_slice.channel_b, &mut delay, &mut buf);
board::sweep_down(&uart, &mut pwm_slice.channel_b, &mut delay, &mut buf);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+125 -29
View File
@@ -186,28 +186,28 @@ pub(crate) fn init_delay(clocks: &hal::clocks::ClocksManager) -> cortex_m::delay
///
/// Number of bytes written into the buffer.
pub(crate) fn format_angle(buf: &mut [u8], angle: i32) -> usize {
let prefix = b"Angle: ";
buf[..7].copy_from_slice(prefix);
buf[..7].copy_from_slice(b"Angle: ");
let mut pos = 7;
let a = if angle < 0 { 0 } else { angle as u32 };
if a >= 100 {
buf[pos] = b'0' + (a / 100) as u8; pos += 1;
buf[pos] = b'0' + ((a / 10) % 10) as u8; pos += 1;
buf[pos] = b'0' + (a % 10) as u8; pos += 1;
} else if a >= 10 {
buf[pos] = b' '; pos += 1;
buf[pos] = b'0' + (a / 10) as u8; pos += 1;
buf[pos] = b'0' + (a % 10) as u8; pos += 1;
} else {
buf[pos] = b' '; pos += 1;
buf[pos] = b' '; pos += 1;
buf[pos] = b'0' + a as u8; pos += 1;
}
let suffix = b" deg\r\n";
buf[pos..pos + 6].copy_from_slice(suffix);
pos += write_angle_digits(&mut buf[pos..], a);
buf[pos..pos + 6].copy_from_slice(b" deg\r\n");
pos + 6
}
/// Write 3-character right-justified angle digits into `buf`.
fn write_angle_digits(buf: &mut [u8], a: u32) -> usize {
if a >= 100 {
buf[0] = b'0' + (a / 100) as u8;
buf[1] = b'0' + ((a / 10) % 10) as u8;
buf[2] = b'0' + (a % 10) as u8;
} else if a >= 10 {
buf[0] = b' '; buf[1] = b'0' + (a / 10) as u8; buf[2] = b'0' + (a % 10) as u8;
} else {
buf[0] = b' '; buf[1] = b' '; buf[2] = b'0' + a as u8;
}
3
}
/// Sweep the servo angle upward from 0 to 180 in STEP_DEGREES increments.
///
/// # Arguments
@@ -224,12 +224,7 @@ pub(crate) fn sweep_angle_up(
) {
let mut angle: i32 = 0;
while angle <= 180 {
let pulse = crate::servo::angle_to_pulse_us(angle as f32, crate::servo::SERVO_DEFAULT_MIN_US, crate::servo::SERVO_DEFAULT_MAX_US);
let level = crate::servo::pulse_us_to_level(pulse as u32, crate::servo::SERVO_WRAP, crate::servo::SERVO_HZ) as u16;
channel.set_duty_cycle(level).ok();
let n = format_angle(buf, angle);
uart.write_full_blocking(&buf[..n]);
delay.delay_ms(STEP_DELAY_MS);
apply_angle(uart, channel, delay, buf, angle);
angle += STEP_DEGREES;
}
}
@@ -250,14 +245,115 @@ pub(crate) fn sweep_angle_down(
) {
let mut angle: i32 = 180;
while angle >= 0 {
let pulse = crate::servo::angle_to_pulse_us(angle as f32, crate::servo::SERVO_DEFAULT_MIN_US, crate::servo::SERVO_DEFAULT_MAX_US);
let level = crate::servo::pulse_us_to_level(pulse as u32, crate::servo::SERVO_WRAP, crate::servo::SERVO_HZ) as u16;
channel.set_duty_cycle(level).ok();
let n = format_angle(buf, angle);
uart.write_full_blocking(&buf[..n]);
delay.delay_ms(STEP_DELAY_MS);
apply_angle(uart, channel, delay, buf, angle);
angle -= STEP_DEGREES;
}
}
/// Apply a single angle step: compute pulse, set PWM, format, print, delay.
fn apply_angle(
uart: &EnabledUart,
channel: &mut impl SetDutyCycle,
delay: &mut cortex_m::delay::Delay,
buf: &mut [u8; 20],
angle: i32,
) {
let level = compute_servo_level(angle) as u16;
channel.set_duty_cycle(level).ok();
let n = format_angle(buf, angle);
uart.write_full_blocking(&buf[..n]);
delay.delay_ms(STEP_DELAY_MS);
}
/// Compute the PWM level for a given angle using servo constants.
fn compute_servo_level(angle: i32) -> u32 {
let pulse = crate::servo::angle_to_pulse_us(angle as f32, crate::servo::SERVO_DEFAULT_MIN_US, crate::servo::SERVO_DEFAULT_MAX_US);
crate::servo::pulse_us_to_level(pulse as u32, crate::servo::SERVO_WRAP, crate::servo::SERVO_HZ)
}
/// Type alias for PWM slice 3 (servo on GPIO 6, channel A).
type PwmSlice3 = hal::pwm::Slice<hal::pwm::Pwm3, hal::pwm::FreeRunning>;
/// Initialise all peripherals and run the servo sweep demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = init_delay(&clocks);
let mut pwm = init_servo_pwm(pac.PWM, &mut pac.RESETS, &clocks, pins.gpio6);
announce_servo(&uart);
servo_loop(&uart, &mut pwm, &mut delay)
}
/// Configure PWM slice 3 for 50 Hz servo output on channel A (GPIO 6).
///
/// # Arguments
///
/// * `pwm_pac` - PAC PWM peripheral singleton.
/// * `resets` - Mutable reference to the RESETS peripheral.
/// * `clocks` - Reference to the initialised clock configuration.
/// * `servo_pin` - Default GPIO 6 pin to bind to PWM channel A.
///
/// # Returns
///
/// Configured PWM slice 3 in free-running mode.
fn init_servo_pwm(
pwm_pac: hal::pac::PWM,
resets: &mut hal::pac::RESETS,
clocks: &hal::clocks::ClocksManager,
servo_pin: Pin<hal::gpio::bank0::Gpio6, FunctionNull, PullDown>,
) -> PwmSlice3 {
let slices = hal::pwm::Slices::new(pwm_pac, resets);
let mut slice = slices.pwm3;
configure_servo_div(&mut slice, clocks);
slice.enable();
slice.channel_a.output_to(servo_pin);
slice
}
/// Set the clock divider and wrap for a servo PWM slice.
///
/// # Arguments
///
/// * `slice` - Mutable reference to the PWM slice to configure.
/// * `clocks` - Reference to the initialised clock configuration.
fn configure_servo_div(slice: &mut PwmSlice3, clocks: &hal::clocks::ClocksManager) {
let sys_hz = clocks.system_clock.freq().to_Hz();
let div = crate::servo::calc_clk_div(sys_hz, crate::servo::SERVO_HZ, crate::servo::SERVO_WRAP);
let div_int = div as u8;
slice.set_div_int(div_int);
slice.set_div_frac((((div - div_int as f32) * 16.0) as u8).min(15));
slice.set_top(crate::servo::SERVO_WRAP as u16);
}
/// Print the servo initialisation banner over UART.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
fn announce_servo(uart: &EnabledUart) {
uart.write_full_blocking(b"Servo driver initialized on GPIO 6\r\n");
uart.write_full_blocking(b"Sweeping 0 -> 180 -> 0 degrees in 10-degree steps\r\n");
}
/// Run the servo angle sweep loop forever.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
/// * `pwm` - Mutable reference to the configured PWM slice.
/// * `delay` - Mutable reference to the blocking delay provider.
fn servo_loop(uart: &EnabledUart, pwm: &mut PwmSlice3, delay: &mut cortex_m::delay::Delay) -> ! {
let mut buf = [0u8; 20];
loop {
sweep_angle_up(uart, &mut pwm.channel_a, delay, &mut buf);
sweep_angle_down(uart, &mut pwm.channel_a, delay, &mut buf);
}
}
// End of file
+1 -32
View File
@@ -78,40 +78,9 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the servo sweep demo.
///
/// Initializes the servo on GPIO 6 and continuously sweeps 0-180-0
/// degrees in 10-degree increments, reporting each angle over UART.
///
/// # Returns
///
/// Does not return.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = board::init_delay(&clocks);
let pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS);
let mut pwm = pwm_slices.pwm3;
let sys_hz = clocks.system_clock.freq().to_Hz();
let div = servo::calc_clk_div(sys_hz, servo::SERVO_HZ, servo::SERVO_WRAP);
let div_int = div as u8;
pwm.set_div_int(div_int);
pwm.set_div_frac((((div - div_int as f32) * 16.0) as u8).min(15));
pwm.set_top(servo::SERVO_WRAP as u16);
pwm.enable();
pwm.channel_a.output_to(pins.gpio6);
uart.write_full_blocking(b"Servo driver initialized on GPIO 6\r\n");
uart.write_full_blocking(b"Sweeping 0 -> 180 -> 0 degrees in 10-degree steps\r\n");
let mut buf = [0u8; 20];
loop {
board::sweep_angle_up(&uart, &mut pwm.channel_a, &mut delay, &mut buf);
board::sweep_angle_down(&uart, &mut pwm.channel_a, &mut delay, &mut buf);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+122 -26
View File
@@ -183,37 +183,133 @@ pub(crate) fn init_delay(clocks: &hal::clocks::ClocksManager) -> cortex_m::delay
///
/// Number of bytes written into the buffer.
pub(crate) fn format_adc_line(buf: &mut [u8], mv: u32, temp_int: i32, temp_frac: u8) -> usize {
let prefix = b"ADC0: ";
buf[..6].copy_from_slice(prefix);
buf[..6].copy_from_slice(b"ADC0: ");
let mut pos = 6;
let thousands = ((mv / 1000) % 10) as u8;
let hundreds = ((mv / 100) % 10) as u8;
let tens = ((mv / 10) % 10) as u8;
let ones = (mv % 10) as u8;
buf[pos] = b'0' + thousands; pos += 1;
buf[pos] = b'0' + hundreds; pos += 1;
buf[pos] = b'0' + tens; pos += 1;
buf[pos] = b'0' + ones; pos += 1;
let mid = b" mV | Chip temp: ";
buf[pos..pos + 19].copy_from_slice(mid);
pos += write_mv_digits(&mut buf[pos..], mv);
buf[pos..pos + 19].copy_from_slice(b" mV | Chip temp: ");
pos += 19;
let abs_temp = if temp_int < 0 { -temp_int } else { temp_int } as u32;
if temp_int < 0 {
buf[pos] = b'-'; pos += 1;
}
if abs_temp >= 100 {
buf[pos] = b'0' + ((abs_temp / 100) % 10) as u8; pos += 1;
}
if abs_temp >= 10 {
buf[pos] = b'0' + ((abs_temp / 10) % 10) as u8; pos += 1;
}
buf[pos] = b'0' + (abs_temp % 10) as u8; pos += 1;
pos += write_temp(&mut buf[pos..], temp_int, temp_frac);
buf[pos..pos + 4].copy_from_slice(b" C\r\n");
pos + 4
}
/// Write 4-digit millivolt value into `buf`.
fn write_mv_digits(buf: &mut [u8], mv: u32) -> usize {
buf[0] = b'0' + ((mv / 1000) % 10) as u8;
buf[1] = b'0' + ((mv / 100) % 10) as u8;
buf[2] = b'0' + ((mv / 10) % 10) as u8;
buf[3] = b'0' + (mv % 10) as u8;
4
}
/// Write temperature as "[-]NN.F" into `buf`.
fn write_temp(buf: &mut [u8], temp_int: i32, temp_frac: u8) -> usize {
let mut pos = 0;
let abs_temp = if temp_int < 0 { buf[pos] = b'-'; pos += 1; -temp_int } else { temp_int } as u32;
pos += write_min_digits(&mut buf[pos..], abs_temp);
buf[pos] = b'.'; pos += 1;
buf[pos] = b'0' + temp_frac; pos += 1;
let suffix = b" C\r\n";
buf[pos..pos + 4].copy_from_slice(suffix);
pos += 4;
pos
}
/// Write a u32 with minimum digits (no leading zeros).
fn write_min_digits(buf: &mut [u8], val: u32) -> usize {
let mut pos = 0;
if val >= 100 { buf[pos] = b'0' + ((val / 100) % 10) as u8; pos += 1; }
if val >= 10 { buf[pos] = b'0' + ((val / 10) % 10) as u8; pos += 1; }
buf[pos] = b'0' + (val % 10) as u8;
pos + 1
}
/// Type alias for the ADC input pin on GPIO 26.
type Gpio26Adc = hal::adc::AdcPin<Pin<hal::gpio::bank0::Gpio26, FunctionNull, PullDown>>;
/// Initialise all peripherals and run the ADC demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = init_delay(&clocks);
let (mut adc, mut adc_pin, mut temp) = init_adc(pac.ADC, pins.gpio26, &mut pac.RESETS);
uart.write_full_blocking(b"ADC driver initialized: GPIO26 (channel 0)\r\n");
adc_loop(&uart, &mut adc, &mut adc_pin, &mut temp, &mut delay)
}
/// Create the ADC peripheral, GPIO 26 input channel, and temperature sensor.
///
/// # Arguments
///
/// * `adc_pac` - PAC ADC peripheral singleton.
/// * `gpio26` - Default GPIO 26 pin to use as ADC input.
/// * `resets` - Mutable reference to the RESETS peripheral.
///
/// # Returns
///
/// Tuple of (ADC driver, ADC pin channel, temperature sensor channel).
fn init_adc(
adc_pac: hal::pac::ADC,
gpio26: Pin<hal::gpio::bank0::Gpio26, FunctionNull, PullDown>,
resets: &mut hal::pac::RESETS,
) -> (hal::Adc, Gpio26Adc, hal::adc::TempSense) {
let mut adc = hal::Adc::new(adc_pac, resets);
let pin = hal::adc::AdcPin::new(gpio26).unwrap();
let temp = adc.take_temp_sensor().unwrap();
(adc, pin, temp)
}
/// Sample voltage and temperature, format, and print in a loop.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
/// * `adc` - Mutable reference to the ADC driver.
/// * `adc_pin` - Mutable reference to the GPIO 26 ADC channel.
/// * `temp` - Mutable reference to the temperature sensor channel.
/// * `delay` - Mutable reference to the blocking delay provider.
fn adc_loop(
uart: &EnabledUart,
adc: &mut hal::Adc,
adc_pin: &mut Gpio26Adc,
temp: &mut hal::adc::TempSense,
delay: &mut cortex_m::delay::Delay,
) -> ! {
let mut buf = [0u8; 48];
loop {
let (mv, temp_int, temp_frac) = read_adc(adc, adc_pin, temp);
let n = format_adc_line(&mut buf, mv, temp_int, temp_frac);
uart.write_full_blocking(&buf[..n]);
delay.delay_ms(POLL_MS);
}
}
/// Read voltage and temperature from the ADC.
///
/// # Arguments
///
/// * `adc` - Mutable reference to the ADC driver.
/// * `adc_pin` - Mutable reference to the GPIO 26 ADC channel.
/// * `temp` - Mutable reference to the temperature sensor channel.
///
/// # Returns
///
/// Tuple of (millivolts, integer temperature, fractional temperature digit).
fn read_adc(
adc: &mut hal::Adc,
adc_pin: &mut Gpio26Adc,
temp: &mut hal::adc::TempSense,
) -> (u32, i32, u8) {
let raw_v: u16 = adc.read(adc_pin).unwrap();
let mv = crate::adc::raw_to_mv(raw_v);
let raw_t: u16 = adc.read(temp).unwrap();
let celsius = crate::adc::raw_to_celsius(raw_t);
let temp_int = celsius as i32;
let temp_frac = (((celsius - temp_int as f32) * 10.0) as u8).min(9);
(mv, temp_int, temp_frac)
}
// End of file
+1 -31
View File
@@ -78,39 +78,9 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the ADC voltage and temperature demo.
///
/// Initializes the ADC on GPIO26 channel 0 and prints readings
/// every 500 ms over UART.
///
/// # Returns
///
/// Does not return.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = board::init_delay(&clocks);
let mut adc_hw = hal::Adc::new(pac.ADC, &mut pac.RESETS);
let mut adc_pin = hal::adc::AdcPin::new(pins.gpio26).unwrap();
let mut temp_sensor = adc_hw.take_temp_sensor().unwrap();
uart.write_full_blocking(b"ADC driver initialized: GPIO26 (channel 0)\r\n");
let mut buf = [0u8; 48];
loop {
let raw_v: u16 = adc_hw.read(&mut adc_pin).unwrap();
let mv = adc::raw_to_mv(raw_v);
let raw_t: u16 = adc_hw.read(&mut temp_sensor).unwrap();
let temp = adc::raw_to_celsius(raw_t);
let temp_int = temp as i32;
let temp_frac = (((temp - temp_int as f32) * 10.0) as u8).min(9);
let n = board::format_adc_line(&mut buf, mv, temp_int, temp_frac);
uart.write_full_blocking(&buf[..n]);
delay.delay_ms(board::POLL_MS);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+74 -1
View File
@@ -32,7 +32,7 @@ use fugit::RateExtU32;
// Clock trait for accessing system clock frequency
use hal::Clock;
// GPIO pin types and function selectors
use hal::gpio::{FunctionNull, FunctionUart, Pin, PullDown, PullNone};
use hal::gpio::{FunctionI2C, FunctionNull, FunctionUart, Pin, PullDown, PullNone, PullUp};
// UART configuration and peripheral types
use hal::uart::{DataBits, Enabled, StopBits, UartConfig, UartPeripheral};
@@ -190,4 +190,77 @@ pub(crate) fn probe_addr(i2c: &mut impl I2c, addr: u8) -> bool {
i2c.read(addr, &mut dummy).is_ok()
}
/// Initialise all peripherals and run the I2C bus scanner demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = init_delay(&clocks);
let mut i2c = init_i2c(pac.I2C1, pins.gpio2, pins.gpio3, &mut pac.RESETS, &clocks);
uart.write_full_blocking(b"I2C driver initialized: I2C1 @ 100000 Hz SDA=GPIO2 SCL=GPIO3\r\n");
scan_loop(&uart, &mut i2c, &mut delay)
}
/// Initialise I2C1 on SDA=GPIO2 / SCL=GPIO3.
///
/// # Arguments
///
/// * `i2c1` - PAC I2C1 peripheral singleton.
/// * `sda` - Default GPIO 2 pin (will be reconfigured for I2C).
/// * `scl` - Default GPIO 3 pin (will be reconfigured for I2C).
/// * `resets` - Mutable reference to the RESETS peripheral.
/// * `clocks` - Reference to the initialised clock configuration.
///
/// # Returns
///
/// Configured I2C1 bus controller.
fn init_i2c(
i2c1: hal::pac::I2C1,
sda: Pin<hal::gpio::bank0::Gpio2, FunctionNull, PullDown>,
scl: Pin<hal::gpio::bank0::Gpio3, FunctionNull, PullDown>,
resets: &mut hal::pac::RESETS,
clocks: &hal::clocks::ClocksManager,
) -> impl I2c {
let sda = sda.reconfigure::<FunctionI2C, PullUp>();
let scl = scl.reconfigure::<FunctionI2C, PullUp>();
hal::I2C::i2c1(i2c1, sda, scl, I2C_BAUD.Hz(), resets, clocks.system_clock.freq())
}
/// Run the I2C address scan loop forever.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
/// * `i2c` - Mutable reference to the I2C bus controller.
/// * `delay` - Mutable reference to the blocking delay provider.
fn scan_loop(uart: &EnabledUart, i2c: &mut impl I2c, delay: &mut cortex_m::delay::Delay) -> ! {
let mut buf = [0u8; 80];
loop {
let n = crate::i2c::format_scan_header(&mut buf);
uart.write_full_blocking(&buf[..n]);
scan_addresses(uart, i2c, &mut buf);
delay.delay_ms(SCAN_DELAY_MS);
}
}
/// Scan all 128 addresses and print the formatted result.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
/// * `i2c` - Mutable reference to the I2C bus controller.
/// * `buf` - Scratch buffer for formatting output.
fn scan_addresses(uart: &EnabledUart, i2c: &mut impl I2c, buf: &mut [u8; 80]) {
for addr in 0u8..128 {
let found = !crate::i2c::is_reserved(addr) && probe_addr(i2c, addr);
let n = crate::i2c::format_scan_entry(buf, addr, found);
uart.write_full_blocking(&buf[..n]);
}
}
// End of file
+27 -24
View File
@@ -87,33 +87,36 @@ pub fn format_scan_header(buf: &mut [u8]) -> usize {
///
/// Number of bytes written into the buffer.
pub fn format_scan_entry(buf: &mut [u8], addr: u8, found: bool) -> usize {
let mut pos = 0;
if addr % 16 == 0 {
buf[pos] = hex_digit((addr >> 4) & 0x0F); pos += 1;
buf[pos] = hex_digit(addr & 0x0F); pos += 1;
buf[pos] = b':'; pos += 1;
buf[pos] = b' '; pos += 1;
}
if is_reserved(addr) {
buf[pos] = b' '; pos += 1;
buf[pos] = b' '; pos += 1;
buf[pos] = b' '; pos += 1;
} else if found {
buf[pos] = hex_digit((addr >> 4) & 0x0F); pos += 1;
buf[pos] = hex_digit(addr & 0x0F); pos += 1;
buf[pos] = b' '; pos += 1;
} else {
buf[pos] = b'-'; pos += 1;
buf[pos] = b'-'; pos += 1;
buf[pos] = b' '; pos += 1;
}
if addr % 16 == 15 {
buf[pos] = b'\r'; pos += 1;
buf[pos] = b'\n'; pos += 1;
}
let mut pos = format_row_prefix(buf, addr);
pos += format_cell(&mut buf[pos..], addr, found);
if addr % 16 == 15 { buf[pos] = b'\r'; pos += 1; buf[pos] = b'\n'; pos += 1; }
pos
}
/// Write the row prefix ("XX: ") if addr is at a 16-byte boundary.
fn format_row_prefix(buf: &mut [u8], addr: u8) -> usize {
if addr % 16 != 0 { return 0; }
buf[0] = hex_digit((addr >> 4) & 0x0F);
buf[1] = hex_digit(addr & 0x0F);
buf[2] = b':';
buf[3] = b' ';
4
}
/// Write a single cell: "XX " if found, "-- " if not, " " if reserved.
fn format_cell(buf: &mut [u8], addr: u8, found: bool) -> usize {
let cell = cell_bytes(addr, found);
buf[..3].copy_from_slice(&cell);
3
}
/// Return the 3-byte cell content for an I2C scan address.
fn cell_bytes(addr: u8, found: bool) -> [u8; 3] {
if is_reserved(addr) { return [b' ', b' ', b' ']; }
if found { [hex_digit((addr >> 4) & 0x0F), hex_digit(addr & 0x0F), b' '] }
else { [b'-', b'-', b' '] }
}
#[cfg(test)]
mod tests {
// Import all parent module items
+1 -40
View File
@@ -56,14 +56,8 @@ use panic_halt as _;
#[cfg(target_arch = "arm")]
use panic_probe as _;
// Rate extension trait for .Hz() baud rate construction
use fugit::RateExtU32;
// Clock trait for accessing system clock frequency
use hal::Clock;
// HAL entry-point macro
use hal::entry;
// GPIO traits for I2C pin reconfiguration
use hal::gpio::{FunctionI2C, PullUp};
// Alias our HAL crate
#[cfg(rp2350)]
@@ -84,42 +78,9 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the I2C bus scanner demo.
///
/// Initializes I2C1 at 100 kHz on SDA=GPIO2 / SCL=GPIO3 and prints
/// a formatted hex table of all responding device addresses over UART,
/// repeating every 5 seconds.
///
/// # Returns
///
/// Does not return.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = board::init_delay(&clocks);
let sda_pin = pins.gpio2.reconfigure::<FunctionI2C, PullUp>();
let scl_pin = pins.gpio3.reconfigure::<FunctionI2C, PullUp>();
let mut i2c = hal::I2C::i2c1(
pac.I2C1, sda_pin, scl_pin, board::I2C_BAUD.Hz(),
&mut pac.RESETS, clocks.system_clock.freq(),
);
uart.write_full_blocking(b"I2C driver initialized: I2C1 @ 100000 Hz SDA=GPIO2 SCL=GPIO3\r\n");
let mut buf = [0u8; 80];
loop {
let n = i2c::format_scan_header(&mut buf);
uart.write_full_blocking(&buf[..n]);
for addr in 0u8..128 {
let found = !i2c::is_reserved(addr) && board::probe_addr(&mut i2c, addr);
let n = i2c::format_scan_entry(&mut buf, addr, found);
uart.write_full_blocking(&buf[..n]);
}
delay.delay_ms(board::SCAN_DELAY_MS);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+85 -8
View File
@@ -32,7 +32,7 @@ use fugit::RateExtU32;
// Clock trait for accessing system clock frequency
use hal::Clock;
// GPIO pin types and function selectors
use hal::gpio::{FunctionNull, FunctionUart, Pin, PullDown, PullNone};
use hal::gpio::{FunctionI2C, FunctionNull, FunctionUart, Pin, PullDown, PullNone, PullUp};
// UART configuration and peripheral types
use hal::uart::{DataBits, Enabled, StopBits, UartConfig, UartPeripheral};
@@ -246,14 +246,19 @@ fn lcd_send(i2c: &mut impl I2c, addr: u8, value: u8, mode: u8, delay: &mut corte
/// * `addr` - 7-bit I2C address of the PCF8574.
/// * `delay` - Delay provider for timing.
fn lcd_hd44780_reset(i2c: &mut impl I2c, addr: u8, delay: &mut cortex_m::delay::Delay) {
lcd_reset_pulse_3x(i2c, addr, delay);
lcd_write4(i2c, addr, 0x02, 0, delay);
delay.delay_us(150);
}
/// Send three 0x03 nibbles with required power-on delays.
fn lcd_reset_pulse_3x(i2c: &mut impl I2c, addr: u8, delay: &mut cortex_m::delay::Delay) {
lcd_write4(i2c, addr, 0x03, 0, delay);
delay.delay_ms(5);
lcd_write4(i2c, addr, 0x03, 0, delay);
delay.delay_us(150);
lcd_write4(i2c, addr, 0x03, 0, delay);
delay.delay_us(150);
lcd_write4(i2c, addr, 0x02, 0, delay);
delay.delay_us(150);
}
/// Send post-reset configuration commands to the HD44780.
@@ -312,9 +317,14 @@ pub(crate) fn setup_display(
) {
lcd_hd44780_reset(i2c, LCD_I2C_ADDR, delay);
lcd_hd44780_configure(i2c, LCD_I2C_ADDR, delay);
lcd_show_title(i2c, delay);
uart.write_full_blocking(b"LCD 1602 driver initialized at I2C addr 0x27\r\n");
}
/// Write the title text on LCD row 0.
fn lcd_show_title(i2c: &mut impl I2c, delay: &mut cortex_m::delay::Delay) {
lcd_set_cursor(i2c, LCD_I2C_ADDR, 0, 0, delay);
lcd_puts(i2c, LCD_I2C_ADDR, b"Reverse Eng.", delay);
uart.write_full_blocking(b"LCD 1602 driver initialized at I2C addr 0x27\r\n");
}
/// Format and display the next counter value on LCD line 1.
@@ -334,11 +344,78 @@ pub(crate) fn update_counter(
let mut buf = [0u8; 16];
let n = crate::lcd1602::format_counter(&mut buf, *count);
*count += 1;
lcd_set_cursor(i2c, LCD_I2C_ADDR, 1, 0, delay);
lcd_puts(i2c, LCD_I2C_ADDR, &buf[..n], delay);
uart.write_full_blocking(&buf[..n]);
uart.write_full_blocking(b"\r\n");
lcd_display_counter(i2c, delay, &buf[..n]);
uart_log_counter(uart, &buf[..n]);
delay.delay_ms(COUNTER_DELAY_MS);
}
/// Write counter text to LCD line 1.
fn lcd_display_counter(i2c: &mut impl I2c, delay: &mut cortex_m::delay::Delay, text: &[u8]) {
lcd_set_cursor(i2c, LCD_I2C_ADDR, 1, 0, delay);
lcd_puts(i2c, LCD_I2C_ADDR, text, delay);
}
/// Log counter text over UART with trailing CRLF.
fn uart_log_counter(uart: &EnabledUart, text: &[u8]) {
uart.write_full_blocking(text);
uart.write_full_blocking(b"\r\n");
}
/// Initialise all peripherals and run the LCD 1602 counter demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = init_delay(&clocks);
let mut i2c = init_i2c(pac.I2C1, pins.gpio2, pins.gpio3, &mut pac.RESETS, &clocks);
setup_display(&mut i2c, &uart, &mut delay);
counter_loop(&mut i2c, &uart, &mut delay)
}
/// Initialise I2C1 on SDA=GPIO2 / SCL=GPIO3.
///
/// # Arguments
///
/// * `i2c1` - PAC I2C1 peripheral singleton.
/// * `sda` - Default GPIO 2 pin (will be reconfigured for I2C).
/// * `scl` - Default GPIO 3 pin (will be reconfigured for I2C).
/// * `resets` - Mutable reference to the RESETS peripheral.
/// * `clocks` - Reference to the initialised clock configuration.
///
/// # Returns
///
/// Configured I2C1 bus controller.
fn init_i2c(
i2c1: hal::pac::I2C1,
sda: Pin<hal::gpio::bank0::Gpio2, FunctionNull, PullDown>,
scl: Pin<hal::gpio::bank0::Gpio3, FunctionNull, PullDown>,
resets: &mut hal::pac::RESETS,
clocks: &hal::clocks::ClocksManager,
) -> impl I2c {
let sda = sda.reconfigure::<FunctionI2C, PullUp>();
let scl = scl.reconfigure::<FunctionI2C, PullUp>();
hal::I2C::i2c1(i2c1, sda, scl, I2C_BAUD.Hz(), resets, clocks.system_clock.freq())
}
/// Run the counter display loop forever.
///
/// # Arguments
///
/// * `i2c` - Mutable reference to the I2C bus controller.
/// * `uart` - Reference to the enabled UART peripheral for serial output.
/// * `delay` - Mutable reference to the blocking delay provider.
fn counter_loop(
i2c: &mut impl I2c,
uart: &EnabledUart,
delay: &mut cortex_m::delay::Delay,
) -> ! {
let mut count: u32 = 0;
loop { update_counter(i2c, uart, delay, &mut count); }
}
// End of file
+1 -32
View File
@@ -56,14 +56,8 @@ use panic_halt as _;
#[cfg(target_arch = "arm")]
use panic_probe as _;
// Rate extension trait for .Hz() baud rate construction
use fugit::RateExtU32;
// Clock trait for accessing system clock frequency
use hal::Clock;
// HAL entry-point macro
use hal::entry;
// GPIO traits for I2C pin reconfiguration
use hal::gpio::{FunctionI2C, PullUp};
// Alias our HAL crate
#[cfg(rp2350)]
@@ -84,34 +78,9 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the LCD 1602 counter demo.
///
/// Initializes the LCD over I2C with a static title on line 0 and
/// continuously increments a counter on line 1 every second.
///
/// # Returns
///
/// Does not return.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = board::init_delay(&clocks);
let sda_pin = pins.gpio2.reconfigure::<FunctionI2C, PullUp>();
let scl_pin = pins.gpio3.reconfigure::<FunctionI2C, PullUp>();
let mut i2c = hal::I2C::i2c1(
pac.I2C1, sda_pin, scl_pin, board::I2C_BAUD.Hz(),
&mut pac.RESETS, clocks.system_clock.freq(),
);
board::setup_display(&mut i2c, &uart, &mut delay);
let mut count: u32 = 0;
loop {
board::update_counter(&mut i2c, &uart, &mut delay, &mut count);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+20
View File
@@ -382,4 +382,24 @@ pub(crate) fn poll_sensor(
delay.delay_ms(POLL_MS);
}
/// Initialise all peripherals and run the DHT11 sensor demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = init_delay(&clocks);
#[cfg(rp2350)]
let timer = hal::Timer::new_timer0(pac.TIMER0, &mut pac.RESETS, &clocks);
#[cfg(rp2040)]
let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);
let _ = pins.gpio4.into_pull_up_input();
uart.write_full_blocking(b"DHT11 driver initialized on GPIO 4\r\n");
loop { poll_sensor(&uart, &timer, &mut delay); }
}
// End of file
+25 -21
View File
@@ -111,21 +111,20 @@ pub fn parse_temperature(data: &[u8; 5]) -> f32 {
///
/// Number of bytes written into the buffer.
pub fn format_reading(buf: &mut [u8], humidity: f32, temperature: f32) -> usize {
let mut pos = 0;
let prefix = b"Humidity: ";
buf[pos..pos + prefix.len()].copy_from_slice(prefix);
pos += prefix.len();
let mut pos = copy_slice(buf, 0, b"Humidity: ");
pos += format_f32_1(&mut buf[pos..], humidity);
let mid = b"% Temperature: ";
buf[pos..pos + mid.len()].copy_from_slice(mid);
pos += mid.len();
pos += copy_slice(buf, pos, b"% Temperature: ");
pos += format_f32_1(&mut buf[pos..], temperature);
let suffix = b" C";
buf[pos..pos + suffix.len()].copy_from_slice(suffix);
pos += suffix.len();
pos += copy_slice(buf, pos, b" C");
pos
}
/// Copy a byte slice into `buf` at the given offset, returning bytes written.
fn copy_slice(buf: &mut [u8], offset: usize, src: &[u8]) -> usize {
buf[offset..offset + src.len()].copy_from_slice(src);
src.len()
}
/// Format a failed-read error message.
///
/// # Arguments
@@ -185,17 +184,7 @@ fn format_f32_1(buf: &mut [u8], val: f32) -> usize {
let scaled = (val * 10.0) as u32;
let integer = scaled / 10;
let frac = (scaled % 10) as u8;
let mut pos = 0;
if integer >= 100 {
buf[pos] = b'0' + (integer / 100) as u8;
pos += 1;
}
if integer >= 10 {
buf[pos] = b'0' + ((integer / 10) % 10) as u8;
pos += 1;
}
buf[pos] = b'0' + (integer % 10) as u8;
pos += 1;
let mut pos = format_u32_minimal(buf, integer);
buf[pos] = b'.';
pos += 1;
buf[pos] = b'0' + frac;
@@ -203,6 +192,21 @@ fn format_f32_1(buf: &mut [u8], val: f32) -> usize {
pos
}
/// Format a u32 as minimal decimal digits (no leading zeros).
fn format_u32_minimal(buf: &mut [u8], value: u32) -> usize {
let mut pos = 0;
if value >= 100 {
buf[pos] = b'0' + (value / 100) as u8;
pos += 1;
}
if value >= 10 {
buf[pos] = b'0' + ((value / 10) % 10) as u8;
pos += 1;
}
buf[pos] = b'0' + (value % 10) as u8;
pos + 1
}
#[cfg(test)]
mod tests {
// Import all parent module items
+1 -24
View File
@@ -78,32 +78,9 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the DHT11 sensor demo.
///
/// Initializes the DHT11 on GPIO4 and continuously reads temperature
/// and humidity, printing results over UART every 2 seconds.
///
/// # Returns
///
/// Does not return.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = board::init_delay(&clocks);
#[cfg(rp2350)]
let timer = hal::Timer::new_timer0(pac.TIMER0, &mut pac.RESETS, &clocks);
#[cfg(rp2040)]
let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);
let _dht_pin = pins.gpio4.into_pull_up_input();
uart.write_full_blocking(b"DHT11 driver initialized on GPIO 4\r\n");
loop {
board::poll_sensor(&uart, &timer, &mut delay);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+33 -1
View File
@@ -216,4 +216,36 @@ pub(crate) fn poll_receiver(
uart.write_full_blocking(&buf[..len]);
}
delay.delay_ms(POLL_MS);
}
}
/// Initialise all peripherals and run the NEC IR receiver demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = init_delay(&clocks);
#[cfg(rp2350)]
let timer = hal::Timer::new_timer0(pac.TIMER0, &mut pac.RESETS, &clocks);
#[cfg(rp2040)]
let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);
let _ = pins.gpio5.into_pull_up_input();
announce_ir(&uart);
loop { poll_receiver(&uart, &timer, &mut delay); }
}
/// Print the IR driver initialisation banner over UART.
///
/// # Arguments
///
/// * `uart` - Reference to the enabled UART peripheral for serial output.
fn announce_ir(uart: &EnabledUart) {
uart.write_full_blocking(b"NEC IR driver initialized on GPIO 5\r\n");
uart.write_full_blocking(b"Press a button on your NEC remote...\r\n");
}
// End of file
+24 -25
View File
@@ -98,39 +98,38 @@ pub fn validate_nec_frame(data: &[u8; 4]) -> Option<u8> {
/// Format the decoded command as hexadecimal and decimal followed by CRLF.
pub fn format_command(buf: &mut [u8], command: u8) -> usize {
let mut pos = 0;
let prefix = b"NEC command: 0x";
buf[pos..pos + prefix.len()].copy_from_slice(prefix);
pos += prefix.len();
let mut pos = copy_slice(buf, 0, prefix);
pos += format_hex_u8(buf, pos, command);
let middle = b" (";
buf[pos..pos + middle.len()].copy_from_slice(middle);
pos += middle.len();
pos += copy_slice(buf, pos, b" (");
pos += format_u8(buf, pos, command);
buf[pos] = b')';
pos += 1;
buf[pos] = b'\r';
pos += 1;
buf[pos] = b'\n';
pos += 1;
pos += copy_slice(buf, pos, b")\r\n");
pos
}
/// Copy a byte slice into `buf` at the given offset, returning bytes written.
fn copy_slice(buf: &mut [u8], offset: usize, src: &[u8]) -> usize {
buf[offset..offset + src.len()].copy_from_slice(src);
src.len()
}
/// Format an unsigned 8-bit integer at the given buffer offset.
fn format_u8(buf: &mut [u8], pos: usize, value: u8) -> usize {
if value >= 100 {
buf[pos] = b'0' + value / 100;
buf[pos + 1] = b'0' + (value / 10) % 10;
buf[pos + 2] = b'0' + value % 10;
3
} else if value >= 10 {
buf[pos] = b'0' + value / 10;
buf[pos + 1] = b'0' + value % 10;
2
} else {
buf[pos] = b'0' + value;
1
}
let n = u8_digit_count(value);
write_u8_digits(buf, pos, value, n);
n
}
/// Return the number of decimal digits in a u8.
fn u8_digit_count(value: u8) -> usize {
if value >= 100 { 3 } else if value >= 10 { 2 } else { 1 }
}
/// Write the decimal digits of a u8 into `buf` at `pos`.
fn write_u8_digits(buf: &mut [u8], pos: usize, value: u8, n: usize) {
if n >= 3 { buf[pos] = b'0' + value / 100; }
if n >= 2 { buf[pos + n - 2] = b'0' + (value / 10) % 10; }
buf[pos + n - 1] = b'0' + value % 10;
}
/// Format an unsigned 8-bit integer as two uppercase hexadecimal digits.
+1 -18
View File
@@ -79,24 +79,7 @@ pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the NEC IR receiver demo.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = board::init_delay(&clocks);
#[cfg(rp2350)]
let timer = hal::Timer::new_timer0(pac.TIMER0, &mut pac.RESETS, &clocks);
#[cfg(rp2040)]
let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);
let _ir_pin = pins.gpio5.into_pull_up_input();
uart.write_full_blocking(b"NEC IR driver initialized on GPIO 5\r\n");
uart.write_full_blocking(b"Press a button on your NEC remote...\r\n");
loop {
board::poll_receiver(&uart, &timer, &mut delay);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+21 -1
View File
@@ -196,4 +196,24 @@ pub(crate) fn loopback_transfer(
uart.write_full_blocking(&line_buf[..rx_len]);
spi::clear_rx_buffer(&mut rx);
delay.delay_ms(POLL_MS);
}
}
/// Initialise all peripherals and run the SPI loopback demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let pins = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = init_delay(&clocks);
let (mut spi, mut cs) = init_spi(
pac.SPI0, pins.gpio16, pins.gpio17, pins.gpio18, pins.gpio19, &mut pac.RESETS, &clocks,
);
uart.write_full_blocking(b"SPI driver initialized on SPI0 at 1000000 Hz\r\n");
loop { loopback_transfer(&mut spi, &mut cs, &uart, &mut delay); }
}
// End of file
+1 -21
View File
@@ -78,27 +78,7 @@ pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the SPI loopback demo.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let pins = board::init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = board::init_delay(&clocks);
let (mut spi_dev, mut cs) = board::init_spi(
pac.SPI0,
pins.gpio16,
pins.gpio17,
pins.gpio18,
pins.gpio19,
&mut pac.RESETS,
&clocks,
);
uart.write_full_blocking(b"SPI driver initialized on SPI0 at 1000000 Hz\r\n");
loop {
board::loopback_transfer(&mut spi_dev, &mut cs, &uart, &mut delay);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+16 -13
View File
@@ -77,22 +77,25 @@ fn format_line(buf: &mut [u8], prefix: &[u8], text: &[u8], extra_blank_line: boo
let mut pos = 0;
buf[pos..pos + prefix.len()].copy_from_slice(prefix);
pos += prefix.len();
let text_len = c_string_len(text);
buf[pos..pos + text_len].copy_from_slice(&text[..text_len]);
pos += text_len;
buf[pos] = b'\r';
pos += 1;
buf[pos] = b'\n';
pos += 1;
if extra_blank_line {
buf[pos] = b'\r';
pos += 1;
buf[pos] = b'\n';
pos += 1;
}
pos += copy_c_string(&mut buf[pos..], text);
pos += append_crlf(&mut buf[pos..], extra_blank_line);
pos
}
/// Copy bytes from `text` up to the first NUL into `buf`.
fn copy_c_string(buf: &mut [u8], text: &[u8]) -> usize {
let len = c_string_len(text);
buf[..len].copy_from_slice(&text[..len]);
len
}
/// Append CRLF (and optionally a second blank CRLF) to `buf`.
fn append_crlf(buf: &mut [u8], extra: bool) -> usize {
buf[0] = b'\r';
buf[1] = b'\n';
if extra { buf[2] = b'\r'; buf[3] = b'\n'; 4 } else { 2 }
}
/// Return the length up to the first NUL byte or full slice length.
fn c_string_len(text: &[u8]) -> usize {
let mut len = 0usize;
+18
View File
@@ -165,3 +165,21 @@ pub(crate) fn send_and_print(
*counter = counter.wrapping_add(1);
delay.delay_ms(POLL_MS);
}
/// Initialise all peripherals and run the multicore FIFO demo.
///
/// # Arguments
///
/// * `pac` - PAC Peripherals singleton (consumed).
pub(crate) fn run(mut pac: hal::pac::Peripherals) -> ! {
let mut wd = hal::Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks(pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut wd);
let (pins, mut fifo) = init_pins(pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS);
let uart = init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = init_delay(&clocks);
spawn_core1(&mut pac.PSM, &mut pac.PPB, &mut fifo);
let mut counter = 0u32;
loop { send_and_print(&mut fifo, &uart, &mut counter, &mut delay); }
}
// End of file
+1 -15
View File
@@ -76,21 +76,7 @@ pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
/// Application entry point for the multicore FIFO demo.
#[entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let clocks = board::init_clocks(
pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS,
&mut hal::Watchdog::new(pac.WATCHDOG),
);
let (pins, mut fifo) = board::init_pins(
pac.IO_BANK0, pac.PADS_BANK0, pac.SIO, &mut pac.RESETS,
);
let uart = board::init_uart(pac.UART0, pins.gpio0, pins.gpio1, &mut pac.RESETS, &clocks);
let mut delay = board::init_delay(&clocks);
board::spawn_core1(&mut pac.PSM, &mut pac.PPB, &mut fifo);
let mut counter = 0u32;
loop {
board::send_and_print(&mut fifo, &uart, &mut counter, &mut delay);
}
board::run(hal::pac::Peripherals::take().unwrap())
}
// Picotool binary info metadata
+19 -9
View File
@@ -37,17 +37,27 @@ fn format_u32(buf: &mut [u8], value: u32) -> usize {
return 1;
}
let mut tmp = [0u8; 10];
let mut pos = 0usize;
let mut v = value;
while v > 0 {
tmp[pos] = b'0' + (v % 10) as u8;
v /= 10;
pos += 1;
let n = u32_to_digits_reversed(&mut tmp, value);
reverse_copy(buf, &tmp, n);
n
}
/// Convert a u32 to reversed decimal digits in a temporary buffer.
fn u32_to_digits_reversed(tmp: &mut [u8; 10], mut value: u32) -> usize {
let mut n = 0usize;
while value > 0 {
tmp[n] = b'0' + (value % 10) as u8;
value /= 10;
n += 1;
}
for i in 0..pos {
buf[i] = tmp[pos - 1 - i];
n
}
/// Copy digits from a reversed temporary buffer into the output buffer.
fn reverse_copy(buf: &mut [u8], tmp: &[u8], n: usize) {
for i in 0..n {
buf[i] = tmp[n - 1 - i];
}
pos
}
/// Format the round-trip message for UART output.

Some files were not shown because too many files have changed in this diff Show More