Rahix / avr-hal

embedded-hal abstractions for AVR microcontrollers
Apache License 2.0
1.32k stars 223 forks source link

ADC cannot read from a Pin<Analog> object. #33

Open bbonenfant opened 4 years ago

bbonenfant commented 4 years ago

Hello, this is a great project. When trying to perform the Adc.read method on a Pin<Analog> object, I receive the following error:

the trait bound `arduino_uno::atmega328p_hal::port::Pin<arduino_uno::atmega328p_hal::port::mode::Analog>: embedded_hal::adc::Channel<arduino_uno::adc::Adc>` is not satisfied
required because of the requirements on the impl of `arduino_uno::prelude::_embedded_hal_adc_OneShot<arduino_uno::adc::Adc, _, arduino_uno::atmega328p_hal::port::Pin<arduino_uno::atmega328p_hal::port::mode::Analog>>` for `arduino_uno::adc::Adc` rustc(E0277)

which cleaned up for you benefit becomes:

the trait bound `Pin<Analog>: Channel<Adc>` is not satisfied
required because of the requirements on the impl of `OneShot<Adc, _, Pin<Analog>>` for `Adc` rustc(E0277)

I believe that this just means that the downgraded/generic Pin<Analog> object needs this OneShot trait implemented? It's a little hard to figure out what is and isn't implemented with all of the procedural macros.


Here is a minimal reproducible example:

#![no_std]
#![no_main]
extern crate panic_halt;
use arduino_uno::prelude::*;
use nb;

#[arduino_uno::entry]
fn main() -> ! {
    let peripherals = arduino_uno::Peripherals::take().unwrap();
    let mut pins = arduino_uno::Pins::new(
        peripherals.PORTB, peripherals.PORTC, peripherals.PORTD
    );

    let mut adc = arduino_uno::adc::Adc::new(
        peripherals.ADC, arduino_uno::adc::AdcSettings::default()
    );
    let analog_pin = pins.a0.into_analog_input(&mut adc).downgrade();
    let val: u16 = nb::block!(adc.read(&mut analog_pin)).void_unwrap();
    loop {}
}
couchand commented 4 years ago

From what I can tell, this is not possible to implement due to limitations in embedded-hal. The OneShot trait itself would be easy enough (just delegate to the correct port variant), but OneShot has a bound on Channel, which isn't implementable for the generic Pin, see: https://github.com/rust-embedded/embedded-hal/issues/110. It looks like there was buy-in a year and a half ago to change that API, but there's been no movement since then.

couchand commented 4 years ago

Correction: there has been movement in the API, but not in a direction that supports this usage. Ahead of an imminent 1.0 release, the channel() associated function has been removed entirely in favor of an associated constant.

Rahix commented 4 years ago

We will address this issue when https://github.com/rust-embedded/embedded-hal/pull/242 is merged and this project migrates to embedded-hal version 1.0.0.

Rahix commented 3 years ago

On the next branch we now have a "solution" to this. Check the mega2560-adc example: https://github.com/Rahix/avr-hal/blob/next/examples/arduino-mega2560/src/bin/mega2560-adc.rs

davystrong commented 3 years ago

Is there any workaround for this until the next branch stabilizes?

Rahix commented 3 years ago

@davystrong: I would consider the next branch just as stable (or unstable) as master at this point. So if you need this right now, I would suggest just switching to the next branch already. But of course you'll need to refactor your code quite a bit to work with the new design.

davystrong commented 3 years ago

Ok, thanks, I'll try that.