How to borrow Peripherals struct?

I'm working with the ESP32-C3 and trying to initialize peripherals in separate functions. However, I'm struggling to borrow the Peripherals struct for each function. I get the error:

move occurs because `peripherals.pins.gpio4` has type `Gpio4<esp_idf_hal::gpio::Unknown>`, which does not implement the `Copy` trait

Here's the code:

main.rs

    // // Initialize peripherals
    let peripherals = Peripherals::take().unwrap();

    // I2C
    let mut i2c = init::i2c_peripheral(&peripherals);
    let mut expander = init::sx1509_init(&mut i2c);
    // ADC
    let (mut powered_adc1, mut a1_ch0) = init::adc_init(&peripherals);

init.rs

pub fn i2c_peripheral(
    peripherals: &Peripherals,
) -> i2c::Master<
    i2c::I2C0,
    esp_idf_hal::gpio::Gpio4<gpio::InputOutput>,
    esp_idf_hal::gpio::Gpio5<gpio::Output>,
> {
    let sda = peripherals.pins.gpio4.into_input_output().unwrap();
    let scl = peripherals.pins.gpio5.into_output().unwrap();
    let i2c = peripherals.i2c0;

    let config = <i2c::config::MasterConfig as Default>::default().baudrate(400.kHz().into());
    let i2c =
        i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    i2c
}

pub fn sx1509_init(
    i2c: &mut i2c::Master<i2c::I2C0, gpio::Gpio4<gpio::InputOutput>, gpio::Gpio5<gpio::Output>>,
) -> sx1509::Sx1509<i2c::Master<i2c::I2C0, gpio::Gpio4<gpio::InputOutput>, gpio::Gpio5<gpio::Output>>>
{
    let mut expander = sx1509::Sx1509::new(i2c, sx1509::DEFAULT_ADDRESS);
    // ptype(&expander);
    expander.borrow(i2c).software_reset().unwrap();
    expander.borrow(i2c).set_bank_a_direction(0).unwrap();
    expander.borrow(i2c).set_bank_b_direction(0xFF).unwrap();

    expander
}

pub fn adc_init(
    peripherals: &Peripherals,
) -> (PoweredAdc<adc::ADC1>, gpio::Gpio0<Atten11dB<adc::ADC1>>) {
    let pin = peripherals.pins.gpio0.into_analog_atten_11db().unwrap();
    let config = adc::config::Config::new().calibration(true);
    let adc = PoweredAdc::new(peripherals.adc1, config).unwrap();

    (adc, pin)
}

Which results in the errors

error[E0507]: cannot move out of `peripherals.pins.gpio4` which is behind a shared reference
    --> src/init.rs:15:15
     |
15   |     let sda = peripherals.pins.gpio4.into_input_output().unwrap();
     |               ^^^^^^^^^^^^^^^^^^^^^^ ------------------- `peripherals.pins.gpio4` moved due to this method call
     |               |
     |               move occurs because `peripherals.pins.gpio4` has type `Gpio4<esp_idf_hal::gpio::Unknown>`, which does not implement the `Copy` trait
     |
note: this function takes ownership of the receiver `self`, which moves `peripherals.pins.gpio4`
    --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/gpio.rs:1465:5
     |
1465 |     pin!(Gpio4:4,   IO,   RTC:4,  ADC1:4, NODAC:0, NOTOUCH:0);
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     = note: this error originates in the macro `impl_input_output` which comes from the expansion of the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0507]: cannot move out of `peripherals.pins.gpio5` which is behind a shared reference
    --> src/init.rs:16:15
     |
16   |     let scl = peripherals.pins.gpio5.into_output().unwrap();
     |               ^^^^^^^^^^^^^^^^^^^^^^ ------------- `peripherals.pins.gpio5` moved due to this method call
     |               |
     |               move occurs because `peripherals.pins.gpio5` has type `Gpio5<esp_idf_hal::gpio::Unknown>`, which does not implement the `Copy` trait
     |
note: this function takes ownership of the receiver `self`, which moves `peripherals.pins.gpio5`
    --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/gpio.rs:1466:5
     |
1466 |     pin!(Gpio5:5,   IO,   RTC:5,  ADC2:0, NODAC:0, NOTOUCH:0);
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     = note: this error originates in the macro `impl_input_output` which comes from the expansion of the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0507]: cannot move out of `peripherals.i2c0` which is behind a shared reference
  --> src/init.rs:17:15
   |
17 |     let i2c = peripherals.i2c0;
   |               ^^^^^^^^^^^^^^^^
   |               |
   |               move occurs because `peripherals.i2c0` has type `I2C0`, which does not implement the `Copy` trait
   |               help: consider borrowing here: `&peripherals.i2c0`

error[E0507]: cannot move out of `peripherals.pins.gpio0` which is behind a shared reference
    --> src/init.rs:41:15
     |
41   |     let pin = peripherals.pins.gpio0.into_analog_atten_11db().unwrap();
     |               ^^^^^^^^^^^^^^^^^^^^^^ ------------------------ `peripherals.pins.gpio0` moved due to this method call
     |               |
     |               move occurs because `peripherals.pins.gpio0` has type `Gpio0<esp_idf_hal::gpio::Unknown>`, which does not implement the `Copy` trait
     |
note: this function takes ownership of the receiver `self`, which moves `peripherals.pins.gpio0`
    --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/gpio.rs:1461:5
     |
1461 |     pin!(Gpio0:0,   IO,   RTC:0,  ADC1:0, NODAC:0, NOTOUCH:0);
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     = note: this error originates in the macro `impl_adc` which comes from the expansion of the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0507]: cannot move out of `peripherals.adc1` which is behind a shared reference
  --> src/init.rs:43:31
   |
43 |     let adc = PoweredAdc::new(peripherals.adc1, config).unwrap();
   |                               ^^^^^^^^^^^^^^^^ move occurs because `peripherals.adc1` has type `ADC1`, which does not implement the `Copy` trait

I also tried borrowing peripherals in the sub-initialization functions but I get errors:
the trait esp_idf_hal::gpio::OutputPinis not implemented for&Gpio4`

Function with peripherals borrow attempt:

pub fn i2c_peripheral(
    peripherals: &Peripherals,
) -> i2c::Master<
    i2c::I2C0,
    esp_idf_hal::gpio::Gpio4<gpio::InputOutput>,
    esp_idf_hal::gpio::Gpio5<gpio::Output>,
> {
    let sda = &peripherals.pins.gpio4.into_input_output().unwrap();
    let scl = &peripherals.pins.gpio5.into_output().unwrap();
    let i2c = &peripherals.i2c0;

    let config = <i2c::config::MasterConfig as Default>::default().baudrate(400.kHz().into());
    let i2c =
        i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    i2c
}

Errors:

error[E0277]: the trait bound `&Gpio4<InputOutput>: esp_idf_hal::gpio::OutputPin` is not satisfied
  --> src/init.rs:21:68
   |
21 |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
   |                                                                    ^^^ the trait `esp_idf_hal::gpio::OutputPin` is not implemented for `&Gpio4<InputOutput>`
   |
   = help: the trait `esp_idf_hal::gpio::OutputPin` is implemented for `Gpio4<MODE>`
note: required by a bound in `MasterPins`
  --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:13:28
   |
13 | pub struct MasterPins<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin> {
   |                            ^^^^^^^^^ required by this bound in `MasterPins`

error[E0277]: the trait bound `&Gpio4<InputOutput>: esp_idf_hal::gpio::InputPin` is not satisfied
  --> src/init.rs:21:68
   |
21 |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
   |                                                                    ^^^ the trait `esp_idf_hal::gpio::InputPin` is not implemented for `&Gpio4<InputOutput>`
   |
   = help: the trait `esp_idf_hal::gpio::InputPin` is implemented for `Gpio4<MODE>`
note: required by a bound in `MasterPins`
  --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:13:40
   |
13 | pub struct MasterPins<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin> {
   |                                        ^^^^^^^^ required by this bound in `MasterPins`

error[E0277]: the trait bound `&Gpio5<esp_idf_hal::gpio::Output>: esp_idf_hal::gpio::OutputPin` is not satisfied
  --> src/init.rs:21:73
   |
21 |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
   |                                                                         ^^^ the trait `esp_idf_hal::gpio::OutputPin` is not implemented for `&Gpio5<esp_idf_hal::gpio::Output>`
   |
   = help: the trait `esp_idf_hal::gpio::OutputPin` is implemented for `Gpio5<MODE>`
note: required by a bound in `MasterPins`
  --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:13:55
   |
13 | pub struct MasterPins<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin> {
   |                                                       ^^^^^^^^^ required by this bound in `MasterPins`

error[E0277]: the trait bound `&Gpio5<esp_idf_hal::gpio::Output>: esp_idf_hal::gpio::InputPin` is not satisfied
  --> src/init.rs:21:73
   |
21 |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
   |                                                                         ^^^ the trait `esp_idf_hal::gpio::InputPin` is not implemented for `&Gpio5<esp_idf_hal::gpio::Output>`
   |
   = help: the trait `esp_idf_hal::gpio::InputPin` is implemented for `Gpio5<MODE>`
note: required by a bound in `MasterPins`
  --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:13:67
   |
13 | pub struct MasterPins<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin> {
   |                                                                   ^^^^^^^^ required by this bound in `MasterPins`

error[E0277]: the trait bound `&Gpio4<InputOutput>: esp_idf_hal::gpio::OutputPin` is not satisfied
   --> src/init.rs:21:50
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         -----------------------------------      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::OutputPin` is not implemented for `&Gpio4<InputOutput>`
    |         |
    |         required by a bound introduced by this call
    |
    = help: the trait `esp_idf_hal::gpio::OutputPin` is implemented for `Gpio4<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master::<I2C, SDA, SCL>::new`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:176:10
    |
176 |     SDA: OutputPin + InputPin,
    |          ^^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master::<I2C, SDA, SCL>::new`

error[E0277]: the trait bound `&Gpio4<InputOutput>: esp_idf_hal::gpio::InputPin` is not satisfied
   --> src/init.rs:21:50
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         -----------------------------------      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::InputPin` is not implemented for `&Gpio4<InputOutput>`
    |         |
    |         required by a bound introduced by this call
    |
    = help: the trait `esp_idf_hal::gpio::InputPin` is implemented for `Gpio4<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master::<I2C, SDA, SCL>::new`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:176:22
    |
176 |     SDA: OutputPin + InputPin,
    |                      ^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master::<I2C, SDA, SCL>::new`

error[E0277]: the trait bound `&Gpio5<esp_idf_hal::gpio::Output>: esp_idf_hal::gpio::OutputPin` is not satisfied
   --> src/init.rs:21:50
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         -----------------------------------      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::OutputPin` is not implemented for `&Gpio5<esp_idf_hal::gpio::Output>`
    |         |
    |         required by a bound introduced by this call
    |
    = help: the trait `esp_idf_hal::gpio::OutputPin` is implemented for `Gpio5<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master::<I2C, SDA, SCL>::new`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:177:10
    |
177 |     SCL: OutputPin + InputPin,
    |          ^^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master::<I2C, SDA, SCL>::new`

error[E0277]: the trait bound `&Gpio5<esp_idf_hal::gpio::Output>: esp_idf_hal::gpio::InputPin` is not satisfied
   --> src/init.rs:21:50
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         -----------------------------------      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::InputPin` is not implemented for `&Gpio5<esp_idf_hal::gpio::Output>`
    |         |
    |         required by a bound introduced by this call
    |
    = help: the trait `esp_idf_hal::gpio::InputPin` is implemented for `Gpio5<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master::<I2C, SDA, SCL>::new`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:177:22
    |
177 |     SCL: OutputPin + InputPin,
    |                      ^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master::<I2C, SDA, SCL>::new`

error[E0308]: mismatched types
   --> src/init.rs:21:45
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         ----------------------------------- ^^^ expected struct `I2C0`, found `&I2C0`
    |         |
    |         arguments to this function are incorrect
    |
note: associated function defined here
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:179:12
    |
179 |     pub fn new(
    |            ^^^

error[E0277]: the trait bound `&Gpio4<InputOutput>: esp_idf_hal::gpio::OutputPin` is not satisfied
   --> src/init.rs:21:9
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::OutputPin` is not implemented for `&Gpio4<InputOutput>`
    |
    = help: the trait `esp_idf_hal::gpio::OutputPin` is implemented for `Gpio4<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:149:10
    |
149 |     SDA: OutputPin + InputPin,
    |          ^^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master`

error[E0277]: the trait bound `&Gpio4<InputOutput>: esp_idf_hal::gpio::InputPin` is not satisfied
   --> src/init.rs:21:9
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::InputPin` is not implemented for `&Gpio4<InputOutput>`
    |
    = help: the trait `esp_idf_hal::gpio::InputPin` is implemented for `Gpio4<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:149:22
    |
149 |     SDA: OutputPin + InputPin,
    |                      ^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master`

error[E0277]: the trait bound `&Gpio5<esp_idf_hal::gpio::Output>: esp_idf_hal::gpio::OutputPin` is not satisfied
   --> src/init.rs:21:9
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::OutputPin` is not implemented for `&Gpio5<esp_idf_hal::gpio::Output>`
    |
    = help: the trait `esp_idf_hal::gpio::OutputPin` is implemented for `Gpio5<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:150:10
    |
150 |     SCL: OutputPin + InputPin,
    |          ^^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master`

error[E0277]: the trait bound `&Gpio5<esp_idf_hal::gpio::Output>: esp_idf_hal::gpio::InputPin` is not satisfied
   --> src/init.rs:21:9
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::InputPin` is not implemented for `&Gpio5<esp_idf_hal::gpio::Output>`
    |
    = help: the trait `esp_idf_hal::gpio::InputPin` is implemented for `Gpio5<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:150:22
    |
150 |     SCL: OutputPin + InputPin,
    |                      ^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master`

error[E0277]: the trait bound `&Gpio4<InputOutput>: esp_idf_hal::gpio::OutputPin` is not satisfied
   --> src/init.rs:21:9
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::OutputPin` is not implemented for `&Gpio4<InputOutput>`
    |
    = help: the trait `esp_idf_hal::gpio::OutputPin` is implemented for `Gpio4<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:149:10
    |
149 |     SDA: OutputPin + InputPin,
    |          ^^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master`

error[E0277]: the trait bound `&Gpio4<InputOutput>: esp_idf_hal::gpio::InputPin` is not satisfied
   --> src/init.rs:21:9
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::InputPin` is not implemented for `&Gpio4<InputOutput>`
    |
    = help: the trait `esp_idf_hal::gpio::InputPin` is implemented for `Gpio4<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:149:22
    |
149 |     SDA: OutputPin + InputPin,
    |                      ^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master`

error[E0277]: the trait bound `&Gpio5<esp_idf_hal::gpio::Output>: esp_idf_hal::gpio::OutputPin` is not satisfied
   --> src/init.rs:21:9
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::OutputPin` is not implemented for `&Gpio5<esp_idf_hal::gpio::Output>`
    |
    = help: the trait `esp_idf_hal::gpio::OutputPin` is implemented for `Gpio5<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:150:10
    |
150 |     SCL: OutputPin + InputPin,
    |          ^^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master`

error[E0277]: the trait bound `&Gpio5<esp_idf_hal::gpio::Output>: esp_idf_hal::gpio::InputPin` is not satisfied
   --> src/init.rs:21:9
    |
21  |         i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `esp_idf_hal::gpio::InputPin` is not implemented for `&Gpio5<esp_idf_hal::gpio::Output>`
    |
    = help: the trait `esp_idf_hal::gpio::InputPin` is implemented for `Gpio5<MODE>`
note: required by a bound in `esp_idf_hal::i2c::Master`
   --> /home/shane/.cargo/registry/src/github.com-1ecc6299db9ec823/esp-idf-hal-0.38.1/src/i2c.rs:150:22
    |
150 |     SCL: OutputPin + InputPin,
    |                      ^^^^^^^^ required by this bound in `esp_idf_hal::i2c::Master`

error[E0308]: mismatched types
  --> src/init.rs:22:5
   |
10 |   ) -> i2c::Master<
   |  ______-
11 | |     i2c::I2C0,
12 | |     esp_idf_hal::gpio::Gpio4<gpio::InputOutput>,
13 | |     esp_idf_hal::gpio::Gpio5<gpio::Output>,
14 | | > {
   | |_- expected `esp_idf_hal::i2c::Master<I2C0, Gpio4<InputOutput>, Gpio5<esp_idf_hal::gpio::Output>>` because of return type
...
22 |       i2c
   |       ^^^ expected struct `Gpio4`, found reference
   |
   = note: expected struct `esp_idf_hal::i2c::Master<_, Gpio4<InputOutput>, Gpio5<esp_idf_hal::gpio::Output>>`
              found struct `esp_idf_hal::i2c::Master<_, &Gpio4<InputOutput>, &Gpio5<esp_idf_hal::gpio::Output>>`

I don't think you can move them out from a borrowed Peripheral. I normally consume Peripheral and retrieve all the peripherals I need from one function.

Here is an example.

pub struct Board {
    /// Onboard LED 1
    pub led1: Output<'static, AnyPin>,
    /// Onboard LED 2
    pub led2: Output<'static, AnyPin>,
    /// Onboard LED 3
    pub led3: Output<'static, AnyPin>,
    /// Onboard LED 4
    pub led4: Output<'static, AnyPin>,
    /// Onboard Button 1
    pub button1: Input<'static, AnyPin>,
    /// Onboard Button 2
    pub button2: Input<'static, AnyPin>,
    /// Onboard Button 3
    pub button3: Input<'static, AnyPin>,
    /// Onboard Button 4
    pub button4: Input<'static, AnyPin>,
    /// UART
    pub uart: Uarte<'static, UARTE0>,
}

impl Board {
    pub fn init(p: embassy_nrf::Peripherals) -> Board {
        let led1 = Output::new(p.P0_17.degrade(), Level::High, OutputDrive::Standard);
        let led2 = Output::new(p.P0_18.degrade(), Level::High, OutputDrive::Standard);
        let led3 = Output::new(p.P0_19.degrade(), Level::High, OutputDrive::Standard);
        let led4 = Output::new(p.P0_20.degrade(), Level::High, OutputDrive::Standard);

        let button1 = Input::new(p.P0_13.degrade(), Pull::Up);
        let button2 = Input::new(p.P0_14.degrade(), Pull::Up);
        let button3 = Input::new(p.P0_15.degrade(), Pull::Up);
        let button4 = Input::new(p.P0_16.degrade(), Pull::Up);

        // uart
        let mut uart_config = uarte::Config::default();
        uart_config.parity = uarte::Parity::EXCLUDED;
        uart_config.baudrate = uarte::Baudrate::BAUD115200;
        let uart_irq = interrupt::take!(UARTE0_UART0);
        uart_irq.set_priority(Priority::P3);
        let uart = uarte::Uarte::new(p.UARTE0, uart_irq, p.P0_08, p.P0_06, uart_config);

        Board {
            led1,
            led2,
            led3,
            led4,
            button1,
            button2,
            button3,
            button4,
            uart,
        }
    }
}

In main:

    let board = Board::init(peripheral);
    let mut led1 = board.led1;
    let mut led2 = board.led2;
    led1.set_high();
    led2.set_high();
2 Likes

Thank you @lonesometraveler, that is the answer! Here's my working init.rs file:

use esp_idf_hal::adc::PoweredAdc;
use esp_idf_hal::adc::{self, Atten11dB};
use esp_idf_hal::prelude::*;
use esp_idf_hal::units::FromValueType;
use esp_idf_hal::{gpio, i2c};
use sx1509;

pub struct Board {
    pub i2c1: i2c::Master<
        i2c::I2C0,
        esp_idf_hal::gpio::Gpio4<gpio::InputOutput>,
        esp_idf_hal::gpio::Gpio5<gpio::Output>,
    >,
    pub adc1: PoweredAdc<adc::ADC1>,
    pub adc1_ch0: gpio::Gpio0<Atten11dB<adc::ADC1>>,
    pub gpio_exp: sx1509::Sx1509<
        i2c::Master<i2c::I2C0, gpio::Gpio4<gpio::InputOutput>, gpio::Gpio5<gpio::Output>>,
    >,
}

impl Board {
    pub fn init(p: Peripherals) -> Board {
        // I2C
        let sda = p.pins.gpio4.into_input_output().unwrap();
        let scl = p.pins.gpio5.into_output().unwrap();
        let i2c = p.i2c0;
        let config = <i2c::config::MasterConfig as Default>::default().baudrate(400.kHz().into());
        let mut i2c1 =
            i2c::Master::<i2c::I2C0, _, _>::new(i2c, i2c::MasterPins { sda, scl }, config).unwrap();

        // GPIO expander
        let mut expander = sx1509::Sx1509::new(&mut i2c1, sx1509::DEFAULT_ADDRESS);
        expander.borrow(&mut i2c1).software_reset().unwrap();
        expander.borrow(&mut i2c1).set_bank_a_direction(0).unwrap();
        expander
            .borrow(&mut i2c1)
            .set_bank_b_direction(0xFF)
            .unwrap();

        // ADC
        let adc1_ch0 = p.pins.gpio0.into_analog_atten_11db().unwrap();
        let config = adc::config::Config::new().calibration(true);
        let adc1 = PoweredAdc::new(p.adc1, config).unwrap();

        Board {
            i2c1: i2c1,
            adc1: adc1,
            adc1_ch0: adc1_ch0,
            gpio_exp: expander,
        }
    }
}

Then my main.rs loop:

    let peripherals = Peripherals::take().unwrap();
    let mut board = init::Board::init(peripherals);

    loop {
        let buff = board
            .gpio_exp
            .borrow(&mut board.i2c1)
            .get_bank_a_data()
            .unwrap();
        board
            .gpio_exp
            .borrow(&mut board.i2c1)
            .set_bank_b_data(buff)
            .unwrap();
        log::info!("{:?}", buff);
        log::info!(
            "a1_ch0 sensor reading: {}mV",
            board.adc1.read(&mut board.adc1_ch0).unwrap()
        );
        thread::sleep(Duration::from_millis(100));
    }
2 Likes

Some reference material I found on Singletons:

https://docs.rust-embedded.org/book/peripherals/singletons.html