Reference the same variable multiple times without borrowing or cloning

83 Views Asked by At

Currently, I am redefining the same variable (dp) multiple times to make the program work. However, this feels wrong, and I would think there would be a much better way to do this. For context, I am in a no_std environment, and compiling for avr-atmega328p (Arduino Uno), using the avr-hal-template.

#![no_std]
#![no_main]

use arduino_hal::hal::wdt;
use motor_shield::{dc::DcMotor, init_pwm, Motor};
use panic_halt as _;

#[arduino_hal::entry]
fn main() -> ! {
    let dp = arduino_hal::Peripherals::take().unwrap();
    let pins = arduino_hal::pins!(dp);

    let dp = arduino_hal::Peripherals::take().unwrap();
    let mut pwm = init_pwm(None, dp, pins).unwrap();
    let mut dc_motor = DcMotor::try_new(&mut pwm, Motor::Motor1).unwrap();

    let dp = arduino_hal::Peripherals::take().unwrap();
    let mut watchdog = wdt::Wdt::new(dp.WDT, &dp.CPU.mcusr);
    watchdog.start(wdt::Timeout::Ms4000).unwrap();

    loop {
        let _ = dc_motor.set_throttle(&mut pwm, 0.5);
        arduino_hal::delay_ms(1000);
        let _ = dc_motor.set_throttle(&mut pwm, 0.0);
        arduino_hal::delay_ms(1000);
        watchdog.feed();
    }
}

For context, here is the init_pwm function:

pub fn init_pwm(i2c: Option<I2c>, dp: Peripherals, pins: Pins) -> Result<Pca9685<I2c>, MotorError> {
    let i2c = if let Some(i2c) = i2c {
        i2c
    } else {
        I2c::new(
            dp.TWI,
            pins.a4.into_pull_up_input(),
            pins.a5.into_pull_up_input(),
            50000,
        )
    };

    let address = Address::from(60);

    let mut pwm = Pca9685::new(i2c, address).map_err(|_| MotorError::PwmError)?;
    pwm.enable().map_err(|_| MotorError::PwmError)?;
    pwm.set_prescale(4).map_err(|_| MotorError::PwmError)?;
    Ok(pwm)
}

The one thing I could think to do was borrow dp, but that wouldn't work because the functions don't accept references. I also cannot clone dp because it does not implement the Clone trait.

1

There are 1 best solutions below

0
n3rd3x3 On

Thanks to the comment by Chayim Friedman, I finally figured out a solution. I changed the init_pwm function to require WDT instead of the full Peripherals, as that was all it needed. I was then able to call the function with just dp.TWI instead of dp.

pub fn init_pwm(i2c: Option<I2c>, twi: TWI, pins: Pins) -> Result<Pca9685<I2c>, MotorError> {
  // ...
  else {
    I2c::new(
      twi,
      pins.a4.into_pull_up_input(),
      pins.a5.into_pull_up_input(),
      50000,
    )
  }
// in main.rs
fn main() -> ! {
  let dp = Peripherals::take().unwrap();
  let pins = arduino_hal::pins!(dp);
    
  let mut pwm = init_pwm(None, dp.TWI, pins).unwrap();
  let mut dc_motor = DcMotor::try_new(&mut pwm, Motor::Motor1).unwrap();
    
  let mut watchdog = wdt::Wdt::new(dp.WDT, &dp.CPU.mcusr);
  watchdog.start(wdt::Timeout::Ms4000).unwrap();
  // ...
}