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

implement embedded-io traits #721

Open
rursprung opened this issue Dec 29, 2023 · 2 comments
Open

implement embedded-io traits #721

rursprung opened this issue Dec 29, 2023 · 2 comments

Comments

@rursprung
Copy link
Contributor

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)

@pdgilbert
Copy link
Contributor

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.

@pdgilbert
Copy link
Contributor

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

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

2 participants