nrf-rs / nrf-hal

A Rust HAL for the nRF family of devices
Apache License 2.0
507 stars 140 forks source link

Using TWIM0 with multiple pin configuration #287

Open kuon opened 3 years ago

kuon commented 3 years ago

I'd like to use TWIM0 with multiple sets of pins in sequence, something like:

        let i2c_0 = Twim::new(cx.device.TWIM0, Pins {
            sda: p0.p0_26.into_floating_input().degrade(),
            scl: p0.p0_27.into_floating_input().degrade(),
        }, K100);
       i2c_0.disable();

        let i2c_1 = Twim::new(cx.device.TWIM0, Pins {
            sda: p0.p0_28.into_floating_input().degrade(),
            scl: p0.p0_29.into_floating_input().degrade(),
        }, K100);
       i2c_1.disable();

      .... later on:

    i2c_0.enable();
   ... use
    i2c_0.disable();
    i2c_1.enable();
   ... use
    i2c_1.disable();

I realize that there is the Twim::free() function which can give me the TWIM0 device back but then I cannot reuse it, so the pins are "lost".

I have 4 i2c devices with same addresses. I just used 8 pins on the nrf52840 thinking I would just enable them in sequence, but I realize it might have been better to use a hardware multiplexer.

fnafnio commented 3 years ago

The PSEL register contains the pin and port (on 52840), so you can use Pin::from_psel_bits which is unsafe, but as the TWIM instance owns the pins this should be sound.

I've added a function like

    pub fn free_with_pins(self) -> (T, Pins) {
        // get pin and port from psel
        let scl_pin = (self.0.psel.scl.read().bits() & 0b111111) as _;
        let sda_pin = (self.0.psel.sda.read().bits() & 0b111111) as _;

        // disconnecting the pin resets the register -> reading PSEL before disconnecting, no reset needed afterwards
        self.0.psel.scl.write(|w| w.connect().disconnected());
        self.0.psel.sda.write(|w| w.connect().disconnected());

        let sda = unsafe { Pin::from_psel_bits(sda_pin) };
        let scl = unsafe { Pin::from_psel_bits(scl_pin) };

        (self.0, Pins { sda, scl })
    }

for this purpose. I guess it could be added to nrf-hal, but I think the port part would need to be feature flagged, as the reset value for all the bits is 1 and not all devices have a port1