type mismatch / trait problems
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.)