984: rp pico async i2c implementation r=Dirbaio a=jsgf

This implements an interrupt-driven async i2c master. It is based on https://github.com/embassy-rs/embassy/pull/914, a bit of https://github.com/embassy-rs/embassy/pull/978 and `@ithinuel's` https://github.com/ithinuel/rp2040-async-i2c.git

This is still work-in-progress, and is currently untested.

1006: Removes some of the code duplication for UarteWithIdle r=Dirbaio a=huntc

This PR removes some of the code duplications for `UarteWithIdle` at the slight expense of requiring a split when using idle processing. As the nRF example illustrates though given the LoC removed, this expense seems worth the benefit in terms of maintenance, and the avoidance of copying over methods. My main motivation for this PR was actually due to the `event_endtx` method not having been copied across to the idle-related code.

Tested the uart_idle example on my nRF52840-dk, and from within my app. Both appear to work fine.

Co-authored-by: Jeremy Fitzhardinge <jeremy@goop.org>
Co-authored-by: huntc <huntchr@gmail.com>
This commit is contained in:
bors[bot]
2022-10-12 19:41:52 +00:00
committed by GitHub
5 changed files with 655 additions and 325 deletions

View File

@ -31,3 +31,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
embedded-hal-async = { version = "0.1.0-alpha.1" }
embedded-io = { version = "0.3.0", features = ["async", "defmt"] }
static_cell = "1.0.0"
[profile.release]
debug = true

View File

@ -0,0 +1,102 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::Spawner;
use embassy_rp::i2c::{self, Config};
use embassy_rp::interrupt;
use embassy_time::{Duration, Timer};
use embedded_hal_async::i2c::I2c;
use {defmt_rtt as _, panic_probe as _};
#[allow(dead_code)]
mod mcp23017 {
pub const ADDR: u8 = 0x20; // default addr
macro_rules! mcpregs {
($($name:ident : $val:expr),* $(,)?) => {
$(
pub const $name: u8 = $val;
)*
pub fn regname(reg: u8) -> &'static str {
match reg {
$(
$val => stringify!($name),
)*
_ => panic!("bad reg"),
}
}
}
}
// These are correct for IOCON.BANK=0
mcpregs! {
IODIRA: 0x00,
IPOLA: 0x02,
GPINTENA: 0x04,
DEFVALA: 0x06,
INTCONA: 0x08,
IOCONA: 0x0A,
GPPUA: 0x0C,
INTFA: 0x0E,
INTCAPA: 0x10,
GPIOA: 0x12,
OLATA: 0x14,
IODIRB: 0x01,
IPOLB: 0x03,
GPINTENB: 0x05,
DEFVALB: 0x07,
INTCONB: 0x09,
IOCONB: 0x0B,
GPPUB: 0x0D,
INTFB: 0x0F,
INTCAPB: 0x11,
GPIOB: 0x13,
OLATB: 0x15,
}
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default());
let sda = p.PIN_14;
let scl = p.PIN_15;
let irq = interrupt::take!(I2C1_IRQ);
info!("set up i2c ");
let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, irq, Config::default());
use mcp23017::*;
info!("init mcp23017 config for IxpandO");
// init - a outputs, b inputs
i2c.write(ADDR, &[IODIRA, 0x00]).await.unwrap();
i2c.write(ADDR, &[IODIRB, 0xff]).await.unwrap();
i2c.write(ADDR, &[GPPUB, 0xff]).await.unwrap(); // pullups
let mut val = 1;
loop {
let mut portb = [0];
i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).await.unwrap();
info!("portb = {:02x}", portb[0]);
i2c.write(mcp23017::ADDR, &[GPIOA, val | portb[0]]).await.unwrap();
val = val.rotate_left(1);
// get a register dump
info!("getting register dump");
let mut regs = [0; 22];
i2c.write_read(ADDR, &[0], &mut regs).await.unwrap();
// always get the regdump but only display it if portb'0 is set
if portb[0] & 1 != 0 {
for (idx, reg) in regs.into_iter().enumerate() {
info!("{} => {:02x}", regname(idx as u8), reg);
}
}
Timer::after(Duration::from_millis(100)).await;
}
}