From 6d7d10ad7c527c2c57b7b2e99b3932fbf6f74b05 Mon Sep 17 00:00:00 2001 From: Piroro-hs Date: Wed, 28 Apr 2021 23:31:30 +0900 Subject: [PATCH] Update docs and some fixes --- .github/workflows/ci.yml | 1 + CHANGELOG.md | 5 + Cargo.toml | 2 +- README.md | 97 ++++++---- build.rs | 139 +++++++++++---- src/lib.rs | 370 +++++++++++++++++---------------------- 6 files changed, 338 insertions(+), 276 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5b2fe1ca..699af5ec9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: + # Devices only differ in memory size are commented out mcu: - stm32f301x6 - stm32f318x8 diff --git a/CHANGELOG.md b/CHANGELOG.md index 98fac0b9a..3fbde7627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Enable better GPIO internal resistor configuration ([#189]) - Support for GPIO output slew rate configuration ([#189]) - Support for GPIO interrupts ([#189]) +- `ld` feature, which enables the memory.x generation ([#216]) ### Changed @@ -26,6 +27,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Delay based on systick no longer panics ([#203]) for to high values and support longer delays ([#208]) +- Long delay during ADC initialization ([#217]) ### Breaking Changes @@ -35,6 +37,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). If the supplied frequency cannot be converted to `Hertz` the code will `panic`. This will occur if the supplied `Megahertz` frequency cannot fit into `u32::MAX` when converting to `Hertz` ([#192]) +- You always required to select a sub-target for target chips ([#216]) ```rust // The supplied frequencies must be in `MHz`. @@ -313,6 +316,8 @@ let clocks = rcc [defmt]: https://github.com/knurling-rs/defmt [filter]: https://defmt.ferrous-systems.com/filtering.html +[#217]: https://github.com/stm32-rs/stm32f3xx-hal/pull/217 +[#216]: https://github.com/stm32-rs/stm32f3xx-hal/pull/216 [#211]: https://github.com/stm32-rs/stm32f3xx-hal/pull/211 [#210]: https://github.com/stm32-rs/stm32f3xx-hal/pull/210 [#208]: https://github.com/stm32-rs/stm32f3xx-hal/pull/208 diff --git a/Cargo.toml b/Cargo.toml index 5580fb72f..906542e7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,7 +90,7 @@ gpio-f303e = [] gpio-f333 = [] gpio-f373 = [] -# Any changes here should be mirrored in README.md, src/lib.rs, and +# Any changes here should be mirrored in README.md, build.rs, src/lib.rs, and # .github/workflows/ci.yml. stm32f301 = ["svd-f301", "direct-call-deprecated"] stm32f301x6 = ["stm32f301", "mem-6", "gpio-f302", "device-selected"] diff --git a/README.md b/README.md index c144d4e3f..a913e62f0 100644 --- a/README.md +++ b/README.md @@ -38,20 +38,50 @@ Almost all of the implementation was shamelessly adapted from the [`stm32f30x-hal`]: https://github.com/japaric/stm32f30x-hal [`embedded-hal`]: https://github.com/japaric/embedded-hal -## [Changelog](CHANGELOG.md) +## Getting Started + +### Adding stm32f3xx-hal and other dependencies + +Cargo.toml: + +```toml +[dependencies] +cortex-m = "0.7.2" +cortex-m-rt = { version = "0.6.13", features = ["device"] } +# Panic behaviour, see https://crates.io/keywords/panic-impl for alternatives +panic-halt = "0.2.0" +# Replace stm32f303xc with your target chip, see next section for more info +stm32f3xx-hal = { version = "0.7.0", features = ["ld", "rt", "stm32f303xc"] } +``` + +We also need to tell Rust about target architecture and how to link our +executable by creating `.cargo/config`. -## Selecting the right chip +.cargo/config: + +```toml +[target.thumbv7em-none-eabihf] +rustflags = [ + "-C", "link-arg=-Tlink.x", +] + +[build] +target = "thumbv7em-none-eabihf" +``` + +### Selecting the right chip This crate requires you to specify your target chip as a feature. -*Example: The STM32F3Discovery board has a STM32F303VCT6 chip. -So you want to expand your call to `cargo` with `--features stm32f303xc`.* +*Example: The STM32F3Discovery board has a STM32F303VCT6 chip according to the +[user manual][]. So you need to specify `stm32f303xc` in your `Cargo.toml` +(note that VC → xc).* -### Possible chips +#### Possible chips [comment]: # (Any changes here should be mirrored in src/lib.rs) -Note: `x` denotes any character in [a-z] +Please select one of the following (`x` denotes any character in [a-z]): * stm32f301x6 * stm32f301x8 @@ -79,7 +109,7 @@ Note: `x` denotes any character in [a-z] * stm32f334x6 * stm32f334x8 -### Background +#### Background For some of the stm32f3xx chips there are sub-variants that differ in functionality, peripheral use and hence 'under the hood' implementation. To @@ -87,43 +117,40 @@ allow the full use of all peripherals on certain subvariants without allowing for code that just doesn't run on other sub-vairants, they are distinct features that need to be specified. -As this crate is still under fundamental development, expect more -sub-variants replacing the plain variants in the future as we are -implementing more stuff. It is not desired to allow the plain variants to -be used as this leads to confusion. -*Example: the stm32f303xc has a gpio_e bank while the stm32f303x6 does -not. Hence we don't want to expose the gpoio_e bank on all stm32f303 (i.e. -when specifying the feature stm32f303) albeit a stm32f303xc user would -expect it to do so.* - -### Detailed steps to select the right chip - -1. Get the full name of the chip you are using from your datasheet, user manual - or other source. +[user manual]: https://www.st.com/content/ccc/resource/technical/document/user_manual/8a/56/97/63/8d/56/41/73/DM00063382.pdf/files/DM00063382.pdf/jcr:content/translations/en.DM00063382.pdf - _Example_: +### Basic Usage - We want to use the STM32F3Discovery kit. - The [Usermanual][] tells us it's using a STM32F303VC chip. +```rust +#![no_std] +#![no_main] -2. Find your chip as a feature in the list above. +use cortex_m::asm; +use cortex_m_rt::entry; +use panic_halt as _; +use stm32f3xx_hal::{self as hal, pac, prelude::*}; - _Example_: +#[entry] +fn main() -> ! { + let dp = pac::Peripherals::take().unwrap(); - Looking for the right feature for our STM32F303VC chip we first find - `stm32f301xb`. This is the wrong chip, as we're not looking for `f301` but - for `f303`. + let mut rcc = dp.RCC.constrain(); + let mut gpioe = dp.GPIOE.split(&mut rcc.ahb); - Looking further we find `stm32f303xc`. This matches STM32F303VC - (note that VC → xc). + let mut led = gpioe + .pe13 + .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper); -3. Add the chip name as a feature to your cargo call. - - _Example_: + loop { + led.toggle().unwrap(); + asm::delay(8_000_000); + } +} +``` - Using the STM32F303VC chip we run `cargo check --features stm32f303xc`. +See the [examples folder](examples) for more example programs. -[Usermanual]: https://www.st.com/content/ccc/resource/technical/document/user_manual/8a/56/97/63/8d/56/41/73/DM00063382.pdf/files/DM00063382.pdf/jcr:content/translations/en.DM00063382.pdf +## [Changelog](CHANGELOG.md) ## Minimum Supported Rust Version (MSRV) diff --git a/build.rs b/build.rs index 1cb4d54e3..3be804879 100644 --- a/build.rs +++ b/build.rs @@ -1,55 +1,124 @@ use std::{env, fs::File, io::prelude::*, path::PathBuf}; fn main() { + check_device_feature(); if cfg!(feature = "ld") { gen_memory_x(); } println!("cargo:rerun-if-changed=build.rs"); } +/// Check device feature selection +fn check_device_feature() { + if !cfg!(feature = "device-selected") { + if cfg!(feature = "direct-call-deprecated") { + eprintln!( + "The feature you selected is deprecated, because it was split up into sub-devices. + +Example: The STM32F3Discovery board has a STM32F303VCT6 chip. +You probably used to use `stm32f303` but now functionalities for the sub-device were added. +In this case replace it with `stm32f303xc` to make your code build again. + +For more information, see \x1b]8;;https://github.com/stm32-rs/stm32f3xx-hal#selecting-the-right-chip\x1b\\README -> Selecting the right chip\x1b]8;;\x1b\\." + ); + } else { + eprintln!( + "This crate requires you to specify your target chip as a feature. + +Please select one of the following (`x` denotes any character in [a-z]): + + stm32f301x6 stm32f301x8 + stm32f318x8 + stm32f302x6 stm32f302x8 stm32f302xb stm32f302xc stm32f302xd stm32f302xe + stm32f303x6 stm32f303x8 stm32f303xb stm32f303xc stm32f303xd stm32f303xe + stm32f328x8 + stm32f358xc + stm32f398xe + stm32f373x8 stm32f373xb stm32f373xc + stm32f378xc + stm32f334x4 stm32f334x6 stm32f334x8 + +Example: The STM32F3Discovery board has a STM32F303VCT6 chip. +So you need to specify stm32f303xc in your Cargo.toml (note that VC → xc). + +For more information, see \x1b]8;;https://github.com/stm32-rs/stm32f3xx-hal#selecting-the-right-chip\x1b\\README -> Selecting the right chip\x1b]8;;\x1b\\." + ); + } + std::process::exit(1); + } +} + +/// Generate `memory.x` for selected device +/// +/// Available RAM/CCMRAM/FLASH value is extracted from RM0313/RM0316/RM0364/RM0365/RM0366 fn gen_memory_x() { - #![allow(clippy::unneeded_wildcard_pattern)] + enum Mem { + _4, + _6, + _8, + B, + C, + D, + E, + } + + let mem = if cfg!(feature = "mem-4") { + Mem::_4 + } else if cfg!(feature = "mem-6") { + Mem::_6 + } else if cfg!(feature = "mem-8") { + Mem::_8 + } else if cfg!(feature = "mem-b") { + Mem::B + } else if cfg!(feature = "mem-c") { + Mem::C + } else if cfg!(feature = "mem-d") { + Mem::D + } else if cfg!(feature = "mem-e") { + Mem::E + } else { + eprintln!( + "Memory size unknown. +This may be due to incorrect feature configuration in Cargo.toml or stm32f3xx-hal's internal issue." + ); + std::process::exit(1); + }; - let mem_cfg_set = ( - cfg!(feature = "mem-4"), - cfg!(feature = "mem-6"), - cfg!(feature = "mem-8"), - cfg!(feature = "mem-b"), - cfg!(feature = "mem-c"), - cfg!(feature = "mem-d"), - cfg!(feature = "mem-e"), - ); - let flash = match mem_cfg_set { - (true, ..) => 16, - (_, true, ..) => 32, - (_, _, true, ..) => 64, - (.., true, _, _, _) => 128, - (.., _, true, _, _) => 256, - (.., _, _, true, _) => 384, - (.., _, _, _, true) => 512, - _ => unreachable!(), + let flash = match mem { + Mem::_4 => 16, + Mem::_6 => 32, + Mem::_8 => 64, + Mem::B => 128, + Mem::C => 256, + Mem::D => 384, + Mem::E => 512, }; let ccmram = if cfg!(feature = "svd-f303") || cfg!(feature = "svd-f3x4") { - match mem_cfg_set { - (true, ..) | (_, true, ..) | (_, _, true, ..) => 4, - (.., true, _, _, _) | (.., _, true, _, _) => 8, - (.., _, _, true, _) | (.., _, _, _, true) => 16, - _ => unreachable!(), + match mem { + Mem::_4 | Mem::_6 | Mem::_8 => 4, + Mem::B | Mem::C => 8, + Mem::D | Mem::E => 16, } } else { 0 }; - let ram = match mem_cfg_set { - (true, ..) | (_, true, ..) | (_, _, true, ..) => 16, - (.., true, _, _, _) if cfg!(feature = "svd-f373") => 24, - (.., true, _, _, _) if cfg!(feature = "svd-f302") => 32, - (.., _, true, _, _) if cfg!(feature = "svd-f373") => 32, - (.., true, _, _, _) if cfg!(feature = "svd-f303") => 40, - (.., _, true, _, _) if cfg!(feature = "svd-f302") => 40, - (.., _, true, _, _) if cfg!(feature = "svd-f303") => 48, - (.., _, _, true, _) | (.., _, _, _, true) if cfg!(feature = "svd-f302") => 64, - (.., _, _, true, _) | (.., _, _, _, true) if cfg!(feature = "svd-f303") => 80, - _ => unreachable!(), + let ram = match mem { + Mem::_4 | Mem::_6 | Mem::_8 => 16, + Mem::B if cfg!(feature = "svd-f373") => 24, + Mem::B if cfg!(feature = "svd-f302") => 32, + Mem::C if cfg!(feature = "svd-f373") => 32, + Mem::B if cfg!(feature = "svd-f303") => 40, + Mem::C if cfg!(feature = "svd-f302") => 40, + Mem::C if cfg!(feature = "svd-f303") => 48, + Mem::D | Mem::E if cfg!(feature = "svd-f302") => 64, + Mem::D | Mem::E if cfg!(feature = "svd-f303") => 80, + _ => { + eprintln!( + "Memory size unknown. +This may be due to incorrect feature configuration in Cargo.toml or stm32f3xx-hal's internal issue." + ); + std::process::exit(1); + }, } - ccmram; let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); diff --git a/src/lib.rs b/src/lib.rs index a8ba53d39..88457c6d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,49 +2,72 @@ # stm32f3xx-hal `stm32f3xx-hal` contains a multi device hardware abstraction on top of the - peripheral access API for the STMicro [STM32F3][stm] series microcontrollers. The - selection of the MCU is done by [feature][f] gates + peripheral access API for the STMicro [STM32F3][stm] series microcontrollers. - [f]: #selecting-the-right-chip [stm]: https://www.st.com/en/microcontrollers-microprocessors/stm32f3-series.html - # Selecting the right chip - - This crate requires you to specify your target chip as a feature. - - Please select one of the following - - (Note: `x` denotes any character in [a-z]) - * stm32f301x6 - * stm32f301x8 - * stm32f318x8 - * stm32f302x6 - * stm32f302x8 - * stm32f302xb - * stm32f302xc - * stm32f302xd - * stm32f302xe - * stm32f303x6 - * stm32f303x8 - * stm32f303xb - * stm32f303xc - * stm32f303xd - * stm32f303xe - * stm32f328x8 - * stm32f358xc - * stm32f398xe - * stm32f373x8 - * stm32f373xb - * stm32f373xc - * stm32f378xc - * stm32f334x4 - * stm32f334x6 - * stm32f334x8 - - Example: The STM32F3Discovery board has a STM32F303VCT6 chip. - So you want to expand your call to `cargo` with `--features stm32f303xc`. - - For more information, see the [README](https://github.com/stm32-rs/stm32f3xx-hal/blob/master/README.md#selecting-the-right-chip) + ## Cargo features + + ### Target chip selection + + This crate requires you to specify your target chip as a feature. + + Please select one of the following (`x` denotes any character in [a-z]): + + * stm32f301x6 + * stm32f301x8 + * stm32f318x8 + * stm32f302x6 + * stm32f302x8 + * stm32f302xb + * stm32f302xc + * stm32f302xd + * stm32f302xe + * stm32f303x6 + * stm32f303x8 + * stm32f303xb + * stm32f303xc + * stm32f303xd + * stm32f303xe + * stm32f328x8 + * stm32f358xc + * stm32f398xe + * stm32f373x8 + * stm32f373xb + * stm32f373xc + * stm32f378xc + * stm32f334x4 + * stm32f334x6 + * stm32f334x8 + + Example: The STM32F3Discovery board has a STM32F303VCT6 chip. + So you need to specify `stm32f303xc` in your `Cargo.toml` (note that VC → xc). + + For more information, see the [README][]. + + [README]: https://github.com/stm32-rs/stm32f3xx-hal/blob/master/README.md#selecting-the-right-chip + + ### ld + + When this feature is enabled the `memory.x` linker script for target chip is automatically + provided by this crate. See [`cortex-m-rt` document][memoryx] for more info. + + [memoryx]: https://docs.rs/cortex-m-rt/0.6.13/cortex_m_rt/#memoryx + + ### rt + + This feature enables [`stm32f3`][]'s `rt` feature. See [`cortex-m-rt` document][device] for more info. + + [`stm32f3`]: https://crates.io/crates/stm32f3 + [device]: https://docs.rs/cortex-m-rt/0.6.13/cortex_m_rt/#device + + ### can + + Enable CAN peripherals on supported targets. + + ### stm32-usbd + + Enable USB peripherals on supported targets. */ #![no_std] #![allow(non_camel_case_types)] @@ -52,177 +75,114 @@ #![warn(missing_docs)] #![deny(macro_use_extern_crate)] -#[cfg(all(feature = "direct-call-deprecated", not(feature = "device-selected")))] -compile_error!( - "The feature you selected is deprecated, because it was split up into sub-devices. - - Example: The STM32F3Discovery board has a STM32F303VCT6 chip. - You probably used to use `--features stm32f303` but now functionalities for the sub-device were added. - In this case replace it with `--features stm32f303xc` to make your code build again. - - Please select one of the chip features stated above." -); +use cfg_if::cfg_if; -// TODO Remove because, as of stm32f3 v0.12, this will be caught by it's build.rs? +pub use embedded_hal as hal; + +pub use nb; +pub use nb::block; + +pub use embedded_time as time; + +/// Peripheral access +#[cfg(feature = "svd-f301")] +pub use stm32f3::stm32f301 as pac; + +/// Peripheral access +#[cfg(feature = "svd-f302")] +pub use stm32f3::stm32f302 as pac; + +/// Peripheral access +#[cfg(feature = "svd-f303")] +pub use stm32f3::stm32f303 as pac; + +/// Peripheral access +#[cfg(feature = "svd-f373")] +pub use stm32f3::stm32f373 as pac; + +/// Peripheral access +#[cfg(feature = "svd-f3x4")] +pub use stm32f3::stm32f3x4 as pac; + +/// Peripheral access +#[deprecated(since = "0.5.0", note = "please use `pac` instead")] +pub use crate::pac as stm32; + +// Enable use of interrupt macro +#[cfg(feature = "rt")] +pub use crate::pac::interrupt; + +#[cfg(feature = "stm32f303")] +pub mod adc; +#[cfg(feature = "can")] +pub mod can; +pub mod delay; +#[cfg(any(feature = "stm32f302", feature = "stm32f303"))] +pub mod dma; +pub mod flash; +pub mod gpio; +pub mod i2c; +pub mod prelude; +pub mod pwm; +pub mod rcc; +pub mod rtc; +pub mod serial; +pub mod spi; +pub mod syscfg; +pub mod timer; #[cfg(all( - not(feature = "direct-call-deprecated"), - not(feature = "device-selected") + feature = "stm32-usbd", + any( + feature = "stm32f303xb", + feature = "stm32f303xc", + feature = "stm32f303xd", + feature = "stm32f303xe", + ), ))] -compile_error!( - "This crate requires you to specify your target chip as a feature. - - Please select one of the following - - (Note: `x` denotes any character in [a-z]) - * stm32f301x6 - * stm32f301x8 - * stm32f318x8 - * stm32f302x6 - * stm32f302x8 - * stm32f302xb - * stm32f302xc - * stm32f302xd - * stm32f302xe - * stm32f303x6 - * stm32f303x8 - * stm32f303xb - * stm32f303xc - * stm32f303xd - * stm32f303xe - * stm32f328x8 - * stm32f358xc - * stm32f398xe - * stm32f373x8 - * stm32f373xb - * stm32f373xc - * stm32f378xc - * stm32f334x4 - * stm32f334x6 - * stm32f334x8 - - Example: The STM32F3Discovery board has a STM32F303VCT6 chip. - So you want to expand your call to `cargo` with `--features stm32f303xc`. - - For more information, see README -> Selecting the right chip. - " -); - -use cfg_if::cfg_if; +pub mod usb; +pub mod watchdog; cfg_if! { - if #[cfg(feature = "device-selected")] { - pub use embedded_hal as hal; - - pub use nb; - pub use nb::block; - - pub use embedded_time as time; - - /// Peripheral access - #[cfg(feature = "svd-f301")] - pub use stm32f3::stm32f301 as pac; - - /// Peripheral access - #[cfg(feature = "svd-f302")] - pub use stm32f3::stm32f302 as pac; - - /// Peripheral access - #[cfg(feature = "svd-f303")] - pub use stm32f3::stm32f303 as pac; - - /// Peripheral access - #[cfg(feature = "svd-f373")] - pub use stm32f3::stm32f373 as pac; - - /// Peripheral access - #[cfg(feature = "svd-f3x4")] - pub use stm32f3::stm32f3x4 as pac; - - /// Peripheral access - #[deprecated(since = "0.5.0", note = "please use `pac` instead")] - pub use crate::pac as stm32; - - // Enable use of interrupt macro - #[cfg(feature = "rt")] - pub use crate::pac::interrupt; - - #[cfg(feature = "stm32f303")] - pub mod adc; - #[cfg(feature = "can")] - pub mod can; - pub mod delay; - #[cfg(any(feature = "stm32f302", feature = "stm32f303"))] - pub mod dma; - pub mod flash; - pub mod gpio; - pub mod i2c; - pub mod prelude; - pub mod pwm; - pub mod rcc; - pub mod rtc; - pub mod serial; - pub mod spi; - pub mod syscfg; - pub mod timer; - #[cfg(all( - feature = "stm32-usbd", - any( - feature = "stm32f303xb", - feature = "stm32f303xc", - feature = "stm32f303xd", - feature = "stm32f303xe", - ), - ))] - pub mod usb; - pub mod watchdog; - - cfg_if! { - if #[cfg(feature = "defmt")] { - pub(crate) use defmt::{assert, panic, unreachable, unwrap}; - pub(crate) use macros::expect; - - mod macros { - #![allow(clippy::single_component_path_imports)] - - /// Wrapper function for `.expect()` - /// - /// Uses [`defmt::unwrap!`] instead, because - /// it has the same functionality as `expect()` - macro_rules! expect { - ($l:expr, $s:tt) => { - defmt::unwrap!($l, $s) - }; - } - pub(crate) use expect; - } - } else { - pub(crate) use core::{assert, panic, unreachable}; - pub(crate) use macros::{unwrap, expect}; - - mod macros { - #![allow(clippy::single_component_path_imports)] - - /// Wrapper macro for `.unwrap()` - /// - /// Uses core function, when defmt feature is not active - macro_rules! unwrap { - ($l:expr) => { - $l.unwrap() - }; - } - pub(crate) use unwrap; - - /// Wrapper macro for `.expect()` - /// - /// Uses core function, when defmt feature is not active - macro_rules! expect { - ($l:expr, $s:tt) => { - $l.expect($s) - }; - } - pub(crate) use expect; - } + if #[cfg(feature = "defmt")] { + pub(crate) use defmt::{assert, panic, unreachable, unwrap}; + pub(crate) use macros::expect; + + mod macros { + /// Wrapper function for `.expect()` + /// + /// Uses [`defmt::unwrap!`] instead, because + /// it has the same functionality as `expect()` + macro_rules! expect_wrapper { + ($l:expr, $s:tt) => { + defmt::unwrap!($l, $s) + }; + } + pub(crate) use expect_wrapper as expect; + } + } else { + pub(crate) use core::{assert, panic, unreachable}; + pub(crate) use macros::{unwrap, expect}; + + mod macros { + /// Wrapper macro for `.unwrap()` + /// + /// Uses core function, when defmt feature is not active + macro_rules! unwrap_wrapper { + ($l:expr) => { + $l.unwrap() + }; + } + pub(crate) use unwrap_wrapper as unwrap; + + /// Wrapper macro for `.expect()` + /// + /// Uses core function, when defmt feature is not active + macro_rules! expect_wrapper { + ($l:expr, $s:tt) => { + $l.expect($s) + }; } + pub(crate) use expect_wrapper as expect; } } }