diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 149769e..9084188 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,8 +26,8 @@ jobs: - if: steps.changes.outputs.rust == 'true' run: | cargo build --target=thumbv6m-none-eabi - cd examples/adafruit_rgb - cargo build --target=thumbv6m-none-eabi + cd examples/adafruit_rgb && cargo build --target=thumbv6m-none-eabi + cd examples/ledmatrix && cargo build --target=thumbv6m-none-eabi rustdoc: runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 7f17ba1..58d1578 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.0" embedded-graphics-core = { optional = true, version = "0.4.0" } [package.metadata.docs.rs] @@ -18,5 +18,6 @@ all-features = true [features] adafruit_rgb_13x9 = [] +framework_ledmatrix = [] embedded_graphics = ["embedded-graphics-core"] -default = ["adafruit_rgb_13x9", "embedded_graphics"] +default = ["adafruit_rgb_13x9", "framework_ledmatrix", "embedded_graphics"] diff --git a/Makefile b/Makefile index 4a83099..4cb39fd 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ build-all: cd examples/adafruit_rgb && \ cargo build --target=thumbv6m-none-eabi --examples --all-features + cd examples/ledmatrix && \ + cargo build --target=thumbv6m-none-eabi --examples --all-features diff --git a/README.md b/README.md index 51882ea..cd36841 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ Driver for [Lumissil Microsystem's IS31FL3741 integrated circuit](https://www.lu 1. Use of embedded HAL traits (works with any embedded device that supports the required traits). This means that this driver is platform agnostic. 2. Library features (only turn on what devices you need to save compiled binary space). 3. [Examples](./examples) on how to use this driver. -Right now there is only an example on how to use this crate with a stm32 nucleo. ## Install diff --git a/examples/adafruit_rgb/Cargo.toml b/examples/adafruit_rgb/Cargo.toml index 96a77cb..2b43493 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.0" cortex-m-rt = "0.7.3" cortex-m = "0.7.7" fugit = "0.3.7" diff --git a/examples/ledmatrix/Cargo.toml b/examples/ledmatrix/Cargo.toml new file mode 100644 index 0000000..b34bdb5 --- /dev/null +++ b/examples/ledmatrix/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "ledmatrix" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +is31fl3741 = { path = "../../", features = ["framework_ledmatrix"] } +embedded-hal = "1.0.0" +cortex-m-rt = "0.7.3" +cortex-m = "0.7.7" +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-boot2 = "0.3" diff --git a/examples/ledmatrix/README.md b/examples/ledmatrix/README.md new file mode 100644 index 0000000..93eb32f --- /dev/null +++ b/examples/ledmatrix/README.md @@ -0,0 +1,7 @@ +# Framework LED Matrix + +## Build and run + +``` +cargo build --target=thumbv6m-none-eabi +``` diff --git a/examples/ledmatrix/examples/main.rs b/examples/ledmatrix/examples/main.rs new file mode 100644 index 0000000..351f7ca --- /dev/null +++ b/examples/ledmatrix/examples/main.rs @@ -0,0 +1,124 @@ +//! LED Matrix Module +#![no_std] +#![no_main] +#![allow(clippy::needless_range_loop)] + +use embedded_hal::digital::{InputPin, OutputPin}; +//use rp2040_hal::{ +// gpio::bank0::Gpio29, +//}; +use rp2040_panic_usb_boot as _; +//use panic_halt as _; + +/// 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; + +use bsp::hal::{ + clocks::{init_clocks_and_plls, Clock}, + gpio, pac, + sio::Sio, + watchdog::Watchdog, +}; +use fugit::RateExtU32; + +#[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, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); + + let pins = bsp::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + // Enable LED controller + // SDB - Gpio29 + let mut led_enable = pins.voltage_monitor.into_push_pull_output(); + led_enable.set_high().unwrap(); + // INTB. Currently ignoring + pins.gpio28.into_floating_input(); + + let i2c = bsp::hal::I2C::i2c1( + pac.I2C1, + pins.gpio26.into_mode::(), + pins.gpio27.into_mode::(), + // 1000, + 1000.kHz(), + &mut pac.RESETS, + &clocks.peripheral_clock, + ); + + // Gpio25 (LED on rp-pico) + let dip1 = pins.led.into_pull_up_input(); + + let mut matrix = LedMatrix::new(i2c, CALC_PIXEL); + matrix + .setup(&mut delay) + .expect("failed to setup RGB controller"); + + // Enable only the SW pins that we're using. + // Otherwise driving the unused pins might result in audible noise. + matrix + .device + .sw_enablement(is31fl3741::SwSetting::Sw1Sw8) + .unwrap(); + + matrix + .set_scaling(MAX_BRIGHTNESS) + .expect("failed to set scaling"); + + // Set to 29kHz PWM frequency + // TODO: Create enum + matrix.device.set_pwm_freq(PwmFreq::P29k).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(); + if sleep.is_low().unwrap() { + sleep_present = true; + } + let sleep = sleep.into_pull_down_input(); + if sleep.is_high().unwrap() { + sleep_present = true; + } + + loop { + let _dip1_state = dip1.is_low().unwrap(); + + if sleep_present { + let host_sleeping = sleep.is_low().unwrap(); + } + + // fill_grid_pixels(&state, &mut matrix); + } +} diff --git a/examples/ledmatrix/src/lib.rs b/examples/ledmatrix/src/lib.rs new file mode 100644 index 0000000..0c9ac1a --- /dev/null +++ b/examples/ledmatrix/src/lib.rs @@ -0,0 +1 @@ +#![no_std] diff --git a/src/devices.rs b/src/devices.rs index 0af91ef..0983fc5 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -1,13 +1,11 @@ // #[cfg_attr(docsrs, doc(cfg(feature = "adafruit_rgb_13x9")))] -#[allow(unused_imports)] -use crate::{Error, IS31FL3741}; +use crate::{Is31Error, IS31FL3741}; #[allow(unused_imports)] use core::convert::TryFrom; #[allow(unused_imports)] -use embedded_hal::blocking::delay::DelayMs; -use embedded_hal::blocking::i2c::Read; +use embedded_hal::delay::DelayNs; #[allow(unused_imports)] -use embedded_hal::blocking::i2c::Write; +use embedded_hal::i2c::{Error, I2c}; #[cfg(feature = "adafruit_rgb_13x9")] pub struct AdafruitRGB13x9 { @@ -18,10 +16,9 @@ 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 +impl Dimensions for AdafruitRGB13x9 where - I2C: Write, - I2C: Read, + I2C: I2c, { fn bounding_box(&self) -> Rectangle { Rectangle::new(Point::zero(), Size::new(13, 9)) @@ -29,14 +26,12 @@ where } #[cfg(all(feature = "adafruit_rgb_13x9", feature = "embedded_graphics"))] -impl DrawTarget for AdafruitRGB13x9 +impl DrawTarget for AdafruitRGB13x9 where - I2C: Write, - I2C: Read, - I2cError:, + I2C: I2c, { type Color = Rgb888; - type Error = Error; + type Error = Is31Error; fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> where @@ -57,10 +52,9 @@ where } #[cfg(feature = "adafruit_rgb_13x9")] -impl AdafruitRGB13x9 +impl AdafruitRGB13x9 where - I2C: Write, - I2C: Read, + I2C: I2c, { pub fn unwrap(self) -> I2C { self.device.i2c @@ -208,7 +202,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<(), Is31Error> { let x = x + y * 13; self.device.pixel(x, 2, r)?; self.device.pixel(x, 1, g)?; @@ -216,11 +217,11 @@ where Ok(()) } - pub fn setup>(&mut self, delay: &mut DEL) -> Result<(), Error> { + pub fn setup(&mut self, delay: &mut DEL) -> Result<(), Is31Error> { 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<(), Is31Error> { for x in 0..13 { for y in 0..9 { self.pixel_rgb(x, y, r, g, b)?; @@ -229,3 +230,370 @@ where Ok(()) } } + +#[cfg(feature = "framework_ledmatrix")] +pub const CALC_PIXEL: fn(x: u8, y: u8) -> (u8, u8) = |x: u8, y: u8| -> (u8, u8) { + // Generated by led-matrix.py + let lookup: [(u8, u8); 34 * 9] = [ + (0x00, 0), // x: 1, y: 1, sw: 1, cs: 1, id: 1 + (0x1e, 0), // x: 2, y: 1, sw: 2, cs: 1, id: 2 + (0x3c, 0), // x: 3, y: 1, sw: 3, cs: 1, id: 3 + (0x5a, 0), // x: 4, y: 1, sw: 4, cs: 1, id: 4 + (0x78, 0), // x: 5, y: 1, sw: 5, cs: 1, id: 5 + (0x96, 0), // x: 6, y: 1, sw: 6, cs: 1, id: 6 + (0x00, 1), // x: 7, y: 1, sw: 7, cs: 1, id: 7 + (0x1e, 1), // x: 8, y: 1, sw: 8, cs: 1, id: 8 + (0x5f, 1), // x: 9, y: 1, sw: 1, cs:36, id: 9 + (0x01, 0), // x: 1, y: 2, sw: 1, cs: 2, id: 10 + (0x1f, 0), // x: 2, y: 2, sw: 2, cs: 2, id: 11 + (0x3d, 0), // x: 3, y: 2, sw: 3, cs: 2, id: 12 + (0x5b, 0), // x: 4, y: 2, sw: 4, cs: 2, id: 13 + (0x79, 0), // x: 5, y: 2, sw: 5, cs: 2, id: 14 + (0x97, 0), // x: 6, y: 2, sw: 6, cs: 2, id: 15 + (0x01, 1), // x: 7, y: 2, sw: 7, cs: 2, id: 16 + (0x1f, 1), // x: 8, y: 2, sw: 8, cs: 2, id: 17 + (0x60, 1), // x: 9, y: 2, sw: 1, cs:37, id: 18 + (0x02, 0), // x: 1, y: 3, sw: 1, cs: 3, id: 19 + (0x20, 0), // x: 2, y: 3, sw: 2, cs: 3, id: 20 + (0x3e, 0), // x: 3, y: 3, sw: 3, cs: 3, id: 21 + (0x5c, 0), // x: 4, y: 3, sw: 4, cs: 3, id: 22 + (0x7a, 0), // x: 5, y: 3, sw: 5, cs: 3, id: 23 + (0x98, 0), // x: 6, y: 3, sw: 6, cs: 3, id: 24 + (0x02, 1), // x: 7, y: 3, sw: 7, cs: 3, id: 25 + (0x20, 1), // x: 8, y: 3, sw: 8, cs: 3, id: 26 + (0x61, 1), // x: 9, y: 3, sw: 1, cs:38, id: 27 + (0x03, 0), // x: 1, y: 4, sw: 1, cs: 4, id: 28 + (0x21, 0), // x: 2, y: 4, sw: 2, cs: 4, id: 29 + (0x3f, 0), // x: 3, y: 4, sw: 3, cs: 4, id: 30 + (0x5d, 0), // x: 4, y: 4, sw: 4, cs: 4, id: 31 + (0x7b, 0), // x: 5, y: 4, sw: 5, cs: 4, id: 32 + (0x99, 0), // x: 6, y: 4, sw: 6, cs: 4, id: 33 + (0x03, 1), // x: 7, y: 4, sw: 7, cs: 4, id: 34 + (0x21, 1), // x: 8, y: 4, sw: 8, cs: 4, id: 35 + (0x62, 1), // x: 9, y: 4, sw: 1, cs:39, id: 36 + (0x04, 0), // x: 1, y: 5, sw: 1, cs: 5, id: 37 + (0x22, 0), // x: 2, y: 5, sw: 2, cs: 5, id: 41 + (0x40, 0), // x: 3, y: 5, sw: 3, cs: 5, id: 45 + (0x5e, 0), // x: 4, y: 5, sw: 4, cs: 5, id: 49 + (0x7c, 0), // x: 5, y: 5, sw: 5, cs: 5, id: 53 + (0x9a, 0), // x: 6, y: 5, sw: 6, cs: 5, id: 57 + (0x04, 1), // x: 7, y: 5, sw: 7, cs: 5, id: 61 + (0x22, 1), // x: 8, y: 5, sw: 8, cs: 5, id: 65 + (0x5e, 1), // x: 9, y: 5, sw: 1, cs:35, id: 69 + (0x05, 0), // x: 1, y: 6, sw: 1, cs: 6, id: 38 + (0x23, 0), // x: 2, y: 6, sw: 2, cs: 6, id: 42 + (0x41, 0), // x: 3, y: 6, sw: 3, cs: 6, id: 46 + (0x5f, 0), // x: 4, y: 6, sw: 4, cs: 6, id: 50 + (0x7d, 0), // x: 5, y: 6, sw: 5, cs: 6, id: 54 + (0x9b, 0), // x: 6, y: 6, sw: 6, cs: 6, id: 58 + (0x05, 1), // x: 7, y: 6, sw: 7, cs: 6, id: 62 + (0x23, 1), // x: 8, y: 6, sw: 8, cs: 6, id: 66 + (0x68, 1), // x: 9, y: 6, sw: 2, cs:36, id: 70 + (0x06, 0), // x: 1, y: 7, sw: 1, cs: 7, id: 39 + (0x24, 0), // x: 2, y: 7, sw: 2, cs: 7, id: 43 + (0x42, 0), // x: 3, y: 7, sw: 3, cs: 7, id: 47 + (0x60, 0), // x: 4, y: 7, sw: 4, cs: 7, id: 51 + (0x7e, 0), // x: 5, y: 7, sw: 5, cs: 7, id: 55 + (0x9c, 0), // x: 6, y: 7, sw: 6, cs: 7, id: 59 + (0x06, 1), // x: 7, y: 7, sw: 7, cs: 7, id: 63 + (0x24, 1), // x: 8, y: 7, sw: 8, cs: 7, id: 67 + (0x69, 1), // x: 9, y: 7, sw: 2, cs:37, id: 71 + (0x07, 0), // x: 1, y: 8, sw: 1, cs: 8, id: 40 + (0x25, 0), // x: 2, y: 8, sw: 2, cs: 8, id: 44 + (0x43, 0), // x: 3, y: 8, sw: 3, cs: 8, id: 48 + (0x61, 0), // x: 4, y: 8, sw: 4, cs: 8, id: 52 + (0x7f, 0), // x: 5, y: 8, sw: 5, cs: 8, id: 56 + (0x9d, 0), // x: 6, y: 8, sw: 6, cs: 8, id: 60 + (0x07, 1), // x: 7, y: 8, sw: 7, cs: 8, id: 64 + (0x25, 1), // x: 8, y: 8, sw: 8, cs: 8, id: 68 + (0x6a, 1), // x: 9, y: 8, sw: 2, cs:38, id: 72 + (0x08, 0), // x: 1, y: 9, sw: 1, cs: 9, id: 73 + (0x26, 0), // x: 2, y: 9, sw: 2, cs: 9, id: 81 + (0x44, 0), // x: 3, y: 9, sw: 3, cs: 9, id: 89 + (0x62, 0), // x: 4, y: 9, sw: 4, cs: 9, id: 97 + (0x80, 0), // x: 5, y: 9, sw: 5, cs: 9, id:105 + (0x9e, 0), // x: 6, y: 9, sw: 6, cs: 9, id:113 + (0x08, 1), // x: 7, y: 9, sw: 7, cs: 9, id:121 + (0x26, 1), // x: 8, y: 9, sw: 8, cs: 9, id:129 + (0x6b, 1), // x: 9, y: 9, sw: 2, cs:39, id:137 + (0x09, 0), // x: 1, y:10, sw: 1, cs:10, id: 74 + (0x27, 0), // x: 2, y:10, sw: 2, cs:10, id: 82 + (0x45, 0), // x: 3, y:10, sw: 3, cs:10, id: 90 + (0x63, 0), // x: 4, y:10, sw: 4, cs:10, id: 98 + (0x81, 0), // x: 5, y:10, sw: 5, cs:10, id:106 + (0x9f, 0), // x: 6, y:10, sw: 6, cs:10, id:114 + (0x09, 1), // x: 7, y:10, sw: 7, cs:10, id:122 + (0x27, 1), // x: 8, y:10, sw: 8, cs:10, id:130 + (0x67, 1), // x: 9, y:10, sw: 2, cs:35, id:138 + (0x0a, 0), // x: 1, y:11, sw: 1, cs:11, id: 75 + (0x28, 0), // x: 2, y:11, sw: 2, cs:11, id: 83 + (0x46, 0), // x: 3, y:11, sw: 3, cs:11, id: 91 + (0x64, 0), // x: 4, y:11, sw: 4, cs:11, id: 99 + (0x82, 0), // x: 5, y:11, sw: 5, cs:11, id:107 + (0xa0, 0), // x: 6, y:11, sw: 6, cs:11, id:115 + (0x0a, 1), // x: 7, y:11, sw: 7, cs:11, id:123 + (0x28, 1), // x: 8, y:11, sw: 8, cs:11, id:131 + (0x71, 1), // x: 9, y:11, sw: 3, cs:36, id:139 + (0x0b, 0), // x: 1, y:12, sw: 1, cs:12, id: 76 + (0x29, 0), // x: 2, y:12, sw: 2, cs:12, id: 84 + (0x47, 0), // x: 3, y:12, sw: 3, cs:12, id: 92 + (0x65, 0), // x: 4, y:12, sw: 4, cs:12, id:100 + (0x83, 0), // x: 5, y:12, sw: 5, cs:12, id:108 + (0xa1, 0), // x: 6, y:12, sw: 6, cs:12, id:116 + (0x0b, 1), // x: 7, y:12, sw: 7, cs:12, id:124 + (0x29, 1), // x: 8, y:12, sw: 8, cs:12, id:132 + (0x72, 1), // x: 9, y:12, sw: 3, cs:37, id:140 + (0x0c, 0), // x: 1, y:13, sw: 1, cs:13, id: 77 + (0x2a, 0), // x: 2, y:13, sw: 2, cs:13, id: 85 + (0x48, 0), // x: 3, y:13, sw: 3, cs:13, id: 93 + (0x66, 0), // x: 4, y:13, sw: 4, cs:13, id:101 + (0x84, 0), // x: 5, y:13, sw: 5, cs:13, id:109 + (0xa2, 0), // x: 6, y:13, sw: 6, cs:13, id:117 + (0x0c, 1), // x: 7, y:13, sw: 7, cs:13, id:125 + (0x2a, 1), // x: 8, y:13, sw: 8, cs:13, id:133 + (0x73, 1), // x: 9, y:13, sw: 3, cs:38, id:141 + (0x0d, 0), // x: 1, y:14, sw: 1, cs:14, id: 78 + (0x2b, 0), // x: 2, y:14, sw: 2, cs:14, id: 86 + (0x49, 0), // x: 3, y:14, sw: 3, cs:14, id: 94 + (0x67, 0), // x: 4, y:14, sw: 4, cs:14, id:102 + (0x85, 0), // x: 5, y:14, sw: 5, cs:14, id:110 + (0xa3, 0), // x: 6, y:14, sw: 6, cs:14, id:118 + (0x0d, 1), // x: 7, y:14, sw: 7, cs:14, id:126 + (0x2b, 1), // x: 8, y:14, sw: 8, cs:14, id:134 + (0x70, 1), // x: 9, y:14, sw: 3, cs:35, id:142 + (0x0e, 0), // x: 1, y:15, sw: 1, cs:15, id: 79 + (0x2c, 0), // x: 2, y:15, sw: 2, cs:15, id: 87 + (0x4a, 0), // x: 3, y:15, sw: 3, cs:15, id: 95 + (0x68, 0), // x: 4, y:15, sw: 4, cs:15, id:103 + (0x86, 0), // x: 5, y:15, sw: 5, cs:15, id:111 + (0xa4, 0), // x: 6, y:15, sw: 6, cs:15, id:119 + (0x0e, 1), // x: 7, y:15, sw: 7, cs:15, id:127 + (0x2c, 1), // x: 8, y:15, sw: 8, cs:15, id:135 + (0x7a, 1), // x: 9, y:15, sw: 4, cs:36, id:143 + (0x0f, 0), // x: 1, y:16, sw: 1, cs:16, id: 80 + (0x2d, 0), // x: 2, y:16, sw: 2, cs:16, id: 88 + (0x4b, 0), // x: 3, y:16, sw: 3, cs:16, id: 96 + (0x69, 0), // x: 4, y:16, sw: 4, cs:16, id:104 + (0x87, 0), // x: 5, y:16, sw: 5, cs:16, id:112 + (0xa5, 0), // x: 6, y:16, sw: 6, cs:16, id:120 + (0x0f, 1), // x: 7, y:16, sw: 7, cs:16, id:128 + (0x2d, 1), // x: 8, y:16, sw: 8, cs:16, id:136 + (0x7b, 1), // x: 9, y:16, sw: 4, cs:37, id:144 + (0x10, 0), // x: 1, y:17, sw: 1, cs:17, id:145 + (0x2e, 0), // x: 2, y:17, sw: 2, cs:17, id:161 + (0x4c, 0), // x: 3, y:17, sw: 3, cs:17, id:177 + (0x6a, 0), // x: 4, y:17, sw: 4, cs:17, id:193 + (0x88, 0), // x: 5, y:17, sw: 5, cs:17, id:209 + (0xa6, 0), // x: 6, y:17, sw: 6, cs:17, id:225 + (0x10, 1), // x: 7, y:17, sw: 7, cs:17, id:241 + (0x2e, 1), // x: 8, y:17, sw: 8, cs:17, id:257 + (0x7c, 1), // x: 9, y:17, sw: 4, cs:38, id:273 + (0x11, 0), // x: 1, y:18, sw: 1, cs:18, id:146 + (0x2f, 0), // x: 2, y:18, sw: 2, cs:18, id:162 + (0x4d, 0), // x: 3, y:18, sw: 3, cs:18, id:178 + (0x6b, 0), // x: 4, y:18, sw: 4, cs:18, id:194 + (0x89, 0), // x: 5, y:18, sw: 5, cs:18, id:210 + (0xa7, 0), // x: 6, y:18, sw: 6, cs:18, id:226 + (0x11, 1), // x: 7, y:18, sw: 7, cs:18, id:242 + (0x2f, 1), // x: 8, y:18, sw: 8, cs:18, id:258 + (0x79, 1), // x: 9, y:18, sw: 4, cs:35, id:274 + (0x12, 0), // x: 1, y:19, sw: 1, cs:19, id:147 + (0x30, 0), // x: 2, y:19, sw: 2, cs:19, id:163 + (0x4e, 0), // x: 3, y:19, sw: 3, cs:19, id:179 + (0x6c, 0), // x: 4, y:19, sw: 4, cs:19, id:195 + (0x8a, 0), // x: 5, y:19, sw: 5, cs:19, id:211 + (0xa8, 0), // x: 6, y:19, sw: 6, cs:19, id:227 + (0x12, 1), // x: 7, y:19, sw: 7, cs:19, id:243 + (0x30, 1), // x: 8, y:19, sw: 8, cs:19, id:259 + (0x83, 1), // x: 9, y:19, sw: 5, cs:36, id:275 + (0x13, 0), // x: 1, y:20, sw: 1, cs:20, id:148 + (0x31, 0), // x: 2, y:20, sw: 2, cs:20, id:164 + (0x4f, 0), // x: 3, y:20, sw: 3, cs:20, id:180 + (0x6d, 0), // x: 4, y:20, sw: 4, cs:20, id:196 + (0x8b, 0), // x: 5, y:20, sw: 5, cs:20, id:212 + (0xa9, 0), // x: 6, y:20, sw: 6, cs:20, id:228 + (0x13, 1), // x: 7, y:20, sw: 7, cs:20, id:244 + (0x31, 1), // x: 8, y:20, sw: 8, cs:20, id:260 + (0x84, 1), // x: 9, y:20, sw: 5, cs:37, id:276 + (0x14, 0), // x: 1, y:21, sw: 1, cs:21, id:149 + (0x32, 0), // x: 2, y:21, sw: 2, cs:21, id:165 + (0x50, 0), // x: 3, y:21, sw: 3, cs:21, id:181 + (0x6e, 0), // x: 4, y:21, sw: 4, cs:21, id:197 + (0x8c, 0), // x: 5, y:21, sw: 5, cs:21, id:213 + (0xaa, 0), // x: 6, y:21, sw: 6, cs:21, id:229 + (0x14, 1), // x: 7, y:21, sw: 7, cs:21, id:245 + (0x32, 1), // x: 8, y:21, sw: 8, cs:21, id:261 + (0x85, 1), // x: 9, y:21, sw: 5, cs:38, id:277 + (0x15, 0), // x: 1, y:22, sw: 1, cs:22, id:150 + (0x33, 0), // x: 2, y:22, sw: 2, cs:22, id:166 + (0x51, 0), // x: 3, y:22, sw: 3, cs:22, id:182 + (0x6f, 0), // x: 4, y:22, sw: 4, cs:22, id:198 + (0x8d, 0), // x: 5, y:22, sw: 5, cs:22, id:214 + (0xab, 0), // x: 6, y:22, sw: 6, cs:22, id:230 + (0x15, 1), // x: 7, y:22, sw: 7, cs:22, id:246 + (0x33, 1), // x: 8, y:22, sw: 8, cs:22, id:262 + (0x82, 1), // x: 9, y:22, sw: 5, cs:35, id:278 + (0x16, 0), // x: 1, y:23, sw: 1, cs:23, id:151 + (0x34, 0), // x: 2, y:23, sw: 2, cs:23, id:167 + (0x52, 0), // x: 3, y:23, sw: 3, cs:23, id:183 + (0x70, 0), // x: 4, y:23, sw: 4, cs:23, id:199 + (0x8e, 0), // x: 5, y:23, sw: 5, cs:23, id:215 + (0xac, 0), // x: 6, y:23, sw: 6, cs:23, id:231 + (0x16, 1), // x: 7, y:23, sw: 7, cs:23, id:247 + (0x34, 1), // x: 8, y:23, sw: 8, cs:23, id:263 + (0x8c, 1), // x: 9, y:23, sw: 6, cs:36, id:279 + (0x17, 0), // x: 1, y:24, sw: 1, cs:24, id:152 + (0x35, 0), // x: 2, y:24, sw: 2, cs:24, id:168 + (0x53, 0), // x: 3, y:24, sw: 3, cs:24, id:184 + (0x71, 0), // x: 4, y:24, sw: 4, cs:24, id:200 + (0x8f, 0), // x: 5, y:24, sw: 5, cs:24, id:216 + (0xad, 0), // x: 6, y:24, sw: 6, cs:24, id:232 + (0x17, 1), // x: 7, y:24, sw: 7, cs:24, id:248 + (0x35, 1), // x: 8, y:24, sw: 8, cs:24, id:264 + (0x8d, 1), // x: 9, y:24, sw: 6, cs:37, id:280 + (0x18, 0), // x: 1, y:25, sw: 1, cs:25, id:153 + (0x36, 0), // x: 2, y:25, sw: 2, cs:25, id:169 + (0x54, 0), // x: 3, y:25, sw: 3, cs:25, id:185 + (0x72, 0), // x: 4, y:25, sw: 4, cs:25, id:201 + (0x90, 0), // x: 5, y:25, sw: 5, cs:25, id:217 + (0xae, 0), // x: 6, y:25, sw: 6, cs:25, id:233 + (0x18, 1), // x: 7, y:25, sw: 7, cs:25, id:249 + (0x36, 1), // x: 8, y:25, sw: 8, cs:25, id:265 + (0x8e, 1), // x: 9, y:25, sw: 6, cs:38, id:281 + (0x19, 0), // x: 1, y:26, sw: 1, cs:26, id:154 + (0x37, 0), // x: 2, y:26, sw: 2, cs:26, id:170 + (0x55, 0), // x: 3, y:26, sw: 3, cs:26, id:186 + (0x73, 0), // x: 4, y:26, sw: 4, cs:26, id:202 + (0x91, 0), // x: 5, y:26, sw: 5, cs:26, id:218 + (0xaf, 0), // x: 6, y:26, sw: 6, cs:26, id:234 + (0x19, 1), // x: 7, y:26, sw: 7, cs:26, id:250 + (0x37, 1), // x: 8, y:26, sw: 8, cs:26, id:266 + (0x8b, 1), // x: 9, y:26, sw: 6, cs:35, id:282 + (0x1a, 0), // x: 1, y:27, sw: 1, cs:27, id:155 + (0x38, 0), // x: 2, y:27, sw: 2, cs:27, id:171 + (0x56, 0), // x: 3, y:27, sw: 3, cs:27, id:187 + (0x74, 0), // x: 4, y:27, sw: 4, cs:27, id:203 + (0x92, 0), // x: 5, y:27, sw: 5, cs:27, id:219 + (0xb0, 0), // x: 6, y:27, sw: 6, cs:27, id:235 + (0x1a, 1), // x: 7, y:27, sw: 7, cs:27, id:251 + (0x38, 1), // x: 8, y:27, sw: 8, cs:27, id:267 + (0x95, 1), // x: 9, y:27, sw: 7, cs:36, id:283 + (0x1b, 0), // x: 1, y:28, sw: 1, cs:28, id:156 + (0x39, 0), // x: 2, y:28, sw: 2, cs:28, id:172 + (0x57, 0), // x: 3, y:28, sw: 3, cs:28, id:188 + (0x75, 0), // x: 4, y:28, sw: 4, cs:28, id:204 + (0x93, 0), // x: 5, y:28, sw: 5, cs:28, id:220 + (0xb1, 0), // x: 6, y:28, sw: 6, cs:28, id:236 + (0x1b, 1), // x: 7, y:28, sw: 7, cs:28, id:252 + (0x39, 1), // x: 8, y:28, sw: 8, cs:28, id:268 + (0x96, 1), // x: 9, y:28, sw: 7, cs:37, id:284 + (0x1c, 0), // x: 1, y:29, sw: 1, cs:29, id:157 + (0x3a, 0), // x: 2, y:29, sw: 2, cs:29, id:173 + (0x58, 0), // x: 3, y:29, sw: 3, cs:29, id:189 + (0x76, 0), // x: 4, y:29, sw: 4, cs:29, id:205 + (0x94, 0), // x: 5, y:29, sw: 5, cs:29, id:221 + (0xb2, 0), // x: 6, y:29, sw: 6, cs:29, id:237 + (0x1c, 1), // x: 7, y:29, sw: 7, cs:29, id:253 + (0x3a, 1), // x: 8, y:29, sw: 8, cs:29, id:269 + (0x97, 1), // x: 9, y:29, sw: 7, cs:38, id:285 + (0x1d, 0), // x: 1, y:30, sw: 1, cs:30, id:158 + (0x3b, 0), // x: 2, y:30, sw: 2, cs:30, id:174 + (0x59, 0), // x: 3, y:30, sw: 3, cs:30, id:190 + (0x77, 0), // x: 4, y:30, sw: 4, cs:30, id:206 + (0x95, 0), // x: 5, y:30, sw: 5, cs:30, id:222 + (0xb3, 0), // x: 6, y:30, sw: 6, cs:30, id:238 + (0x1d, 1), // x: 7, y:30, sw: 7, cs:30, id:254 + (0x3b, 1), // x: 8, y:30, sw: 8, cs:30, id:270 + (0x94, 1), // x: 9, y:30, sw: 7, cs:35, id:286 + (0x5a, 1), // x: 1, y:31, sw: 1, cs:31, id:159 + (0x63, 1), // x: 2, y:31, sw: 2, cs:31, id:175 + (0x6c, 1), // x: 3, y:31, sw: 3, cs:31, id:191 + (0x75, 1), // x: 4, y:31, sw: 4, cs:31, id:207 + (0x7e, 1), // x: 5, y:31, sw: 5, cs:31, id:223 + (0x87, 1), // x: 6, y:31, sw: 6, cs:31, id:239 + (0x90, 1), // x: 7, y:31, sw: 7, cs:31, id:255 + (0x99, 1), // x: 8, y:31, sw: 8, cs:31, id:271 + (0x9e, 1), // x: 9, y:31, sw: 8, cs:36, id:287 + (0x5b, 1), // x: 1, y:32, sw: 1, cs:32, id:160 + (0x64, 1), // x: 2, y:32, sw: 2, cs:32, id:176 + (0x6d, 1), // x: 3, y:32, sw: 3, cs:32, id:192 + (0x76, 1), // x: 4, y:32, sw: 4, cs:32, id:208 + (0x7f, 1), // x: 5, y:32, sw: 5, cs:32, id:224 + (0x88, 1), // x: 6, y:32, sw: 6, cs:32, id:240 + (0x91, 1), // x: 7, y:32, sw: 7, cs:32, id:256 + (0x9a, 1), // x: 8, y:32, sw: 8, cs:32, id:272 + (0x9f, 1), // x: 9, y:32, sw: 8, cs:37, id:288 + (0x5c, 1), // x: 1, y:33, sw: 1, cs:33, id:289 + (0x65, 1), // x: 2, y:33, sw: 2, cs:33, id:290 + (0x6e, 1), // x: 3, y:33, sw: 3, cs:33, id:291 + (0x77, 1), // x: 4, y:33, sw: 4, cs:33, id:292 + (0x80, 1), // x: 5, y:33, sw: 5, cs:33, id:293 + (0x89, 1), // x: 6, y:33, sw: 6, cs:33, id:294 + (0x92, 1), // x: 7, y:33, sw: 7, cs:33, id:295 + (0x9b, 1), // x: 8, y:33, sw: 8, cs:33, id:296 + (0xa0, 1), // x: 9, y:33, sw: 8, cs:38, id:297 + (0x5d, 1), // x: 1, y:34, sw: 1, cs:34, id:298 + (0x66, 1), // x: 2, y:34, sw: 2, cs:34, id:299 + (0x6f, 1), // x: 3, y:34, sw: 3, cs:34, id:300 + (0x78, 1), // x: 4, y:34, sw: 4, cs:34, id:301 + (0x81, 1), // x: 5, y:34, sw: 5, cs:34, id:302 + (0x8a, 1), // x: 6, y:34, sw: 6, cs:34, id:303 + (0x93, 1), // x: 7, y:34, sw: 7, cs:34, id:304 + (0x9c, 1), // x: 8, y:34, sw: 8, cs:34, id:305 + (0x9d, 1), // x: 9, y:34, sw: 8, cs:35, id:306 + ]; + let index: usize = (x as usize) + (y as usize) * 9; + if index < lookup.len() { + lookup[index] + } else { + (0x00, 0) + } +}; + +#[cfg(feature = "framework_ledmatrix")] +pub struct LedMatrix { + pub device: IS31FL3741, +} + +#[cfg(feature = "framework_ledmatrix")] +impl LedMatrix +where + I2C: I2c, +{ + 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> { + self.device.set_scaling(scale) + } + + pub fn new(i2c: I2C, calc_pixel: fn(x: u8, y: u8) -> (u8, u8)) -> LedMatrix { + LedMatrix { + device: IS31FL3741 { + i2c, + address: 0x30, + width: 9, + height: 34, + calc_pixel, + }, + } + } + + pub fn setup(&mut self, delay: &mut DEL) -> Result<(), Is31Error> { + 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<(), Is31Error> { + for x in 0..self.device.width { + for y in 0..self.device.height { + self.device.pixel(x, y, brightness)?; + } + } + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 15a0569..638016f 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::{Error, I2c}; /// A struct to integrate with a new IS31FL3741 powered device. pub struct IS31FL3741 { @@ -23,10 +22,9 @@ pub struct IS31FL3741 { pub calc_pixel: fn(x: u8, y: u8) -> (u8, u8), } -impl IS31FL3741 +impl IS31FL3741 where - I2C: Write, - I2C: Read, + I2C: I2c, { /// 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> { @@ -64,7 +62,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<(), Is31Error> { self.reset(delay)?; self.shutdown(true)?; delay.delay_ms(10); @@ -84,12 +82,12 @@ where /// 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<(), Is31Error> { if x > self.width { - return Err(Error::InvalidLocation(x)); + return Err(Is31Error::InvalidLocation(x)); } if y > self.height { - return Err(Error::InvalidLocation(y)); + return Err(Is31Error::InvalidLocation(y)); } let (pixel, frame) = (self.calc_pixel)(x, y); let bank = if frame == 0 { Page::Pwm1 } else { Page::Pwm2 }; @@ -106,7 +104,7 @@ 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<(), I2cError> { self.write_register(Page::Config, addresses::RESET_REGISTER, addresses::RESET)?; delay.delay_ms(10); Ok(()) @@ -207,15 +205,15 @@ pub mod addresses { } #[derive(Clone, Copy, Debug)] -pub enum Error { +pub enum Is31Error { I2cError(I2cError), InvalidLocation(u8), InvalidFrame(u8), } -impl From for Error { +impl From for Is31Error { fn from(error: E) -> Self { - Error::I2cError(error) + Is31Error::I2cError(error) } }