Skip to content
Snippets Groups Projects
Commit 295829ec authored by Benjamin Koch's avatar Benjamin Koch
Browse files

some small improvements

parent 6522374c
No related branches found
No related tags found
No related merge requests found
...@@ -72,7 +72,12 @@ fn format_scan_result<const N : usize>(msg : &mut String<N>, scan_result : [Scan ...@@ -72,7 +72,12 @@ fn format_scan_result<const N : usize>(msg : &mut String<N>, scan_result : [Scan
Ok(()) Ok(())
} }
async fn _clockStretch<'d, SCL: gpio::Pin>(scl: &mut Flex<'d, SCL>) -> Result<(), i2c::Error> {
// adapted from arduino-pico:
// https://github.com/earlephilhower/arduino-pico/blob/6e52b72523b11470b2ad2b0578ca1500be238108/libraries/Wire/src/Wire.cpp#L257
// This seems to be the only way to do zero-length writes:
// see https://github.com/raspberrypi/pico-sdk/issues/238
async fn handle_clock_stretching<'d, SCL: gpio::Pin>(scl: &mut Flex<'d, SCL>) -> Result<(), i2c::Error> {
use i2c::Error::*; use i2c::Error::*;
use i2c::AbortReason::*; use i2c::AbortReason::*;
...@@ -88,26 +93,24 @@ async fn _clockStretch<'d, SCL: gpio::Pin>(scl: &mut Flex<'d, SCL>) -> Result<() ...@@ -88,26 +93,24 @@ async fn _clockStretch<'d, SCL: gpio::Pin>(scl: &mut Flex<'d, SCL>) -> Result<()
Second(_) => Err(Abort(ArbitrationLoss)), Second(_) => Err(Abort(ArbitrationLoss)),
} }
} }
// adapted from https://github.com/earlephilhower/arduino-pico/blob/6e52b72523b11470b2ad2b0578ca1500be238108/libraries/Wire/src/Wire.cpp#L257
async fn i2c_write_zero_bytes_middle_part<'d, SCL: gpio::Pin, SDA: gpio::Pin, const FREQ : u64>( async fn i2c_write_zero_bytes_middle_part<'d, SCL: gpio::Pin, SDA: gpio::Pin, const FREQ : u64>(
mut addr: u16, delay: Duration, scl: &mut Flex<'d, SCL>, sda: &mut Flex<'d, SDA>) mut addr: u16, delay: Duration, scl: &mut Flex<'d, SCL>, sda: &mut Flex<'d, SDA>)
-> Result<(), i2c::Error> { -> Result<(), i2c::Error> {
sda.set_as_input(); sda.set_as_input();
Timer::after(delay).await; Timer::after(delay).await;
scl.set_as_input(); scl.set_as_input();
_clockStretch(scl).await?; handle_clock_stretching(scl).await?;
sda.set_as_output(); sda.set_as_output();
Timer::after(delay).await; Timer::after(delay).await;
scl.set_as_output(); scl.set_as_output();
Timer::after(delay).await; Timer::after(delay).await;
for i in 0..8 { for _ in 0..8 {
addr <<= 1; addr <<= 1;
sda.set_level(if (addr & (1 << 7)) != 0 { gpio::Level::High } else { gpio::Level::Low }); sda.set_level(if (addr & (1 << 7)) != 0 { gpio::Level::High } else { gpio::Level::Low });
Timer::after(delay).await; Timer::after(delay).await;
scl.set_as_input(); scl.set_as_input();
Timer::after(delay).await; Timer::after(delay).await;
_clockStretch(scl).await?; handle_clock_stretching(scl).await?;
scl.set_as_output(); scl.set_as_output();
Timer::after(Duration::from_micros(5)).await; // Ensure we don't change too close to clock edge Timer::after(Duration::from_micros(5)).await; // Ensure we don't change too close to clock edge
} }
...@@ -115,7 +118,7 @@ async fn i2c_write_zero_bytes_middle_part<'d, SCL: gpio::Pin, SDA: gpio::Pin, co ...@@ -115,7 +118,7 @@ async fn i2c_write_zero_bytes_middle_part<'d, SCL: gpio::Pin, SDA: gpio::Pin, co
sda.set_as_input(); sda.set_as_input();
Timer::after(delay).await; Timer::after(delay).await;
scl.set_as_input(); scl.set_as_input();
_clockStretch(scl).await?; handle_clock_stretching(scl).await?;
let result = if sda.is_low() { let result = if sda.is_low() {
Ok(()) Ok(())
...@@ -129,13 +132,12 @@ async fn i2c_write_zero_bytes_middle_part<'d, SCL: gpio::Pin, SDA: gpio::Pin, co ...@@ -129,13 +132,12 @@ async fn i2c_write_zero_bytes_middle_part<'d, SCL: gpio::Pin, SDA: gpio::Pin, co
result result
} }
async fn i2c_write_zero_bytes<SCL: gpio::Pin, SDA: gpio::Pin, const FREQ : u64>(mut addr: u16, scl: &mut SCL, sda: &mut SDA) async fn i2c_write_zero_bytes<SCL: gpio::Pin, SDA: gpio::Pin, const FREQ : u64>(addr: u16, scl: &mut SCL, sda: &mut SDA)
-> Result<(), i2c::Error> { -> Result<(), i2c::Error> {
use i2c::Error::*; use i2c::Error::*;
use i2c::AbortReason::*; use i2c::AbortReason::*;
let delay = Duration::from_micros((1000000 / FREQ) / 2); let delay = Duration::from_micros((1000000 / FREQ) / 2);
let ack = false;
let mut sda = Flex::new(sda); let mut sda = Flex::new(sda);
let mut scl = Flex::new(scl); let mut scl = Flex::new(scl);
...@@ -181,18 +183,13 @@ async fn i2c_task(mut i2c_peri: embassy_rp::peripherals::I2C0, ...@@ -181,18 +183,13 @@ async fn i2c_task(mut i2c_peri: embassy_rp::peripherals::I2C0,
const MAX_ADDRESS : u8 = 128; const MAX_ADDRESS : u8 = 128;
let mut scan_result = [ScanResult::Error; MAX_ADDRESS as usize]; let mut scan_result = [ScanResult::Error; MAX_ADDRESS as usize];
for i in 0..MAX_ADDRESS { for i in 0..MAX_ADDRESS {
match i2c_write_zero_bytes::<_, _, 400_000>(i as u16, &mut scl, &mut sda).await { scan_result[i as usize] = match i2c_write_zero_bytes::<_, _, 400_000>(i as u16, &mut scl, &mut sda).await {
Result::Ok(()) => { Result::Ok(()) => ScanResult::Ack,
//info!("I2C ok: {}", i); Result::Err(Abort(NoAcknowledge)) => ScanResult::NAck,
scan_result[i as usize] = ScanResult::Ack Result::Err(AddressReserved(_)) => ScanResult::Reserved,
},
Result::Err(Abort(NoAcknowledge)) =>
scan_result[i as usize] = ScanResult::NAck,
Result::Err(AddressReserved(_)) =>
scan_result[i as usize] = ScanResult::Reserved,
Result::Err(e) => { Result::Err(e) => {
scan_result[i as usize] = ScanResult::Error; warn!("I2C problem: {:02x}: {:?}", i, e);
warn!("I2C problem: {:?}", e); ScanResult::Error
} }
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment