From ba0b98e53d8946da21e813ccb959427595e1c225 Mon Sep 17 00:00:00 2001 From: Benjamin Koch <bbbsnowball@gmail.com> Date: Sat, 13 May 2023 03:09:33 +0200 Subject: [PATCH] add very broken I2C scan --- firmware/rust1/Cargo.lock | 1 + firmware/rust1/Cargo.toml | 2 + firmware/rust1/src/bin/heizung.rs | 150 +++++++++++++++++++++++------- 3 files changed, 121 insertions(+), 32 deletions(-) diff --git a/firmware/rust1/Cargo.lock b/firmware/rust1/Cargo.lock index 2226689..6dcddbb 100644 --- a/firmware/rust1/Cargo.lock +++ b/firmware/rust1/Cargo.lock @@ -616,6 +616,7 @@ dependencies = [ "fixed", "fixed-macro", "futures", + "heapless", "log", "lora-phy", "lorawan", diff --git a/firmware/rust1/Cargo.toml b/firmware/rust1/Cargo.toml index 2548ef4..678eb3e 100644 --- a/firmware/rust1/Cargo.toml +++ b/firmware/rust1/Cargo.toml @@ -46,5 +46,7 @@ log = "0.4" pio-proc = "0.2" pio = "0.2.1" +heapless = "0.7.16" + [profile.release] debug = true diff --git a/firmware/rust1/src/bin/heizung.rs b/firmware/rust1/src/bin/heizung.rs index 42f6588..e461f5e 100644 --- a/firmware/rust1/src/bin/heizung.rs +++ b/firmware/rust1/src/bin/heizung.rs @@ -10,12 +10,13 @@ use embassy_rp::gpio::{Input, Level, Output, Pull}; use embassy_rp::i2c::{self}; use embassy_rp::interrupt; use embedded_hal_async::i2c::I2c; -use embassy_rp::peripherals::UART0; -use embassy_rp::uart::{self, Async, UartRx, UartTx, Parity}; +use embassy_rp::peripherals::{UART0, I2C0}; +use embassy_rp::uart::{self, UartRx, Parity}; use {defmt_rtt as _, panic_probe as _}; +use heapless::String; #[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART0, Async>) { +async fn reader(mut rx: UartRx<'static, UART0, uart::Async>) { info!("Reading..."); loop { let mut buf = [0; 1]; @@ -26,50 +27,135 @@ async fn reader(mut rx: UartRx<'static, UART0, Async>) { } } +fn append_hex1<const N : usize>(s : &mut String<N>, num : u8) -> Result<(), ()> { + let ch = if num < 10 { + ('0' as u8 + num) as char + } else { + ('a' as u8 + num - 10) as char + }; + s.push(ch) +} + +fn append_hex2<const N : usize>(s : &mut String<N>, num : u8) -> Result<(), ()> { + append_hex1(s, num >> 4)?; + append_hex1(s, num & 0xf) +} + +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +enum ScanResult { + NAck, + Ack, + Reserved, + Error +} + +fn format_scan_result<const N : usize>(msg : &mut String<N>, scan_result : [ScanResult; 128]) -> Result<(), ()> { + const MAX_ADDRESS : u8 = 128; + for i in 0..MAX_ADDRESS/16 { + let base = i*16; + append_hex2(msg, base)?; + msg.push_str(":")?; + for j in 0..16 { + msg.push_str(" ")?; + match scan_result[(base+j) as usize] { + ScanResult::Ack => append_hex2(msg, base+j)?, + ScanResult::NAck => msg.push_str("--")?, + ScanResult::Reserved => msg.push_str("rr")?, + ScanResult::Error => msg.push_str("!!")?, + } + } + msg.push_str("\n")?; + } + Ok(()) +} + +#[embassy_executor::task] +async fn i2c_task(mut i2c: i2c::I2c<'static, I2C0, i2c::Async>) { + use i2c::Error::*; + use i2c::AbortReason::*; + + loop { + const MAX_ADDRESS : u8 = 128; + let mut scan_result = [ScanResult::Error; MAX_ADDRESS as usize]; + for i in 0..MAX_ADDRESS { + //NOTE It looks like the blocking implementation doesn't accept an empty buffer + // but the async one does. Lucky for us because we need that here! + // -> Actually, it doesn't. It just hangs. + //info!("I2C testing: {}", i); + //FIXME Don't test with buffer size 1 because that will actually write, which can cause all kinds of issues! + match i2c.write_async(i.into(), [0; 1]).await { + Result::Ok(()) => { + //info!("I2C ok: {}", i); + scan_result[i as usize] = ScanResult::Ack + }, + Result::Err(Abort(NoAcknowledge)) => + scan_result[i as usize] = ScanResult::NAck, + Result::Err(AddressReserved(_)) => + scan_result[i as usize] = ScanResult::Reserved, + Result::Err(e) => { + scan_result[i as usize] = ScanResult::Error; + warn!("I2C problem: {:?}", e); + } + } + } + + const MSG_LEN : usize = (MAX_ADDRESS as usize)*3 + (MAX_ADDRESS as usize)/16*6; + let mut msg = String::<MSG_LEN>::new(); + match format_scan_result(&mut msg, scan_result) { + Ok(()) => info!("I2C scan result:\n{}", msg), + Err(()) => info!("I2C scan result: too long for our buffer!"), + } + + Timer::after(Duration::from_secs(1)).await; + } +} #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); + info!("starting"); // pinout: - let mut drive1 = Output::new(p.PIN_0, Level::Low); - let mut drive2 = Output::new(p.PIN_1, Level::Low); + let mut _drive1 = Output::new(p.PIN_0, Level::Low); + let mut _drive2 = Output::new(p.PIN_1, Level::Low); //let LED_W = p.PIN_2; - let ws2812_display = p.PIN_2; + let _ws2812_display = p.PIN_2; //let LED_Y = p.PIN_3; - let mut en_measure_current = Output::new(p.PIN_3, Level::Low); + let mut _en_measure_current = Output::new(p.PIN_3, Level::Low); let mut led_b = Output::new(p.PIN_4, Level::Low); - let mut led_g = Output::new(p.PIN_5, Level::Low); - let mut led_r = Output::new(p.PIN_6, Level::Low); - let matrix_in1 = Input::new(p.PIN_7, Pull::Up); - let sbu1 = p.PIN_8; - let sbu2 = p.PIN_9; - let vbus_det = p.PIN_10; - let button_boot2 = Input::new(p.PIN_11, Pull::Up); + let mut _led_g = Output::new(p.PIN_5, Level::Low); + let mut _led_r = Output::new(p.PIN_6, Level::Low); + let _matrix_in1 = Input::new(p.PIN_7, Pull::Up); + let _sbu1 = p.PIN_8; + let _sbu2 = p.PIN_9; + let _vbus_det = p.PIN_10; + let _button_boot2 = Input::new(p.PIN_11, Pull::Up); let sda = p.PIN_12; let scl = p.PIN_13; - let ws2811_red_in = Input::new(p.PIN_14, Pull::None); - let tx_en = p.PIN_15; - let tx = p.PIN_16; + let _ws2811_red_in = Input::new(p.PIN_14, Pull::None); + let _tx_en = p.PIN_15; + let _tx = p.PIN_16; let rx = p.PIN_17; - let matrix_in2 = Input::new(p.PIN_18, Pull::Up); - let reed3 = Input::new(p.PIN_19, Pull::Up); - let reed4 = Input::new(p.PIN_20, Pull::Up); - let reed2 = Input::new(p.PIN_21, Pull::Up); - let reed1 = Input::new(p.PIN_22, Pull::Up); - let matrix_in3 = Input::new(p.PIN_23, Pull::Up); - let digout1 = p.PIN_24; - let digout2 = p.PIN_25; - let analog_in1 = p.PIN_26; - let current2 = p.PIN_27; - let current1 = p.PIN_28; - let measure_vcc = p.PIN_29; - - info!("set up i2c "); + let _matrix_in2 = Input::new(p.PIN_18, Pull::Up); + let _reed3 = Input::new(p.PIN_19, Pull::Up); + let _reed4 = Input::new(p.PIN_20, Pull::Up); + let _reed2 = Input::new(p.PIN_21, Pull::Up); + let _reed1 = Input::new(p.PIN_22, Pull::Up); + let _matrix_in3 = Input::new(p.PIN_23, Pull::Up); + let _digout1 = p.PIN_24; + let _digout2 = p.PIN_25; + let _analog_in1 = p.PIN_26; + let _current2 = p.PIN_27; + let _current1 = p.PIN_28; + let _measure_vcc = p.PIN_29; + + info!("set up i2c"); let i2c_irq = interrupt::take!(I2C0_IRQ); let mut i2c_config = i2c::Config::default(); i2c_config.frequency = 400_000; - let mut i2c = i2c::I2c::new_async(p.I2C0, scl, sda, i2c_irq, i2c_config); + let i2c = i2c::I2c::new_async(p.I2C0, scl, sda, i2c_irq, i2c_config); + unwrap!(spawner.spawn(i2c_task(i2c))); // use 19200 baud in 8E1 mode - not great but Modbus default let mut uart_config = uart::Config::default(); -- GitLab