implement `embedded-io` traits
rursprung opened this issue · comments
with embedded-hal
v1 the UART related traits have been removed in favour of embedded-io
. thus these traits should be implemented by this HAL so that the replacement for the old e-h 0.2 traits is available.
for avr-hal i've done an attempt at this, maybe that helps as a reference: Rahix/avr-hal#484 (i don't have an STM32 at hand, so i can't provide it here, sorry)
I am working on an example that reads from one serial port and writes to another using Read
and Write
traits from embedded-io-0.6.1
(and using embedded-hal-1.0.0
). The code further below compiles using @techmccat 's fork of stm32g4xx-hal
and branch eh-v1.0
of stm32h7xx-hal
. Compiling with stm32f4xx-hal
gives these errors:
Click to expand compile errors
$ cargo build --no-default-features --target thumbv7em-none-eabihf --features stm32f411,stm32f4xx --example echo_by_char
Updating crates.io index
Updating git repository `https://github.com/techmccat/stm32g4xx-hal`
Updating git repository `https://github.com/stm32-rs/stm32h7xx-hal`
Compiling proc-macro2 v1.0.78
Compiling unicode-ident v1.0.12
Compiling semver-parser v0.7.0
Compiling cortex-m v0.7.7
Compiling nb v1.1.0
Compiling semver v1.0.21
Compiling vcell v0.1.3
Compiling cortex-m-rt v0.7.3
Compiling syn v1.0.109
Compiling nb v0.1.3
Compiling void v1.0.2
Compiling volatile-register v0.2.2
Compiling embedded-hal v0.2.7
Compiling critical-section v1.1.2
Compiling semver v0.9.0
Compiling autocfg v1.1.0
Compiling bitfield v0.13.2
Compiling rustc_version v0.2.3
Compiling byteorder v1.5.0
Compiling az v1.2.1
Compiling gcd v2.3.0
Compiling stm32f4 v0.15.1
Compiling rustc_version v0.4.0
Compiling bare-metal v0.2.5
Compiling stable_deref_trait v1.2.0
Compiling powerfmt v0.2.0
Compiling num-traits v0.2.17
Compiling cortex-m-semihosting v0.5.0
Compiling deranged v0.3.11
Compiling quote v1.0.35
Compiling syn v2.0.48
Compiling heapless v0.7.17
Compiling fugit v0.3.7
Compiling stm32f4xx-hal v0.20.0
Compiling num-conv v0.1.0
Compiling time-core v0.1.2
Compiling embedded-hal v1.0.0
Compiling litrs v0.4.1
Compiling bare-metal v1.0.0
Compiling embedded-hal-nb v1.0.0
Compiling time v0.3.34
Compiling fugit-timer v0.1.3
Compiling embedded-dma v0.2.0
Compiling hash32 v0.2.1
Compiling rand_core v0.6.4
Compiling float-cmp v0.9.0
Compiling embedded-graphics-core v0.4.0
Compiling micromath v2.1.0
Compiling embedded-storage v0.3.1
Compiling panic-semihosting v0.6.0
Compiling panic-halt v0.2.0
Compiling embedded-io v0.6.1
Compiling document-features v0.2.8
Compiling embedded-graphics v0.8.1
Compiling enumflags2_derive v0.7.8
Compiling cortex-m-rt-macros v0.7.0
Compiling enumflags2 v0.7.8
Compiling echo v0.0.1 (echo)
error[E0308]: mismatched types
--> examples/echo_by_char.rs:131:15
|
131 | tx1.write(b"\r\nconsole connect check.\r\n").ok();
| ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `&[u8; 26]`
| |
| arguments to this method are incorrect
|
note: method defined here
--> .cargo/registry/src/index.crates.io-6f17d22bba15001f/embedded-hal-nb-1.0.0/src/serial.rs:98:8
|
98 | fn write(&mut self, word: Word) -> nb::Result<(), Self::Error>;
| ^^^^^
error[E0308]: mismatched types
--> examples/echo_by_char.rs:135:15
|
135 | tx1.write(b"test read and write by char. Please type into the console ...").ok();
| ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `&[u8; 61]`
| |
| arguments to this method are incorrect
|
note: method defined here
--> .cargo/registry/src/index.crates.io-6f17d22bba15001f/embedded-hal-nb-1.0.0/src/serial.rs:98:8
|
98 | fn write(&mut self, word: Word) -> nb::Result<(), Self::Error>;
| ^^^^^
error[E0061]: this method takes 0 arguments but 1 argument was supplied
--> examples/echo_by_char.rs:141:24
|
141 | let _len = rx1.read(&mut buffer);
| ^^^^ -----------
| |
| unexpected argument of type `&mut [u8; 5]`
| help: remove the extra argument
|
note: method defined here
--> .cargo/registry/src/index.crates.io-6f17d22bba15001f/embedded-hal-nb-1.0.0/src/serial.rs:85:8
|
85 | fn read(&mut self) -> nb::Result<Word, Self::Error>;
| ^^^^
error[E0308]: mismatched types
--> examples/echo_by_char.rs:145:19
|
145 | tx1.write(&buffer).ok();
| ----- ^^^^^^^ expected `u8`, found `&[u8; 5]`
| |
| arguments to this method are incorrect
|
note: method defined here
--> .cargo/registry/src/index.crates.io-6f17d22bba15001f/embedded-hal-nb-1.0.0/src/serial.rs:98:8
|
98 | fn write(&mut self, word: Word) -> nb::Result<(), Self::Error>;
| ^^^^^
warning: unused import: `Write`
--> examples/echo_by_char.rs:23:25
|
23 | use embedded_io::{Read, Write};
| ^^^^^
|
= note: `#[warn(unused_imports)]` on by default
warning: unused import: `Read`
--> examples/echo_by_char.rs:23:19
|
23 | use embedded_io::{Read, Write};
| ^^^^
Some errors have detailed explanations: E0061, E0308.
For more information about an error, try `rustc --explain E0061`.
warning: `echo` (example "echo_by_char") generated 2 warnings
error: could not compile `echo` (example "echo_by_char") due to 4 previous errors; 2 warnings emitted
$ cargo build --no-default-features --target thumbv7em-none-eabihf --features stm32g474,stm32g4xx --example echo_by_char
Compiling paste v1.0.14
Compiling cast v0.2.7
Compiling stm32g4 v0.15.1
Compiling bitflags v1.3.2
Compiling static_assertions v1.1.0
Compiling embedded-dma v0.1.2
Compiling fdcan v0.1.2
Compiling stm32g4xx-hal v0.0.2 (https://github.com/techmccat/stm32g4xx-hal?branch=hal-1#bf979a6b)
Compiling echo v0.0.1 (echo)
Finished dev [unoptimized + debuginfo] target(s) in 21.62s
$ cargo build --no-default-features --target thumbv7em-none-eabihf --features stm32h742,stm32h7xx --example echo_by_char
Compiling nb v0.1.3
Compiling stm32h7 v0.15.1
Compiling cast v0.3.0
Compiling embedded-hal v0.2.7
Compiling cortex-m v0.7.7
Compiling cortex-m-semihosting v0.5.0
Compiling panic-semihosting v0.6.0
Compiling stm32h7xx-hal v0.15.1 (https://github.com/stm32-rs/stm32h7xx-hal?branch=eh-v1.0#24dcd419)
Compiling echo v0.0.1 (echo)
Finished dev [unoptimized + debuginfo] target(s) in 24.69s
From the unused import
messages I think the stm32f4xx-hal
compile is not finding the traits properly. Is there a work-around or fix for this? The code and Cargo.toml` are
Click to expand code
//! Echo console input back to console
//!
//! On blackpill:
//! Connect the Tx pin pa9 to the Rx pin of usb-ttl converter
//! Connect the Rx pin pa10 to the Tx pin of usb-ttl converter
//! Set up the serial console (e.g. minicom) with the same settings used here.
//! (Using 9600bps, could be higher but needs serial console to be the same.)
#![deny(unsafe_code)]
#![no_main]
#![no_std]
#[cfg(debug_assertions)]
use panic_semihosting as _;
#[cfg(not(debug_assertions))]
use panic_halt as _;
use cortex_m_semihosting::hprintln;
use cortex_m_rt::entry;
use embedded_io::{Read, Write};
//use core::str::from_utf8;
#[cfg(feature = "stm32f4xx")]
use stm32f4xx_hal as hal;
#[cfg(feature = "stm32g4xx")]
use stm32g4xx_hal as hal;
#[cfg(feature = "stm32h7xx")]
use stm32h7xx_hal as hal;
use hal::{ // for common locations, differences below
// pac::Peripherals,
//pac::USART1,
prelude::*,
serial::{Rx, Tx},
};
// setup() does hal/MCU specific setup and returns generic (tx, rx) for use in main code.
#[cfg(feature = "stm32f4xx")]
use stm32f4xx_hal::{
pac::Peripherals,
pac::USART1,
serial::{config::Config, Serial},
};
#[cfg(feature = "stm32f4xx")]
fn setup() -> (Tx<USART1>, Rx<USART1>) {
let dp = Peripherals::take().unwrap();
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze();
let gpioa = dp.GPIOA.split();
Serial::new(
dp.USART1,
(gpioa.pa9.into_alternate(), gpioa.pa10.into_alternate()),
Config::default().baudrate(9600.bps()),
&clocks,
).unwrap().split()
}
#[cfg(feature = "stm32g4xx")]
use stm32g4xx_hal::{
stm32::Peripherals, // is there a convention that pac should be used or an alias?
stm32::USART1, // is there a convention that pac should be used or an alias?
serial::{FullConfig, NoDMA},
gpio::{Alternate, gpioa::{PA9, PA10}}, // why Tx<USART1, pin, pin> not Tx<USART1> ?
};
#[cfg(feature = "stm32g4xx")]
fn setup() -> (Tx<USART1, PA9<Alternate<7_u8>>, NoDMA>, Rx<USART1, PA10<Alternate<7_u8>>, NoDMA>) {
let dp = Peripherals::take().unwrap();
let mut rcc = dp.RCC.constrain();
let gpioa = dp.GPIOA.split(&mut rcc);
dp.USART1.usart(
gpioa.pa9.into_alternate(),
gpioa.pa10.into_alternate(),
FullConfig::default().baudrate(9600.bps()), &mut rcc).unwrap().split()
}
#[cfg(feature = "stm32h7xx")]
use stm32h7xx_hal::{
pac::Peripherals,
pac::USART1,
};
#[cfg(feature = "stm32h7xx")]
fn setup() -> (Tx<USART1>, Rx<USART1>) {
let dp = Peripherals::take().unwrap();
let pwr = dp.PWR.constrain();
let vos = pwr.freeze();
let rcc = dp.RCC.constrain();
let ccdr = rcc.sys_ck(160.MHz()).freeze(vos, &dp.SYSCFG);
let clocks = ccdr.clocks;
let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
dp.USART1.serial(
(
gpioa.pa9.into_alternate(), //tx
gpioa.pa10.into_alternate(), //rx
),
9600.bps(),
ccdr.peripheral.USART1,
&clocks,
).unwrap().split()
}
// End of hal/MCU specific setup. Following should be generic code.
#[entry]
fn main() -> ! {
let (mut tx1, mut rx1) = setup();
hprintln!("test write to console ...");
tx1.write(b"\r\nconsole connect check.\r\n").ok();
hprintln!("test read and write by char. Please type into the console ...");
tx1.write(b"test read and write by char. Please type into the console ...").ok();
let mut buffer: [u8; 5] = [0; 5]; // could be length 1 for a byte
loop {
// Read a byte and write
let _len = rx1.read(&mut buffer);
//hprintln!("received"); // for debugging
tx1.write(&buffer).ok();
hprintln!("{:?}", &buffer); // for debugging
}
}
Click to expand Cargo.toml
[package]
authors = ["pdGilbert"]
categories = ["embedded", "no-std"]
description = "echo between serial interfaces, embedded-io example"
keywords = ["serial", "embedded-io", "example"]
license = "MIT OR Apache-2.0"
name = "echo"
version = "0.0.1"
edition = "2021"
[dependencies]
stm32f4xx-hal = { version = "0.20.0", optional = true }
stm32g4xx-hal = { git = "https://github.com/techmccat/stm32g4xx-hal", optional = true, branch = "hal-1" }
stm32h7xx-hal = { git = "https://github.com/stm32-rs/stm32h7xx-hal", optional = true, branch = "eh-v1.0"}
embedded-hal = "1.0"
embedded-io = "0.6.1"
embedded-graphics = ">=0.7"
heapless = "0.7"
cortex-m-rt = ">=0.7.0"
cortex-m-semihosting = { version = "0.5.0" }
panic-halt = { version = ">=0.2.0" }
panic-semihosting = { version = ">=0.6.0" }
[features]
stm32f4xx = ["stm32f4xx-hal" ]
stm32g4xx = ["stm32g4xx-hal" ]
stm32h7xx = ["stm32h7xx-hal" ]
stm32f401 = ["stm32f4xx-hal/stm32f401" ]
stm32f411 = ["stm32f4xx-hal/stm32f411" ]
stm32g473 = ["stm32g4xx-hal/stm32g473" ]
stm32g474 = ["stm32g4xx-hal/stm32g474" ]
stm32h742 = ["stm32h7xx-hal/stm32h742" ]
These are also available in a package structure at https://github.com/pdgilbert/echo .
This example is derived from an example that worked with embedded-hal-0.2.7
by reading and writing individual bytes. As pointed out by @richardion (see stm32-rs/stm32h7xx-hal#474 (comment) ), there are no methods for byte wise serial operations in embedded-io
. Thus the read/write buffer in the example can now be more than a single byte. I am not sure the example code will accomplish this properly, so comments on the code would also be appreciated.
Also tried with the stm32f4xx_hal
io
branch for @burrbull 's pull request #725. The error message suggests to disambiguate the method. So changing, for example, tx1.write(b"\r\nconsole connect check.\r\n").ok();
to embedded_io::Write::write(&mut tx1, b"\r\nconsole connect check.\r\n").ok();
the writes do not cause errors. It does not address Read
. Attempting read with let _len = embedded_io::Read::read(&mut rx1, &mut buffer).ok();
to disambiguate gives
Click to expand compile errors
$ cargo build --no-default-features --target $TARGET --features $MCU,$HAL --example echo_by_char
Compiling echo v0.0.1 (echo)
warning: unused imports: `Read`, `Write`
--> examples/echo_by_char.rs:23:19
|
23 | use embedded_io::{Read, Write};
| ^^^^ ^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error[E0277]: the trait bound `stm32f4xx_hal::serial::Rx<stm32f4xx_hal::pac::USART1>: embedded_io::Read` is not satisfied
--> examples/echo_by_char.rs:144:44
|
144 | let _len = embedded_io::Read::read(&mut rx1, &mut buffer).ok();
| ----------------------- ^^^^^^^^ the trait `embedded_io::Read` is not implemented for `stm32f4xx_hal::serial::Rx<stm32f4xx_hal::pac::USART1>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `embedded_io::Read`:
&[u8]
&mut T
For more information about this error, try `rustc --explain E0277`.
warning: `echo` (example "echo_by_char") generated 1 warning
error: could not compile `echo` (example "echo_by_char") due to 1 previous error; 1 warning emitted