Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

type mismatch / trait problems #2

Open
pdgilbert opened this issue May 19, 2021 · 0 comments
Open

type mismatch / trait problems #2

pdgilbert opened this issue May 19, 2021 · 0 comments

Comments

@pdgilbert
Copy link

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.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant