summaryrefslogtreecommitdiff
path: root/examples/rp/src/bin/i2c_async.rs
blob: d1a2e3cd759e7d1c8b5112a5e79e56fbcd71e964 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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;
    }
}