From 10ffbc39d220f8121a9bde47fb6e59bddd967bf8 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 14 Jan 2026 23:45:58 +0800 Subject: [PATCH 1/4] Update embedded-hal to 1.0 Signed-off-by: Daniel Schaefer --- Cargo.toml | 2 +- examples/adafruit_rgb/Cargo.toml | 2 +- examples/adafruit_rgb/examples/stm32.rs | 2 +- examples/ledmatrix/Cargo.toml | 2 +- examples/ledmatrix/examples/ledtest.rs | 2 +- src/devices.rs | 54 ++++++++++--------------- src/lib.rs | 43 +++++++++----------- 7 files changed, 45 insertions(+), 62 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c45b768..cdd9765 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/FrameworkComputer/is31fl3741-rs" readme = "README.md" [dependencies] -embedded-hal = "0.2.7" +embedded-hal = "1.0" embedded-graphics-core = { optional = true, version = "0.4.0" } [package.metadata.docs.rs] diff --git a/examples/adafruit_rgb/Cargo.toml b/examples/adafruit_rgb/Cargo.toml index 96a77cb..eabca54 100644 --- a/examples/adafruit_rgb/Cargo.toml +++ b/examples/adafruit_rgb/Cargo.toml @@ -6,7 +6,7 @@ publish = false [dependencies] is31fl3741 = { path = "../../", features = [ "adafruit_rgb_13x9", "embedded_graphics" ] } -embedded-hal = "0.2.7" +embedded-hal = "1.0" cortex-m-rt = "0.7.3" cortex-m = "0.7.7" fugit = "0.3.7" diff --git a/examples/adafruit_rgb/examples/stm32.rs b/examples/adafruit_rgb/examples/stm32.rs index bb25f4e..71d3b4f 100644 --- a/examples/adafruit_rgb/examples/stm32.rs +++ b/examples/adafruit_rgb/examples/stm32.rs @@ -45,7 +45,7 @@ fn main() -> ! { matrix .pixel_rgb(x, y, 0x1E, 0x90, 0xFF) .expect("couldn't turn on"); - delay.delay_ms(100u8); + delay.delay_ms(100_u32); matrix.pixel_rgb(x, y, 0, 0, 0).expect("couldn't turn off"); } } diff --git a/examples/ledmatrix/Cargo.toml b/examples/ledmatrix/Cargo.toml index 01a82ba..4431586 100644 --- a/examples/ledmatrix/Cargo.toml +++ b/examples/ledmatrix/Cargo.toml @@ -6,7 +6,7 @@ publish = false [dependencies] is31fl3741 = { path = "../../", features = ["framework_ledmatrix"] } -embedded-hal = "0.2.7" +embedded-hal = "1.0" cortex-m-rt = "0.7.3" cortex-m = "0.7.7" fugit = "0.3.7" diff --git a/examples/ledmatrix/examples/ledtest.rs b/examples/ledmatrix/examples/ledtest.rs index 20dcea4..963f489 100644 --- a/examples/ledmatrix/examples/ledtest.rs +++ b/examples/ledmatrix/examples/ledtest.rs @@ -8,7 +8,7 @@ #![no_main] #![allow(clippy::needless_range_loop)] -use embedded_hal::digital::v2::{InputPin, OutputPin}; +use embedded_hal::digital::{InputPin, OutputPin}; use rp2040_hal::rom_data::reset_to_usb_boot; use rp2040_panic_usb_boot as _; diff --git a/src/devices.rs b/src/devices.rs index 5521980..5a19eb8 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -4,11 +4,9 @@ use crate::{Error, IS31FL3741}; #[allow(unused_imports)] use core::convert::TryFrom; #[allow(unused_imports)] -use embedded_hal::blocking::delay::DelayMs; +use embedded_hal::delay::DelayNs; #[allow(unused_imports)] -use embedded_hal::blocking::i2c::Read; -#[allow(unused_imports)] -use embedded_hal::blocking::i2c::Write; +use embedded_hal::i2c::I2c; #[cfg(feature = "adafruit_rgb_13x9")] pub struct AdafruitRGB13x9 { @@ -19,25 +17,16 @@ pub struct AdafruitRGB13x9 { use embedded_graphics_core::{pixelcolor::Rgb888, prelude::*, primitives::Rectangle}; #[cfg(all(feature = "adafruit_rgb_13x9", feature = "embedded_graphics"))] -impl Dimensions for AdafruitRGB13x9 -where - I2C: Write, - I2C: Read, -{ +impl Dimensions for AdafruitRGB13x9 { fn bounding_box(&self) -> Rectangle { Rectangle::new(Point::zero(), Size::new(13, 9)) } } #[cfg(all(feature = "adafruit_rgb_13x9", feature = "embedded_graphics"))] -impl DrawTarget for AdafruitRGB13x9 -where - I2C: Write, - I2C: Read, - I2cError:, -{ +impl DrawTarget for AdafruitRGB13x9 { type Color = Rgb888; - type Error = Error; + type Error = Error; fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> where @@ -58,16 +47,12 @@ where } #[cfg(feature = "adafruit_rgb_13x9")] -impl AdafruitRGB13x9 -where - I2C: Write, - I2C: Read, -{ +impl AdafruitRGB13x9 { pub fn unwrap(self) -> I2C { self.device.i2c } - pub fn set_scaling(&mut self, scale: u8) -> Result<(), I2cError> { + pub fn set_scaling(&mut self, scale: u8) -> Result<(), I2C::Error> { self.device.set_scaling(scale) } @@ -209,7 +194,14 @@ where } } - pub fn pixel_rgb(&mut self, x: u8, y: u8, r: u8, g: u8, b: u8) -> Result<(), Error> { + pub fn pixel_rgb( + &mut self, + x: u8, + y: u8, + r: u8, + g: u8, + b: u8, + ) -> Result<(), Error> { let x = x + y * 13; self.device.pixel(x, 2, r)?; self.device.pixel(x, 1, g)?; @@ -217,11 +209,11 @@ where Ok(()) } - pub fn setup>(&mut self, delay: &mut DEL) -> Result<(), Error> { + pub fn setup(&mut self, delay: &mut DEL) -> Result<(), Error> { self.device.setup(delay) } - pub fn fill_rgb(&mut self, r: u8, g: u8, b: u8) -> Result<(), Error> { + pub fn fill_rgb(&mut self, r: u8, g: u8, b: u8) -> Result<(), Error> { for x in 0..13 { for y in 0..9 { self.pixel_rgb(x, y, r, g, b)?; @@ -556,17 +548,13 @@ pub struct LedMatrix { } #[cfg(feature = "framework_ledmatrix")] -impl LedMatrix -where - I2C: Write, - I2C: Read, -{ +impl LedMatrix { pub fn unwrap(self) -> I2C { self.device.i2c } // TODO: Maybe make this private and set it once in the constructor - pub fn set_scaling(&mut self, scale: u8) -> Result<(), I2cError> { + pub fn set_scaling(&mut self, scale: u8) -> Result<(), I2C::Error> { self.device.set_scaling(scale) } @@ -582,14 +570,14 @@ where } } - pub fn setup>(&mut self, delay: &mut DEL) -> Result<(), Error> { + pub fn setup(&mut self, delay: &mut DEL) -> Result<(), Error> { self.device.setup(delay)?; Ok(()) } /// Fills the matrix with a _raw_ brightness value, i.e. without gamma /// correction, to show the native PWM values. - pub fn fill_brightness(&mut self, brightness: u8) -> Result<(), Error> { + pub fn fill_brightness(&mut self, brightness: u8) -> Result<(), Error> { for x in 0..self.device.width { for y in 0..self.device.height { self.device.pixel(x, y, brightness)?; diff --git a/src/lib.rs b/src/lib.rs index 15a0569..d0759b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,9 +3,8 @@ /// Preconfigured devices pub mod devices; -use embedded_hal::blocking::delay::DelayMs; -use embedded_hal::blocking::i2c::Read; -use embedded_hal::blocking::i2c::Write; +use embedded_hal::delay::DelayNs; +use embedded_hal::i2c::I2c; /// A struct to integrate with a new IS31FL3741 powered device. pub struct IS31FL3741 { @@ -23,13 +22,9 @@ pub struct IS31FL3741 { pub calc_pixel: fn(x: u8, y: u8) -> (u8, u8), } -impl IS31FL3741 -where - I2C: Write, - I2C: Read, -{ +impl IS31FL3741 { /// Fill all pixels of the display at once. The brightness should range from 0 to 255. - pub fn fill_matrix(&mut self, brightnesses: &[u8]) -> Result<(), I2cError> { + pub fn fill_matrix(&mut self, brightnesses: &[u8]) -> Result<(), I2C::Error> { // Extend by one, to add address to the beginning let mut buf = [0x00; 0xB5]; buf[0] = 0x00; // set the initial address @@ -45,7 +40,7 @@ where } /// Fill the display with a single brightness. The brightness should range from 0 to 255. - pub fn fill(&mut self, brightness: u8) -> Result<(), I2cError> { + pub fn fill(&mut self, brightness: u8) -> Result<(), I2C::Error> { self.bank(Page::Pwm1)?; let mut buf = [brightness; 0xB5]; buf[0] = 0x00; // set the initial address @@ -64,7 +59,7 @@ where /// 2. The chip will be put in shutdown mode /// 3. The chip will be configured to use the maximum voltage /// 4. The chip will be taken out of shutdown mode - pub fn setup>(&mut self, delay: &mut DEL) -> Result<(), Error> { + pub fn setup(&mut self, delay: &mut DEL) -> Result<(), Error> { self.reset(delay)?; self.shutdown(true)?; delay.delay_ms(10); @@ -77,14 +72,14 @@ where /// Read the ID register /// /// Same as the device slave address. Default 0x60 - pub fn read_id(&mut self) -> Result { + pub fn read_id(&mut self) -> Result { self.read_u8(addresses::ID_REGISTER) } /// Set the brightness at a specific x,y coordinate. Just like the [fill method](Self::fill) /// the brightness should range from 0 to 255. If the coordinate is out of range then the /// function will return an error of [InvalidLocation](Error::InvalidLocation). - pub fn pixel(&mut self, x: u8, y: u8, brightness: u8) -> Result<(), Error> { + pub fn pixel(&mut self, x: u8, y: u8, brightness: u8) -> Result<(), Error> { if x > self.width { return Err(Error::InvalidLocation(x)); } @@ -106,14 +101,14 @@ where /// Send a reset message to the slave device. Delay is something that your device's HAL should /// provide which allows for the process to sleep for a certain amount of time (in this case 10 /// MS to perform a reset). - pub fn reset>(&mut self, delay: &mut DEL) -> Result<(), I2cError> { + pub fn reset(&mut self, delay: &mut DEL) -> Result<(), I2C::Error> { self.write_register(Page::Config, addresses::RESET_REGISTER, addresses::RESET)?; delay.delay_ms(10); Ok(()) } /// Set the current available to each LED. 0 is none, 255 is the maximum available - pub fn set_scaling(&mut self, scale: u8) -> Result<(), I2cError> { + pub fn set_scaling(&mut self, scale: u8) -> Result<(), I2C::Error> { self.bank(Page::Scale1)?; let mut buf = [scale; 0xB5]; buf[0] = 0x00; // set the initial address @@ -124,7 +119,7 @@ where } /// Put the device into software shutdown mode - pub fn shutdown(&mut self, yes: bool) -> Result<(), I2cError> { + pub fn shutdown(&mut self, yes: bool) -> Result<(), I2C::Error> { self.write_register( Page::Config, addresses::CONFIG_REGISTER, @@ -134,7 +129,7 @@ where } /// How many SW rows to enable - pub fn sw_enablement(&mut self, setting: SwSetting) -> Result<(), I2cError> { + pub fn sw_enablement(&mut self, setting: SwSetting) -> Result<(), I2C::Error> { let config_register = self.read_register(Page::Config, addresses::CONFIG_REGISTER)?; let new_val = (config_register & 0x0F) | (setting as u8) << 4; @@ -143,40 +138,40 @@ where } /// Set the PWM frequency - pub fn set_pwm_freq(&mut self, pwm: PwmFreq) -> Result<(), I2cError> { + pub fn set_pwm_freq(&mut self, pwm: PwmFreq) -> Result<(), I2C::Error> { self.write_register(Page::Config, addresses::PWM_FREQ_REGISTER, pwm as u8) } - fn write(&mut self, buf: &[u8]) -> Result<(), I2cError> { + fn write(&mut self, buf: &[u8]) -> Result<(), I2C::Error> { self.i2c.write(self.address, buf) } - fn write_register(&mut self, bank: Page, register: u8, value: u8) -> Result<(), I2cError> { + fn write_register(&mut self, bank: Page, register: u8, value: u8) -> Result<(), I2C::Error> { self.bank(bank)?; self.write(&[register, value])?; Ok(()) } - fn read_u8(&mut self, register: u8) -> Result { + fn read_u8(&mut self, register: u8) -> Result { let mut buf = [0x00]; self.i2c.write(self.address, &[register])?; self.i2c.read(self.address, &mut buf)?; Ok(buf[0]) } - fn read_register(&mut self, bank: Page, register: u8) -> Result { + fn read_register(&mut self, bank: Page, register: u8) -> Result { self.bank(bank)?; let value = self.read_u8(register)?; Ok(value) } - fn bank(&mut self, bank: Page) -> Result<(), I2cError> { + fn bank(&mut self, bank: Page) -> Result<(), I2C::Error> { self.unlock()?; self.write(&[addresses::PAGE_SELECT_REGISTER, bank as u8])?; Ok(()) } - fn unlock(&mut self) -> Result<(), I2cError> { + fn unlock(&mut self) -> Result<(), I2C::Error> { self.i2c.write( self.address, &[ From 3f28be64038065b331b3791241732c2b1c6c2ab4 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 14 Jan 2026 23:58:52 +0800 Subject: [PATCH 2/4] Migrate example from stm32 to QT Py RP2040 The stm32 hal hasn't been updated to embedded-hal 1.0. Signed-off-by: Daniel Schaefer --- examples/adafruit_rgb/Cargo.toml | 17 ++-- examples/adafruit_rgb/examples/gaypride.rs | 83 +++++++++++++----- examples/adafruit_rgb/examples/rgbmatrix.rs | 96 +++++++++++++++++++++ examples/adafruit_rgb/examples/stm32.rs | 53 ------------ 4 files changed, 170 insertions(+), 79 deletions(-) create mode 100644 examples/adafruit_rgb/examples/rgbmatrix.rs delete mode 100644 examples/adafruit_rgb/examples/stm32.rs diff --git a/examples/adafruit_rgb/Cargo.toml b/examples/adafruit_rgb/Cargo.toml index eabca54..aae784b 100644 --- a/examples/adafruit_rgb/Cargo.toml +++ b/examples/adafruit_rgb/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "stm3" +name = "adafruit_rgb" version = "0.2.0" edition = "2021" publish = false @@ -7,16 +7,23 @@ publish = false [dependencies] is31fl3741 = { path = "../../", features = [ "adafruit_rgb_13x9", "embedded_graphics" ] } embedded-hal = "1.0" -cortex-m-rt = "0.7.3" cortex-m = "0.7.7" +cortex-m-rt = "0.7.3" fugit = "0.3.7" -panic-halt = { version = "0.2.0" } -stm32g0xx-hal = {version = "0.2.0", features = ["rt", "stm32g071"]} +panic-halt = "1.0.0" +rp2040-hal = { version = "0.11.0", features = ["rt", "critical-section-impl"] } +rp2040-boot2 = "0.3" tinybmp = "0.5.0" embedded-graphics = "0.8.1" [[example]] -name = "stm32" +name = "rgbmatrix" [[example]] name = "gaypride" + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" diff --git a/examples/adafruit_rgb/examples/gaypride.rs b/examples/adafruit_rgb/examples/gaypride.rs index 6d14951..446f8d8 100644 --- a/examples/adafruit_rgb/examples/gaypride.rs +++ b/examples/adafruit_rgb/examples/gaypride.rs @@ -1,43 +1,84 @@ +//! Adafruit RGB 13x9 Matrix - Pride Flag Example for QT Py RP2040 +//! +//! Displays a pride flag image on the Adafruit IS31FL3741 RGB matrix. +//! Connect the matrix to the STEMMA QT connector on the QT Py RP2040. +//! +//! STEMMA QT pinout on QT Py RP2040: +//! - SDA: GPIO22 +//! - SCL: GPIO23 #![no_std] #![no_main] -// pick a panicking behavior use panic_halt as _; -// use cortex_m::delay::Delay; -use cortex_m_rt::entry; -use is31fl3741::devices::AdafruitRGB13x9; -use fugit::RateExtU32; - use embedded_graphics::{image::Image, pixelcolor::Rgb888, prelude::*}; -use stm32g0xx_hal::{ - prelude::*, - rcc::{Config, Prescaler}, - stm32, +use fugit::RateExtU32; +use rp2040_hal::{ + self as hal, + clocks::init_clocks_and_plls, + entry, + gpio::{FunctionI2C, PullUp}, + pac, + sio::Sio, + watchdog::Watchdog, + Timer, I2C, }; use tinybmp::Bmp; +use is31fl3741::devices::AdafruitRGB13x9; + +/// External crystal frequency (QT Py RP2040 uses 12MHz) +const XTAL_FREQ_HZ: u32 = 12_000_000; + +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GD25Q64CS; + #[entry] fn main() -> ! { - let dp = stm32::Peripherals::take().expect("cannot take peripherals"); - let mut rcc = dp.RCC.freeze(Config::hsi(Prescaler::NotDivided)); - let mut delay = dp.TIM15.delay(&mut rcc); + let mut pac = pac::Peripherals::take().unwrap(); + let mut watchdog = Watchdog::new(pac.WATCHDOG); + let sio = Sio::new(pac.SIO); + + let clocks = init_clocks_and_plls( + XTAL_FREQ_HZ, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); - // let cp = cortex_m::Peripherals::take().unwrap(); - // let dp = pac::Peripherals::take().unwrap(); - let gpiob = dp.GPIOB.split(&mut rcc); + let timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks); + let mut delay = timer; - let sda = gpiob.pb9.into_open_drain_output_in_state(PinState::High); - let scl = gpiob.pb8.into_open_drain_output_in_state(PinState::High); + let pins = hal::gpio::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); - let i2c = dp.I2C1.i2c(sda, scl, 100.kHz(), &mut rcc); + // STEMMA QT connector I2C1 pins on QT Py RP2040 + let sda: hal::gpio::Pin<_, FunctionI2C, PullUp> = pins.gpio22.reconfigure(); + let scl: hal::gpio::Pin<_, FunctionI2C, PullUp> = pins.gpio23.reconfigure(); - // // https://github.com/adafruit/Adafruit_CircuitPython_IS31FL3741/blob/main/adafruit_is31fl3 741/adafruit_rgbmatrixqt.py#L53-L65 + let i2c = I2C::i2c1( + pac.I2C1, + sda, + scl, + 400.kHz(), + &mut pac.RESETS, + &clocks.peripheral_clock, + ); let mut matrix = AdafruitRGB13x9::configure(i2c); matrix .setup(&mut delay) - .expect("failed to setup rgb controller"); + .expect("failed to setup RGB controller"); matrix.set_scaling(0xFF).expect("failed to set scaling"); diff --git a/examples/adafruit_rgb/examples/rgbmatrix.rs b/examples/adafruit_rgb/examples/rgbmatrix.rs new file mode 100644 index 0000000..b8ef17f --- /dev/null +++ b/examples/adafruit_rgb/examples/rgbmatrix.rs @@ -0,0 +1,96 @@ +//! Adafruit RGB 13x9 Matrix Example for QT Py RP2040 +//! +//! Lights up each LED one by one on the Adafruit IS31FL3741 RGB matrix. +//! Connect the matrix to the STEMMA QT connector on the QT Py RP2040. +//! +//! STEMMA QT pinout on QT Py RP2040: +//! - SDA: GPIO22 +//! - SCL: GPIO23 +#![no_std] +#![no_main] + +use panic_halt as _; + +use embedded_hal::delay::DelayNs; +use fugit::RateExtU32; +use rp2040_hal::{ + self as hal, + clocks::init_clocks_and_plls, + entry, + gpio::{FunctionI2C, PullUp}, + pac, + sio::Sio, + watchdog::Watchdog, + Timer, I2C, +}; + +use is31fl3741::devices::AdafruitRGB13x9; + +/// External crystal frequency (QT Py RP2040 uses 12MHz) +const XTAL_FREQ_HZ: u32 = 12_000_000; + +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GD25Q64CS; + +#[entry] +fn main() -> ! { + let mut pac = pac::Peripherals::take().unwrap(); + let mut watchdog = Watchdog::new(pac.WATCHDOG); + let sio = Sio::new(pac.SIO); + + let clocks = init_clocks_and_plls( + XTAL_FREQ_HZ, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + + let timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks); + let mut delay = timer; + + let pins = hal::gpio::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + // STEMMA QT connector I2C1 pins on QT Py RP2040 + let sda: hal::gpio::Pin<_, FunctionI2C, PullUp> = pins.gpio22.reconfigure(); + let scl: hal::gpio::Pin<_, FunctionI2C, PullUp> = pins.gpio23.reconfigure(); + + let i2c = I2C::i2c1( + pac.I2C1, + sda, + scl, + 400.kHz(), + &mut pac.RESETS, + &clocks.peripheral_clock, + ); + + let mut matrix = AdafruitRGB13x9::configure(i2c); + matrix + .setup(&mut delay) + .expect("failed to setup RGB controller"); + + matrix.set_scaling(0xFF).expect("failed to set scaling"); + + loop { + // Light up each LED one by one + for y in 0..9 { + for x in 0..13 { + matrix + .pixel_rgb(x, y, 0x1E, 0x90, 0xFF) + .expect("couldn't turn on"); + delay.delay_ms(100); + matrix.pixel_rgb(x, y, 0, 0, 0).expect("couldn't turn off"); + } + } + } +} diff --git a/examples/adafruit_rgb/examples/stm32.rs b/examples/adafruit_rgb/examples/stm32.rs deleted file mode 100644 index 71d3b4f..0000000 --- a/examples/adafruit_rgb/examples/stm32.rs +++ /dev/null @@ -1,53 +0,0 @@ -#![no_std] -#![no_main] - -// pick a panicking behavior -use panic_halt as _; - -// use cortex_m::delay::Delay; -use cortex_m_rt::entry; -use is31fl3741::devices::AdafruitRGB13x9; -use fugit::RateExtU32; - -use stm32g0xx_hal::{ - prelude::*, - rcc::{Config, Prescaler}, - stm32, -}; - -#[entry] -fn main() -> ! { - let dp = stm32::Peripherals::take().expect("cannot take peripherals"); - let mut rcc = dp.RCC.freeze(Config::hsi(Prescaler::NotDivided)); - let mut delay = dp.TIM15.delay(&mut rcc); - - // let cp = cortex_m::Peripherals::take().unwrap(); - // let dp = pac::Peripherals::take().unwrap(); - let gpiob = dp.GPIOB.split(&mut rcc); - - let sda = gpiob.pb9.into_open_drain_output_in_state(PinState::High); - let scl = gpiob.pb8.into_open_drain_output_in_state(PinState::High); - - let i2c = dp.I2C1.i2c(sda, scl, 100.kHz(), &mut rcc); - - // // https://github.com/adafruit/Adafruit_CircuitPython_IS31FL3741/blob/main/adafruit_is31fl3 741/adafruit_rgbmatrixqt.py#L53-L65 - - let mut matrix = AdafruitRGB13x9::configure(i2c); - matrix - .setup(&mut delay) - .expect("failed to setup rgb controller"); - - matrix.set_scaling(0xFF).expect("failed to set scaling"); - - loop { - for y in 0..9 { - for x in 0..13 { - matrix - .pixel_rgb(x, y, 0x1E, 0x90, 0xFF) - .expect("couldn't turn on"); - delay.delay_ms(100_u32); - matrix.pixel_rgb(x, y, 0, 0, 0).expect("couldn't turn off"); - } - } - } -} From 6b4fe3b984053da4dd3fa075438a1d280b39b808 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Thu, 15 Jan 2026 00:44:01 +0800 Subject: [PATCH 3/4] Update ledmatrix exmaple to embedded-hal 1.0 Signed-off-by: Daniel Schaefer --- examples/ledmatrix/Cargo.toml | 15 +++-- examples/ledmatrix/examples/ledtest.rs | 79 ++++++++++++++------------ 2 files changed, 53 insertions(+), 41 deletions(-) diff --git a/examples/ledmatrix/Cargo.toml b/examples/ledmatrix/Cargo.toml index 4431586..56833dd 100644 --- a/examples/ledmatrix/Cargo.toml +++ b/examples/ledmatrix/Cargo.toml @@ -1,4 +1,4 @@ -[package] +[package] name = "ledmatrix" version = "0.1.0" edition = "2021" @@ -7,10 +7,15 @@ publish = false [dependencies] is31fl3741 = { path = "../../", features = ["framework_ledmatrix"] } embedded-hal = "1.0" -cortex-m-rt = "0.7.3" cortex-m = "0.7.7" +cortex-m-rt = "0.7.3" fugit = "0.3.7" -rp2040-hal = { version = "0.8", features = ["rt", "critical-section-impl"] } -rp-pico = "0.7" -rp2040-panic-usb-boot = "0.5.0" +rp2040-hal = { version = "0.11.0", features = ["rt", "critical-section-impl"] } +rp2040-panic-usb-boot = "0.6.0" rp2040-boot2 = "0.3" + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" diff --git a/examples/ledmatrix/examples/ledtest.rs b/examples/ledmatrix/examples/ledtest.rs index 963f489..6f50cac 100644 --- a/examples/ledmatrix/examples/ledtest.rs +++ b/examples/ledmatrix/examples/ledtest.rs @@ -1,47 +1,52 @@ //! LED Matrix Module //! -//! -//! //! Goes into bootloader mode when the host is asleep. This is to make it easy to reflash your //! firmware - the regular bootloader mechanism using the DIP switch still works. #![no_std] #![no_main] #![allow(clippy::needless_range_loop)] -use embedded_hal::digital::{InputPin, OutputPin}; -use rp2040_hal::rom_data::reset_to_usb_boot; use rp2040_panic_usb_boot as _; +use embedded_hal::delay::DelayNs; +use embedded_hal::digital::{InputPin, OutputPin}; +use fugit::RateExtU32; +use rp2040_hal::{ + self as hal, + clocks::init_clocks_and_plls, + entry, + gpio::{FunctionI2C, PullUp}, + pac, + rom_data::reset_to_usb_boot, + sio::Sio, + watchdog::Watchdog, + Timer, I2C, +}; + +use is31fl3741::devices::{LedMatrix, CALC_PIXEL}; +use is31fl3741::PwmFreq; + /// Maximum brightness out of 255 /// /// 100/255 results in 250mA current draw and is plenty bright. /// 50/255 results in 160mA current draw and is plenty bright. const MAX_BRIGHTNESS: u8 = 50; -// Provide an alias for our BSP so we can switch targets quickly. -// Uncomment the BSP you included in Cargo.toml, the rest of the code does not need to change. -use bsp::entry; -use is31fl3741::devices::{LedMatrix, CALC_PIXEL}; -use is31fl3741::{PwmFreq}; -use rp_pico as bsp; +/// External crystal frequency (12MHz on RP Pico and Framework LED Matrix) +const XTAL_FREQ_HZ: u32 = 12_000_000; -use bsp::hal::{ - clocks::{init_clocks_and_plls, Clock}, - gpio, pac, - sio::Sio, - watchdog::Watchdog, -}; -use fugit::RateExtU32; +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GD25Q64CS; #[entry] fn main() -> ! { let mut pac = pac::Peripherals::take().unwrap(); - let core = pac::CorePeripherals::take().unwrap(); let mut watchdog = Watchdog::new(pac.WATCHDOG); let sio = Sio::new(pac.SIO); let clocks = init_clocks_and_plls( - bsp::XOSC_CRYSTAL_FREQ, + XTAL_FREQ_HZ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -51,9 +56,11 @@ fn main() -> ! { ) .ok() .unwrap(); - let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); - let pins = bsp::Pins::new( + let timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks); + let mut delay = timer; + + let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, @@ -62,34 +69,37 @@ fn main() -> ! { // Enable LED controller // SDB - Gpio29 - let mut led_enable = pins.voltage_monitor.into_push_pull_output(); + let mut led_enable = pins.gpio29.into_push_pull_output(); led_enable.set_high().unwrap(); // INTB. Currently ignoring - pins.gpio28.into_floating_input(); + let _intb = pins.gpio28.into_floating_input(); + + // I2C1 pins for the LED matrix + let sda: hal::gpio::Pin<_, FunctionI2C, PullUp> = pins.gpio26.reconfigure(); + let scl: hal::gpio::Pin<_, FunctionI2C, PullUp> = pins.gpio27.reconfigure(); - let i2c = bsp::hal::I2C::i2c1( + let i2c = I2C::i2c1( pac.I2C1, - pins.gpio26.into_mode::(), - pins.gpio27.into_mode::(), - // 1000, + sda, + scl, 1000.kHz(), &mut pac.RESETS, &clocks.peripheral_clock, ); - // Gpio25 (LED on rp-pico) - let dip1 = pins.led.into_pull_up_input(); + // Gpio25 (LED on rp-pico, DIP switch on Framework LED Matrix) + let mut dip1 = pins.gpio25.into_pull_up_input(); let _dip1_state = dip1.is_low().unwrap(); // Detect whether the sleep pin is connected // Early revisions of the hardware didn't have it wired up, if that is the // case we have to ignore its state. let mut sleep_present = false; - let sleep = pins.gpio0.into_pull_up_input(); + let mut sleep = pins.gpio0.into_pull_up_input(); if sleep.is_low().unwrap() { sleep_present = true; } - let sleep = sleep.into_pull_down_input(); + let mut sleep = sleep.into_pull_down_input(); if sleep.is_high().unwrap() { sleep_present = true; } @@ -116,15 +126,12 @@ fn main() -> ! { // Light up each LED, one by one for y in 0..matrix.device.height { for x in 0..matrix.device.width { - matrix - .device - .pixel(x, y, 0xFF) - .expect("couldn't turn on"); + matrix.device.pixel(x, y, 0xFF).expect("couldn't turn on"); delay.delay_ms(100); matrix.device.pixel(x, y, 0).expect("couldn't turn off"); // Reset into bootloader if system asleep - if sleep_present && sleep.is_low().unwrap(){ + if sleep_present && sleep.is_low().unwrap() { reset_to_usb_boot(0, 0); } } From e6cf602fa6dbc10dd72396b8c70b54dc164b3ab5 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Thu, 15 Jan 2026 01:17:55 +0800 Subject: [PATCH 4/4] ledmatrix: Document how to convert to uf2 Signed-off-by: Daniel Schaefer --- examples/ledmatrix/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/examples/ledmatrix/README.md b/examples/ledmatrix/README.md index f00f9d4..2e8909b 100644 --- a/examples/ledmatrix/README.md +++ b/examples/ledmatrix/README.md @@ -1,6 +1,6 @@ # Framework LED Matrix -## Build and run +## Build and run with flip-link Make sure you're in bootloader mode and then run the following command, which automatically flashes the matrix. @@ -9,3 +9,15 @@ automatically flashes the matrix. cargo install flip-link cargo run --example ledtest ``` + +## Building a UF2 file + +To create a UF2 file for manual flashing: + +``` +cargo install elf2uf2-rs +cargo build --example ledtest +elf2uf2-rs target/thumbv6m-none-eabi/debug/examples/ledtest ledtest.uf2 +``` + +Then copy `ledtest.uf2` to the RP2040 mass storage device while in bootloader mode.