Giter VIP home page Giter VIP logo

stm32f4xx-hal's Introduction

stm32f4xx-hal

Crates.io Crates.io Released API docs Minimum Supported Rust Version dependency status Continuous integration

stm32f4xx-hal contains a multi device hardware abstraction on top of the peripheral access API for the STMicro STM32F4 series microcontrollers. The selection of the MCU is done by feature gates, typically specified by board support crates. Currently supported configurations are:

  • stm32f401
  • stm32f405
  • stm32f407
  • stm32f410
  • stm32f411
  • stm32f412
  • stm32f413
  • stm32f415
  • stm32f417
  • stm32f423
  • stm32f427
  • stm32f429
  • stm32f437
  • stm32f439
  • stm32f446
  • stm32f469
  • stm32f479

The idea behind this crate is to gloss over the slight differences in the various peripherals available on those MCUs so a HAL can be written for all chips in that same family without having to cut and paste crates for every single model.

Other optional features

  • rtic1 — support RTICv1 framework.
  • rtic2 — support RTICv2 framework (incompatible with rtic1, require nightly compiller).
  • defmt — implementation of defmt::Format for public enums and structures. See defmt.
  • can — bxCAN peripheral support. See bxcan.
  • i2s — I2S peripheral support. See stm32_i2s_v12x.
  • usb_fs or usb_hs — USB OTG FS/HS peripheral support. See synopsys-usb-otg.
  • fsmc_lcd — LCD support via FMC/FSMC peripheral. See display-interface.
  • sdio-host — SDIO peripheral support. See sdio-host.

Collaboration on this crate is highly welcome as are pull requests!

This crate relies on Adam Greigs fantastic stm32f4 crate to provide appropriate register definitions and implements a partial set of the embedded-hal traits.

Some of the implementation was shamelessly adapted from the stm32f1xx-hal crate originally started by Jorge Aparicio.

Setting up your project

Check if the BSP for your board exists in the stm32-rs page. If it exists, the stm32f4xx-hal crate should be already included, so you can use the bsp as BSP for your project.

Manually

Otherwise, create a new Rust project as you usually do with cargo init. The "hello world" of embedded development is usually to blink a LED. The code to do so is available in examples/delay-syst-blinky.rs. Copy that file to the main.rs of your project.

You also need to add some dependencies to your Cargo.toml:

[dependencies]
embedded-hal = "0.2"
nb = "1"
cortex-m = "0.7"
cortex-m-rt = "0.7"
# Panic behaviour, see https://crates.io/keywords/panic-impl for alternatives
panic-halt = "0.2"

[dependencies.stm32f4xx-hal]
version = "0.21.0"
features = ["stm32f407"] # replace the model of your microcontroller here
                         # and add other required features

We also need to tell Rust how to link our executable and how to lay out the result in memory. To accomplish all this, copy .cargo/config and memory.x from the stm32f4xx-hal repository to your project and make sure the sizes match up with the datasheet. Also note that there might be different kinds of memory which are not equal; to be on the safe side only specify the size of the first block at the specified address.

Fast start

To create empty project faster you could use cargo generate command. See stm32-template.

$ cargo generate --git https://github.com/burrbull/stm32-template/

Note that you need to know your chip full name.

License

0-clause BSD license.

stm32f4xx-hal's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stm32f4xx-hal's Issues

Crashing on unreachable!() when computing ppre1

I'm working on a stm32f407. I'm using the default clock settings:

let clocks = _device.RCC.constrain().cfgr.freeze();

On master I'm getting a crash on this line:

stm32f4xx-hal/src/rcc.rs

Lines 264 to 269 in d1871fc

let (ppre1_bits, ppre1) = match hclk / self.pclk1.unwrap_or(pclk1_max) {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3...5 => (0b101, 4),
6...11 => (0b110, 8),

Values:

hclk: 16000000
pclk1: 42000000

Dividing 16,000,000 by 42,000,000 is .38, which would then truncate to zero. Should this always work with default values? Perhaps sysclk should be set to sysclk_max by default?

Thanks!

P.S. Thanks for the awesome work on this crate!

Update to stm32f4-0.6.0

Unfortunately having any mismatch here causes two versions of stm32f4 to be built, and a linker error:

= note: rust-lld: error: duplicate symbol: DEVICE_PERIPHERALS
>>> defined at mod.rs:1240 (/home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4-0.4.0/src/stm32f401/mod.rs:1240)
>>> stm32f4-8d4128126bbacf9e.stm32f4.ahbyhsiv-cgu.8.rcgu.o:(DEVICE_PERIPHERALS) in archive /home/thomas/sandbox/td-crt/td-deflect/td-deflect-firmware/target/thumbv7em-none-eabihf/debug/deps/libstm32f4-8d4128126bbacf9e.rlib
>>> defined at mod.rs:1212 (/home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4-0.6.0/src/stm32f401/mod.rs:1212)
>>> stm32f4-102ad208fe39464e.stm32f4.sgay4gpn-cgu.9.rcgu.o:(.bss.DEVICE_PERIPHERALS+0x0) in archive /home/thomas/sandbox/td-crt/td-deflect/td-deflect-firmware/target/thumbv7em-none-eabihf/debug/deps/libstm32f4-102ad208fe39464e.rlib

using i2c multi-byte WriteRead with stm32f4xx-hal hangs

I've tried a couple different embedded rust projects that use embedded hal i2c Read (or WriteRead) to read data from a sensor, with no success. Is there an i2c Read example that's known to work with a common F4 dev board?


Details:
I've tried using the STM32F4Discovery board and cheap stm32f401CxUx board. I've tried both a sensor driver that uses WriteRead and one that uses Read. I've tried two distinctly different sensors from two different manufacturers.

WriteRead appears to work once or twice but then subsequently hangs in eg i2c::write:

        // Wait until START condition was generated
        while self.i2c.sr1.read().sb().bit_is_clear() {}

Question: I2C blocking behaviour

Hi!
I have a question regarding I2C behaviour during failure scenario.

Now, if I try to write some data to I2C interface and a target device is not there (disconnected or whatever), HAL implementation just hangs - while loop waiting for a register to be set.

// Wait until address was sent
while self.i2c.sr1.read().addr().bit_is_clear() {}

Apart from the fact that I don't know whether it is possible to implement it more sanely while satisfying embedded_hal API (I'm a rust newbie unfortunately 😞), I dare to say it is very much unacceptable behaviour to have.

Unless I'm misunderstanding something, then sorry for a dumb question :/

Thank you for your response.

add instrutions to README

Instructions of how to integrate this crate in your project should be added to README.
For example in this crate they are documented.

Is this a good place for the stm32f446 hal ?

Hi there !
I have a partial hal for the stm32f446 forked from the one from dkarwowski but I am missing the time to implement all the features...
Could I reuse your implementation and add support for the stm32f446 in this repo ?
Thanks !

ADC initialization may panic

When constructing ADC3, I observed the initialization function panic. Upon debugging, it appears that the initializer is panicking during adc::calibrate() because vref_samp is set to zero.

Upon inspection of the STM32F4xx reference manual, I found this snippet:
image

It does not appear that it is valid to read the VREF_INT signal from any ADC other than ADC1.

HAL for stm32f411

It would be nice to have an embedded-hal for the stm32f411xx chips, I'm new to embedded development but I'd be willing to help out with implementing this

Slightly incorrect PLL divisions when HSE is odd

When using the 16mhz HSI, the pll divisions are perfect. When using the HSE with a 25mhz crystal the generated clocks are close, but not close enough.

The cfgr configuration:

let clocks = rcc.cfgr
                            .use_hse(25.mhz())
                            .sysclk(120.mhz())
                            .pclk1(30.mhz())
                            .pclk2(60.mhz())
                            .use_pll48mhz()
                            .freeze();

HSI(16mhz):

INFO  src/main.rs:99 - Clocks {
    hclk: Hertz(
        120000000,
    ),
    pclk1: Hertz(
        30000000,
    ),
    pclk2: Hertz(
        60000000,
    ),
    ppre1: 4,
    ppre2: 2,
    sysclk: Hertz(
        120000000,
    ),
}

HSE (25mhz):

INFO  src/main.rs:99 - Clocks {
    hclk: Hertz(
        119230712,
    ),
    pclk1: Hertz(
        29807678,
    ),
    pclk2: Hertz(
        59615356,
    ),
    ppre1: 4,
    ppre2: 2,
    sysclk: Hertz(
        119230712,
    ),
}

A valid clock configuration can be calculated in CubeMX (this is an attempt to port an existing project to Rust), just wondering if its possible to adjust the calculations such that the HAL can find them too?

Examples

I am trying to use serial but failing to do so. [STM32F4Discovery board]

#[entry]
fn main() -> ! {
    let p = hal::stm32::Peripherals::take().unwrap();

    let rcc = p.RCC.constrain();
    let clocks = rcc.cfgr
        .hclk(8.mhz())
        .sysclk(168.mhz())
        .freeze();
    let gpioa = p.GPIOA.split();

    // USART1
    let tx = gpioa.pa9.into_alternate_af7();
    let rx = gpioa.pa10.into_alternate_af7();

    let s = Serial::usart1(p.USART1, (tx, rx), 9600.bps(), clocks);
    let (mut tx, _) = s.split();

    loop {
        block!(tx.write(b'x'));
    }
}

And all I get on the serial is unreadable mess (0xF8, 0xF8, 0xF8, ...).
I think it would be nice to have examples that were tested to work.

Audit crate for potential racy code

As noted in #170 this crate has code in various places which are potentially racy, e.g. when reconfiguring within interrupt handlers lacking the use of synchronisation primitives.

Known areas which require a closer look:

  • I2C
  • gpio mode modification

StopWatch can't measure long lap times that overflow DWT CYCCNT

Assuming a user uses a board with clock frequency of 168 MHz (max frequency of stm32f407),

the maximum lap time that StopWatch::lap_time can correctly measure is

(u32::MAX cycles) / (168 * 1_000_000 cycles / second) = 25.565281518 second (s),

since CYCCNT (cycle counter) has a limited size of u32.

I thought it would be nice to specify the current limitation as doc comments for struct StopWatch.

Thank you for taking a look 😺

missing ADC2

Using recent git versions I am getting

stm32::{ADC1, ADC2},
|              ^^^^
|              no `ADC2` in `stm32`

(nor is it in pac). According to release doc.rs, which may be out of sync with git, I think it should be there, and ADC1 is there.

Also, Adc::adc2(...) givesfunction or associated item not found instm32f4xx_hal::adc::Adc<_>``

Is something missing or changed in the git version, or am I missing something? The later is likely, I am still a newbie and my code is new and untested.

Why is this not called stm32f4-hal?

There seems to be a tradition of inserting "xx" in certain crates, which I don't know where it's coming from ;) Is there a rhyme or reason behind this? Given for instance there is the stm32f4 crate, which contains all the devices of the series, personally I would prefer the succinctness. Asking because we are renaming stm32l432xx-hal from https://github.com/MabezDev/stm32l4xx-hal.

Deprecation warning from embedded-hal 0.2.3

embedded-hal changed the OutputPin traits that can return a Result. The old versions are deprecated. Cargo automatically upgrades the linked version 0.2.2 to 0.2.3, hence the deprecation warnings show.

Enable voltage overdrive for HCLK > 168 MHz?

The reference manual RM0090 states that for HCLK > 168 MHz on F42x and F43x, the over-drive mode should be enabled (the procedure is on page 123). I have run some devices at 180 MHz without over-drive and not seen problems, but would it be more proper to do this in RCC.freeze() if indicated?

Wrong max clock on F407?

Hi,

I have observed slower performance of my C code when executed from Rust, compared to when executing from the original C. As it's exactly the same code running, and there are no other differences (e.g. interrupts) I started digging around system clock/ I noticed different clock register values in both configurations.
I'm using the STM32F407 Discovery board, which has an 8Mhz external oscillator.

In Rust I setup my clock as either:

rcc.cfgr.sysclk(stm32f4xx_hal::time::MegaHertz(168)).freeze();

or:

rcc.cfgr
                            .use_hse(stm32f4xx_hal::time::MegaHertz(8))
                            .sysclk(stm32f4xx_hal::time::MegaHertz(168))
                            .pclk1(stm32f4xx_hal::time::MegaHertz(42))
                            .pclk2(stm32f4xx_hal::time::MegaHertz(84))
                            .freeze();

(no difference in observed performance).

In C config, system clock is setup by ST-provided code:

*=============================================================================
*        Supported STM32F4xx device revision    | Rev A
*-----------------------------------------------------------------------------
*        System Clock source                    | PLL (HSE)
*-----------------------------------------------------------------------------
*        SYSCLK(Hz)                             | 168000000
*-----------------------------------------------------------------------------
*        HCLK(Hz)                               | 168000000
*-----------------------------------------------------------------------------
*        AHB Prescaler                          | 1
*-----------------------------------------------------------------------------
*        APB1 Prescaler                         | 4
*-----------------------------------------------------------------------------
*        APB2 Prescaler                         | 2
*-----------------------------------------------------------------------------
*        HSE Frequency(Hz)                      | 8000000
*-----------------------------------------------------------------------------
*        PLL_M                                  | 8
*-----------------------------------------------------------------------------
*        PLL_N                                  | 336
*-----------------------------------------------------------------------------
*        PLL_P                                  | 2
*-----------------------------------------------------------------------------
*        PLL_Q                                  | 7
*-----------------------------------------------------------------------------

When I dump RCC registers they do differ.
In Rust:

(gdb) x/16x 0x40023800
0x40023800:	0x03038583	0x24402a04	0x0000940a	0x00000000
0x40023810:	0x00000000	0x00000000	0x00000000	0x00000000
0x40023820:	0x00000000	0x00000000	0x00000000	0x00000000
0x40023830:	0x00100008	0x00000000	0x00000000	0x00000000

In C:

(gdb) x/16xw 0x40023800
0x40023800:	0x03038583	0x07405408	0x0000940a	0x00000000
0x40023810:	0x00000000	0x00000000	0x00000000	0x00000000
0x40023820:	0x00000000	0x00000000	0x00000000	0x00000000
0x40023830:	0x00100008	0x00000000	0x00000000	0x00000000

How can I achieve the same configuration, and performance, in Rust?

memory.x wrong for stopwatch-with-ssd1306-and-interrupts

(somewhat related to #115 ) Not sure if you deserve this, but maybe you are not running CI with the git memory.x ?
With memory.x from the git repository, which has
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 32K

For 'cargo build --target thumbv7em-none-eabihf --features stm32f411,rt --example stopwatch-with-ssd1306-and-interrupts' I get
= note: rust-lld: error: section '.rodata' will not fit in region 'FLASH': overflowed by 12 bytes
rust-lld: error: section '.rodata' will not fit in region 'FLASH': overflowed by 49 bytes
...
error: Could not compile stm32f4xx-hal.

There is no problem with the memory.x for my actual device, which has
/* Define memory regions. STM32F411RE */
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K

TIM DMA transfer support

Hi,
I'm trying to implement the Dshot protocol, similar to the one WS2812B uses.
This is the code where I already fail:

let dma1_streams = dma::StreamsTuple::new(device.DMA1);
let dma_transfer = dma::Transfer::init(
    dma1_streams.4,
    device.TIM3.ccr1,
    cortex_m::singleton!(: [u16; 18] = [0; 18]).unwrap(),
    None,
    dma::config::DmaConfig::default()
        .fifo_enable(true)
        .memory_increment(true),
);

Unfortunately it doesn't let me compile and returns an error message:

the trait bound `stm32f4::generic::Reg<u32, stm32f4xx_hal::stm32::tim3::_CCR>: stm32f4xx_hal::dma::traits::PeriAddress` is not satisfied
the trait `stm32f4xx_hal::dma::traits::PeriAddress` is not implemented for `stm32f4::generic::Reg<u32, stm32f4xx_hal::stm32::tim3::_CCR>`

I've seen in the source code that it requires the struct CCR1<pac::TIM3> to use TIM3_CH1, but where do I get it from?

Pll config invalid for 8mHz HSE

Hey,

In rcc pll config there is the following line:

// Input divisor from PLL source clock, must result to frequency in the range from 1 to 2 MHz
let pllm = 16;

If your HSE is 8mhz this results in a pll source clock of 500_000 which isn't valid, as the comment says.

Pull request #57 appears to fix this among other things.

It's a shame the writeConstraints in the SVD don't propagate through and enforce valid values for the fields - the ranges are all set correctly by stm32-rs but svd2rust just marks the fields as unsafe if the range doesn't cover the full width of the fields. As a fallback position, would it be a good idea to put some asserts or debug assertions in this crate to enforce valid values in the fields?

Cheers

The I2c driver does not check/set open_drain

Hi,

I was having issues with the I2c and it turned out to be that I had not done set_open_drain() on the pins.

There should be a check, or that the I2c should set this - as missing this does not produce a compile error and it can in worst case burn a slave when the master holds the bus high and the slave wants to ACK the address.
As it is now should be considered a design error as it can cause irreparable damage to a system without (compile-time/run-time) warning.

BR Emil

error: symbol `DEVICE_PERIPHERALS` is already defined

I cannot seem to compile the crate when using the stm32f429 feature. I have tried to use your crate in a project but could not compile it. So I tried cloning your repo to see if I could compile that. If I try to compile using this command:

cargo build --features stm32f407,rt

it works. If I try with the stm32f429 like this:

cargo build --features stm32f429,rt

it fails giving the error below:

error: symbol `DEVICE_PERIPHERALS` is already defined
    --> C:\Users\Ju\.cargo\registry\src\github.com-1ecc6299db9ec823\stm32f4-0.3.2\src\stm32f429\mod.rs:2206:1
     |
2206 | static mut DEVICE_PERIPHERALS: bool = false;
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

I'm new to embedded rust and rust in general, so sorry if I am missing something obvious.

Build broken with version update

A small demo program compiles find with this Cargo.toml:

[package]
name = "sbus-demo"
version = "0.0.1"
authors = ["Tim Docker<[email protected]>"]
description = "SBUS test"
keywords = ["arm", "cortex-m"]
categories = ["embedded", "no-std"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/timbod7/..."

[dependencies.stm32f407g-disc]
version = "0.1.1"

[dependencies.stm32f4xx-hal]
version = "0.2.2"

[dependencies.embedded-hal]
version = "0.2.2"

[dependencies.cortex-m]
version = "0.5.8"

[dependencies.cortex-m-rt]
version = "0.6.5"

[dependencies.panic-itm]
version = "0.4.0"

[dependencies.cast]
version = "0.2.2"
default-features = false

[dependencies.nb]
version = "0.1.1"

But after updating updating to reference the most recent stm32f4xx-hal (0.2.5), it fails to build:

$ cargo build
    Updating crates.io index
   Compiling stm32f4xx-hal v0.2.5                                                                                           
error[E0658]: access to extern crates through prelude is experimental (see issue #44660)
   --> /home/timd/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.2.5/src/serial.rs:326:39
    |
326 |                 fn read(&mut self) -> nb::Result<u8, Error> {
    |                                       ^^
    |
    = help: add #![feature(extern_prelude)] to the crate attributes to enable

error[E0658]: access to extern crates through prelude is experimental (see issue #44660)
   --> /home/timd/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.2.5/src/serial.rs:340:25
    |
340 |                         nb::Error::Other(Error::Parity)
    |                         ^^
    |
    = help: add #![feature(extern_prelude)] to the crate attributes to enable

error[E0658]: access to extern crates through prelude is experimental (see issue #44660)
   --> /home/timd/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.2.5/src/serial.rs:342:25
    |
342 |                         nb::Error::Other(Error::Framing)
    |                         ^^
    |
    = help: add #![feature(extern_prelude)] to the crate attributes to enable

error[E0658]: access to extern crates through prelude is experimental (see issue #44660)
   --> /home/timd/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.2.5/src/serial.rs:344:25
    |
344 |                         nb::Error::Other(Error::Noise)
    |                         ^^
    |
    = help: add #![feature(extern_prelude)] to the crate attributes to enable

error[E0658]: access to extern crates through prelude is experimental (see issue #44660)
   --> /home/timd/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.2.5/src/serial.rs:346:25
    |
346 |                         nb::Error::Other(Error::Overrun)
    |                         ^^
    |
    = help: add #![feature(extern_prelude)] to the crate attributes to enable

error[E0658]: access to extern crates through prelude is experimental (see issue #44660)
   --> /home/timd/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.2.5/src/serial.rs:351:25
    |
351 |                         nb::Error::WouldBlock
    |                         ^^
    |
    = help: add #![feature(extern_prelude)] to the crate attributes to enable

error[E0658]: access to extern crates through prelude is experimental (see issue #44660)
   --> /home/timd/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.2.5/src/serial.rs:359:40
    |
359 |                 fn flush(&mut self) -> nb::Result<(), Self::Error> {
    |                                        ^^
    |
    = help: add #![feature(extern_prelude)] to the crate attributes to enable

error[E0658]: access to extern crates through prelude is experimental (see issue #44660)
   --> /home/timd/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.2.5/src/serial.rs:366:29
    |
366 |                         Err(nb::Error::WouldBlock)
    |                             ^^
    |
    = help: add #![feature(extern_prelude)] to the crate attributes to enable

error[E0658]: access to extern crates through prelude is experimental (see issue #44660)
   --> /home/timd/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.2.5/src/serial.rs:370:50
    |
370 |                 fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
    |                                                  ^^
    |
    = help: add #![feature(extern_prelude)] to the crate attributes to enable

error[E0658]: access to extern crates through prelude is experimental (see issue #44660)
   --> /home/timd/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.2.5/src/serial.rs:380:29
    |
380 |                         Err(nb::Error::WouldBlock)
    |                             ^^
    |
    = help: add #![feature(extern_prelude)] to the crate attributes to enable

error: aborting due to 10 previous errors

any suggestions?

control of USART serial format

I've started attempting to use the serial abstraction, and immediately needed to tweak the flags. The existing code:

        usart
            .cr1
            .write(|w| w.ue().set_bit().te().set_bit().re().set_bit());

I needed to change to:

        usart
            .cr1
            .write(|w| w
              .ue().set_bit()
              .te().set_bit()
              .re().set_bit()
              .m().set_bit()    // 9 data bits
              .pce().set_bit()  // enable parity
              .ps().clear_bit() // even parity
              );

        usart.cr2.write( |w| w
          .stop().bits(2)    // 2 stops bits
        );

It didn't seem possible to set these flags prior or after the call to Serial::usart2(). Have you any ideas as to how you would generalise the API to allow control over the serialized format? Perhaps an extra parameter with options to control parity, number of stop bits etc?

Differences between this crate and stm32f1xx-hal

Hi there! I'm relatively new to the Rust embedded scene, but I've been able to get some simple firmware onto an stm32f411-based board and everything has worked great, I'm loving the way the type system guides me to using the correct pins for particular hardware peripherals.

I have both stm32f411 boards and stm32f103 boards. I started with the f411 but thought I'd try out some of my code on an f103. Immediately I noticed some differences between the crates and their APIs. As an example, the pwm code from both repos:

f103 pwm example
f411 pwm example

Lines like this have me a little confused:

// f103
let mut gpioa = p.GPIOA.split(&mut rcc.apb2);
...
let mut pwm = Timer::tim2(p.TIM2, &clocks, &mut rcc.apb1).pwm::<Tim2NoRemap, _, _, _>(
    pins,
    &mut afio.mapr,
    1.khz(),
);
// f411
let gpioa = dp.GPIOA.split();
...
let pwm = pwm::tim1(dp.TIM1, channels, clocks, 20u32.khz());

Why does the f411 code seem so much...simpler? Is its API design further along (or further behind)? Is the goal to get these two APIs closer than they currently are, or are they structured that way due to fundamental hardware differences?

I'd love to help out however I can, it's just hard for me to tell the state of these repos and where they're going. Thanks!

No implementation of `embedded_hal::blocking::serial::Write` for `stm32f4xx::serial::Tx`

I just noticed that there is no implementation of the embedded_hal::blocking::serial::Write trait when porting an application from my teensy4.0 to the stm32f407. Is there any reason for omitting this? If not, would you be happy to accept an implementation?

If so, would it be acceptable to implement it in terms of the existing embedded_hal::serial::Write implementation? I'm imagining something like this (unchecked):

impl<T> embedded_hal::blocking::serial::Write<u8> for serial::Tx<T>
where
    serial::Tx<T>: embedded_hal::serial::Write<u8>,
{
    type Error = serial::Error;
    fn bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
        for &b in bytes {
            loop {
                match self.write(b) {
                    Err(nb::Error::WouldBlock) => continue,
                    Err(err) => return Err(err),
                    Ok(()) => break,
                }
            }
        }
        Ok(())
    }

    fn bflush(&mut self) -> Result<(), Self::Error> {
        self.flush()
    }
}

i2c write hangs when receiving NACK

The current I2C implementation will hang indefinitely whenever a NACK is received on the bus during a write request.

This occurs because the current implementation waits for the SR1.addr bit to be set before determining that the address transfer is complete. The RM notes that this bit does not assert when a NACK is received.

image

Bit-banging is slow compared to the CubeIDE C version

I've been stuck on this for two days now, so even though it's probably a noob question, help would be appreciated. And if this is inappropriate as an issue, I'd appreciate being redirected to an appropriate forum..

  • STM32F411 "Black Pill" board with 25MHz external oscillator
  • stm32f4xx-hal version 0.8.0
  • Frequencies measured on a 100MHz 1GSa/s oscilloscope

In the course of trying (and failing) to get some sample neopixel code to work, I started to look at the setup of the various clocks, as my issues were timing related.
I created the simplest code, to turn a pin on, off then loop.

My initial results were a disappointing 75KHz
Once I figure out I needed to manually enable the HSE...

Rust

    let clocks = rcc.cfgr
        .use_hse(25.mhz())
        .sysclk(100.mhz())
        .freeze();     //actually: clock_and_pll_setup()

I can now get 483KHz

Yet when I try the same in CubeIDE, using CubeMX for clock and peripheral setup,

C in CubeIDE

    let mut pin = gpioa.pa7
        .into_push_pull_output()
        .set_speed(stm32f4xx_hal::gpio::Speed::VeryHigh);    //makes no difference

    loop {
        pin.set_low().ok();
        pin.set_high().ok();
    }

I now get 1.37MHz
Now, for a 100MHz processor, all these results seem very slow. I don't know ARM assembler, but I'd have thought that the entire loop is only 3 instructions, but even if it were 10, I'd expect to gt 10MHz out of it.

  1. Are my expectations wrong
  2. Why might the Rust code be only 1/3 of the speed of the C code?

How to access the status register (sr) when using the Serial hal implementation?

I'm (finally) trying to make use of this feature:

#42

In order to determine what caused the usart interrupt, I need to access the usart status register (sr) from the interrupt handler. But with code like this to initialize the usart:

        let config = serial::config::Config::default()
            .baudrate(100_000.bps())
            .parity_even()
            .wordlength_9()
            .stopbits(serial::config::StopBits::STOP2);
        let serial = Serial::usart2(p.USART2, (txpin, rxpin), config, clocks).unwrap();
        serial.listen(serial::Event::Rxne);
        serial.listen(serial::Event::Idle);
        let (mut tx, mut rx) = serial.split();

the move semantics for the first parameters of Serial::usart2() means that I cannot subsequently access p.USART2.sr.

Can you suggest a way to access sr after calling serial.split() ?

proposed example: countdown timer (GPIO, ADC, timers, IRQs, I2C/OLED)

As I finally managed to put together a working (yet seriously improvable) "quiet timer", it could be useful as an example of various features of the F4xx-hal crate. It has I2C-connected OLED display, ADC, timers and interrupts. It does have some issues: the board has to be reset after powering up to get the display to run (something related to the display driver), and the ADC reading needs to be more stable, but it does show some things that could be useful to others.

https://github.com/nebelgrau77/STM32F4-OLED-IRQ_timecounter

External interrupt source not correct

Relevant code and relevant datasheet section from STM32F411RE MCU.

stm32f4xx-hal/src/gpio.rs

Lines 190 to 217 in 216f7f6

impl<MODE> ExtiPin for $PXx<Input<MODE>> {
/// Make corresponding EXTI line sensitive to this pin
fn make_interrupt_source(&mut self, syscfg: &mut SYSCFG) {
let offset = 4 * ($extigpionr % 4);
match self.i {
0...3 => {
syscfg.exticr1.modify(|r, w| unsafe {
w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset))
});
},
4...7 => {
syscfg.exticr2.modify(|r, w| unsafe {
w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset))
});
},
8...11 => {
syscfg.exticr3.modify(|r, w| unsafe {
w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset))
});
},
12...15 => {
syscfg.exticr4.modify(|r, w| unsafe {
w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset))
});
},
_ => {}
}
}

macro_rules! gpio {
($GPIOX:ident, $gpiox:ident, $iopxenr:ident, $PXx:ident, $extigpionr:expr, [
$($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty, $exticri:ident),)+
]) => {

stm32f4xx-hal/src/gpio.rs

Lines 713 to 730 in 216f7f6

gpio!(GPIOB, gpiob, gpioben, PB, 1, [
PB0: (pb0, 0, Input<Floating>, exticr1),
PB1: (pb1, 1, Input<Floating>, exticr1),
PB2: (pb2, 2, Input<Floating>, exticr1),
PB3: (pb3, 3, Input<Floating>, exticr1),
PB4: (pb4, 4, Input<Floating>, exticr2),
PB5: (pb5, 5, Input<Floating>, exticr2),
PB6: (pb6, 6, Input<Floating>, exticr2),
PB7: (pb7, 7, Input<Floating>, exticr2),
PB8: (pb8, 8, Input<Floating>, exticr3),
PB9: (pb9, 9, Input<Floating>, exticr3),
PB10: (pb10, 10, Input<Floating>, exticr3),
PB11: (pb11, 11, Input<Floating>, exticr3),
PB12: (pb12, 12, Input<Floating>, exticr4),
PB13: (pb13, 13, Input<Floating>, exticr4),
PB14: (pb14, 14, Input<Floating>, exticr4),
PB15: (pb15, 15, Input<Floating>, exticr4),
]);

asdf

So for example if I would to be pin PB2 the interrupt line it should select is EXTI2.

$extigpionr = 1
$i = 1

which would imply

offset = 4
self.i = 1

in make_interrupt_source

This writes 0bXXXX_XXXX_0001_XXXX to the SYSCFG_EXTICR1 register. This enables EXTI1 which is not the correct one for PB2 pin.

Not completely sure if I missed something, or the implementation is not correct?

Thanks!

linking with `rust-lld` failed when stm32f4 crate is 0.8.0

So I was playing with this crate, and it seems only compatible with stm32f4 0.7.0,
if you have 0.8.0 in the Cargo.toml file, you get the below error

Compiling nucleo v0.1.0 (C:\Users\Beau\Code\rust\nucleo)
error: linking with rust-lld failed: exit code: 1
|
= note: "rust-lld" "-flavor" "gnu" "-L" "C:\Users\Beau\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\thumbv7em-none-eabihf\lib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.271x5gr5qamfyx15.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.2rkr7foartczqb4x.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.2ual8ehbeivzvzip.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.35u4h8fbwv4k3f1.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.3giu8u2ftlj6pjgq.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.3kxoq02mgsdnfnvw.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.46wer6d7gc7foq85.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.4pd5vo7t97ol8azi.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.4vxh1s0pjgr87h8.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.4yxwb4agdbctcsoq.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.50bp00c2ip9fgqaq.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.5361pmkaifxg2t6q.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.5cc3h2ivztv8wejj.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.8za6gpd8u0v7785.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.bb66a0hyld6wge3.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.nsbs2py5ykaohn2.rcgu.o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa.zqicaw9s06rvxl6.rcgu.o" "-o" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\nucleo-eaaf61e3bc003baa" "--gc-sections" "-L" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps" "-L" "C:\Users\Beau\Code\rust\nucleo\target\debug\deps" "-L" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\build\nucleo-1088d14277a13585\out" "-L" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\build\cortex-m-ed386150c0e5b37b\out" "-L" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\build\cortex-m-rt-6e040e191a361a80\out" "-L" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\build\cortex-m-semihosting-45af5f14089f505b\out" "-L" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\build\stm32f4-9e673fea380aabac\out" "-L" "C:\Users\Beau\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\thumbv7em-none-eabihf\lib" "-Bstatic" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libstm32f4xx_hal-cb9b9bd0f92caaa6.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libcast-102715931883d16a.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libstm32f4-8809c841ede78228.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libembedded_hal-6fa59b145b3f24df.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libvoid-caccc68030e75381.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libnb-8931201fc2df3281.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libcortex_m_rt-85ca3f10c3275010.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libr0-9e358f45ff0bc31a.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libcortex_m-7b43f46696745147.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libvolatile_register-e6d630b6a82d3760.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libvcell-932c9f4834bcbb12.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libbare_metal-6619d71299218a92.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libaligned-007dfa6be3bf44e6.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libas_slice-f6f01597d8c478e0.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libstable_deref_trait-6302bc78b015966f.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libgeneric_array-c50a2d94c73ba8d5.rlib" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libtypenum-b03d23e43a84478c.rlib" "--start-group" "C:\Users\Beau\Code\rust\nucleo\target\thumbv7em-none-eabihf\debug\deps\libpanic_halt-31b039c857184d9a.rlib" "C:\Users\Beau\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\thumbv7em-none-eabihf\lib\librustc_std_workspace_core-895383a3232f6572.rlib" "C:\Users\Beau\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\thumbv7em-none-eabihf\lib\libcore-5594cb4f559bc761.rlib" "--end-group" "C:\Users\Beau\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\thumbv7em-none-eabihf\lib\libcompiler_builtins-d0c6e5a851d2d415.rlib" "-Tlink.x" "-Bdynamic"
= note: rust-lld: error:
ERROR(cortex-m-rt): The interrupt vectors are missing.
Possible solutions, from most likely to less likely:
- Link to a svd2rust generated device crate
- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency
may be enabling it)
- Supply the interrupt handlers yourself. Check the documentation for details.

error: aborting due to previous error

error: Could not compile nucleo.

To learn more, run the command again with --verbose.

SPI DMA transfer size support

With current DMA implementation, it's impossible to configure DMA with 16-bit transfer size for SPI. It's also impossible to implement a wrapper type around SPI to define the u16 size manually, as you cannot implement the necessary DMASet outside of the crate.

With the current structure, it would be necessary for PeriAddress to accept transfer size as a generic type argument instead of having it as an associated type to enable multiple possible implementations for SPI (as you cannot implement PeriAddress twice with different MemSize when MemSize is an associated type). This change then propagates upwards up to the Transfer<> type where another generic type argument defining the transfer size would be necessary.

This in fact makes perfect sense, as you cannot always assume the transfer size from the peripheral upon which you want to perform the DMA transfers.

type DmaTransfer = Transfer<Stream4<DMA1>, Channel0, SPI2, MemoryToPeripheral, &'static mut [u16; 64], u16 /* transfer size */>;

This is how the new Transfer<> type would probably look like when implemented naively like I proposed. There was also a proposition to hold the DMA transfer size associated with the SPI peripheral (as it usually depends on the SPI frame size), but I think it's not always desirable, as you could also use a [u8] source (something like BBQueue) to feed SPI with u16 frame size.

I think the transfer size parameter should be made a bit less confusing at least, by using something like an enum to define the desired size, if implemented like this.

serial example

I have been trying to write an example using serial that works on different MCUs/boards to help me better understand the advantages of embedded-hal. My current version uses a setup function to isolate the MCU specific setup part and separate it from the code that should be generic enough to work with different stm32??xx_hal HALs.

The code below compiles (and works) with stm32f4xx_hal but the need to specify details of the type returned by serial1_setup() seems unnecessarily messy.

//! Echo console input back to console + semihost output, char by char
//!
//! 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)]
extern crate panic_semihosting;

#[cfg(not(debug_assertions))]
extern crate panic_halt;

use cortex_m_rt::entry;
use cortex_m_semihosting::hprintln;
use core::str::from_utf8;
use nb::block;

//use embedded_hal::serial;

#[cfg(feature = "stm32f4xx")] // eg Nucleo-64  stm32f411
use {stm32f4, stm32f4xx_hal::{prelude::*,  pac::Peripherals, serial::{config::Config, Serial }}};


#[entry]
fn main() -> ! {

    #[cfg(feature  = "stm32f4xx")]
    type SerialType = stm32f4xx_hal::serial::Serial<stm32f4::stm32f411::USART1,
    (stm32f4xx_hal::gpio::gpioa::PA9<stm32f4xx_hal::gpio::Alternate<stm32f4xx_hal::gpio::AF7>>,
     stm32f4xx_hal::gpio::gpioa::PA10<stm32f4xx_hal::gpio::Alternate<stm32f4xx_hal::gpio::AF7>>)>;

    #[cfg(feature = "stm32f4xx")]
    fn serial1_setup() -> SerialType {
        let cnfg = Config::default() .baudrate(9600.bps());
        let p = Peripherals::take().unwrap();
    	let rcc = p.RCC.constrain();
    	let clocks = rcc.cfgr.freeze();
    	let gpioa = p.GPIOA.split();
    	p.USART1.cr1.modify(|_,w| w.rxneie().set_bit());  //need RX interrupt? 
    	Serial::usart1(
    	    p.USART1,
    	    (gpioa.pa9.into_alternate_af7(),			      //rx pa9
	     gpioa.pa10.into_alternate_af7()),  		      //tx pa10
    	    cnfg,
    	    clocks,
    	    ).unwrap()
	}


    let mut txrx1 = serial1_setup(); 

    hprintln!("testwrite to console ...").unwrap();

    for byte in b"\r\nconsole connect check.\r\n" { block!(txrx1.write(*byte)).ok(); }

    hprintln!("test read and write by char. Please type into the console ...").unwrap();

    for byte in b"\r\nType (slowly) below:\r\n" { block!(txrx1.write(*byte)).ok(); }

    loop { // Read a byte and write
       let received = block!(txrx1.read()).unwrap();
       block!(txrx1.write(received)).ok();
       hprintln!("{}", from_utf8(&[received]).unwrap()).unwrap();
     }
}

With stm32f1xx_hal I can

use stm32f1xx_hal::{prelude::*, pac::Peripherals, serial::{Config, Serial, Tx1, Rx1 }};

and specify the signature of serial1_setup() as

fn serial1_setup(cnfg : Config) -> (Tx1, Rx1)

then split the result of Serial::usart1() before returning it, but stm32f4xx_hal does not seem to have any types or traits that allow me to do this cleanly. (Possibly I should be using embedded-hal traits Read and Write but so far I have not figured out how to do that in a way that works.)

An example of how to initiate serial in a clean, proper, idiomatic way would be very much appreciated.

BTW. stm32f4xx_hal has serial::config::Config while stm32f4xx_hal and others I have looked at have serial::Config. It would be nice if they could be the same.

I2c got stuck if no any wire connected

This is a strange phenomenon that, even I connect SCL with a wire that connected to nothing, this infinite loop breaks; And if I connect I2C to any device, this phenomenon no longer exists.

I2C running at 1/10th the frequency setting

Hi,

I'm using this HAL with an STM32F401RE MCU and have run into an issue with I2C configuration. Tried a few different parameters for i2c1 speed (setting -> observed):

  • 10 kHz -> 8.7 kHz
  • 20 kHz -> 17.4 kHz
  • 40 kHz -> 34.7 kHz
  • 60 kHz -> 6.45 kHz
  • 100 kHz -> 7.5 kHz
  • 200 kHz ->11.5 kHz
  • 400 kHz -> 23.6 khz
  • 1600 kHz -> 94.7 kHz

My delay provider does work correctly, however. delay.delay_ms(100_u16); measures at 99.7 ms.

Any idea why SCL runs at 1/10th (or less) the speed of the setting? Also, I'm running the MCU at 40 MHz, which could relate to the change in mapping after 40 kHz.

RCC.constrain eats the RCC

When calling the constrain function on the RCC, it eats the register. This is highly inconvenient as I want to later enable and disable different peripheral clocks and can't access the register. Now I need to resort to getting the register unsafely which I want to minimize.

Please consider to either give it back when freeze is called or implement the turning on and off of peripheral clocks in the Rcc type.

example stopwatch-with-ssd1306-and-interrupts fails to build

$ cargo build --target thumbv7em-none-eabihf --features stm32f411,rt --example stopwatch-with-ssd1306-and-interrupts
Compiling stm32f4xx-hal v0.6.0 (/home/paul/rust/egAttempts/stm32f4xx-hal)
error[E0061]: this function takes 0 parameters but 1 parameter was supplied
--> examples/stopwatch-with-ssd1306-and-interrupts.rs:149:17
|
149 | btn.clear_interrupt_pending_bit(exti);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 0 parameters

error: aborting due to previous error

For more information about this error, try rustc --explain E0061.
error: Could not compile stm32f4xx-hal.

UART8 interrupt not found

I'm trying to setup a receiving interrupt for the UART8 peripheral. When declaring the interrupt handler however, the UART8 variant is not found. When writing:

use stm32f4xx_hal::interrupt;
#[interrupt]
fn UART8() {
}

The compilation fails with the following error:

error[E0599]: no variant or associated item named `UART8` found for enum `stm32f4::stm32f413::Interrupt` in the current scope
  --> src/system/uart8.rs:42:4
   |
42 | fn UART8() {
   |    ^^^^^
   |    |
   |    variant or associated item not found in `stm32f4::stm32f413::Interrupt`
   |    help: there is a variant with a similar name: `UART5`

I'm compiling for the stm32f413 device, which is supposed to have an UART8 (I can read and write on it synchronously). I can write USART8 instead of UART8, even if the 8th UART does not support synchronous mode; the compilation succeeds, but then the interrupt handler is never called (I am enabling it with listen).

I am confused over what the issue could be. Is there some reason why I shouldn't be able to use UART8 interrupts?

Factory calibration is not present on all variants

According to the STMF407 reference manual, signature memory does not contain any internal reference calibration data - only flash size and the device signature are present.

The result of this is that ADC conversions (which then convert the sample to millivolts) may have an undefined value on this line of devices.

RM0090 for reference

Cannot use USART 1 of STMF407G (DISCOVERY)

I have tried to setup and use the USART 1 for serial communication. If the baud rate is 1200/2400, it works; around 4800 communication becomes corrupted and 19k2 or above just doesn't seem to work anymore. I have adapted the "serial_echo" example from the stm32f407g-disc create to work on this HAL crate as follows:

#![no_main]
#![no_std]

extern crate cortex_m_rt;
extern crate panic_semihosting;

use cortex_m_rt::entry;
use hal::block;
use hal::prelude::*;
use hal::serial::{config::Config, Serial};

#[entry]
fn main() -> ! 
    if let Some(p) = hal::stm32::Peripherals::take() {
        let gpioa = p.GPIOA.split();
        let rcc = p.RCC.constrain();
        let clocks = rcc.cfgr.sysclk(48.mhz()).freeze();

        // USART 1 at PA9 (TX) and PA10(RX)
        let tx = gpioa.pa9.into_alternate_af7();
        let rx = gpioa.pa10.into_alternate_af7();

        // Set up USART 1 configured pins and a baudrate of 115200 baud
        let serial = Serial::usart1(
            p.USART1,
            (tx, rx),
            Config::default().baudrate(115_200.bps()),
            clocks,
        )
        .unwrap();

        // Separate out the sender and receiver of the serial port
        let (mut tx, mut rx) = serial.split();

        loop {
            // Read character and echo it back
            let received = block!(rx.read()).unwrap();
            block!(tx.write(received)).ok();
        }
    }

    loop {
        continue;
    }
}

But this results in a panic, even though we are only configuring the sysclk:

panicked at 'assertion failed: pclk1 <= pclk1_max', /home/paul/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.3.0/src/rcc.rs:277:9

When leaving out the sysclk(48.mhz()) call, it compiles, but communication seems inpossible.
When setting to 9600 baud and sending 0xAA (10101010), I get back 0xFA or 0xEA.

See also the attached output below of a logic analysis where you can see that the TX part has malformed with respect to what was sent on RX.

Screenshot from 2019-03-08 22-32-11

When changing the code to use USART 2 (pins PA1/PA2) instead, everything works just fine.

I2C write may hang indefinitely after read

When performing an I2C write immediately after an I2C read, the write transaction sometimes holds indefinitely.

Upon investigation, I believe this is because software is not currently waiting for the STOP condition to transmit at the end of the write process (it is left to complete asynchronously). This can then lead to a race condition within the I2C peripheral. When a read() occurs quickly afterwards, the START bit is set.

This can lead to conditions where the I2C peripheral has both START and STOP set at the same time at the end of a write process.

I believe this is causing the I2C write transaction to not actually complete in this case and instead a RESTART is sent on the bus, which results in the read() hanging indefinitely

A fix would be to update the i2c::write() function to wait for the STOP condition to be sent (wait for STOP bit to clear) before returning.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.