driver-examples icon indicating copy to clipboard operation
driver-examples copied to clipboard

type mismatch / trait problems

Open pdgilbert opened this issue 4 years ago • 0 comments

As a learning exercise I have being trying to organizing some of these examples with a setup() function for the HAL/hardware specific part of the code. This makes it easier to generalize the example to use with other boards. (More on that when I get further.) The example si4703-fm-radio-display-bp is a bit difficult because of the seek control pins in addition to the i2c. This code seems like it is almost working but I am having type mismatch / trait problems

Click to expand
#![deny(unsafe_code)]
#![no_std]
#![no_main]

use core::fmt::Write;
use cortex_m_rt::entry;
use embedded_graphics::{
    fonts::{Font6x8, Text},
    pixelcolor::BinaryColor,
    prelude::*,
    style::TextStyleBuilder,
};
use embedded_hal::digital::v2::{InputPin, OutputPin};
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use si4703::{
    reset_and_select_i2c_method1 as reset_si4703, ChannelSpacing, DeEmphasis, ErrorWithPin,
    SeekDirection, SeekMode, Si4703, Volume,
};

use ssd1306::{prelude::*, Builder, I2CDIBuilder};

pub trait LED {
    // depending on board wiring, on may be set_high or set_low, with off also reversed
    // implementation should deal with this difference
    fn on(&mut self) -> ();
    fn off(&mut self) -> ();

    // default methods
    fn blink(&mut self, time: u16, delay: &mut Delay) -> () {
        self.on();
        delay.delay_ms(time);
        self.off();
        delay.delay_ms(time); // consider delay.delay_ms(500u16);
    }
}

pub struct SeekPins<T, U> {
    p_seekup:   T,
    p_seekdown: U,
    //p_stcint:   V,
}

pub trait SEEK {
    fn seekup(&mut self)   -> bool;
    fn seekdown(&mut self) -> bool;
    //fn stcint(&mut self) -> ;
}

// setup() does all  hal/MCU specific setup and returns generic hal device for use in main code.
use stm32f1xx_hal::{
    delay::Delay,
    gpio::{
        gpiob::{PB10, PB11, PB6},
        gpioc::PC13,
        Input, Output, PullDown, PullUp, PushPull,
    },
    i2c::{BlockingI2c, DutyCycle, Mode, Pins},
    pac::{CorePeripherals, Peripherals, I2C1},
    prelude::*,
};

fn setup() -> (
    BlockingI2c<I2C1, impl Pins<I2C1>>,
    impl LED,
    Delay,
    impl SEEK,
    PB6<Input<PullUp>>,
) {
    let cp = CorePeripherals::take().unwrap();
    let dp = Peripherals::take().unwrap();

    let mut flash = dp.FLASH.constrain();
    let mut rcc = dp.RCC.constrain();

    let clocks = rcc.cfgr.freeze(&mut flash.acr);

    let mut afio = dp.AFIO.constrain(&mut rcc.apb2);

    let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);

    let scl = gpiob.pb8.into_alternate_open_drain(&mut gpiob.crh);
    //let sda = gpiob.pb9.into_alternate_open_drain(&mut gpiob.crh);  //OutputPin is not implemented
    let sda = gpiob.pb9.into_push_pull_output(&mut gpiob.crh);        //trait Pins<I2C1> not implemented

    let i2c = BlockingI2c::i2c1(
        dp.I2C1,
        (scl, sda),
        &mut afio.mapr,
        Mode::Fast {
            frequency: 400_000.hz(),
            duty_cycle: DutyCycle::Ratio2to1,
        },
        clocks,
        &mut rcc.apb1,
        1000,
        10,
        1000,
        1000,
    );

    let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
    let led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
    let delay = Delay::new(cp.SYST, clocks);

    impl LED for PC13<Output<PushPull>> {
        fn on(&mut self) -> () {
            self.set_low().unwrap()
        }
        fn off(&mut self) -> () {
            self.set_high().unwrap()
        }
    }

    let stcint   = gpiob.pb6.into_pull_up_input(&mut gpiob.crl);

    let buttons: SeekPins<PB10<Input<PullDown>>, PB11<Input<PullDown>>> = SeekPins{
        p_seekup   : gpiob.pb10.into_pull_down_input(&mut gpiob.crh), 
        p_seekdown : gpiob.pb11.into_pull_down_input(&mut gpiob.crh)
    };
    
    impl  SEEK for SeekPins<PB10<Input<PullDown>>, PB11<Input<PullDown>>> {
        fn seekup(&mut self) -> bool {
            self.p_seekup.is_high().unwrap()
        }
        fn seekdown(&mut self) -> bool {
            self.p_seekdown.is_high().unwrap()
        }
    }

    let mut rst = gpiob.pb7.into_push_pull_output(&mut gpiob.crl);
    //let z = reset_si4703(&mut rst, &mut sda, &mut delay).unwrap();
    let _z = reset_si4703(&mut rst, &mut sda, &mut delay);

    (i2c, led, delay, buttons, stcint)
}

// End of hal/MCU specific setup. Following should be generic code.

#[entry]
fn main() -> ! {
    rtt_init_print!();
    rprintln!("Si4703 example");

    let (i2c, mut led, mut delay, mut buttons, mut stcint) = setup();

    let manager = shared_bus::BusManager::<cortex_m::interrupt::Mutex<_>, _>::new(i2c);
    let interface = I2CDIBuilder::new().init(manager.acquire());
    let mut disp: GraphicsMode<_> = Builder::new().connect(interface).into();
    disp.init().unwrap();
    disp.flush().unwrap();

    let text_style = TextStyleBuilder::new(Font6x8)
        .text_color(BinaryColor::On)
        .build();

    let mut radio = Si4703::new(manager.acquire());
    radio.enable_oscillator().unwrap();
    delay.delay_ms(500_u16);
    radio.enable().unwrap();
    delay.delay_ms(110_u16);

    radio.set_volume(Volume::Dbfsm28).unwrap();
    radio.set_deemphasis(DeEmphasis::Us50).unwrap();
    radio.set_channel_spacing(ChannelSpacing::Khz100).unwrap();
    radio.unmute().unwrap();

    let mut buffer: heapless::String<64> = heapless::String::new();
    loop {
        // Blink LED 0 every time a new seek is started
        // to check that everything is actually running.
        led.blink(50_u16, &mut delay);

        let should_seek_down = buttons.seekdown();
        let should_seek_up   = buttons.seekup();
        if should_seek_down || should_seek_up {
            buffer.clear();
            write!(buffer, "Seeking...").unwrap();

            disp.clear();
            Text::new(&buffer, Point::zero())
                .into_styled(text_style)
                .draw(&mut disp)
                .unwrap();

            disp.flush().unwrap();
            let direction = if should_seek_down {
                SeekDirection::Down
            } else {
                SeekDirection::Up
            };

            buffer.clear();
            loop {
                match radio.seek_with_stc_int_pin(SeekMode::Wrap, direction, &stcint) {
                    Err(nb::Error::WouldBlock) => {}
                    Err(nb::Error::Other(ErrorWithPin::SeekFailed)) => {
                        write!(buffer, "Seek Failed!  ").unwrap();
                        break;
                    }
                    Err(_) => {
                        write!(buffer, "Error!     ").unwrap();
                        break;
                    }
                    Ok(_) => {
                        let channel = radio.channel().unwrap_or(-1.0);
                        write!(buffer, "Found {:1} MHz ", channel).unwrap();
                        break;
                    }
                }
            }
            disp.clear();
            Text::new(&buffer, Point::zero())
                .into_styled(text_style)
                .draw(&mut disp)
                .unwrap();

            disp.flush().unwrap();
        }
    }
}

with the code as shown, sda as in your code, I get

error[E0277]: the trait bound `(PB8<Alternate<OpenDrain>>, PB9<Output<PushPull>>): stm32f1xx_hal::i2c::Pins<I2C1>` is not satisfied
  --> examples/zz.rs:87:15
   |
87 |     let i2c = BlockingI2c::i2c1(
   |               ^^^^^^^^^^^^^^^^^ the trait `stm32f1xx_hal::i2c::Pins<I2C1>` is not implemented for `(PB8<Alternate<OpenDrain>>, PB9<Output<PushPull>>)`
   |
   = help: the following implementations were found:
             <(PB10<Alternate<OpenDrain>>, PB11<Alternate<OpenDrain>>) as stm32f1xx_hal::i2c::Pins<I2C2>>
             <(PB6<Alternate<OpenDrain>>, PB7<Alternate<OpenDrain>>) as stm32f1xx_hal::i2c::Pins<I2C1>>
             <(PB8<Alternate<OpenDrain>>, PB9<Alternate<OpenDrain>>) as stm32f1xx_hal::i2c::Pins<I2C1>>
   = note: required by `BlockingI2c::<I2C1, PINS>::i2c1`

error[E0277]: the trait bound `(PB8<Alternate<OpenDrain>>, PB9<Output<PushPull>>): stm32f1xx_hal::i2c::Pins<I2C1>` is not satisfied
  --> examples/zz.rs:65:23
   |
65 |     BlockingI2c<I2C1, impl Pins<I2C1>>,
   |                       ^^^^^^^^^^^^^^^ the trait `stm32f1xx_hal::i2c::Pins<I2C1>` is not implemented for `(PB8<Alternate<OpenDrain>>, PB9<Output<PushPull>>)`
   |
   = help: the following implementations were found:
             <(PB10<Alternate<OpenDrain>>, PB11<Alternate<OpenDrain>>) as stm32f1xx_hal::i2c::Pins<I2C2>>
             <(PB6<Alternate<OpenDrain>>, PB7<Alternate<OpenDrain>>) as stm32f1xx_hal::i2c::Pins<I2C1>>
             <(PB8<Alternate<OpenDrain>>, PB9<Alternate<OpenDrain>>) as stm32f1xx_hal::i2c::Pins<I2C1>>

error: aborting due to 2 previous errors


and with

let sda = gpiob.pb9.into_alternate_open_drain(&mut gpiob.crh);  //OutputPin is not implemented

I get

error[E0271]: type mismatch resolving `<PB9<Alternate<OpenDrain>> as embedded_hal::digital::v2::OutputPin>::Error == Infallible`
   --> examples/zz.rs:134:14
    |
134 |     let _z = reset_si4703(&mut rst, &mut sda, &mut delay);
    |              ^^^^^^^^^^^^ expected enum `Infallible`, found `()`
    | 
   ::: /home/paul/.cargo/git/checkouts/si4703-rs-df77d9d8ce5b9ec0/7d40805/src/reset.rs:12:20
    |
12  |     SDA: OutputPin<Error = E>,
    |                    --------- required by this bound in `reset_and_select_i2c_method1`

error[E0277]: the trait bound `PB9<Alternate<OpenDrain>>: embedded_hal::digital::OutputPin` is not satisfied
   --> examples/zz.rs:134:14
    |
134 |     let _z = reset_si4703(&mut rst, &mut sda, &mut delay);
    |              ^^^^^^^^^^^^ the trait `embedded_hal::digital::OutputPin` is not implemented for `PB9<Alternate<OpenDrain>>`
    | 
   ::: /home/paul/.cargo/git/checkouts/si4703-rs-df77d9d8ce5b9ec0/7d40805/src/reset.rs:12:10
    |
12  |     SDA: OutputPin<Error = E>,
    |          -------------------- required by this bound in `reset_and_select_i2c_method1`
    |
    = note: required because of the requirements on the impl of `embedded_hal::digital::v2::OutputPin` for `PB9<Alternate<OpenDrain>>`

error: aborting due to 2 previous errors

I do not have this problem with i2c in the other examples, in which I use

let sda = gpiob.pb9.into_alternate_open_drain(&mut gpiob.crh);

I am using an up-to-date fork of driver-examples and current github version of stm32f1xx_hal.

Suggestions?

(BTW, I am not really happy with my struct seekPins and trait SEEK, I think they should be tied more closely to radio. Suggestions on that also appreciated.)

pdgilbert avatar May 19 '21 19:05 pdgilbert