Giter Site home page Giter Site logo

stm32h7xx-hal's Introduction

STM32 Peripheral Access Crates

CI crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io Matrix

This repository provides Rust device support crates for all STM32 microcontrollers, providing a safe API to that device's peripherals using svd2rust and a community-built collection of patches to the basic SVD files. There is one crate per device family, and each supported device is a feature-gated module in that crate. These crates are commonly known as peripheral access crates or "PACs".

To view the generated code that makes up each crate, visit the stm32-rs-nightlies repository, which is automatically rebuilt on every commit to stm32-rs master. The stm32-rs repository contains the patches to the underlying SVD files and the tooling to generate the crates.

While these crates are widely used, not every register of every device will have been tested on hardware, and so errors or omissions may remain. We can't make any guarantee of correctness. Please report any bugs you find!

You can see current coverage status for each chip here. Coverage means that individual fields are documented with possible values, but even devices with low coverage should have every register and field available in the API. That page also allows you to drill down into each field on each register on each peripheral.

Using Device Crates In Your Own Project

In your own project's Cargo.toml:

[dependencies.stm32f4]
version = "0.15.1"
features = ["stm32f405", "rt"]

The rt feature is optional but helpful. See svd2rust for details.

Then, in your code:

use stm32f4::stm32f405;

let mut peripherals = stm32f405::Peripherals::take().unwrap();

Refer to svd2rust documentation for further usage.

Replace stm32f4 and stm32f405 with your own device; see the individual crate READMEs for the complete list of supported devices. All current STM32 devices should be supported to some level.

Using Latest "Nightly" Builds

Whenever the master branch of this repository is updated, all device crates are built and deployed to the stm32-rs-nightlies repository. You can use this in your Cargo.toml:

[dependencies.stm32f4]
git = "https://github.com/stm32-rs/stm32-rs-nightlies"
features = ["stm32f405", "rt"]

The nightlies should always build and be as stable as the latest release, but contain the latest patches and updates.

Generating Device Crates / Building Locally

  • Install svd2rust, svdtools, and form:
    • On x86-64 Linux, run make install to download pre-built binaries at the current version used by stm32-rs
    • Otherwise, build using cargo (double check versions against scripts/tool_install.sh):
      • cargo install form --version 0.12.1
      • cargo install svdtools --version 0.3.17
      • cargo install svd2rust --version 0.33.4
  • Install rustfmt: rustup component add rustfmt
  • Generate patched SVD files: make patch (you probably want -j for all make invocations)
    • Alternatively you could install cargo-make runner and then use it instead of make. Works on MS Windows natively:
      • cargo install cargo-make
      • cargo make patch
  • Generate svd2rust device crates: make svd2rust
  • Optional: Format device crates: make form

Motivation and Objectives

This project serves two purposes:

  • Create a source of high-quality STM32 SVD files, with manufacturer errors and inconsistencies fixed. These files could be used with svd2rust or other tools, or in other projects. They should hopefully be useful in their own right.
  • Create and publish svd2rust-generated crates covering all STM32s, using the SVD files.

When this project began, many individual crates existed for specific STM32 devices, typically maintained separately with hand-edited updates to the SVD files. This project hopes to reduce that duplication of effort and centralise the community's STM32 device support in one place.

Helping

This project is still young and there's a lot to do!

  • More peripheral patches need to be written, most of all. See what we've got in peripherals/ and grab a reference manual!
  • Also everything needs testing, and you can't so easily automate finding bugs in the SVD files...

Supported Device Families

crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io crates.io

Please see the individual crate READMEs for the full list of devices each crate supports. All SVDs released by ST for STM32 devices are covered, so probably your device is supported to some extent!

Devices that are nearly identical, like the STM32F405/F415, are supported by ST under a single SVD file STM32F405, so if you can't find your exact device check if its sibling is supported instead. The crate READMEs make this clear.

Many peripherals are not yet patched to provide the type-safe friendly-name interface (enumerated values); please consider helping out with this!

Check out the full list of supported devices here.

Adding New Devices

  • Update SVD zips in svd/vendor to include new SVDs.
  • Run make extract to extract the new zip files.
  • Add new YAML file in devices/ with the new SVD path and include any required SVD patches for this device, such as renaming or merging fields.
  • Add the new devices to stm32_part_table.yaml.
  • Add the new devices to scripts/makecrates.py.
  • You can run scripts/matchperipherals.py script to find out what existing peripherals could be cleanly applied to this new SVD. If they look sensible, you can include them in your device YAML. This requires a Python environment with the pyyaml and svdtools dependencies. Example command: python scripts/matchperipherals.py peripherals/rcc devices/stm32h562.yaml
  • Re-run scripts/makecrates.py devices/ to update the crates with the new devices.
  • Run make to rebuild, which will make a patched SVD and then run svd2rust on it to generate the final library.

If adding a new STM32 family (not just a new device to an existing family), complete these steps as well:

  • Add the new devices to the CRATES field in Makefile.
  • Update this Readme to include the new devices.
  • Add the devices to workflows/ci.yaml and workflows/nightlies.yaml.

Updating Existing Devices/Peripherals

  • Using Linux, run make extract at least once to pull the SVDs out.
  • Edit the device or peripheral YAML (see below for format).
  • Using Linux, run make to rebuild all the crates using svd patch and svd2rust.
  • Test your new stuff compiles: cd stm32f4; cargo build --features stm32f405

If you've added a new peripheral, consider using the matchperipherals.py script to see which devices it would cleanly apply to.

To generate a new peripheral file from scratch, consider using periphtemplate.py, which creates an empty peripheral file based on a single SVD file, with registers and fields ready to be populated. For single bit wide fields with names ending in 'E' or 'D' it additionally generates sample "Enabled"/"Disabled" entries to save time.

Device and Peripheral YAML Format

Please see the svdtools documentation for full details of the patch file format.

Style Guide

  • Enumerated values should be named in the past tense ("enabled", "masked", etc).
  • Descriptions should start with capital letters but do not end with a period

Releasing

Notes for maintainers:

  1. Create PR preparing for new release:
    • Update CHANGELOG.md with changes since last release and new contributors
    • Update README.md to bump version number in example snippet
    • Update scripts/makecrates.py to update version number for generated PACs
  2. Merge PR once CI passes, pull master locally.
  3. make clean
  4. make -j16 form
  5. for f in stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32h7 stm32l0 stm32l1 stm32l4 stm32l5 stm32g0 stm32g4 stm32mp1 stm32wl stm32wb; cd $f; pwd; cargo publish --allow-dirty --no-default-features; cd ..; end
  6. git tag -a vX.X.X -m vX.X.X
  7. git push vX.X.X

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

stm32h7xx-hal's People

Contributors

alyoshavasilieva avatar andrewgazelka avatar antoinevg avatar astraw avatar bors[bot] avatar burrbull avatar dflemstr avatar diondokter avatar dsmcfarl avatar elouanpetereau avatar glindstedt avatar hargonix avatar jarredallen avatar jlogan03 avatar jordens avatar lachlansneff-parallel avatar mattico avatar mlamoore avatar mtthw-meyer avatar newam avatar nkrackow avatar olback avatar orange-murker avatar ostenning avatar phoracek avatar richardeoin avatar robamu avatar romixlab avatar ryan-summers avatar x37v avatar

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

stm32h7xx-hal's Issues

No QSPI support for memories

Some of the features that would be required to communicate with memories over QSPI (instructions, dummy cycles..) are not supported

Already existing stm32h7x3-hal project

Hey guys, I'm the owner of https://github.com/hargoniX/stm32h7x3-hal which I've been working on for the past few months and I was wondering if you'd be interested in me PRing all my implementations you don't have yet, like for example the already tested I2C and the SPI one over to you and continue my work on your repository.

EDIT: Looking at your code a little I can also provide you with a few extensions of for example the rcc with a custom sys_ck setting which I've been spending on getting to work for a few weeks in feburary.

GPIOC Unknown Field

I can compile this without any issues
cargo build --example blinky --features=stm32h750v,rt

But if I take the same code, paste it into a new crate, copying the .cargo/config and dependencies it won't compile. I've compared everything I can think of and there is just something missing that I can't figure out.

cargo build
   Compiling daisy-lib2 v0.1.0 (/home/zerikin/rust/daisy-lib2)
error[E0609]: no field `GPIOC` on type `stm32h7xx_hal::rcc::rec::PeripheralREC`
  --> src/main.rs:28:48
   |
28 |     let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);
   |                                                ^^^^^ unknown field
   |
   = note: available fields are: `ETH1MAC`, `DMA2`, `DMA1`, `SDMMC2`, `HASH` ... and 22 others

error: aborting due to previous error

For more information about this error, try `rustc --explain E0609`.
error: could not compile `daisy-lib2`.

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

[Proposal] Log wrapper

For my own project I wrapped the log crate to allow output via RTT or none via feature. A feature gated logger implementing several implementations sounds really useful. Could include ITM, RTT, etc. Leaving no features selected makes the macro empty and it get's compiled out.

Is this the right level of crate for this or should it go somewhere else?

Example

Reincorporate stm32h7-ethernet

As per the conversation on Matrix and in #76, it has been proposed that the various stm32h7 peripheral drivers should be contained within this crate to prevent many interdependent crates in the h7 ecosystem. Instead, peripherals that are not directly related to the embedded-hal should be placed behind feature gates.

This issue encompasses re-incorporating the stm32h7-ethernet crate into this crate.

@hargoniX mentioned that he was planning on getting to this in the near future.

Implement tick_timer() for lptimers

Ref #114

The tick_timer method is not implemented for LPTIM[1-5]

Is there some limitation of the LPTIMs that makes it difficult?

The LPTIMs require a specific initialisation sequence (for example, CFGR must be set before enabling the timer, ARR must be set after), so it's not difficult but rather a little tedious to check against the RM that it's correct.

More constfn!

It has finally happened! As per rust-lang/rust#72437 the following things are now allowed in const functions:

  • if, if let, and match
  • while, while let, and loop
  • the && and || operators

This should allows us to basically move all of our clock calculation optionally to compile time since for most of the peripherals we provide it's very unlikely someone will want to dynamically change the clock speed at runtime, if they instead opt in to const-fn calculation of their clock speeds we can:

  • reduce initialization time since we don't have to calculate the config while starting up anymore
  • reduce binary size since the code wanders from runtime to compile time

I'm not quite sure whether this is doable as a const fn without breaking the current API though? I'd imagine we would need to add an additional parameter clock_configuration that gets passed the result of such a config calculator function? For example an I2C init might end up looking like:

dp.I2C1.i2c((scl, sda), i2c_configuration(100.khz()), ccdr.peripheral.I2C1, &ccdr.clocks);

Because otherwise the constant functions aren't called in a constant context so the rust compiler would treat them just like normal functions, or am I mistaken about that? If the compiler was feeling really clever it could of course allow us to call the const fn inside the i2c function, see that the parameter is a constant and evaluate the const fn at compile time, but I dont think it can perform such magic? Again not quite sure, this definitely requires some further investigation but definitely provides some big benefits for the HAL once adopted.

Examples use ITM

May cause a hang when running examples, if debugger is removed or mis-configured.

Feature gating ITM usage is a possible solution.

Ethernet

  • ETH_MACMIIAR_CR is only valid for HCLK 150-250 MHz
  • MDIO interface only supports PHYs with address 0 - #130
  • Add documentation explaining how to use PHY feature flags - #130
  • Add ethernet to CI - #130

See also #121

UART bug

In a mail by @eeboo he brought up the following repository: https://github.com/eeboo/stm32h743zi-test/

In there you will find two examples, one tagged ok, the other tagged ko. The ko example is producing garbage on his logic analyzer.
As one can see in his example code the only difference is:

// Acquire the GPIOD peripheral. This also enables the clock for
    // GPIOD in the RCC register.
    let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);

    let tx = gpiod.pd8.into_alternate_af7();
    let rx = gpiod.pd9.into_alternate_af7();


    // Configure the serial peripheral.
    let serial = dp
        .USART3
        .usart(
            (tx, rx),
            serial::config::Config::default(),
            ccdr.peripheral.USART3,
            &ccdr.clocks,
        )
        .unwrap();

in the Ok example, vs

    let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);

    let tx = gpiob.pb9.into_alternate_af8();
    let rx = gpiob.pb8.into_alternate_af8();


    // Configure the serial peripheral.
    let mut serial = dp
        .UART4
        .usart(
            (tx, rx),
            serial::config::Config::default(),
            ccdr.peripheral.UART4,
            &ccdr.clocks,
        )
        .unwrap();

in the not working example. (and only now am I realizing that in my response I actually misread, its not pd8 being used for both but pb8 for the not working one)

We should definitely investigate on this.

ResetEnable trait methods require ownership

The ResetEnable trait is implemented for Peripheral Reset Enable Control (PREC) ZSTs. However, its methods require self, so it cannot be used when we only have a &mut- reference to the PREC.

Proposal:

Change the ResetEnable trait to implement these methods for &mut self instead.

Advantages:

  • Usability, see #116

Downsides:

  • Allows the PREC to be reset/enabled when we only hold a &mut- reference to it. Currently if the PREC is part of a struct, we can be sure the peripheral will not be reset / disabled until that struct's destructor.

Implementing peripherals which arent in embedded hal yet

If somebody was to use this project as a basis for peripherals which aren't defined (and maybe never will be because they are too specific to this or the stm32 series) he would probably fail at the simple fact that he cannot use the RCC registers (rb) in the Ccdr at the moment. Is there any workaround to this which comes to mind (apart from the two obvious ones, setting the RCC from pub (crate) to pub or just PRing it in, which brings up the question, are peripherals which aren't defined in embedded hal supposed to live here as well?)

DMA module does not reset/enable during initialization

When DMA::split() is called, the PREC is not provided and the DMA does not set the reset/enable bits in the RCC.

Further configuration and usage of the DMA is then inoperative because the peripheral is not enabled.

Add PLL strategy for fractional clock

The fractional divisor allows setting of precise clocks during runtime using the rcc_pllxfracr register. It needs to be enabled during startup. I purpose adding two new PLL strategies that enable the fractional divisor. One for just below and just above a target value. (e.g. for audio I want a clock that is as close to possible as 48 KHz * 256 without going under).

I think the existing iterative strategy could be used to set the base clock and then tweak the rcc_pllxfracr from there.

PllConfigStrategy::FractionalGreaterThan
PllConfigStrategy::FractionalLessThan

README on crates.io

The README on crates.io doesn't seem to be up to date as of now, at least it still states that we require nightly / beta to build which isn't the case since the stabilization of 1.37 anymore, I think we should update that.

Secondly our build for docs.rs is currently failing, however I've already been pointed at a way to fix this and will look into that in a few minutes.

As a side not as to where this is coming from I'm currently doing a PR to get our crate into the awesome-embedded-rust list: rust-embedded/awesome-embedded-rust#209

Clocks contains wrong value of `sys_ck` when it comes from PLL1

When the system clock is set by rcc.sys_ck(), the required clock usually comes from PLL1 P CK. But in the case where the generated PLL1 P CK does not exactly match what was specified (depending on the pll strategy), then the calculated PLL1 P CK frequency should be used for sys_ck and derived clocks. Currently the specified value is used.

PWR needs to be updated to support vos0 (480Mhz).

Looking at how VOS0 scaling needs to be implemented the current structure is going to need to be broken a bit I opted to create a new freeze_vos0 function to not break all the existing code.

RM0433 rev 7

VOS0 activation/deactivation sequence
The system maximum frequency can be reached by boosting the voltage scaling level to
VOS0. This is done through the ODEN bit in the SYSCFG_PWRCR register.
The sequence to activate the VOS0 is the following:

Ensure that the system voltage scaling is set to VOS1 by checking the VOS bits in
PWR D3 domain control register (PWR D3 domain control register (PWR_D3CR))

Enable the SYSCFG clock in the RCC by setting the SYSCFGEN bit in the
RCC_APB4ENR register.

Enable the ODEN bit in the SYSCFG_PWRCR register.

Wait for VOSRDY to be set.
Once the VCORE supply has reached the required level, the system frequency can be
increased. Figure 31 shows the recommended sequence for switching VCORE from VOS1 to
VOS0 sequence.

Setup PWR...
Setup RCC...

stm32h7xx-hal example - RCC

hclk = 240 MHz
sys_ck = 480 MHz

#96

[Bug] ADC initialization might panic

Description and Reproduction

Currently, the ADC initialization might panic if following happens:

  • Watchdog enabled
  • ADC initialized and enabled
  • Panic occurs, causing watchdog to restart the software
  • ADC initialized again (and thus calibrated) -> fails because:
    • Reset isn't being triggered because the clock of the ADC is still running (see adc.rs, line 283)
    • Therefore, ADC is still enabled
      -> ADC calibration will panic

Possible fix

Upon initialization, check if ADC is enabled and disable it then.

Support custom SPI configurations

The existing SPI configuration assumes a lot of default configuration values (e.g. 8 bit frames, 1 frame per transaction, no delay between CS and SCK assertions).

I propose that we update the Spi constructors to accept a spi::Config structure instead of the spi::Mode parameter. This Config structure would contain all of the device-specific implementation. To construct the Config, a builder semantic can be used:

Let config = Spi::Config::new(Mode {polarity: Polarity::IdleHigh, phase: Phase::CaptureOnSecondTransition})
    .frame_size(8) // Configure 8-bit transactions
    .swap_miso_mosi() // Swap MOSI and MISO lines
    .cs_delay(100e-6) // 100uS delay from CS -> SCK
    .freeze();

let spi = spi::Spi1::new(dp.SPI1, (sck, miso, mosi), config, 10.mhz(), &clocks);

This allows us to initially provide a minimal configuration as to what users require and expand on it as needed without changing the API at all (e.g. backwards compatible).

I'd be happy to implement this and PR it, just wanted to get some feedback first.

Background

I'm currently working on a platform using SPI to talk to some ADCs and DACs where the channel is half-duplex. Some additional configurations that I need are:

  1. MSSI support (programmable delay from CS assertion to transaction)
  2. Configurable transaction length (16 bit frames)
  3. Support for swapping MOSI/MISO lines

[Proposal] Add pwm features for power electronics

I'm working on a project using the STM32H750 for power electronics applications. I need several features of the chip that are beyond the simple interface of embedded-hal, but I'd like to do this in a way that is still compatible with the embedded-hal traits and is as generally useful as possible.

I'm an experienced embedded C developer but relatively new to Rust, especially trait/generic based libraries and macros. I'm looking for feedback on what features should be included and how they should be exposed to the user.

Here's the features I want to add:

  • Center-aligned PWM
  • PWM break input pins for overcurrent faults
  • Complementary PWM outputs with dead time

Center-aligned PWM is a different counter mode that can be set up on initialization of timers 1,2,3,4,5,8. It can be easily set up at timer initialization and ignored while running.

PWM fault input pins, complementary outputs, and dead time are all supported only on timers that have the BDTR register: timers 1,8,15,16,17. All channels use the same dead time, so I envision that being configured at timer initialization. I think it would make sense to initialize channels as standard/positive polarity and add a .into_complementary_output(complementary_pin) function that changes the PWM mode from single ended to complementary.

For the break inputs, the hardware is very flexible and configurable. I would like to use the break input functionality to turn off PWM when the break input pin goes low and not turn it back on until a function is called to clear the fault. I would like to do this by returning a separate struct that implements a trait with functions fault_active() -> bool and clear_fault(). The individual PWM channels would be completely unaware of the fault functionality: they would continue to set duty cycle, enable, or disable normally and the output would just stay inactive until a fault was cleared.

I'm thinking about two different APIs for this:

Separate functions, like this:
TIM1.pwm(pins, freq, prec, clocks) -> (channels)
TIM1.pwm_center(pins, freq, prec, clocks) -> (channels)
TIM1.pwm_deadtime(pins, freq, prec, clocks, deadtime) -> (channels)
TIM1.pwm_fault_deadtime(pins, freq, prec, clocks, fault_pin, fault_state, deadtime) -> (fault_monitor, channels)
TIM1.pwm_center_fault_deadtime(pins, freq, prec, clocks, fault_pin, fault_state, deadtime) -> (fault_monitor, channels)

Then channels could be adjusted like this:
channel.set_active_level( ActiveHigh or ActiveLow )
channel.set_fault_level( ActiveHigh or ActiveLow )
let channel = channel.into_complementary_pwm( complementary_pin, complementary_active_state, complementary_fault_state )

Or I could make a builder style API, something like this (with the same methods to adjust an individual channel mode):

TIM1.pwm(pins, freq, prec, clocks).center_aligned(),deadtime(500.ns()).fault( fault_pin, fault_state, complementary_fault_state ).freeze() -> (fault_monitor, channels)

The downside is that breaks existing code using TIM1.pwm(), so I could keep TIM1.pwm() as is and add TIM1.advanced_pwm() for the builder.

Does anybody have an opinion on whether I should implement the first API, the second API, or something else? And are there other PWM related functions people would like to see or other places I should make this more flexible for others?

ST have renamed D3 to SRD on new A3/B3 parts

Hi all,

This issue really affects the PACs but I expect it will have an impact on the HAL, and the HAL developers are probably in a good position to comment on it, so I thought I'd ask here first.

It's been pointed out that ST have started calling "SmartRun", "SmartRun Domain", and "SRD" what used to be called "D3". Our SVDs for the A3/B3/B0 parts use "D3", for example in PWR:CPUCR:RUN_D3 which is now called RUN_SRD in the reference manual. It seems like the older H7 parts are not renamed (yet?).

What do you think we should do about it? Options seemingly include:

  • Do nothing, keep D3, which maintains easier compatibility with other H7 parts for clock and memory setup, but disagrees with the reference manual
  • Rename D3 to SRD in the SVDs, so HAL and user code will have to handle these devices separately
  • Other?

I assume future H7 devices will use the new names, which might suggest we stick to the reference manuals and at some point have to rename the current SVDs.

Cargo.toml typo

In Cargo.toml I think the line
stm32h742 = ["stm32h7/stm32h743", "device-selected", "singlecore"]
should have 742 in place of 743

No implementation for SAI I2S

As far as I can tell the only implemented functionality for SAI is PDM. The daisy uses SAI I2S for audio I/O to the codec chip. If I can figure it out I may take a shot at implementing it myself.

Unused trait in Serial?

So I was just reading through our UART/USART implementation in serial.rs and there we define the trait pub trait PinCk<USART> {} in line 155. It's only ever used again in the macro that implements it en mass for all the pins that are valid clock pins for USART. However I believe the correct intention should be to implement the Pin trait for a (TX, RX, CK) triple for all USART constructors right? Otherwise the trait doesn't bring any additional safety guarantees as far as I can see (feel free to correct me on that).

Type-erased GPIO pin modes

I have a number of drivers where I need to change the mode of a GPIO pin during normal operation. However the type-state GPIO design makes this very annoying. For example:

enum ReadyPin {
    PullDown(gpioe::PE1<Input<PullDown>>),
    PullUp(gpioe::PE1<Input<PullUp>>),
}

pub struct Outgoing {
    i2c: i2c::I2c<pac::I2C1>,
    ready: ReadyPin,
    _aux: gpioe::PE0<Analog>,
}

I just want to store the pin in the driver struct but it's hard because its type changes all the time. I want to enable and disable interrupt generation on the pin but now I have to match every time I want to access the pin even though nothing changes but the type. It would be nice to have a GPIO pin type which erases the MODE type.

I'm also questioning the value of the MODE type-state altogether.

In user code the gpio pin is probably wrapped up in a driver which implements the desired behavior. Drivers in my experience either:

  1. Are built on top of embedded-hal, which doesn't care about our MODE types at all.
  2. Are built for a specific board which will use specific pins for specific peripherals. I found in this case it's cleaner to have your drivers just take Analog pins and do the configuration themselves to remove that pin-configuring clutter from main() and into the code that cares about it.

Am I missing something that these types help in user code?

I could only find one place in the HAL that actually used a mode type for anything. internal_pull_up(&mut self, bool) is only implemented for Output<OpenDrain> and Alternate<MODE>. I don't think it's particularly important that the type system prevents you from calling it on a push-pull output. All of the peripherals take Alternate<> pins which already erases the PushPull/OpenDrain and PullUp/PullDown/Floating types. Perhaps there are cases where the AF* typestates disambiguate things so those could be kept? If not, just have the peripherals do the pin configuration themselves and save us the trouble.

I don't have much hope that this will happen. It would be a huge breaking change in the HAL and a huge break with the other STM32 HALs, so I'll settle for adding a type-erased GPIO pin. With all the 1.0 discussions happening though, maybe I should make a last-chance push to remove the needless (?) complexity.

Flash clock and wait states

To calculate the number of wait states for the flash, we use RM0433 Rev 7. Table 17

image

This table implies the calculation should be based on the AXI Interface clock (= rcc_hclk). However the text immediately above it says it should be based on sys_ck. Indeed the block diagram (Fig. 5) shows only sys_ck entering the flash sub-system.

image

image

Which clock should we use for this calculation? (see Figure 49.)

  • sys_ck
  • sys_d1cpre_ck ( = sys_ck / 1)
  • rcc_hclk ( = sys_d1cpre / 2 by default)

Currently we use sys_d1cpre_ck, so the flash is always set to 7 wait states for sys_d1cpre_ck > 225MHz.

TODO:

  • Decide and use correct clock
  • Add flash wait state table for VOS0

DMA API

During today's embedded WG meeting James mentioned that:

If you see anyone working on DMA stuff, ping them and see if they could move their work over to the new APIs :)

Referring to these https://github.com/ra-kete/dma-poc APIs.

So @Jan561 should maybe try and look into directing his efforts towards getting DMA running towards these APIs, if enough succesul implementations show up they might be added to embedded-hal soon ™️ which would be a big plus embedded Rust.

Expose RCC registers for external usage

When the HAL is used in an application, there are (many) peripherals that are not yet supported by the HAL (such as ethernet, quadspi, DMA, etc.). Often, these peripherals may need a custom implementation for performance or specific use-case considerations.

The Rcc::Ccdr should expose the underlying RCC register block publicly so that other drivers may modify the necessary RCC registers to enable clocks and reset peripherals as needed. This is currently done only for the HAL crate, but it may be appropriate to allow this block to be exposed for all usage.

As currently implemented, the HAL takes exclusive ownership of the RCC registers, so it's impossible to implement application-specific drivers outside of the HAL alongside drivers that utilize the HAL implementation.

Timer first cycle is invalid

When the timer is configured, the first cycle of the timer will have an incorrect period. After the first cycle, all following periods will be correct.

This occurs because the ARR register is buffered and doesn't become "Active" (referred as the shadow register in the datasheet) until an update event occurs (either by software or hardware).

As such, the timer start() routine needs to make a call to

self.tim.egr.write(|w| w.ug.set_bit());

to force an update of the ARR register. There's another method of accomplishing this (bypassing the shadow register), but I don't think that's what we want.

[RFC] Erase pin types from HAL driver types

When implementing an application using RTFM and storing peripheral resources in the Resource structure, the type of the peripheral can be quite onerous to carry around as it contains generic parameters for the pins and peripheral instance.

Example:

let spi = hal::spi::Spi1::new(dp.SP2, (sck, miso, mosi), ...);

The spi variable has the following type:

hal::spi::Spi<
    hal::stm32::SPI2, (
        hal::gpio::gpiob::PB10<hal::gpio::Alternate<hal::gpio::AF5>>, 
        hal::gpio::gpiob::PB14<hal::gpio::Alternate<hal::gpio::AF5>>,
        hal::spi::NoMosi)
>

This type then changes based on which pins are used. This type is also required to be specified in the RTFM resource structure declaration, which results in a (fairly messy) structure definition that's non-intuitive.

Because the pin types are used only as a compile-time guarantee that they implement the necessary SPI alternate functions, I don't believe there's a need for the SPI module to carry around this type information after instantiation (although the SPI peripheral needs to maintain ownership of the pins).

I propose that we update the SPI constructor to downgrade the pins to a generic "pin" type since they are never directly controlled by the SPI peripheral. This would remove pin types from the type signature and simplify it to something like hal::spi::Spi<hal::stm32::SPI2>, which is much more manageable (and we could potentially remove the SPI2 type as well with other work, although that's beyond scope here).

SPI operates in "endless transaction" mode

When a SPI transaction occurs, the HAL operates the SPI in "endless transaction" mode, which means that the SPI peripheral is not able to detect when a transaction completes.

The SPI_CR2.TSIZE register value needs to be updated with the size of the transaction in bytes before a transaction is initiated.

QSPI reads unstable

Due to a likely silicon bug, the QSPI peripheral (reference quartiq/stabilizer#101), QSPI reads may be incorrect when reading at the rising clock edge.

To work around this, the QSPI peripheral can be updated to read on the falling clock edge instead by setting the SSHIFT bit:
image

embedded hal digital IO v2

The embedded hal group marked the v1 of digital IO as deprecated, should we also implement a v2 version for the future already?

Support for stm32h725/735

Hi,

I'd like for a project to use the stm32h725. It has ECC RAM, something the other stm32h7 boards don't have. Well except for the stm32h747/757, but I'd rather not pay the premium for features I won't use anyway.
I noticed those boards aren't supported by this library.

Is it because nobody has the μControler to test? Or is it because of an incompatibility with the hardware?

If it's because of testing or minor incompatibility I'd be willing to help. I have never worked on a HAL like this though, so if it's ok with you I'd still want instructions about how to proceed.

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.