From e19f7d9a76fa13012b6c606167a6a8f215875a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Fri, 18 Aug 2023 00:01:13 +0200 Subject: [PATCH 001/233] Add embassy-net-adin1110 This add a library for Analog ADIN1110 SPE SPI chip. This library is inspired by `embassy-net-w5500`. --- embassy-net-adin1110/.gitignore | 1 + embassy-net-adin1110/.vscode/settings.json | 8 + embassy-net-adin1110/Cargo.toml | 41 + embassy-net-adin1110/README.md | 55 + embassy-net-adin1110/rust-toolchain.toml | 3 + embassy-net-adin1110/src/crc32.rs | 101 ++ embassy-net-adin1110/src/crc8.rs | 53 + embassy-net-adin1110/src/lib.rs | 1246 ++++++++++++++++++++ embassy-net-adin1110/src/mdio.rs | 174 +++ embassy-net-adin1110/src/phy.rs | 137 +++ embassy-net-adin1110/src/regs.rs | 407 +++++++ 11 files changed, 2226 insertions(+) create mode 100644 embassy-net-adin1110/.gitignore create mode 100644 embassy-net-adin1110/.vscode/settings.json create mode 100644 embassy-net-adin1110/Cargo.toml create mode 100644 embassy-net-adin1110/README.md create mode 100644 embassy-net-adin1110/rust-toolchain.toml create mode 100644 embassy-net-adin1110/src/crc32.rs create mode 100644 embassy-net-adin1110/src/crc8.rs create mode 100644 embassy-net-adin1110/src/lib.rs create mode 100644 embassy-net-adin1110/src/mdio.rs create mode 100644 embassy-net-adin1110/src/phy.rs create mode 100644 embassy-net-adin1110/src/regs.rs diff --git a/embassy-net-adin1110/.gitignore b/embassy-net-adin1110/.gitignore new file mode 100644 index 00000000..c41cc9e3 --- /dev/null +++ b/embassy-net-adin1110/.gitignore @@ -0,0 +1 @@ +/target \ No newline at end of file diff --git a/embassy-net-adin1110/.vscode/settings.json b/embassy-net-adin1110/.vscode/settings.json new file mode 100644 index 00000000..daa2ccf0 --- /dev/null +++ b/embassy-net-adin1110/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "rust-analyzer.check.command": "clippy", + "rust-analyzer.showUnlinkedFileNotification": false, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + "editor.formatOnSave": true + } +} \ No newline at end of file diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml new file mode 100644 index 00000000..e74fb7cd --- /dev/null +++ b/embassy-net-adin1110/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "embassy-net-adin1110" +version = "0.1.0" +description = "embassy-net driver for the ADIN1110 ethernet chip" +keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet", "async"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +license = "MIT OR Apache-2.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +heapless = "0.7.16" +defmt = { version = "0.3", optional = true } +log = { version = "0.4.4", default-features = false, optional = true } +embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } +embedded-hal-async = { version = "=1.0.0-rc.1" } +embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] } +embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } +embassy-time = { version = "0.1.0" } +embassy-futures = { version = "0.1.0", path = "../embassy-futures" } +bitfield = "0.14.0" + + +[dev-dependencies] +# reenable when https://github.com/dbrgn/embedded-hal-mock/pull/86 is merged. +#embedded-hal-mock = { git = "https://github.com/dbrgn/embedded-hal-mock", branch = "1-alpha", features = ["embedded-hal-async", "eh1"] }] } +embedded-hal-mock = { git = "https://github.com/newAM/embedded-hal-mock", branch = "eh1-rc.1", features = ["embedded-hal-async", "eh1"] } +crc = "3.0.1" +env_logger = "0.10" +critical-section = { version = "1.1.1", features = ["std"] } +futures-test = "0.3.17" + +[features] +default = [ ] +defmt = [ "dep:defmt" ] + +[package.metadata.embassy_docs] +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-adin1110-v$VERSION/embassy-net-adin1110/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-adin1110/src/" +target = "thumbv7em-none-eabi" diff --git a/embassy-net-adin1110/README.md b/embassy-net-adin1110/README.md new file mode 100644 index 00000000..9b7b4e0e --- /dev/null +++ b/embassy-net-adin1110/README.md @@ -0,0 +1,55 @@ +# SPE ADIN1110 `embassy-net` integration + +[`embassy-net`](https://crates.io/crates/embassy-net) integration for the `Analog ADIN1110` SPI SPE ethernet chips. + +## What is SPE or Single Pair Ethernet / 10 BASE-T1L + +SPE is Single Pair Ethernet, what the names implies, it uses a single twisted/differancial pair (only 2 wires) to transmit ethernet packet in full-duplex. +SPE is still ethernet, only the phissical layer is different. + +SPE also supports [`PoDL(Power over Data Line)`](https://www.ti.com/lit/an/snla395/snla395.pdf), power delivery from 0.5 up to 50 Watts, similair to [`PoE`](https://en.wikipedia.org/wiki/Power_over_Ethernet), but additional hardware and handshake protocol is needed. + +SPE has many link speeds but only `10 BASE-T1L` is able to reach cable length up to 1000 meters in `2.4 Vpp` transmit amplitude. +Currently in 2023, none of the standards are compatiable with eachother. +So `10 BASE-T1L` don't work with a `10 BASE-T1S` or `100 BASE-T1`. + +In the industry SPE is also called [`APL(Advanced Physical Layer)`](https://www.ethernet-apl.org), it is based on the `10 BASE-T1L` standard. + +APL can be use in [`intrinsic safety applications/explosion hazardous areas`](https://en.wikipedia.org/wiki/Electrical_equipment_in_hazardous_areas) which has it's own name and standard [`2-WISE(2-wire intrinsically safe ethernet) IEC TS 60079-47:2021`](https://webstore.iec.ch/publication/64292). + +`10 BASE-T1L` and `ADIN1110` are designed to support intrinsic safety applications. The power supply energy is fixed and PDoL is not supported. + +## Supported SPI modes + +`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf) + +Both modes support with and without additional CRC. +Currently only `Generic` SPI with or without CRC is supported. + +*NOTE:* SPI Mode is selected by the hardware pins `SPI_CFG0` and `SPI_CFG1`. Software can't detect nor change the mode. + +## Hardware + +- Testen on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with a `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) example. +- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit`](https://www.sparkfun.com/products/19628), the kit supports multiple microcontrollers, please check if get the right microcontroller that is supported by Embassy! + +## Other SPE chips + +* [`Analog ADIN2111`](https://www.analog.com/en/products/adin2111.html) 2 Port SPI version. Can work with this driver. +* [`Analog ADIN1100`](https://www.analog.com/en/products/adin1100.html) RGMII version. + +## Testing + +ADIN1110 library can tested on the host with a mock SPI driver + +$ `cargo test --target x86_64-unknown-linux-gnu` + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. diff --git a/embassy-net-adin1110/rust-toolchain.toml b/embassy-net-adin1110/rust-toolchain.toml new file mode 100644 index 00000000..d5f51a7f --- /dev/null +++ b/embassy-net-adin1110/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly" +components = [ "rustfmt", "rustc-dev" ] diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs new file mode 100644 index 00000000..75a7d65b --- /dev/null +++ b/embassy-net-adin1110/src/crc32.rs @@ -0,0 +1,101 @@ +pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, + 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, + 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, + 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, + 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, + 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, + 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, + 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, + 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, + 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, + 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, + 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, + 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, + 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, + 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +]; + +#[allow(non_camel_case_types)] +#[derive(Debug)] +pub struct ETH_FSC(pub u32); + +impl ETH_FSC { + pub const CRC32_OK: u32 = 0x2144df1c; + + pub fn new(data: &[u8]) -> Self { + let fsc = data.iter().fold(u32::MAX, |crc, byte| { + let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte; + CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8) + }) ^ u32::MAX; + Self(fsc) + } + + pub fn crc_ok(&self) -> bool { + self.0 == Self::CRC32_OK + } + + pub fn hton_bytes(&self) -> [u8; 4] { + self.0.to_le_bytes() + } + + pub fn hton(&self) -> u32 { + self.0.to_le() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn crc32_ethernet_frame() { + let packet_a = &[ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xff, 0x06, 0x00, 0x01, 0x08, 0x00, + 0x06, 0x04, 0x00, 0x01, 0x00, 0xe0, 0x4c, 0x68, 0x0e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xa8, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x65, 0x90, 0x3d, + ]; + + let packet_b = &[ + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xdd, 0x06, 0x00, 0x01, 0x08, 0x00, + 0x06, 0x04, 0x00, 0x02, 0x00, 0xe0, 0x4c, 0x68, 0x09, 0xde, 0xc0, 0xa8, 0x01, 0x02, 0x12, 0x34, 0x56, 0x78, + 0x9a, 0xbc, 0xc0, 0xa8, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x3d, 0x67, 0x7c, + ]; + + // Packet A + let own_crc = ETH_FSC::new(&packet_a[0..60]); + let crc_bytes = own_crc.hton_bytes(); + println!("{:08x} {:02x?}", own_crc.0, crc_bytes); + assert_eq!(&crc_bytes, &packet_a[60..64]); + + let own_crc = ETH_FSC::new(packet_a); + println!("{:08x}", own_crc.0); + assert_eq!(own_crc.0, ETH_FSC::CRC32_OK); + + // Packet B + let own_crc = ETH_FSC::new(&packet_b[0..60]); + let crc_bytes = own_crc.hton_bytes(); + println!("{:08x} {:02x?}", own_crc.0, crc_bytes); + assert_eq!(&crc_bytes, &packet_b[60..64]); + + let own_crc = ETH_FSC::new(packet_b); + println!("{:08x}", own_crc.0); + assert_eq!(own_crc.0, ETH_FSC::CRC32_OK); + } +} diff --git a/embassy-net-adin1110/src/crc8.rs b/embassy-net-adin1110/src/crc8.rs new file mode 100644 index 00000000..7d20a740 --- /dev/null +++ b/embassy-net-adin1110/src/crc8.rs @@ -0,0 +1,53 @@ +/// CRC-8/ITU +const CRC8X_TABLE: [u8; 256] = [ + 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, + 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, + 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, + 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, + 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, + 0x9a, 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, + 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80, 0x95, + 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, + 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, + 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, + 0x33, 0x34, 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, 0x3e, + 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7, + 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, + 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3, +]; + +/// Calculate the crc of a pease of data. +pub fn crc8(data: &[u8]) -> u8 { + data.iter().fold(0, |crc, &byte| CRC8X_TABLE[usize::from(byte ^ crc)]) +} + +#[cfg(test)] +mod tests { + use ::crc::{Crc, CRC_8_SMBUS}; + + use super::crc8; + + #[test] + fn spi_header_crc8() { + let data = &[0x80, 0x00]; + + let c = Crc::::new(&CRC_8_SMBUS); + let mut dig = c.digest(); + dig.update(data); + let sw_crc = dig.finalize(); + + let own_crc = crc8(data); + + assert_eq!(own_crc, sw_crc); + assert_eq!(own_crc, 182); + + let data = &[0x80, 0x01]; + let mut dig = c.digest(); + dig.update(data); + let sw_crc = dig.finalize(); + let own_crc = crc8(data); + + assert_eq!(own_crc, sw_crc); + assert_eq!(own_crc, 177); + } +} diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs new file mode 100644 index 00000000..a4010d25 --- /dev/null +++ b/embassy-net-adin1110/src/lib.rs @@ -0,0 +1,1246 @@ +#![allow(clippy::pedantic)] +#![feature(type_alias_impl_trait)] +#![feature(async_fn_in_trait)] +#![cfg_attr(not(any(test, feature = "std")), no_std)] + +use ch::driver::LinkState; +use embassy_futures::select::{select, Either}; +use embassy_net_driver_channel as ch; +use embassy_time::{Duration, Timer}; +use embedded_hal_1::digital::OutputPin; +use embedded_hal_async::digital::Wait; +use embedded_hal_async::spi::{Operation, SpiDevice}; +use heapless::Vec; + +mod crc32; +mod crc8; +mod mdio; +mod phy; +mod regs; + +pub use crc32::ETH_FSC; +use crc8::crc8; +pub use mdio::MdioBus; +pub use phy::{Phy10BaseT1x, RegsC22, RegsC45}; +pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1}; + +use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader}; + +pub const PHYID: u32 = 0x0283BC91; + +/// Error values ADIN1110 +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[allow(non_camel_case_types)] +pub enum AdinError { + Spi(E), + SENDERROR, + READERROR, + CRC, + PACKET_TOO_BIG, + PACKET_TOO_SMALL, + MDIO_ACC_TIMEOUT, +} + +pub type AEResult = core::result::Result>; +pub const MDIO_PHY_ADDR: u8 = 0x01; +pub const MTU: usize = 1500; +/// Max SPI/Frame buffer size +pub const MAX_BUFF: usize = 2048; + +const DONT_CARE_BYTE: u8 = 0x00; +const TURN_AROUND_BYTE: u8 = 0x00; + +const FEC_LEN: usize = 4; +const FRAME_HEADER_LEN: usize = 2; +const WR_HEADER_LEN: usize = 2; + +// P1 = 0x00, P2 = 0x01 +const PORT_ID_BYTE: u8 = 0x00; + +pub type Packet = Vec; + +/// Type alias for the embassy-net driver for ADIN1110 +pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; + +/// Internal state for the embassy-net integration. +pub struct State { + ch_state: ch::State, +} +impl State { + /// Create a new `State`. + pub const fn new() -> Self { + Self { + ch_state: ch::State::new(), + } + } +} + +#[derive(Debug)] +pub struct ADIN1110 { + /// SPI bus + spi: SPI, + /// Enable CRC on SPI transfer. + /// This must match with the hardware pin SPI_CFG0 were 0 = CRC enable, 1 CRC disabled. + crc: bool, +} + +// Round size up the N u32; +pub(crate) fn size_align_u32(size: u32) -> u32 { + (size + 3) & 0xFFFF_FFFC +} + +impl ADIN1110 +where + SPI: SpiDevice, + SpiE: core::fmt::Debug, +{ + pub fn new(spi: SPI, crc: bool) -> Self { + Self { spi, crc } + } + + pub async fn read_reg(&mut self, reg: sr) -> AEResult { + let mut tx_buf = Vec::::new(); + + let mut spi_hdr = SpiHeader(0); + spi_hdr.set_control(true); + spi_hdr.set_addr(reg); + let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); + + if self.crc { + // Add CRC for header data + let _ = tx_buf.push(crc8(&tx_buf)); + } + + // Turn around byte, TODO: Unknown that this is. + let _ = tx_buf.push(TURN_AROUND_BYTE); + + let mut rx_buf = [0; 5]; + + let spi_read_len = if self.crc { rx_buf.len() } else { rx_buf.len() - 1 }; + + let mut spi_op = [Operation::Write(&tx_buf), Operation::Read(&mut rx_buf[0..spi_read_len])]; + + self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; + + if self.crc { + let crc = crc8(&rx_buf[0..4]); + if crc != rx_buf[4] { + return Err(AdinError::CRC); + } + } + + let value = u32::from_be_bytes(rx_buf[0..4].try_into().unwrap()); + + #[cfg(feature = "defmt")] + defmt::trace!("REG Read {} = {:08x} SPI {:02x}", reg, value, &tx_buf); + + Ok(value) + } + + pub async fn write_reg(&mut self, reg: sr, value: u32) -> AEResult<(), SpiE> { + let mut tx_buf = Vec::::new(); + + let mut spi_hdr = SpiHeader(0); + spi_hdr.set_control(true); + spi_hdr.set_write(true); + spi_hdr.set_addr(reg); + let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); + + if self.crc { + // Add CRC for header data + let _ = tx_buf.push(crc8(&tx_buf)); + } + + let val = value.to_be_bytes(); + let _ = tx_buf.extend_from_slice(val.as_slice()); + + if self.crc { + // Add CRC for header data + let _ = tx_buf.push(crc8(val.as_slice())); + } + + #[cfg(feature = "defmt")] + defmt::trace!("REG Write {} = {:08x} SPI {:02x}", reg, value, &tx_buf); + + self.spi.write(&tx_buf).await.map_err(AdinError::Spi) + } + + // helper function for write to MDIO_ACC register and wait for ready! + async fn write_mdio_acc_reg(&mut self, mdio_acc_val: u32) -> AEResult { + self.write_reg(sr::MDIO_ACC, mdio_acc_val).await?; + + // TODO: Add proper timeout! + for _ in 0..100_000 { + let val = self.read_reg(sr::MDIO_ACC).await?; + if val & 0x8000_0000 != 0 { + return Ok(val); + } + } + + Err(AdinError::MDIO_ACC_TIMEOUT) + } + + pub async fn read_fifo(&mut self, packet: &mut [u8]) -> AEResult { + let mut tx_buf = Vec::::new(); + + // Size of the frame, also includes the appednded header. + let packet_size = self.read_reg(sr::RX_FSIZE).await?; + + // Packet read of write to the MAC packet buffer must be a multipul of 4! + let read_size = size_align_u32(packet_size); + + if packet_size < u32::try_from(FRAME_HEADER_LEN + FEC_LEN).unwrap() + || read_size > u32::try_from(packet.len()).unwrap() + { + return Err(AdinError::PACKET_TOO_BIG); + } + + let mut spi_hdr = SpiHeader(0); + spi_hdr.set_control(true); + spi_hdr.set_addr(sr::RX); + let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); + + if self.crc { + // Add CRC for header data + let _ = tx_buf.push(crc8(&tx_buf)); + } + + // Turn around byte, TODO: Unknown that this is. + let _ = tx_buf.push(TURN_AROUND_BYTE); + + let spi_packet = &mut packet[0..read_size as usize]; + + assert_eq!(spi_packet.len() & 0x03, 0x00); + + let mut pkt_header = [0, 0]; + + let mut spi_op = [ + Operation::Write(&tx_buf), + Operation::Read(&mut pkt_header), + Operation::Read(spi_packet), + ]; + + self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; + + Ok(packet_size as usize) + } + + pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SpiE> { + let header_len = self.header_write_len(); + // if packet.len() < header_len { + // return Err(AdinError::PACKET_TOO_SMALL); + // } + + let mut packet = Packet::new(); + + let mut spi_hdr = SpiHeader(0); + spi_hdr.set_control(true); + spi_hdr.set_write(true); + spi_hdr.set_addr(sr::TX); + + packet + .extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()) + .map_err(|_| AdinError::PACKET_TOO_BIG)?; + + if self.crc { + assert_eq!(header_len, 5); + // Add CRC for header data + packet + .push(crc8(&packet[0..2])) + .map_err(|_| AdinError::PACKET_TOO_BIG)?; + } + + // Add port number + // packet[header_len - FRAME_HEADER_LEN..header_len] + // .copy_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice()); + packet + .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice()) + .map_err(|_| AdinError::PACKET_TOO_BIG)?; + + packet.extend_from_slice(frame).map_err(|_| AdinError::PACKET_TOO_BIG)?; + + // Pad data up to 64 + for _ in packet.len()..(64 - FEC_LEN + header_len) { + let _ = packet.push(0x00); + } + + // // add ethernet crc32 + let crc = ETH_FSC::new(&packet[header_len..]); + let _ = packet.extend_from_slice(crc.hton_bytes().as_slice()); + + let crc = ETH_FSC::new(&packet[header_len..]); + assert!(crc.crc_ok()); + + let send_len = packet.len() - header_len + FRAME_HEADER_LEN; + + // Packet read of write to the MAC packet buffer must be a multipul of 4! + while packet.len() & 0x3 != 0 { + let _ = packet.push(DONT_CARE_BYTE); + } + + #[cfg(feature = "defmt")] + defmt::trace!( + "TX: hdr {} [{}] {:02x} SIZE: {}", + header_len, + packet.len(), + &packet, + send_len, + ); + + self.write_reg(sr::TX_FSIZE, send_len as u32).await?; + + // Spi packet must be half word / even length + if send_len & 1 != 0 { + let _ = packet.push(0x00); + } + + self.spi.write(&packet).await.map_err(AdinError::Spi) + } + + pub fn header_write_len(&self) -> usize { + // u16 + [CRC] + PORT + WR_HEADER_LEN + FRAME_HEADER_LEN + usize::from(self.crc) + } + + pub fn header_len_read(&self) -> usize { + // u16 + [CRC] + u8 + WR_HEADER_LEN + 1 + usize::from(self.crc) + } + + /// Programs the mac address in the mac filters. + /// Also set the boardcast address. + /// The chip supports 2 priority queues but current code doesn't support this mode. + pub async fn set_mac_addr(&mut self, mac: &[u8; 6]) -> AEResult<(), SpiE> { + let mac_high_part = u16::from_be_bytes(mac[0..2].try_into().unwrap()); + let mac_low_part = u32::from_be_bytes(mac[2..6].try_into().unwrap()); + + // program our mac address in the mac address filter + self.write_reg(sr::ADDR_FILT_UPR0, (1 << 16) | (1 << 30) | u32::from(mac_high_part)) + .await?; + self.write_reg(sr::ADDR_FILT_LWR0, mac_low_part).await?; + + self.write_reg(sr::ADDR_MSK_UPR0, u32::from(mac_high_part)).await?; + self.write_reg(sr::ADDR_MSK_LWR0, mac_low_part).await?; + + // Also program broadcast address in the mac address filter + self.write_reg(sr::ADDR_FILT_UPR1, (1 << 16) | (1 << 30) | 0xFFFF) + .await?; + self.write_reg(sr::ADDR_FILT_LWR1, 0xFFFF_FFFF).await?; + self.write_reg(sr::ADDR_MSK_UPR1, 0xFFFF).await?; + self.write_reg(sr::ADDR_MSK_LWR1, 0xFFFF_FFFF).await?; + + Ok(()) + } +} + +impl mdio::MdioBus for ADIN1110 +where + SPI: SpiDevice, + SpiE: core::fmt::Debug, +{ + type Error = AdinError; + + /// Read from the PHY Registers as Clause 22. + async fn read_cl22(&mut self, phy_id: u8, reg: u8) -> Result { + let mdio_acc_val: u32 = + (0x1 << 28) | u32::from(phy_id & 0x1F) << 21 | u32::from(reg & 0x1F) << 16 | (0x3 << 26); + + self.write_mdio_acc_reg(mdio_acc_val).await.map(|val| val as u16) + } + + /// Read from the PHY Registers as Clause 45. + async fn read_cl45(&mut self, phy_id: u8, regc45: (u8, u16)) -> Result { + let mdio_acc_val: u32 = u32::from(phy_id & 0x1F) << 21 | u32::from(regc45.0 & 0x1F) << 16 | u32::from(regc45.1); + + self.write_mdio_acc_reg(mdio_acc_val).await?; + + let mdio_acc_val: u32 = u32::from(phy_id & 0x1F) << 21 | u32::from(regc45.0 & 0x1F) << 16 | (0x03 << 26); + + self.write_mdio_acc_reg(mdio_acc_val).await.map(|val| val as u16) + } + + /// Write to the PHY Registers as Clause 22. + async fn write_cl22(&mut self, phy_id: u8, reg: u8, val: u16) -> Result<(), Self::Error> { + let mdio_acc_val: u32 = + (0x1 << 28) | u32::from(phy_id & 0x1F) << 21 | u32::from(reg & 0x1F) << 16 | (0x1 << 26) | u32::from(val); + + self.write_mdio_acc_reg(mdio_acc_val).await.map(|_| ()) + } + + /// Write to the PHY Registers as Clause 45. + async fn write_cl45(&mut self, phy_id: u8, regc45: (u8, u16), value: u16) -> AEResult<(), SpiE> { + let phy_id = u32::from(phy_id & 0x1F) << 21; + let dev_addr = u32::from(regc45.0 & 0x1F) << 16; + let reg = u32::from(regc45.1); + + let mdio_acc_val: u32 = phy_id | dev_addr | reg; + self.write_mdio_acc_reg(mdio_acc_val).await?; + + let mdio_acc_val: u32 = phy_id | dev_addr | (0x01 << 26) | u32::from(value); + self.write_mdio_acc_reg(mdio_acc_val).await.map(|_| ()) + } +} + +/// Background runner for the ADIN110. +/// +/// You must call `.run()` in a background task for the ADIN1100 to operate. +pub struct Runner<'d, SPI, INT, RST> { + mac: ADIN1110, + ch: ch::Runner<'d, MTU>, + int: INT, + is_link_up: bool, + _reset: RST, +} + +impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { + pub async fn run(mut self) -> ! { + loop { + let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); + + loop { + #[cfg(feature = "defmt")] + defmt::debug!("Waiting for interrupts"); + match select(self.int.wait_for_low(), tx_chan.tx_buf()).await { + Either::First(_) => { + let mut status1_clr = Status1(0); + let mut status1 = Status1(self.mac.read_reg(sr::STATUS1).await.unwrap()); + + while status1.p1_rx_rdy() { + #[cfg(feature = "defmt")] + defmt::debug!("alloc RX packet buffer"); + match select(rx_chan.rx_buf(), tx_chan.tx_buf()).await { + // Handle frames that needs to transmit from the wire. + // Note: rx_chan.rx_buf() channel donĀ“t accept new request + // when the tx_chan is full. So these will be handled + // automaticly. + Either::First(frame) => match self.mac.read_fifo(frame).await { + Ok(n) => { + rx_chan.rx_done(n); + } + Err(e) => match e { + AdinError::PACKET_TOO_BIG => { + #[cfg(feature = "defmt")] + defmt::error!("RX Packet to big, DROP"); + self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap(); + } + AdinError::Spi(_) => { + #[cfg(feature = "defmt")] + defmt::error!("RX Spi error") + } + _ => { + #[cfg(feature = "defmt")] + defmt::error!("RX Error") + } + }, + }, + Either::Second(frame) => { + // Handle frames that needs to transmit to the wire. + self.mac.write_fifo(frame).await.unwrap(); + tx_chan.tx_done(); + } + } + status1 = Status1(self.mac.read_reg(sr::STATUS1).await.unwrap()); + } + + let status0 = Status0(self.mac.read_reg(sr::STATUS0).await.unwrap()); + if status1.0 & !0x1b != 0 { + #[cfg(feature = "defmt")] + defmt::error!("SPE CHIP STATUS 0:{:08x} 1:{:08x}", status0.0, status1.0); + } + + if status1.tx_rdy() { + status1_clr.set_tx_rdy(true); + #[cfg(feature = "defmt")] + defmt::info!("TX_DONE"); + } + + if status1.link_change() { + let link = status1.p1_link_status(); + self.is_link_up = link; + + #[cfg(feature = "defmt")] + if link { + let link_status = self + .mac + .read_cl45(MDIO_PHY_ADDR, RegsC45::DA7::AN_STATUS_EXTRA.into()) + .await + .unwrap(); + + let volt = if link_status & (0b11 << 5) == (0b11 << 5) { + "2.4" + } else { + "1.0" + }; + + let mse = self + .mac + .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1::MSE_VAL.into()) + .await + .unwrap(); + + defmt::info!("LINK Changed: Link Up, Volt: {} V p-p, MSE: {:0004}", volt, mse); + } else { + defmt::info!("LINK Changed: Link Down"); + } + + state_chan.set_link_state(if link { LinkState::Up } else { LinkState::Down }); + status1_clr.set_link_change(true); + } + + if status1.tx_ecc_err() { + #[cfg(feature = "defmt")] + defmt::error!("SPI TX_ECC_ERR error, CLEAR TX FIFO"); + self.mac.write_reg(sr::FIFO_CLR, 2).await.unwrap(); + status1_clr.set_tx_ecc_err(true); + } + + if status1.rx_ecc_err() { + #[cfg(feature = "defmt")] + defmt::error!("SPI RX_ECC_ERR error"); + status1_clr.set_rx_ecc_err(true); + } + + if status1.spi_err() { + #[cfg(feature = "defmt")] + defmt::error!("SPI SPI_ERR CRC error"); + status1_clr.set_spi_err(true); + } + + if status0.phyint() { + let crsm_irq_st = self + .mac + .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::CRSM_IRQ_STATUS.into()) + .await + .unwrap(); + + let phy_irq_st = self + .mac + .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1F::PHY_SYBSYS_IRQ_STATUS.into()) + .await + .unwrap(); + #[cfg(feature = "defmt")] + defmt::warn!( + "SPE CHIP PHY CRSM_IRQ_STATUS {:04x} PHY_SUBSYS_IRQ_STATUS {:04x}", + crsm_irq_st, + phy_irq_st + ); + } + + if status0.txfcse() { + #[cfg(feature = "defmt")] + defmt::error!("SPE CHIP PHY TX Frame CRC error"); + } + + // Clear status0 + self.mac.write_reg(sr::STATUS0, 0xFFF).await.unwrap(); + self.mac.write_reg(sr::STATUS1, status1_clr.0).await.unwrap(); + } + Either::Second(packet) => { + // Handle frames that needs to transmit to the wire. + self.mac.write_fifo(packet).await.unwrap(); + tx_chan.tx_done(); + } + } + } + } + } +} + +/// Obtain a driver for using the ADIN1110 with [`embassy-net`](crates.io/crates/embassy-net). +pub async fn new( + mac_addr: [u8; 6], + state: &'_ mut State, + spi_dev: SPI, + int: INT, + mut reset: RST, + crc: bool, +) -> (Device<'_>, Runner<'_, SPI, INT, RST>) { + use crate::regs::{IMask0, IMask1}; + + #[cfg(feature = "defmt")] + defmt::info!("INIT ADIN1110"); + + // Reset sequence + reset.set_low().unwrap(); + // Wait t1: 20-43mS + Timer::after(Duration::from_millis(30)).await; + + reset.set_high().unwrap(); + + // Wait t3: 50mS + Timer::after(Duration::from_millis(50)).await; + + // Create device + let mut mac = ADIN1110::new(spi_dev, crc); + + // Check PHYID + let id = mac.read_reg(sr::PHYID).await.unwrap(); + assert_eq!(id, PHYID); + + #[cfg(feature = "defmt")] + defmt::debug!("SPE: CHIP MAC/ID: {:08x}", id); + + #[cfg(feature = "defmt")] + let adin_phy = Phy10BaseT1x::default(); + #[cfg(feature = "defmt")] + let phy_id = adin_phy.get_id(&mut mac).await.unwrap(); + #[cfg(feature = "defmt")] + defmt::debug!("SPE: CHIP: PHY ID: {:08x}", phy_id); + + let mi_control = mac.read_cl22(MDIO_PHY_ADDR, RegsC22::CONTROL as u8).await.unwrap(); + #[cfg(feature = "defmt")] + defmt::println!("SPE CHIP PHY MI_CONTROL {:04x}", mi_control); + if mi_control & 0x0800 != 0 { + let val = mi_control & !0x0800; + #[cfg(feature = "defmt")] + defmt::println!("SPE CHIP PHY MI_CONTROL Disable PowerDown"); + mac.write_cl22(MDIO_PHY_ADDR, RegsC22::CONTROL as u8, val) + .await + .unwrap(); + } + + // Config2: CRC_APPEND + let mut config2 = Config2(0x00000800); + config2.set_crc_append(true); + mac.write_reg(sr::CONFIG2, config2.0).await.unwrap(); + + // Pin Mux Config 1 + let led_val = (0b11 << 6) | (0b11 << 4); // | (0b00 << 1); + mac.write_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::DIGIO_PINMUX.into(), led_val) + .await + .unwrap(); + + let mut led_pol = LedPolarity(0); + led_pol.set_led1_polarity(LedPol::ActiveLow); + led_pol.set_led0_polarity(LedPol::ActiveLow); + + // Led Polarity Regisgere Active Low + mac.write_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::LED_POLARITY.into(), led_pol.0) + .await + .unwrap(); + + // Led Both On + let mut led_cntr = LedCntrl(0x0); + + // LED1: Yellow + led_cntr.set_led1_en(true); + led_cntr.set_led1_function(LedFunc::TxLevel2P4); + // LED0: Green + led_cntr.set_led0_en(true); + led_cntr.set_led0_function(LedFunc::LinkupTxRxActicity); + + mac.write_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::LED_CNTRL.into(), led_cntr.0) + .await + .unwrap(); + + // Set ADIN1110 Interrupts, RX_READY and LINK_CHANGE + // Enable interrupts LINK_CHANGE, TX_RDY, RX_RDY(P1), SPI_ERR + // Have to clear the mask the enable it. + let mut imask0_val = IMask0(0x0000_1FBF); + imask0_val.set_txfcsem(false); + imask0_val.set_phyintm(false); + imask0_val.set_txboem(false); + imask0_val.set_rxboem(false); + imask0_val.set_txpem(false); + + mac.write_reg(sr::IMASK0, imask0_val.0).await.unwrap(); + + // Set ADIN1110 Interrupts, RX_READY and LINK_CHANGE + // Enable interrupts LINK_CHANGE, TX_RDY, RX_RDY(P1), SPI_ERR + // Have to clear the mask the enable it. + let mut imask1_val = IMask1(0x43FA_1F1A); + imask1_val.set_link_change_mask(false); + imask1_val.set_p1_rx_rdy_mask(false); + imask1_val.set_spi_err_mask(false); + imask1_val.set_tx_ecc_err_mask(false); + imask1_val.set_rx_ecc_err_mask(false); + + mac.write_reg(sr::IMASK1, imask1_val.0).await.unwrap(); + + // Program mac address but also sets mac filters. + mac.set_mac_addr(&mac_addr).await.unwrap(); + + let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr)); + ( + device, + Runner { + ch: runner, + mac, + int, + is_link_up: false, + _reset: reset, + }, + ) +} + +#[cfg(test)] +mod tests { + use core::convert::Infallible; + + use embedded_hal_1::digital::{ErrorType, OutputPin}; + use embedded_hal_async::delay::DelayUs; + use embedded_hal_bus::spi::ExclusiveDevice; + use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction}; + + #[derive(Debug, Default)] + struct CsPinMock { + pub high: u32, + pub low: u32, + } + impl OutputPin for CsPinMock { + fn set_low(&mut self) -> Result<(), Self::Error> { + self.low += 1; + Ok(()) + } + + fn set_high(&mut self) -> Result<(), Self::Error> { + self.high += 1; + Ok(()) + } + } + impl ErrorType for CsPinMock { + type Error = Infallible; + } + + use super::*; + + // TODO: This is currently a workaround unit `ExclusiveDevice` is moved to `embedded-hal-bus` + // see https://github.com/rust-embedded/embedded-hal/pull/462#issuecomment-1560014426 + struct MockDelay {} + + impl DelayUs for MockDelay { + async fn delay_us(&mut self, _us: u32) { + todo!() + } + + async fn delay_ms(&mut self, _ms: u32) { + todo!() + } + } + + #[futures_test::test] + async fn mac_read_registers_without_crc() { + // Configure expectations + let expectations = [ + // 1st + SpiTransaction::write_vec(vec![0x80, 0x01, TURN_AROUND_BYTE]), + SpiTransaction::read_vec(vec![0x02, 0x83, 0xBC, 0x91]), + SpiTransaction::flush(), + // 2nd + SpiTransaction::write_vec(vec![0x80, 0x02, TURN_AROUND_BYTE]), + SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3]), + SpiTransaction::flush(), + ]; + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + let mut spe = ADIN1110::new(spi_dev, false); + + // Read PHIID + match spe.read_reg(sr::PHYID).await { + Ok(val) => assert_eq!(val, 0x0283BC91), + Err(_e) => panic!("Error:"), + }; + + // Read CAPAVILITY + match spe.read_reg(sr::CAPABILITY).await { + Ok(val) => assert_eq!(val, 0x000006C3), + Err(_e) => panic!("Error:"), + }; + + spi.done(); + } + + #[futures_test::test] + async fn mac_read_registers_with_crc() { + // Configure expectations + let expectations = [ + // 1st + SpiTransaction::write_vec(vec![0x80, 0x01, 177, TURN_AROUND_BYTE]), + SpiTransaction::read_vec(vec![0x02, 0x83, 0xBC, 0x91, 215]), + SpiTransaction::flush(), + // 2nd + SpiTransaction::write_vec(vec![0x80, 0x02, 184, TURN_AROUND_BYTE]), + SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3, 57]), + SpiTransaction::flush(), + ]; + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, true); + + assert_eq!(crc8(0x0283BC91_u32.to_be_bytes().as_slice()), 215); + assert_eq!(crc8(0x000006C3_u32.to_be_bytes().as_slice()), 57); + + // Read PHIID + match spe.read_reg(sr::PHYID).await { + Ok(val) => assert_eq!(val, 0x0283BC91), + Err(e) => panic!("Error: {e:?}"), + }; + + // Read CAPAVILITY + match spe.read_reg(sr::CAPABILITY).await { + Ok(val) => assert_eq!(val, 0x000006C3), + Err(_e) => panic!("Error:"), + }; + + spi.done(); + } + + #[futures_test::test] + async fn mac_write_registers_without_crc() { + // Configure expectations + let expectations = [ + SpiTransaction::write_vec(vec![0xA0, 0x09, 0x12, 0x34, 0x56, 0x78]), + SpiTransaction::flush(), + ]; + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, false); + + // Write reg: 0x1FFF + assert!(spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok()); + + spi.done(); + } + + #[futures_test::test] + async fn mac_write_registers_with_crc() { + // Configure expectations + let expectations = [ + SpiTransaction::write_vec(vec![0xA0, 0x09, 39, 0x12, 0x34, 0x56, 0x78, 28]), + SpiTransaction::flush(), + ]; + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, true); + + // Write reg: 0x1FFF + assert!(spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok()); + + spi.done(); + } + + #[test] + fn align_size() { + assert_eq!(size_align_u32(1), 4); + assert_eq!(size_align_u32(2), 4); + assert_eq!(size_align_u32(3), 4); + assert_eq!(size_align_u32(4), 4); + assert_eq!(size_align_u32(5), 8); + assert_eq!(size_align_u32(6), 8); + assert_eq!(size_align_u32(7), 8); + assert_eq!(size_align_u32(8), 8); + } + + // #[test] + // fn write_packet_to_fifo_less_64b_with_crc() { + // // Configure expectations + // let mut expectations = vec![ + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x30), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(136), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Frame Size + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(66), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(201), + // SpiTransaction::read(DONT_CARE_BYTE), + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x31), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Port + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(PORT_ID_BYTE), + // SpiTransaction::read(DONT_CARE_BYTE), + // ]; + + // let mut packet = Packet::new(); + // packet.resize(64, 0).unwrap(); + + // for &byte in &packet[4..] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // padding + // for _ in packet.len() as u32..65 { + // expectations.push(SpiTransaction::send(0x00)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // fcs + // for &byte in &[8, 137, 18, 4] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // let spi = SpiMock::new(&expectations); + + // let cs = CsPinMock {}; + // let mut spe = Adin1110::new(spi, cs, true); + + // assert!(spe.write_fifo(&mut packet).is_ok()); + // } + + // #[test] + // fn write_packet_to_fifo_less_64b_no_crc() { + // // Configure expectations + // let mut expectations = vec![ + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x30), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Frame Size + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(66), + // SpiTransaction::read(DONT_CARE_BYTE), + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x31), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Port + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(PORT_ID_BYTE), + // SpiTransaction::read(DONT_CARE_BYTE), + // ]; + + // let mut packet = Packet::new(); + // packet.resize(64, 0).unwrap(); + + // for &byte in &packet[4..] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // padding + // for _ in packet.len() as u32..64 { + // expectations.push(SpiTransaction::send(0x00)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // fcs + // for &byte in &[8, 137, 18, 4] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // let spi = SpiMock::new(&expectations); + + // let cs = CsPinMock {}; + // let mut spe = Adin1110::new(spi, cs, false); + + // assert!(spe.write_fifo(&mut packet).is_ok()); + // } + + // #[test] + // fn write_packet_to_fifo_1500b() { + // // Configure expectations + // let mut expectations = vec![ + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x30), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Frame Size + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x05), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0xDE), + // SpiTransaction::read(DONT_CARE_BYTE), + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x31), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Port + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(PORT_ID_BYTE), + // SpiTransaction::read(DONT_CARE_BYTE), + // ]; + + // let mut packet = Packet::new(); + // packet.resize(1500, 0).unwrap(); + + // for &byte in &packet[4..] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // fcs + // for &byte in &[212, 114, 18, 50] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // let spi = SpiMock::new(&expectations); + + // let cs = CsPinMock {}; + // let mut spe = Adin1110::new(spi, cs, false); + + // assert!(spe.write_fifo(&mut packet).is_ok()); + // } + + // #[test] + // fn write_packet_to_fifo_65b() { + // // Configure expectations + // let mut expectations = vec![ + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x30), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Frame Size + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(67), + // SpiTransaction::read(DONT_CARE_BYTE), + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x31), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Port + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(PORT_ID_BYTE), + // SpiTransaction::read(DONT_CARE_BYTE), + // ]; + + // let mut packet = Packet::new(); + // packet.resize(65, 0).unwrap(); + + // for &byte in &packet[4..] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // padding + // for _ in packet.len() as u32..64 { + // expectations.push(SpiTransaction::send(0x00)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // fcs + // for &byte in &[54, 117, 221, 220] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // let spi = SpiMock::new(&expectations); + + // let cs = CsPinMock {}; + // let mut spe = Adin1110::new(spi, cs, false); + + // assert!(spe.write_fifo(&mut packet).is_ok()); + // } + + // #[test] + // fn write_packet_to_fifo_66b() { + // // Configure expectations + // let mut expectations = vec![ + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x30), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Frame Size + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(68), + // SpiTransaction::read(DONT_CARE_BYTE), + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x31), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Port + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(PORT_ID_BYTE), + // SpiTransaction::read(DONT_CARE_BYTE), + // ]; + + // let mut packet = Packet::new(); + // packet.resize(66, 0).unwrap(); + + // for &byte in &packet[4..] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // padding + // for _ in packet.len() as u32..64 { + // expectations.push(SpiTransaction::send(0x00)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // fcs + // for &byte in &[97, 167, 100, 29] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + // let spi = SpiMock::new(&expectations); + + // let cs = CsPinMock {}; + // let mut spe = Adin1110::new(spi, cs, false); + + // assert!(spe.write_fifo(&mut packet).is_ok()); + // } + + // #[test] + // fn write_packet_to_fifo_67b() { + // // Configure expectations + // let mut expectations = vec![ + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x30), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Frame Size + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(69), + // SpiTransaction::read(DONT_CARE_BYTE), + // // HEADER + // SpiTransaction::send(0xA0), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(0x31), + // SpiTransaction::read(DONT_CARE_BYTE), + // // Port + // SpiTransaction::send(0x00), + // SpiTransaction::read(DONT_CARE_BYTE), + // SpiTransaction::send(PORT_ID_BYTE), + // SpiTransaction::read(DONT_CARE_BYTE), + // ]; + + // let mut packet = Packet::new(); + // packet.resize(67, 0).unwrap(); + + // for &byte in &packet[4..] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // padding + // for _ in packet.len() as u32..64 { + // expectations.push(SpiTransaction::send(0x00)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + + // // fcs + // for &byte in &[228, 218, 170, 232] { + // expectations.push(SpiTransaction::send(byte)); + // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); + // } + // let spi = SpiMock::new(&expectations); + + // let cs = CsPinMock {}; + // let mut spe = Adin1110::new(spi, cs, false); + + // assert!(spe.write_fifo(&mut packet).is_ok()); + // } + + #[futures_test::test] + async fn write_packet_to_fifo_arp_46bytes() { + // Configure expectations + let mut expectations = vec![]; + + let mut packet = Packet::new(); + //arp packet; + packet + .extend_from_slice(&[ + 34, 51, 68, 85, 102, 119, 18, 52, 86, 120, 154, 188, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, 18, 52, 86, 120, + 154, 188, 192, 168, 16, 4, 34, 51, 68, 85, 102, 119, 192, 168, 16, 1, + ]) + .unwrap(); + + let mut spi_packet = Packet::new(); + + // Write TX_SIZE reg + expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 66, 201])); + expectations.push(SpiTransaction::flush()); + + // Write TX reg. + // Header + spi_packet.extend_from_slice(&[160, 49, 143, 0, 0]).unwrap(); + // Packet data + spi_packet.extend_from_slice(&packet).unwrap(); + // Packet padding up to 60 (64 - FCS) + for _ in packet.len() as u32..60 { + spi_packet.push(0x00).unwrap(); + } + // Packet FCS + spi_packet.extend_from_slice(&[147, 149, 213, 68]).unwrap(); + + // SPI HEADER Padding of u32 + for _ in spi_packet.len() as u32..size_align_u32(spi_packet.len() as u32) { + spi_packet.push(0x00).unwrap(); + } + + expectations.push(SpiTransaction::write_vec(spi_packet.to_vec())); + expectations.push(SpiTransaction::flush()); + + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, true); + + assert!(spe.write_fifo(&mut packet).await.is_ok()); + + spi.done(); + } +} diff --git a/embassy-net-adin1110/src/mdio.rs b/embassy-net-adin1110/src/mdio.rs new file mode 100644 index 00000000..ab7629d3 --- /dev/null +++ b/embassy-net-adin1110/src/mdio.rs @@ -0,0 +1,174 @@ +/// PHY Address: (0..=0x1F), 5-bits long. +#[allow(dead_code)] +type PhyAddr = u8; + +/// PHY Register: (0..=0x1F), 5-bits long. +#[allow(dead_code)] +type RegC22 = u8; + +/// PHY Register Clause 45. +#[allow(dead_code)] +type RegC45 = u16; + +/// PHY Register Value +#[allow(dead_code)] +type RegVal = u16; + +#[allow(dead_code)] +const REG13: RegC22 = 13; +#[allow(dead_code)] +const REG14: RegC22 = 14; + +#[allow(dead_code)] +const PHYADDR_MASK: u8 = 0x1f; +#[allow(dead_code)] +const DEV_MASK: u8 = 0x1f; + +#[allow(dead_code)] +#[repr(u16)] +enum Reg13Op { + Addr = 0b00 << 14, + Write = 0b01 << 14, + PostReadIncAddr = 0b10 << 14, + Read = 0b11 << 14, +} +/// MdioBus trait +/// Driver needs to implemnt the Claus 22 +/// Optional Clause 45 is the device supports this. +/// +/// Claus 45 methodes are bases on https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf +pub trait MdioBus { + type Error; + + /// Read, Clause 22 + async fn read_cl22(&mut self, phy_id: PhyAddr, reg: RegC22) -> Result; + + /// Write, Clause 22 + async fn write_cl22(&mut self, phy_id: PhyAddr, reg: RegC22, reg_val: RegVal) -> Result<(), Self::Error>; + + /// Read, Clause 45 + /// This is the default implementation. + /// Many hardware these days support direct Clause 45 operations. + /// Implement this function when your hardware supports it. + async fn read_cl45(&mut self, phy_id: PhyAddr, regc45: (u8, RegC45)) -> Result { + // Write FN + let val = (Reg13Op::Addr as RegVal) | (regc45.0 & DEV_MASK) as RegVal; + self.write_cl22(phy_id, REG13, val).await?; + // Write Addr + self.write_cl22(phy_id, REG14, regc45.1).await?; + + // Write FN + let val = (Reg13Op::Read as RegVal) | (regc45.0 & DEV_MASK) as RegVal; + self.write_cl22(phy_id, REG13, val).await?; + // Write Addr + self.read_cl22(phy_id, REG14).await + } + + /// Write, Clause 45 + /// This is the default implementation. + /// Many hardware these days support direct Clause 45 operations. + /// Implement this function when your hardware supports it. + async fn write_cl45(&mut self, phy_id: PhyAddr, regc45: (u8, RegC45), reg_val: RegVal) -> Result<(), Self::Error> { + let dev_addr = (regc45.0 & DEV_MASK) as RegVal; + let reg = regc45.1; + + // Write FN + let val = (Reg13Op::Addr as RegVal) | dev_addr; + self.write_cl22(phy_id, REG13, val).await?; + // Write Addr + self.write_cl22(phy_id, REG14, reg).await?; + + // Write FN + let val = (Reg13Op::Write as RegVal) | dev_addr; + self.write_cl22(phy_id, REG13, val).await?; + // Write Addr + self.write_cl22(phy_id, REG14, reg_val).await + } +} + +// #[cfg(test)] +// mod tests { +// use core::convert::Infallible; + +// use super::{MdioBus, PhyAddr, RegC22, RegVal}; + +// #[derive(Debug, PartialEq, Eq)] +// enum A { +// Read(PhyAddr, RegC22), +// Write(PhyAddr, RegC22, RegVal), +// } + +// struct MockMdioBus(Vec); + +// impl MockMdioBus { +// pub fn clear(&mut self) { +// self.0.clear(); +// } +// } + +// impl MdioBus for MockMdioBus { +// type Error = Infallible; + +// fn write_cl22( +// &mut self, +// phy_id: super::PhyAddr, +// reg: super::RegC22, +// reg_val: super::RegVal, +// ) -> Result<(), Self::Error> { +// self.0.push(A::Write(phy_id, reg, reg_val)); +// Ok(()) +// } + +// fn read_cl22( +// &mut self, +// phy_id: super::PhyAddr, +// reg: super::RegC22, +// ) -> Result { +// self.0.push(A::Read(phy_id, reg)); +// Ok(0) +// } +// } + +// #[test] +// fn read_test() { +// let mut mdiobus = MockMdioBus(Vec::with_capacity(20)); + +// mdiobus.clear(); +// mdiobus.read_cl22(0x01, 0x00).unwrap(); +// assert_eq!(mdiobus.0, vec![A::Read(0x01, 0x00)]); + +// mdiobus.clear(); +// mdiobus.read_cl45(0x01, (0xBB, 0x1234)).unwrap(); +// assert_eq!( +// mdiobus.0, +// vec![ +// #[allow(clippy::identity_op)] +// A::Write(0x01, 13, (0b00 << 14) | 27), +// A::Write(0x01, 14, 0x1234), +// A::Write(0x01, 13, (0b11 << 14) | 27), +// A::Read(0x01, 14) +// ] +// ); +// } + +// #[test] +// fn write_test() { +// let mut mdiobus = MockMdioBus(Vec::with_capacity(20)); + +// mdiobus.clear(); +// mdiobus.write_cl22(0x01, 0x00, 0xABCD).unwrap(); +// assert_eq!(mdiobus.0, vec![A::Write(0x01, 0x00, 0xABCD)]); + +// mdiobus.clear(); +// mdiobus.write_cl45(0x01, (0xBB, 0x1234), 0xABCD).unwrap(); +// assert_eq!( +// mdiobus.0, +// vec![ +// A::Write(0x01, 13, 27), +// A::Write(0x01, 14, 0x1234), +// A::Write(0x01, 13, (0b01 << 14) | 27), +// A::Write(0x01, 14, 0xABCD) +// ] +// ); +// } +// } diff --git a/embassy-net-adin1110/src/phy.rs b/embassy-net-adin1110/src/phy.rs new file mode 100644 index 00000000..78d3fdf7 --- /dev/null +++ b/embassy-net-adin1110/src/phy.rs @@ -0,0 +1,137 @@ +use crate::mdio::MdioBus; + +#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)] +#[repr(u8)] +/// Clause 22 Registers +pub enum RegsC22 { + /// MII Control Register + CONTROL = 0x00, + /// MII Status Register + STATUS = 0x01, + /// PHY Identifier 1 Register + PHY_ID1 = 0x02, + /// PHY Identifier 2 Register. + PHY_ID2 = 0x03, +} + +/// Clause 45 Registers +#[allow(non_snake_case, dead_code)] +pub mod RegsC45 { + /// Device Address: 0x01 + #[allow(non_camel_case_types, clippy::upper_case_acronyms)] + #[repr(u16)] + pub enum DA1 { + /// PMA/PMD Control 1 Register + PMA_PMD_CNTRL1 = 0x0000, + /// PMA/PMD Status 1 Register + PMA_PMD_STAT1 = 0x0001, + /// MSE Value Register + MSE_VAL = 0x830B, + } + + impl DA1 { + pub fn into(self) -> (u8, u16) { + (0x01, self as u16) + } + } + + /// Device Address: 0x03 + #[allow(non_camel_case_types, clippy::upper_case_acronyms)] + #[repr(u16)] + pub enum DA3 { + /// PCS Control 1 Register + PCS_CNTRL1 = 0x0000, + /// PCS Status 1 Register + PCS_STAT1 = 0x0001, + /// PCS Status 2 Register + PCS_STAT2 = 0x0008, + } + + impl DA3 { + pub fn into(self) -> (u8, u16) { + (0x03, self as u16) + } + } + + /// Device Address: 0x07 + #[allow(non_camel_case_types, clippy::upper_case_acronyms)] + #[repr(u16)] + pub enum DA7 { + /// Extra Autonegotiation Status Register + AN_STATUS_EXTRA = 0x8001, + } + + impl DA7 { + pub fn into(self) -> (u8, u16) { + (0x07, self as u16) + } + } + + /// Device Address: 0x1E + #[allow(non_camel_case_types, clippy::upper_case_acronyms)] + #[repr(u16)] + pub enum DA1E { + /// System Interrupt Status Register + CRSM_IRQ_STATUS = 0x0010, + /// System Interrupt Mask Register + CRSM_IRQ_MASK = 0x0020, + /// Pin Mux Configuration 1 Register + DIGIO_PINMUX = 0x8c56, + /// LED Control Register. + LED_CNTRL = 0x8C82, + /// LED Polarity Register + LED_POLARITY = 0x8C83, + } + + impl DA1E { + pub fn into(self) -> (u8, u16) { + (0x1e, self as u16) + } + } + + /// Device Address: 0x1F + #[allow(non_camel_case_types, clippy::upper_case_acronyms)] + #[repr(u16)] + pub enum DA1F { + /// PHY Subsystem Interrupt Status Register + PHY_SYBSYS_IRQ_STATUS = 0x0011, + /// PHY Subsystem Interrupt Mask Register + PHY_SYBSYS_IRQ_MASK = 0x0021, + } + + impl DA1F { + pub fn into(self) -> (u8, u16) { + (0x1f, self as u16) + } + } +} + +pub struct Phy10BaseT1x(u8); + +impl Default for Phy10BaseT1x { + fn default() -> Self { + Self(0x01) + } +} + +impl Phy10BaseT1x { + /// Get the both parts of the PHYID. + pub async fn get_id(&self, mdiobus: &mut MDIOBUS) -> Result + where + MDIOBUS: MdioBus, + MDE: core::fmt::Debug, + { + let mut phyid = (mdiobus.read_cl22(self.0, RegsC22::PHY_ID1 as u8).await? as u32) << 16; + phyid |= mdiobus.read_cl22(self.0, RegsC22::PHY_ID2 as u8).await? as u32; + Ok(phyid) + } + + /// Get the Mean Squared Error Value. + pub async fn get_sqi(&self, mdiobus: &mut MDIOBUS) -> Result + where + MDIOBUS: MdioBus, + MDE: core::fmt::Debug, + { + mdiobus.read_cl45(self.0, RegsC45::DA1::MSE_VAL.into()).await + } +} diff --git a/embassy-net-adin1110/src/regs.rs b/embassy-net-adin1110/src/regs.rs new file mode 100644 index 00000000..93ce812d --- /dev/null +++ b/embassy-net-adin1110/src/regs.rs @@ -0,0 +1,407 @@ +use bitfield::{bitfield, bitfield_bitrange, bitfield_fields}; + +#[allow(non_camel_case_types)] +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u16)] +/// SPI REGISTER DETAILS +/// Table 38. +pub enum SpiRegisters { + IDVER = 0x00, + PHYID = 0x01, + CAPABILITY = 0x02, + RESET = 0x03, + CONFIG0 = 0x04, + CONFIG2 = 0x06, + STATUS0 = 0x08, + STATUS1 = 0x09, + IMASK0 = 0x0C, + IMASK1 = 0x0D, + MDIO_ACC = 0x20, + TX_FSIZE = 0x30, + TX = 0x31, + TX_SPACE = 0x32, + FIFO_CLR = 0x36, + ADDR_FILT_UPR0 = 0x50, + ADDR_FILT_LWR0 = 0x51, + ADDR_FILT_UPR1 = 0x52, + ADDR_FILT_LWR1 = 0x53, + ADDR_MSK_LWR0 = 0x70, + ADDR_MSK_UPR0 = 0x71, + ADDR_MSK_LWR1 = 0x72, + ADDR_MSK_UPR1 = 0x73, + RX_FSIZE = 0x90, + RX = 0x91, +} + +impl From for u16 { + fn from(val: SpiRegisters) -> Self { + val as u16 + } +} + +impl From for SpiRegisters { + fn from(value: u16) -> Self { + match value { + 0x00 => Self::IDVER, + 0x01 => Self::PHYID, + 0x02 => Self::CAPABILITY, + 0x03 => Self::RESET, + 0x04 => Self::CONFIG0, + 0x06 => Self::CONFIG2, + 0x08 => Self::STATUS0, + 0x09 => Self::STATUS1, + 0x0C => Self::IMASK0, + 0x0D => Self::IMASK1, + 0x20 => Self::MDIO_ACC, + 0x30 => Self::TX_FSIZE, + 0x31 => Self::TX, + 0x32 => Self::TX_SPACE, + 0x36 => Self::FIFO_CLR, + 0x50 => Self::ADDR_FILT_UPR0, + 0x51 => Self::ADDR_FILT_LWR0, + 0x52 => Self::ADDR_FILT_UPR1, + 0x53 => Self::ADDR_FILT_LWR1, + 0x70 => Self::ADDR_MSK_LWR0, + 0x71 => Self::ADDR_MSK_UPR0, + 0x72 => Self::ADDR_MSK_LWR1, + 0x73 => Self::ADDR_MSK_UPR1, + 0x90 => Self::RX_FSIZE, + 0x91 => Self::RX, + e => panic!("Unknown value {e}"), + } + } +} + +// Register definitions + +bitfield! { + /// Status0 Register bits + pub struct Status0(u32); + impl Debug; + u32; + /// Control Data Protection Error + pub cdpe, _ : 12; + /// Transmit Frame Check Squence Error + pub txfcse, _: 11; + /// Transmit Time Stamp Capture Available C + pub ttscac, _ : 10; + /// Transmit Time Stamp Capture Available B + pub ttscab, _ : 9; + /// Transmit Time Stamp Capture Available A + pub ttscaa, _ : 8; + /// PHY Interrupt for Port 1 + pub phyint, _ : 7; + /// Reset Complete + pub resetc, _ : 6; + /// Header error + pub hdre, _ : 5; + /// Loss of Frame Error + pub lofe, _ : 4; + /// Receiver Buffer Overflow Error + pub rxboe, _ : 3; + /// Host Tx FIFO Under Run Error + pub txbue, _ : 2; + /// Host Tx FIFO Overflow + pub txboe, _ : 1; + /// Transmit Protocol Error + pub txpe, _ : 0; +} + +bitfield! { + /// Status1 Register bits + pub struct Status1(u32); + impl Debug; + u32; + /// ECC Error on Reading the Frame Size from a Tx FIFO + pub tx_ecc_err, set_tx_ecc_err: 12; + /// ECC Error on Reading the Frame Size from an Rx FIFO + pub rx_ecc_err, set_rx_ecc_err : 11; + /// Detected an Error on an SPI Transaction + pub spi_err, set_spi_err: 10; + /// Rx MAC Interframe Gap Error + pub p1_rx_ifg_err, set_p1_rx_ifg_err : 8; + /// Port1 Rx Ready High Priority + pub p1_rx_rdy_hi, set_p1_rx_rdy_hi : 5; + /// Port 1 Rx FIFO Contains Data + pub p1_rx_rdy, set_p1_rx_rdy : 4; + /// Tx Ready + pub tx_rdy, set_tx_rdy : 3; + /// Link Status Changed + pub link_change, set_link_change : 1; + /// Port 1 Link Status + pub p1_link_status, _ : 0; +} + +bitfield! { + /// Config0 Register bits + pub struct Config0(u32); + impl Debug; + u32; + /// Configuration Synchronization + pub sync, set_sync : 15; + /// Transmit Frame Check Sequence Validation Enable + pub txfcsve, set_txfcsve : 14; + /// !CS Align Receive Frame Enable + pub csarfe, set_csarfe : 13; + /// Zero Align Receive Frame Enable + pub zarfe, set_zarfe : 12; + /// Transmit Credit Threshold + pub tcxthresh, set_tcxthresh : 11, 10; + /// Transmit Cut Through Enable + pub txcte, set_txcte : 9; + /// Receive Cut Through Enable + pub rxcte, set_rxcte : 8; + /// Frame Time Stamp Enable + pub ftse, set_ftse : 7; + /// Receive Frame Time Stamp Select + pub ftss, set_ftss : 6; + /// Enable Control Data Read Write Protection + pub prote, set_prote : 5; + /// Enable TX Data Chunk Sequence and Retry + pub seqe, set_seqe : 4; + /// Chunk Payload Selector (N). + pub cps, set_cps : 2, 0; +} + +bitfield! { + /// Config2 Register bits + pub struct Config2(u32); + impl Debug; + u32; + /// Assert TX_RDY When the Tx FIFO is Empty + pub tx_rdy_on_empty, set_tx_rdy_on_empty : 8; + /// Determines If the SFD is Detected in the PHY or MAC + pub sdf_detect_src, set_sdf_detect_src : 7; + /// Statistics Clear on Reading + pub stats_clr_on_rd, set_stats_clr_on_rd : 6; + /// Enable CRC Append + pub crc_append, set_crc_append : 5; + /// Admit Frames with IFG Errors on Port 1 (P1) + pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4; + /// Forward Frames Not Matching Any MAC Address to the Host + pub p1_fwd_unk2host, set_p1_fwd_unk2host : 2; + /// SPI to MDIO Bridge MDC Clock Speed + pub mspeed, set_mspeed : 0; +} + +bitfield! { + /// IMASK0 Register bits + pub struct IMask0(u32); + impl Debug; + u32; + /// Control Data Protection Error Mask + pub cppem, set_cppem : 12; + /// Transmit Frame Check Sequence Error Mask + pub txfcsem, set_txfcsem : 11; + /// Transmit Time Stamp Capture Available C Mask + pub ttscacm, set_ttscacm : 10; + /// Transmit Time Stamp Capture Available B Mask + pub ttscabm, set_ttscabm : 9; + /// Transmit Time Stamp Capture Available A Mask + pub ttscaam, set_ttscaam : 8; + /// Physical Layer Interrupt Mask + pub phyintm, set_phyintm : 7; + /// RESET Complete Mask + pub resetcm, set_resetcm : 6; + /// Header Error Mask + pub hdrem, set_hdrem : 5; + /// Loss of Frame Error Mask + pub lofem, set_lofem : 4; + /// Receive Buffer Overflow Error Mask + pub rxboem, set_rxboem : 3; + /// Transmit Buffer Underflow Error Mask + pub txbuem, set_txbuem : 2; + /// Transmit Buffer Overflow Error Mask + pub txboem, set_txboem : 1; + /// Transmit Protocol Error Mask + pub txpem, set_txpem : 0; +} + +bitfield! { + /// IMASK1 Register bits + pub struct IMask1(u32); + impl Debug; + u32; + /// Mask Bit for TXF_ECC_ERR + pub tx_ecc_err_mask, set_tx_ecc_err_mask : 12; + /// Mask Bit for RXF_ECC_ERR + pub rx_ecc_err_mask, set_rx_ecc_err_mask : 11; + /// Mask Bit for SPI_ERR + /// This field is only used with the generic SPI protocol + pub spi_err_mask, set_spi_err_mask : 10; + /// Mask Bit for RX_IFG_ERR + pub p1_rx_ifg_err_mask, set_p1_rx_ifg_err_mask : 8; + /// Mask Bit for P1_RX_RDY + /// This field is only used with the generic SPI protocol + pub p1_rx_rdy_mask, set_p1_rx_rdy_mask : 4; + /// Mask Bit for TX_FRM_DONE + /// This field is only used with the generic SPI protocol + pub tx_rdy_mask, set_tx_rdy_mask : 3; + /// Mask Bit for LINK_CHANGE + pub link_change_mask, set_link_change_mask : 1; +} + +#[repr(u8)] +pub enum LedFunc { + LinkupTxRxActicity = 0, + LinkupTxActicity, + LinkupRxActicity, + LinkupOnly, + TxRxActivity, + TxActivity, + RxActivity, + LinkupRxEr, + LinkupRxTxEr, + RxEr, + RxTxEr, + TxSop, + RxSop, + On, + Off, + Blink, + TxLevel2P4, + TxLevel1P0, + Master, + Slave, + IncompatiableLinkCfg, + AnLinkGood, + AnComplete, + TsTimer, + LocRcvrStatus, + RemRcvrStatus, + Clk25Ref, + TxTCLK, + Clk120MHz, +} + +impl From for u8 { + fn from(val: LedFunc) -> Self { + val as u8 + } +} + +impl From for LedFunc { + fn from(value: u8) -> Self { + match value { + 0 => LedFunc::LinkupTxRxActicity, + 1 => LedFunc::LinkupTxActicity, + 2 => LedFunc::LinkupRxActicity, + 3 => LedFunc::LinkupOnly, + 4 => LedFunc::TxRxActivity, + 5 => LedFunc::TxActivity, + 6 => LedFunc::RxActivity, + 7 => LedFunc::LinkupRxEr, + 8 => LedFunc::LinkupRxTxEr, + 9 => LedFunc::RxEr, + 10 => LedFunc::RxTxEr, + 11 => LedFunc::TxSop, + 12 => LedFunc::RxSop, + 13 => LedFunc::On, + 14 => LedFunc::Off, + 15 => LedFunc::Blink, + 16 => LedFunc::TxLevel2P4, + 17 => LedFunc::TxLevel1P0, + 18 => LedFunc::Master, + 19 => LedFunc::Slave, + 20 => LedFunc::IncompatiableLinkCfg, + 21 => LedFunc::AnLinkGood, + 22 => LedFunc::AnComplete, + 23 => LedFunc::TsTimer, + 24 => LedFunc::LocRcvrStatus, + 25 => LedFunc::RemRcvrStatus, + 26 => LedFunc::Clk25Ref, + 27 => LedFunc::TxTCLK, + 28 => LedFunc::Clk120MHz, + e => panic!("Invalid value {e}"), + } + } +} + +/// LED Control Register +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct LedCntrl(pub u16); +bitfield_bitrange! {struct LedCntrl(u16)} + +impl LedCntrl { + bitfield_fields! { + u8; + /// LED_0 Pin Function + pub from into LedFunc, led0_function, set_led0_function: 4, 0; + /// LED 0 Mode Selection + pub led0_mode, set_led0_mode: 5; + /// Qualify Certain LED 0 Options with Link Status. + pub led0_link_st_qualify, set_led0_link_st_qualify: 6; + /// LED 0 Enable + pub led0_en, set_led0_en: 7; + /// LED_1 Pin Function + pub from into LedFunc, led1_function, set_led1_function: 12, 8; + /// /// LED 1 Mode Selection + pub led1_mode, set_led1_mode: 13; + /// Qualify Certain LED 1 Options with Link Status. + pub led1_link_st_qualify, set_led1_link_st_qualify: 14; + /// LED 1 Enable + pub led1_en, set_led1_en: 15; + } + + pub fn new() -> Self { + LedCntrl(0) + } +} + +// #[allow(dead_code)] +#[repr(u8)] +pub enum LedPol { + AutoSense = 0, + ActiveHigh, + ActiveLow, +} + +impl From for u8 { + fn from(val: LedPol) -> Self { + val as u8 + } +} + +impl From for LedPol { + fn from(value: u8) -> Self { + match value { + 0 => LedPol::AutoSense, + 1 => LedPol::ActiveHigh, + 2 => LedPol::ActiveLow, + e => panic!("Invalid value {e}"), + } + } +} + +/// LED Control Register +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct LedPolarity(pub u16); +bitfield_bitrange! {struct LedPolarity(u16)} + +impl LedPolarity { + bitfield_fields! { + u8; + /// LED 1 Polarity + pub from into LedPol, led1_polarity, set_led1_polarity: 3, 2; + /// LED_0 Polarity + pub from into LedPol, led0_polarity, set_led0_polarity: 1, 0; + } +} + +/// LED Control Register +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct SpiHeader(pub u16); +bitfield_bitrange! {struct SpiHeader(u16)} + +impl SpiHeader { + bitfield_fields! { + u16; + /// Mask Bit for TXF_ECC_ERR + pub control, set_control : 15; + pub full_duplex, set_full_duplex : 14; + pub write, set_write : 13; + /// LED_0 Polarity + pub from into SpiRegisters, addr, set_addr: 11, 0; + } +} From 2cf6a5911408ff0a666f915e32fac7bc6b9fb5d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Thu, 24 Aug 2023 00:45:15 +0200 Subject: [PATCH 002/233] stm32l4: Add EVAL-ADIN1110EBZ example with basic http server Page show the current temperature and auto refresh every 1s. --- examples/stm32l4/.cargo/config.toml | 2 +- examples/stm32l4/Cargo.toml | 12 +- .../src/bin/spe_adin1110_http_server.rs | 438 ++++++++++++++++++ 3 files changed, 449 insertions(+), 3 deletions(-) create mode 100644 examples/stm32l4/src/bin/spe_adin1110_http_server.rs diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml index 36e74e5a..db3a7cef 100644 --- a/examples/stm32l4/.cargo/config.toml +++ b/examples/stm32l4/.cargo/config.toml @@ -2,7 +2,7 @@ # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` #runner = "probe-rs run --chip STM32L475VGT6" #runner = "probe-rs run --chip STM32L475VG" -runner = "probe-rs run --chip STM32L4S5VI" +runner = "probe-run --chip STM32L4S5QI" [build] target = "thumbv7em-none-eabi" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index f552a610..e5be94ed 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -6,12 +6,17 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "memory-x", "time-driver-any", "exti", "unstable-traits", "chrono"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "unstable-traits", "chrono"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-net-adin1110 = { version = "0.1.0", path = "../../embassy-net-adin1110", default-features = false } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "udp", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } +embedded-io-async = { version = "0.5.0", features = ["defmt-03"] } +embedded-io = { version = "0.5.0", features = ["defmt-03"] } defmt = "0.3" defmt-rtt = "0.4" @@ -21,10 +26,13 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" } +embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] } panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } chrono = { version = "^0.4", default-features = false } +rand = { version = "0.8.5", default-features = false } +static_cell = {version = "1.1", features = ["nightly"]} micromath = "2.0.0" diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs new file mode 100644 index 00000000..148c5877 --- /dev/null +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -0,0 +1,438 @@ +#![deny(clippy::pedantic)] +#![allow(clippy::doc_markdown)] +#![no_main] +#![no_std] +// Needed unitl https://github.com/rust-lang/rust/issues/63063 is stablised. +#![feature(type_alias_impl_trait)] +#![feature(associated_type_bounds)] +#![allow(clippy::missing_errors_doc)] + +// This example works on a ANALOG DEVICE EVAL-ADIN110EBZ board. +// Settings switch S201 "HW CFG": +// - Without SPI CRC: OFF-ON-OFF-OFF-OFF +// - With SPI CRC: ON -ON-OFF-OFF-OFF +// Settings switch S303 "uC CFG": CFG0: On = static ip, Off = Dhcp +// The webserver shows the actual temperature of the onboard i2c temp sensor. + +use core::marker::PhantomData; +use core::sync::atomic::{AtomicI32, Ordering}; + +use defmt::{error, info, println, unwrap, Format}; +use defmt_rtt as _; // global logger +use embassy_executor::Spawner; +use embassy_futures::select::{select, Either}; +use embassy_futures::yield_now; +use embassy_net::tcp::TcpSocket; +use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; +use embassy_time::{Delay, Duration, Ticker, Timer}; +use embedded_hal_async::i2c::I2c as I2cBus; +use embedded_io::Write as bWrite; +use embedded_io_async::Write; +use hal::gpio::{Input, Level, Output, Speed}; +use hal::i2c::{self, I2c}; +use hal::rcc::{self}; +use hal::rng::{self, Rng}; +use hal::{bind_interrupts, exti, pac, peripherals}; +use heapless::Vec; +use rand::RngCore; +use static_cell::make_static; +use {embassy_stm32 as hal, panic_probe as _}; + +bind_interrupts!(struct Irqs { + I2C3_EV => i2c::InterruptHandler; + RNG => rng::InterruptHandler; +}); + +use embassy_net_adin1110::{self, Device, Runner, ADIN1110}; +use embedded_hal_bus::spi::ExclusiveDevice; +use hal::gpio::Pull; +use hal::i2c::Config as I2C_Config; +use hal::rcc::{ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv}; +use hal::spi::{Config as SPI_Config, Spi}; +use hal::time::Hertz; + +// Basic settings +// MAC-address used by the adin1110 +const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; +// Static IP settings +const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24); +// Listen port for the webserver +const HTTP_LISTEN_PORT: u16 = 80; + +pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>; +pub type SpeSpiCs = ExclusiveDevice, Delay>; +pub type SpeInt = exti::ExtiInput<'static, peripherals::PB11>; +pub type SpeRst = Output<'static, peripherals::PC7>; +pub type Adin1110T = ADIN1110; +pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>; + +static TEMP: AtomicI32 = AtomicI32::new(0); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + defmt::println!("Start main()"); + + let mut config = embassy_stm32::Config::default(); + + // 80Mhz clock (Source: 8 / SrcDiv: 1 * PLLMul 20 / ClkDiv 2) + // 80MHz highest frequency for flash 0 wait. + config.rcc.mux = ClockSrc::PLL( + PLLSource::HSE(Hertz(8_000_000)), + PLLClkDiv::Div2, + PLLSrcDiv::Div1, + PLLMul::Mul20, + None, + ); + config.rcc.hsi48 = true; // needed for rng + config.rcc.rtc_mux = rcc::RtcClockSource::LSI32; + + let dp = embassy_stm32::init(config); + + // RM0432rev9, 5.1.2: Independent I/O supply rail + // After reset, the I/Os supplied by VDDIO2 are logically and electrically isolated and + // therefore are not available. The isolation must be removed before using any I/O from + // PG[15:2], by setting the IOSV bit in the PWR_CR2 register, once the VDDIO2 supply is present + pac::PWR.cr2().modify(|w| w.set_iosv(true)); + + let reset_status = pac::RCC.bdcr().read().0; + defmt::println!("bdcr before: 0x{:X}", reset_status); + + defmt::println!("Setup IO pins"); + + // Setup LEDs + let _led_uc1_green = Output::new(dp.PC13, Level::Low, Speed::Low); + let mut led_uc2_red = Output::new(dp.PE2, Level::High, Speed::Low); + let led_uc3_yellow = Output::new(dp.PE6, Level::High, Speed::Low); + let led_uc4_blue = Output::new(dp.PG15, Level::High, Speed::Low); + + // Read the uc_cfg switches + let uc_cfg0 = Input::new(dp.PB2, Pull::None); + let _uc_cfg1 = Input::new(dp.PF11, Pull::None); + let _uc_cfg2 = Input::new(dp.PG6, Pull::None); + let _uc_cfg3 = Input::new(dp.PG11, Pull::None); + + // Setup I2C pins + let temp_sens_i2c = I2c::new( + dp.I2C3, + dp.PG7, + dp.PG8, + Irqs, + dp.DMA1_CH6, + dp.DMA1_CH7, + Hertz(100_000), + I2C_Config::default(), + ); + + // Setup IO and SPI for the SPE chip + let spe_reset_n = Output::new(dp.PC7, Level::Low, Speed::Low); + let spe_cfg0 = Input::new(dp.PC8, Pull::None); + let spe_cfg1 = Input::new(dp.PC9, Pull::None); + let _spe_ts_capt = Output::new(dp.PC6, Level::Low, Speed::Low); + + let spe_int = Input::new(dp.PB11, Pull::None); + let spe_int = exti::ExtiInput::new(spe_int, dp.EXTI11); + + let spe_spi_cs_n = Output::new(dp.PB12, Level::High, Speed::High); + let spe_spi_sclk = dp.PB13; + let spe_spi_miso = dp.PB14; + let spe_spi_mosi = dp.PB15; + + // Don't turn the clock to high, clock must fit within the system clock as we get a runtime panic. + let mut spi_config = SPI_Config::default(); + spi_config.frequency = Hertz(25_000_000); + + let spe_spi: SpeSpi = Spi::new( + dp.SPI2, + spe_spi_sclk, + spe_spi_mosi, + spe_spi_miso, + dp.DMA1_CH1, + dp.DMA1_CH2, + spi_config, + ); + let spe_spi = SpeSpiCs::new(spe_spi, spe_spi_cs_n, Delay); + + let cfg0_without_crc = spe_cfg0.is_high(); + let cfg1_spi_mode = spe_cfg1.is_high(); + + defmt::println!( + "ADIN1110: CFG SPI-MODE 1-{}, CRC-bit 0-{}", + cfg1_spi_mode, + cfg0_without_crc + ); + + // Check the SPI mode selected with the "HW CFG" dip-switch + if !cfg1_spi_mode { + error!("Driver doesnĀ“t support SPI Protolcol \"OPEN Alliance\".\nplease use the \"Generic SPI\"! Turn On \"HW CFG\": \"SPI_CFG1\""); + loop { + led_uc2_red.toggle(); + Timer::after(Duration::from_hz(10)).await; + } + }; + + let state = make_static!(embassy_net_adin1110::State::<8, 8>::new()); + + let (device, runner) = + embassy_net_adin1110::new(MAC, state, spe_spi, spe_int, spe_reset_n, !cfg0_without_crc).await; + + // Start task blink_led + unwrap!(spawner.spawn(heartbeat_led(led_uc3_yellow))); + // Start task temperature measurement + unwrap!(spawner.spawn(temp_task(temp_sens_i2c, led_uc4_blue))); + // Start ethernet task + unwrap!(spawner.spawn(ethernet_task(runner))); + + let mut rng = Rng::new(dp.RNG, Irqs); + // Generate random seed + let seed = rng.next_u64(); + + let ip_cfg = if uc_cfg0.is_low() { + println!("Waiting for DHCP..."); + let dhcp4_config = embassy_net::DhcpConfig::default(); + embassy_net::Config::dhcpv4(dhcp4_config) + } else { + embassy_net::Config::ipv4_static(StaticConfigV4 { + address: IP_ADDRESS, + gateway: None, + dns_servers: Vec::new(), + }) + }; + + // Init network stack + let stack = &*make_static!(Stack::new( + device, + ip_cfg, + make_static!(StackResources::<2>::new()), + seed + )); + + // Launch network task + unwrap!(spawner.spawn(net_task(stack))); + + let cfg = wait_for_config(stack).await; + let local_addr = cfg.address.address(); + + // Then we can use it! + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; + let mut mb_buf = [0; 4096]; + loop { + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(1))); + + info!("Listening on http://{}:{}...", local_addr, HTTP_LISTEN_PORT); + if let Err(e) = socket.accept(HTTP_LISTEN_PORT).await { + defmt::error!("accept error: {:?}", e); + continue; + } + + loop { + let _n = match socket.read(&mut mb_buf).await { + Ok(0) => { + defmt::info!("read EOF"); + break; + } + Ok(n) => n, + Err(e) => { + defmt::error!("{:?}", e); + break; + } + }; + led_uc2_red.set_low(); + + let status_line = "HTTP/1.1 200 OK"; + let contents = PAGE; + let length = contents.len(); + + let _ = write!( + &mut mb_buf[..], + "{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}\r\n\0" + ); + let loc = mb_buf.iter().position(|v| *v == b'#').unwrap(); + + let temp = TEMP.load(Ordering::Relaxed); + let cel = temp / 1000; + let mcel = temp % 1000; + + info!("{}.{}", cel, mcel); + + let _ = write!(&mut mb_buf[loc..loc + 7], "{cel}.{mcel}"); + + let n = mb_buf.iter().position(|v| *v == 0).unwrap(); + + if let Err(e) = socket.write_all(&mb_buf[..n]).await { + error!("write error: {:?}", e); + break; + } + + led_uc2_red.set_high(); + } + } +} + +async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { + loop { + if let Some(config) = stack.config_v4() { + return config; + } + yield_now().await; + } +} + +#[embassy_executor::task] +async fn heartbeat_led(mut led: Output<'static, peripherals::PE6>) { + let mut tmr = Ticker::every(Duration::from_hz(3)); + loop { + led.toggle(); + tmr.next().await; + } +} + +// ADT7422 +#[embassy_executor::task] +async fn temp_task(temp_dev_i2c: TempSensI2c, mut led: Output<'static, peripherals::PG15>) -> ! { + let mut tmr = Ticker::every(Duration::from_hz(1)); + let mut temp_sens = ADT7422::new(temp_dev_i2c, 0x48).unwrap(); + + loop { + led.set_low(); + match select(temp_sens.read_temp(), Timer::after(Duration::from_millis(500))).await { + Either::First(i2c_ret) => match i2c_ret { + Ok(value) => { + led.set_high(); + let temp = i32::from(value); + println!("TEMP: {:04x}, {}", temp, temp * 78 / 10); + TEMP.store(temp * 78 / 10, Ordering::Relaxed); + } + Err(e) => defmt::println!("ADT7422: {}", e), + }, + Either::Second(_) => println!("Timeout"), + } + + tmr.next().await; + } +} + +#[embassy_executor::task] +async fn ethernet_task(runner: Runner<'static, SpeSpiCs, SpeInt, SpeRst>) -> ! { + runner.run().await +} + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack>) -> ! { + stack.run().await +} + +// same panicking *behavior* as `panic-probe` but doesn't print a panic message +// this prevents the panic message being printed *twice* when `defmt::panic` is invoked +#[defmt::panic_handler] +fn panic() -> ! { + cortex_m::asm::udf() +} + +#[allow(non_camel_case_types)] +#[repr(C)] +pub enum Registers { + Temp_MSB = 0x00, + Temp_LSB, + Status, + Cfg, + T_HIGH_MSB, + T_HIGH_LSB, + T_LOW_MSB, + T_LOW_LSB, + T_CRIT_MSB, + T_CRIT_LSB, + T_HYST, + ID, + SW_RESET = 0x2F, +} + +pub struct ADT7422<'d, BUS: I2cBus> { + addr: u8, + phantom: PhantomData<&'d ()>, + bus: BUS, +} + +#[derive(Debug, Format)] +pub enum Error { + I2c(I2cError), + Address, +} + +impl<'d, BUS> ADT7422<'d, BUS> +where + BUS: I2cBus, + BUS::Error: Format, +{ + pub fn new(bus: BUS, addr: u8) -> Result> { + if !(0x48..=0x4A).contains(&addr) { + return Err(Error::Address); + } + + Ok(Self { + bus, + phantom: PhantomData, + addr, + }) + } + + pub async fn init(&mut self) -> Result<(), Error> { + let mut cfg = 0b000_0000; + // if self.int.is_some() { + // // Set 1 SPS mode + // cfg |= 0b10 << 5; + // } else { + // One shot mode + cfg |= 0b01 << 5; + // } + + self.write_cfg(cfg).await + } + + pub async fn read(&mut self, reg: Registers) -> Result> { + let mut buffer = [0u8; 1]; + self.bus + .write_read(self.addr, &[reg as u8], &mut buffer) + .await + .map_err(Error::I2c)?; + Ok(buffer[0]) + } + + pub async fn write_cfg(&mut self, cfg: u8) -> Result<(), Error> { + let buf = [Registers::Cfg as u8, cfg]; + self.bus.write(self.addr, &buf).await.map_err(Error::I2c) + } + + pub async fn read_temp(&mut self) -> Result> { + let mut buffer = [0u8; 2]; + + // if let Some(int) = &mut self.int { + // // Wait for interrupt + // int.wait_for_low().await.unwrap(); + // } else { + // Start: One shot + let cfg = 0b01 << 5; + self.write_cfg(cfg).await?; + Timer::after(Duration::from_millis(250)).await; + self.bus + .write_read(self.addr, &[Registers::Temp_MSB as u8], &mut buffer) + .await + .map_err(Error::I2c)?; + Ok(i16::from_be_bytes(buffer)) + } +} + +// Web page +const PAGE: &str = r#" + + + + + ADIN1110 with Rust + + +

EVAL-ADIN1110EBZ

+
Temp Sensor ADT7422: #00.00 °C
+ +"#; From 577d644e2272efc81ae452aa0af9ca092b71fbd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Fri, 18 Aug 2023 00:46:58 +0200 Subject: [PATCH 003/233] fix warning --- embassy-net-adin1110/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index a4010d25..4ce8a189 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -508,17 +508,20 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { } if status0.phyint() { + #[cfg_attr(not(feature = "defmt"), allow(unused_variables))] let crsm_irq_st = self .mac .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::CRSM_IRQ_STATUS.into()) .await .unwrap(); + #[cfg_attr(not(feature = "defmt"), allow(unused_variables))] let phy_irq_st = self .mac .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1F::PHY_SYBSYS_IRQ_STATUS.into()) .await .unwrap(); + #[cfg(feature = "defmt")] defmt::warn!( "SPE CHIP PHY CRSM_IRQ_STATUS {:04x} PHY_SUBSYS_IRQ_STATUS {:04x}", From 46ddf7013a426f67eb737ae8436d1032a3ec9d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Fri, 18 Aug 2023 23:08:51 +0200 Subject: [PATCH 004/233] update README.md after review --- embassy-net-adin1110/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/embassy-net-adin1110/README.md b/embassy-net-adin1110/README.md index 9b7b4e0e..3c280418 100644 --- a/embassy-net-adin1110/README.md +++ b/embassy-net-adin1110/README.md @@ -4,18 +4,18 @@ ## What is SPE or Single Pair Ethernet / 10 BASE-T1L -SPE is Single Pair Ethernet, what the names implies, it uses a single twisted/differancial pair (only 2 wires) to transmit ethernet packet in full-duplex. -SPE is still ethernet, only the phissical layer is different. +SPE stands for Single Pair Ethernet. As the names implies, SPE uses differential signalling with 2 wires (a twisted-pair) in a cable as the physical medium. +SPE is full-duplex - it can transmit and receive ethernet packets at the same time. SPE is still ethernet, only the physical layer is different. -SPE also supports [`PoDL(Power over Data Line)`](https://www.ti.com/lit/an/snla395/snla395.pdf), power delivery from 0.5 up to 50 Watts, similair to [`PoE`](https://en.wikipedia.org/wiki/Power_over_Ethernet), but additional hardware and handshake protocol is needed. +SPE also supports [`PoDL (Power over Data Line)`](https://www.ti.com/lit/an/snla395/snla395.pdf), power delivery from 0.5 up to 50 Watts, similar to [`PoE`](https://en.wikipedia.org/wiki/Power_over_Ethernet), but an additional hardware and handshake protocol are needed. -SPE has many link speeds but only `10 BASE-T1L` is able to reach cable length up to 1000 meters in `2.4 Vpp` transmit amplitude. -Currently in 2023, none of the standards are compatiable with eachother. -So `10 BASE-T1L` don't work with a `10 BASE-T1S` or `100 BASE-T1`. +SPE has many link speeds but only `10 BASE-T1L` is able to reach cable lengths up to 1000 meters in `2.4 Vpp` transmit amplitude. +Currently in 2023, none of the standards are compatible with each other. +Thus `10 BASE-T1L` won't work with a `10 BASE-T1S`, `100 BASE-T1` or any standard `x BASE-T`. -In the industry SPE is also called [`APL(Advanced Physical Layer)`](https://www.ethernet-apl.org), it is based on the `10 BASE-T1L` standard. +In the industry SPE is also called [`APL (Advanced Physical Layer)`](https://www.ethernet-apl.org), and is based on the `10 BASE-T1L` standard. -APL can be use in [`intrinsic safety applications/explosion hazardous areas`](https://en.wikipedia.org/wiki/Electrical_equipment_in_hazardous_areas) which has it's own name and standard [`2-WISE(2-wire intrinsically safe ethernet) IEC TS 60079-47:2021`](https://webstore.iec.ch/publication/64292). +APL can be used in [`intrinsic safety applications/explosion hazardous areas`](https://en.wikipedia.org/wiki/Electrical_equipment_in_hazardous_areas) which has its own name and standard called [`2-WISE (2-wire intrinsically safe ethernet) IEC TS 60079-47:2021`](https://webstore.iec.ch/publication/64292). `10 BASE-T1L` and `ADIN1110` are designed to support intrinsic safety applications. The power supply energy is fixed and PDoL is not supported. @@ -30,8 +30,8 @@ Currently only `Generic` SPI with or without CRC is supported. ## Hardware -- Testen on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with a `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) example. -- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit`](https://www.sparkfun.com/products/19628), the kit supports multiple microcontrollers, please check if get the right microcontroller that is supported by Embassy! +- Tested on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with an `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) dor an example. +- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit`](https://www.sparkfun.com/products/19628), supporting multiple microcontrollers. **Make sure to check if it's a microcontroller that is supported by Embassy!** ## Other SPE chips @@ -40,7 +40,7 @@ Currently only `Generic` SPI with or without CRC is supported. ## Testing -ADIN1110 library can tested on the host with a mock SPI driver +ADIN1110 library can tested on the host with a mock SPI driver. $ `cargo test --target x86_64-unknown-linux-gnu` From 10bf33dcacd162f0ab92a37bdc439cbac9fa437c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Sun, 20 Aug 2023 16:28:57 +0200 Subject: [PATCH 005/233] Fix linting. I like program with deny(clippy::pedantic) but it was set as allowed, so I did get less linting errors/hints. Now it is corrected and also fix the lint errors and hints. Also fixes some comment and demagic some values. Rename `FEC` to more appropriate name `FSC`. --- embassy-net-adin1110/src/crc32.rs | 68 +++++++-------- embassy-net-adin1110/src/lib.rs | 138 ++++++++++++++++-------------- embassy-net-adin1110/src/mdio.rs | 13 +-- embassy-net-adin1110/src/phy.rs | 14 +-- embassy-net-adin1110/src/regs.rs | 15 ++-- 5 files changed, 128 insertions(+), 120 deletions(-) diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs index 75a7d65b..906c9aad 100644 --- a/embassy-net-adin1110/src/crc32.rs +++ b/embassy-net-adin1110/src/crc32.rs @@ -1,33 +1,33 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [ - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, - 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, - 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, - 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, - 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, - 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, - 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, - 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, - 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, - 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, - 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, - 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, - 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, - 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, - 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, - 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, - 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, - 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, - 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, - 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, - 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, - 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, + 0x0000_0000, 0x7707_3096, 0xEE0E_612C, 0x9909_51BA, 0x076D_C419, 0x706A_F48F, 0xE963_A535, 0x9E64_95A3, 0x0EDB_8832, + 0x79DC_B8A4, 0xE0D5_E91E, 0x97D2_D988, 0x09B6_4C2B, 0x7EB1_7CBD, 0xE7B8_2D07, 0x90BF_1D91, 0x1DB7_1064, 0x6AB0_20F2, + 0xF3B9_7148, 0x84BE_41DE, 0x1ADA_D47D, 0x6DDD_E4EB, 0xF4D4_B551, 0x83D3_85C7, 0x136C_9856, 0x646B_A8C0, 0xFD62_F97A, + 0x8A65_C9EC, 0x1401_5C4F, 0x6306_6CD9, 0xFA0F_3D63, 0x8D08_0DF5, 0x3B6E_20C8, 0x4C69_105E, 0xD560_41E4, 0xA267_7172, + 0x3C03_E4D1, 0x4B04_D447, 0xD20D_85FD, 0xA50A_B56B, 0x35B5_A8FA, 0x42B2_986C, 0xDBBB_C9D6, 0xACBC_F940, 0x32D8_6CE3, + 0x45DF_5C75, 0xDCD6_0DCF, 0xABD1_3D59, 0x26D9_30AC, 0x51DE_003A, 0xC8D7_5180, 0xBFD0_6116, 0x21B4_F4B5, 0x56B3_C423, + 0xCFBA_9599, 0xB8BD_A50F, 0x2802_B89E, 0x5F05_8808, 0xC60C_D9B2, 0xB10B_E924, 0x2F6F_7C87, 0x5868_4C11, 0xC161_1DAB, + 0xB666_2D3D, 0x76DC_4190, 0x01DB_7106, 0x98D2_20BC, 0xEFD5_102A, 0x71B1_8589, 0x06B6_B51F, 0x9FBF_E4A5, 0xE8B8_D433, + 0x7807_C9A2, 0x0F00_F934, 0x9609_A88E, 0xE10E_9818, 0x7F6A_0DBB, 0x086D_3D2D, 0x9164_6C97, 0xE663_5C01, 0x6B6B_51F4, + 0x1C6C_6162, 0x8565_30D8, 0xF262_004E, 0x6C06_95ED, 0x1B01_A57B, 0x8208_F4C1, 0xF50F_C457, 0x65B0_D9C6, 0x12B7_E950, + 0x8BBE_B8EA, 0xFCB9_887C, 0x62DD_1DDF, 0x15DA_2D49, 0x8CD3_7CF3, 0xFBD4_4C65, 0x4DB2_6158, 0x3AB5_51CE, 0xA3BC_0074, + 0xD4BB_30E2, 0x4ADF_A541, 0x3DD8_95D7, 0xA4D1_C46D, 0xD3D6_F4FB, 0x4369_E96A, 0x346E_D9FC, 0xAD67_8846, 0xDA60_B8D0, + 0x4404_2D73, 0x3303_1DE5, 0xAA0A_4C5F, 0xDD0D_7CC9, 0x5005_713C, 0x2702_41AA, 0xBE0B_1010, 0xC90C_2086, 0x5768_B525, + 0x206F_85B3, 0xB966_D409, 0xCE61_E49F, 0x5EDE_F90E, 0x29D9_C998, 0xB0D0_9822, 0xC7D7_A8B4, 0x59B3_3D17, 0x2EB4_0D81, + 0xB7BD_5C3B, 0xC0BA_6CAD, 0xEDB8_8320, 0x9ABF_B3B6, 0x03B6_E20C, 0x74B1_D29A, 0xEAD5_4739, 0x9DD2_77AF, 0x04DB_2615, + 0x73DC_1683, 0xE363_0B12, 0x9464_3B84, 0x0D6D_6A3E, 0x7A6A_5AA8, 0xE40E_CF0B, 0x9309_FF9D, 0x0A00_AE27, 0x7D07_9EB1, + 0xF00F_9344, 0x8708_A3D2, 0x1E01_F268, 0x6906_C2FE, 0xF762_575D, 0x8065_67CB, 0x196C_3671, 0x6E6B_06E7, 0xFED4_1B76, + 0x89D3_2BE0, 0x10DA_7A5A, 0x67DD_4ACC, 0xF9B9_DF6F, 0x8EBE_EFF9, 0x17B7_BE43, 0x60B0_8ED5, 0xD6D6_A3E8, 0xA1D1_937E, + 0x38D8_C2C4, 0x4FDF_F252, 0xD1BB_67F1, 0xA6BC_5767, 0x3FB5_06DD, 0x48B2_364B, 0xD80D_2BDA, 0xAF0A_1B4C, 0x3603_4AF6, + 0x4104_7A60, 0xDF60_EFC3, 0xA867_DF55, 0x316E_8EEF, 0x4669_BE79, 0xCB61_B38C, 0xBC66_831A, 0x256F_D2A0, 0x5268_E236, + 0xCC0C_7795, 0xBB0B_4703, 0x2202_16B9, 0x5505_262F, 0xC5BA_3BBE, 0xB2BD_0B28, 0x2BB4_5A92, 0x5CB3_6A04, 0xC2D7_FFA7, + 0xB5D0_CF31, 0x2CD9_9E8B, 0x5BDE_AE1D, 0x9B64_C2B0, 0xEC63_F226, 0x756A_A39C, 0x026D_930A, 0x9C09_06A9, 0xEB0E_363F, + 0x7207_6785, 0x0500_5713, 0x95BF_4A82, 0xE2B8_7A14, 0x7BB1_2BAE, 0x0CB6_1B38, 0x92D2_8E9B, 0xE5D5_BE0D, 0x7CDC_EFB7, + 0x0BDB_DF21, 0x86D3_D2D4, 0xF1D4_E242, 0x68DD_B3F8, 0x1FDA_836E, 0x81BE_16CD, 0xF6B9_265B, 0x6FB0_77E1, 0x18B7_4777, + 0x8808_5AE6, 0xFF0F_6A70, 0x6606_3BCA, 0x1101_0B5C, 0x8F65_9EFF, 0xF862_AE69, 0x616B_FFD3, 0x166C_CF45, 0xA00A_E278, + 0xD70D_D2EE, 0x4E04_8354, 0x3903_B3C2, 0xA767_2661, 0xD060_16F7, 0x4969_474D, 0x3E6E_77DB, 0xAED1_6A4A, 0xD9D6_5ADC, + 0x40DF_0B66, 0x37D8_3BF0, 0xA9BC_AE53, 0xDEBB_9EC5, 0x47B2_CF7F, 0x30B5_FFE9, 0xBDBD_F21C, 0xCABA_C28A, 0x53B3_9330, + 0x24B4_A3A6, 0xBAD0_3605, 0xCDD7_0693, 0x54DE_5729, 0x23D9_67BF, 0xB366_7A2E, 0xC461_4AB8, 0x5D68_1B02, 0x2A6F_2B94, + 0xB40B_BE37, 0xC30C_8EA1, 0x5A05_DF1B, 0x2D02_EF8D, ]; #[allow(non_camel_case_types)] @@ -35,9 +35,9 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [ pub struct ETH_FSC(pub u32); impl ETH_FSC { - pub const CRC32_OK: u32 = 0x2144df1c; + pub const CRC32_OK: u32 = 0x2144_df1c; - pub fn new(data: &[u8]) -> Self { + #[must_use] pub fn new(data: &[u8]) -> Self { let fsc = data.iter().fold(u32::MAX, |crc, byte| { let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte; CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8) @@ -45,15 +45,15 @@ impl ETH_FSC { Self(fsc) } - pub fn crc_ok(&self) -> bool { + #[must_use] pub fn crc_ok(&self) -> bool { self.0 == Self::CRC32_OK } - pub fn hton_bytes(&self) -> [u8; 4] { + #[must_use] pub fn hton_bytes(&self) -> [u8; 4] { self.0.to_le_bytes() } - pub fn hton(&self) -> u32 { + #[must_use] pub fn hton(&self) -> u32 { self.0.to_le() } } diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 4ce8a189..c7464893 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -1,16 +1,10 @@ -#![allow(clippy::pedantic)] +#![deny(clippy::pedantic)] #![feature(type_alias_impl_trait)] #![feature(async_fn_in_trait)] #![cfg_attr(not(any(test, feature = "std")), no_std)] - -use ch::driver::LinkState; -use embassy_futures::select::{select, Either}; -use embassy_net_driver_channel as ch; -use embassy_time::{Duration, Timer}; -use embedded_hal_1::digital::OutputPin; -use embedded_hal_async::digital::Wait; -use embedded_hal_async::spi::{Operation, SpiDevice}; -use heapless::Vec; +#![allow(clippy::module_name_repetitions)] +#![allow(clippy::missing_errors_doc)] +#![allow(clippy::missing_panics_doc)] mod crc32; mod crc8; @@ -18,15 +12,23 @@ mod mdio; mod phy; mod regs; +use ch::driver::LinkState; pub use crc32::ETH_FSC; use crc8::crc8; +use embassy_futures::select::{select, Either}; +use embassy_net_driver_channel as ch; +use embassy_time::{Duration, Timer}; +use embedded_hal_1::digital::OutputPin; +use embedded_hal_async::digital::Wait; +use embedded_hal_async::spi::{Operation, SpiDevice}; +use heapless::Vec; pub use mdio::MdioBus; pub use phy::{Phy10BaseT1x, RegsC22, RegsC45}; pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1}; use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader}; -pub const PHYID: u32 = 0x0283BC91; +pub const PHYID: u32 = 0x0283_BC91; /// Error values ADIN1110 #[derive(Debug)] @@ -44,21 +46,28 @@ pub enum AdinError { pub type AEResult = core::result::Result>; pub const MDIO_PHY_ADDR: u8 = 0x01; -pub const MTU: usize = 1500; + +/// Maximum Transmission Unit +pub const MTU: usize = 1514; + /// Max SPI/Frame buffer size pub const MAX_BUFF: usize = 2048; const DONT_CARE_BYTE: u8 = 0x00; const TURN_AROUND_BYTE: u8 = 0x00; -const FEC_LEN: usize = 4; +/// Packet minimal frame/packet length +const ETH_MIN_LEN: usize = 64; + +/// Ethernet `Frame Check Sequence` length +const FSC_LEN: usize = 4; const FRAME_HEADER_LEN: usize = 2; const WR_HEADER_LEN: usize = 2; // P1 = 0x00, P2 = 0x01 const PORT_ID_BYTE: u8 = 0x00; -pub type Packet = Vec; +pub type Packet = Vec; /// Type alias for the embassy-net driver for ADIN1110 pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; @@ -69,6 +78,7 @@ pub struct State { } impl State { /// Create a new `State`. + #[must_use] pub const fn new() -> Self { Self { ch_state: ch::State::new(), @@ -81,11 +91,11 @@ pub struct ADIN1110 { /// SPI bus spi: SPI, /// Enable CRC on SPI transfer. - /// This must match with the hardware pin SPI_CFG0 were 0 = CRC enable, 1 CRC disabled. + /// This must match with the hardware pin `SPI_CFG0` were low = CRC enable, high = CRC disabled. crc: bool, } -// Round size up the N u32; +/// Round size up the N u32; pub(crate) fn size_align_u32(size: u32) -> u32 { (size + 3) & 0xFFFF_FFFC } @@ -166,7 +176,7 @@ where self.spi.write(&tx_buf).await.map_err(AdinError::Spi) } - // helper function for write to MDIO_ACC register and wait for ready! + /// helper function for write to `MDIO_ACC` register and wait for ready! async fn write_mdio_acc_reg(&mut self, mdio_acc_val: u32) -> AEResult { self.write_reg(sr::MDIO_ACC, mdio_acc_val).await?; @@ -181,6 +191,7 @@ where Err(AdinError::MDIO_ACC_TIMEOUT) } + /// Read out fifo ethernet packet memory received via the wire. pub async fn read_fifo(&mut self, packet: &mut [u8]) -> AEResult { let mut tx_buf = Vec::::new(); @@ -190,7 +201,7 @@ where // Packet read of write to the MAC packet buffer must be a multipul of 4! let read_size = size_align_u32(packet_size); - if packet_size < u32::try_from(FRAME_HEADER_LEN + FEC_LEN).unwrap() + if packet_size < u32::try_from(FRAME_HEADER_LEN + FSC_LEN).unwrap() || read_size > u32::try_from(packet.len()).unwrap() { return Err(AdinError::PACKET_TOO_BIG); @@ -226,11 +237,9 @@ where Ok(packet_size as usize) } + /// Write to fifo ethernet packet memory send over the wire. pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SpiE> { let header_len = self.header_write_len(); - // if packet.len() < header_len { - // return Err(AdinError::PACKET_TOO_SMALL); - // } let mut packet = Packet::new(); @@ -244,37 +253,33 @@ where .map_err(|_| AdinError::PACKET_TOO_BIG)?; if self.crc { - assert_eq!(header_len, 5); // Add CRC for header data packet .push(crc8(&packet[0..2])) .map_err(|_| AdinError::PACKET_TOO_BIG)?; } - // Add port number - // packet[header_len - FRAME_HEADER_LEN..header_len] - // .copy_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice()); + // Add port number, ADIN1110 its fixed to zero/P1, but for ADIN2111 has two ports. packet .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice()) .map_err(|_| AdinError::PACKET_TOO_BIG)?; + // Copy packet data to spi buffer. packet.extend_from_slice(frame).map_err(|_| AdinError::PACKET_TOO_BIG)?; - // Pad data up to 64 - for _ in packet.len()..(64 - FEC_LEN + header_len) { + // Pad data up to ETH_MIN_LEN - FCS_LEN + for _ in packet.len()..(ETH_MIN_LEN - FSC_LEN + header_len) { let _ = packet.push(0x00); } - // // add ethernet crc32 + // add ethernet FCS only over the ethernet packet. let crc = ETH_FSC::new(&packet[header_len..]); let _ = packet.extend_from_slice(crc.hton_bytes().as_slice()); - let crc = ETH_FSC::new(&packet[header_len..]); - assert!(crc.crc_ok()); + let send_len = + u32::try_from(packet.len() - header_len + FRAME_HEADER_LEN).map_err(|_| AdinError::PACKET_TOO_BIG)?; - let send_len = packet.len() - header_len + FRAME_HEADER_LEN; - - // Packet read of write to the MAC packet buffer must be a multipul of 4! + // Packet read of write to the MAC packet buffer must be a multipul of 4 bytes! while packet.len() & 0x3 != 0 { let _ = packet.push(DONT_CARE_BYTE); } @@ -288,7 +293,7 @@ where send_len, ); - self.write_reg(sr::TX_FSIZE, send_len as u32).await?; + self.write_reg(sr::TX_FSIZE, send_len).await?; // Spi packet must be half word / even length if send_len & 1 != 0 { @@ -346,17 +351,21 @@ where let mdio_acc_val: u32 = (0x1 << 28) | u32::from(phy_id & 0x1F) << 21 | u32::from(reg & 0x1F) << 16 | (0x3 << 26); + // Result is in the lower half of the answer. + #[allow(clippy::cast_possible_truncation)] self.write_mdio_acc_reg(mdio_acc_val).await.map(|val| val as u16) } /// Read from the PHY Registers as Clause 45. async fn read_cl45(&mut self, phy_id: u8, regc45: (u8, u16)) -> Result { - let mdio_acc_val: u32 = u32::from(phy_id & 0x1F) << 21 | u32::from(regc45.0 & 0x1F) << 16 | u32::from(regc45.1); + let mdio_acc_val = u32::from(phy_id & 0x1F) << 21 | u32::from(regc45.0 & 0x1F) << 16 | u32::from(regc45.1); self.write_mdio_acc_reg(mdio_acc_val).await?; - let mdio_acc_val: u32 = u32::from(phy_id & 0x1F) << 21 | u32::from(regc45.0 & 0x1F) << 16 | (0x03 << 26); + let mdio_acc_val = u32::from(phy_id & 0x1F) << 21 | u32::from(regc45.0 & 0x1F) << 16 | (0x03 << 26); + // Result is in the lower half of the answer. + #[allow(clippy::cast_possible_truncation)] self.write_mdio_acc_reg(mdio_acc_val).await.map(|val| val as u16) } @@ -394,6 +403,7 @@ pub struct Runner<'d, SPI, INT, RST> { } impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { + #[allow(clippy::too_many_lines)] pub async fn run(mut self) -> ! { loop { let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); @@ -566,6 +576,7 @@ pub async fn new assert_eq!(val, 0x0283BC91), - Err(_e) => panic!("Error:"), - }; + let val = spe.read_reg(sr::PHYID).await.expect("Error"); + assert_eq!(val, 0x0283_BC91); // Read CAPAVILITY - match spe.read_reg(sr::CAPABILITY).await { - Ok(val) => assert_eq!(val, 0x000006C3), - Err(_e) => panic!("Error:"), - }; + let val = spe.read_reg(sr::CAPABILITY).await.expect("Error"); + assert_eq!(val, 0x0000_06C3); spi.done(); } @@ -778,20 +786,16 @@ mod tests { let mut spe = ADIN1110::new(spi_dev, true); - assert_eq!(crc8(0x0283BC91_u32.to_be_bytes().as_slice()), 215); - assert_eq!(crc8(0x000006C3_u32.to_be_bytes().as_slice()), 57); + assert_eq!(crc8(0x0283_BC91_u32.to_be_bytes().as_slice()), 215); + assert_eq!(crc8(0x0000_06C3_u32.to_be_bytes().as_slice()), 57); // Read PHIID - match spe.read_reg(sr::PHYID).await { - Ok(val) => assert_eq!(val, 0x0283BC91), - Err(e) => panic!("Error: {e:?}"), - }; + let val = spe.read_reg(sr::PHYID).await.expect("Error"); + assert_eq!(val, 0x0283_BC91); // Read CAPAVILITY - match spe.read_reg(sr::CAPABILITY).await { - Ok(val) => assert_eq!(val, 0x000006C3), - Err(_e) => panic!("Error:"), - }; + let val = spe.read_reg(sr::CAPABILITY).await.expect("Error"); + assert_eq!(val, 0x0000_06C3); spi.done(); } @@ -885,7 +889,7 @@ mod tests { // ]; // let mut packet = Packet::new(); - // packet.resize(64, 0).unwrap(); + // packet.resize(ETH_MIN_LEN, 0).unwrap(); // for &byte in &packet[4..] { // expectations.push(SpiTransaction::send(byte)); @@ -893,7 +897,7 @@ mod tests { // } // // padding - // for _ in packet.len() as u32..65 { + // for _ in packet.len()..65 { // expectations.push(SpiTransaction::send(0x00)); // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); // } @@ -943,7 +947,7 @@ mod tests { // ]; // let mut packet = Packet::new(); - // packet.resize(64, 0).unwrap(); + // packet.resize(ETH_MIN_LEN, 0).unwrap(); // for &byte in &packet[4..] { // expectations.push(SpiTransaction::send(byte)); @@ -951,7 +955,7 @@ mod tests { // } // // padding - // for _ in packet.len() as u32..64 { + // for _ in packet.len() as u32..ETH_MIN_LEN { // expectations.push(SpiTransaction::send(0x00)); // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); // } @@ -1061,7 +1065,7 @@ mod tests { // } // // padding - // for _ in packet.len() as u32..64 { + // for _ in packet.len()..ETH_MIN_LEN { // expectations.push(SpiTransaction::send(0x00)); // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); // } @@ -1119,7 +1123,7 @@ mod tests { // } // // padding - // for _ in packet.len() as u32..64 { + // for _ in packet.len()..ETH_MIN_LEN { // expectations.push(SpiTransaction::send(0x00)); // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); // } @@ -1176,7 +1180,7 @@ mod tests { // } // // padding - // for _ in packet.len() as u32..64 { + // for _ in packet.len()..ETH_MIN_LEN { // expectations.push(SpiTransaction::send(0x00)); // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); // } @@ -1219,15 +1223,17 @@ mod tests { spi_packet.extend_from_slice(&[160, 49, 143, 0, 0]).unwrap(); // Packet data spi_packet.extend_from_slice(&packet).unwrap(); - // Packet padding up to 60 (64 - FCS) - for _ in packet.len() as u32..60 { + // Packet padding up to 60 (ETH_MIN_LEN - FCS) + for _ in packet.len()..(ETH_MIN_LEN - FSC_LEN) { spi_packet.push(0x00).unwrap(); } // Packet FCS spi_packet.extend_from_slice(&[147, 149, 213, 68]).unwrap(); + let spi_packet_len = u32::try_from(spi_packet.len()).unwrap(); + // SPI HEADER Padding of u32 - for _ in spi_packet.len() as u32..size_align_u32(spi_packet.len() as u32) { + for _ in spi_packet_len..size_align_u32(spi_packet_len) { spi_packet.push(0x00).unwrap(); } @@ -1242,7 +1248,7 @@ mod tests { let mut spe = ADIN1110::new(spi_dev, true); - assert!(spe.write_fifo(&mut packet).await.is_ok()); + assert!(spe.write_fifo(&packet).await.is_ok()); spi.done(); } diff --git a/embassy-net-adin1110/src/mdio.rs b/embassy-net-adin1110/src/mdio.rs index ab7629d3..68477006 100644 --- a/embassy-net-adin1110/src/mdio.rs +++ b/embassy-net-adin1110/src/mdio.rs @@ -32,11 +32,11 @@ enum Reg13Op { PostReadIncAddr = 0b10 << 14, Read = 0b11 << 14, } -/// MdioBus trait -/// Driver needs to implemnt the Claus 22 +/// `MdioBus` trait +/// Driver needs to implement the Clause 22 /// Optional Clause 45 is the device supports this. /// -/// Claus 45 methodes are bases on https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf +/// Claus 45 methodes are bases on pub trait MdioBus { type Error; @@ -52,13 +52,14 @@ pub trait MdioBus { /// Implement this function when your hardware supports it. async fn read_cl45(&mut self, phy_id: PhyAddr, regc45: (u8, RegC45)) -> Result { // Write FN - let val = (Reg13Op::Addr as RegVal) | (regc45.0 & DEV_MASK) as RegVal; + let val = (Reg13Op::Addr as RegVal) | RegVal::from(regc45.0 & DEV_MASK); + self.write_cl22(phy_id, REG13, val).await?; // Write Addr self.write_cl22(phy_id, REG14, regc45.1).await?; // Write FN - let val = (Reg13Op::Read as RegVal) | (regc45.0 & DEV_MASK) as RegVal; + let val = (Reg13Op::Read as RegVal) | RegVal::from(regc45.0 & DEV_MASK); self.write_cl22(phy_id, REG13, val).await?; // Write Addr self.read_cl22(phy_id, REG14).await @@ -69,7 +70,7 @@ pub trait MdioBus { /// Many hardware these days support direct Clause 45 operations. /// Implement this function when your hardware supports it. async fn write_cl45(&mut self, phy_id: PhyAddr, regc45: (u8, RegC45), reg_val: RegVal) -> Result<(), Self::Error> { - let dev_addr = (regc45.0 & DEV_MASK) as RegVal; + let dev_addr = RegVal::from(regc45.0 & DEV_MASK); let reg = regc45.1; // Write FN diff --git a/embassy-net-adin1110/src/phy.rs b/embassy-net-adin1110/src/phy.rs index 78d3fdf7..70060a0c 100644 --- a/embassy-net-adin1110/src/phy.rs +++ b/embassy-net-adin1110/src/phy.rs @@ -30,7 +30,7 @@ pub mod RegsC45 { } impl DA1 { - pub fn into(self) -> (u8, u16) { + #[must_use] pub fn into(self) -> (u8, u16) { (0x01, self as u16) } } @@ -48,7 +48,7 @@ pub mod RegsC45 { } impl DA3 { - pub fn into(self) -> (u8, u16) { + #[must_use] pub fn into(self) -> (u8, u16) { (0x03, self as u16) } } @@ -62,7 +62,7 @@ pub mod RegsC45 { } impl DA7 { - pub fn into(self) -> (u8, u16) { + #[must_use] pub fn into(self) -> (u8, u16) { (0x07, self as u16) } } @@ -84,7 +84,7 @@ pub mod RegsC45 { } impl DA1E { - pub fn into(self) -> (u8, u16) { + #[must_use] pub fn into(self) -> (u8, u16) { (0x1e, self as u16) } } @@ -100,7 +100,7 @@ pub mod RegsC45 { } impl DA1F { - pub fn into(self) -> (u8, u16) { + #[must_use] pub fn into(self) -> (u8, u16) { (0x1f, self as u16) } } @@ -121,8 +121,8 @@ impl Phy10BaseT1x { MDIOBUS: MdioBus, MDE: core::fmt::Debug, { - let mut phyid = (mdiobus.read_cl22(self.0, RegsC22::PHY_ID1 as u8).await? as u32) << 16; - phyid |= mdiobus.read_cl22(self.0, RegsC22::PHY_ID2 as u8).await? as u32; + let mut phyid = u32::from(mdiobus.read_cl22(self.0, RegsC22::PHY_ID1 as u8).await?) << 16; + phyid |= u32::from(mdiobus.read_cl22(self.0, RegsC22::PHY_ID2 as u8).await?); Ok(phyid) } diff --git a/embassy-net-adin1110/src/regs.rs b/embassy-net-adin1110/src/regs.rs index 93ce812d..4557929f 100644 --- a/embassy-net-adin1110/src/regs.rs +++ b/embassy-net-adin1110/src/regs.rs @@ -74,7 +74,6 @@ impl From for SpiRegisters { } // Register definitions - bitfield! { /// Status0 Register bits pub struct Status0(u32); @@ -242,6 +241,7 @@ bitfield! { pub link_change_mask, set_link_change_mask : 1; } +/// LED Functions #[repr(u8)] pub enum LedFunc { LinkupTxRxActicity = 0, @@ -326,7 +326,7 @@ bitfield_bitrange! {struct LedCntrl(u16)} impl LedCntrl { bitfield_fields! { u8; - /// LED_0 Pin Function + /// LED 0 Pin Function pub from into LedFunc, led0_function, set_led0_function: 4, 0; /// LED 0 Mode Selection pub led0_mode, set_led0_mode: 5; @@ -334,7 +334,7 @@ impl LedCntrl { pub led0_link_st_qualify, set_led0_link_st_qualify: 6; /// LED 0 Enable pub led0_en, set_led0_en: 7; - /// LED_1 Pin Function + /// LED 1 Pin Function pub from into LedFunc, led1_function, set_led1_function: 12, 8; /// /// LED 1 Mode Selection pub led1_mode, set_led1_mode: 13; @@ -349,7 +349,7 @@ impl LedCntrl { } } -// #[allow(dead_code)] +// LED Polarity #[repr(u8)] pub enum LedPol { AutoSense = 0, @@ -384,12 +384,12 @@ impl LedPolarity { u8; /// LED 1 Polarity pub from into LedPol, led1_polarity, set_led1_polarity: 3, 2; - /// LED_0 Polarity + /// LED 0 Polarity pub from into LedPol, led0_polarity, set_led0_polarity: 1, 0; } } -/// LED Control Register +/// SPI Header #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct SpiHeader(pub u16); bitfield_bitrange! {struct SpiHeader(u16)} @@ -400,8 +400,9 @@ impl SpiHeader { /// Mask Bit for TXF_ECC_ERR pub control, set_control : 15; pub full_duplex, set_full_duplex : 14; + /// Read or Write to register pub write, set_write : 13; - /// LED_0 Polarity + /// Registers ID/addr pub from into SpiRegisters, addr, set_addr: 11, 0; } } From e082cd0cda23b485f123f34efdeb3e54bcf3a616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Sun, 20 Aug 2023 21:21:33 +0200 Subject: [PATCH 006/233] Remove unneeded files. --- embassy-net-adin1110/.gitignore | 1 - embassy-net-adin1110/.vscode/settings.json | 8 -------- embassy-net-adin1110/rust-toolchain.toml | 3 --- 3 files changed, 12 deletions(-) delete mode 100644 embassy-net-adin1110/.gitignore delete mode 100644 embassy-net-adin1110/.vscode/settings.json delete mode 100644 embassy-net-adin1110/rust-toolchain.toml diff --git a/embassy-net-adin1110/.gitignore b/embassy-net-adin1110/.gitignore deleted file mode 100644 index c41cc9e3..00000000 --- a/embassy-net-adin1110/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target \ No newline at end of file diff --git a/embassy-net-adin1110/.vscode/settings.json b/embassy-net-adin1110/.vscode/settings.json deleted file mode 100644 index daa2ccf0..00000000 --- a/embassy-net-adin1110/.vscode/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "rust-analyzer.check.command": "clippy", - "rust-analyzer.showUnlinkedFileNotification": false, - "[rust]": { - "editor.defaultFormatter": "rust-lang.rust-analyzer", - "editor.formatOnSave": true - } -} \ No newline at end of file diff --git a/embassy-net-adin1110/rust-toolchain.toml b/embassy-net-adin1110/rust-toolchain.toml deleted file mode 100644 index d5f51a7f..00000000 --- a/embassy-net-adin1110/rust-toolchain.toml +++ /dev/null @@ -1,3 +0,0 @@ -[toolchain] -channel = "nightly" -components = [ "rustfmt", "rustc-dev" ] From 0e9524de621d338f71ba380f6036f23210365d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Sun, 20 Aug 2023 21:26:43 +0200 Subject: [PATCH 007/233] more clippy fixes --- embassy-net-adin1110/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index c7464893..10ed9f70 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -250,7 +250,7 @@ where packet .extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()) - .map_err(|_| AdinError::PACKET_TOO_BIG)?; + .map_err(|_e| AdinError::PACKET_TOO_BIG)?; if self.crc { // Add CRC for header data @@ -262,10 +262,12 @@ where // Add port number, ADIN1110 its fixed to zero/P1, but for ADIN2111 has two ports. packet .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice()) - .map_err(|_| AdinError::PACKET_TOO_BIG)?; + .map_err(|_e| AdinError::PACKET_TOO_BIG)?; // Copy packet data to spi buffer. - packet.extend_from_slice(frame).map_err(|_| AdinError::PACKET_TOO_BIG)?; + packet + .extend_from_slice(frame) + .map_err(|_e| AdinError::PACKET_TOO_BIG)?; // Pad data up to ETH_MIN_LEN - FCS_LEN for _ in packet.len()..(ETH_MIN_LEN - FSC_LEN + header_len) { From 1ded213ae904b90b20e15615f08873da4b4ef077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Sun, 20 Aug 2023 21:27:19 +0200 Subject: [PATCH 008/233] remove the type_alias_impl_trait feature --- embassy-net-adin1110/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 10ed9f70..113db3df 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -1,5 +1,4 @@ #![deny(clippy::pedantic)] -#![feature(type_alias_impl_trait)] #![feature(async_fn_in_trait)] #![cfg_attr(not(any(test, feature = "std")), no_std)] #![allow(clippy::module_name_repetitions)] From 0a7c061ddcd8db08449546a1121add8e37c6ddbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Sun, 20 Aug 2023 22:20:47 +0200 Subject: [PATCH 009/233] rustfmt --- embassy-net-adin1110/src/crc32.rs | 297 ++++++++++++++++++++++++++---- embassy-net-adin1110/src/phy.rs | 15 +- 2 files changed, 274 insertions(+), 38 deletions(-) diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs index 906c9aad..a41fedca 100644 --- a/embassy-net-adin1110/src/crc32.rs +++ b/embassy-net-adin1110/src/crc32.rs @@ -1,33 +1,260 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [ - 0x0000_0000, 0x7707_3096, 0xEE0E_612C, 0x9909_51BA, 0x076D_C419, 0x706A_F48F, 0xE963_A535, 0x9E64_95A3, 0x0EDB_8832, - 0x79DC_B8A4, 0xE0D5_E91E, 0x97D2_D988, 0x09B6_4C2B, 0x7EB1_7CBD, 0xE7B8_2D07, 0x90BF_1D91, 0x1DB7_1064, 0x6AB0_20F2, - 0xF3B9_7148, 0x84BE_41DE, 0x1ADA_D47D, 0x6DDD_E4EB, 0xF4D4_B551, 0x83D3_85C7, 0x136C_9856, 0x646B_A8C0, 0xFD62_F97A, - 0x8A65_C9EC, 0x1401_5C4F, 0x6306_6CD9, 0xFA0F_3D63, 0x8D08_0DF5, 0x3B6E_20C8, 0x4C69_105E, 0xD560_41E4, 0xA267_7172, - 0x3C03_E4D1, 0x4B04_D447, 0xD20D_85FD, 0xA50A_B56B, 0x35B5_A8FA, 0x42B2_986C, 0xDBBB_C9D6, 0xACBC_F940, 0x32D8_6CE3, - 0x45DF_5C75, 0xDCD6_0DCF, 0xABD1_3D59, 0x26D9_30AC, 0x51DE_003A, 0xC8D7_5180, 0xBFD0_6116, 0x21B4_F4B5, 0x56B3_C423, - 0xCFBA_9599, 0xB8BD_A50F, 0x2802_B89E, 0x5F05_8808, 0xC60C_D9B2, 0xB10B_E924, 0x2F6F_7C87, 0x5868_4C11, 0xC161_1DAB, - 0xB666_2D3D, 0x76DC_4190, 0x01DB_7106, 0x98D2_20BC, 0xEFD5_102A, 0x71B1_8589, 0x06B6_B51F, 0x9FBF_E4A5, 0xE8B8_D433, - 0x7807_C9A2, 0x0F00_F934, 0x9609_A88E, 0xE10E_9818, 0x7F6A_0DBB, 0x086D_3D2D, 0x9164_6C97, 0xE663_5C01, 0x6B6B_51F4, - 0x1C6C_6162, 0x8565_30D8, 0xF262_004E, 0x6C06_95ED, 0x1B01_A57B, 0x8208_F4C1, 0xF50F_C457, 0x65B0_D9C6, 0x12B7_E950, - 0x8BBE_B8EA, 0xFCB9_887C, 0x62DD_1DDF, 0x15DA_2D49, 0x8CD3_7CF3, 0xFBD4_4C65, 0x4DB2_6158, 0x3AB5_51CE, 0xA3BC_0074, - 0xD4BB_30E2, 0x4ADF_A541, 0x3DD8_95D7, 0xA4D1_C46D, 0xD3D6_F4FB, 0x4369_E96A, 0x346E_D9FC, 0xAD67_8846, 0xDA60_B8D0, - 0x4404_2D73, 0x3303_1DE5, 0xAA0A_4C5F, 0xDD0D_7CC9, 0x5005_713C, 0x2702_41AA, 0xBE0B_1010, 0xC90C_2086, 0x5768_B525, - 0x206F_85B3, 0xB966_D409, 0xCE61_E49F, 0x5EDE_F90E, 0x29D9_C998, 0xB0D0_9822, 0xC7D7_A8B4, 0x59B3_3D17, 0x2EB4_0D81, - 0xB7BD_5C3B, 0xC0BA_6CAD, 0xEDB8_8320, 0x9ABF_B3B6, 0x03B6_E20C, 0x74B1_D29A, 0xEAD5_4739, 0x9DD2_77AF, 0x04DB_2615, - 0x73DC_1683, 0xE363_0B12, 0x9464_3B84, 0x0D6D_6A3E, 0x7A6A_5AA8, 0xE40E_CF0B, 0x9309_FF9D, 0x0A00_AE27, 0x7D07_9EB1, - 0xF00F_9344, 0x8708_A3D2, 0x1E01_F268, 0x6906_C2FE, 0xF762_575D, 0x8065_67CB, 0x196C_3671, 0x6E6B_06E7, 0xFED4_1B76, - 0x89D3_2BE0, 0x10DA_7A5A, 0x67DD_4ACC, 0xF9B9_DF6F, 0x8EBE_EFF9, 0x17B7_BE43, 0x60B0_8ED5, 0xD6D6_A3E8, 0xA1D1_937E, - 0x38D8_C2C4, 0x4FDF_F252, 0xD1BB_67F1, 0xA6BC_5767, 0x3FB5_06DD, 0x48B2_364B, 0xD80D_2BDA, 0xAF0A_1B4C, 0x3603_4AF6, - 0x4104_7A60, 0xDF60_EFC3, 0xA867_DF55, 0x316E_8EEF, 0x4669_BE79, 0xCB61_B38C, 0xBC66_831A, 0x256F_D2A0, 0x5268_E236, - 0xCC0C_7795, 0xBB0B_4703, 0x2202_16B9, 0x5505_262F, 0xC5BA_3BBE, 0xB2BD_0B28, 0x2BB4_5A92, 0x5CB3_6A04, 0xC2D7_FFA7, - 0xB5D0_CF31, 0x2CD9_9E8B, 0x5BDE_AE1D, 0x9B64_C2B0, 0xEC63_F226, 0x756A_A39C, 0x026D_930A, 0x9C09_06A9, 0xEB0E_363F, - 0x7207_6785, 0x0500_5713, 0x95BF_4A82, 0xE2B8_7A14, 0x7BB1_2BAE, 0x0CB6_1B38, 0x92D2_8E9B, 0xE5D5_BE0D, 0x7CDC_EFB7, - 0x0BDB_DF21, 0x86D3_D2D4, 0xF1D4_E242, 0x68DD_B3F8, 0x1FDA_836E, 0x81BE_16CD, 0xF6B9_265B, 0x6FB0_77E1, 0x18B7_4777, - 0x8808_5AE6, 0xFF0F_6A70, 0x6606_3BCA, 0x1101_0B5C, 0x8F65_9EFF, 0xF862_AE69, 0x616B_FFD3, 0x166C_CF45, 0xA00A_E278, - 0xD70D_D2EE, 0x4E04_8354, 0x3903_B3C2, 0xA767_2661, 0xD060_16F7, 0x4969_474D, 0x3E6E_77DB, 0xAED1_6A4A, 0xD9D6_5ADC, - 0x40DF_0B66, 0x37D8_3BF0, 0xA9BC_AE53, 0xDEBB_9EC5, 0x47B2_CF7F, 0x30B5_FFE9, 0xBDBD_F21C, 0xCABA_C28A, 0x53B3_9330, - 0x24B4_A3A6, 0xBAD0_3605, 0xCDD7_0693, 0x54DE_5729, 0x23D9_67BF, 0xB366_7A2E, 0xC461_4AB8, 0x5D68_1B02, 0x2A6F_2B94, - 0xB40B_BE37, 0xC30C_8EA1, 0x5A05_DF1B, 0x2D02_EF8D, + 0x0000_0000, + 0x7707_3096, + 0xEE0E_612C, + 0x9909_51BA, + 0x076D_C419, + 0x706A_F48F, + 0xE963_A535, + 0x9E64_95A3, + 0x0EDB_8832, + 0x79DC_B8A4, + 0xE0D5_E91E, + 0x97D2_D988, + 0x09B6_4C2B, + 0x7EB1_7CBD, + 0xE7B8_2D07, + 0x90BF_1D91, + 0x1DB7_1064, + 0x6AB0_20F2, + 0xF3B9_7148, + 0x84BE_41DE, + 0x1ADA_D47D, + 0x6DDD_E4EB, + 0xF4D4_B551, + 0x83D3_85C7, + 0x136C_9856, + 0x646B_A8C0, + 0xFD62_F97A, + 0x8A65_C9EC, + 0x1401_5C4F, + 0x6306_6CD9, + 0xFA0F_3D63, + 0x8D08_0DF5, + 0x3B6E_20C8, + 0x4C69_105E, + 0xD560_41E4, + 0xA267_7172, + 0x3C03_E4D1, + 0x4B04_D447, + 0xD20D_85FD, + 0xA50A_B56B, + 0x35B5_A8FA, + 0x42B2_986C, + 0xDBBB_C9D6, + 0xACBC_F940, + 0x32D8_6CE3, + 0x45DF_5C75, + 0xDCD6_0DCF, + 0xABD1_3D59, + 0x26D9_30AC, + 0x51DE_003A, + 0xC8D7_5180, + 0xBFD0_6116, + 0x21B4_F4B5, + 0x56B3_C423, + 0xCFBA_9599, + 0xB8BD_A50F, + 0x2802_B89E, + 0x5F05_8808, + 0xC60C_D9B2, + 0xB10B_E924, + 0x2F6F_7C87, + 0x5868_4C11, + 0xC161_1DAB, + 0xB666_2D3D, + 0x76DC_4190, + 0x01DB_7106, + 0x98D2_20BC, + 0xEFD5_102A, + 0x71B1_8589, + 0x06B6_B51F, + 0x9FBF_E4A5, + 0xE8B8_D433, + 0x7807_C9A2, + 0x0F00_F934, + 0x9609_A88E, + 0xE10E_9818, + 0x7F6A_0DBB, + 0x086D_3D2D, + 0x9164_6C97, + 0xE663_5C01, + 0x6B6B_51F4, + 0x1C6C_6162, + 0x8565_30D8, + 0xF262_004E, + 0x6C06_95ED, + 0x1B01_A57B, + 0x8208_F4C1, + 0xF50F_C457, + 0x65B0_D9C6, + 0x12B7_E950, + 0x8BBE_B8EA, + 0xFCB9_887C, + 0x62DD_1DDF, + 0x15DA_2D49, + 0x8CD3_7CF3, + 0xFBD4_4C65, + 0x4DB2_6158, + 0x3AB5_51CE, + 0xA3BC_0074, + 0xD4BB_30E2, + 0x4ADF_A541, + 0x3DD8_95D7, + 0xA4D1_C46D, + 0xD3D6_F4FB, + 0x4369_E96A, + 0x346E_D9FC, + 0xAD67_8846, + 0xDA60_B8D0, + 0x4404_2D73, + 0x3303_1DE5, + 0xAA0A_4C5F, + 0xDD0D_7CC9, + 0x5005_713C, + 0x2702_41AA, + 0xBE0B_1010, + 0xC90C_2086, + 0x5768_B525, + 0x206F_85B3, + 0xB966_D409, + 0xCE61_E49F, + 0x5EDE_F90E, + 0x29D9_C998, + 0xB0D0_9822, + 0xC7D7_A8B4, + 0x59B3_3D17, + 0x2EB4_0D81, + 0xB7BD_5C3B, + 0xC0BA_6CAD, + 0xEDB8_8320, + 0x9ABF_B3B6, + 0x03B6_E20C, + 0x74B1_D29A, + 0xEAD5_4739, + 0x9DD2_77AF, + 0x04DB_2615, + 0x73DC_1683, + 0xE363_0B12, + 0x9464_3B84, + 0x0D6D_6A3E, + 0x7A6A_5AA8, + 0xE40E_CF0B, + 0x9309_FF9D, + 0x0A00_AE27, + 0x7D07_9EB1, + 0xF00F_9344, + 0x8708_A3D2, + 0x1E01_F268, + 0x6906_C2FE, + 0xF762_575D, + 0x8065_67CB, + 0x196C_3671, + 0x6E6B_06E7, + 0xFED4_1B76, + 0x89D3_2BE0, + 0x10DA_7A5A, + 0x67DD_4ACC, + 0xF9B9_DF6F, + 0x8EBE_EFF9, + 0x17B7_BE43, + 0x60B0_8ED5, + 0xD6D6_A3E8, + 0xA1D1_937E, + 0x38D8_C2C4, + 0x4FDF_F252, + 0xD1BB_67F1, + 0xA6BC_5767, + 0x3FB5_06DD, + 0x48B2_364B, + 0xD80D_2BDA, + 0xAF0A_1B4C, + 0x3603_4AF6, + 0x4104_7A60, + 0xDF60_EFC3, + 0xA867_DF55, + 0x316E_8EEF, + 0x4669_BE79, + 0xCB61_B38C, + 0xBC66_831A, + 0x256F_D2A0, + 0x5268_E236, + 0xCC0C_7795, + 0xBB0B_4703, + 0x2202_16B9, + 0x5505_262F, + 0xC5BA_3BBE, + 0xB2BD_0B28, + 0x2BB4_5A92, + 0x5CB3_6A04, + 0xC2D7_FFA7, + 0xB5D0_CF31, + 0x2CD9_9E8B, + 0x5BDE_AE1D, + 0x9B64_C2B0, + 0xEC63_F226, + 0x756A_A39C, + 0x026D_930A, + 0x9C09_06A9, + 0xEB0E_363F, + 0x7207_6785, + 0x0500_5713, + 0x95BF_4A82, + 0xE2B8_7A14, + 0x7BB1_2BAE, + 0x0CB6_1B38, + 0x92D2_8E9B, + 0xE5D5_BE0D, + 0x7CDC_EFB7, + 0x0BDB_DF21, + 0x86D3_D2D4, + 0xF1D4_E242, + 0x68DD_B3F8, + 0x1FDA_836E, + 0x81BE_16CD, + 0xF6B9_265B, + 0x6FB0_77E1, + 0x18B7_4777, + 0x8808_5AE6, + 0xFF0F_6A70, + 0x6606_3BCA, + 0x1101_0B5C, + 0x8F65_9EFF, + 0xF862_AE69, + 0x616B_FFD3, + 0x166C_CF45, + 0xA00A_E278, + 0xD70D_D2EE, + 0x4E04_8354, + 0x3903_B3C2, + 0xA767_2661, + 0xD060_16F7, + 0x4969_474D, + 0x3E6E_77DB, + 0xAED1_6A4A, + 0xD9D6_5ADC, + 0x40DF_0B66, + 0x37D8_3BF0, + 0xA9BC_AE53, + 0xDEBB_9EC5, + 0x47B2_CF7F, + 0x30B5_FFE9, + 0xBDBD_F21C, + 0xCABA_C28A, + 0x53B3_9330, + 0x24B4_A3A6, + 0xBAD0_3605, + 0xCDD7_0693, + 0x54DE_5729, + 0x23D9_67BF, + 0xB366_7A2E, + 0xC461_4AB8, + 0x5D68_1B02, + 0x2A6F_2B94, + 0xB40B_BE37, + 0xC30C_8EA1, + 0x5A05_DF1B, + 0x2D02_EF8D, ]; #[allow(non_camel_case_types)] @@ -37,7 +264,8 @@ pub struct ETH_FSC(pub u32); impl ETH_FSC { pub const CRC32_OK: u32 = 0x2144_df1c; - #[must_use] pub fn new(data: &[u8]) -> Self { + #[must_use] + pub fn new(data: &[u8]) -> Self { let fsc = data.iter().fold(u32::MAX, |crc, byte| { let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte; CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8) @@ -45,15 +273,18 @@ impl ETH_FSC { Self(fsc) } - #[must_use] pub fn crc_ok(&self) -> bool { + #[must_use] + pub fn crc_ok(&self) -> bool { self.0 == Self::CRC32_OK } - #[must_use] pub fn hton_bytes(&self) -> [u8; 4] { + #[must_use] + pub fn hton_bytes(&self) -> [u8; 4] { self.0.to_le_bytes() } - #[must_use] pub fn hton(&self) -> u32 { + #[must_use] + pub fn hton(&self) -> u32 { self.0.to_le() } } diff --git a/embassy-net-adin1110/src/phy.rs b/embassy-net-adin1110/src/phy.rs index 70060a0c..176ad019 100644 --- a/embassy-net-adin1110/src/phy.rs +++ b/embassy-net-adin1110/src/phy.rs @@ -30,7 +30,8 @@ pub mod RegsC45 { } impl DA1 { - #[must_use] pub fn into(self) -> (u8, u16) { + #[must_use] + pub fn into(self) -> (u8, u16) { (0x01, self as u16) } } @@ -48,7 +49,8 @@ pub mod RegsC45 { } impl DA3 { - #[must_use] pub fn into(self) -> (u8, u16) { + #[must_use] + pub fn into(self) -> (u8, u16) { (0x03, self as u16) } } @@ -62,7 +64,8 @@ pub mod RegsC45 { } impl DA7 { - #[must_use] pub fn into(self) -> (u8, u16) { + #[must_use] + pub fn into(self) -> (u8, u16) { (0x07, self as u16) } } @@ -84,7 +87,8 @@ pub mod RegsC45 { } impl DA1E { - #[must_use] pub fn into(self) -> (u8, u16) { + #[must_use] + pub fn into(self) -> (u8, u16) { (0x1e, self as u16) } } @@ -100,7 +104,8 @@ pub mod RegsC45 { } impl DA1F { - #[must_use] pub fn into(self) -> (u8, u16) { + #[must_use] + pub fn into(self) -> (u8, u16) { (0x1f, self as u16) } } From 681165e84c35fcc760977c799aa1372ebdd83f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Sun, 20 Aug 2023 23:26:22 +0200 Subject: [PATCH 010/233] add embassy-net-adin1110 to .github/ci/test.sh --- .github/ci/test.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 2892bcf8..04f4fc7c 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -28,3 +28,5 @@ cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --featu cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f429vg,exti,time-driver-any,exti cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f732ze,exti,time-driver-any,exti cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features nightly,stm32f769ni,exti,time-driver-any,exti + +cargo test --manifest-path ./embassy-net-adin1110/Cargo.toml From ca588f901f5987b8335f380ef8b5dddd7060f75b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Mon, 21 Aug 2023 20:44:42 +0200 Subject: [PATCH 011/233] add embassy-net-adin1110 to .github/ci/doc.sh --- .github/ci/doc.sh | 1 + embassy-net-adin1110/src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index 57184dc1..c317a12e 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -39,6 +39,7 @@ docserver-builder -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/g docserver-builder -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static +docserver-builder -i ./embassy-net-adin1110 -o webroot/crates/embassy-net-adin1110/git.zup export KUBECONFIG=/ci/secrets/kubeconfig.yml POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 113db3df..fd2bf868 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -4,6 +4,7 @@ #![allow(clippy::module_name_repetitions)] #![allow(clippy::missing_errors_doc)] #![allow(clippy::missing_panics_doc)] +#![doc = include_str!("../README.md")] mod crc32; mod crc8; From 4b6045d446ec52906f158d5b48c879c868629ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Mon, 21 Aug 2023 20:53:17 +0200 Subject: [PATCH 012/233] Remove the `SPI::Error` as a generic parameter. --- embassy-net-adin1110/src/lib.rs | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index fd2bf868..e917edcc 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -44,7 +44,7 @@ pub enum AdinError { MDIO_ACC_TIMEOUT, } -pub type AEResult = core::result::Result>; +pub type AEResult = core::result::Result>; pub const MDIO_PHY_ADDR: u8 = 0x01; /// Maximum Transmission Unit @@ -100,16 +100,12 @@ pub(crate) fn size_align_u32(size: u32) -> u32 { (size + 3) & 0xFFFF_FFFC } -impl ADIN1110 -where - SPI: SpiDevice, - SpiE: core::fmt::Debug, -{ +impl ADIN1110 { pub fn new(spi: SPI, crc: bool) -> Self { Self { spi, crc } } - pub async fn read_reg(&mut self, reg: sr) -> AEResult { + pub async fn read_reg(&mut self, reg: sr) -> AEResult { let mut tx_buf = Vec::::new(); let mut spi_hdr = SpiHeader(0); @@ -148,7 +144,7 @@ where Ok(value) } - pub async fn write_reg(&mut self, reg: sr, value: u32) -> AEResult<(), SpiE> { + pub async fn write_reg(&mut self, reg: sr, value: u32) -> AEResult<(), SPI::Error> { let mut tx_buf = Vec::::new(); let mut spi_hdr = SpiHeader(0); @@ -177,7 +173,7 @@ where } /// helper function for write to `MDIO_ACC` register and wait for ready! - async fn write_mdio_acc_reg(&mut self, mdio_acc_val: u32) -> AEResult { + async fn write_mdio_acc_reg(&mut self, mdio_acc_val: u32) -> AEResult { self.write_reg(sr::MDIO_ACC, mdio_acc_val).await?; // TODO: Add proper timeout! @@ -192,7 +188,7 @@ where } /// Read out fifo ethernet packet memory received via the wire. - pub async fn read_fifo(&mut self, packet: &mut [u8]) -> AEResult { + pub async fn read_fifo(&mut self, packet: &mut [u8]) -> AEResult { let mut tx_buf = Vec::::new(); // Size of the frame, also includes the appednded header. @@ -238,7 +234,7 @@ where } /// Write to fifo ethernet packet memory send over the wire. - pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SpiE> { + pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> { let header_len = self.header_write_len(); let mut packet = Packet::new(); @@ -318,7 +314,7 @@ where /// Programs the mac address in the mac filters. /// Also set the boardcast address. /// The chip supports 2 priority queues but current code doesn't support this mode. - pub async fn set_mac_addr(&mut self, mac: &[u8; 6]) -> AEResult<(), SpiE> { + pub async fn set_mac_addr(&mut self, mac: &[u8; 6]) -> AEResult<(), SPI::Error> { let mac_high_part = u16::from_be_bytes(mac[0..2].try_into().unwrap()); let mac_low_part = u32::from_be_bytes(mac[2..6].try_into().unwrap()); @@ -341,12 +337,8 @@ where } } -impl mdio::MdioBus for ADIN1110 -where - SPI: SpiDevice, - SpiE: core::fmt::Debug, -{ - type Error = AdinError; +impl mdio::MdioBus for ADIN1110 { + type Error = AdinError; /// Read from the PHY Registers as Clause 22. async fn read_cl22(&mut self, phy_id: u8, reg: u8) -> Result { @@ -380,7 +372,7 @@ where } /// Write to the PHY Registers as Clause 45. - async fn write_cl45(&mut self, phy_id: u8, regc45: (u8, u16), value: u16) -> AEResult<(), SpiE> { + async fn write_cl45(&mut self, phy_id: u8, regc45: (u8, u16), value: u16) -> AEResult<(), SPI::Error> { let phy_id = u32::from(phy_id & 0x1F) << 21; let dev_addr = u32::from(regc45.0 & 0x1F) << 16; let reg = u32::from(regc45.1); From 5f5e3bcd18040ae3c9bf23196961b804ac8831a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Mon, 21 Aug 2023 20:58:26 +0200 Subject: [PATCH 013/233] Replace size_align_u32() with next_multiple_of() Currently next_multiple_of() is behinged a Feature gate: int_rounding. See https://github.com/rust-lang/rust/issues/88581 But it seems that this function is stablized in rust 1.73. See https://github.com/rust-lang/rust/pull/94455 Currently Embassy is still using nightly for many other unstable features. So I do see an issue to use this function. --- embassy-net-adin1110/src/lib.rs | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index e917edcc..8b81065c 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -95,11 +95,6 @@ pub struct ADIN1110 { crc: bool, } -/// Round size up the N u32; -pub(crate) fn size_align_u32(size: u32) -> u32 { - (size + 3) & 0xFFFF_FFFC -} - impl ADIN1110 { pub fn new(spi: SPI, crc: bool) -> Self { Self { spi, crc } @@ -192,14 +187,12 @@ impl ADIN1110 { let mut tx_buf = Vec::::new(); // Size of the frame, also includes the appednded header. - let packet_size = self.read_reg(sr::RX_FSIZE).await?; + let packet_size = self.read_reg(sr::RX_FSIZE).await? as usize; // Packet read of write to the MAC packet buffer must be a multipul of 4! - let read_size = size_align_u32(packet_size); + let read_size = packet_size.next_multiple_of(4); - if packet_size < u32::try_from(FRAME_HEADER_LEN + FSC_LEN).unwrap() - || read_size > u32::try_from(packet.len()).unwrap() - { + if packet_size < (FRAME_HEADER_LEN + FSC_LEN) || read_size > packet.len() { return Err(AdinError::PACKET_TOO_BIG); } @@ -836,18 +829,6 @@ mod tests { spi.done(); } - #[test] - fn align_size() { - assert_eq!(size_align_u32(1), 4); - assert_eq!(size_align_u32(2), 4); - assert_eq!(size_align_u32(3), 4); - assert_eq!(size_align_u32(4), 4); - assert_eq!(size_align_u32(5), 8); - assert_eq!(size_align_u32(6), 8); - assert_eq!(size_align_u32(7), 8); - assert_eq!(size_align_u32(8), 8); - } - // #[test] // fn write_packet_to_fifo_less_64b_with_crc() { // // Configure expectations @@ -1224,10 +1205,9 @@ mod tests { // Packet FCS spi_packet.extend_from_slice(&[147, 149, 213, 68]).unwrap(); - let spi_packet_len = u32::try_from(spi_packet.len()).unwrap(); - // SPI HEADER Padding of u32 - for _ in spi_packet_len..size_align_u32(spi_packet_len) { + let spi_packet_len = spi_packet.len(); + for _ in spi_packet_len..spi_packet_len.next_multiple_of(4) { spi_packet.push(0x00).unwrap(); } From 1d4d11ba259b9c7174d2944b6609deeade401055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Thu, 24 Aug 2023 00:40:01 +0200 Subject: [PATCH 014/233] =?UTF-8?q?refactor=20write=5Ffifo(),=20don=C2=B4t?= =?UTF-8?q?=20copy=20frame=20data?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now this function uses frame data directly in the SPI transaction instead making a copy of it. Also fixing some length calculations and refactor/add tests to test this function. --- embassy-net-adin1110/src/crc32.rs | 26 ++ embassy-net-adin1110/src/lib.rs | 647 +++++++++++------------------- 2 files changed, 258 insertions(+), 415 deletions(-) diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs index a41fedca..a3474f70 100644 --- a/embassy-net-adin1110/src/crc32.rs +++ b/embassy-net-adin1110/src/crc32.rs @@ -273,6 +273,15 @@ impl ETH_FSC { Self(fsc) } + #[must_use] + pub fn update(self, data: &[u8]) -> Self { + let fsc = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| { + let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte; + CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8) + }) ^ u32::MAX; + Self(fsc) + } + #[must_use] pub fn crc_ok(&self) -> bool { self.0 == Self::CRC32_OK @@ -329,4 +338,21 @@ mod tests { println!("{:08x}", own_crc.0); assert_eq!(own_crc.0, ETH_FSC::CRC32_OK); } + + #[test] + fn crc32_update() { + let full_data = &[ + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xdd, 0x06, 0x00, 0x01, 0x08, 0x00, + 0x06, 0x04, 0x00, 0x02, 0x00, 0xe0, 0x4c, 0x68, 0x09, 0xde, 0xc0, 0xa8, 0x01, 0x02, 0x12, 0x34, 0x56, 0x78, + 0x9a, 0xbc, 0xc0, 0xa8, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x3d, 0x67, 0x7c, + ]; + + let (part_a, part_b) = full_data.split_at(16); + let crc_partially = ETH_FSC::new(part_a).update(part_b); + + let crc_full = ETH_FSC::new(full_data); + + assert_eq!(crc_full.0, crc_partially.0); + } } diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 8b81065c..c0a9b44e 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -61,13 +61,17 @@ const ETH_MIN_LEN: usize = 64; /// Ethernet `Frame Check Sequence` length const FSC_LEN: usize = 4; +/// SPI Header, contains SPI action and register id. +const SPI_HEADER_LEN: usize = 2; +/// SPI Header CRC length +const SPI_HEADER_CRC_LEN: usize = 1; +/// Frame Header, const FRAME_HEADER_LEN: usize = 2; -const WR_HEADER_LEN: usize = 2; // P1 = 0x00, P2 = 0x01 const PORT_ID_BYTE: u8 = 0x00; -pub type Packet = Vec; +pub type Packet = Vec; /// Type alias for the embassy-net driver for ADIN1110 pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; @@ -192,7 +196,13 @@ impl ADIN1110 { // Packet read of write to the MAC packet buffer must be a multipul of 4! let read_size = packet_size.next_multiple_of(4); - if packet_size < (FRAME_HEADER_LEN + FSC_LEN) || read_size > packet.len() { + if packet_size < (SPI_HEADER_LEN + FSC_LEN) { + return Err(AdinError::PACKET_TOO_SMALL); + } + + if read_size > packet.len() { + #[cfg(feature = "defmt")] + defmt::trace!("MAX: {} WANT: {}", packet.len(), read_size); return Err(AdinError::PACKET_TOO_BIG); } @@ -209,16 +219,18 @@ impl ADIN1110 { // Turn around byte, TODO: Unknown that this is. let _ = tx_buf.push(TURN_AROUND_BYTE); - let spi_packet = &mut packet[0..read_size as usize]; + let spi_packet = &mut packet[0..read_size]; assert_eq!(spi_packet.len() & 0x03, 0x00); let mut pkt_header = [0, 0]; + let mut fsc = [0, 0, 0, 0]; let mut spi_op = [ Operation::Write(&tx_buf), Operation::Read(&mut pkt_header), Operation::Read(spi_packet), + Operation::Read(&mut fsc), ]; self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; @@ -228,80 +240,86 @@ impl ADIN1110 { /// Write to fifo ethernet packet memory send over the wire. pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> { - let header_len = self.header_write_len(); + const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + FRAME_HEADER_LEN; + const TAIL_LEN: usize = ETH_MIN_LEN - FSC_LEN + FSC_LEN + 1; - let mut packet = Packet::new(); + if frame.len() < (6 + 6 + 2) { + return Err(AdinError::PACKET_TOO_SMALL); + } + if frame.len() > (MAX_BUFF - FRAME_HEADER_LEN) { + return Err(AdinError::PACKET_TOO_BIG); + } + + // SPI HEADER + [OPTIONAL SPI CRC] + FRAME HEADER + let mut head_data = Vec::::new(); + // [OPTIONAL PAD DATA] + FCS + [OPTINAL BYTES MAKE SPI FRAME EVEN] + let mut tail_data = Vec::::new(); let mut spi_hdr = SpiHeader(0); spi_hdr.set_control(true); spi_hdr.set_write(true); spi_hdr.set_addr(sr::TX); - packet + head_data .extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()) .map_err(|_e| AdinError::PACKET_TOO_BIG)?; if self.crc { // Add CRC for header data - packet - .push(crc8(&packet[0..2])) + head_data + .push(crc8(&head_data[0..2])) .map_err(|_| AdinError::PACKET_TOO_BIG)?; } // Add port number, ADIN1110 its fixed to zero/P1, but for ADIN2111 has two ports. - packet + head_data .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice()) .map_err(|_e| AdinError::PACKET_TOO_BIG)?; - // Copy packet data to spi buffer. - packet - .extend_from_slice(frame) - .map_err(|_e| AdinError::PACKET_TOO_BIG)?; + let mut frame_fcs = ETH_FSC::new(frame); - // Pad data up to ETH_MIN_LEN - FCS_LEN - for _ in packet.len()..(ETH_MIN_LEN - FSC_LEN + header_len) { - let _ = packet.push(0x00); + // ADIN1110 MAC and PHY donĀ“t accept ethernet packet smaller than 64 bytes. + // So padded the data minus the FCS, FCS is automatilly added to by the MAC. + if let Some(pad_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(frame.len()) { + let _ = tail_data.resize(pad_len, 0x00); + frame_fcs = frame_fcs.update(&tail_data); } - // add ethernet FCS only over the ethernet packet. - let crc = ETH_FSC::new(&packet[header_len..]); - let _ = packet.extend_from_slice(crc.hton_bytes().as_slice()); + // Add ethernet FCS only over the ethernet packet. + // Only usefull when `CONFIG0`, `Transmit Frame Check Sequence Validation Enable` bit is enabled. + let _ = tail_data.extend_from_slice(frame_fcs.hton_bytes().as_slice()); - let send_len = - u32::try_from(packet.len() - header_len + FRAME_HEADER_LEN).map_err(|_| AdinError::PACKET_TOO_BIG)?; + // len = frame_size + optional padding + 2 bytes Frame header + let send_len_orig = frame.len() + tail_data.len() + FRAME_HEADER_LEN; + let spi_pad_len = send_len_orig.next_multiple_of(4); + let send_len = u32::try_from(send_len_orig).map_err(|_| AdinError::PACKET_TOO_BIG)?; // Packet read of write to the MAC packet buffer must be a multipul of 4 bytes! - while packet.len() & 0x3 != 0 { - let _ = packet.push(DONT_CARE_BYTE); + if spi_pad_len != send_len_orig { + let spi_pad_len = spi_pad_len - send_len_orig; + let _ = tail_data.extend_from_slice(&[DONT_CARE_BYTE, DONT_CARE_BYTE, DONT_CARE_BYTE][..spi_pad_len]); } #[cfg(feature = "defmt")] defmt::trace!( - "TX: hdr {} [{}] {:02x} SIZE: {}", - header_len, - packet.len(), - &packet, + "TX: hdr {} [{}] {:02x}-{:02x}-{:02x} SIZE: {}", + head_data.len(), + frame.len(), + head_data.as_slice(), + frame, + tail_data.as_slice(), send_len, ); self.write_reg(sr::TX_FSIZE, send_len).await?; - // Spi packet must be half word / even length - if send_len & 1 != 0 { - let _ = packet.push(0x00); - } + let mut transaction = [ + Operation::Write(head_data.as_slice()), + Operation::Write(frame), + Operation::Write(tail_data.as_slice()), + ]; - self.spi.write(&packet).await.map_err(AdinError::Spi) - } - - pub fn header_write_len(&self) -> usize { - // u16 + [CRC] + PORT - WR_HEADER_LEN + FRAME_HEADER_LEN + usize::from(self.crc) - } - - pub fn header_len_read(&self) -> usize { - // u16 + [CRC] + u8 - WR_HEADER_LEN + 1 + usize::from(self.crc) + self.spi.transaction(&mut transaction).await.map_err(AdinError::Spi) } /// Programs the mac address in the mac filters. @@ -815,12 +833,12 @@ mod tests { SpiTransaction::write_vec(vec![0xA0, 0x09, 39, 0x12, 0x34, 0x56, 0x78, 28]), SpiTransaction::flush(), ]; - let mut spi = SpiMock::new(&expectations); + // Basic test init block + let mut spi = SpiMock::new(&expectations); let cs = CsPinMock::default(); let delay = MockDelay {}; let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); - let mut spe = ADIN1110::new(spi_dev, true); // Write reg: 0x1FFF @@ -829,389 +847,31 @@ mod tests { spi.done(); } - // #[test] - // fn write_packet_to_fifo_less_64b_with_crc() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(136), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(66), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(201), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(ETH_MIN_LEN, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // padding - // for _ in packet.len()..65 { - // expectations.push(SpiTransaction::send(0x00)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[8, 137, 18, 4] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, true); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - - // #[test] - // fn write_packet_to_fifo_less_64b_no_crc() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(66), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(ETH_MIN_LEN, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // padding - // for _ in packet.len() as u32..ETH_MIN_LEN { - // expectations.push(SpiTransaction::send(0x00)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[8, 137, 18, 4] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, false); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - - // #[test] - // fn write_packet_to_fifo_1500b() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x05), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0xDE), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(1500, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[212, 114, 18, 50] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, false); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - - // #[test] - // fn write_packet_to_fifo_65b() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(67), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(65, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // padding - // for _ in packet.len()..ETH_MIN_LEN { - // expectations.push(SpiTransaction::send(0x00)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[54, 117, 221, 220] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, false); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - - // #[test] - // fn write_packet_to_fifo_66b() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(68), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(66, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // padding - // for _ in packet.len()..ETH_MIN_LEN { - // expectations.push(SpiTransaction::send(0x00)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[97, 167, 100, 29] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, false); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - - // #[test] - // fn write_packet_to_fifo_67b() { - // // Configure expectations - // let mut expectations = vec![ - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x30), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Frame Size - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(69), - // SpiTransaction::read(DONT_CARE_BYTE), - // // HEADER - // SpiTransaction::send(0xA0), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(0x31), - // SpiTransaction::read(DONT_CARE_BYTE), - // // Port - // SpiTransaction::send(0x00), - // SpiTransaction::read(DONT_CARE_BYTE), - // SpiTransaction::send(PORT_ID_BYTE), - // SpiTransaction::read(DONT_CARE_BYTE), - // ]; - - // let mut packet = Packet::new(); - // packet.resize(67, 0).unwrap(); - - // for &byte in &packet[4..] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // padding - // for _ in packet.len()..ETH_MIN_LEN { - // expectations.push(SpiTransaction::send(0x00)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - - // // fcs - // for &byte in &[228, 218, 170, 232] { - // expectations.push(SpiTransaction::send(byte)); - // expectations.push(SpiTransaction::read(DONT_CARE_BYTE)); - // } - // let spi = SpiMock::new(&expectations); - - // let cs = CsPinMock {}; - // let mut spe = Adin1110::new(spi, cs, false); - - // assert!(spe.write_fifo(&mut packet).is_ok()); - // } - #[futures_test::test] - async fn write_packet_to_fifo_arp_46bytes() { + async fn write_packet_to_fifo_minimal_with_crc() { // Configure expectations let mut expectations = vec![]; - let mut packet = Packet::new(); - //arp packet; - packet - .extend_from_slice(&[ - 34, 51, 68, 85, 102, 119, 18, 52, 86, 120, 154, 188, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, 18, 52, 86, 120, - 154, 188, 192, 168, 16, 4, 34, 51, 68, 85, 102, 119, 192, 168, 16, 1, - ]) - .unwrap(); - - let mut spi_packet = Packet::new(); - // Write TX_SIZE reg expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 66, 201])); expectations.push(SpiTransaction::flush()); // Write TX reg. - // Header - spi_packet.extend_from_slice(&[160, 49, 143, 0, 0]).unwrap(); + // SPI Header + optional CRC + Frame Header + expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0])); // Packet data - spi_packet.extend_from_slice(&packet).unwrap(); - // Packet padding up to 60 (ETH_MIN_LEN - FCS) - for _ in packet.len()..(ETH_MIN_LEN - FSC_LEN) { - spi_packet.push(0x00).unwrap(); - } - // Packet FCS - spi_packet.extend_from_slice(&[147, 149, 213, 68]).unwrap(); + let packet = [0xFF_u8; 60]; + expectations.push(SpiTransaction::write_vec(packet.to_vec())); - // SPI HEADER Padding of u32 - let spi_packet_len = spi_packet.len(); - for _ in spi_packet_len..spi_packet_len.next_multiple_of(4) { - spi_packet.push(0x00).unwrap(); + let mut tail = std::vec::Vec::::with_capacity(100); + // Padding + if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + tail.resize(padding_len, 0x00); } + // Packet FCS + optinal padding + tail.extend_from_slice(&[77, 241, 140, 244, DONT_CARE_BYTE, DONT_CARE_BYTE]); - expectations.push(SpiTransaction::write_vec(spi_packet.to_vec())); + expectations.push(SpiTransaction::write_vec(tail)); expectations.push(SpiTransaction::flush()); let mut spi = SpiMock::new(&expectations); @@ -1226,4 +886,161 @@ mod tests { spi.done(); } + + #[futures_test::test] + async fn write_packet_to_fifo_max_mtu_with_crc() { + assert_eq!(MTU, 1514); + // Configure expectations + let mut expectations = vec![]; + + // Write TX_SIZE reg + expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 5, 240, 159])); + expectations.push(SpiTransaction::flush()); + + // Write TX reg. + // SPI Header + optional CRC + Frame Header + expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0])); + // Packet data + let packet = [0xAA_u8; MTU]; + expectations.push(SpiTransaction::write_vec(packet.to_vec())); + + let mut tail = std::vec::Vec::::with_capacity(100); + // Padding + if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + tail.resize(padding_len, 0x00); + } + // Packet FCS + optinal padding + tail.extend_from_slice(&[49, 196, 205, 160]); + + expectations.push(SpiTransaction::write_vec(tail)); + expectations.push(SpiTransaction::flush()); + + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, true); + + assert!(spe.write_fifo(&packet).await.is_ok()); + + spi.done(); + } + + #[futures_test::test] + async fn write_packet_to_fifo_invalid_lengths() { + assert_eq!(MTU, 1514); + + // Configure expectations + let expectations = vec![]; + + // Max packet size = MAX_BUFF - FRAME_HEADER_LEN + let packet = [0xAA_u8; MAX_BUFF - FRAME_HEADER_LEN + 1]; + + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, true); + + // minimal + assert!(matches!( + spe.write_fifo(&packet[0..(6 + 6 + 2 - 1)]).await, + Err(AdinError::PACKET_TOO_SMALL) + )); + + // max + 1 + assert!(matches!(spe.write_fifo(&packet).await, Err(AdinError::PACKET_TOO_BIG))); + + spi.done(); + } + + #[futures_test::test] + async fn write_packet_to_fifo_arp_46bytes_with_crc() { + // Configure expectations + let mut expectations = vec![]; + + // Write TX_SIZE reg + expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 66, 201])); + expectations.push(SpiTransaction::flush()); + + // Write TX reg. + // Header + expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0])); + // Packet data + let packet = [ + 34, 51, 68, 85, 102, 119, 18, 52, 86, 120, 154, 188, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, 18, 52, 86, 120, 154, + 188, 192, 168, 16, 4, 34, 51, 68, 85, 102, 119, 192, 168, 16, 1, + ]; + expectations.push(SpiTransaction::write_vec(packet.to_vec())); + + let mut tail = std::vec::Vec::::with_capacity(100); + // Padding + if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + tail.resize(padding_len, 0x00); + } + // Packet FCS + optinal padding + tail.extend_from_slice(&[147, 149, 213, 68, DONT_CARE_BYTE, DONT_CARE_BYTE]); + + expectations.push(SpiTransaction::write_vec(tail)); + expectations.push(SpiTransaction::flush()); + + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, true); + + assert!(spe.write_fifo(&packet).await.is_ok()); + + spi.done(); + } + + #[futures_test::test] + async fn write_packet_to_fifo_arp_46bytes_without_crc() { + // Configure expectations + let mut expectations = vec![]; + + // Write TX_SIZE reg + expectations.push(SpiTransaction::write_vec(vec![160, 48, 0, 0, 0, 66])); + expectations.push(SpiTransaction::flush()); + + // Write TX reg. + // SPI Header + Frame Header + expectations.push(SpiTransaction::write_vec(vec![160, 49, 0, 0])); + // Packet data + let packet = [ + 34, 51, 68, 85, 102, 119, 18, 52, 86, 120, 154, 188, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, 18, 52, 86, 120, 154, + 188, 192, 168, 16, 4, 34, 51, 68, 85, 102, 119, 192, 168, 16, 1, + ]; + expectations.push(SpiTransaction::write_vec(packet.to_vec())); + + let mut tail = std::vec::Vec::::with_capacity(100); + // Padding + if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + tail.resize(padding_len, 0x00); + } + // Packet FCS + optinal padding + tail.extend_from_slice(&[147, 149, 213, 68, DONT_CARE_BYTE, DONT_CARE_BYTE]); + + expectations.push(SpiTransaction::write_vec(tail)); + expectations.push(SpiTransaction::flush()); + + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, false); + + assert!(spe.write_fifo(&packet).await.is_ok()); + + spi.done(); + } } From cda404731093015f84bad96675fdbfc712bc0215 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 24 Aug 2023 19:29:11 -0500 Subject: [PATCH 015/233] stm32: flesh out lp executor --- embassy-stm32/src/lib.rs | 5 +++ embassy-stm32/src/low_power.rs | 45 +++++++++++++------ embassy-stm32/src/rcc/mod.rs | 2 + embassy-stm32/src/rtc/v2.rs | 25 ++++++++--- embassy-stm32/src/time_driver.rs | 76 ++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 8c87ea7d..ec8648ee 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -197,6 +197,11 @@ pub fn init(config: Config) -> Peripherals { // must be after rcc init #[cfg(feature = "_time-driver")] time_driver::init(); + + #[cfg(feature = "low-power")] + while !crate::rcc::low_power_ready() { + crate::rcc::clock_refcount_sub(); + } } p diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 7814fa38..0d9506aa 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -9,6 +9,7 @@ use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::pac::EXTI; use crate::rcc::low_power_ready; +use crate::time_driver::{pause_time, resume_time, time_until_next_alarm}; const THREAD_PENDER: usize = usize::MAX; const THRESHOLD: Duration = Duration::from_millis(500); @@ -16,6 +17,9 @@ const THRESHOLD: Duration = Duration::from_millis(500); use crate::rtc::{Rtc, RtcInstant}; static mut RTC: Option<&'static Rtc> = None; +static mut STOP_TIME: embassy_time::Duration = Duration::from_ticks(0); +static mut NEXT_ALARM: embassy_time::Duration = Duration::from_ticks(u64::MAX); +static mut RTC_INSTANT: Option = None; foreach_interrupt! { (RTC, rtc, $block:ident, WKUP, $irq:ident) => { @@ -69,13 +73,25 @@ impl Executor { } unsafe fn on_wakeup_irq() { - info!("on wakeup irq"); + trace!("on wakeup irq"); - cortex_m::asm::bkpt(); - } + let elapsed = RTC_INSTANT.take().unwrap() - stop_wakeup_alarm(); - fn time_until_next_alarm(&self) -> Duration { - Duration::from_secs(3) + STOP_TIME += elapsed; + // let to_next = NEXT_ALARM - STOP_TIME; + let to_next = Duration::from_secs(3); + + trace!("on wakeup irq: to next: {}", to_next); + if to_next > THRESHOLD { + trace!("start wakeup alarm"); + RTC_INSTANT.replace(start_wakeup_alarm(to_next)); + + trace!("set sleeponexit"); + Self::get_scb().set_sleeponexit(); + } else { + Self::get_scb().clear_sleeponexit(); + Self::get_scb().clear_sleepdeep(); + } } fn get_scb() -> SCB { @@ -86,25 +102,28 @@ impl Executor { trace!("configure_pwr"); if !low_power_ready() { + trace!("configure_pwr: low power not ready"); return; } - let time_until_next_alarm = self.time_until_next_alarm(); + let time_until_next_alarm = time_until_next_alarm(); if time_until_next_alarm < THRESHOLD { + trace!("configure_pwr: not enough time until next alarm"); return; } - trace!("low power stop required"); + unsafe { + NEXT_ALARM = time_until_next_alarm; + RTC_INSTANT = Some(start_wakeup_alarm(time_until_next_alarm)) + }; - critical_section::with(|_| { - trace!("executor: set wakeup alarm..."); + // return; - start_wakeup_alarm(time_until_next_alarm); + pause_time(); - trace!("low power wait for rtc ready..."); + trace!("enter stop..."); - Self::get_scb().set_sleepdeep(); - }); + Self::get_scb().set_sleepdeep(); } /// Run the executor. diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 3c75923e..45a4d880 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -86,6 +86,8 @@ static CLOCK_REFCOUNT: AtomicU32 = AtomicU32::new(0); #[cfg(feature = "low-power")] pub fn low_power_ready() -> bool { + trace!("clock refcount: {}", CLOCK_REFCOUNT.load(Ordering::SeqCst)); + CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0 } diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index bcb127ec..197c3b8f 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -30,9 +30,6 @@ impl RtcInstant { let _ = RTC::regs().dr().read(); - trace!("ssr: {}", ssr); - trace!("st: {}", st); - Self { ssr, st } } } @@ -52,7 +49,12 @@ impl core::ops::Sub for RtcInstant { let other_ticks = rhs.st as u32 * 256 + (255 - rhs.ssr as u32); let rtc_ticks = self_ticks - other_ticks; - trace!("self, other, rtc ticks: {}, {}, {}", self_ticks, other_ticks, rtc_ticks); + trace!( + "rtc: instant sub: self, other, rtc ticks: {}, {}, {}", + self_ticks, + other_ticks, + rtc_ticks + ); Duration::from_ticks( ((((st as u32 * 256 + (255u32 - self.ssr as u32)) - (rhs.st as u32 * 256 + (255u32 - rhs.ssr as u32))) @@ -174,10 +176,10 @@ impl super::Rtc { rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, ); - trace!("set wakeup timer for {} ms", duration.as_millis()); + trace!("rtc: set wakeup timer for {} ms", duration.as_millis()); self.write(false, |regs| { - regs.cr().modify(|w| w.set_wutie(true)); + // regs.cr().modify(|w| w.set_wutie(true)); regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); @@ -187,6 +189,15 @@ impl super::Rtc { regs.cr().modify(|w| w.set_wute(true)); }); + self.write(false, |regs| { + regs.cr().modify(|w| w.set_wutie(false)); + + regs.isr().modify(|w| w.set_wutf(false)); + crate::pac::PWR.cr1().modify(|w| w.set_cwuf(false)); + + regs.cr().modify(|w| w.set_wutie(true)); + }); + RtcInstant::now() } @@ -197,7 +208,7 @@ impl super::Rtc { /// note: this api is exposed for testing purposes until low power is implemented. /// it is not intended to be public pub(crate) fn stop_wakeup_alarm(&self) -> RtcInstant { - trace!("disable wakeup timer..."); + trace!("rtc: stop wakeup alarm..."); self.write(false, |regs| { regs.cr().modify(|w| w.set_wute(false)); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 2622442f..8e05346a 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -259,6 +259,64 @@ impl RtcDriver { let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) }; f(alarm.ctx.get()); } + + #[cfg(feature = "low-power")] + /// Compute the approximate amount of time until the next alarm + pub(crate) fn time_until_next_alarm(&self) -> embassy_time::Duration { + critical_section::with(|cs| { + let now = self.now() + 32; + + embassy_time::Duration::from_ticks( + self.alarms + .borrow(cs) + .iter() + .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now)) + .min() + .unwrap_or(u64::MAX), + ) + }) + } + + #[cfg(feature = "low-power")] + /// Pause the timer + pub(crate) fn pause_time(&self) { + T::regs_gp16().cr1().modify(|w| w.set_cen(false)); + } + + #[cfg(feature = "low-power")] + /// Resume the timer with the given offset + pub(crate) fn resume_time(&self, offset: embassy_time::Duration) { + let offset = offset.as_ticks(); + let cnt = T::regs_gp16().cnt().read().cnt() as u32; + let period = self.period.load(Ordering::SeqCst); + + // Correct the race, if it exists + let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 { + period + 1 + } else { + period + }; + + // Normalize to the full overflow + let period = (period / 2) * 2; + + // Add the offset + let period = period + 2 * (offset / u16::MAX as u64) as u32; + let cnt = cnt + (offset % u16::MAX as u64) as u32; + + let (cnt, period) = if cnt > u16::MAX as u32 { + (cnt - u16::MAX as u32, period + 2) + } else { + (cnt, period) + }; + + let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; + + self.period.store(period, Ordering::SeqCst); + T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); + + T::regs_gp16().cr1().modify(|w| w.set_cen(true)); + } } impl Driver for RtcDriver { @@ -329,6 +387,24 @@ impl Driver for RtcDriver { } } +#[cfg(feature = "low-power")] +/// Compute the approximate amount of time until the next alarm +pub(crate) fn time_until_next_alarm() -> embassy_time::Duration { + DRIVER.time_until_next_alarm() +} + +#[cfg(feature = "low-power")] +/// Pause the timer +pub(crate) fn pause_time() { + DRIVER.pause_time(); +} + +#[cfg(feature = "low-power")] +/// Resume the timer with the given offset +pub(crate) fn resume_time(offset: embassy_time::Duration) { + DRIVER.resume_time(offset); +} + pub(crate) fn init() { DRIVER.init() } From cc8961034e53d4fc2ac4539096c2a67059eb60b7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 19:48:45 +0200 Subject: [PATCH 016/233] net: allow changing IP config at runtime. --- embassy-net/src/lib.rs | 346 +++++++++++++++++------------------- examples/stm32wb/Cargo.toml | 2 +- 2 files changed, 162 insertions(+), 186 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 2fb34f43..9f881289 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -3,6 +3,9 @@ #![warn(missing_docs)] #![doc = include_str!("../README.md")] +#[cfg(not(any(feature = "proto-ipv4", feature = "proto-ipv6")))] +compile_error!("You must enable at least one of the following features: proto-ipv4, proto-ipv6"); + // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -20,7 +23,7 @@ use core::future::{poll_fn, Future}; use core::task::{Context, Poll}; pub use embassy_net_driver as driver; -use embassy_net_driver::{Driver, LinkState, Medium}; +use embassy_net_driver::{Driver, LinkState}; use embassy_sync::waitqueue::WakerRegistration; use embassy_time::{Instant, Timer}; use futures::pin_mut; @@ -133,6 +136,8 @@ impl Default for DhcpConfig { } /// Network stack configuration. +#[derive(Debug, Clone, Default)] +#[non_exhaustive] pub struct Config { /// IPv4 configuration #[cfg(feature = "proto-ipv4")] @@ -181,23 +186,27 @@ impl Config { /// Network stack IPv4 configuration. #[cfg(feature = "proto-ipv4")] +#[derive(Debug, Clone, Default)] pub enum ConfigV4 { + /// Do not configure IPv4. + #[default] + None, /// Use a static IPv4 address configuration. Static(StaticConfigV4), /// Use DHCP to obtain an IP address configuration. #[cfg(feature = "dhcpv4")] Dhcp(DhcpConfig), - /// Do not configure IPv6. - None, } /// Network stack IPv6 configuration. #[cfg(feature = "proto-ipv6")] +#[derive(Debug, Clone, Default)] pub enum ConfigV6 { + /// Do not configure IPv6. + #[default] + None, /// Use a static IPv6 address configuration. Static(StaticConfigV6), - /// Do not configure IPv6. - None, } /// A network stack. @@ -276,7 +285,6 @@ impl Stack { next_local_port, }; - #[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))] let mut inner = Inner { device, link_up: false, @@ -295,30 +303,11 @@ impl Stack { dns_waker: WakerRegistration::new(), }; - #[cfg(feature = "medium-ieee802154")] - let _ = config; - #[cfg(feature = "proto-ipv4")] - match config.ipv4 { - ConfigV4::Static(config) => { - inner.apply_config_v4(&mut socket, config); - } - #[cfg(feature = "dhcpv4")] - ConfigV4::Dhcp(config) => { - let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); - inner.apply_dhcp_config(&mut dhcp_socket, config); - let handle = socket.sockets.add(dhcp_socket); - inner.dhcp_socket = Some(handle); - } - ConfigV4::None => {} - } + inner.set_config_v4(&mut socket, config.ipv4); #[cfg(feature = "proto-ipv6")] - match config.ipv6 { - ConfigV6::Static(config) => { - inner.apply_config_v6(&mut socket, config); - } - ConfigV6::None => {} - } + inner.set_config_v6(&mut socket, config.ipv6); + inner.apply_static_config(&mut socket); Self { socket: RefCell::new(socket), @@ -372,15 +361,36 @@ impl Stack { } /// Get the current IPv4 configuration. + /// + /// If using DHCP, this will be None if DHCP hasn't been able to + /// acquire an IP address, or Some if it has. #[cfg(feature = "proto-ipv4")] pub fn config_v4(&self) -> Option { - self.with(|_s, i| i.static_v4.clone()) + self.with(|_, i| i.static_v4.clone()) } /// Get the current IPv6 configuration. #[cfg(feature = "proto-ipv6")] pub fn config_v6(&self) -> Option { - self.with(|_s, i| i.static_v6.clone()) + self.with(|_, i| i.static_v6.clone()) + } + + /// Set the IPv4 configuration. + #[cfg(feature = "proto-ipv4")] + pub fn set_config_v4(&self, config: ConfigV4) { + self.with_mut(|s, i| { + i.set_config_v4(s, config); + i.apply_static_config(s); + }) + } + + /// Set the IPv6 configuration. + #[cfg(feature = "proto-ipv6")] + pub fn set_config_v6(&self, config: ConfigV6) { + self.with_mut(|s, i| { + i.set_config_v6(s, config); + i.apply_static_config(s); + }) } /// Run the network stack. @@ -582,166 +592,125 @@ impl SocketStack { impl Inner { #[cfg(feature = "proto-ipv4")] - fn apply_config_v4(&mut self, s: &mut SocketStack, config: StaticConfigV4) { - debug!("Acquired IP configuration:"); - - debug!(" IP address: {}", config.address); - s.iface.update_ip_addrs(|addrs| { - if let Some((index, _)) = addrs - .iter() - .enumerate() - .find(|(_, &addr)| matches!(addr, IpCidr::Ipv4(_))) - { - addrs.remove(index); - } - addrs.push(IpCidr::Ipv4(config.address)).unwrap(); - }); - - #[cfg(feature = "medium-ip")] - let skip_gateway = self.device.capabilities().medium != Medium::Ip; - #[cfg(not(feature = "medium-ip"))] - let skip_gateway = false; - - if !skip_gateway { - if let Some(gateway) = config.gateway { - debug!(" Default gateway: {}", gateway); - s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap(); - } else { - debug!(" Default gateway: None"); - s.iface.routes_mut().remove_default_ipv4_route(); - } - } - for (i, s) in config.dns_servers.iter().enumerate() { - debug!(" DNS server {}: {}", i, s); - } - - self.static_v4 = Some(config); - - #[cfg(feature = "dns")] - { - self.update_dns_servers(s) - } - } - - /// Replaces the current IPv6 static configuration with a newly supplied config. - #[cfg(feature = "proto-ipv6")] - fn apply_config_v6(&mut self, s: &mut SocketStack, config: StaticConfigV6) { - #[cfg(feature = "medium-ethernet")] - let medium = self.device.capabilities().medium; - - debug!("Acquired IPv6 configuration:"); - - debug!(" IP address: {}", config.address); - s.iface.update_ip_addrs(|addrs| { - if let Some((index, _)) = addrs - .iter() - .enumerate() - .find(|(_, &addr)| matches!(addr, IpCidr::Ipv6(_))) - { - addrs.remove(index); - } - addrs.push(IpCidr::Ipv6(config.address)).unwrap(); - }); - - #[cfg(feature = "medium-ethernet")] - if Medium::Ethernet == medium { - if let Some(gateway) = config.gateway { - debug!(" Default gateway: {}", gateway); - s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap(); - } else { - debug!(" Default gateway: None"); - s.iface.routes_mut().remove_default_ipv6_route(); - } - } - for (i, s) in config.dns_servers.iter().enumerate() { - debug!(" DNS server {}: {}", i, s); - } - - self.static_v6 = Some(config); - - #[cfg(feature = "dns")] - { - self.update_dns_servers(s) - } - } - - #[cfg(feature = "dns")] - fn update_dns_servers(&mut self, s: &mut SocketStack) { - let socket = s.sockets.get_mut::(self.dns_socket); - - let servers_v4; - #[cfg(feature = "proto-ipv4")] - { - servers_v4 = self - .static_v4 - .iter() - .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv4(*c))); + pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) { + // Handle static config. + self.static_v4 = match config.clone() { + ConfigV4::None => None, + #[cfg(feature = "dhcpv4")] + ConfigV4::Dhcp(_) => None, + ConfigV4::Static(c) => Some(c), }; - #[cfg(not(feature = "proto-ipv4"))] - { - servers_v4 = core::iter::empty(); - } - let servers_v6; - #[cfg(feature = "proto-ipv6")] - { - servers_v6 = self - .static_v6 - .iter() - .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv6(*c))); - } - #[cfg(not(feature = "proto-ipv6"))] - { - servers_v6 = core::iter::empty(); - } + // Handle DHCP config. + #[cfg(feature = "dhcpv4")] + match config { + ConfigV4::Dhcp(c) => { + // Create the socket if it doesn't exist. + if self.dhcp_socket.is_none() { + let socket = smoltcp::socket::dhcpv4::Socket::new(); + let handle = _s.sockets.add(socket); + self.dhcp_socket = Some(handle); + } - // Prefer the v6 DNS servers over the v4 servers - let servers: Vec = servers_v6.chain(servers_v4).collect(); - socket.update_servers(&servers[..]); - } - - #[cfg(feature = "dhcpv4")] - fn apply_dhcp_config(&self, socket: &mut smoltcp::socket::dhcpv4::Socket, config: DhcpConfig) { - socket.set_ignore_naks(config.ignore_naks); - socket.set_max_lease_duration(config.max_lease_duration.map(crate::time::duration_to_smoltcp)); - socket.set_ports(config.server_port, config.client_port); - socket.set_retry_config(config.retry_config); - } - - #[cfg(feature = "dhcpv4")] - fn unapply_config_v4(&mut self, s: &mut SocketStack) { - #[cfg(feature = "medium-ethernet")] - let medium = self.device.capabilities().medium; - debug!("Lost IP configuration"); - s.iface.update_ip_addrs(|ip_addrs| { - #[cfg(feature = "proto-ipv4")] - if let Some((index, _)) = ip_addrs - .iter() - .enumerate() - .find(|(_, &addr)| matches!(addr, IpCidr::Ipv4(_))) - { - ip_addrs.remove(index); + // Configure it + let socket = _s.sockets.get_mut::(self.dhcp_socket.unwrap()); + socket.set_ignore_naks(c.ignore_naks); + socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp)); + socket.set_ports(c.server_port, c.client_port); + socket.set_retry_config(c.retry_config); + socket.reset(); } - }); - #[cfg(feature = "medium-ethernet")] - if medium == Medium::Ethernet { - #[cfg(feature = "proto-ipv4")] - { - s.iface.routes_mut().remove_default_ipv4_route(); + _ => { + // Remove DHCP socket if any. + if let Some(socket) = self.dhcp_socket { + _s.sockets.remove(socket); + self.dhcp_socket = None; + } } } + } + + #[cfg(feature = "proto-ipv6")] + pub fn set_config_v6(&mut self, _s: &mut SocketStack, config: ConfigV6) { + self.static_v6 = match config { + ConfigV6::None => None, + ConfigV6::Static(c) => Some(c), + }; + } + + fn apply_static_config(&mut self, s: &mut SocketStack) { + let mut addrs = Vec::new(); + #[cfg(feature = "dns")] + let mut dns_servers: Vec<_, 6> = Vec::new(); #[cfg(feature = "proto-ipv4")] - { - self.static_v4 = None + let mut gateway_v4 = None; + #[cfg(feature = "proto-ipv6")] + let mut gateway_v6 = None; + + #[cfg(feature = "proto-ipv4")] + if let Some(config) = &self.static_v4 { + debug!("IPv4: UP"); + debug!(" IP address: {:?}", config.address); + debug!(" Default gateway: {:?}", config.gateway); + + addrs.push(IpCidr::Ipv4(config.address)).unwrap(); + gateway_v4 = config.gateway.into(); + #[cfg(feature = "dns")] + for s in &config.dns_servers { + debug!(" DNS server: {:?}", s); + dns_servers.push(s.clone().into()).unwrap(); + } + } else { + info!("IPv4: DOWN"); } + + #[cfg(feature = "proto-ipv6")] + if let Some(config) = &self.static_v6 { + debug!("IPv6: UP"); + debug!(" IP address: {:?}", config.address); + debug!(" Default gateway: {:?}", config.gateway); + + addrs.push(IpCidr::Ipv6(config.address)).unwrap(); + gateway_v6 = config.gateway.into(); + #[cfg(feature = "dns")] + for s in &config.dns_servers { + debug!(" DNS server: {:?}", s); + dns_servers.push(s.clone().into()).unwrap(); + } + } else { + info!("IPv6: DOWN"); + } + + // Apply addresses + s.iface.update_ip_addrs(|a| *a = addrs); + + // Apply gateways + #[cfg(feature = "proto-ipv4")] + if let Some(gateway) = gateway_v4 { + s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap(); + } else { + s.iface.routes_mut().remove_default_ipv4_route(); + } + #[cfg(feature = "proto-ipv6")] + if let Some(gateway) = gateway_v6 { + s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap(); + } else { + s.iface.routes_mut().remove_default_ipv6_route(); + } + + // Apply DNS servers + #[cfg(feature = "dns")] + s.sockets + .get_mut::(self.dns_socket) + .update_servers(&dns_servers[..]); } fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { s.waker.register(cx.waker()); #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))] - if self.device.capabilities().medium == Medium::Ethernet - || self.device.capabilities().medium == Medium::Ieee802154 + if self.device.capabilities().medium == embassy_net_driver::Medium::Ethernet + || self.device.capabilities().medium == embassy_net_driver::Medium::Ieee802154 { s.iface .set_hardware_addr(to_smoltcp_hardware_address(self.device.hardware_address())); @@ -763,6 +732,9 @@ impl Inner { info!("link_up = {:?}", self.link_up); } + #[allow(unused_mut)] + let mut apply_config = false; + #[cfg(feature = "dhcpv4")] if let Some(dhcp_handle) = self.dhcp_socket { let socket = s.sockets.get_mut::(dhcp_handle); @@ -770,25 +742,29 @@ impl Inner { if self.link_up { match socket.poll() { None => {} - Some(dhcpv4::Event::Deconfigured) => self.unapply_config_v4(s), + Some(dhcpv4::Event::Deconfigured) => { + self.static_v4 = None; + apply_config = true; + } Some(dhcpv4::Event::Configured(config)) => { - let config = StaticConfigV4 { + self.static_v4 = Some(StaticConfigV4 { address: config.address, gateway: config.router, dns_servers: config.dns_servers, - }; - self.apply_config_v4(s, config) + }); + apply_config = true; } } } else if old_link_up { socket.reset(); - self.unapply_config_v4(s); + self.static_v4 = None; + apply_config = true; } } - //if old_link_up || self.link_up { - // self.poll_configurator(timestamp) - //} - // + + if apply_config { + self.apply_static_config(s); + } if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) { let t = Timer::at(instant_from_smoltcp(poll_at)); diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index f58a5189..16db92c1 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -11,7 +11,7 @@ embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", fea embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "medium-ieee802154", "nightly"], optional=true } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true } defmt = "0.3" defmt-rtt = "0.4" From b5748524f86f809d9c8dc2c5b4bb3f07e55dbda1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 01:03:24 +0200 Subject: [PATCH 017/233] net: improve error message on unsupported medium. --- embassy-net/Cargo.toml | 1 + embassy-net/src/lib.rs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 0c551f20..0361f1db 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -9,6 +9,7 @@ categories = [ "embedded", "no-std", "asynchronous", + "network-programming", ] [package.metadata.embassy_docs] diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 9f881289..3a385fad 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -249,7 +249,10 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> HardwareAddress driver::HardwareAddress::Ip => HardwareAddress::Ip, #[allow(unreachable_patterns)] - _ => panic!("Unsupported address {:?}. Make sure to enable medium-ethernet or medium-ieee802154 in embassy-net's Cargo features.", addr), + _ => panic!( + "Unsupported medium {:?}. Make sure to enable the right medium feature in embassy-net's Cargo features.", + addr + ), } } From 100200d021bbf650f7dd569414ee52b2d5ac10f0 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 01:03:39 +0200 Subject: [PATCH 018/233] net-driver-channel: do not hardcode medium to ethernet. --- embassy-net-driver-channel/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index 076238ba..f23c0441 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -8,6 +8,7 @@ use core::cell::RefCell; use core::mem::MaybeUninit; use core::task::{Context, Poll}; +use driver::HardwareAddress; pub use embassy_net_driver as driver; use embassy_net_driver::{Capabilities, LinkState, Medium}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; @@ -218,7 +219,11 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( ) -> (Runner<'d, MTU>, Device<'d, MTU>) { let mut caps = Capabilities::default(); caps.max_transmission_unit = MTU; - caps.medium = Medium::Ethernet; + caps.medium = match &hardware_address { + HardwareAddress::Ethernet(_) => Medium::Ethernet, + HardwareAddress::Ieee802154(_) => Medium::Ieee802154, + HardwareAddress::Ip => Medium::Ip, + }; // safety: this is a self-referential struct, however: // - it can't move while the `'d` borrow is active. From aacf14b62a28277599871edf74106b1cd2e01795 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 01:04:51 +0200 Subject: [PATCH 019/233] net-ppp: Add it. --- embassy-net-ppp/Cargo.toml | 28 ++++ embassy-net-ppp/README.md | 19 +++ embassy-net-ppp/src/fmt.rs | 257 +++++++++++++++++++++++++++++++++++++ embassy-net-ppp/src/lib.rs | 165 ++++++++++++++++++++++++ 4 files changed, 469 insertions(+) create mode 100644 embassy-net-ppp/Cargo.toml create mode 100644 embassy-net-ppp/README.md create mode 100644 embassy-net-ppp/src/fmt.rs create mode 100644 embassy-net-ppp/src/lib.rs diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml new file mode 100644 index 00000000..b2874c68 --- /dev/null +++ b/embassy-net-ppp/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "embassy-net-ppp" +version = "0.1.0" +description = "embassy-net driver for PPP over Serial" +keywords = ["embedded", "ppp", "embassy-net", "embedded-hal-async", "ethernet", "async"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] +license = "MIT OR Apache-2.0" +edition = "2021" + +[features] +defmt = ["dep:defmt", "ppproto/defmt"] +log = ["dep:log", "ppproto/log"] + +[dependencies] +defmt = { version = "0.3", optional = true } +log = { version = "0.4.14", optional = true } + +embedded-io-async = { version = "0.5.0" } +embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } +embassy-futures = { version = "0.1.0", path = "../embassy-futures" } +ppproto = { version = "0.1.1"} +embassy-sync = { version = "0.2.0", path = "../embassy-sync" } + +[package.metadata.embassy_docs] +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION/embassy-net-ppp/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-ppp/src/" +target = "thumbv7em-none-eabi" +features = ["defmt"] diff --git a/embassy-net-ppp/README.md b/embassy-net-ppp/README.md new file mode 100644 index 00000000..58d67395 --- /dev/null +++ b/embassy-net-ppp/README.md @@ -0,0 +1,19 @@ +# `embassy-net-ppp` + +[`embassy-net`](https://crates.io/crates/embassy-net) integration for PPP over Serial. + +## Interoperability + +This crate can run on any executor. + +It supports any serial port implementing [`embedded-io-async`](https://crates.io/crates/embedded-io-async). + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. diff --git a/embassy-net-ppp/src/fmt.rs b/embassy-net-ppp/src/fmt.rs new file mode 100644 index 00000000..91984bde --- /dev/null +++ b/embassy-net-ppp/src/fmt.rs @@ -0,0 +1,257 @@ +#![macro_use] +#![allow(unused_macros)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unreachable { + ($($x:tt)*) => { + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*); + }; +} + +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +pub struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-net-ppp/src/lib.rs b/embassy-net-ppp/src/lib.rs new file mode 100644 index 00000000..7853e04a --- /dev/null +++ b/embassy-net-ppp/src/lib.rs @@ -0,0 +1,165 @@ +#![no_std] +#![warn(missing_docs)] +#![doc = include_str!("../README.md")] + +// must be first +mod fmt; + +use core::convert::Infallible; +use core::mem::MaybeUninit; + +use embassy_futures::select::{select3, Either3}; +use embassy_net_driver_channel as ch; +use embassy_net_driver_channel::driver::LinkState; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::signal::Signal; +use embedded_io_async::{BufRead, Write, WriteAllError}; +use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction}; + +const MTU: usize = 1500; + +/// Type alias for the embassy-net driver. +pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; + +/// Internal state for the embassy-net integration. +pub struct State { + ch_state: ch::State, +} + +impl State { + /// Create a new `State`. + pub const fn new() -> Self { + Self { + ch_state: ch::State::new(), + } + } +} + +/// Background runner for the driver. +/// +/// You must call `.run()` in a background task for the driver to operate. +pub struct Runner<'d, R: BufRead, W: Write> { + ch: ch::Runner<'d, MTU>, + r: R, + w: W, +} + +/// Error returned by [`Runner::run`]. +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum RunError { + /// Reading from the serial port failed. + Read(RE), + /// Writing to the serial port failed. + Write(WE), + /// Writing to the serial port wrote zero bytes, indicating it can't accept more data. + WriteZero, + /// Writing to the serial got EOF. + Eof, +} + +impl<'d, R: BufRead, W: Write> Runner<'d, R, W> { + /// You must call this in a background task for the driver to operate. + pub async fn run(mut self) -> Result> { + let config = ppproto::Config { + username: b"myuser", + password: b"mypass", + }; + let mut ppp = PPPoS::new(config); + ppp.open().unwrap(); + + let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); + state_chan.set_link_state(LinkState::Down); + let _ondrop = OnDrop::new(|| state_chan.set_link_state(LinkState::Down)); + + let mut rx_buf = [0; 2048]; + let mut tx_buf = [0; 2048]; + + let poll_signal: Signal = Signal::new(); + poll_signal.signal(()); + + loop { + let mut poll = false; + match select3(self.r.fill_buf(), tx_chan.tx_buf(), poll_signal.wait()).await { + Either3::First(r) => { + let data = r.map_err(RunError::Read)?; + if data.is_empty() { + return Err(RunError::Eof); + } + let n = ppp.consume(data, &mut rx_buf); + self.r.consume(n); + poll = true; + } + Either3::Second(pkt) => { + match ppp.send(pkt, &mut tx_buf) { + Ok(n) => match self.w.write_all(&tx_buf[..n]).await { + Ok(()) => {} + Err(WriteAllError::WriteZero) => return Err(RunError::WriteZero), + Err(WriteAllError::Other(e)) => return Err(RunError::Write(e)), + }, + Err(BufferFullError) => unreachable!(), + } + tx_chan.tx_done(); + } + Either3::Third(_) => poll = true, + } + + if poll { + match ppp.poll(&mut tx_buf, &mut rx_buf) { + PPPoSAction::None => {} + PPPoSAction::Received(rg) => { + let pkt = &rx_buf[rg]; + let buf = rx_chan.rx_buf().await; // TODO: fix possible deadlock + buf[..pkt.len()].copy_from_slice(pkt); + rx_chan.rx_done(pkt.len()); + + poll_signal.signal(()); + } + PPPoSAction::Transmit(n) => { + match self.w.write_all(&tx_buf[..n]).await { + Ok(()) => {} + Err(WriteAllError::WriteZero) => return Err(RunError::WriteZero), + Err(WriteAllError::Other(e)) => return Err(RunError::Write(e)), + } + poll_signal.signal(()); + } + } + + match ppp.status().phase { + ppproto::Phase::Open => state_chan.set_link_state(LinkState::Up), + _ => state_chan.set_link_state(LinkState::Down), + } + } + } + } +} + +/// Create a PPP embassy-net driver instance. +/// +/// This returns two structs: +/// - a `Device` that you must pass to the `embassy-net` stack. +/// - a `Runner`. You must call `.run()` on it in a background task. +pub fn new<'a, const N_RX: usize, const N_TX: usize, R: BufRead, W: Write>( + state: &'a mut State, + r: R, + w: W, +) -> (Device<'a>, Runner<'a, R, W>) { + let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ip); + (device, Runner { ch: runner, r, w }) +} + +struct OnDrop { + f: MaybeUninit, +} + +impl OnDrop { + fn new(f: F) -> Self { + Self { f: MaybeUninit::new(f) } + } +} + +impl Drop for OnDrop { + fn drop(&mut self) { + unsafe { self.f.as_ptr().read()() } + } +} From 2303382dfd6f4e6275a699b938f465a1e6170449 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 15:39:25 +0200 Subject: [PATCH 020/233] net-ppp: nicer processing loop structure that can't deadlock. --- embassy-net-ppp/src/lib.rs | 84 +++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/embassy-net-ppp/src/lib.rs b/embassy-net-ppp/src/lib.rs index 7853e04a..af216c96 100644 --- a/embassy-net-ppp/src/lib.rs +++ b/embassy-net-ppp/src/lib.rs @@ -8,11 +8,9 @@ mod fmt; use core::convert::Infallible; use core::mem::MaybeUninit; -use embassy_futures::select::{select3, Either3}; +use embassy_futures::select::{select, Either}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use embassy_sync::signal::Signal; use embedded_io_async::{BufRead, Write, WriteAllError}; use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction}; @@ -75,22 +73,50 @@ impl<'d, R: BufRead, W: Write> Runner<'d, R, W> { let mut rx_buf = [0; 2048]; let mut tx_buf = [0; 2048]; - let poll_signal: Signal = Signal::new(); - poll_signal.signal(()); + let mut needs_poll = true; loop { - let mut poll = false; - match select3(self.r.fill_buf(), tx_chan.tx_buf(), poll_signal.wait()).await { - Either3::First(r) => { - let data = r.map_err(RunError::Read)?; - if data.is_empty() { - return Err(RunError::Eof); - } - let n = ppp.consume(data, &mut rx_buf); + let rx_fut = async { + let buf = rx_chan.rx_buf().await; + let rx_data = match needs_poll { + true => &[][..], + false => match self.r.fill_buf().await { + Ok(rx_data) if rx_data.len() == 0 => return Err(RunError::Eof), + Ok(rx_data) => rx_data, + Err(e) => return Err(RunError::Read(e)), + }, + }; + Ok((buf, rx_data)) + }; + let tx_fut = tx_chan.tx_buf(); + match select(rx_fut, tx_fut).await { + Either::First(r) => { + needs_poll = false; + + let (buf, rx_data) = r?; + let n = ppp.consume(rx_data, &mut rx_buf); self.r.consume(n); - poll = true; + + match ppp.poll(&mut tx_buf, &mut rx_buf) { + PPPoSAction::None => {} + PPPoSAction::Received(rg) => { + let pkt = &rx_buf[rg]; + buf[..pkt.len()].copy_from_slice(pkt); + rx_chan.rx_done(pkt.len()); + } + PPPoSAction::Transmit(n) => match self.w.write_all(&tx_buf[..n]).await { + Ok(()) => {} + Err(WriteAllError::WriteZero) => return Err(RunError::WriteZero), + Err(WriteAllError::Other(e)) => return Err(RunError::Write(e)), + }, + } + + match ppp.status().phase { + ppproto::Phase::Open => state_chan.set_link_state(LinkState::Up), + _ => state_chan.set_link_state(LinkState::Down), + } } - Either3::Second(pkt) => { + Either::Second(pkt) => { match ppp.send(pkt, &mut tx_buf) { Ok(n) => match self.w.write_all(&tx_buf[..n]).await { Ok(()) => {} @@ -101,34 +127,6 @@ impl<'d, R: BufRead, W: Write> Runner<'d, R, W> { } tx_chan.tx_done(); } - Either3::Third(_) => poll = true, - } - - if poll { - match ppp.poll(&mut tx_buf, &mut rx_buf) { - PPPoSAction::None => {} - PPPoSAction::Received(rg) => { - let pkt = &rx_buf[rg]; - let buf = rx_chan.rx_buf().await; // TODO: fix possible deadlock - buf[..pkt.len()].copy_from_slice(pkt); - rx_chan.rx_done(pkt.len()); - - poll_signal.signal(()); - } - PPPoSAction::Transmit(n) => { - match self.w.write_all(&tx_buf[..n]).await { - Ok(()) => {} - Err(WriteAllError::WriteZero) => return Err(RunError::WriteZero), - Err(WriteAllError::Other(e)) => return Err(RunError::Write(e)), - } - poll_signal.signal(()); - } - } - - match ppp.status().phase { - ppproto::Phase::Open => state_chan.set_link_state(LinkState::Up), - _ => state_chan.set_link_state(LinkState::Down), - } } } } From c2d601abeff6f9f911b8140f3ceb6806971dc7dd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 15:57:02 +0200 Subject: [PATCH 021/233] net-ppp: take serial port and config in run(), allow calling it multiple times. --- embassy-net-driver-channel/src/lib.rs | 12 +++++++ embassy-net-ppp/src/lib.rs | 50 +++++++++++++++------------ 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index f23c0441..f2aa6b25 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -74,6 +74,18 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { ) } + pub fn borrow_split(&mut self) -> (StateRunner<'_>, RxRunner<'_, MTU>, TxRunner<'_, MTU>) { + ( + StateRunner { shared: self.shared }, + RxRunner { + rx_chan: self.rx_chan.borrow(), + }, + TxRunner { + tx_chan: self.tx_chan.borrow(), + }, + ) + } + pub fn state_runner(&self) -> StateRunner<'d> { StateRunner { shared: self.shared } } diff --git a/embassy-net-ppp/src/lib.rs b/embassy-net-ppp/src/lib.rs index af216c96..df583fb3 100644 --- a/embassy-net-ppp/src/lib.rs +++ b/embassy-net-ppp/src/lib.rs @@ -13,6 +13,7 @@ use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embedded_io_async::{BufRead, Write, WriteAllError}; use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction}; +pub use ppproto::Config; const MTU: usize = 1500; @@ -36,37 +37,44 @@ impl State { /// Background runner for the driver. /// /// You must call `.run()` in a background task for the driver to operate. -pub struct Runner<'d, R: BufRead, W: Write> { +pub struct Runner<'d> { ch: ch::Runner<'d, MTU>, - r: R, - w: W, } /// Error returned by [`Runner::run`]. #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum RunError { +pub enum RunError { /// Reading from the serial port failed. - Read(RE), + Read(E), /// Writing to the serial port failed. - Write(WE), + Write(E), /// Writing to the serial port wrote zero bytes, indicating it can't accept more data. WriteZero, /// Writing to the serial got EOF. Eof, } -impl<'d, R: BufRead, W: Write> Runner<'d, R, W> { +impl<'d> Runner<'d> { /// You must call this in a background task for the driver to operate. - pub async fn run(mut self) -> Result> { - let config = ppproto::Config { - username: b"myuser", - password: b"mypass", - }; + /// + /// If reading/writing to the underlying serial port fails, the link state + /// is set to Down and the error is returned. + /// + /// It is allowed to cancel this function's future (i.e. drop it). This will terminate + /// the PPP connection and set the link state to Down. + /// + /// After this function returns or is canceled, you can call it again to establish + /// a new PPP connection. + pub async fn run( + &mut self, + mut rw: RW, + config: ppproto::Config<'_>, + ) -> Result> { let mut ppp = PPPoS::new(config); ppp.open().unwrap(); - let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); + let (state_chan, mut rx_chan, mut tx_chan) = self.ch.borrow_split(); state_chan.set_link_state(LinkState::Down); let _ondrop = OnDrop::new(|| state_chan.set_link_state(LinkState::Down)); @@ -80,7 +88,7 @@ impl<'d, R: BufRead, W: Write> Runner<'d, R, W> { let buf = rx_chan.rx_buf().await; let rx_data = match needs_poll { true => &[][..], - false => match self.r.fill_buf().await { + false => match rw.fill_buf().await { Ok(rx_data) if rx_data.len() == 0 => return Err(RunError::Eof), Ok(rx_data) => rx_data, Err(e) => return Err(RunError::Read(e)), @@ -95,7 +103,7 @@ impl<'d, R: BufRead, W: Write> Runner<'d, R, W> { let (buf, rx_data) = r?; let n = ppp.consume(rx_data, &mut rx_buf); - self.r.consume(n); + rw.consume(n); match ppp.poll(&mut tx_buf, &mut rx_buf) { PPPoSAction::None => {} @@ -104,7 +112,7 @@ impl<'d, R: BufRead, W: Write> Runner<'d, R, W> { buf[..pkt.len()].copy_from_slice(pkt); rx_chan.rx_done(pkt.len()); } - PPPoSAction::Transmit(n) => match self.w.write_all(&tx_buf[..n]).await { + PPPoSAction::Transmit(n) => match rw.write_all(&tx_buf[..n]).await { Ok(()) => {} Err(WriteAllError::WriteZero) => return Err(RunError::WriteZero), Err(WriteAllError::Other(e)) => return Err(RunError::Write(e)), @@ -118,7 +126,7 @@ impl<'d, R: BufRead, W: Write> Runner<'d, R, W> { } Either::Second(pkt) => { match ppp.send(pkt, &mut tx_buf) { - Ok(n) => match self.w.write_all(&tx_buf[..n]).await { + Ok(n) => match rw.write_all(&tx_buf[..n]).await { Ok(()) => {} Err(WriteAllError::WriteZero) => return Err(RunError::WriteZero), Err(WriteAllError::Other(e)) => return Err(RunError::Write(e)), @@ -137,13 +145,9 @@ impl<'d, R: BufRead, W: Write> Runner<'d, R, W> { /// This returns two structs: /// - a `Device` that you must pass to the `embassy-net` stack. /// - a `Runner`. You must call `.run()` on it in a background task. -pub fn new<'a, const N_RX: usize, const N_TX: usize, R: BufRead, W: Write>( - state: &'a mut State, - r: R, - w: W, -) -> (Device<'a>, Runner<'a, R, W>) { +pub fn new<'a, const N_RX: usize, const N_TX: usize>(state: &'a mut State) -> (Device<'a>, Runner<'a>) { let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ip); - (device, Runner { ch: runner, r, w }) + (device, Runner { ch: runner }) } struct OnDrop { From a026db3f570cae504dc5da6c7055afc52e122930 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 16:04:22 +0200 Subject: [PATCH 022/233] net-ppp: use From and ? to handle write errors. --- embassy-net-ppp/src/lib.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/embassy-net-ppp/src/lib.rs b/embassy-net-ppp/src/lib.rs index df583fb3..e3b208ee 100644 --- a/embassy-net-ppp/src/lib.rs +++ b/embassy-net-ppp/src/lib.rs @@ -55,6 +55,15 @@ pub enum RunError { Eof, } +impl From> for RunError { + fn from(value: WriteAllError) -> Self { + match value { + WriteAllError::Other(e) => Self::Write(e), + WriteAllError::WriteZero => Self::WriteZero, + } + } +} + impl<'d> Runner<'d> { /// You must call this in a background task for the driver to operate. /// @@ -112,11 +121,7 @@ impl<'d> Runner<'d> { buf[..pkt.len()].copy_from_slice(pkt); rx_chan.rx_done(pkt.len()); } - PPPoSAction::Transmit(n) => match rw.write_all(&tx_buf[..n]).await { - Ok(()) => {} - Err(WriteAllError::WriteZero) => return Err(RunError::WriteZero), - Err(WriteAllError::Other(e)) => return Err(RunError::Write(e)), - }, + PPPoSAction::Transmit(n) => rw.write_all(&tx_buf[..n]).await?, } match ppp.status().phase { @@ -126,11 +131,7 @@ impl<'d> Runner<'d> { } Either::Second(pkt) => { match ppp.send(pkt, &mut tx_buf) { - Ok(n) => match rw.write_all(&tx_buf[..n]).await { - Ok(()) => {} - Err(WriteAllError::WriteZero) => return Err(RunError::WriteZero), - Err(WriteAllError::Other(e)) => return Err(RunError::Write(e)), - }, + Ok(n) => rw.write_all(&tx_buf[..n]).await?, Err(BufferFullError) => unreachable!(), } tx_chan.tx_done(); From 623f37a27368c53d782cc9819c180bdf45f15612 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 19:49:28 +0200 Subject: [PATCH 023/233] net-ppp: add callback for IP configuration. --- embassy-net-ppp/src/lib.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/embassy-net-ppp/src/lib.rs b/embassy-net-ppp/src/lib.rs index e3b208ee..ca87fbae 100644 --- a/embassy-net-ppp/src/lib.rs +++ b/embassy-net-ppp/src/lib.rs @@ -13,7 +13,7 @@ use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embedded_io_async::{BufRead, Write, WriteAllError}; use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction}; -pub use ppproto::Config; +pub use ppproto::{Config, Ipv4Status}; const MTU: usize = 1500; @@ -79,6 +79,7 @@ impl<'d> Runner<'d> { &mut self, mut rw: RW, config: ppproto::Config<'_>, + mut on_ipv4_up: impl FnMut(Ipv4Status), ) -> Result> { let mut ppp = PPPoS::new(config); ppp.open().unwrap(); @@ -91,6 +92,7 @@ impl<'d> Runner<'d> { let mut tx_buf = [0; 2048]; let mut needs_poll = true; + let mut was_up = false; loop { let rx_fut = async { @@ -124,9 +126,19 @@ impl<'d> Runner<'d> { PPPoSAction::Transmit(n) => rw.write_all(&tx_buf[..n]).await?, } - match ppp.status().phase { - ppproto::Phase::Open => state_chan.set_link_state(LinkState::Up), - _ => state_chan.set_link_state(LinkState::Down), + let status = ppp.status(); + match status.phase { + ppproto::Phase::Open => { + if !was_up { + on_ipv4_up(status.ipv4.unwrap()); + } + was_up = true; + state_chan.set_link_state(LinkState::Up); + } + _ => { + was_up = false; + state_chan.set_link_state(LinkState::Down); + } } } Either::Second(pkt) => { From d812cc574571e60a092f10727046c494face09c9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 19:49:43 +0200 Subject: [PATCH 024/233] net-ppp: add std example. --- examples/std/Cargo.toml | 4 +- examples/std/src/bin/net_ppp.rs | 218 ++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 examples/std/src/bin/net_ppp.rs diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 0d4d5fa1..7b0d0bda 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -8,11 +8,13 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["log", "std", "nightly"] } -embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } +embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} embedded-io-async = { version = "0.5.0" } embedded-io-adapters = { version = "0.5.0", features = ["futures-03"] } critical-section = { version = "1.1", features = ["std"] } +smoltcp = { version = "0.10.0", features = ["dns-max-server-count-4"] } async-io = "1.6.0" env_logger = "0.9.0" diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs new file mode 100644 index 00000000..9cf6e19d --- /dev/null +++ b/examples/std/src/bin/net_ppp.rs @@ -0,0 +1,218 @@ +//! Testing against pppd: +//! +//! echo myuser $(hostname) mypass 192.168.7.10 >> /etc/ppp/pap-secrets +//! socat -v -x PTY,link=pty1,rawer PTY,link=pty2,rawer +//! sudo pppd $PWD/pty1 115200 192.168.7.1: ms-dns 8.8.4.4 ms-dns 8.8.8.8 nodetach debug local persist silent noproxyarp +//! RUST_LOG=trace cargo run --bin net_ppp -- --device pty2 +//! ping 192.168.7.10 +//! nc 192.168.7.10 1234 + +#![feature(type_alias_impl_trait)] +#![feature(async_fn_in_trait, impl_trait_projections)] + +#[path = "../serial_port.rs"] +mod serial_port; + +use async_io::Async; +use clap::Parser; +use embassy_executor::{Executor, Spawner}; +use embassy_net::tcp::TcpSocket; +use embassy_net::{Config, ConfigV4, Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net_ppp::Runner; +use embedded_io_async::Write; +use futures::io::BufReader; +use heapless::Vec; +use log::*; +use nix::sys::termios; +use rand_core::{OsRng, RngCore}; +use static_cell::{make_static, StaticCell}; + +use crate::serial_port::SerialPort; + +#[derive(Parser)] +#[clap(version = "1.0")] +struct Opts { + /// Serial port device name + #[clap(short, long)] + device: String, +} + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack>) -> ! { + stack.run().await +} + +#[embassy_executor::task] +async fn ppp_task( + stack: &'static Stack>, + mut runner: Runner<'static>, + port: SerialPort, +) -> ! { + let port = Async::new(port).unwrap(); + let port = BufReader::new(port); + let port = adapter::FromFutures::new(port); + + let config = embassy_net_ppp::Config { + username: b"myuser", + password: b"mypass", + }; + + runner + .run(port, config, |ipv4| { + let Some(addr) = ipv4.address else { + warn!("PPP did not provide an IP address."); + return; + }; + let mut dns_servers = Vec::new(); + for s in ipv4.dns_servers.iter().flatten() { + let _ = dns_servers.push(Ipv4Address::from_bytes(&s.0)); + } + let config = ConfigV4::Static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(Ipv4Address::from_bytes(&addr.0), 0), + gateway: None, + dns_servers, + }); + stack.set_config_v4(config); + }) + .await + .unwrap(); + unreachable!() +} + +#[embassy_executor::task] +async fn main_task(spawner: Spawner) { + let opts: Opts = Opts::parse(); + + // Open serial port + let baudrate = termios::BaudRate::B115200; + let port = SerialPort::new(opts.device.as_str(), baudrate).unwrap(); + + // Init network device + let state = make_static!(embassy_net_ppp::State::<4, 4>::new()); + let (device, runner) = embassy_net_ppp::new(state); + + // Generate random seed + let mut seed = [0; 8]; + OsRng.fill_bytes(&mut seed); + let seed = u64::from_le_bytes(seed); + + // Init network stack + let stack = &*make_static!(Stack::new( + device, + Config::default(), // don't configure IP yet + make_static!(StackResources::<3>::new()), + seed + )); + + // Launch network task + spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(ppp_task(stack, runner, port)).unwrap(); + + // Then we can use it! + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; + let mut buf = [0; 4096]; + + loop { + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); + + info!("Listening on TCP:1234..."); + if let Err(e) = socket.accept(1234).await { + warn!("accept error: {:?}", e); + continue; + } + + info!("Received connection from {:?}", socket.remote_endpoint()); + + loop { + let n = match socket.read(&mut buf).await { + Ok(0) => { + warn!("read EOF"); + break; + } + Ok(n) => n, + Err(e) => { + warn!("read error: {:?}", e); + break; + } + }; + + info!("rxd {:02x?}", &buf[..n]); + + match socket.write_all(&buf[..n]).await { + Ok(()) => {} + Err(e) => { + warn!("write error: {:?}", e); + break; + } + }; + } + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +fn main() { + env_logger::builder() + .filter_level(log::LevelFilter::Trace) + .filter_module("polling", log::LevelFilter::Info) + .filter_module("async_io", log::LevelFilter::Info) + .format_timestamp_nanos() + .init(); + + let executor = EXECUTOR.init(Executor::new()); + executor.run(|spawner| { + spawner.spawn(main_task(spawner)).unwrap(); + }); +} + +mod adapter { + use core::future::poll_fn; + use core::pin::Pin; + + use futures::AsyncBufReadExt; + + /// Adapter from `futures::io` traits. + #[derive(Clone)] + pub struct FromFutures { + inner: T, + } + + impl FromFutures { + /// Create a new adapter. + pub fn new(inner: T) -> Self { + Self { inner } + } + } + + impl embedded_io_async::ErrorType for FromFutures { + type Error = std::io::Error; + } + + impl embedded_io_async::Read for FromFutures { + async fn read(&mut self, buf: &mut [u8]) -> Result { + poll_fn(|cx| Pin::new(&mut self.inner).poll_read(cx, buf)).await + } + } + + impl embedded_io_async::BufRead for FromFutures { + async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { + self.inner.fill_buf().await + } + + fn consume(&mut self, amt: usize) { + Pin::new(&mut self.inner).consume(amt) + } + } + + impl embedded_io_async::Write for FromFutures { + async fn write(&mut self, buf: &[u8]) -> Result { + poll_fn(|cx| Pin::new(&mut self.inner).poll_write(cx, buf)).await + } + + async fn flush(&mut self) -> Result<(), Self::Error> { + poll_fn(|cx| Pin::new(&mut self.inner).poll_flush(cx)).await + } + } +} From f8299d10f7c0387416989e00acc02d99661537fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 25 Aug 2023 23:32:00 +0200 Subject: [PATCH 025/233] Prepare executor and macros for release (#1825) * Set release date, bump macros version * Add pool_size change to changelog --- embassy-executor/CHANGELOG.md | 3 ++- embassy-executor/Cargo.toml | 2 +- embassy-macros/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 4853ba29..ccbca1eb 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -5,11 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.3.0 - TBD +## 0.3.0 - 2023-08-25 - Replaced Pender. Implementations now must define an extern function called `__pender`. - Made `raw::AvailableTask` public - Made `SpawnToken::new_failed` public +- You can now use arbitrary expressions to specify `#[task(pool_size = X)]` ## 0.2.1 - 2023-08-10 diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 2a67f70d..5bf68fc6 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -58,7 +58,7 @@ log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.2", optional = true } futures-util = { version = "0.3.17", default-features = false } -embassy-macros = { version = "0.2.0", path = "../embassy-macros" } +embassy-macros = { version = "0.2.1", path = "../embassy-macros" } embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true} atomic-polyfill = "1.0.1" critical-section = "1.1" diff --git a/embassy-macros/Cargo.toml b/embassy-macros/Cargo.toml index 3b8fe8b4..a893cd30 100644 --- a/embassy-macros/Cargo.toml +++ b/embassy-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-macros" -version = "0.2.0" +version = "0.2.1" edition = "2021" license = "MIT OR Apache-2.0" description = "macros for creating the entry point and tasks for embassy-executor" From 3023e70ccf14157c6a9c1315b987951cb6138e0d Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 25 Aug 2023 18:41:51 -0500 Subject: [PATCH 026/233] stm32: clenaup lp executor --- embassy-stm32/src/low_power.rs | 154 +++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 63 deletions(-) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 0d9506aa..cf12a1ea 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -16,36 +16,30 @@ const THRESHOLD: Duration = Duration::from_millis(500); use crate::rtc::{Rtc, RtcInstant}; -static mut RTC: Option<&'static Rtc> = None; -static mut STOP_TIME: embassy_time::Duration = Duration::from_ticks(0); -static mut NEXT_ALARM: embassy_time::Duration = Duration::from_ticks(u64::MAX); -static mut RTC_INSTANT: Option = None; +static mut EXECUTOR: Option = None; foreach_interrupt! { (RTC, rtc, $block:ident, WKUP, $irq:ident) => { #[interrupt] unsafe fn $irq() { - Executor::on_wakeup_irq(); + unsafe { EXECUTOR.as_mut().unwrap() }.on_wakeup_irq(); } }; } pub fn stop_with_rtc(rtc: &'static Rtc) { - crate::interrupt::typelevel::RTC_WKUP::unpend(); - unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; - - EXTI.rtsr(0).modify(|w| w.set_line(22, true)); - EXTI.imr(0).modify(|w| w.set_line(22, true)); - - unsafe { RTC = Some(rtc) }; + unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) } pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> RtcInstant { - unsafe { RTC }.unwrap().start_wakeup_alarm(requested_duration) + unsafe { EXECUTOR.as_mut().unwrap() } + .rtc + .unwrap() + .start_wakeup_alarm(requested_duration) } pub fn stop_wakeup_alarm() -> RtcInstant { - unsafe { RTC }.unwrap().stop_wakeup_alarm() + unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm() } /// Thread mode executor, using WFE/SEV. @@ -61,69 +55,103 @@ pub fn stop_wakeup_alarm() -> RtcInstant { pub struct Executor { inner: raw::Executor, not_send: PhantomData<*mut ()>, + scb: SCB, + pub(self) rtc: Option<&'static Rtc>, + stop_time: embassy_time::Duration, + next_alarm: embassy_time::Duration, + last_stop: Option, } impl Executor { /// Create a new Executor. - pub fn new() -> Self { - Self { - inner: raw::Executor::new(THREAD_PENDER as *mut ()), - not_send: PhantomData, + pub fn new() -> &'static mut Self { + unsafe { + assert!(EXECUTOR.is_none()); + + EXECUTOR = Some(Self { + inner: raw::Executor::new(THREAD_PENDER as *mut ()), + not_send: PhantomData, + scb: cortex_m::Peripherals::steal().SCB, + rtc: None, + stop_time: Duration::from_ticks(0), + next_alarm: Duration::from_ticks(u64::MAX), + last_stop: None, + }); + + EXECUTOR.as_mut().unwrap() } } - unsafe fn on_wakeup_irq() { - trace!("on wakeup irq"); + unsafe fn on_wakeup_irq(&mut self) { + trace!("low power: one wakekup irq"); - let elapsed = RTC_INSTANT.take().unwrap() - stop_wakeup_alarm(); - - STOP_TIME += elapsed; - // let to_next = NEXT_ALARM - STOP_TIME; - let to_next = Duration::from_secs(3); - - trace!("on wakeup irq: to next: {}", to_next); - if to_next > THRESHOLD { - trace!("start wakeup alarm"); - RTC_INSTANT.replace(start_wakeup_alarm(to_next)); - - trace!("set sleeponexit"); - Self::get_scb().set_sleeponexit(); - } else { - Self::get_scb().clear_sleeponexit(); - Self::get_scb().clear_sleepdeep(); - } + self.rtc.unwrap().clear_wakeup_alarm(); + // Self::get_scb().set_sleeponexit(); + // + // return; + // + // let elapsed = RTC_INSTANT.take().unwrap() - stop_wakeup_alarm(); + // + // STOP_TIME += elapsed; + // // let to_next = NEXT_ALARM - STOP_TIME; + // let to_next = Duration::from_secs(3); + // + // trace!("on wakeup irq: to next: {}", to_next); + // if to_next > THRESHOLD { + // trace!("start wakeup alarm"); + // RTC_INSTANT.replace(start_wakeup_alarm(to_next)); + // + // trace!("set sleeponexit"); + // Self::get_scb().set_sleeponexit(); + // } else { + // Self::get_scb().clear_sleeponexit(); + // Self::get_scb().clear_sleepdeep(); + // } } - fn get_scb() -> SCB { - unsafe { cortex_m::Peripherals::steal() }.SCB + pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { + assert!(self.rtc.is_none()); + + crate::interrupt::typelevel::RTC_WKUP::unpend(); + unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; + + EXTI.rtsr(0).modify(|w| w.set_line(22, true)); + EXTI.imr(0).modify(|w| w.set_line(22, true)); + + self.rtc = Some(rtc); } fn configure_pwr(&self) { - trace!("configure_pwr"); + // defeat the borrow checker + let s = unsafe { EXECUTOR.as_mut().unwrap() }; - if !low_power_ready() { - trace!("configure_pwr: low power not ready"); - return; - } - - let time_until_next_alarm = time_until_next_alarm(); - if time_until_next_alarm < THRESHOLD { - trace!("configure_pwr: not enough time until next alarm"); - return; - } - - unsafe { - NEXT_ALARM = time_until_next_alarm; - RTC_INSTANT = Some(start_wakeup_alarm(time_until_next_alarm)) - }; - - // return; - - pause_time(); - - trace!("enter stop..."); - - Self::get_scb().set_sleepdeep(); + // trace!("configure_pwr"); + // + // if !low_power_ready() { + // trace!("configure_pwr: low power not ready"); + // return; + // } + // + // let time_until_next_alarm = time_until_next_alarm(); + // if time_until_next_alarm < THRESHOLD { + // trace!("configure_pwr: not enough time until next alarm"); + // return; + // } + // + // unsafe { + // NEXT_ALARM = time_until_next_alarm; + // if RTC_INSTANT.is_none() { + // RTC_INSTANT = Some(start_wakeup_alarm(time_until_next_alarm)) + // } + // }; + // + // // return; + // + // pause_time(); + // + // trace!("enter stop..."); + // + // Self::get_scb().set_sleepdeep(); } /// Run the executor. From 54e2e17520e678eb5f57661222670f7d891f1810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 26 Aug 2023 05:43:16 +0200 Subject: [PATCH 027/233] Avoid dead code warning --- embassy-executor/src/arch/cortex_m.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index 0806a22a..fde862f3 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs @@ -1,5 +1,3 @@ -const THREAD_PENDER: usize = usize::MAX; - #[export_name = "__pender"] #[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))] fn __pender(context: *mut ()) { @@ -48,13 +46,14 @@ fn __pender(context: *mut ()) { pub use thread::*; #[cfg(feature = "executor-thread")] mod thread { + pub(super) const THREAD_PENDER: usize = usize::MAX; + use core::arch::asm; use core::marker::PhantomData; #[cfg(feature = "nightly")] pub use embassy_macros::main_cortex_m as main; - use crate::arch::THREAD_PENDER; use crate::{raw, Spawner}; /// Thread mode executor, using WFE/SEV. From d33246b072f222bd221471da7d498593ef8c6211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 26 Aug 2023 12:40:57 +0200 Subject: [PATCH 028/233] Add new feature/arch combinations to executor CI check --- ci.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ci.sh b/ci.sh index e83b3b84..db00c406 100755 --- a/ci.sh +++ b/ci.sh @@ -19,6 +19,19 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ From 2897670f2438525bc128cf016ee8f8a948edfbb7 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 26 Aug 2023 19:23:25 -0500 Subject: [PATCH 029/233] stm32: get the basic lp working --- embassy-stm32/src/low_power.rs | 126 +++++++++++++++++-------------- embassy-stm32/src/rtc/v2.rs | 55 +++++++++++--- embassy-stm32/src/time_driver.rs | 107 ++++++++++++++++++++------ 3 files changed, 196 insertions(+), 92 deletions(-) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index cf12a1ea..964819ab 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -9,12 +9,11 @@ use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::pac::EXTI; use crate::rcc::low_power_ready; -use crate::time_driver::{pause_time, resume_time, time_until_next_alarm}; +use crate::time_driver::{get_driver, RtcDriver}; const THREAD_PENDER: usize = usize::MAX; -const THRESHOLD: Duration = Duration::from_millis(500); -use crate::rtc::{Rtc, RtcInstant}; +use crate::rtc::Rtc; static mut EXECUTOR: Option = None; @@ -27,20 +26,30 @@ foreach_interrupt! { }; } +// pub fn timer_driver_pause_time() { +// pause_time(); +// } + pub fn stop_with_rtc(rtc: &'static Rtc) { unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) } -pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> RtcInstant { - unsafe { EXECUTOR.as_mut().unwrap() } - .rtc - .unwrap() - .start_wakeup_alarm(requested_duration) -} - -pub fn stop_wakeup_alarm() -> RtcInstant { - unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm() -} +// pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) { +// let rtc_instant = unsafe { EXECUTOR.as_mut().unwrap() } +// .rtc +// .unwrap() +// .start_wakeup_alarm(requested_duration); +// +// unsafe { EXECUTOR.as_mut().unwrap() }.last_stop = Some(rtc_instant); +// } +// +// pub fn set_sleepdeep() { +// unsafe { EXECUTOR.as_mut().unwrap() }.scb.set_sleepdeep(); +// } +// +// pub fn stop_wakeup_alarm() -> RtcInstant { +// unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm() +// } /// Thread mode executor, using WFE/SEV. /// @@ -56,15 +65,15 @@ pub struct Executor { inner: raw::Executor, not_send: PhantomData<*mut ()>, scb: SCB, - pub(self) rtc: Option<&'static Rtc>, + time_driver: &'static RtcDriver, stop_time: embassy_time::Duration, next_alarm: embassy_time::Duration, - last_stop: Option, + wfe: u8, } impl Executor { /// Create a new Executor. - pub fn new() -> &'static mut Self { + pub fn take() -> &'static mut Self { unsafe { assert!(EXECUTOR.is_none()); @@ -72,10 +81,10 @@ impl Executor { inner: raw::Executor::new(THREAD_PENDER as *mut ()), not_send: PhantomData, scb: cortex_m::Peripherals::steal().SCB, - rtc: None, + time_driver: get_driver(), stop_time: Duration::from_ticks(0), next_alarm: Duration::from_ticks(u64::MAX), - last_stop: None, + wfe: 0, }); EXECUTOR.as_mut().unwrap() @@ -83,9 +92,31 @@ impl Executor { } unsafe fn on_wakeup_irq(&mut self) { - trace!("low power: one wakekup irq"); + trace!("low power: on wakeup irq"); - self.rtc.unwrap().clear_wakeup_alarm(); + if crate::pac::RTC.isr().read().wutf() { + trace!("low power: wutf set"); + } else { + trace!("low power: wutf not set"); + } + + self.time_driver.resume_time(); + trace!("low power: resume time"); + + crate::interrupt::typelevel::RTC_WKUP::disable(); + + // cortex_m::asm::bkpt(); + + // let time_elasped = self.rtc.unwrap().stop_wakeup_alarm() - self.last_stop.take().unwrap(); + // + // trace!("low power: {} ms elapsed", time_elasped.as_millis()); + // + // resume_time(time_elasped); + // trace!("low power: resume time"); + // + // self.scb.clear_sleepdeep(); + + // cortex_m::asm::bkpt(); // Self::get_scb().set_sleeponexit(); // // return; @@ -110,48 +141,33 @@ impl Executor { } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { - assert!(self.rtc.is_none()); + trace!("low power: stop with rtc configured"); + + self.time_driver.set_rtc(rtc); crate::interrupt::typelevel::RTC_WKUP::unpend(); unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; EXTI.rtsr(0).modify(|w| w.set_line(22, true)); EXTI.imr(0).modify(|w| w.set_line(22, true)); - - self.rtc = Some(rtc); } - fn configure_pwr(&self) { - // defeat the borrow checker - let s = unsafe { EXECUTOR.as_mut().unwrap() }; + fn configure_pwr(&mut self) { + trace!("low power: configure_pwr"); - // trace!("configure_pwr"); - // - // if !low_power_ready() { - // trace!("configure_pwr: low power not ready"); - // return; - // } - // - // let time_until_next_alarm = time_until_next_alarm(); - // if time_until_next_alarm < THRESHOLD { - // trace!("configure_pwr: not enough time until next alarm"); - // return; - // } - // - // unsafe { - // NEXT_ALARM = time_until_next_alarm; - // if RTC_INSTANT.is_none() { - // RTC_INSTANT = Some(start_wakeup_alarm(time_until_next_alarm)) - // } - // }; - // - // // return; - // - // pause_time(); - // - // trace!("enter stop..."); - // - // Self::get_scb().set_sleepdeep(); + self.scb.clear_sleepdeep(); + if !low_power_ready() { + trace!("low power: configure_pwr: low power not ready"); + return; + } + + if self.time_driver.pause_time().is_err() { + trace!("low power: configure_pwr: time driver failed to pause"); + return; + } + + trace!("low power: enter stop..."); + self.scb.set_sleepdeep(); } /// Run the executor. @@ -173,11 +189,11 @@ impl Executor { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - init(self.inner.spawner()); + init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); loop { unsafe { - self.inner.poll(); + EXECUTOR.as_mut().unwrap().inner.poll(); self.configure_pwr(); asm!("wfe"); }; diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 197c3b8f..525dc45a 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -30,6 +30,8 @@ impl RtcInstant { let _ = RTC::regs().dr().read(); + trace!("rtc: instant now: st, ssr: {}, {}", st, ssr); + Self { ssr, st } } } @@ -146,6 +148,21 @@ impl super::Rtc { } } + // pub(crate) fn clear_wakeup_alarm(&self) { + // use crate::interrupt::typelevel::Interrupt; + // + // self.write(false, |regs| { + // regs.cr().modify(|w| w.set_wutie(false)); + // + // regs.isr().modify(|w| w.set_wutf(false)); + // crate::pac::PWR.cr1().modify(|w| w.set_cwuf(false)); + // crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, false)); + // crate::interrupt::typelevel::RTC_WKUP::unpend(); + // + // regs.cr().modify(|w| w.set_wutie(true)); + // }); + // } + #[allow(dead_code)] #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] /// start the wakeup alarm and return the actual duration of the alarm @@ -157,6 +174,7 @@ impl super::Rtc { pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) -> RtcInstant { use embassy_time::{Duration, TICK_HZ}; + use crate::interrupt::typelevel::Interrupt; use crate::rcc::get_freqs; let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; @@ -176,28 +194,40 @@ impl super::Rtc { rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, ); - trace!("rtc: set wakeup timer for {} ms", duration.as_millis()); - self.write(false, |regs| { - // regs.cr().modify(|w| w.set_wutie(true)); - regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); while !regs.isr().read().wutwf() {} regs.cr().modify(|w| w.set_wucksel(prescaler.into())); regs.cr().modify(|w| w.set_wute(true)); - }); - - self.write(false, |regs| { - regs.cr().modify(|w| w.set_wutie(false)); - - regs.isr().modify(|w| w.set_wutf(false)); - crate::pac::PWR.cr1().modify(|w| w.set_cwuf(false)); - regs.cr().modify(|w| w.set_wutie(true)); }); + trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); + + // self.write(false, |regs| { + // regs.cr().modify(|w| w.set_wutie(false)); + // + // regs.isr().modify(|w| w.set_wutf(false)); + // + // regs.cr().modify(|w| w.set_wutie(true)); + // }); + // + // trace!("rtc: clear wuf..."); + // crate::pac::PWR.cr1().modify(|w| w.set_cwuf(true)); + // while crate::pac::PWR.csr1().read().wuf() {} + // trace!("rtc: clear wuf...done"); + // + // crate::pac::PWR + // .cr1() + // .modify(|w| w.set_pdds(crate::pac::pwr::vals::Pdds::STANDBY_MODE)); + // + // // crate::pac::PWR.cr1().modify(|w| w.set_lpds(true)); + // + // // crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); + // crate::interrupt::typelevel::RTC_WKUP::unpend(); + RtcInstant::now() } @@ -211,6 +241,7 @@ impl super::Rtc { trace!("rtc: stop wakeup alarm..."); self.write(false, |regs| { + regs.cr().modify(|w| w.set_wutie(false)); regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); }); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 8e05346a..56f42aa9 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -14,6 +14,8 @@ use stm32_metapac::timer::regs; use crate::interrupt::typelevel::Interrupt; use crate::pac::timer::vals; use crate::rcc::sealed::RccPeripheral; +#[cfg(feature = "low-power")] +use crate::rtc::{Rtc, RtcInstant}; use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; use crate::{interrupt, peripherals}; @@ -130,12 +132,16 @@ impl AlarmState { } } -struct RtcDriver { +pub(crate) struct RtcDriver { /// Number of 2^15 periods elapsed since boot. period: AtomicU32, alarm_count: AtomicU8, /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. alarms: Mutex, + #[cfg(feature = "low-power")] + rtc: Mutex>>, + #[cfg(feature = "low-power")] + stop_time: Mutex>>, } const ALARM_STATE_NEW: AlarmState = AlarmState::new(); @@ -144,6 +150,10 @@ embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), alarm_count: AtomicU8::new(0), alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), + #[cfg(feature = "low-power")] + rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), + #[cfg(feature = "low-power")] + stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }); impl RtcDriver { @@ -260,9 +270,15 @@ impl RtcDriver { f(alarm.ctx.get()); } + #[cfg(feature = "low-power")] + /// Set the rtc but panic if it's already been set + pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { + critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())); + } + #[cfg(feature = "low-power")] /// Compute the approximate amount of time until the next alarm - pub(crate) fn time_until_next_alarm(&self) -> embassy_time::Duration { + fn time_until_next_alarm(&self) -> embassy_time::Duration { critical_section::with(|cs| { let now = self.now() + 32; @@ -278,14 +294,8 @@ impl RtcDriver { } #[cfg(feature = "low-power")] - /// Pause the timer - pub(crate) fn pause_time(&self) { - T::regs_gp16().cr1().modify(|w| w.set_cen(false)); - } - - #[cfg(feature = "low-power")] - /// Resume the timer with the given offset - pub(crate) fn resume_time(&self, offset: embassy_time::Duration) { + /// Add the given offset to the current time + fn add_time(&self, offset: embassy_time::Duration) { let offset = offset.as_ticks(); let cnt = T::regs_gp16().cnt().read().cnt() as u32; let period = self.period.load(Ordering::SeqCst); @@ -315,6 +325,66 @@ impl RtcDriver { self.period.store(period, Ordering::SeqCst); T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); + // Now, recompute all alarms + critical_section::with(|cs| { + for i in 0..ALARM_COUNT { + let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; + let alarm = self.get_alarm(cs, alarm_handle); + + self.set_alarm(alarm_handle, alarm.timestamp.get()); + } + }) + } + + #[cfg(feature = "low-power")] + /// Stop the wakeup alarm, if enabled, and add the appropriate offset + fn stop_wakeup_alarm(&self) { + critical_section::with(|cs| { + if let Some(stop_time) = self.stop_time.borrow(cs).take() { + let current_time = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(); + self.add_time(current_time - stop_time); + } + }); + } + + #[cfg(feature = "low-power")] + /// Pause the timer if ready; return err if not + pub(crate) fn pause_time(&self) -> Result<(), ()> { + /* + If the wakeup timer is currently running, then we need to stop it and + add the elapsed time to the current time + */ + self.stop_wakeup_alarm(); + + let time_until_next_alarm = self.time_until_next_alarm(); + if time_until_next_alarm < embassy_time::Duration::from_millis(250) { + Err(()) + } else { + critical_section::with(|cs| { + assert!(self + .stop_time + .borrow(cs) + .replace(Some( + self.rtc + .borrow(cs) + .get() + .unwrap() + .start_wakeup_alarm(time_until_next_alarm) + )) + .is_none()); + }); + + T::regs_gp16().cr1().modify(|w| w.set_cen(false)); + + Ok(()) + } + } + + #[cfg(feature = "low-power")] + /// Resume the timer with the given offset + pub(crate) fn resume_time(&self) { + self.stop_wakeup_alarm(); + T::regs_gp16().cr1().modify(|w| w.set_cen(true)); } } @@ -388,21 +458,8 @@ impl Driver for RtcDriver { } #[cfg(feature = "low-power")] -/// Compute the approximate amount of time until the next alarm -pub(crate) fn time_until_next_alarm() -> embassy_time::Duration { - DRIVER.time_until_next_alarm() -} - -#[cfg(feature = "low-power")] -/// Pause the timer -pub(crate) fn pause_time() { - DRIVER.pause_time(); -} - -#[cfg(feature = "low-power")] -/// Resume the timer with the given offset -pub(crate) fn resume_time(offset: embassy_time::Duration) { - DRIVER.resume_time(offset); +pub(crate) fn get_driver() -> &'static RtcDriver { + &DRIVER } pub(crate) fn init() { From 1e430f74133acaeb31cb689ded3da77cb7b1c0ca Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 26 Aug 2023 20:31:12 -0500 Subject: [PATCH 030/233] stm32: complete stop impl. --- embassy-stm32/src/low_power.rs | 48 ------------- embassy-stm32/src/rtc/mod.rs | 79 ++++++++++++++++++++ embassy-stm32/src/rtc/v2.rs | 119 ++++++------------------------- embassy-stm32/src/time_driver.rs | 25 ++----- 4 files changed, 107 insertions(+), 164 deletions(-) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 964819ab..42536216 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -66,9 +66,6 @@ pub struct Executor { not_send: PhantomData<*mut ()>, scb: SCB, time_driver: &'static RtcDriver, - stop_time: embassy_time::Duration, - next_alarm: embassy_time::Duration, - wfe: u8, } impl Executor { @@ -82,9 +79,6 @@ impl Executor { not_send: PhantomData, scb: cortex_m::Peripherals::steal().SCB, time_driver: get_driver(), - stop_time: Duration::from_ticks(0), - next_alarm: Duration::from_ticks(u64::MAX), - wfe: 0, }); EXECUTOR.as_mut().unwrap() @@ -94,50 +88,8 @@ impl Executor { unsafe fn on_wakeup_irq(&mut self) { trace!("low power: on wakeup irq"); - if crate::pac::RTC.isr().read().wutf() { - trace!("low power: wutf set"); - } else { - trace!("low power: wutf not set"); - } - self.time_driver.resume_time(); trace!("low power: resume time"); - - crate::interrupt::typelevel::RTC_WKUP::disable(); - - // cortex_m::asm::bkpt(); - - // let time_elasped = self.rtc.unwrap().stop_wakeup_alarm() - self.last_stop.take().unwrap(); - // - // trace!("low power: {} ms elapsed", time_elasped.as_millis()); - // - // resume_time(time_elasped); - // trace!("low power: resume time"); - // - // self.scb.clear_sleepdeep(); - - // cortex_m::asm::bkpt(); - // Self::get_scb().set_sleeponexit(); - // - // return; - // - // let elapsed = RTC_INSTANT.take().unwrap() - stop_wakeup_alarm(); - // - // STOP_TIME += elapsed; - // // let to_next = NEXT_ALARM - STOP_TIME; - // let to_next = Duration::from_secs(3); - // - // trace!("on wakeup irq: to next: {}", to_next); - // if to_next > THRESHOLD { - // trace!("start wakeup alarm"); - // RTC_INSTANT.replace(start_wakeup_alarm(to_next)); - // - // trace!("set sleeponexit"); - // Self::get_scb().set_sleeponexit(); - // } else { - // Self::get_scb().clear_sleeponexit(); - // Self::get_scb().clear_sleepdeep(); - // } } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index a6102077..1f1abb78 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -1,6 +1,14 @@ //! RTC peripheral abstraction mod datetime; +#[cfg(feature = "low-power")] +use core::cell::Cell; + +#[cfg(feature = "low-power")] +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +#[cfg(feature = "low-power")] +use embassy_sync::blocking_mutex::Mutex; + pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; /// refer to AN4759 to compare features of RTC2 and RTC3 @@ -30,9 +38,73 @@ pub enum RtcError { NotRunning, } +#[cfg(feature = "low-power")] +/// Represents an instant in time that can be substracted to compute a duration +struct RtcInstant { + second: u8, + subsecond: u16, +} + +#[cfg(feature = "low-power")] +impl RtcInstant { + pub fn now() -> Self { + let tr = RTC::regs().tr().read(); + let tr2 = RTC::regs().tr().read(); + let ssr = RTC::regs().ssr().read().ss(); + let ssr2 = RTC::regs().ssr().read().ss(); + + let st = bcd2_to_byte((tr.st(), tr.su())); + let st2 = bcd2_to_byte((tr2.st(), tr2.su())); + + assert!(st == st2); + assert!(ssr == ssr2); + + let _ = RTC::regs().dr().read(); + + let subsecond = ssr; + let second = st; + + // trace!("rtc: instant now: st, ssr: {}, {}", st, ssr); + + Self { second, subsecond } + } +} + +#[cfg(feature = "low-power")] +impl core::ops::Sub for RtcInstant { + type Output = embassy_time::Duration; + + fn sub(self, rhs: Self) -> Self::Output { + use embassy_time::{Duration, TICK_HZ}; + + let second = if self.second < rhs.second { + self.second + 60 + } else { + self.second + }; + + // TODO: read prescaler + + let self_ticks = second as u32 * 256 + (255 - self.subsecond as u32); + let other_ticks = rhs.second as u32 * 256 + (255 - rhs.subsecond as u32); + let rtc_ticks = self_ticks - other_ticks; + + // trace!( + // "rtc: instant sub: self, other, rtc ticks: {}, {}, {}", + // self_ticks, + // other_ticks, + // rtc_ticks + // ); + + Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / 256u32) as u64) + } +} + /// RTC Abstraction pub struct Rtc { rtc_config: RtcConfig, + #[cfg(feature = "low-power")] + stop_time: Mutex>>, } #[derive(Copy, Clone, Debug, PartialEq)] @@ -108,8 +180,15 @@ impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { RTC::enable_peripheral_clk(); + #[cfg(not(feature = "low-power"))] let mut rtc_struct = Self { rtc_config }; + #[cfg(feature = "low-power")] + let mut rtc_struct = Self { + rtc_config, + stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), + }; + Self::enable(); rtc_struct.configure(rtc_config); diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 525dc45a..d73e7083 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -1,71 +1,12 @@ use stm32_metapac::rtc::vals::{Init, Osel, Pol}; +#[cfg(feature = "low-power")] +use super::RtcInstant; use super::{sealed, RtcClockSource, RtcConfig}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; use crate::rtc::sealed::Instance; -#[cfg(all(feature = "time", any(stm32wb, stm32f4)))] -pub struct RtcInstant { - ssr: u16, - st: u8, -} - -#[cfg(all(feature = "time", any(stm32wb, stm32f4)))] -impl RtcInstant { - pub fn now() -> Self { - // TODO: read value twice - use crate::rtc::bcd2_to_byte; - - let tr = RTC::regs().tr().read(); - let tr2 = RTC::regs().tr().read(); - let ssr = RTC::regs().ssr().read().ss(); - let ssr2 = RTC::regs().ssr().read().ss(); - - let st = bcd2_to_byte((tr.st(), tr.su())); - let st2 = bcd2_to_byte((tr2.st(), tr2.su())); - - assert!(st == st2); - assert!(ssr == ssr2); - - let _ = RTC::regs().dr().read(); - - trace!("rtc: instant now: st, ssr: {}, {}", st, ssr); - - Self { ssr, st } - } -} - -#[cfg(all(feature = "time", any(stm32wb, stm32f4)))] -impl core::ops::Sub for RtcInstant { - type Output = embassy_time::Duration; - - fn sub(self, rhs: Self) -> Self::Output { - use embassy_time::{Duration, TICK_HZ}; - - let st = if self.st < rhs.st { self.st + 60 } else { self.st }; - - // TODO: read prescaler - - let self_ticks = st as u32 * 256 + (255 - self.ssr as u32); - let other_ticks = rhs.st as u32 * 256 + (255 - rhs.ssr as u32); - let rtc_ticks = self_ticks - other_ticks; - - trace!( - "rtc: instant sub: self, other, rtc ticks: {}, {}, {}", - self_ticks, - other_ticks, - rtc_ticks - ); - - Duration::from_ticks( - ((((st as u32 * 256 + (255u32 - self.ssr as u32)) - (rhs.st as u32 * 256 + (255u32 - rhs.ssr as u32))) - * TICK_HZ as u32) as u32 - / 256u32) as u64, - ) - } -} - #[allow(dead_code)] #[derive(Clone, Copy, Debug)] pub(crate) enum WakeupPrescaler { @@ -165,16 +106,11 @@ impl super::Rtc { #[allow(dead_code)] #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] - /// start the wakeup alarm and return the actual duration of the alarm - /// the actual duration will be the closest value possible that is less - /// than the requested duration. - /// - /// note: this api is exposed for testing purposes until low power is implemented. - /// it is not intended to be public - pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) -> RtcInstant { + /// start the wakeup alarm and wtih a duration that is as close to but less than + /// the requested duration, and record the instant the wakeup alarm was started + pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { use embassy_time::{Duration, TICK_HZ}; - use crate::interrupt::typelevel::Interrupt; use crate::rcc::get_freqs; let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; @@ -206,47 +142,34 @@ impl super::Rtc { trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); - // self.write(false, |regs| { - // regs.cr().modify(|w| w.set_wutie(false)); - // - // regs.isr().modify(|w| w.set_wutf(false)); - // - // regs.cr().modify(|w| w.set_wutie(true)); - // }); - // - // trace!("rtc: clear wuf..."); - // crate::pac::PWR.cr1().modify(|w| w.set_cwuf(true)); - // while crate::pac::PWR.csr1().read().wuf() {} - // trace!("rtc: clear wuf...done"); - // - // crate::pac::PWR - // .cr1() - // .modify(|w| w.set_pdds(crate::pac::pwr::vals::Pdds::STANDBY_MODE)); - // - // // crate::pac::PWR.cr1().modify(|w| w.set_lpds(true)); - // - // // crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); - // crate::interrupt::typelevel::RTC_WKUP::unpend(); - - RtcInstant::now() + critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(RtcInstant::now())).is_none())) } #[allow(dead_code)] #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] - /// stop the wakeup alarm and return the time remaining - /// - /// note: this api is exposed for testing purposes until low power is implemented. - /// it is not intended to be public - pub(crate) fn stop_wakeup_alarm(&self) -> RtcInstant { + /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` + /// was called, otherwise none + pub(crate) fn stop_wakeup_alarm(&self) -> Option { + use crate::interrupt::typelevel::Interrupt; + trace!("rtc: stop wakeup alarm..."); self.write(false, |regs| { regs.cr().modify(|w| w.set_wutie(false)); regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); + + crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); + crate::interrupt::typelevel::RTC_WKUP::unpend(); }); - RtcInstant::now() + critical_section::with(|cs| { + if let Some(stop_time) = self.stop_time.borrow(cs).take() { + Some(RtcInstant::now() - stop_time) + } else { + None + } + }) } #[allow(dead_code)] diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 56f42aa9..99d423d0 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -15,7 +15,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::pac::timer::vals; use crate::rcc::sealed::RccPeripheral; #[cfg(feature = "low-power")] -use crate::rtc::{Rtc, RtcInstant}; +use crate::rtc::Rtc; use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; use crate::{interrupt, peripherals}; @@ -140,8 +140,6 @@ pub(crate) struct RtcDriver { alarms: Mutex, #[cfg(feature = "low-power")] rtc: Mutex>>, - #[cfg(feature = "low-power")] - stop_time: Mutex>>, } const ALARM_STATE_NEW: AlarmState = AlarmState::new(); @@ -152,8 +150,6 @@ embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), #[cfg(feature = "low-power")] rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), - #[cfg(feature = "low-power")] - stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }); impl RtcDriver { @@ -340,9 +336,8 @@ impl RtcDriver { /// Stop the wakeup alarm, if enabled, and add the appropriate offset fn stop_wakeup_alarm(&self) { critical_section::with(|cs| { - if let Some(stop_time) = self.stop_time.borrow(cs).take() { - let current_time = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(); - self.add_time(current_time - stop_time); + if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm() { + self.add_time(offset); } }); } @@ -361,17 +356,11 @@ impl RtcDriver { Err(()) } else { critical_section::with(|cs| { - assert!(self - .stop_time + self.rtc .borrow(cs) - .replace(Some( - self.rtc - .borrow(cs) - .get() - .unwrap() - .start_wakeup_alarm(time_until_next_alarm) - )) - .is_none()); + .get() + .unwrap() + .start_wakeup_alarm(time_until_next_alarm); }); T::regs_gp16().cr1().modify(|w| w.set_cen(false)); From db71887817e665c5c226e8775ad2d5814babac6e Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 26 Aug 2023 20:37:01 -0500 Subject: [PATCH 031/233] tests/stm32: add stop and cleanpu --- embassy-stm32/src/low_power.rs | 1 - tests/stm32/Cargo.toml | 9 +++++- tests/stm32/src/bin/stop.rs | 53 ++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 tests/stm32/src/bin/stop.rs diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 42536216..65b93f8a 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -3,7 +3,6 @@ use core::marker::PhantomData; use cortex_m::peripheral::SCB; use embassy_executor::*; -use embassy_time::Duration; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 754356cb..1f8c7373 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -7,7 +7,7 @@ autobins = false [features] stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill -stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "can", "not-gpdma", "dac-adc-pin"] # Nucleo "sdmmc" +stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "stop", "can", "not-gpdma", "dac-adc-pin"] # Nucleo "sdmmc" stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma", "dac-adc-pin"] # Nucleo stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo @@ -17,6 +17,7 @@ stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board sdmmc = [] +stop = ["embassy-stm32/low-power"] chrono = ["embassy-stm32/chrono", "dep:chrono"] can = [] ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] @@ -47,6 +48,7 @@ micromath = "2.0.0" panic-probe = { version = "0.3.0", features = ["print-defmt"] } rand_core = { version = "0.6", default-features = false } rand_chacha = { version = "0.3", default-features = false } +static_cell = {version = "1.1", features = ["nightly"] } chrono = { version = "^0.4", default-features = false, optional = true} @@ -87,6 +89,11 @@ name = "spi_dma" path = "src/bin/spi_dma.rs" required-features = [] +[[bin]] +name = "stop" +path = "src/bin/stop.rs" +required-features = [ "stop", "chrono",] + [[bin]] name = "timer" path = "src/bin/timer.rs" diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs new file mode 100644 index 00000000..4a49bde9 --- /dev/null +++ b/tests/stm32/src/bin/stop.rs @@ -0,0 +1,53 @@ +// required-features: stop,chrono + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] +#[path = "../common.rs"] +mod common; + +use chrono::NaiveDate; +use common::*; +use cortex_m_rt::entry; +use embassy_executor::Spawner; +use embassy_stm32::low_power::{stop_with_rtc, Executor}; +use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; +use embassy_time::{Duration, Timer}; +use static_cell::make_static; + +#[entry] +fn main() -> ! { + let executor = Executor::take(); + executor.run(|spawner| { + unwrap!(spawner.spawn(async_main(spawner))); + }); +} + +#[embassy_executor::task] +async fn async_main(_spawner: Spawner) { + let mut config = config(); + + config.rcc.rtc = Some(RtcClockSource::LSI); + + let p = embassy_stm32::init(config); + info!("Hello World!"); + + let now = NaiveDate::from_ymd_opt(2020, 5, 15) + .unwrap() + .and_hms_opt(10, 30, 15) + .unwrap(); + + let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + + rtc.set_datetime(now.into()).expect("datetime not set"); + + let rtc = make_static!(rtc); + + stop_with_rtc(rtc); + + info!("Waiting 5 seconds"); + Timer::after(Duration::from_secs(5)).await; + + info!("Test OK"); + cortex_m::asm::bkpt(); +} From 94de1a53530d58cf6db38dffcf434ba19a576d40 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 26 Aug 2023 20:40:21 -0500 Subject: [PATCH 032/233] stm32: feature-gate wakeup alarm --- embassy-stm32/src/rtc/v2.rs | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index d73e7083..bf926f98 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -89,23 +89,7 @@ impl super::Rtc { } } - // pub(crate) fn clear_wakeup_alarm(&self) { - // use crate::interrupt::typelevel::Interrupt; - // - // self.write(false, |regs| { - // regs.cr().modify(|w| w.set_wutie(false)); - // - // regs.isr().modify(|w| w.set_wutf(false)); - // crate::pac::PWR.cr1().modify(|w| w.set_cwuf(false)); - // crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, false)); - // crate::interrupt::typelevel::RTC_WKUP::unpend(); - // - // regs.cr().modify(|w| w.set_wutie(true)); - // }); - // } - - #[allow(dead_code)] - #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] + #[cfg(feature = "low-power")] /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { @@ -145,8 +129,7 @@ impl super::Rtc { critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(RtcInstant::now())).is_none())) } - #[allow(dead_code)] - #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] + #[cfg(feature = "low-power")] /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` /// was called, otherwise none pub(crate) fn stop_wakeup_alarm(&self) -> Option { From 59a5e84df584faed5676de027601d09772be55f7 Mon Sep 17 00:00:00 2001 From: aidant <15520814+aidant@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:36:35 +1000 Subject: [PATCH 033/233] fix day of the week conversion --- embassy-stm32/src/rtc/datetime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index a9c48d88..3efe9be5 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs @@ -89,7 +89,7 @@ pub enum DayOfWeek { #[cfg(feature = "chrono")] impl From for DayOfWeek { fn from(weekday: Weekday) -> Self { - day_of_week_from_u8(weekday.number_from_monday() as u8).unwrap() + day_of_week_from_u8(weekday.num_days_from_monday() as u8).unwrap() } } From db6f9afa2e4b1da47a655a59c4f09a60a3a87a50 Mon Sep 17 00:00:00 2001 From: aidant <15520814+aidant@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:37:10 +1000 Subject: [PATCH 034/233] fix hanging on rtc example --- examples/stm32f4/src/bin/rtc.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs index 0eca5820..33c4ebfd 100644 --- a/examples/stm32f4/src/bin/rtc.rs +++ b/examples/stm32f4/src/bin/rtc.rs @@ -5,13 +5,19 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_stm32::{ + rtc::{Rtc, RtcClockSource, RtcConfig}, + Config, +}; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let mut config = Config::default(); + config.rcc.rtc = Option::Some(RtcClockSource::LSI); + let p = embassy_stm32::init(config); + info!("Hello World!"); let now = NaiveDate::from_ymd_opt(2020, 5, 15) @@ -23,8 +29,11 @@ async fn main(_spawner: Spawner) { rtc.set_datetime(now.into()).expect("datetime not set"); - // In reality the delay would be much longer - Timer::after(Duration::from_millis(20000)).await; + loop { + let now: NaiveDateTime = rtc.now().unwrap().into(); - let _then: NaiveDateTime = rtc.now().unwrap().into(); + info!("{}", now.timestamp()); + + Timer::after(Duration::from_millis(1000)).await; + } } From 4b6538c8a86947c64a0cf22fadeac847923f16e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Fri, 25 Aug 2023 23:39:32 +0200 Subject: [PATCH 035/233] Fix read_fifo() better readout and more checks read_fifo() used part of the frame buffer to readout non-frame data. This results in incorrect readout of the fifo buffer but also the full MTU could not be used. Also added some more tests to check this and that the readout is a multipule of 4 bytes. --- embassy-net-adin1110/src/lib.rs | 187 ++++++++++++++++++++++++++++---- 1 file changed, 165 insertions(+), 22 deletions(-) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index c0a9b44e..8e5fef70 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -65,14 +65,16 @@ const FSC_LEN: usize = 4; const SPI_HEADER_LEN: usize = 2; /// SPI Header CRC length const SPI_HEADER_CRC_LEN: usize = 1; -/// Frame Header, +/// SPI Header Trun Around length +const SPI_HEADER_TA_LEN: usize = 1; +/// Frame Header length const FRAME_HEADER_LEN: usize = 2; +/// Space for last bytes to create multipule 4 bytes on the end of a FIFO read/write. +const SPI_SPACE_MULTIPULE: usize = 3; // P1 = 0x00, P2 = 0x01 const PORT_ID_BYTE: u8 = 0x00; -pub type Packet = Vec; - /// Type alias for the embassy-net driver for ADIN1110 pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; @@ -187,22 +189,24 @@ impl ADIN1110 { } /// Read out fifo ethernet packet memory received via the wire. - pub async fn read_fifo(&mut self, packet: &mut [u8]) -> AEResult { - let mut tx_buf = Vec::::new(); + pub async fn read_fifo(&mut self, frame: &mut [u8]) -> AEResult { + const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + SPI_HEADER_TA_LEN; + const TAIL_LEN: usize = FSC_LEN + SPI_SPACE_MULTIPULE; - // Size of the frame, also includes the appednded header. - let packet_size = self.read_reg(sr::RX_FSIZE).await? as usize; + let mut tx_buf = Vec::::new(); - // Packet read of write to the MAC packet buffer must be a multipul of 4! - let read_size = packet_size.next_multiple_of(4); + // Size of the frame, also includes the `frame header` and `FSC`. + let fifo_frame_size = self.read_reg(sr::RX_FSIZE).await? as usize; - if packet_size < (SPI_HEADER_LEN + FSC_LEN) { + if fifo_frame_size < ETH_MIN_LEN + FRAME_HEADER_LEN { return Err(AdinError::PACKET_TOO_SMALL); } - if read_size > packet.len() { + let packet_size = fifo_frame_size - FRAME_HEADER_LEN - FSC_LEN; + + if packet_size > frame.len() { #[cfg(feature = "defmt")] - defmt::trace!("MAX: {} WANT: {}", packet.len(), read_size); + defmt::trace!("MAX: {} WANT: {}", frame.len(), packet_size); return Err(AdinError::PACKET_TOO_BIG); } @@ -219,29 +223,28 @@ impl ADIN1110 { // Turn around byte, TODO: Unknown that this is. let _ = tx_buf.push(TURN_AROUND_BYTE); - let spi_packet = &mut packet[0..read_size]; + let mut frame_header = [0, 0]; + let mut fsc_and_extra = [0; TAIL_LEN]; - assert_eq!(spi_packet.len() & 0x03, 0x00); - - let mut pkt_header = [0, 0]; - let mut fsc = [0, 0, 0, 0]; + // Packet read of write to the MAC packet buffer must be a multipul of 4! + let tail_size = (fifo_frame_size & 0x03) + FSC_LEN; let mut spi_op = [ Operation::Write(&tx_buf), - Operation::Read(&mut pkt_header), - Operation::Read(spi_packet), - Operation::Read(&mut fsc), + Operation::Read(&mut frame_header), + Operation::Read(&mut frame[0..packet_size]), + Operation::Read(&mut fsc_and_extra[0..tail_size]), ]; self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; - Ok(packet_size as usize) + Ok(packet_size) } /// Write to fifo ethernet packet memory send over the wire. pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> { const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + FRAME_HEADER_LEN; - const TAIL_LEN: usize = ETH_MIN_LEN - FSC_LEN + FSC_LEN + 1; + const TAIL_LEN: usize = ETH_MIN_LEN - FSC_LEN + FSC_LEN + SPI_SPACE_MULTIPULE; if frame.len() < (6 + 6 + 2) { return Err(AdinError::PACKET_TOO_SMALL); @@ -1043,4 +1046,144 @@ mod tests { spi.done(); } + + #[futures_test::test] + async fn read_packet_from_fifo_packet_too_big_for_frame_buffer() { + // Configure expectations + let mut expectations = vec![]; + + // Read RX_SIZE reg + let rx_size: u32 = u32::try_from(ETH_MIN_LEN + FRAME_HEADER_LEN + FSC_LEN).unwrap(); + let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); + rx_size_vec.push(crc8(&rx_size_vec)); + + expectations.push(SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE])); + expectations.push(SpiTransaction::read_vec(rx_size_vec)); + expectations.push(SpiTransaction::flush()); + + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, true); + + let mut frame = [0; MTU]; + + let ret = spe.read_fifo(&mut frame[0..ETH_MIN_LEN - 1]).await; + assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_BIG))); + + spi.done(); + } + + #[futures_test::test] + async fn read_packet_from_fifo_packet_too_small() { + // Configure expectations + let mut expectations = vec![]; + + // This value is importen for this test! + assert_eq!(ETH_MIN_LEN, 64); + + // Packet data, size = `ETH_MIN_LEN` - `FSC_LEN` - 1 + let packet = [0; 64 - FSC_LEN - 1]; + + // Read RX_SIZE reg + let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FSC_LEN).unwrap(); + let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); + rx_size_vec.push(crc8(&rx_size_vec)); + + expectations.push(SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE])); + expectations.push(SpiTransaction::read_vec(rx_size_vec)); + expectations.push(SpiTransaction::flush()); + + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, true); + + let mut frame = [0; MTU]; + + let ret = spe.read_fifo(&mut frame).await; + assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_SMALL))); + + spi.done(); + } + + #[futures_test::test] + async fn read_packet_to_fifo_check_spi_read_multipule_of_u32_valid_lengths() { + let packet_buffer = [0; MTU]; + let mut frame = [0; MTU]; + let mut expectations = std::vec::Vec::with_capacity(16); + + // Packet data, size = `ETH_MIN_LEN` - `FSC_LEN` + for packet_size in [60, 61, 62, 63, 64, MTU - 4, MTU - 3, MTU - 2, MTU - 1, MTU] { + for crc_en in [false, true] { + expectations.clear(); + + let packet = &packet_buffer[0..packet_size]; + + // Read RX_SIZE reg + let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FSC_LEN).unwrap(); + let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); + if crc_en { + rx_size_vec.push(crc8(&rx_size_vec)); + } + + // SPI Header with CRC + let mut rx_fsize = vec![128, 144, 79, TURN_AROUND_BYTE]; + if !crc_en { + // remove the CRC on idx 2 + rx_fsize.swap_remove(2); + } + expectations.push(SpiTransaction::write_vec(rx_fsize)); + expectations.push(SpiTransaction::read_vec(rx_size_vec)); + expectations.push(SpiTransaction::flush()); + + // Read RX reg, SPI Header with CRC + let mut rx_reg = vec![128, 145, 72, TURN_AROUND_BYTE]; + if !crc_en { + // remove the CRC on idx 2 + rx_reg.swap_remove(2); + } + expectations.push(SpiTransaction::write_vec(rx_reg)); + // Frame Header + expectations.push(SpiTransaction::read_vec(vec![0, 0])); + // Packet data + expectations.push(SpiTransaction::read_vec(packet.to_vec())); + + let packet_crc = ETH_FSC::new(packet); + + let mut tail = std::vec::Vec::::with_capacity(100); + + tail.extend_from_slice(&packet_crc.hton_bytes()); + + // Need extra bytes? + let pad = (packet_size + FSC_LEN + FRAME_HEADER_LEN) & 0x03; + if pad != 0 { + // Packet FCS + optinal padding + tail.resize(tail.len() + pad, DONT_CARE_BYTE); + } + + expectations.push(SpiTransaction::read_vec(tail)); + expectations.push(SpiTransaction::flush()); + + let mut spi = SpiMock::new(&expectations); + + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + + let mut spe = ADIN1110::new(spi_dev, crc_en); + + let ret = spe.read_fifo(&mut frame).await.expect("Error!"); + assert_eq!(ret, packet_size); + + spi.done(); + } + } + } } From 7f7256050cd8a4f1cb1bb270ee39cb9c8dfdafb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Sat, 26 Aug 2023 00:21:01 +0200 Subject: [PATCH 036/233] Don't let the MAC add FCS when it is done by app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The application can append FSC to outgoing packets and the MAC can detect and report when a bitflip has occurred. But the MAC can also add FSC if we want, but we canĀ“t do both. When adding FSC by the application and MAC results in the packet drop by the MAC when the TX packet size > (MTU - 4). Having the application append the FSC is preferred. So set the right config bits. --- embassy-net-adin1110/src/lib.rs | 41 +++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 8e5fef70..4042bd73 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -58,9 +58,11 @@ const TURN_AROUND_BYTE: u8 = 0x00; /// Packet minimal frame/packet length const ETH_MIN_LEN: usize = 64; - /// Ethernet `Frame Check Sequence` length const FSC_LEN: usize = 4; +/// Packet minimal frame/packet length without `Frame Check Sequence` length +const ETH_MIN_WITHOUT_FSC_LEN: usize = ETH_MIN_LEN - FSC_LEN; + /// SPI Header, contains SPI action and register id. const SPI_HEADER_LEN: usize = 2; /// SPI Header CRC length @@ -283,8 +285,8 @@ impl ADIN1110 { // ADIN1110 MAC and PHY donĀ“t accept ethernet packet smaller than 64 bytes. // So padded the data minus the FCS, FCS is automatilly added to by the MAC. - if let Some(pad_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(frame.len()) { - let _ = tail_data.resize(pad_len, 0x00); + if frame.len() < ETH_MIN_WITHOUT_FSC_LEN { + let _ = tail_data.resize(ETH_MIN_WITHOUT_FSC_LEN - frame.len(), 0x00); frame_fcs = frame_fcs.update(&tail_data); } @@ -294,15 +296,18 @@ impl ADIN1110 { // len = frame_size + optional padding + 2 bytes Frame header let send_len_orig = frame.len() + tail_data.len() + FRAME_HEADER_LEN; - let spi_pad_len = send_len_orig.next_multiple_of(4); + let send_len = u32::try_from(send_len_orig).map_err(|_| AdinError::PACKET_TOO_BIG)?; // Packet read of write to the MAC packet buffer must be a multipul of 4 bytes! - if spi_pad_len != send_len_orig { - let spi_pad_len = spi_pad_len - send_len_orig; - let _ = tail_data.extend_from_slice(&[DONT_CARE_BYTE, DONT_CARE_BYTE, DONT_CARE_BYTE][..spi_pad_len]); + let pad_len = send_len_orig & 0x03; + if pad_len != 0 { + let spi_pad_len = 4 - pad_len + tail_data.len(); + let _ = tail_data.resize(spi_pad_len, DONT_CARE_BYTE); } + self.write_reg(sr::TX_FSIZE, send_len).await?; + #[cfg(feature = "defmt")] defmt::trace!( "TX: hdr {} [{}] {:02x}-{:02x}-{:02x} SIZE: {}", @@ -314,8 +319,6 @@ impl ADIN1110 { send_len, ); - self.write_reg(sr::TX_FSIZE, send_len).await?; - let mut transaction = [ Operation::Write(head_data.as_slice()), Operation::Write(frame), @@ -439,7 +442,12 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { Err(e) => match e { AdinError::PACKET_TOO_BIG => { #[cfg(feature = "defmt")] - defmt::error!("RX Packet to big, DROP"); + defmt::error!("RX Packet too big, DROP"); + self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap(); + } + AdinError::PACKET_TOO_SMALL => { + #[cfg(feature = "defmt")] + defmt::error!("RX Packet too small, DROP"); self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap(); } AdinError::Spi(_) => { @@ -622,9 +630,18 @@ pub async fn new Date: Sun, 27 Aug 2023 08:35:13 -0500 Subject: [PATCH 037/233] stm32/rcc: rename common to bus --- embassy-stm32/src/rcc/{common.rs => bus.rs} | 0 embassy-stm32/src/rcc/c0.rs | 2 +- embassy-stm32/src/rcc/f2.rs | 4 ++-- embassy-stm32/src/rcc/f3.rs | 6 +++--- embassy-stm32/src/rcc/g0.rs | 2 +- embassy-stm32/src/rcc/g4.rs | 2 +- embassy-stm32/src/rcc/h5.rs | 2 +- embassy-stm32/src/rcc/h7.rs | 2 +- embassy-stm32/src/rcc/l0.rs | 2 +- embassy-stm32/src/rcc/l1.rs | 2 +- embassy-stm32/src/rcc/l4.rs | 2 +- embassy-stm32/src/rcc/l5.rs | 2 +- embassy-stm32/src/rcc/mod.rs | 2 +- embassy-stm32/src/rcc/u5.rs | 4 ++-- embassy-stm32/src/rcc/wb.rs | 2 +- embassy-stm32/src/rcc/wl.rs | 2 +- 16 files changed, 19 insertions(+), 19 deletions(-) rename embassy-stm32/src/rcc/{common.rs => bus.rs} (100%) diff --git a/embassy-stm32/src/rcc/common.rs b/embassy-stm32/src/rcc/bus.rs similarity index 100% rename from embassy-stm32/src/rcc/common.rs rename to embassy-stm32/src/rcc/bus.rs diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 6a932634..d8579079 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw}; use crate::pac::{FLASH, RCC}; diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index ec4ed99b..9d9bc59f 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -1,7 +1,7 @@ use core::convert::TryFrom; use core::ops::{Div, Mul}; -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; use crate::pac::{FLASH, RCC}; @@ -201,7 +201,7 @@ pub struct PLLClocks { pub pll48_freq: Hertz, } -pub use super::common::VoltageScale; +pub use super::bus::VoltageScale; impl VoltageScale { const fn wait_states(&self, ahb_freq: Hertz) -> Option { diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 321270a7..7480c039 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -201,9 +201,9 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { // Calculates the Multiplier and the Divisor to arrive at // the required System clock from PLL source frequency let get_mul_div = |sysclk, pllsrcclk| { - let common_div = gcd(sysclk, pllsrcclk); - let mut multiplier = sysclk / common_div; - let mut divisor = pllsrcclk / common_div; + let bus_div = gcd(sysclk, pllsrcclk); + let mut multiplier = sysclk / bus_div; + let mut divisor = pllsrcclk / bus_div; // Minimum PLL multiplier is two if multiplier == 1 { multiplier *= 2; diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index bf2d5199..7fdbcb00 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{self, Hsidiv, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index dff04023..3b044cd1 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -2,7 +2,7 @@ use stm32_metapac::flash::vals::Latency; use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw}; use stm32_metapac::FLASH; -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::{PWR, RCC}; use crate::rcc::sealed::RccPeripheral; use crate::rcc::{set_freqs, Clocks}; diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs index 2e72b193..5741cdf9 100644 --- a/embassy-stm32/src/rcc/h5.rs +++ b/embassy-stm32/src/rcc/h5.rs @@ -26,7 +26,7 @@ const VCO_MAX: u32 = 420_000_000; const VCO_WIDE_MIN: u32 = 128_000_000; const VCO_WIDE_MAX: u32 = 560_000_000; -pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale}; +pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; pub enum HseMode { /// crystal/ceramic oscillator (HSEBYP=0) diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index 7fb4fb95..a6e69461 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -24,7 +24,7 @@ pub const HSI48_FREQ: Hertz = Hertz(48_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(32_000); -pub use super::common::VoltageScale; +pub use super::bus::VoltageScale; #[derive(Clone, Copy)] pub enum AdcClockSource { diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 46b58ca7..7f9ab01f 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; use crate::pac::RCC; #[cfg(crs)] diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs index bdfc5b87..ed949ea6 100644 --- a/embassy-stm32/src/rcc/l1.rs +++ b/embassy-stm32/src/rcc/l1.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index b34b8caa..4c4b4bfd 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -4,7 +4,7 @@ use embassy_hal_internal::into_ref; use stm32_metapac::rcc::regs::Cfgr; use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel}; -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index a85e1488..9e4e0fc7 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs @@ -1,6 +1,6 @@ use stm32_metapac::PWR; -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 45a4d880..f9ac88d9 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,6 +1,6 @@ #![macro_use] -pub mod common; +pub mod bus; use core::mem::MaybeUninit; diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index b5feeb0c..4aca9cd3 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -1,6 +1,6 @@ use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw}; -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -11,7 +11,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(32_000); -pub use super::common::VoltageScale; +pub use super::bus::VoltageScale; #[derive(Copy, Clone)] pub enum ClockSrc { diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index ae708b37..653d4d59 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::rcc::Clocks; use crate::rtc::{Rtc, RtcClockSource}; use crate::time::{khz, mhz, Hertz}; diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index f1dd2bd7..29f50dc6 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale}; +pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; use crate::pac::pwr::vals::Dbp; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; From 4caa8497fcac5099d9e885683542aca6b4f0911e Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 09:07:34 -0500 Subject: [PATCH 038/233] stm32: extract backupdomain into mod --- embassy-stm32/src/rcc/bd.rs | 168 +++++++++++++++++++++++++++++++++++ embassy-stm32/src/rcc/f4.rs | 4 +- embassy-stm32/src/rcc/l4.rs | 6 +- embassy-stm32/src/rcc/mod.rs | 1 + embassy-stm32/src/rcc/wb.rs | 6 +- embassy-stm32/src/rcc/wl.rs | 6 +- embassy-stm32/src/rtc/mod.rs | 16 +--- embassy-stm32/src/rtc/v2.rs | 81 +---------------- embassy-stm32/src/rtc/v3.rs | 65 +------------- 9 files changed, 185 insertions(+), 168 deletions(-) create mode 100644 embassy-stm32/src/rcc/bd.rs diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs new file mode 100644 index 00000000..e0973769 --- /dev/null +++ b/embassy-stm32/src/rcc/bd.rs @@ -0,0 +1,168 @@ +#[derive(Copy, Clone, Debug, PartialEq)] +#[repr(u8)] +pub enum RtcClockSource { + /// 00: No clock + NoClock = 0b00, + /// 01: LSE oscillator clock used as RTC clock + LSE = 0b01, + /// 10: LSI oscillator clock used as RTC clock + LSI = 0b10, + /// 11: HSE oscillator clock divided by 32 used as RTC clock + HSE = 0b11, +} + +pub struct BackupDomain {} + +impl BackupDomain { + #[cfg(any( + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + ))] + fn unlock_registers() { + #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] + let cr = crate::pac::PWR.cr(); + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] + let cr = crate::pac::PWR.cr1(); + + // TODO: Missing from PAC for l0 and f0? + #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] + { + if !cr.read().dbp() { + cr.modify(|w| w.set_dbp(true)); + while !cr.read().dbp() {} + } + } + } + + #[cfg(any(rtc_v3, rtc_v3u5))] + fn unlock_registers() { + // Unlock the backup domain + #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] + { + if !crate::pac::PWR.cr1().read().dbp() { + crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); + while !crate::pac::PWR.cr1().read().dbp() {} + } + } + #[cfg(any(rcc_wl5, rcc_wle))] + { + use crate::pac::pwr::vals::Dbp; + + if crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED { + crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); + while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} + } + } + } + + #[cfg(any( + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + ))] + pub fn set_rtc_clock_source(clock_source: RtcClockSource) { + #[cfg(not(rtc_v2wb))] + use stm32_metapac::rcc::vals::Rtcsel; + + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let cr = crate::pac::RCC.bdcr(); + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let cr = crate::pac::RCC.csr(); + + Self::unlock_registers(); + + cr.modify(|w| { + // Select RTC source + #[cfg(not(rtc_v2wb))] + w.set_rtcsel(Rtcsel::from_bits(clock_source as u8)); + #[cfg(rtc_v2wb)] + w.set_rtcsel(clock_source as u8); + }); + } + + #[cfg(any(rtc_v3, rtc_v3u5))] + pub fn set_rtc_clock_source(clock_source: RtcClockSource) { + let clock_source = clock_source as u8; + #[cfg(not(any(rcc_wl5, rcc_wle)))] + let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); + + Self::unlock_registers(); + + crate::pac::RCC.bdcr().modify(|w| { + // Select RTC source + w.set_rtcsel(clock_source); + }); + } + + #[cfg(any( + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + ))] + pub fn enable_rtc() { + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let reg = crate::pac::RCC.bdcr().read(); + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let reg = crate::pac::RCC.csr().read(); + + #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] + assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); + + if !reg.rtcen() { + Self::unlock_registers(); + + #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] + crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let cr = crate::pac::RCC.bdcr(); + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let cr = crate::pac::RCC.csr(); + + cr.modify(|w| { + // Reset + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + w.set_bdrst(false); + + w.set_rtcen(true); + w.set_rtcsel(reg.rtcsel()); + + // Restore bcdr + #[cfg(any(rtc_v2l4, rtc_v2wb))] + w.set_lscosel(reg.lscosel()); + #[cfg(any(rtc_v2l4, rtc_v2wb))] + w.set_lscoen(reg.lscoen()); + + w.set_lseon(reg.lseon()); + + #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] + w.set_lsedrv(reg.lsedrv()); + w.set_lsebyp(reg.lsebyp()); + }); + } + } + + #[cfg(any(rtc_v3, rtc_v3u5))] + pub fn enable_rtc() { + let bdcr = crate::pac::RCC.bdcr(); + + let reg = bdcr.read(); + assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); + + if !reg.rtcen() { + Self::unlock_registers(); + + bdcr.modify(|w| w.set_bdrst(true)); + + bdcr.modify(|w| { + // Reset + w.set_bdrst(false); + + w.set_rtcen(true); + w.set_rtcsel(reg.rtcsel()); + + // Restore bcdr + w.set_lscosel(reg.lscosel()); + w.set_lscoen(reg.lscoen()); + + w.set_lseon(reg.lseon()); + w.set_lsedrv(reg.lsedrv()); + w.set_lsebyp(reg.lsebyp()); + }); + } + } +} diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index ee9cb289..10d3322a 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -8,8 +8,8 @@ use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; -use crate::rtc::{Rtc, RtcClockSource}; use crate::time::Hertz; use crate::{peripherals, Peripheral}; @@ -470,7 +470,7 @@ pub(crate) unsafe fn init(config: Config) { } config.rtc.map(|clock_source| { - Rtc::set_clock_source(clock_source); + BackupDomain::set_rtc_clock_source(clock_source); }); let rtc = match config.rtc { diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 4c4b4bfd..1f02254b 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -9,8 +9,8 @@ use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::bd::{BackupDomain, RtcClockSource as RCS}; use crate::rcc::{set_freqs, Clocks}; -use crate::rtc::{Rtc, RtcClockSource as RCS}; use crate::time::Hertz; use crate::{peripherals, Peripheral}; @@ -429,7 +429,7 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSE is running while !RCC.bdcr().read().lserdy() {} - Rtc::set_clock_source(RCS::LSE); + BackupDomain::set_rtc_clock_source(RCS::LSE); } RtcClockSource::LSI32 => { // Turn on the internal 32 kHz LSI oscillator @@ -438,7 +438,7 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSI is running while !RCC.csr().read().lsirdy() {} - Rtc::set_clock_source(RCS::LSI); + BackupDomain::set_rtc_clock_source(RCS::LSI); } } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index f9ac88d9..7b68495b 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,5 +1,6 @@ #![macro_use] +pub(crate) mod bd; pub mod bus; use core::mem::MaybeUninit; diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index 653d4d59..6a3eab70 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -1,6 +1,6 @@ pub use super::bus::{AHBPrescaler, APBPrescaler}; +use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::Clocks; -use crate::rtc::{Rtc, RtcClockSource}; use crate::time::{khz, mhz, Hertz}; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, @@ -375,5 +375,7 @@ pub(crate) fn configure_clocks(config: &Config) { w.set_shdhpre(config.ahb3_pre.into()); }); - config.rtc.map(|clock_source| Rtc::set_clock_source(clock_source)); + config + .rtc + .map(|clock_source| BackupDomain::set_rtc_clock_source(clock_source)); } diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 29f50dc6..8a9b24c9 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,8 +1,8 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; use crate::pac::pwr::vals::Dbp; use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::bd::{BackupDomain, RtcClockSource as RCS}; use crate::rcc::{set_freqs, Clocks}; -use crate::rtc::{Rtc, RtcClockSource as RCS}; use crate::time::Hertz; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, @@ -231,7 +231,7 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSE is running while !RCC.bdcr().read().lserdy() {} - Rtc::set_clock_source(RCS::LSE); + BackupDomain::set_rtc_clock_source(RCS::LSE); } RtcClockSource::LSI32 => { // Turn on the internal 32 kHz LSI oscillator @@ -240,7 +240,7 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSI is running while !RCC.csr().read().lsirdy() {} - Rtc::set_clock_source(RCS::LSI); + BackupDomain::set_rtc_clock_source(RCS::LSI); } } diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 1f1abb78..0f915951 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -10,6 +10,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; +use crate::rcc::bd::BackupDomain; /// refer to AN4759 to compare features of RTC2 and RTC3 #[cfg_attr(any(rtc_v1), path = "v1.rs")] @@ -107,19 +108,6 @@ pub struct Rtc { stop_time: Mutex>>, } -#[derive(Copy, Clone, Debug, PartialEq)] -#[repr(u8)] -pub enum RtcClockSource { - /// 00: No clock - NoClock = 0b00, - /// 01: LSE oscillator clock used as RTC clock - LSE = 0b01, - /// 10: LSI oscillator clock used as RTC clock - LSI = 0b10, - /// 11: HSE oscillator clock divided by 32 used as RTC clock - HSE = 0b11, -} - #[derive(Copy, Clone, PartialEq)] pub struct RtcConfig { /// Asynchronous prescaler factor @@ -189,7 +177,7 @@ impl Rtc { stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }; - Self::enable(); + BackupDomain::enable_rtc(); rtc_struct.configure(rtc_config); rtc_struct.rtc_config = rtc_config; diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index bf926f98..1e0ca9b4 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -2,7 +2,7 @@ use stm32_metapac::rtc::vals::{Init, Osel, Pol}; #[cfg(feature = "low-power")] use super::RtcInstant; -use super::{sealed, RtcClockSource, RtcConfig}; +use super::{sealed, RtcConfig}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; use crate::rtc::sealed::Instance; @@ -73,22 +73,6 @@ impl WakeupPrescaler { } impl super::Rtc { - fn unlock_registers() { - #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] - let cr = crate::pac::PWR.cr(); - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] - let cr = crate::pac::PWR.cr1(); - - // TODO: Missing from PAC for l0 and f0? - #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] - { - if !cr.read().dbp() { - cr.modify(|w| w.set_dbp(true)); - while !cr.read().dbp() {} - } - } - } - #[cfg(feature = "low-power")] /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started @@ -155,69 +139,6 @@ impl super::Rtc { }) } - #[allow(dead_code)] - pub(crate) fn set_clock_source(clock_source: RtcClockSource) { - #[cfg(not(rtc_v2wb))] - use stm32_metapac::rcc::vals::Rtcsel; - - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let cr = crate::pac::RCC.bdcr(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let cr = crate::pac::RCC.csr(); - - Self::unlock_registers(); - - cr.modify(|w| { - // Select RTC source - #[cfg(not(rtc_v2wb))] - w.set_rtcsel(Rtcsel::from_bits(clock_source as u8)); - #[cfg(rtc_v2wb)] - w.set_rtcsel(clock_source as u8); - }); - } - - pub(super) fn enable() { - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let reg = crate::pac::RCC.bdcr().read(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let reg = crate::pac::RCC.csr().read(); - - #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() { - Self::unlock_registers(); - - #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let cr = crate::pac::RCC.bdcr(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let cr = crate::pac::RCC.csr(); - - cr.modify(|w| { - // Reset - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - w.set_bdrst(false); - - w.set_rtcen(true); - w.set_rtcsel(reg.rtcsel()); - - // Restore bcdr - #[cfg(any(rtc_v2l4, rtc_v2wb))] - w.set_lscosel(reg.lscosel()); - #[cfg(any(rtc_v2l4, rtc_v2wb))] - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - - #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } - } - /// Applies the RTC config /// It this changes the RTC clock source the time will be reset pub(super) fn configure(&mut self, rtc_config: RtcConfig) { diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 3297303e..12952b15 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -1,74 +1,11 @@ use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; -use super::{sealed, RtcCalibrationCyclePeriod, RtcClockSource, RtcConfig}; +use super::{sealed, RtcCalibrationCyclePeriod, RtcConfig}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; use crate::rtc::sealed::Instance; impl super::Rtc { - fn unlock_registers() { - // Unlock the backup domain - #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] - { - if !crate::pac::PWR.cr1().read().dbp() { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr1().read().dbp() {} - } - } - #[cfg(any(rcc_wl5, rcc_wle))] - { - use crate::pac::pwr::vals::Dbp; - - if crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); - while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} - } - } - } - - #[allow(dead_code)] - pub(crate) fn set_clock_source(clock_source: RtcClockSource) { - let clock_source = clock_source as u8; - #[cfg(not(any(rcc_wl5, rcc_wle)))] - let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); - - Self::unlock_registers(); - - crate::pac::RCC.bdcr().modify(|w| { - // Select RTC source - w.set_rtcsel(clock_source); - }); - } - - pub(super) fn enable() { - let bdcr = crate::pac::RCC.bdcr(); - - let reg = bdcr.read(); - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() { - Self::unlock_registers(); - - bdcr.modify(|w| w.set_bdrst(true)); - - bdcr.modify(|w| { - // Reset - w.set_bdrst(false); - - w.set_rtcen(true); - w.set_rtcsel(reg.rtcsel()); - - // Restore bcdr - w.set_lscosel(reg.lscosel()); - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } - } - /// Applies the RTC config /// It this changes the RTC clock source the time will be reset pub(super) fn configure(&mut self, rtc_config: RtcConfig) { From 10ea06802761a7aa6feb0241ebdbbe9bbaf37a7f Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 09:12:04 -0500 Subject: [PATCH 039/233] stm32/bd: allow dead code --- embassy-stm32/src/rcc/bd.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index e0973769..fd1b8d45 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -1,5 +1,6 @@ #[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] +#[allow(dead_code)] pub enum RtcClockSource { /// 00: No clock NoClock = 0b00, @@ -11,12 +12,14 @@ pub enum RtcClockSource { HSE = 0b11, } +#[allow(dead_code)] pub struct BackupDomain {} impl BackupDomain { #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb ))] + #[allow(dead_code)] fn unlock_registers() { #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] let cr = crate::pac::PWR.cr(); @@ -34,6 +37,7 @@ impl BackupDomain { } #[cfg(any(rtc_v3, rtc_v3u5))] + #[allow(dead_code)] fn unlock_registers() { // Unlock the backup domain #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] @@ -57,6 +61,7 @@ impl BackupDomain { #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb ))] + #[allow(dead_code)] pub fn set_rtc_clock_source(clock_source: RtcClockSource) { #[cfg(not(rtc_v2wb))] use stm32_metapac::rcc::vals::Rtcsel; @@ -78,6 +83,7 @@ impl BackupDomain { } #[cfg(any(rtc_v3, rtc_v3u5))] + #[allow(dead_code)] pub fn set_rtc_clock_source(clock_source: RtcClockSource) { let clock_source = clock_source as u8; #[cfg(not(any(rcc_wl5, rcc_wle)))] @@ -94,6 +100,7 @@ impl BackupDomain { #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb ))] + #[allow(dead_code)] pub fn enable_rtc() { #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] let reg = crate::pac::RCC.bdcr().read(); @@ -137,6 +144,7 @@ impl BackupDomain { } #[cfg(any(rtc_v3, rtc_v3u5))] + #[allow(dead_code)] pub fn enable_rtc() { let bdcr = crate::pac::RCC.bdcr(); From fb942e6675097540b6ca3f5fa37e0696337c2fc0 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 09:25:14 -0500 Subject: [PATCH 040/233] stm32: re-export rtcclocksource --- embassy-stm32/src/rcc/mod.rs | 2 +- embassy-stm32/src/rtc/mod.rs | 1 + tests/stm32/src/bin/rtc.rs | 3 ++- tests/stm32/src/bin/stop.rs | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 7b68495b..9f1b3b66 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -2,9 +2,9 @@ pub(crate) mod bd; pub mod bus; - use core::mem::MaybeUninit; +pub use crate::rcc::bd::RtcClockSource; use crate::time::Hertz; #[cfg_attr(rcc_f0, path = "f0.rs")] diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 0f915951..c408b2d6 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -11,6 +11,7 @@ use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; use crate::rcc::bd::BackupDomain; +pub use crate::rcc::RtcClockSource; /// refer to AN4759 to compare features of RTC2 and RTC3 #[cfg_attr(any(rtc_v1), path = "v1.rs")] diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs index 7df415b4..1a64dd38 100644 --- a/tests/stm32/src/bin/rtc.rs +++ b/tests/stm32/src/bin/rtc.rs @@ -10,7 +10,8 @@ use chrono::{NaiveDate, NaiveDateTime}; use common::*; use defmt::assert; use embassy_executor::Spawner; -use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; +use embassy_stm32::rcc::RtcClockSource; +use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_time::{Duration, Timer}; #[embassy_executor::main] diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index 4a49bde9..0b3f4a30 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -11,7 +11,8 @@ use common::*; use cortex_m_rt::entry; use embassy_executor::Spawner; use embassy_stm32::low_power::{stop_with_rtc, Executor}; -use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; +use embassy_stm32::rcc::RtcClockSource; +use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_time::{Duration, Timer}; use static_cell::make_static; From 3bf6081eb5985d853ffee1bf8064304daa1fdfd8 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 09:41:31 -0500 Subject: [PATCH 041/233] stm32: fix wl re-export --- embassy-stm32/src/rcc/wl.rs | 20 ++++++++------------ examples/stm32wl/src/bin/rtc.rs | 6 +++--- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 8a9b24c9..5b190965 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,7 +1,7 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; use crate::pac::pwr::vals::Dbp; use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::bd::{BackupDomain, RtcClockSource as RCS}; +use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -130,16 +130,11 @@ impl Default for Config { apb2_pre: APBPrescaler::NotDivided, enable_lsi: false, enable_rtc_apb: false, - rtc_mux: RtcClockSource::LSI32, + rtc_mux: RtcClockSource::LSI, } } } -pub enum RtcClockSource { - LSE32, - LSI32, -} - #[repr(u8)] pub enum Lsedrv { Low = 0, @@ -215,7 +210,7 @@ pub(crate) unsafe fn init(config: Config) { while FLASH.acr().read().latency() != ws {} match config.rtc_mux { - RtcClockSource::LSE32 => { + RtcClockSource::LSE => { // 1. Unlock the backup domain PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); @@ -231,17 +226,18 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSE is running while !RCC.bdcr().read().lserdy() {} - BackupDomain::set_rtc_clock_source(RCS::LSE); + BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); } - RtcClockSource::LSI32 => { + RtcClockSource::LSI => { // Turn on the internal 32 kHz LSI oscillator RCC.csr().modify(|w| w.set_lsion(true)); // Wait until LSI is running while !RCC.csr().read().lsirdy() {} - BackupDomain::set_rtc_clock_source(RCS::LSI); + BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); } + _ => unreachable!(), } match config.mux { @@ -266,7 +262,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_msirange(range.into()); w.set_msion(true); - if let RtcClockSource::LSE32 = config.rtc_mux { + if let RtcClockSource::LSE = config.rtc_mux { // If LSE is enabled, enable calibration of MSI w.set_msipllen(true); } else { diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index fb1bc6e3..2be6c7b9 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs @@ -5,8 +5,8 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::{self, ClockSrc}; -use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_stm32::rcc::ClockSrc; +use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; use embassy_stm32::Config; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) { let p = { let mut config = Config::default(); config.rcc.mux = ClockSrc::HSE32; - config.rcc.rtc_mux = rcc::RtcClockSource::LSE32; + config.rcc.rtc_mux = RtcClockSource::LSE; config.rcc.enable_rtc_apb = true; embassy_stm32::init(config) }; From f28ab18d7bc05ade2130979d67b0af6ad4085d76 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 09:50:02 -0500 Subject: [PATCH 042/233] stm32: fix l4 re-export --- embassy-stm32/src/rcc/l4.rs | 20 ++++++++----------- examples/stm32l4/src/bin/rtc.rs | 2 +- .../src/bin/spe_adin1110_http_server.rs | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 1f02254b..c6bccfd2 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -9,7 +9,7 @@ use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::bd::{BackupDomain, RtcClockSource as RCS}; +use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; use crate::{peripherals, Peripheral}; @@ -254,16 +254,11 @@ impl Default for Config { pllsai1: None, #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] hsi48: false, - rtc_mux: RtcClockSource::LSI32, + rtc_mux: RtcClockSource::LSI, } } } -pub enum RtcClockSource { - LSE32, - LSI32, -} - pub enum McoClock { DIV1, DIV2, @@ -413,7 +408,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr1().modify(|w| w.set_pwren(true)); match config.rtc_mux { - RtcClockSource::LSE32 => { + RtcClockSource::LSE => { // 1. Unlock the backup domain PWR.cr1().modify(|w| w.set_dbp(true)); @@ -429,17 +424,18 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSE is running while !RCC.bdcr().read().lserdy() {} - BackupDomain::set_rtc_clock_source(RCS::LSE); + BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); } - RtcClockSource::LSI32 => { + RtcClockSource::LSI => { // Turn on the internal 32 kHz LSI oscillator RCC.csr().modify(|w| w.set_lsion(true)); // Wait until LSI is running while !RCC.csr().read().lsirdy() {} - BackupDomain::set_rtc_clock_source(RCS::LSI); + BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); } + _ => unreachable!(), } let (sys_clk, sw) = match config.mux { @@ -451,7 +447,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_msirgsel(true); w.set_msion(true); - if let RtcClockSource::LSE32 = config.rtc_mux { + if let RtcClockSource::LSE = config.rtc_mux { // If LSE is enabled, enable calibration of MSI w.set_msipllen(true); } else { diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index 294ea456..f3f8aa46 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { PLLMul::Mul20, None, ); - config.rcc.rtc_mux = rcc::RtcClockSource::LSE32; + config.rcc.rtc_mux = rcc::RtcClockSource::LSE; embassy_stm32::init(config) }; info!("Hello World!"); diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 148c5877..0a677be7 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -84,7 +84,7 @@ async fn main(spawner: Spawner) { None, ); config.rcc.hsi48 = true; // needed for rng - config.rcc.rtc_mux = rcc::RtcClockSource::LSI32; + config.rcc.rtc_mux = rcc::RtcClockSource::LSI; let dp = embassy_stm32::init(config); From 531f51d0eb66af9b681b49c10e28ef25e88bbcc2 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 15:01:09 -0500 Subject: [PATCH 043/233] rcc/bd: consolidate mod --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/rcc/bd.rs | 119 +++++++++++++----------------------- embassy-stm32/src/rcc/wl.rs | 3 +- 3 files changed, 46 insertions(+), 80 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 150014af..d0ada97a 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b87e34c661e19ff6dc603fabfe7fe99ab7261f7" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9a61a1f090462df8bd1751f89951f04934fdceb3" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -77,7 +77,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b87e34c661e19ff6dc603fabfe7fe99ab7261f7", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9a61a1f090462df8bd1751f89951f04934fdceb3", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index fd1b8d45..d56bc033 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -12,86 +12,67 @@ pub enum RtcClockSource { HSE = 0b11, } +#[cfg(not(any(rtc_v2l0, rtc_v2l1)))] +type Bdcr = crate::pac::rcc::regs::Bdcr; + +#[cfg(any(rtc_v2l0, rtc_v2l1))] +type Bdcr = crate::pac::rcc::regs::Csr; + #[allow(dead_code)] pub struct BackupDomain {} impl BackupDomain { #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, + rtc_v3u5 ))] #[allow(dead_code)] - fn unlock_registers() { + fn modify(f: impl FnOnce(&mut Bdcr) -> R) -> R { #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] let cr = crate::pac::PWR.cr(); - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] let cr = crate::pac::PWR.cr1(); // TODO: Missing from PAC for l0 and f0? - #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] + #[cfg(not(any(rtc_v2f0, rtc_v2l0, rtc_v3u5)))] { - if !cr.read().dbp() { - cr.modify(|w| w.set_dbp(true)); - while !cr.read().dbp() {} - } + cr.modify(|w| w.set_dbp(true)); + while !cr.read().dbp() {} } - } - #[cfg(any(rtc_v3, rtc_v3u5))] - #[allow(dead_code)] - fn unlock_registers() { - // Unlock the backup domain - #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] - { - if !crate::pac::PWR.cr1().read().dbp() { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr1().read().dbp() {} - } - } - #[cfg(any(rcc_wl5, rcc_wle))] - { - use crate::pac::pwr::vals::Dbp; - - if crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); - while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} - } - } + crate::pac::RCC.bdcr().modify(|w| f(w)) } #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, + rtc_v3u5 + ))] + #[allow(dead_code)] + fn read() -> Bdcr { + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let r = crate::pac::RCC.csr().read(); + + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let r = crate::pac::RCC.bdcr().read(); + + r + } + + #[cfg(any( + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, + rtc_v3u5 ))] #[allow(dead_code)] - pub fn set_rtc_clock_source(clock_source: RtcClockSource) { - #[cfg(not(rtc_v2wb))] - use stm32_metapac::rcc::vals::Rtcsel; - - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let cr = crate::pac::RCC.bdcr(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let cr = crate::pac::RCC.csr(); - - Self::unlock_registers(); - - cr.modify(|w| { - // Select RTC source - #[cfg(not(rtc_v2wb))] - w.set_rtcsel(Rtcsel::from_bits(clock_source as u8)); - #[cfg(rtc_v2wb)] - w.set_rtcsel(clock_source as u8); - }); - } - - #[cfg(any(rtc_v3, rtc_v3u5))] - #[allow(dead_code)] pub fn set_rtc_clock_source(clock_source: RtcClockSource) { let clock_source = clock_source as u8; - #[cfg(not(any(rcc_wl5, rcc_wle)))] + #[cfg(any( + all(not(any(rtc_v3, rtc_v3u5)), not(rtc_v2wb)), + all(any(rtc_v3, rtc_v3u5), not(any(rcc_wl5, rcc_wle))) + ))] let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); - Self::unlock_registers(); - - crate::pac::RCC.bdcr().modify(|w| { + #[cfg(not(rtc_v2wb))] + Self::modify(|w| { // Select RTC source w.set_rtcsel(clock_source); }); @@ -102,25 +83,16 @@ impl BackupDomain { ))] #[allow(dead_code)] pub fn enable_rtc() { - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let reg = crate::pac::RCC.bdcr().read(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let reg = crate::pac::RCC.csr().read(); + let reg = Self::read(); #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); if !reg.rtcen() { - Self::unlock_registers(); - #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let cr = crate::pac::RCC.bdcr(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let cr = crate::pac::RCC.csr(); + Self::modify(|w| w.set_bdrst(true)); - cr.modify(|w| { + Self::modify(|w| { // Reset #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] w.set_bdrst(false); @@ -146,18 +118,13 @@ impl BackupDomain { #[cfg(any(rtc_v3, rtc_v3u5))] #[allow(dead_code)] pub fn enable_rtc() { - let bdcr = crate::pac::RCC.bdcr(); - - let reg = bdcr.read(); + let reg = Self::read(); assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); if !reg.rtcen() { - Self::unlock_registers(); + Self::modify(|w| w.set_bdrst(true)); - bdcr.modify(|w| w.set_bdrst(true)); - - bdcr.modify(|w| { - // Reset + Self::modify(|w| { w.set_bdrst(false); w.set_rtcen(true); diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 5b190965..e33690d1 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,5 +1,4 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; -use crate::pac::pwr::vals::Dbp; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; @@ -212,7 +211,7 @@ pub(crate) unsafe fn init(config: Config) { match config.rtc_mux { RtcClockSource::LSE => { // 1. Unlock the backup domain - PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); + PWR.cr1().modify(|w| w.set_dbp(true)); // 2. Setup the LSE RCC.bdcr().modify(|w| { From cbc92dce052060bb15b82921c0a05c3a81d6dcc9 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 15:18:34 -0500 Subject: [PATCH 044/233] stm32/bd: fix errors --- embassy-stm32/src/rcc/bd.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index d56bc033..0fc116ed 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -12,10 +12,12 @@ pub enum RtcClockSource { HSE = 0b11, } -#[cfg(not(any(rtc_v2l0, rtc_v2l1)))] +#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] +#[allow(dead_code)] type Bdcr = crate::pac::rcc::regs::Bdcr; #[cfg(any(rtc_v2l0, rtc_v2l1))] +#[allow(dead_code)] type Bdcr = crate::pac::rcc::regs::Csr; #[allow(dead_code)] @@ -26,7 +28,7 @@ impl BackupDomain { rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5 ))] - #[allow(dead_code)] + #[allow(dead_code, unused_variables)] fn modify(f: impl FnOnce(&mut Bdcr) -> R) -> R { #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] let cr = crate::pac::PWR.cr(); @@ -40,7 +42,13 @@ impl BackupDomain { while !cr.read().dbp() {} } - crate::pac::RCC.bdcr().modify(|w| f(w)) + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let cr = crate::pac::RCC.csr(); + + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let cr = crate::pac::RCC.bdcr(); + + cr.modify(|w| f(w)) } #[cfg(any( @@ -62,7 +70,7 @@ impl BackupDomain { rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5 ))] - #[allow(dead_code)] + #[allow(dead_code, unused_variables)] pub fn set_rtc_clock_source(clock_source: RtcClockSource) { let clock_source = clock_source as u8; #[cfg(any( From 326e78757b6b69ba598fb89030defd62e081af64 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 15:25:12 -0500 Subject: [PATCH 045/233] rustfmt --- examples/stm32f4/src/bin/rtc.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs index 33c4ebfd..23ff8ac4 100644 --- a/examples/stm32f4/src/bin/rtc.rs +++ b/examples/stm32f4/src/bin/rtc.rs @@ -5,10 +5,8 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::{ - rtc::{Rtc, RtcClockSource, RtcConfig}, - Config, -}; +use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; +use embassy_stm32::Config; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; From 9f928010a86be9e0f8b5fa4257c3edd70261c0dc Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 16:06:33 -0500 Subject: [PATCH 046/233] stm32/rtc: use psc to compute instants --- embassy-stm32/src/rtc/mod.rs | 53 ++++++++++++------------------------ embassy-stm32/src/rtc/v2.rs | 4 +-- 2 files changed, 19 insertions(+), 38 deletions(-) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index c408b2d6..8bda0926 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -47,31 +47,6 @@ struct RtcInstant { subsecond: u16, } -#[cfg(feature = "low-power")] -impl RtcInstant { - pub fn now() -> Self { - let tr = RTC::regs().tr().read(); - let tr2 = RTC::regs().tr().read(); - let ssr = RTC::regs().ssr().read().ss(); - let ssr2 = RTC::regs().ssr().read().ss(); - - let st = bcd2_to_byte((tr.st(), tr.su())); - let st2 = bcd2_to_byte((tr2.st(), tr2.su())); - - assert!(st == st2); - assert!(ssr == ssr2); - - let _ = RTC::regs().dr().read(); - - let subsecond = ssr; - let second = st; - - // trace!("rtc: instant now: st, ssr: {}, {}", st, ssr); - - Self { second, subsecond } - } -} - #[cfg(feature = "low-power")] impl core::ops::Sub for RtcInstant { type Output = embassy_time::Duration; @@ -85,20 +60,13 @@ impl core::ops::Sub for RtcInstant { self.second }; - // TODO: read prescaler + let psc = RTC::regs().prer().read().prediv_s() as u32; - let self_ticks = second as u32 * 256 + (255 - self.subsecond as u32); - let other_ticks = rhs.second as u32 * 256 + (255 - rhs.subsecond as u32); + let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32); + let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32); let rtc_ticks = self_ticks - other_ticks; - // trace!( - // "rtc: instant sub: self, other, rtc ticks: {}, {}, {}", - // self_ticks, - // other_ticks, - // rtc_ticks - // ); - - Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / 256u32) as u64) + Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / psc) as u64) } } @@ -198,6 +166,19 @@ impl Rtc { Ok(()) } + /// Return the current instant. + fn instant(&self) -> RtcInstant { + let r = RTC::regs(); + let tr = r.tr().read(); + let subsecond = r.ssr().read().ss(); + let second = bcd2_to_byte((tr.st(), tr.su())); + + // Unlock the registers + r.dr(); + + RtcInstant { second, subsecond } + } + /// Return the current datetime. /// /// # Errors diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 1e0ca9b4..62b39868 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -110,7 +110,7 @@ impl super::Rtc { trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); - critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(RtcInstant::now())).is_none())) + critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) } #[cfg(feature = "low-power")] @@ -132,7 +132,7 @@ impl super::Rtc { critical_section::with(|cs| { if let Some(stop_time) = self.stop_time.borrow(cs).take() { - Some(RtcInstant::now() - stop_time) + Some(self.instant() - stop_time) } else { None } From 13a0be628937125042a961175861bbdba6dcab34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Sat, 26 Aug 2023 01:29:06 +0200 Subject: [PATCH 047/233] Validate FCS in fifo_read() and refactor tests. Adding TestHarnass to declutter the tests. Also added a test for FCS and SPI_CRC. --- embassy-net-adin1110/src/crc32.rs | 29 +- embassy-net-adin1110/src/lib.rs | 451 +++++++++++++++++++----------- embassy-net-adin1110/src/regs.rs | 2 +- 3 files changed, 307 insertions(+), 175 deletions(-) diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs index a3474f70..ec020b70 100644 --- a/embassy-net-adin1110/src/crc32.rs +++ b/embassy-net-adin1110/src/crc32.rs @@ -257,29 +257,30 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [ 0x2D02_EF8D, ]; +/// Generate Ethernet Frame Check Sequence #[allow(non_camel_case_types)] #[derive(Debug)] -pub struct ETH_FSC(pub u32); +pub struct ETH_FCS(pub u32); -impl ETH_FSC { +impl ETH_FCS { pub const CRC32_OK: u32 = 0x2144_df1c; #[must_use] pub fn new(data: &[u8]) -> Self { - let fsc = data.iter().fold(u32::MAX, |crc, byte| { + let fcs = data.iter().fold(u32::MAX, |crc, byte| { let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte; CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8) }) ^ u32::MAX; - Self(fsc) + Self(fcs) } #[must_use] pub fn update(self, data: &[u8]) -> Self { - let fsc = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| { + let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| { let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte; CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8) }) ^ u32::MAX; - Self(fsc) + Self(fcs) } #[must_use] @@ -319,24 +320,24 @@ mod tests { ]; // Packet A - let own_crc = ETH_FSC::new(&packet_a[0..60]); + let own_crc = ETH_FCS::new(&packet_a[0..60]); let crc_bytes = own_crc.hton_bytes(); println!("{:08x} {:02x?}", own_crc.0, crc_bytes); assert_eq!(&crc_bytes, &packet_a[60..64]); - let own_crc = ETH_FSC::new(packet_a); + let own_crc = ETH_FCS::new(packet_a); println!("{:08x}", own_crc.0); - assert_eq!(own_crc.0, ETH_FSC::CRC32_OK); + assert_eq!(own_crc.0, ETH_FCS::CRC32_OK); // Packet B - let own_crc = ETH_FSC::new(&packet_b[0..60]); + let own_crc = ETH_FCS::new(&packet_b[0..60]); let crc_bytes = own_crc.hton_bytes(); println!("{:08x} {:02x?}", own_crc.0, crc_bytes); assert_eq!(&crc_bytes, &packet_b[60..64]); - let own_crc = ETH_FSC::new(packet_b); + let own_crc = ETH_FCS::new(packet_b); println!("{:08x}", own_crc.0); - assert_eq!(own_crc.0, ETH_FSC::CRC32_OK); + assert_eq!(own_crc.0, ETH_FCS::CRC32_OK); } #[test] @@ -349,9 +350,9 @@ mod tests { ]; let (part_a, part_b) = full_data.split_at(16); - let crc_partially = ETH_FSC::new(part_a).update(part_b); + let crc_partially = ETH_FCS::new(part_a).update(part_b); - let crc_full = ETH_FSC::new(full_data); + let crc_full = ETH_FCS::new(full_data); assert_eq!(crc_full.0, crc_partially.0); } diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 4042bd73..8d73e024 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -13,7 +13,7 @@ mod phy; mod regs; use ch::driver::LinkState; -pub use crc32::ETH_FSC; +pub use crc32::ETH_FCS; use crc8::crc8; use embassy_futures::select::{select, Either}; use embassy_net_driver_channel as ch; @@ -35,16 +35,22 @@ pub const PHYID: u32 = 0x0283_BC91; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[allow(non_camel_case_types)] pub enum AdinError { + /// SPI-BUS Error Spi(E), - SENDERROR, - READERROR, - CRC, + /// Ethernet FCS error + FCS, + /// SPI Header CRC error + SPI_CRC, + /// Received or sended ethernet packet is too big PACKET_TOO_BIG, + /// Received or sended ethernet packet is too small PACKET_TOO_SMALL, + /// MDIO transaction timeout MDIO_ACC_TIMEOUT, } pub type AEResult = core::result::Result>; +/// Internet PHY address pub const MDIO_PHY_ADDR: u8 = 0x01; /// Maximum Transmission Unit @@ -59,9 +65,9 @@ const TURN_AROUND_BYTE: u8 = 0x00; /// Packet minimal frame/packet length const ETH_MIN_LEN: usize = 64; /// Ethernet `Frame Check Sequence` length -const FSC_LEN: usize = 4; +const FCS_LEN: usize = 4; /// Packet minimal frame/packet length without `Frame Check Sequence` length -const ETH_MIN_WITHOUT_FSC_LEN: usize = ETH_MIN_LEN - FSC_LEN; +const ETH_MIN_WITHOUT_FCS_LEN: usize = ETH_MIN_LEN - FCS_LEN; /// SPI Header, contains SPI action and register id. const SPI_HEADER_LEN: usize = 2; @@ -74,7 +80,7 @@ const FRAME_HEADER_LEN: usize = 2; /// Space for last bytes to create multipule 4 bytes on the end of a FIFO read/write. const SPI_SPACE_MULTIPULE: usize = 3; -// P1 = 0x00, P2 = 0x01 +/// P1 = 0x00, P2 = 0x01 const PORT_ID_BYTE: u8 = 0x00; /// Type alias for the embassy-net driver for ADIN1110 @@ -100,12 +106,18 @@ pub struct ADIN1110 { spi: SPI, /// Enable CRC on SPI transfer. /// This must match with the hardware pin `SPI_CFG0` were low = CRC enable, high = CRC disabled. - crc: bool, + spi_crc: bool, + /// Append FCS by the application of transmit packet, false = FCS is appended by the MAC, true = FCS appended by the application. + append_fcs_on_tx: bool, } impl ADIN1110 { - pub fn new(spi: SPI, crc: bool) -> Self { - Self { spi, crc } + pub fn new(spi: SPI, spi_crc: bool, append_fcs_on_tx: bool) -> Self { + Self { + spi, + spi_crc, + append_fcs_on_tx, + } } pub async fn read_reg(&mut self, reg: sr) -> AEResult { @@ -116,7 +128,7 @@ impl ADIN1110 { spi_hdr.set_addr(reg); let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); - if self.crc { + if self.spi_crc { // Add CRC for header data let _ = tx_buf.push(crc8(&tx_buf)); } @@ -126,16 +138,16 @@ impl ADIN1110 { let mut rx_buf = [0; 5]; - let spi_read_len = if self.crc { rx_buf.len() } else { rx_buf.len() - 1 }; + let spi_read_len = if self.spi_crc { rx_buf.len() } else { rx_buf.len() - 1 }; let mut spi_op = [Operation::Write(&tx_buf), Operation::Read(&mut rx_buf[0..spi_read_len])]; self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; - if self.crc { + if self.spi_crc { let crc = crc8(&rx_buf[0..4]); if crc != rx_buf[4] { - return Err(AdinError::CRC); + return Err(AdinError::SPI_CRC); } } @@ -156,7 +168,7 @@ impl ADIN1110 { spi_hdr.set_addr(reg); let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); - if self.crc { + if self.spi_crc { // Add CRC for header data let _ = tx_buf.push(crc8(&tx_buf)); } @@ -164,7 +176,7 @@ impl ADIN1110 { let val = value.to_be_bytes(); let _ = tx_buf.extend_from_slice(val.as_slice()); - if self.crc { + if self.spi_crc { // Add CRC for header data let _ = tx_buf.push(crc8(val.as_slice())); } @@ -193,18 +205,18 @@ impl ADIN1110 { /// Read out fifo ethernet packet memory received via the wire. pub async fn read_fifo(&mut self, frame: &mut [u8]) -> AEResult { const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + SPI_HEADER_TA_LEN; - const TAIL_LEN: usize = FSC_LEN + SPI_SPACE_MULTIPULE; + const TAIL_LEN: usize = FCS_LEN + SPI_SPACE_MULTIPULE; let mut tx_buf = Vec::::new(); - // Size of the frame, also includes the `frame header` and `FSC`. + // Size of the frame, also includes the `frame header` and `FCS`. let fifo_frame_size = self.read_reg(sr::RX_FSIZE).await? as usize; if fifo_frame_size < ETH_MIN_LEN + FRAME_HEADER_LEN { return Err(AdinError::PACKET_TOO_SMALL); } - let packet_size = fifo_frame_size - FRAME_HEADER_LEN - FSC_LEN; + let packet_size = fifo_frame_size - FRAME_HEADER_LEN - FCS_LEN; if packet_size > frame.len() { #[cfg(feature = "defmt")] @@ -217,7 +229,7 @@ impl ADIN1110 { spi_hdr.set_addr(sr::RX); let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); - if self.crc { + if self.spi_crc { // Add CRC for header data let _ = tx_buf.push(crc8(&tx_buf)); } @@ -226,27 +238,36 @@ impl ADIN1110 { let _ = tx_buf.push(TURN_AROUND_BYTE); let mut frame_header = [0, 0]; - let mut fsc_and_extra = [0; TAIL_LEN]; + let mut fcs_and_extra = [0; TAIL_LEN]; // Packet read of write to the MAC packet buffer must be a multipul of 4! - let tail_size = (fifo_frame_size & 0x03) + FSC_LEN; + let tail_size = (fifo_frame_size & 0x03) + FCS_LEN; let mut spi_op = [ Operation::Write(&tx_buf), Operation::Read(&mut frame_header), Operation::Read(&mut frame[0..packet_size]), - Operation::Read(&mut fsc_and_extra[0..tail_size]), + Operation::Read(&mut fcs_and_extra[0..tail_size]), ]; self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; - Ok(packet_size) + // According to register `CONFIG2`, bit 5 `CRC_APPEND` discription: + // "Similarly, on receive, the CRC32 is forwarded with the frame to the host where the host must verify it is correct." + // The application must allways check the FCS. It seems that the MAC/PHY has no option to handle this. + let fcs_calc = ETH_FCS::new(&frame[0..packet_size]); + + if fcs_calc.hton_bytes() == fcs_and_extra[0..4] { + Ok(packet_size) + } else { + Err(AdinError::FCS) + } } /// Write to fifo ethernet packet memory send over the wire. pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> { const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + FRAME_HEADER_LEN; - const TAIL_LEN: usize = ETH_MIN_LEN - FSC_LEN + FSC_LEN + SPI_SPACE_MULTIPULE; + const TAIL_LEN: usize = ETH_MIN_LEN - FCS_LEN + FCS_LEN + SPI_SPACE_MULTIPULE; if frame.len() < (6 + 6 + 2) { return Err(AdinError::PACKET_TOO_SMALL); @@ -269,7 +290,7 @@ impl ADIN1110 { .extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()) .map_err(|_e| AdinError::PACKET_TOO_BIG)?; - if self.crc { + if self.spi_crc { // Add CRC for header data head_data .push(crc8(&head_data[0..2])) @@ -281,18 +302,22 @@ impl ADIN1110 { .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice()) .map_err(|_e| AdinError::PACKET_TOO_BIG)?; - let mut frame_fcs = ETH_FSC::new(frame); - // ADIN1110 MAC and PHY donĀ“t accept ethernet packet smaller than 64 bytes. // So padded the data minus the FCS, FCS is automatilly added to by the MAC. - if frame.len() < ETH_MIN_WITHOUT_FSC_LEN { - let _ = tail_data.resize(ETH_MIN_WITHOUT_FSC_LEN - frame.len(), 0x00); - frame_fcs = frame_fcs.update(&tail_data); + if frame.len() < ETH_MIN_WITHOUT_FCS_LEN { + let _ = tail_data.resize(ETH_MIN_WITHOUT_FCS_LEN - frame.len(), 0x00); } - // Add ethernet FCS only over the ethernet packet. - // Only usefull when `CONFIG0`, `Transmit Frame Check Sequence Validation Enable` bit is enabled. - let _ = tail_data.extend_from_slice(frame_fcs.hton_bytes().as_slice()); + // Append FCS by the application + if self.append_fcs_on_tx { + let mut frame_fcs = ETH_FCS::new(frame); + + if !tail_data.is_empty() { + frame_fcs = frame_fcs.update(&tail_data); + } + + let _ = tail_data.extend_from_slice(frame_fcs.hton_bytes().as_slice()); + } // len = frame_size + optional padding + 2 bytes Frame header let send_len_orig = frame.len() + tail_data.len() + FRAME_HEADER_LEN; @@ -583,7 +608,8 @@ pub async fn new (Device<'_>, Runner<'_, SPI, INT, RST>) { use crate::regs::{IMask0, IMask1}; @@ -602,7 +628,7 @@ pub async fn new, CsPinMock, MockDelay>>, + spi: Generic, + } + + impl TestHarnass { + pub fn new(expectations: &[SpiTransaction], spi_crc: bool, append_fcs_on_tx: bool) -> Self { + let cs = CsPinMock::default(); + let delay = MockDelay {}; + let spi = SpiMock::new(expectations); + let spi_dev: ExclusiveDevice, CsPinMock, MockDelay> = + ExclusiveDevice::new(spi.clone(), cs, delay); + let spe: ADIN1110< + ExclusiveDevice, CsPinMock, MockDelay>, + > = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx); + + Self { spe, spi } + } + + pub fn done(&mut self) { + self.spi.done(); + } + } + #[futures_test::test] async fn mac_read_registers_without_crc() { // Configure expectations @@ -772,22 +820,20 @@ mod tests { SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3]), SpiTransaction::flush(), ]; - let mut spi = SpiMock::new(&expectations); - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); - let mut spe = ADIN1110::new(spi_dev, false); + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, false, true); // Read PHIID - let val = spe.read_reg(sr::PHYID).await.expect("Error"); + let val = th.spe.read_reg(sr::PHYID).await.expect("Error"); assert_eq!(val, 0x0283_BC91); // Read CAPAVILITY - let val = spe.read_reg(sr::CAPABILITY).await.expect("Error"); + let val = th.spe.read_reg(sr::CAPABILITY).await.expect("Error"); assert_eq!(val, 0x0000_06C3); - spi.done(); + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -803,26 +849,23 @@ mod tests { SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3, 57]), SpiTransaction::flush(), ]; - let mut spi = SpiMock::new(&expectations); - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); - - let mut spe = ADIN1110::new(spi_dev, true); + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, true, true); assert_eq!(crc8(0x0283_BC91_u32.to_be_bytes().as_slice()), 215); assert_eq!(crc8(0x0000_06C3_u32.to_be_bytes().as_slice()), 57); // Read PHIID - let val = spe.read_reg(sr::PHYID).await.expect("Error"); + let val = th.spe.read_reg(sr::PHYID).await.expect("Error"); assert_eq!(val, 0x0283_BC91); // Read CAPAVILITY - let val = spe.read_reg(sr::CAPABILITY).await.expect("Error"); + let val = th.spe.read_reg(sr::CAPABILITY).await.expect("Error"); assert_eq!(val, 0x0000_06C3); - spi.done(); + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -832,18 +875,15 @@ mod tests { SpiTransaction::write_vec(vec![0xA0, 0x09, 0x12, 0x34, 0x56, 0x78]), SpiTransaction::flush(), ]; - let mut spi = SpiMock::new(&expectations); - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); - - let mut spe = ADIN1110::new(spi_dev, false); + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, false, true); // Write reg: 0x1FFF - assert!(spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok()); + assert!(th.spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok()); - spi.done(); + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -854,17 +894,14 @@ mod tests { SpiTransaction::flush(), ]; - // Basic test init block - let mut spi = SpiMock::new(&expectations); - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); - let mut spe = ADIN1110::new(spi_dev, true); + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, true, true); // Write reg: 0x1FFF - assert!(spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok()); + assert!(th.spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok()); - spi.done(); + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -885,7 +922,7 @@ mod tests { let mut tail = std::vec::Vec::::with_capacity(100); // Padding - if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) { tail.resize(padding_len, 0x00); } // Packet FCS + optinal padding @@ -894,17 +931,49 @@ mod tests { expectations.push(SpiTransaction::write_vec(tail)); expectations.push(SpiTransaction::flush()); - let mut spi = SpiMock::new(&expectations); + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, true, true); - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + assert!(th.spe.write_fifo(&packet).await.is_ok()); - let mut spe = ADIN1110::new(spi_dev, true); + // Mark end of the SPI test. + th.done(); + } - assert!(spe.write_fifo(&packet).await.is_ok()); + #[futures_test::test] + async fn write_packet_to_fifo_minimal_with_crc_without_fcs() { + // Configure expectations + let mut expectations = vec![]; - spi.done(); + // Write TX_SIZE reg + expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 62, 186])); + expectations.push(SpiTransaction::flush()); + + // Write TX reg. + // SPI Header + optional CRC + Frame Header + expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0])); + // Packet data + let packet = [0xFF_u8; 60]; + expectations.push(SpiTransaction::write_vec(packet.to_vec())); + + let mut tail = std::vec::Vec::::with_capacity(100); + // Padding + if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) { + tail.resize(padding_len, 0x00); + } + // Packet FCS + optinal padding + tail.extend_from_slice(&[DONT_CARE_BYTE, DONT_CARE_BYTE]); + + expectations.push(SpiTransaction::write_vec(tail)); + expectations.push(SpiTransaction::flush()); + + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, true, false); + + assert!(th.spe.write_fifo(&packet).await.is_ok()); + + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -926,7 +995,7 @@ mod tests { let mut tail = std::vec::Vec::::with_capacity(100); // Padding - if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) { tail.resize(padding_len, 0x00); } // Packet FCS + optinal padding @@ -935,17 +1004,13 @@ mod tests { expectations.push(SpiTransaction::write_vec(tail)); expectations.push(SpiTransaction::flush()); - let mut spi = SpiMock::new(&expectations); + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, true, true); - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + assert!(th.spe.write_fifo(&packet).await.is_ok()); - let mut spe = ADIN1110::new(spi_dev, true); - - assert!(spe.write_fifo(&packet).await.is_ok()); - - spi.done(); + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -958,24 +1023,23 @@ mod tests { // Max packet size = MAX_BUFF - FRAME_HEADER_LEN let packet = [0xAA_u8; MAX_BUFF - FRAME_HEADER_LEN + 1]; - let mut spi = SpiMock::new(&expectations); - - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); - - let mut spe = ADIN1110::new(spi_dev, true); + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, true, true); // minimal assert!(matches!( - spe.write_fifo(&packet[0..(6 + 6 + 2 - 1)]).await, + th.spe.write_fifo(&packet[0..(6 + 6 + 2 - 1)]).await, Err(AdinError::PACKET_TOO_SMALL) )); // max + 1 - assert!(matches!(spe.write_fifo(&packet).await, Err(AdinError::PACKET_TOO_BIG))); + assert!(matches!( + th.spe.write_fifo(&packet).await, + Err(AdinError::PACKET_TOO_BIG) + )); - spi.done(); + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -999,7 +1063,7 @@ mod tests { let mut tail = std::vec::Vec::::with_capacity(100); // Padding - if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) { tail.resize(padding_len, 0x00); } // Packet FCS + optinal padding @@ -1008,17 +1072,13 @@ mod tests { expectations.push(SpiTransaction::write_vec(tail)); expectations.push(SpiTransaction::flush()); - let mut spi = SpiMock::new(&expectations); + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, true, true); - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + assert!(th.spe.write_fifo(&packet).await.is_ok()); - let mut spe = ADIN1110::new(spi_dev, true); - - assert!(spe.write_fifo(&packet).await.is_ok()); - - spi.done(); + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -1042,7 +1102,7 @@ mod tests { let mut tail = std::vec::Vec::::with_capacity(100); // Padding - if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { + if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) { tail.resize(padding_len, 0x00); } // Packet FCS + optinal padding @@ -1051,17 +1111,13 @@ mod tests { expectations.push(SpiTransaction::write_vec(tail)); expectations.push(SpiTransaction::flush()); - let mut spi = SpiMock::new(&expectations); + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, false, true); - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); + assert!(th.spe.write_fifo(&packet).await.is_ok()); - let mut spe = ADIN1110::new(spi_dev, false); - - assert!(spe.write_fifo(&packet).await.is_ok()); - - spi.done(); + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -1070,7 +1126,7 @@ mod tests { let mut expectations = vec![]; // Read RX_SIZE reg - let rx_size: u32 = u32::try_from(ETH_MIN_LEN + FRAME_HEADER_LEN + FSC_LEN).unwrap(); + let rx_size: u32 = u32::try_from(ETH_MIN_LEN + FRAME_HEADER_LEN + FCS_LEN).unwrap(); let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); rx_size_vec.push(crc8(&rx_size_vec)); @@ -1078,20 +1134,16 @@ mod tests { expectations.push(SpiTransaction::read_vec(rx_size_vec)); expectations.push(SpiTransaction::flush()); - let mut spi = SpiMock::new(&expectations); - - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); - - let mut spe = ADIN1110::new(spi_dev, true); - let mut frame = [0; MTU]; - let ret = spe.read_fifo(&mut frame[0..ETH_MIN_LEN - 1]).await; + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, true, true); + + let ret = th.spe.read_fifo(&mut frame[0..ETH_MIN_LEN - 1]).await; assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_BIG))); - spi.done(); + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -1102,11 +1154,11 @@ mod tests { // This value is importen for this test! assert_eq!(ETH_MIN_LEN, 64); - // Packet data, size = `ETH_MIN_LEN` - `FSC_LEN` - 1 - let packet = [0; 64 - FSC_LEN - 1]; + // Packet data, size = `ETH_MIN_LEN` - `FCS_LEN` - 1 + let packet = [0; 64 - FCS_LEN - 1]; // Read RX_SIZE reg - let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FSC_LEN).unwrap(); + let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap(); let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); rx_size_vec.push(crc8(&rx_size_vec)); @@ -1114,20 +1166,84 @@ mod tests { expectations.push(SpiTransaction::read_vec(rx_size_vec)); expectations.push(SpiTransaction::flush()); - let mut spi = SpiMock::new(&expectations); - - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); - - let mut spe = ADIN1110::new(spi_dev, true); - let mut frame = [0; MTU]; - let ret = spe.read_fifo(&mut frame).await; + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, true, true); + + let ret = th.spe.read_fifo(&mut frame).await; assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_SMALL))); - spi.done(); + // Mark end of the SPI test. + th.done(); + } + + #[futures_test::test] + async fn read_packet_from_fifo_packet_corrupted_fcs() { + let mut frame = [0; MTU]; + // Configure expectations + let mut expectations = vec![]; + + let packet = [0xDE; 60]; + let crc_en = true; + + // Read RX_SIZE reg + let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap(); + let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); + if crc_en { + rx_size_vec.push(crc8(&rx_size_vec)); + } + + // SPI Header with CRC + let mut rx_fsize = vec![128, 144, 79, TURN_AROUND_BYTE]; + if !crc_en { + // remove the CRC on idx 2 + rx_fsize.swap_remove(2); + } + expectations.push(SpiTransaction::write_vec(rx_fsize)); + expectations.push(SpiTransaction::read_vec(rx_size_vec)); + expectations.push(SpiTransaction::flush()); + + // Read RX reg, SPI Header with CRC + let mut rx_reg = vec![128, 145, 72, TURN_AROUND_BYTE]; + if !crc_en { + // remove the CRC on idx 2 + rx_reg.swap_remove(2); + } + expectations.push(SpiTransaction::write_vec(rx_reg)); + // Frame Header + expectations.push(SpiTransaction::read_vec(vec![0, 0])); + // Packet data + expectations.push(SpiTransaction::read_vec(packet.to_vec())); + + let packet_crc = ETH_FCS::new(&packet); + + let mut tail = std::vec::Vec::::with_capacity(100); + + tail.extend_from_slice(&packet_crc.hton_bytes()); + // increase last byte with 1. + if let Some(crc) = tail.last_mut() { + *crc = crc.wrapping_add(1); + } + + // Need extra bytes? + let pad = (packet.len() + FCS_LEN + FRAME_HEADER_LEN) & 0x03; + if pad != 0 { + // Packet FCS + optinal padding + tail.resize(tail.len() + pad, DONT_CARE_BYTE); + } + + expectations.push(SpiTransaction::read_vec(tail)); + expectations.push(SpiTransaction::flush()); + + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, crc_en, false); + + let ret = th.spe.read_fifo(&mut frame).await.expect_err("Error!"); + assert!(matches!(ret, AdinError::FCS)); + + // Mark end of the SPI test. + th.done(); } #[futures_test::test] @@ -1136,7 +1252,7 @@ mod tests { let mut frame = [0; MTU]; let mut expectations = std::vec::Vec::with_capacity(16); - // Packet data, size = `ETH_MIN_LEN` - `FSC_LEN` + // Packet data, size = `ETH_MIN_LEN` - `FCS_LEN` for packet_size in [60, 61, 62, 63, 64, MTU - 4, MTU - 3, MTU - 2, MTU - 1, MTU] { for crc_en in [false, true] { expectations.clear(); @@ -1144,7 +1260,7 @@ mod tests { let packet = &packet_buffer[0..packet_size]; // Read RX_SIZE reg - let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FSC_LEN).unwrap(); + let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap(); let mut rx_size_vec = rx_size.to_be_bytes().to_vec(); if crc_en { rx_size_vec.push(crc8(&rx_size_vec)); @@ -1172,14 +1288,14 @@ mod tests { // Packet data expectations.push(SpiTransaction::read_vec(packet.to_vec())); - let packet_crc = ETH_FSC::new(packet); + let packet_crc = ETH_FCS::new(packet); let mut tail = std::vec::Vec::::with_capacity(100); tail.extend_from_slice(&packet_crc.hton_bytes()); // Need extra bytes? - let pad = (packet_size + FSC_LEN + FRAME_HEADER_LEN) & 0x03; + let pad = (packet_size + FCS_LEN + FRAME_HEADER_LEN) & 0x03; if pad != 0 { // Packet FCS + optinal padding tail.resize(tail.len() + pad, DONT_CARE_BYTE); @@ -1188,19 +1304,34 @@ mod tests { expectations.push(SpiTransaction::read_vec(tail)); expectations.push(SpiTransaction::flush()); - let mut spi = SpiMock::new(&expectations); + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, crc_en, false); - let cs = CsPinMock::default(); - let delay = MockDelay {}; - let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); - - let mut spe = ADIN1110::new(spi_dev, crc_en); - - let ret = spe.read_fifo(&mut frame).await.expect("Error!"); + let ret = th.spe.read_fifo(&mut frame).await.expect("Error!"); assert_eq!(ret, packet_size); - spi.done(); + // Mark end of the SPI test. + th.done(); } } } + + #[futures_test::test] + async fn spi_crc_error() { + // Configure expectations + let expectations = vec![ + SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE]), + SpiTransaction::read_vec(vec![0x00, 0x00, 0x00, 0x00, 0xDD]), + SpiTransaction::flush(), + ]; + + // Create TestHarnass + let mut th = TestHarnass::new(&expectations, true, false); + + let ret = th.spe.read_reg(sr::RX_FSIZE).await; + assert!(matches!(dbg!(ret), Err(AdinError::SPI_CRC))); + + // Mark end of the SPI test. + th.done(); + } } diff --git a/embassy-net-adin1110/src/regs.rs b/embassy-net-adin1110/src/regs.rs index 4557929f..46466c7d 100644 --- a/embassy-net-adin1110/src/regs.rs +++ b/embassy-net-adin1110/src/regs.rs @@ -174,7 +174,7 @@ bitfield! { pub sdf_detect_src, set_sdf_detect_src : 7; /// Statistics Clear on Reading pub stats_clr_on_rd, set_stats_clr_on_rd : 6; - /// Enable CRC Append + /// Enable SPI CRC pub crc_append, set_crc_append : 5; /// Admit Frames with IFG Errors on Port 1 (P1) pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4; From 2c36199dea8230f261bc1ee210f96f47272b8b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Sun, 27 Aug 2023 13:47:02 +0200 Subject: [PATCH 048/233] stm32l4: Update adin1110 example add FCS option --- .../src/bin/spe_adin1110_http_server.rs | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 148c5877..baaa9dfa 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -11,7 +11,9 @@ // Settings switch S201 "HW CFG": // - Without SPI CRC: OFF-ON-OFF-OFF-OFF // - With SPI CRC: ON -ON-OFF-OFF-OFF -// Settings switch S303 "uC CFG": CFG0: On = static ip, Off = Dhcp +// Settings switch S303 "uC CFG": +// - CFG0: On = static ip, Off = Dhcp +// - CFG1: Ethernet `FCS` on TX path: On, Off // The webserver shows the actual temperature of the onboard i2c temp sensor. use core::marker::PhantomData; @@ -107,7 +109,7 @@ async fn main(spawner: Spawner) { // Read the uc_cfg switches let uc_cfg0 = Input::new(dp.PB2, Pull::None); - let _uc_cfg1 = Input::new(dp.PF11, Pull::None); + let uc_cfg1 = Input::new(dp.PF11, Pull::None); let _uc_cfg2 = Input::new(dp.PG6, Pull::None); let _uc_cfg3 = Input::new(dp.PG11, Pull::None); @@ -154,11 +156,13 @@ async fn main(spawner: Spawner) { let cfg0_without_crc = spe_cfg0.is_high(); let cfg1_spi_mode = spe_cfg1.is_high(); + let uc_cfg1_fcs_en = uc_cfg1.is_low(); defmt::println!( - "ADIN1110: CFG SPI-MODE 1-{}, CRC-bit 0-{}", + "ADIN1110: CFG SPI-MODE 1-{}, CRC-bit 0-{} FCS-{}", cfg1_spi_mode, - cfg0_without_crc + cfg0_without_crc, + uc_cfg1_fcs_en ); // Check the SPI mode selected with the "HW CFG" dip-switch @@ -172,8 +176,16 @@ async fn main(spawner: Spawner) { let state = make_static!(embassy_net_adin1110::State::<8, 8>::new()); - let (device, runner) = - embassy_net_adin1110::new(MAC, state, spe_spi, spe_int, spe_reset_n, !cfg0_without_crc).await; + let (device, runner) = embassy_net_adin1110::new( + MAC, + state, + spe_spi, + spe_int, + spe_reset_n, + !cfg0_without_crc, + uc_cfg1_fcs_en, + ) + .await; // Start task blink_led unwrap!(spawner.spawn(heartbeat_led(led_uc3_yellow))); From 5c27265a21681938819230fb3d5df1b732bd2470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Sun, 27 Aug 2023 23:36:16 +0200 Subject: [PATCH 049/233] Add fmt.rs to improve log/debug and embbed and PC Also add `defmt` to the features list. --- embassy-net-adin1110/Cargo.toml | 5 +- embassy-net-adin1110/src/fmt.rs | 254 +++++++++++++++++++++++++++++++ embassy-net-adin1110/src/lib.rs | 101 +++++------- embassy-net-adin1110/src/regs.rs | 14 +- 4 files changed, 308 insertions(+), 66 deletions(-) create mode 100644 embassy-net-adin1110/src/fmt.rs diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index e74fb7cd..c13f1018 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -21,7 +21,6 @@ embassy-time = { version = "0.1.0" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" - [dev-dependencies] # reenable when https://github.com/dbrgn/embedded-hal-mock/pull/86 is merged. #embedded-hal-mock = { git = "https://github.com/dbrgn/embedded-hal-mock", branch = "1-alpha", features = ["embedded-hal-async", "eh1"] }] } @@ -33,9 +32,11 @@ futures-test = "0.3.17" [features] default = [ ] -defmt = [ "dep:defmt" ] +defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ] +log = ["dep:log"] [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-adin1110-v$VERSION/embassy-net-adin1110/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-adin1110/src/" target = "thumbv7em-none-eabi" +features = ["defmt"] diff --git a/embassy-net-adin1110/src/fmt.rs b/embassy-net-adin1110/src/fmt.rs new file mode 100644 index 00000000..12737c69 --- /dev/null +++ b/embassy-net-adin1110/src/fmt.rs @@ -0,0 +1,254 @@ +#![macro_use] +#![allow(unused_macros)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +macro_rules! unreachable { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::unreachable!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::unreachable!($($x)*); + } + }; +} + +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ignored = ($( & $x ),*); + } + }; +} + +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ignored = ($( & $x ),*); + } + }; +} + +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ignored = ($( & $x ),*); + } + }; +} + +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ignored = ($( & $x ),*); + } + }; +} + +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ignored = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +pub struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 8d73e024..4af054ae 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -6,6 +6,9 @@ #![allow(clippy::missing_panics_doc)] #![doc = include_str!("../README.md")] +// must go first! +mod fmt; + mod crc32; mod crc8; mod mdio; @@ -20,12 +23,13 @@ use embassy_net_driver_channel as ch; use embassy_time::{Duration, Timer}; use embedded_hal_1::digital::OutputPin; use embedded_hal_async::digital::Wait; -use embedded_hal_async::spi::{Operation, SpiDevice}; +use embedded_hal_async::spi::{Error, Operation, SpiDevice}; use heapless::Vec; pub use mdio::MdioBus; pub use phy::{Phy10BaseT1x, RegsC22, RegsC45}; pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1}; +use crate::fmt::Bytes; use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader}; pub const PHYID: u32 = 0x0283_BC91; @@ -153,8 +157,7 @@ impl ADIN1110 { let value = u32::from_be_bytes(rx_buf[0..4].try_into().unwrap()); - #[cfg(feature = "defmt")] - defmt::trace!("REG Read {} = {:08x} SPI {:02x}", reg, value, &tx_buf); + trace!("REG Read {} = {:08x} SPI {}", reg, value, Bytes(&tx_buf)); Ok(value) } @@ -181,8 +184,7 @@ impl ADIN1110 { let _ = tx_buf.push(crc8(val.as_slice())); } - #[cfg(feature = "defmt")] - defmt::trace!("REG Write {} = {:08x} SPI {:02x}", reg, value, &tx_buf); + trace!("REG Write {} = {:08x} SPI {}", reg, value, Bytes(&tx_buf)); self.spi.write(&tx_buf).await.map_err(AdinError::Spi) } @@ -219,8 +221,7 @@ impl ADIN1110 { let packet_size = fifo_frame_size - FRAME_HEADER_LEN - FCS_LEN; if packet_size > frame.len() { - #[cfg(feature = "defmt")] - defmt::trace!("MAX: {} WANT: {}", frame.len(), packet_size); + trace!("MAX: {} WANT: {}", frame.len(), packet_size); return Err(AdinError::PACKET_TOO_BIG); } @@ -333,14 +334,13 @@ impl ADIN1110 { self.write_reg(sr::TX_FSIZE, send_len).await?; - #[cfg(feature = "defmt")] - defmt::trace!( - "TX: hdr {} [{}] {:02x}-{:02x}-{:02x} SIZE: {}", + trace!( + "TX: hdr {} [{}] {}-{}-{} SIZE: {}", head_data.len(), frame.len(), - head_data.as_slice(), - frame, - tail_data.as_slice(), + Bytes(head_data.as_slice()), + Bytes(frame), + Bytes(tail_data.as_slice()), send_len, ); @@ -445,16 +445,14 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); loop { - #[cfg(feature = "defmt")] - defmt::debug!("Waiting for interrupts"); + debug!("Waiting for interrupts"); match select(self.int.wait_for_low(), tx_chan.tx_buf()).await { Either::First(_) => { let mut status1_clr = Status1(0); let mut status1 = Status1(self.mac.read_reg(sr::STATUS1).await.unwrap()); while status1.p1_rx_rdy() { - #[cfg(feature = "defmt")] - defmt::debug!("alloc RX packet buffer"); + debug!("alloc RX packet buffer"); match select(rx_chan.rx_buf(), tx_chan.tx_buf()).await { // Handle frames that needs to transmit from the wire. // Note: rx_chan.rx_buf() channel donĀ“t accept new request @@ -466,22 +464,18 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { } Err(e) => match e { AdinError::PACKET_TOO_BIG => { - #[cfg(feature = "defmt")] - defmt::error!("RX Packet too big, DROP"); + error!("RX Packet too big, DROP"); self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap(); } AdinError::PACKET_TOO_SMALL => { - #[cfg(feature = "defmt")] - defmt::error!("RX Packet too small, DROP"); + error!("RX Packet too small, DROP"); self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap(); } - AdinError::Spi(_) => { - #[cfg(feature = "defmt")] - defmt::error!("RX Spi error") + AdinError::Spi(e) => { + error!("RX Spi error {}", e.kind()); } _ => { - #[cfg(feature = "defmt")] - defmt::error!("RX Error") + error!("RX Error"); } }, }, @@ -496,21 +490,18 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { let status0 = Status0(self.mac.read_reg(sr::STATUS0).await.unwrap()); if status1.0 & !0x1b != 0 { - #[cfg(feature = "defmt")] - defmt::error!("SPE CHIP STATUS 0:{:08x} 1:{:08x}", status0.0, status1.0); + error!("SPE CHIP STATUS 0:{:08x} 1:{:08x}", status0.0, status1.0); } if status1.tx_rdy() { status1_clr.set_tx_rdy(true); - #[cfg(feature = "defmt")] - defmt::info!("TX_DONE"); + trace!("TX_DONE"); } if status1.link_change() { let link = status1.p1_link_status(); self.is_link_up = link; - #[cfg(feature = "defmt")] if link { let link_status = self .mac @@ -530,9 +521,9 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { .await .unwrap(); - defmt::info!("LINK Changed: Link Up, Volt: {} V p-p, MSE: {:0004}", volt, mse); + info!("LINK Changed: Link Up, Volt: {} V p-p, MSE: {:0004}", volt, mse); } else { - defmt::info!("LINK Changed: Link Down"); + info!("LINK Changed: Link Down"); } state_chan.set_link_state(if link { LinkState::Up } else { LinkState::Down }); @@ -540,50 +531,42 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { } if status1.tx_ecc_err() { - #[cfg(feature = "defmt")] - defmt::error!("SPI TX_ECC_ERR error, CLEAR TX FIFO"); + error!("SPI TX_ECC_ERR error, CLEAR TX FIFO"); self.mac.write_reg(sr::FIFO_CLR, 2).await.unwrap(); status1_clr.set_tx_ecc_err(true); } if status1.rx_ecc_err() { - #[cfg(feature = "defmt")] - defmt::error!("SPI RX_ECC_ERR error"); + error!("SPI RX_ECC_ERR error"); status1_clr.set_rx_ecc_err(true); } if status1.spi_err() { - #[cfg(feature = "defmt")] - defmt::error!("SPI SPI_ERR CRC error"); + error!("SPI SPI_ERR CRC error"); status1_clr.set_spi_err(true); } if status0.phyint() { - #[cfg_attr(not(feature = "defmt"), allow(unused_variables))] let crsm_irq_st = self .mac .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::CRSM_IRQ_STATUS.into()) .await .unwrap(); - #[cfg_attr(not(feature = "defmt"), allow(unused_variables))] let phy_irq_st = self .mac .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1F::PHY_SYBSYS_IRQ_STATUS.into()) .await .unwrap(); - #[cfg(feature = "defmt")] - defmt::warn!( + warn!( "SPE CHIP PHY CRSM_IRQ_STATUS {:04x} PHY_SUBSYS_IRQ_STATUS {:04x}", - crsm_irq_st, - phy_irq_st + crsm_irq_st, phy_irq_st ); } if status0.txfcse() { - #[cfg(feature = "defmt")] - defmt::error!("SPE CHIP PHY TX Frame CRC error"); + error!("Ethernet Frame FCS and calc FCS don't match!"); } // Clear status0 @@ -613,8 +596,7 @@ pub async fn new (Device<'_>, Runner<'_, SPI, INT, RST>) { use crate::regs::{IMask0, IMask1}; - #[cfg(feature = "defmt")] - defmt::info!("INIT ADIN1110"); + info!("INIT ADIN1110"); // Reset sequence reset.set_low().unwrap(); @@ -634,23 +616,20 @@ pub async fn new) -> core::fmt::Result { + write!(f, "{self:?}") + } +} + impl From for u16 { fn from(val: SpiRegisters) -> Self { val as u16 @@ -68,7 +76,7 @@ impl From for SpiRegisters { 0x73 => Self::ADDR_MSK_UPR1, 0x90 => Self::RX_FSIZE, 0x91 => Self::RX, - e => panic!("Unknown value {e}"), + e => panic!("Unknown value {}", e), } } } @@ -313,7 +321,7 @@ impl From for LedFunc { 26 => LedFunc::Clk25Ref, 27 => LedFunc::TxTCLK, 28 => LedFunc::Clk120MHz, - e => panic!("Invalid value {e}"), + e => panic!("Invalid value {}", e), } } } @@ -369,7 +377,7 @@ impl From for LedPol { 0 => LedPol::AutoSense, 1 => LedPol::ActiveHigh, 2 => LedPol::ActiveLow, - e => panic!("Invalid value {e}"), + e => panic!("Invalid value {}", e), } } } From e08dbcd027feb9bad232caa2adc4433b6f4885d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Mon, 28 Aug 2023 00:02:09 +0200 Subject: [PATCH 050/233] embassy-net-adin1110: bump version v0.2.0 --- embassy-net-adin1110/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index c13f1018..26111c09 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net-adin1110" -version = "0.1.0" +version = "0.2.0" description = "embassy-net driver for the ADIN1110 ethernet chip" keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] From 91bb3aae3fdb81f8aafceb6540c5af128b05e718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Mon, 28 Aug 2023 00:03:50 +0200 Subject: [PATCH 051/233] stm32l4: bump embassy-net-adin1110 to v0.2.0 --- examples/stm32l4/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index e5be94ed..e864759b 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-stm32l4-examples" -version = "0.1.0" +version = "0.1.1" license = "MIT OR Apache-2.0" [dependencies] @@ -12,7 +12,7 @@ embassy-executor = { version = "0.3.0", path = "../../embassy-executor", feature embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net-adin1110 = { version = "0.1.0", path = "../../embassy-net-adin1110", default-features = false } +embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embedded-io-async = { version = "0.5.0", features = ["defmt-03"] } From e981cd496827c01cba11fd6ba40b2b7ed482e49b Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 21:15:57 -0500 Subject: [PATCH 052/233] stm32: fix rtc wakeup timing and add dbg --- embassy-stm32/Cargo.toml | 3 ++- embassy-stm32/src/low_power.rs | 7 ++++++ embassy-stm32/src/rcc/f4.rs | 2 +- embassy-stm32/src/rtc/mod.rs | 14 ++++++++++- embassy-stm32/src/rtc/v2.rs | 43 ++++++++++++++++++++++++-------- embassy-stm32/src/time_driver.rs | 2 ++ tests/stm32/src/bin/stop.rs | 6 +++-- 7 files changed, 62 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d0ada97a..ca421910 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" -features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time", "low-power"] +features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time", "low-power", "rtc-debug"] flavors = [ { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, @@ -90,6 +90,7 @@ defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-emb exti = [] low-power = [ "dep:embassy-executor", "embassy-executor/arch-cortex-m" ] +rtc-debug = [] embassy-executor = [] ## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 65b93f8a..f9b5fde9 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -89,6 +89,9 @@ impl Executor { self.time_driver.resume_time(); trace!("low power: resume time"); + + #[cfg(feature = "rtc-debug")] + cortex_m::asm::bkpt(); } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { @@ -118,6 +121,7 @@ impl Executor { } trace!("low power: enter stop..."); + #[cfg(not(feature = "rtc-debug"))] self.scb.set_sleepdeep(); } @@ -140,6 +144,9 @@ impl Executor { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + #[cfg(feature = "rtc-debug")] + trace!("low power: rtc debug enabled"); + init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); loop { diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 10d3322a..d8b689e4 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -17,7 +17,7 @@ use crate::{peripherals, Peripheral}; pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); +pub const LSI_FREQ: Hertz = Hertz(32_768); /// Clocks configuration #[non_exhaustive] diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 8bda0926..496ad5c1 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -47,6 +47,18 @@ struct RtcInstant { subsecond: u16, } +#[cfg(all(feature = "low-power", feature = "defmt"))] +impl defmt::Format for RtcInstant { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!( + fmt, + "{}:{}", + self.second, + RTC::regs().prer().read().prediv_s() - self.subsecond, + ) + } +} + #[cfg(feature = "low-power")] impl core::ops::Sub for RtcInstant { type Output = embassy_time::Duration; @@ -174,7 +186,7 @@ impl Rtc { let second = bcd2_to_byte((tr.st(), tr.su())); // Unlock the registers - r.dr(); + r.dr().read(); RtcInstant { second, subsecond } } diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 62b39868..7eb8a96c 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -1,7 +1,5 @@ use stm32_metapac::rtc::vals::{Init, Osel, Pol}; -#[cfg(feature = "low-power")] -use super::RtcInstant; use super::{sealed, RtcConfig}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; @@ -77,6 +75,21 @@ impl super::Rtc { /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { + #[cfg(feature = "rtc-debug")] + if critical_section::with(|cs| { + if let Some(instant) = self.stop_time.borrow(cs).take() { + self.stop_time.borrow(cs).replace(Some(instant)); + + Some(()) + } else { + None + } + }) + .is_some() + { + return; + } + use embassy_time::{Duration, TICK_HZ}; use crate::rcc::get_freqs; @@ -86,17 +99,14 @@ impl super::Rtc { let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); - // adjust the rtc ticks to the prescaler + // adjust the rtc ticks to the prescaler and subtract one rtc tick let rtc_ticks = rtc_ticks / (>::into(prescaler) as u64); let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { u16::MAX - 1 } else { rtc_ticks as u16 - }; - - let duration = Duration::from_ticks( - rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, - ); + } + .saturating_sub(1); self.write(false, |regs| { regs.cr().modify(|w| w.set_wute(false)); @@ -104,11 +114,21 @@ impl super::Rtc { while !regs.isr().read().wutwf() {} regs.cr().modify(|w| w.set_wucksel(prescaler.into())); + regs.wutr().write(|w| w.set_wut(rtc_ticks)); regs.cr().modify(|w| w.set_wute(true)); regs.cr().modify(|w| w.set_wutie(true)); }); - trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); + trace!( + "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", + Duration::from_ticks( + rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, + ) + .as_millis(), + >::into(prescaler), + rtc_ticks, + self.instant(), + ); critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) } @@ -119,7 +139,10 @@ impl super::Rtc { pub(crate) fn stop_wakeup_alarm(&self) -> Option { use crate::interrupt::typelevel::Interrupt; - trace!("rtc: stop wakeup alarm..."); + trace!("rtc: stop wakeup alarm at {}", self.instant()); + + #[cfg(feature = "rtc-debug")] + return None; self.write(false, |regs| { regs.cr().modify(|w| w.set_wutie(false)); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 99d423d0..d4442c23 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -363,6 +363,7 @@ impl RtcDriver { .start_wakeup_alarm(time_until_next_alarm); }); + #[cfg(not(feature = "rtc-debug"))] T::regs_gp16().cr1().modify(|w| w.set_cen(false)); Ok(()) @@ -374,6 +375,7 @@ impl RtcDriver { pub(crate) fn resume_time(&self) { self.stop_wakeup_alarm(); + #[cfg(not(feature = "rtc-debug"))] T::regs_gp16().cr1().modify(|w| w.set_cen(true)); } } diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index 0b3f4a30..a490d7b8 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -46,8 +46,10 @@ async fn async_main(_spawner: Spawner) { stop_with_rtc(rtc); - info!("Waiting 5 seconds"); - Timer::after(Duration::from_secs(5)).await; + info!("Waiting..."); + Timer::after(Duration::from_secs(2)).await; + info!("Waiting..."); + Timer::after(Duration::from_secs(3)).await; info!("Test OK"); cortex_m::asm::bkpt(); From 538001a4bc4cdf647924d621347c851f13b6a95d Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 21:24:16 -0500 Subject: [PATCH 053/233] stm32/rtc: fix psc div --- embassy-stm32/src/rtc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 496ad5c1..ca375855 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -78,7 +78,7 @@ impl core::ops::Sub for RtcInstant { let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32); let rtc_ticks = self_ticks - other_ticks; - Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / psc) as u64) + Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64) } } From 2c80784fe6e1a165cabae83baf7c842218a35046 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 21:26:29 -0500 Subject: [PATCH 054/233] stm32/rtc: feature-gate instant --- embassy-stm32/src/rtc/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index ca375855..796fd7d9 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -178,6 +178,7 @@ impl Rtc { Ok(()) } + #[cfg(feature = "low-power")] /// Return the current instant. fn instant(&self) -> RtcInstant { let r = RTC::regs(); From 71c4e7e4d22a2f3e8c77ffb4b0a4b01198239bcf Mon Sep 17 00:00:00 2001 From: Dave Andersen Date: Sun, 27 Aug 2023 22:39:44 -0400 Subject: [PATCH 055/233] Fix timing on RP2040 pio_ws2812.rs example The example spins too fast so it doesn't appear to change; it's delaying for microseconds instead of milliseconds. This commit slows it down and adds a comment noting the pin mapping for the Adafruit feather rp2040+RFM95 LoRA module, which has its Neopixel on pin 4 instead of 16. --- examples/rp/src/bin/pio_ws2812.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs index bc87016e..5c0c6024 100644 --- a/examples/rp/src/bin/pio_ws2812.rs +++ b/examples/rp/src/bin/pio_ws2812.rs @@ -138,8 +138,9 @@ async fn main(_spawner: Spawner) { const NUM_LEDS: usize = 1; let mut data = [RGB8::default(); NUM_LEDS]; - // For the thing plus, use pin 8 - // For the feather, use pin 16 + // Common neopixel pins: + // Thing plus: 8 + // Adafruit Feather: 16; Adafruit Feather+RFM95: 4 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); // Loop forever making RGB values and pushing them out to the WS2812. @@ -152,7 +153,7 @@ async fn main(_spawner: Spawner) { } ws2812.write(&data).await; - Timer::after(Duration::from_micros(5)).await; + Timer::after(Duration::from_millis(10)).await; } } } From fd739250ea8b830f06f8a78a272874faa888d42c Mon Sep 17 00:00:00 2001 From: Olle Sandberg Date: Mon, 28 Aug 2023 11:27:56 +0200 Subject: [PATCH 056/233] stm32: fix wait for RNG data If no data was available to read then the loop would wait for an interrupt and skip to the next chunk without writing the current one. This could cause the given slice to only be partially filled with random data. Fixed by moving the wait to before actually writing data to the chunk. --- embassy-stm32/src/rng.rs | 46 ++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 30816e43..0979dce8 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -119,7 +119,31 @@ impl<'d, T: Instance> Rng<'d, T> { pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(4) { - let bits = T::regs().sr().read(); + let mut bits = T::regs().sr().read(); + if !bits.seis() && !bits.ceis() && !bits.drdy() { + // wait for interrupt + poll_fn(|cx| { + // quick check to avoid registration if already done. + let bits = T::regs().sr().read(); + if bits.drdy() || bits.seis() || bits.ceis() { + return Poll::Ready(()); + } + RNG_WAKER.register(cx.waker()); + T::regs().cr().modify(|reg| reg.set_ie(true)); + // Need to check condition **after** `register` to avoid a race + // condition that would result in lost notifications. + let bits = T::regs().sr().read(); + if bits.drdy() || bits.seis() || bits.ceis() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + // Re-read the status register after wait. + bits = T::regs().sr().read() + } if bits.seis() { // in case of noise-source or seed error we try to recover here // but we must not use the data in DR and we return an error @@ -143,26 +167,6 @@ impl<'d, T: Instance> Rng<'d, T> { for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) { *dest = *src } - } else { - // wait for interrupt - poll_fn(|cx| { - // quick check to avoid registration if already done. - let bits = T::regs().sr().read(); - if bits.drdy() || bits.seis() || bits.ceis() { - return Poll::Ready(()); - } - RNG_WAKER.register(cx.waker()); - T::regs().cr().modify(|reg| reg.set_ie(true)); - // Need to check condition **after** `register` to avoid a race - // condition that would result in lost notifications. - let bits = T::regs().sr().read(); - if bits.drdy() || bits.seis() || bits.ceis() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; } } From 1f63bf4153b6ba4a915c0df22041f09adaaca400 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Mon, 28 Aug 2023 08:00:18 -0700 Subject: [PATCH 057/233] Release embassy-time v0.1.3 --- cyw43/Cargo.toml | 4 ++-- embassy-embedded-hal/Cargo.toml | 2 +- embassy-executor/Cargo.toml | 2 +- embassy-lora/Cargo.toml | 4 ++-- embassy-net-enc28j60/Cargo.toml | 4 ++-- embassy-net-esp-hosted/Cargo.toml | 4 ++-- embassy-net-wiznet/Cargo.toml | 4 ++-- embassy-net/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-time/CHANGELOG.md | 7 ++++++- embassy-time/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 4 ++-- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 4 ++-- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 4 ++-- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 4 ++-- examples/wasm/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 4 ++-- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 52 files changed, 67 insertions(+), 62 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 855d54b1..59b297e0 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -11,7 +11,7 @@ log = ["dep:log"] firmware-logs = [] [dependencies] -embassy-time = { version = "0.1.2", path = "../embassy-time"} +embassy-time = { version = "0.1.3", path = "../embassy-time"} embassy-sync = { version = "0.2.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} @@ -31,4 +31,4 @@ num_enum = { version = "0.5.7", default-features = false } src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/" target = "thumbv6m-none-eabi" -features = ["defmt", "firmware-logs"] \ No newline at end of file +features = ["defmt", "firmware-logs"] diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index fd921d27..b311b591 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -21,7 +21,7 @@ default = ["time"] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true } embassy-sync = { version = "0.2.0", path = "../embassy-sync" } -embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", ] } diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 5bf68fc6..35944625 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -59,7 +59,7 @@ rtos-trace = { version = "0.1.2", optional = true } futures-util = { version = "0.3.17", default-features = false } embassy-macros = { version = "0.2.1", path = "../embassy-macros" } -embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true} +embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true} atomic-polyfill = "1.0.1" critical-section = "1.1" static_cell = "1.1" diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index feea0658..fa445a39 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml @@ -20,7 +20,7 @@ defmt = ["dep:defmt", "lorawan-device/defmt"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-sync = { version = "0.2.0", path = "../embassy-sync" } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } embedded-hal-async = { version = "=1.0.0-rc.1" } @@ -31,4 +31,4 @@ lora-phy = { version = "1" } lorawan-device = { version = "0.10.0", default-features = false, features = ["async"], optional = true } [patch.crates-io] -lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file +lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index e02c984e..161d055c 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" embedded-hal = { version = "1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" } embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } -embassy-time = { version = "0.1.2", path = "../embassy-time" } +embassy-time = { version = "0.1.3", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } @@ -20,4 +20,4 @@ log = { version = "0.4.14", optional = true } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-enc28j60-v$VERSION/embassy-net-enc28j60/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-enc28j60/src/" -target = "thumbv7em-none-eabi" \ No newline at end of file +target = "thumbv7em-none-eabi" diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index d334cf3f..67c86936 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embassy-time = { version = "0.1.2", path = "../embassy-time" } +embassy-time = { version = "0.1.3", path = "../embassy-time" } embassy-sync = { version = "0.2.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} @@ -23,4 +23,4 @@ heapless = "0.7.16" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-esp-hosted-v$VERSION/embassy-net-esp-hosted/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-esp-hosted/src/" target = "thumbv7em-none-eabi" -features = ["defmt"] \ No newline at end of file +features = ["defmt"] diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index adf0b45f..afa0d5cd 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" embedded-hal = { version = "1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" } embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } -embassy-time = { version = "0.1.2", path = "../embassy-time" } +embassy-time = { version = "0.1.3", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } @@ -19,4 +19,4 @@ defmt = { version = "0.3", optional = true } src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-wiznet-v$VERSION/embassy-net-wiznet/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-wiznet/src/" target = "thumbv7em-none-eabi" -features = ["defmt"] \ No newline at end of file +features = ["defmt"] diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 0361f1db..c763d41c 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -51,7 +51,7 @@ smoltcp = { version = "0.10.0", default-features = false, features = [ ] } embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } -embassy-time = { version = "0.1.2", path = "../embassy-time" } +embassy-time = { version = "0.1.3", path = "../embassy-time" } embassy-sync = { version = "0.2.0", path = "../embassy-sync" } embedded-io-async = { version = "0.5.0", optional = true } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 67ec4eb9..e7afef26 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -91,7 +91,7 @@ _dppi = [] _gpio-p1 = [] [dependencies] -embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-sync = { version = "0.2.0", path = "../embassy-sync" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 60143c2b..eebb6e3b 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -60,7 +60,7 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"] [dependencies] embassy-sync = { version = "0.2.0", path = "../embassy-sync" } -embassy-time = { version = "0.1.2", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } +embassy-time = { version = "0.1.3", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 96c47484..7a4d3ec6 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -13,7 +13,7 @@ features = ["stm32wb55rg"] [dependencies] embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } embassy-sync = { version = "0.2.0", path = "../embassy-sync" } -embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" } embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d0ada97a..d169107d 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -32,7 +32,7 @@ flavors = [ [dependencies] embassy-sync = { version = "0.2.0", path = "../embassy-sync" } -embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index 26640d93..8bf02dbc 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.1.3 - 2023-08-28 + +- Update `embedded-hal-async` to `1.0.0-rc.1` +- Update `embedded-hal v1` to `1.0.0-rc.1` + ## 0.1.2 - 2023-07-05 - Update `embedded-hal-async` to `0.2.0-alpha.2`. @@ -26,4 +31,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.1.0 - 2022-08-26 -- First release \ No newline at end of file +- First release diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 00d31d30..03aa6ca2 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-time" -version = "0.1.2" +version = "0.1.3" edition = "2021" description = "Instant and Duration for embedded no-std systems, with async timer support" repository = "https://github.com/embassy-rs/embassy" diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 46ce7ba9..49f6eb13 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] } +embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly"] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] } embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] } embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = ["nightly"] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index be85f443..e9d4fb32 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] } +embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly"] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] } embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index ea878933..6a6f967b 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index b39bc292..55a631e9 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index f015b2ca..ff960f22 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index f221e1de..a0f88585 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 2896afa3..1a251df3 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 50d8967a..8d1c8af1 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 27541439..441b355a 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index b06722f5..ed6aca81 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -18,7 +18,7 @@ log = [ [dependencies] embassy-sync = { version = "0.2.0", path = "../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time" } +embassy-time = { version = "0.1.3", path = "../../embassy-time" } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 715f1ecf..02a7f98b 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -9,7 +9,7 @@ rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nightly", "unstable-traits", "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 1b2f1eb1..8b7121ab 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -31,7 +31,7 @@ nightly = [ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true } @@ -67,4 +67,4 @@ microfft = "0.5.0" debug = 2 [patch.crates-io] -lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file +lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 4968a79a..e423ad95 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -14,7 +14,7 @@ embassy-executor = { version = "0.3.0", path = "../../embassy-executor", feature "defmt", "integrated-timers", ] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = [ +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", ] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 3efc804a..3b086133 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } @@ -57,4 +57,4 @@ rand = { version = "0.8.5", default-features = false } debug = 2 [patch.crates-io] -lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file +lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 7b0d0bda..ca061d68 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["log", "std", "nightly"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["log", "std", "nightly"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 9d188513..a691be42 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index ca9ab1cf..894681d0 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -16,7 +16,7 @@ defmt-rtt = "0.4" panic-probe = "0.3" embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = { version = "1.1", features = ["nightly"]} [profile.release] diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 16796841..bec7bf65 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 54eadd1a..7cc5747d 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 5d8f5f74..ffacece5 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index ed456c5c..ca517df7 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index b658a964..f7a7fb8c 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.5.0" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 4e88151a..474c2af8 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 7bb05dbc..0c1cdd67 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index f7a1de63..d4b7d18c 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embedded-io-async = { version = "0.5.0" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 1ee11b07..eda04e44 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embedded-io-async = { version = "0.5.0" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index d4e0da0b..d33e0378 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -14,7 +14,7 @@ nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstab embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } lora-phy = { version = "1", optional = true } lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } @@ -39,4 +39,4 @@ static_cell = "1.1" debug = 2 [patch.crates-io] -lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file +lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 192fd3e3..9bf633ce 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } defmt = "0.3" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index e5be94ed..5fe1499e 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "unstable-traits", "chrono"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.1.0", path = "../../embassy-net-adin1110", default-features = false } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index b46c2570..d387ee62 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index f928e7a6..403e5714 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 16db92c1..81d9ec69 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true } defmt = "0.3" diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 1c771ddc..3ea76cbb 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } lora-phy = { version = "1" } @@ -32,4 +32,4 @@ chrono = { version = "^0.4", default-features = false } debug = 2 [patch.crates-io] -lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file +lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 5b206d71..2999dc52 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["log", "wasm", "nightly"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["log", "wasm", "nightly"] } wasm-logger = "0.2.0" wasm-bindgen = "0.2" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 4e31bed5..867bf272 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -10,7 +10,7 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt", "nightly"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.5.0" } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } @@ -25,4 +25,4 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } \ No newline at end of file +panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index be610b1c..66ab34ec 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" critical-section = { version = "1.1.1", features = ["restore-state-bool"] } embassy-sync = { version = "0.2.0", path = "../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-riscv32", "nightly", "executor-thread"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time" } +embassy-time = { version = "0.1.3", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } riscv-rt = "0.11" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index c494b66e..d71db8bb 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -9,7 +9,7 @@ teleprobe-meta = "1.1" embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 1f8c7373..c96b5a5a 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -31,7 +31,7 @@ teleprobe-meta = "1" embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } From d02886786e4c496dc5a2c8851a7a01764905182b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Mon, 28 Aug 2023 19:00:00 +0200 Subject: [PATCH 058/233] Show the error type --- embassy-net-adin1110/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 4af054ae..9eca801f 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -474,8 +474,8 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { AdinError::Spi(e) => { error!("RX Spi error {}", e.kind()); } - _ => { - error!("RX Error"); + e => { + error!("RX Error {:?}", e); } }, }, From 6e616a6fe60f1ff9355888724af7c201ae70ed1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Mon, 28 Aug 2023 19:23:15 +0200 Subject: [PATCH 059/233] Update comment about turn around byte. --- embassy-net-adin1110/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 9eca801f..e0af7bde 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -77,7 +77,7 @@ const ETH_MIN_WITHOUT_FCS_LEN: usize = ETH_MIN_LEN - FCS_LEN; const SPI_HEADER_LEN: usize = 2; /// SPI Header CRC length const SPI_HEADER_CRC_LEN: usize = 1; -/// SPI Header Trun Around length +/// SPI Header Turn Around length const SPI_HEADER_TA_LEN: usize = 1; /// Frame Header length const FRAME_HEADER_LEN: usize = 2; @@ -137,7 +137,7 @@ impl ADIN1110 { let _ = tx_buf.push(crc8(&tx_buf)); } - // Turn around byte, TODO: Unknown that this is. + // Turn around byte, give the chip the time to access/setup the answer data. let _ = tx_buf.push(TURN_AROUND_BYTE); let mut rx_buf = [0; 5]; From 7fc17bc15001449ea427cb0bff3557922ae595ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Mon, 28 Aug 2023 19:29:32 +0200 Subject: [PATCH 060/233] embassy-net-adin1110 bump deps. --- embassy-net-adin1110/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 26111c09..8de8eade 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -12,12 +12,12 @@ edition = "2021" [dependencies] heapless = "0.7.16" defmt = { version = "0.3", optional = true } -log = { version = "0.4.4", default-features = false, optional = true } +log = { version = "0.4", default-features = false, optional = true } embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" } embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] } embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } -embassy-time = { version = "0.1.0" } +embassy-time = { version = "0.1.3" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" @@ -27,8 +27,8 @@ bitfield = "0.14.0" embedded-hal-mock = { git = "https://github.com/newAM/embedded-hal-mock", branch = "eh1-rc.1", features = ["embedded-hal-async", "eh1"] } crc = "3.0.1" env_logger = "0.10" -critical-section = { version = "1.1.1", features = ["std"] } -futures-test = "0.3.17" +critical-section = { version = "1.1.2", features = ["std"] } +futures-test = "0.3.28" [features] default = [ ] From 1db00f54399307e4ec922965f5ca49547ccd14a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Mon, 28 Aug 2023 20:00:59 +0200 Subject: [PATCH 061/233] embassy-net-adin1110: Add basic benchmark results. --- embassy-net-adin1110/README.md | 37 ++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/embassy-net-adin1110/README.md b/embassy-net-adin1110/README.md index 3c280418..8ea10b71 100644 --- a/embassy-net-adin1110/README.md +++ b/embassy-net-adin1110/README.md @@ -30,8 +30,8 @@ Currently only `Generic` SPI with or without CRC is supported. ## Hardware -- Tested on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with an `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) dor an example. -- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit`](https://www.sparkfun.com/products/19628), supporting multiple microcontrollers. **Make sure to check if it's a microcontroller that is supported by Embassy!** +- Tested on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with an `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) for an example. +- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit (End Of Life)`](https://www.sparkfun.com/products/19628), supporting multiple microcontrollers. **Make sure to check if it's a microcontroller that is supported by Embassy!** ## Other SPE chips @@ -44,6 +44,39 @@ ADIN1110 library can tested on the host with a mock SPI driver. $ `cargo test --target x86_64-unknown-linux-gnu` +## Benchmark + +- Benchmarked on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html), with [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) example. + +Basic `ping` benchmark +```rust,ignore +# ping -c 60 + +60 packets transmitted, 60 received, 0% packet loss, time 59066ms +rtt min/avg/max/mdev = 1.089/1.161/1.237/0.018 ms + +# ping -s 1472 -M do -c 60 + +60 packets transmitted, 60 received, 0% packet loss, time 59066ms +rtt min/avg/max/mdev = 5.122/5.162/6.177/0.133 ms +``` + +HTTP load generator benchmark with [`oha`](https://github.com/hatoo/oha) +```rust,ignore +# oha -c 1 http:// -z 60s +Summary: + Success rate: 50.00% + Total: 60.0005 secs + Slowest: 0.0055 secs + Fastest: 0.0033 secs + Average: 0.0034 secs + Requests/sec: 362.1971 + + Total data: 2.99 MiB + Size/request: 289 B + Size/sec: 51.11 KiB +``` + ## License This work is licensed under either of From 4098a61ef04e42294b182f4b0bf44ced97c706a0 Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Mon, 28 Aug 2023 21:02:38 +0200 Subject: [PATCH 062/233] cyw43: Fix warning in event.rs. Allow non_upper_case_globals, to prevent the compiler from spitting out a warning about the Event enum. --- cyw43/src/events.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyw43/src/events.rs b/cyw43/src/events.rs index a94c49a0..ce0e7e37 100644 --- a/cyw43/src/events.rs +++ b/cyw43/src/events.rs @@ -1,5 +1,5 @@ #![allow(dead_code)] -#![allow(non_camel_case_types)] +#![allow(non_camel_case_types, non_upper_case_globals)] use core::cell::RefCell; From 05ee02b5933dc8e87f3714294d272aa4cb23aefb Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Mon, 28 Aug 2023 21:32:31 +0200 Subject: [PATCH 063/233] cyw43: Introduce seperate up/down functions. Create two helper functions, for setting the interface up/down. --- cyw43/src/control.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index c67614dd..d2f6e4a0 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -124,7 +124,7 @@ impl<'a> Control<'a> { Timer::after(Duration::from_millis(100)).await; // set wifi up - self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; + self.up().await; Timer::after(Duration::from_millis(100)).await; @@ -138,6 +138,16 @@ impl<'a> Control<'a> { debug!("INIT DONE"); } + /// Set the WiFi interface up. + async fn up(&mut self) { + self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; + } + + /// Set the interface down. + async fn down(&mut self) { + self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; + } + pub async fn set_power_management(&mut self, mode: PowerManagementMode) { // power save mode let mode_num = mode.mode(); @@ -256,13 +266,13 @@ impl<'a> Control<'a> { } // Temporarily set wifi down - self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; + self.down().await; // Turn off APSTA mode self.set_iovar_u32("apsta", 0).await; // Set wifi up again - self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; + self.up().await; // Turn on AP mode self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await; From e0256939141ab8e4670f58e87886d0266c1d462c Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Mon, 28 Aug 2023 21:34:14 +0200 Subject: [PATCH 064/233] cyw43: Create leave function on Control struct. Create a function, which disassociates us, from the currently connected infra. --- cyw43/src/consts.rs | 1 + cyw43/src/control.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs index 1f655158..4e2836f3 100644 --- a/cyw43/src/consts.rs +++ b/cyw43/src/consts.rs @@ -96,6 +96,7 @@ pub(crate) const IOCTL_CMD_UP: u32 = 2; pub(crate) const IOCTL_CMD_DOWN: u32 = 3; pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26; pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30; +pub(crate) const IOCTL_CMD_DISASSOC: u32 = 52; pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64; pub(crate) const IOCTL_CMD_SET_AP: u32 = 118; pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263; diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index d2f6e4a0..a6d1f0bf 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -433,6 +433,11 @@ impl<'a> Control<'a> { events: &self.events, } } + /// Leave the wifi, with which we are currently associated. + pub async fn leave(&mut self) { + self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await; + info!("Disassociated") + } } pub struct Scanner<'a> { From b315c28d4eda4fe62747d7f626226862cbc92629 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Aug 2023 15:30:29 -0500 Subject: [PATCH 065/233] stm32/rtc: remove rtc-debug and asbtract exti wakeup --- embassy-stm32/Cargo.toml | 3 +-- embassy-stm32/src/low_power.rs | 10 +--------- embassy-stm32/src/rtc/v2.rs | 26 ++++++++------------------ embassy-stm32/src/time_driver.rs | 2 -- 4 files changed, 10 insertions(+), 31 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ca421910..d0ada97a 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" -features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time", "low-power", "rtc-debug"] +features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time", "low-power"] flavors = [ { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, @@ -90,7 +90,6 @@ defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-emb exti = [] low-power = [ "dep:embassy-executor", "embassy-executor/arch-cortex-m" ] -rtc-debug = [] embassy-executor = [] ## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index f9b5fde9..d0230ed7 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -89,9 +89,6 @@ impl Executor { self.time_driver.resume_time(); trace!("low power: resume time"); - - #[cfg(feature = "rtc-debug")] - cortex_m::asm::bkpt(); } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { @@ -102,8 +99,7 @@ impl Executor { crate::interrupt::typelevel::RTC_WKUP::unpend(); unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; - EXTI.rtsr(0).modify(|w| w.set_line(22, true)); - EXTI.imr(0).modify(|w| w.set_line(22, true)); + rtc.enable_wakeup_line(); } fn configure_pwr(&mut self) { @@ -121,7 +117,6 @@ impl Executor { } trace!("low power: enter stop..."); - #[cfg(not(feature = "rtc-debug"))] self.scb.set_sleepdeep(); } @@ -144,9 +139,6 @@ impl Executor { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - #[cfg(feature = "rtc-debug")] - trace!("low power: rtc debug enabled"); - init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); loop { diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 7eb8a96c..49f66e95 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -75,21 +75,6 @@ impl super::Rtc { /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { - #[cfg(feature = "rtc-debug")] - if critical_section::with(|cs| { - if let Some(instant) = self.stop_time.borrow(cs).take() { - self.stop_time.borrow(cs).replace(Some(instant)); - - Some(()) - } else { - None - } - }) - .is_some() - { - return; - } - use embassy_time::{Duration, TICK_HZ}; use crate::rcc::get_freqs; @@ -133,6 +118,14 @@ impl super::Rtc { critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) } + #[cfg(feature = "low-power")] + pub(crate) fn enable_wakeup_line(&self) { + use crate::pac::EXTI; + + EXTI.rtsr(0).modify(|w| w.set_line(22, true)); + EXTI.imr(0).modify(|w| w.set_line(22, true)); + } + #[cfg(feature = "low-power")] /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` /// was called, otherwise none @@ -141,9 +134,6 @@ impl super::Rtc { trace!("rtc: stop wakeup alarm at {}", self.instant()); - #[cfg(feature = "rtc-debug")] - return None; - self.write(false, |regs| { regs.cr().modify(|w| w.set_wutie(false)); regs.cr().modify(|w| w.set_wute(false)); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index d4442c23..99d423d0 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -363,7 +363,6 @@ impl RtcDriver { .start_wakeup_alarm(time_until_next_alarm); }); - #[cfg(not(feature = "rtc-debug"))] T::regs_gp16().cr1().modify(|w| w.set_cen(false)); Ok(()) @@ -375,7 +374,6 @@ impl RtcDriver { pub(crate) fn resume_time(&self) { self.stop_wakeup_alarm(); - #[cfg(not(feature = "rtc-debug"))] T::regs_gp16().cr1().modify(|w| w.set_cen(true)); } } From 70a5221b2e0d40a43794bf65fc4d84e0af8ab079 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Aug 2023 15:34:08 -0500 Subject: [PATCH 066/233] stm32/bd: consolidate enable_rtc --- embassy-stm32/src/rcc/bd.rs | 39 +++++++------------------------------ 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 0fc116ed..4d8ed82a 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -87,13 +87,14 @@ impl BackupDomain { } #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, + rtc_v3u5 ))] #[allow(dead_code)] pub fn enable_rtc() { let reg = Self::read(); - #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); if !reg.rtcen() { @@ -102,47 +103,21 @@ impl BackupDomain { Self::modify(|w| { // Reset - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] w.set_bdrst(false); w.set_rtcen(true); w.set_rtcsel(reg.rtcsel()); // Restore bcdr - #[cfg(any(rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] w.set_lscosel(reg.lscosel()); - #[cfg(any(rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] w.set_lscoen(reg.lscoen()); w.set_lseon(reg.lseon()); - #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } - } - - #[cfg(any(rtc_v3, rtc_v3u5))] - #[allow(dead_code)] - pub fn enable_rtc() { - let reg = Self::read(); - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() { - Self::modify(|w| w.set_bdrst(true)); - - Self::modify(|w| { - w.set_bdrst(false); - - w.set_rtcen(true); - w.set_rtcsel(reg.rtcsel()); - - // Restore bcdr - w.set_lscosel(reg.lscosel()); - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); + #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] w.set_lsedrv(reg.lsedrv()); w.set_lsebyp(reg.lsebyp()); }); From e07f9435624ea739282665d09fe0f996c71ef54c Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Aug 2023 15:52:13 -0500 Subject: [PATCH 067/233] rustfmt --- embassy-stm32/src/low_power.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index d0230ed7..7e678d32 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -6,7 +6,6 @@ use embassy_executor::*; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; -use crate::pac::EXTI; use crate::rcc::low_power_ready; use crate::time_driver::{get_driver, RtcDriver}; From 6b8b145266faaa06f6483ccb8d227c8060c9a46d Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Aug 2023 16:17:42 -0500 Subject: [PATCH 068/233] stm32: revert changes to rcc f4 --- embassy-stm32/src/rcc/f4.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index d8b689e4..10d3322a 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -17,7 +17,7 @@ use crate::{peripherals, Peripheral}; pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_768); +pub const LSI_FREQ: Hertz = Hertz(32_000); /// Clocks configuration #[non_exhaustive] From 70662ec4ba1d0ba9edd9d6b7a781c19dec938616 Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Tue, 29 Aug 2023 08:29:38 +0200 Subject: [PATCH 069/233] embassy-time: Introduced reset function for Ticker --- embassy-time/src/timer.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index ad5026e6..8996aefb 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -133,7 +133,14 @@ impl Ticker { Self { expires_at, duration } } - /// Waits for the next tick + /// Resets the ticker back to its original state. + /// + /// This causes the ticker to go back to zero, even if the current tick isn't over yet. + pub fn reset(&mut self) { + self.expires_at = Instant::now() + self.duration; + } + + /// Waits for the next tick. pub fn next(&mut self) -> impl Future + '_ { poll_fn(|cx| { if self.expires_at <= Instant::now() { From de01fe352b954c58f8c403d30da496d880b7e353 Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Tue, 29 Aug 2023 08:35:29 +0200 Subject: [PATCH 070/233] Removed unnecessary newline. --- embassy-time/src/timer.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 8996aefb..88134bc6 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -133,8 +133,7 @@ impl Ticker { Self { expires_at, duration } } - /// Resets the ticker back to its original state. - /// + /// Resets the ticker back to its original state. /// This causes the ticker to go back to zero, even if the current tick isn't over yet. pub fn reset(&mut self) { self.expires_at = Instant::now() + self.duration; From 0eeefd3dbf86cc2a590a34a2e1ac2dd80204faf2 Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Tue, 29 Aug 2023 23:05:05 +0200 Subject: [PATCH 071/233] cyw43: Make Scanner public. --- cyw43/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index 30a3d5f2..6b124cf7 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -27,7 +27,7 @@ use ioctl::IoctlState; use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; -pub use crate::control::{Control, Error as ControlError}; +pub use crate::control::{Control, Error as ControlError, Scanner}; pub use crate::runner::Runner; pub use crate::structs::BssInfo; From 975f2f23c0256f192838a5a5cd995faa9ad88f34 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 30 Aug 2023 01:04:43 +0200 Subject: [PATCH 072/233] net-ppp: return error when PPP link gets terminated by the peer. --- embassy-net-ppp/Cargo.toml | 2 +- embassy-net-ppp/src/lib.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index b2874c68..191577b5 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -18,7 +18,7 @@ log = { version = "0.4.14", optional = true } embedded-io-async = { version = "0.5.0" } embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -ppproto = { version = "0.1.1"} +ppproto = { version = "0.1.2"} embassy-sync = { version = "0.2.0", path = "../embassy-sync" } [package.metadata.embassy_docs] diff --git a/embassy-net-ppp/src/lib.rs b/embassy-net-ppp/src/lib.rs index ca87fbae..66496ee0 100644 --- a/embassy-net-ppp/src/lib.rs +++ b/embassy-net-ppp/src/lib.rs @@ -53,6 +53,8 @@ pub enum RunError { WriteZero, /// Writing to the serial got EOF. Eof, + /// PPP protocol was terminated by the peer + Terminated, } impl From> for RunError { @@ -128,6 +130,9 @@ impl<'d> Runner<'d> { let status = ppp.status(); match status.phase { + ppproto::Phase::Dead => { + return Err(RunError::Terminated); + } ppproto::Phase::Open => { if !was_up { on_ipv4_up(status.ipv4.unwrap()); From 6c165f8dc03455863bc123101d4f4a0dabdfcfbf Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 28 Aug 2023 01:53:15 +0200 Subject: [PATCH 073/233] sync/pipe: impl BufRead. --- embassy-sync/src/pipe.rs | 310 +++++++++++++++++++++----------- embassy-sync/src/ring_buffer.rs | 46 ++--- examples/rp/src/bin/pio_uart.rs | 10 +- 3 files changed, 233 insertions(+), 133 deletions(-) diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs index 21d451ea..ec0cbbf2 100644 --- a/embassy-sync/src/pipe.rs +++ b/embassy-sync/src/pipe.rs @@ -1,7 +1,8 @@ //! Async byte stream pipe. -use core::cell::RefCell; +use core::cell::{RefCell, UnsafeCell}; use core::future::Future; +use core::ops::Range; use core::pin::Pin; use core::task::{Context, Poll}; @@ -82,17 +83,6 @@ where pipe: &'p Pipe, } -impl<'p, M, const N: usize> Clone for Reader<'p, M, N> -where - M: RawMutex, -{ - fn clone(&self) -> Self { - Reader { pipe: self.pipe } - } -} - -impl<'p, M, const N: usize> Copy for Reader<'p, M, N> where M: RawMutex {} - impl<'p, M, const N: usize> Reader<'p, M, N> where M: RawMutex, @@ -110,6 +100,29 @@ where pub fn try_read(&self, buf: &mut [u8]) -> Result { self.pipe.try_read(buf) } + + /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. + /// + /// If no bytes are currently available to read, this function waits until at least one byte is available. + /// + /// If the reader is at end-of-file (EOF), an empty slice is returned. + pub fn fill_buf(&mut self) -> FillBufFuture<'_, M, N> { + FillBufFuture { pipe: Some(self.pipe) } + } + + /// Try returning contents of the internal buffer. + /// + /// If no bytes are currently available to read, this function returns `Err(TryReadError::Empty)`. + /// + /// If the reader is at end-of-file (EOF), an empty slice is returned. + pub fn try_fill_buf(&mut self) -> Result<&[u8], TryReadError> { + unsafe { self.pipe.try_fill_buf_with_context(None) } + } + + /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. + pub fn consume(&mut self, amt: usize) { + self.pipe.consume(amt) + } } /// Future returned by [`Pipe::read`] and [`Reader::read`]. @@ -138,6 +151,35 @@ where impl<'p, M, const N: usize> Unpin for ReadFuture<'p, M, N> where M: RawMutex {} +/// Future returned by [`Pipe::fill_buf`] and [`Reader::fill_buf`]. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct FillBufFuture<'p, M, const N: usize> +where + M: RawMutex, +{ + pipe: Option<&'p Pipe>, +} + +impl<'p, M, const N: usize> Future for FillBufFuture<'p, M, N> +where + M: RawMutex, +{ + type Output = &'p [u8]; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let pipe = self.pipe.take().unwrap(); + match unsafe { pipe.try_fill_buf_with_context(Some(cx)) } { + Ok(buf) => Poll::Ready(buf), + Err(TryReadError::Empty) => { + self.pipe = Some(pipe); + Poll::Pending + } + } + } +} + +impl<'p, M, const N: usize> Unpin for FillBufFuture<'p, M, N> where M: RawMutex {} + /// Error returned by [`try_read`](Pipe::try_read). #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -162,67 +204,24 @@ struct PipeState { write_waker: WakerRegistration, } -impl PipeState { - const fn new() -> Self { - PipeState { - buffer: RingBuffer::new(), - read_waker: WakerRegistration::new(), - write_waker: WakerRegistration::new(), - } +#[repr(transparent)] +struct Buffer(UnsafeCell<[u8; N]>); + +impl Buffer { + unsafe fn get<'a>(&self, r: Range) -> &'a [u8] { + let p = self.0.get() as *const u8; + core::slice::from_raw_parts(p.add(r.start), r.end - r.start) } - fn clear(&mut self) { - self.buffer.clear(); - self.write_waker.wake(); - } - - fn try_read(&mut self, buf: &mut [u8]) -> Result { - self.try_read_with_context(None, buf) - } - - fn try_read_with_context(&mut self, cx: Option<&mut Context<'_>>, buf: &mut [u8]) -> Result { - if self.buffer.is_full() { - self.write_waker.wake(); - } - - let available = self.buffer.pop_buf(); - if available.is_empty() { - if let Some(cx) = cx { - self.read_waker.register(cx.waker()); - } - return Err(TryReadError::Empty); - } - - let n = available.len().min(buf.len()); - buf[..n].copy_from_slice(&available[..n]); - self.buffer.pop(n); - Ok(n) - } - - fn try_write(&mut self, buf: &[u8]) -> Result { - self.try_write_with_context(None, buf) - } - - fn try_write_with_context(&mut self, cx: Option<&mut Context<'_>>, buf: &[u8]) -> Result { - if self.buffer.is_empty() { - self.read_waker.wake(); - } - - let available = self.buffer.push_buf(); - if available.is_empty() { - if let Some(cx) = cx { - self.write_waker.register(cx.waker()); - } - return Err(TryWriteError::Full); - } - - let n = available.len().min(buf.len()); - available[..n].copy_from_slice(&buf[..n]); - self.buffer.push(n); - Ok(n) + unsafe fn get_mut<'a>(&self, r: Range) -> &'a mut [u8] { + let p = self.0.get() as *mut u8; + core::slice::from_raw_parts_mut(p.add(r.start), r.end - r.start) } } +unsafe impl Send for Buffer {} +unsafe impl Sync for Buffer {} + /// A bounded byte-oriented pipe for communicating between asynchronous tasks /// with backpressure. /// @@ -234,6 +233,7 @@ pub struct Pipe where M: RawMutex, { + buf: Buffer, inner: Mutex>>, } @@ -252,7 +252,12 @@ where /// ``` pub const fn new() -> Self { Self { - inner: Mutex::new(RefCell::new(PipeState::new())), + buf: Buffer(UnsafeCell::new([0; N])), + inner: Mutex::new(RefCell::new(PipeState { + buffer: RingBuffer::new(), + read_waker: WakerRegistration::new(), + write_waker: WakerRegistration::new(), + })), } } @@ -261,21 +266,91 @@ where } fn try_read_with_context(&self, cx: Option<&mut Context<'_>>, buf: &mut [u8]) -> Result { - self.lock(|c| c.try_read_with_context(cx, buf)) + self.inner.lock(|rc: &RefCell>| { + let s = &mut *rc.borrow_mut(); + + if s.buffer.is_full() { + s.write_waker.wake(); + } + + let available = unsafe { self.buf.get(s.buffer.pop_buf()) }; + if available.is_empty() { + if let Some(cx) = cx { + s.read_waker.register(cx.waker()); + } + return Err(TryReadError::Empty); + } + + let n = available.len().min(buf.len()); + buf[..n].copy_from_slice(&available[..n]); + s.buffer.pop(n); + Ok(n) + }) + } + + // safety: While the returned slice is alive, + // no `read` or `consume` methods in the pipe must be called. + unsafe fn try_fill_buf_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<&[u8], TryReadError> { + self.inner.lock(|rc: &RefCell>| { + let s = &mut *rc.borrow_mut(); + + if s.buffer.is_full() { + s.write_waker.wake(); + } + + let available = unsafe { self.buf.get(s.buffer.pop_buf()) }; + if available.is_empty() { + if let Some(cx) = cx { + s.read_waker.register(cx.waker()); + } + return Err(TryReadError::Empty); + } + + Ok(available) + }) + } + + fn consume(&self, amt: usize) { + self.inner.lock(|rc: &RefCell>| { + let s = &mut *rc.borrow_mut(); + let available = s.buffer.pop_buf(); + assert!(amt <= available.len()); + s.buffer.pop(amt); + }) } fn try_write_with_context(&self, cx: Option<&mut Context<'_>>, buf: &[u8]) -> Result { - self.lock(|c| c.try_write_with_context(cx, buf)) + self.inner.lock(|rc: &RefCell>| { + let s = &mut *rc.borrow_mut(); + + if s.buffer.is_empty() { + s.read_waker.wake(); + } + + let available = unsafe { self.buf.get_mut(s.buffer.push_buf()) }; + if available.is_empty() { + if let Some(cx) = cx { + s.write_waker.register(cx.waker()); + } + return Err(TryWriteError::Full); + } + + let n = available.len().min(buf.len()); + available[..n].copy_from_slice(&buf[..n]); + s.buffer.push(n); + Ok(n) + }) } - /// Get a writer for this pipe. - pub fn writer(&self) -> Writer<'_, M, N> { - Writer { pipe: self } - } - - /// Get a reader for this pipe. - pub fn reader(&self) -> Reader<'_, M, N> { - Reader { pipe: self } + /// Split this pipe into a BufRead-capable reader and a writer. + /// + /// The reader and writer borrow the current pipe mutably, so it is not + /// possible to use it directly while they exist. This is needed because + /// implementing `BufRead` requires there is a single reader. + /// + /// The writer is cloneable, the reader is not. + pub fn split(&mut self) -> (Reader<'_, M, N>, Writer<'_, M, N>) { + (Reader { pipe: self }, Writer { pipe: self }) } /// Write some bytes to the pipe. @@ -312,7 +387,7 @@ where /// or return an error if the pipe is empty. See [`write`](Self::write) for a variant /// that waits instead of returning an error. pub fn try_write(&self, buf: &[u8]) -> Result { - self.lock(|c| c.try_write(buf)) + self.try_write_with_context(None, buf) } /// Read some bytes from the pipe. @@ -339,12 +414,17 @@ where /// or return an error if the pipe is empty. See [`read`](Self::read) for a variant /// that waits instead of returning an error. pub fn try_read(&self, buf: &mut [u8]) -> Result { - self.lock(|c| c.try_read(buf)) + self.try_read_with_context(None, buf) } /// Clear the data in the pipe's buffer. pub fn clear(&self) { - self.lock(|c| c.clear()) + self.inner.lock(|rc: &RefCell>| { + let s = &mut *rc.borrow_mut(); + + s.buffer.clear(); + s.write_waker.wake(); + }) } /// Return whether the pipe is full (no free space in the buffer) @@ -433,6 +513,16 @@ mod io_impls { } } + impl embedded_io_async::BufRead for Reader<'_, M, N> { + async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { + Ok(Reader::fill_buf(self).await) + } + + fn consume(&mut self, amt: usize) { + Reader::consume(self, amt) + } + } + impl embedded_io_async::ErrorType for Writer<'_, M, N> { type Error = Infallible; } @@ -457,43 +547,39 @@ mod tests { use super::*; use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; - fn capacity(c: &PipeState) -> usize { - N - c.buffer.len() - } - #[test] fn writing_once() { - let mut c = PipeState::<3>::new(); + let c = Pipe::::new(); assert!(c.try_write(&[1]).is_ok()); - assert_eq!(capacity(&c), 2); + assert_eq!(c.free_capacity(), 2); } #[test] fn writing_when_full() { - let mut c = PipeState::<3>::new(); + let c = Pipe::::new(); assert_eq!(c.try_write(&[42]), Ok(1)); assert_eq!(c.try_write(&[43]), Ok(1)); assert_eq!(c.try_write(&[44]), Ok(1)); assert_eq!(c.try_write(&[45]), Err(TryWriteError::Full)); - assert_eq!(capacity(&c), 0); + assert_eq!(c.free_capacity(), 0); } #[test] fn receiving_once_with_one_send() { - let mut c = PipeState::<3>::new(); + let c = Pipe::::new(); assert!(c.try_write(&[42]).is_ok()); let mut buf = [0; 16]; assert_eq!(c.try_read(&mut buf), Ok(1)); assert_eq!(buf[0], 42); - assert_eq!(capacity(&c), 3); + assert_eq!(c.free_capacity(), 3); } #[test] fn receiving_when_empty() { - let mut c = PipeState::<3>::new(); + let c = Pipe::::new(); let mut buf = [0; 16]; assert_eq!(c.try_read(&mut buf), Err(TryReadError::Empty)); - assert_eq!(capacity(&c), 3); + assert_eq!(c.free_capacity(), 3); } #[test] @@ -506,13 +592,37 @@ mod tests { } #[test] - fn cloning() { - let c = Pipe::::new(); - let r1 = c.reader(); - let w1 = c.writer(); + fn read_buf() { + let mut c = Pipe::::new(); + let (mut r, w) = c.split(); + assert!(w.try_write(&[42, 43]).is_ok()); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[42, 43]); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[42, 43]); + r.consume(1); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[43]); + r.consume(1); + assert_eq!(r.try_fill_buf(), Err(TryReadError::Empty)); + assert_eq!(w.try_write(&[44, 45, 46]), Ok(1)); + assert_eq!(w.try_write(&[45, 46]), Ok(2)); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[44]); // only one byte due to wraparound. + r.consume(1); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[45, 46]); + assert!(w.try_write(&[47]).is_ok()); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[45, 46, 47]); + r.consume(3); + } - let _ = r1.clone(); - let _ = w1.clone(); + #[test] + fn writer_is_cloneable() { + let mut c = Pipe::::new(); + let (_r, w) = c.split(); + let _ = w.clone(); } #[futures_test::test] diff --git a/embassy-sync/src/ring_buffer.rs b/embassy-sync/src/ring_buffer.rs index 52108402..d95ffa7c 100644 --- a/embassy-sync/src/ring_buffer.rs +++ b/embassy-sync/src/ring_buffer.rs @@ -1,5 +1,6 @@ +use core::ops::Range; + pub struct RingBuffer { - buf: [u8; N], start: usize, end: usize, empty: bool, @@ -8,27 +9,26 @@ pub struct RingBuffer { impl RingBuffer { pub const fn new() -> Self { Self { - buf: [0; N], start: 0, end: 0, empty: true, } } - pub fn push_buf(&mut self) -> &mut [u8] { + pub fn push_buf(&mut self) -> Range { if self.start == self.end && !self.empty { trace!(" ringbuf: push_buf empty"); - return &mut self.buf[..0]; + return 0..0; } let n = if self.start <= self.end { - self.buf.len() - self.end + N - self.end } else { self.start - self.end }; trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); - &mut self.buf[self.end..self.end + n] + self.end..self.end + n } pub fn push(&mut self, n: usize) { @@ -41,20 +41,20 @@ impl RingBuffer { self.empty = false; } - pub fn pop_buf(&mut self) -> &mut [u8] { + pub fn pop_buf(&mut self) -> Range { if self.empty { trace!(" ringbuf: pop_buf empty"); - return &mut self.buf[..0]; + return 0..0; } let n = if self.end <= self.start { - self.buf.len() - self.start + N - self.start } else { self.end - self.start }; trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); - &mut self.buf[self.start..self.start + n] + self.start..self.start + n } pub fn pop(&mut self, n: usize) { @@ -93,8 +93,8 @@ impl RingBuffer { } fn wrap(&self, n: usize) -> usize { - assert!(n <= self.buf.len()); - if n == self.buf.len() { + assert!(n <= N); + if n == N { 0 } else { n @@ -110,37 +110,29 @@ mod tests { fn push_pop() { let mut rb: RingBuffer<4> = RingBuffer::new(); let buf = rb.push_buf(); - assert_eq!(4, buf.len()); - buf[0] = 1; - buf[1] = 2; - buf[2] = 3; - buf[3] = 4; + assert_eq!(0..4, buf); rb.push(4); let buf = rb.pop_buf(); - assert_eq!(4, buf.len()); - assert_eq!(1, buf[0]); + assert_eq!(0..4, buf); rb.pop(1); let buf = rb.pop_buf(); - assert_eq!(3, buf.len()); - assert_eq!(2, buf[0]); + assert_eq!(1..4, buf); rb.pop(1); let buf = rb.pop_buf(); - assert_eq!(2, buf.len()); - assert_eq!(3, buf[0]); + assert_eq!(2..4, buf); rb.pop(1); let buf = rb.pop_buf(); - assert_eq!(1, buf.len()); - assert_eq!(4, buf[0]); + assert_eq!(3..4, buf); rb.pop(1); let buf = rb.pop_buf(); - assert_eq!(0, buf.len()); + assert_eq!(0..0, buf); let buf = rb.push_buf(); - assert_eq!(4, buf.len()); + assert_eq!(0..4, buf); } } diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index 707c99b7..aa9e52cb 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -91,13 +91,11 @@ async fn main(_spawner: Spawner) { let (mut uart_tx, mut uart_rx) = uart.split(); // Pipe setup - let usb_pipe: Pipe = Pipe::new(); - let mut usb_pipe_writer = usb_pipe.writer(); - let mut usb_pipe_reader = usb_pipe.reader(); + let mut usb_pipe: Pipe = Pipe::new(); + let (mut usb_pipe_reader, mut usb_pipe_writer) = usb_pipe.split(); - let uart_pipe: Pipe = Pipe::new(); - let mut uart_pipe_writer = uart_pipe.writer(); - let mut uart_pipe_reader = uart_pipe.reader(); + let mut uart_pipe: Pipe = Pipe::new(); + let (mut uart_pipe_reader, mut uart_pipe_writer) = uart_pipe.split(); let (mut usb_tx, mut usb_rx) = class.split(); From 5e613d9abbb945e7fc7d4c895d645bfad6a3d2c8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 30 Aug 2023 01:37:18 +0200 Subject: [PATCH 074/233] Sync all fmt.rs files. --- cyw43/src/fmt.rs | 18 ++++++----- embassy-boot/boot/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-boot/nrf/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-boot/rp/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-boot/stm32/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-executor/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-futures/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-hal-internal/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-lora/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-net-driver-channel/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-net-enc28j60/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-net-esp-hosted/src/fmt.rs | 5 +-- embassy-net-ppp/src/fmt.rs | 5 +-- embassy-net/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-nrf/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-rp/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-stm32-wpan/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-stm32/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-sync/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-time/src/fmt.rs | 45 +++++++++++++++++++++++---- embassy-usb/src/fmt.rs | 45 +++++++++++++++++++++++---- 21 files changed, 719 insertions(+), 119 deletions(-) diff --git a/cyw43/src/fmt.rs b/cyw43/src/fmt.rs index 9534c101..78e583c1 100644 --- a/cyw43/src/fmt.rs +++ b/cyw43/src/fmt.rs @@ -83,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -226,7 +229,8 @@ impl Try for Result { } } -pub struct Bytes<'a>(pub &'a [u8]); +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { diff --git a/embassy-boot/boot/src/fmt.rs b/embassy-boot/boot/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-boot/boot/src/fmt.rs +++ b/embassy-boot/boot/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-boot/nrf/src/fmt.rs b/embassy-boot/nrf/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-boot/nrf/src/fmt.rs +++ b/embassy-boot/nrf/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-boot/rp/src/fmt.rs b/embassy-boot/rp/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-boot/rp/src/fmt.rs +++ b/embassy-boot/rp/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-boot/stm32/src/fmt.rs b/embassy-boot/stm32/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-boot/stm32/src/fmt.rs +++ b/embassy-boot/stm32/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-executor/src/fmt.rs b/embassy-executor/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-executor/src/fmt.rs +++ b/embassy-executor/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-futures/src/fmt.rs b/embassy-futures/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-futures/src/fmt.rs +++ b/embassy-futures/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-hal-internal/src/fmt.rs b/embassy-hal-internal/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-hal-internal/src/fmt.rs +++ b/embassy-hal-internal/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-lora/src/fmt.rs b/embassy-lora/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-lora/src/fmt.rs +++ b/embassy-lora/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-net-driver-channel/src/fmt.rs b/embassy-net-driver-channel/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-net-driver-channel/src/fmt.rs +++ b/embassy-net-driver-channel/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-net-enc28j60/src/fmt.rs b/embassy-net-enc28j60/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-net-enc28j60/src/fmt.rs +++ b/embassy-net-enc28j60/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-net-esp-hosted/src/fmt.rs b/embassy-net-esp-hosted/src/fmt.rs index 91984bde..78e583c1 100644 --- a/embassy-net-esp-hosted/src/fmt.rs +++ b/embassy-net-esp-hosted/src/fmt.rs @@ -93,7 +93,7 @@ macro_rules! unreachable { #[cfg(feature = "defmt")] macro_rules! unreachable { ($($x:tt)*) => { - ::defmt::unreachable!($($x)*); + ::defmt::unreachable!($($x)*) }; } @@ -229,7 +229,8 @@ impl Try for Result { } } -pub struct Bytes<'a>(pub &'a [u8]); +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { diff --git a/embassy-net-ppp/src/fmt.rs b/embassy-net-ppp/src/fmt.rs index 91984bde..78e583c1 100644 --- a/embassy-net-ppp/src/fmt.rs +++ b/embassy-net-ppp/src/fmt.rs @@ -93,7 +93,7 @@ macro_rules! unreachable { #[cfg(feature = "defmt")] macro_rules! unreachable { ($($x:tt)*) => { - ::defmt::unreachable!($($x)*); + ::defmt::unreachable!($($x)*) }; } @@ -229,7 +229,8 @@ impl Try for Result { } } -pub struct Bytes<'a>(pub &'a [u8]); +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); impl<'a> Debug for Bytes<'a> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { diff --git a/embassy-net/src/fmt.rs b/embassy-net/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-net/src/fmt.rs +++ b/embassy-net/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-nrf/src/fmt.rs b/embassy-nrf/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-nrf/src/fmt.rs +++ b/embassy-nrf/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-rp/src/fmt.rs b/embassy-rp/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-rp/src/fmt.rs +++ b/embassy-rp/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-stm32-wpan/src/fmt.rs b/embassy-stm32-wpan/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-stm32-wpan/src/fmt.rs +++ b/embassy-stm32-wpan/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-stm32/src/fmt.rs +++ b/embassy-stm32/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-sync/src/fmt.rs b/embassy-sync/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-sync/src/fmt.rs +++ b/embassy-sync/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-time/src/fmt.rs b/embassy-time/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-time/src/fmt.rs +++ b/embassy-time/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-usb/src/fmt.rs b/embassy-usb/src/fmt.rs index 06697081..78e583c1 100644 --- a/embassy-usb/src/fmt.rs +++ b/embassy-usb/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} From 989c98f316df3cde4512066e3682debb47d48161 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Aug 2023 19:41:03 -0500 Subject: [PATCH 075/233] stm32/rtc: autocompute prescalers --- embassy-stm32/src/rcc/f4.rs | 1 + embassy-stm32/src/rcc/mod.rs | 6 ++- embassy-stm32/src/rtc/mod.rs | 72 +++++++++++++++--------------------- embassy-stm32/src/rtc/v2.rs | 6 +-- embassy-stm32/src/rtc/v3.rs | 6 +-- 5 files changed, 41 insertions(+), 50 deletions(-) diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 10d3322a..c2c78a45 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -499,6 +499,7 @@ pub(crate) unsafe fn init(config: Config) { pllsai: None, rtc: rtc, + rtc_hse: None, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 9f1b3b66..1ead60b1 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -78,8 +78,12 @@ pub struct Clocks { pub adc: Option, #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - /// Set only if the lsi or lse is configured + /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, + + #[cfg(any(rcc_f4, rcc_f410))] + /// Set if the hse is configured, indicates stop is not supported + pub rtc_hse: Option, } #[cfg(feature = "low-power")] diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 796fd7d9..3704e446 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -12,6 +12,7 @@ use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; use crate::rcc::bd::BackupDomain; pub use crate::rcc::RtcClockSource; +use crate::time::Hertz; /// refer to AN4759 to compare features of RTC2 and RTC3 #[cfg_attr(any(rtc_v1), path = "v1.rs")] @@ -84,47 +85,23 @@ impl core::ops::Sub for RtcInstant { /// RTC Abstraction pub struct Rtc { - rtc_config: RtcConfig, #[cfg(feature = "low-power")] stop_time: Mutex>>, } #[derive(Copy, Clone, PartialEq)] pub struct RtcConfig { - /// Asynchronous prescaler factor - /// This is the asynchronous division factor: - /// ck_apre frequency = RTCCLK frequency/(PREDIV_A+1) - /// ck_apre drives the subsecond register - async_prescaler: u8, - /// Synchronous prescaler factor - /// This is the synchronous division factor: - /// ck_spre frequency = ck_apre frequency/(PREDIV_S+1) - /// ck_spre must be 1Hz - sync_prescaler: u16, + /// The subsecond counter frequency; default is 256 + /// + /// A high counter frequency may impact stop power consumption + pub frequency: Hertz, } impl Default for RtcConfig { /// LSI with prescalers assuming 32.768 kHz. /// Raw sub-seconds in 1/256. fn default() -> Self { - RtcConfig { - async_prescaler: 127, - sync_prescaler: 255, - } - } -} - -impl RtcConfig { - /// Set the asynchronous prescaler of RTC config - pub fn async_prescaler(mut self, prescaler: u8) -> Self { - self.async_prescaler = prescaler; - self - } - - /// Set the synchronous prescaler of RTC config - pub fn sync_prescaler(mut self, prescaler: u16) -> Self { - self.sync_prescaler = prescaler; - self + RtcConfig { frequency: Hertz(256) } } } @@ -147,23 +124,36 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { + use crate::rcc::get_freqs; + RTC::enable_peripheral_clk(); + BackupDomain::enable_rtc(); - #[cfg(not(feature = "low-power"))] - let mut rtc_struct = Self { rtc_config }; - - #[cfg(feature = "low-power")] - let mut rtc_struct = Self { - rtc_config, + let mut this = Self { + #[cfg(feature = "low-power")] stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }; - BackupDomain::enable_rtc(); + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + let freqs = unsafe { get_freqs() }; - rtc_struct.configure(rtc_config); - rtc_struct.rtc_config = rtc_config; + // Load the clock frequency from the rcc mod, if supported + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + let frequency = match freqs.rtc { + Some(hertz) => hertz, + None => freqs.rtc_hse.unwrap(), + }; - rtc_struct + // Assume the default value, if not supported + #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))] + let frequency = Hertz(32_768); + + let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8; + let sync_psc = (rtc_config.frequency.0 - 1) as u16; + + this.configure(async_psc, sync_psc); + + this } /// Set the datetime to a new value. @@ -228,10 +218,6 @@ impl Rtc { }) } - pub fn get_config(&self) -> RtcConfig { - self.rtc_config - } - pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; /// Read content of the backup register. diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 49f66e95..63d9f09e 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -154,7 +154,7 @@ impl super::Rtc { /// Applies the RTC config /// It this changes the RTC clock source the time will be reset - pub(super) fn configure(&mut self, rtc_config: RtcConfig) { + pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { self.write(true, |rtc| { rtc.cr().modify(|w| { #[cfg(rtc_v2f2)] @@ -166,8 +166,8 @@ impl super::Rtc { }); rtc.prer().modify(|w| { - w.set_prediv_s(rtc_config.sync_prescaler); - w.set_prediv_a(rtc_config.async_prescaler); + w.set_prediv_s(sync_psc); + w.set_prediv_a(async_psc); }); }); } diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 12952b15..c03b1071 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -8,7 +8,7 @@ use crate::rtc::sealed::Instance; impl super::Rtc { /// Applies the RTC config /// It this changes the RTC clock source the time will be reset - pub(super) fn configure(&mut self, rtc_config: RtcConfig) { + pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { self.write(true, |rtc| { rtc.cr().modify(|w| { w.set_fmt(Fmt::TWENTYFOURHOUR); @@ -17,8 +17,8 @@ impl super::Rtc { }); rtc.prer().modify(|w| { - w.set_prediv_s(rtc_config.sync_prescaler); - w.set_prediv_a(rtc_config.async_prescaler); + w.set_prediv_s(sync_psc); + w.set_prediv_a(async_psc); }); // TODO: configuration for output pins From 21681d8b4ee392ce3b4f68be76b6096abe104ad3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Aug 2023 19:44:43 -0500 Subject: [PATCH 076/233] rustfmt --- embassy-stm32/src/rtc/mod.rs | 1 + embassy-stm32/src/rtc/v2.rs | 2 +- embassy-stm32/src/rtc/v3.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 3704e446..9db4f69c 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -124,6 +124,7 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] use crate::rcc::get_freqs; RTC::enable_peripheral_clk(); diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 63d9f09e..482b6e75 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -1,6 +1,6 @@ use stm32_metapac::rtc::vals::{Init, Osel, Pol}; -use super::{sealed, RtcConfig}; +use super::sealed; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; use crate::rtc::sealed::Instance; diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index c03b1071..a6b2655d 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -1,6 +1,6 @@ use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; -use super::{sealed, RtcCalibrationCyclePeriod, RtcConfig}; +use super::{sealed, RtcCalibrationCyclePeriod}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; use crate::rtc::sealed::Instance; From 27dfced285f7f997d6a7679373052efb7ae84e01 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Aug 2023 19:51:21 -0500 Subject: [PATCH 077/233] stm32: fix rcc wb --- embassy-stm32/src/rcc/mod.rs | 2 +- embassy-stm32/src/rcc/wb.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 1ead60b1..0430e4a7 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -81,7 +81,7 @@ pub struct Clocks { /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, - #[cfg(any(rcc_f4, rcc_f410))] + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] /// Set if the hse is configured, indicates stop is not supported pub rtc_hse: Option, } diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index 6a3eab70..6496b41e 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -271,6 +271,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { apb1_tim: apb1_tim_clk, apb2_tim: apb2_tim_clk, rtc: rtc_clk, + rtc_hse: None, } } From 416ecc73d8211e348bf51a5cfe84075673b18963 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Aug 2023 20:06:53 -0500 Subject: [PATCH 078/233] add qei draft --- embassy-stm32/src/timer/qei.rs | 142 +++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 embassy-stm32/src/timer/qei.rs diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs new file mode 100644 index 00000000..fa881472 --- /dev/null +++ b/embassy-stm32/src/timer/qei.rs @@ -0,0 +1,142 @@ +//! # Quadrature Encoder Interface +use crate::{ + gpio::PushPull, + pac, rcc, + timer::{CPin, General}, +}; + +pub trait QeiExt: Sized + Instance { + fn qei( + self, + pins: ( + impl Into<>::Ch>, + impl Into<>::Ch>, + ), + ) -> Qei; +} + +impl QeiExt for TIM { + fn qei( + self, + pins: ( + impl Into<>::Ch>, + impl Into<>::Ch>, + ), + ) -> Qei { + Qei::new(self, pins) + } +} + +/// Hardware quadrature encoder interface peripheral +pub struct Qei { + tim: TIM, + pins: ( + >::Ch, + >::Ch, + ), +} + +impl Qei { + /// Configures a TIM peripheral as a quadrature encoder interface input + pub fn new( + mut tim: TIM, + pins: ( + impl Into<>::Ch>, + impl Into<>::Ch>, + ), + ) -> Self { + // Enable and reset clock. + unsafe { + TIM::enable_unchecked(); + TIM::reset_unchecked(); + } + + let pins = (pins.0.into(), pins.1.into()); + tim.setup_qei(); + + Qei { tim, pins } + } + + /// Releases the TIM peripheral and QEI pins + #[allow(clippy::type_complexity)] + pub fn release( + self, + ) -> ( + TIM, + ( + >::Ch, + >::Ch, + ), + ) { + (self.tim, self.pins) + } + + /// Set current count number + pub fn set_count(&mut self, value: TIM::Width) -> &mut Self { + self.tim.write_count(value); + self + } +} + +impl embedded_hal::Qei for Qei { + type Count = TIM::Width; + + fn count(&self) -> Self::Count { + self.tim.read_count() + } + + fn direction(&self) -> embedded_hal::Direction { + if self.tim.read_direction() { + embedded_hal::Direction::Upcounting + } else { + embedded_hal::Direction::Downcounting + } + } +} + +pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + General + CPin<0> + CPin<1> { + fn setup_qei(&mut self); + + fn read_direction(&self) -> bool; +} + +macro_rules! hal { + ($TIM:ty) => { + impl Instance for $TIM { + fn setup_qei(&mut self) { + // Configure TxC1 and TxC2 as captures + #[cfg(not(feature = "gpio-f410"))] + self.ccmr1_input().write(|w| w.cc1s().ti1().cc2s().ti2()); + #[cfg(feature = "gpio-f410")] + self.ccmr1_input() + .write(|w| unsafe { w.cc1s().bits(0b01).cc2s().bits(0b01) }); + // enable and configure to capture on rising edge + self.ccer.write(|w| { + w.cc1e().set_bit().cc1p().clear_bit(); + w.cc2e().set_bit().cc2p().clear_bit() + }); + self.smcr.write(|w| w.sms().encoder_mode_3()); + self.set_auto_reload(<$TIM as General>::Width::MAX as u32) + .unwrap(); + self.cr1.write(|w| w.cen().set_bit()); + } + + fn read_direction(&self) -> bool { + self.cr1.read().dir().bit_is_clear() + } + } + }; +} + +#[cfg(feature = "tim1")] +hal! { pac::TIM1 } +#[cfg(feature = "tim2")] +hal! { pac::TIM2 } +#[cfg(feature = "tim3")] +hal! { pac::TIM3 } +#[cfg(feature = "tim4")] +hal! { pac::TIM4 } +#[cfg(feature = "tim5")] +hal! { pac::TIM5 } +#[cfg(feature = "tim8")] +hal! { pac::TIM8 } From 98f55fa54dd4fd585e90211919f025a7025301a6 Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Wed, 30 Aug 2023 09:59:47 +0200 Subject: [PATCH 079/233] Reverted patch for lint fix. --- cyw43/src/events.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyw43/src/events.rs b/cyw43/src/events.rs index ce0e7e37..a94c49a0 100644 --- a/cyw43/src/events.rs +++ b/cyw43/src/events.rs @@ -1,5 +1,5 @@ #![allow(dead_code)] -#![allow(non_camel_case_types, non_upper_case_globals)] +#![allow(non_camel_case_types)] use core::cell::RefCell; From 36ec9bcc1d4ed9beff2e866bcb5ea388538320bb Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Wed, 30 Aug 2023 19:35:15 +0200 Subject: [PATCH 080/233] Stm32 timer prevent hardfault --- embassy-stm32/src/timer/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 4ffb2a28..b5ced45f 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -211,6 +211,7 @@ macro_rules! impl_basic_16bit_timer { use core::convert::TryInto; let f = frequency.0; let timer_f = Self::frequency().0; + assert!(f > 0); let pclk_ticks_per_timer_period = timer_f / f; let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); @@ -255,6 +256,7 @@ macro_rules! impl_32bit_timer { fn set_frequency(&mut self, frequency: Hertz) { use core::convert::TryInto; let f = frequency.0; + assert!(f > 0); let timer_f = Self::frequency().0; let pclk_ticks_per_timer_period = (timer_f / f) as u64; let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); From ae174fd0e0102ad77d18c33754dc5493e58dfdb5 Mon Sep 17 00:00:00 2001 From: Michael van Niekerk Date: Wed, 30 Aug 2023 21:42:27 +0200 Subject: [PATCH 081/233] RP2040: XOSC delay multiplier --- embassy-rp/src/clocks.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 7b25ecff..4637ae05 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -94,6 +94,7 @@ impl ClockConfig { post_div1: 6, post_div2: 5, }), + delay_multiplier: 1 }), ref_clk: RefClkConfig { src: RefClkSrc::Xosc, @@ -203,6 +204,7 @@ pub struct XoscConfig { pub hz: u32, pub sys_pll: Option, pub usb_pll: Option, + pub delay_multiplier: u32, } pub struct PllConfig { @@ -363,7 +365,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { // start XOSC // datasheet mentions support for clock inputs into XIN, but doesn't go into // how this is achieved. pico-sdk doesn't support this at all. - start_xosc(config.hz); + start_xosc(config.hz, config.delay_multiplier); let pll_sys_freq = match config.sys_pll { Some(sys_pll_config) => configure_pll(pac::PLL_SYS, config.hz, sys_pll_config), @@ -624,12 +626,12 @@ pub fn clk_rtc_freq() -> u16 { CLOCKS.rtc.load(Ordering::Relaxed) } -fn start_xosc(crystal_hz: u32) { +fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { pac::XOSC .ctrl() .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); - let startup_delay = ((crystal_hz / 1000) + 128) / 256; + let startup_delay = (((crystal_hz / 1000) + 128) * delay_multiplier) / 256; pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); pac::XOSC.ctrl().write(|w| { w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ); From 891f1758bcd2621148ffba163d054da4420416aa Mon Sep 17 00:00:00 2001 From: Michael van Niekerk Date: Wed, 30 Aug 2023 21:43:57 +0200 Subject: [PATCH 082/233] RP2040: XOSC delay multiplier --- embassy-rp/src/clocks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 4637ae05..55a18cf6 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -94,7 +94,7 @@ impl ClockConfig { post_div1: 6, post_div2: 5, }), - delay_multiplier: 1 + delay_multiplier: 1, }), ref_clk: RefClkConfig { src: RefClkSrc::Xosc, From f69e8459c9a2362165df9dd603adb0ec6531d383 Mon Sep 17 00:00:00 2001 From: Michael van Niekerk Date: Wed, 30 Aug 2023 21:52:03 +0200 Subject: [PATCH 083/233] RP2040: Fixes as per PR --- embassy-rp/src/clocks.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 55a18cf6..c9b2190c 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -94,7 +94,7 @@ impl ClockConfig { post_div1: 6, post_div2: 5, }), - delay_multiplier: 1, + delay_multiplier: 128, }), ref_clk: RefClkConfig { src: RefClkSrc::Xosc, @@ -631,7 +631,7 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { .ctrl() .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); - let startup_delay = (((crystal_hz / 1000) + 128) * delay_multiplier) / 256; + let startup_delay = ((crystal_hz / 1000 + delay_multiplier) + 128) / 256; pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); pac::XOSC.ctrl().write(|w| { w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ); From a76ff53fb396be26dfc5153e72c3e77c004afdf6 Mon Sep 17 00:00:00 2001 From: Michael van Niekerk Date: Wed, 30 Aug 2023 21:58:36 +0200 Subject: [PATCH 084/233] RP2040: Fixes as per PR --- embassy-rp/src/clocks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index c9b2190c..2c41befe 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -631,7 +631,7 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { .ctrl() .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); - let startup_delay = ((crystal_hz / 1000 + delay_multiplier) + 128) / 256; + let startup_delay = (((crystal_hz / 1000) + 128) * delay_multiplier) / 256; pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); pac::XOSC.ctrl().write(|w| { w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ); From 83a976cf4bd963f39bd0d3e4ea56f4b35bd82031 Mon Sep 17 00:00:00 2001 From: Michael van Niekerk Date: Wed, 30 Aug 2023 21:59:41 +0200 Subject: [PATCH 085/233] RP2040: Fixes as per PR --- embassy-rp/src/clocks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 2c41befe..22066546 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -631,7 +631,7 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { .ctrl() .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); - let startup_delay = (((crystal_hz / 1000) + 128) * delay_multiplier) / 256; + let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256; pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); pac::XOSC.ctrl().write(|w| { w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ); From 37694473824952574e0bd9332b8ef38d77a9bf55 Mon Sep 17 00:00:00 2001 From: kalkyl Date: Wed, 30 Aug 2023 23:20:38 +0200 Subject: [PATCH 086/233] rp: Fix write size in embassy-boot example app --- examples/boot/application/rp/src/bin/a.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs index 15fdaca8..a4602a7e 100644 --- a/examples/boot/application/rp/src/bin/a.rs +++ b/examples/boot/application/rp/src/bin/a.rs @@ -38,7 +38,7 @@ async fn main(_s: Spawner) { let flash = Mutex::new(RefCell::new(flash)); let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); - let mut aligned = AlignedBuffer([0; 4]); + let mut aligned = AlignedBuffer([0; 1]); let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0); Timer::after(Duration::from_secs(5)).await; From c10fb7c1c4ca40749494f4873c2144906c2f1a17 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 30 Aug 2023 18:10:26 -0500 Subject: [PATCH 087/233] stm32: implement qei --- embassy-stm32/src/timer/mod.rs | 1 + embassy-stm32/src/timer/qei.rs | 216 +++++++++++++-------------------- 2 files changed, 86 insertions(+), 131 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 4ffb2a28..6036a456 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,4 +1,5 @@ pub mod complementary_pwm; +pub mod qei; pub mod simple_pwm; use stm32_metapac::timer::vals; diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index fa881472..c0f9288a 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -1,142 +1,96 @@ -//! # Quadrature Encoder Interface -use crate::{ - gpio::PushPull, - pac, rcc, - timer::{CPin, General}, -}; +use core::marker::PhantomData; -pub trait QeiExt: Sized + Instance { - fn qei( - self, - pins: ( - impl Into<>::Ch>, - impl Into<>::Ch>, - ), - ) -> Qei; +use embassy_hal_internal::{into_ref, PeripheralRef}; + +use super::*; +use crate::gpio::sealed::AFType; +use crate::gpio::AnyPin; +use crate::Peripheral; + +pub enum Direction { + Upcounting, + Downcounting, } -impl QeiExt for TIM { - fn qei( - self, - pins: ( - impl Into<>::Ch>, - impl Into<>::Ch>, - ), - ) -> Qei { - Qei::new(self, pins) - } +pub struct Ch1; +pub struct Ch2; + +pub struct QeiPin<'d, Perip, Channel> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(Perip, Channel)>, } -/// Hardware quadrature encoder interface peripheral -pub struct Qei { - tim: TIM, - pins: ( - >::Ch, - >::Ch, - ), -} - -impl Qei { - /// Configures a TIM peripheral as a quadrature encoder interface input - pub fn new( - mut tim: TIM, - pins: ( - impl Into<>::Ch>, - impl Into<>::Ch>, - ), - ) -> Self { - // Enable and reset clock. - unsafe { - TIM::enable_unchecked(); - TIM::reset_unchecked(); - } - - let pins = (pins.0.into(), pins.1.into()); - tim.setup_qei(); - - Qei { tim, pins } - } - - /// Releases the TIM peripheral and QEI pins - #[allow(clippy::type_complexity)] - pub fn release( - self, - ) -> ( - TIM, - ( - >::Ch, - >::Ch, - ), - ) { - (self.tim, self.pins) - } - - /// Set current count number - pub fn set_count(&mut self, value: TIM::Width) -> &mut Self { - self.tim.write_count(value); - self - } -} - -impl embedded_hal::Qei for Qei { - type Count = TIM::Width; - - fn count(&self) -> Self::Count { - self.tim.read_count() - } - - fn direction(&self) -> embedded_hal::Direction { - if self.tim.read_direction() { - embedded_hal::Direction::Upcounting - } else { - embedded_hal::Direction::Downcounting - } - } -} - -pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + General + CPin<0> + CPin<1> { - fn setup_qei(&mut self); - - fn read_direction(&self) -> bool; -} - -macro_rules! hal { - ($TIM:ty) => { - impl Instance for $TIM { - fn setup_qei(&mut self) { - // Configure TxC1 and TxC2 as captures - #[cfg(not(feature = "gpio-f410"))] - self.ccmr1_input().write(|w| w.cc1s().ti1().cc2s().ti2()); - #[cfg(feature = "gpio-f410")] - self.ccmr1_input() - .write(|w| unsafe { w.cc1s().bits(0b01).cc2s().bits(0b01) }); - // enable and configure to capture on rising edge - self.ccer.write(|w| { - w.cc1e().set_bit().cc1p().clear_bit(); - w.cc2e().set_bit().cc2p().clear_bit() +macro_rules! channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident) => { + impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af(pin.af_num(), AFType::Input); + #[cfg(gpio_v2)] + pin.set_speed(crate::gpio::Speed::VeryHigh); }); - self.smcr.write(|w| w.sms().encoder_mode_3()); - self.set_auto_reload(<$TIM as General>::Width::MAX as u32) - .unwrap(); - self.cr1.write(|w| w.cen().set_bit()); - } - - fn read_direction(&self) -> bool { - self.cr1.read().dir().bit_is_clear() + QeiPin { + _pin: pin.map_into(), + phantom: PhantomData, + } } } }; } -#[cfg(feature = "tim1")] -hal! { pac::TIM1 } -#[cfg(feature = "tim2")] -hal! { pac::TIM2 } -#[cfg(feature = "tim3")] -hal! { pac::TIM3 } -#[cfg(feature = "tim4")] -hal! { pac::TIM4 } -#[cfg(feature = "tim5")] -hal! { pac::TIM5 } -#[cfg(feature = "tim8")] -hal! { pac::TIM8 } +channel_impl!(new_ch1, Ch1, Channel1Pin); +channel_impl!(new_ch2, Ch2, Channel2Pin); + +pub struct SimplePwm<'d, T> { + _inner: PeripheralRef<'d, T>, +} + +impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { + pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { + Self::new_inner(tim) + } + + fn new_inner(tim: impl Peripheral

+ 'd) -> Self { + into_ref!(tim); + + T::enable(); + ::reset(); + + // Configure TxC1 and TxC2 as captures + T::regs_gp16().ccmr_input(0).modify(|w| { + w.set_ccs(0, vals::CcmrInputCcs::TI4); + w.set_ccs(1, vals::CcmrInputCcs::TI4); + }); + + // enable and configure to capture on rising edge + T::regs_gp16().ccer().modify(|w| { + w.set_cce(0, true); + w.set_cce(1, true); + + w.set_ccp(0, false); + w.set_ccp(1, false); + }); + + T::regs_gp16().smcr().modify(|w| { + w.set_sms(vals::Sms::ENCODER_MODE_3); + }); + + T::regs_gp16().arr().modify(|w| w.set_arr(u16::MAX)); + T::regs_gp16().cr1().modify(|w| w.set_cen(true)); + + Self { _inner: tim } + } + + pub fn read_direction(&self) -> Direction { + match T::regs_gp16().cr1().read().dir() { + vals::Dir::DOWN => Direction::Downcounting, + vals::Dir::UP => Direction::Upcounting, + } + } + + pub fn count(&self) -> u16 { + T::regs_gp16().cnt().read().cnt() + } +} From b74645e25960c6d4160b5a150d2e6bf239cef9c8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 1 Sep 2023 00:21:01 +0200 Subject: [PATCH 088/233] Delete .github/bors.toml --- .github/bors.toml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .github/bors.toml diff --git a/.github/bors.toml b/.github/bors.toml deleted file mode 100644 index 1ecc9d8d..00000000 --- a/.github/bors.toml +++ /dev/null @@ -1,4 +0,0 @@ -status = [ - "all", -] -delete_merged_branches = true From 1d87ec9cc36442542814d6dca7ae8e71068820e1 Mon Sep 17 00:00:00 2001 From: xoviat <49173759+xoviat@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:30:27 -0500 Subject: [PATCH 089/233] stm32/qei: fix struct naming (#1852) Co-authored-by: xoviat --- embassy-stm32/src/timer/qei.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index c0f9288a..15f2c3a7 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -43,11 +43,11 @@ macro_rules! channel_impl { channel_impl!(new_ch1, Ch1, Channel1Pin); channel_impl!(new_ch2, Ch2, Channel2Pin); -pub struct SimplePwm<'d, T> { +pub struct Qei<'d, T> { _inner: PeripheralRef<'d, T>, } -impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { +impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) } From 0c66636d003979c3aecff36c9e03e87f34147a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 2 Sep 2023 07:44:10 +0200 Subject: [PATCH 090/233] Use fmt::unwrap --- embassy-net/src/device.rs | 4 ++-- embassy-net/src/lib.rs | 14 +++++++------- embassy-net/src/tcp.rs | 4 ++-- embassy-sync/src/channel.rs | 2 +- embassy-sync/src/mutex.rs | 2 +- embassy-time/src/instant.rs | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index d29ab897..8c2b7d31 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -22,13 +22,13 @@ where fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { self.inner - .receive(self.cx.as_deref_mut().unwrap()) + .receive(unwrap!(self.cx.as_deref_mut())) .map(|(rx, tx)| (RxTokenAdapter(rx), TxTokenAdapter(tx))) } /// Construct a transmit token. fn transmit(&mut self, _timestamp: Instant) -> Option> { - self.inner.transmit(self.cx.as_deref_mut().unwrap()).map(TxTokenAdapter) + self.inner.transmit(unwrap!(self.cx.as_deref_mut())).map(TxTokenAdapter) } /// Get a description of device capabilities. diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 3a385fad..c2575267 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -616,7 +616,7 @@ impl Inner { } // Configure it - let socket = _s.sockets.get_mut::(self.dhcp_socket.unwrap()); + let socket = _s.sockets.get_mut::(unwrap!(self.dhcp_socket)); socket.set_ignore_naks(c.ignore_naks); socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp)); socket.set_ports(c.server_port, c.client_port); @@ -656,12 +656,12 @@ impl Inner { debug!(" IP address: {:?}", config.address); debug!(" Default gateway: {:?}", config.gateway); - addrs.push(IpCidr::Ipv4(config.address)).unwrap(); + unwrap!(addrs.push(IpCidr::Ipv4(config.address)).ok()); gateway_v4 = config.gateway.into(); #[cfg(feature = "dns")] for s in &config.dns_servers { debug!(" DNS server: {:?}", s); - dns_servers.push(s.clone().into()).unwrap(); + unwrap!(dns_servers.push(s.clone().into()).ok()); } } else { info!("IPv4: DOWN"); @@ -673,12 +673,12 @@ impl Inner { debug!(" IP address: {:?}", config.address); debug!(" Default gateway: {:?}", config.gateway); - addrs.push(IpCidr::Ipv6(config.address)).unwrap(); + unwrap!(addrs.push(IpCidr::Ipv6(config.address)).ok()); gateway_v6 = config.gateway.into(); #[cfg(feature = "dns")] for s in &config.dns_servers { debug!(" DNS server: {:?}", s); - dns_servers.push(s.clone().into()).unwrap(); + unwrap!(dns_servers.push(s.clone().into()).ok()); } } else { info!("IPv6: DOWN"); @@ -690,13 +690,13 @@ impl Inner { // Apply gateways #[cfg(feature = "proto-ipv4")] if let Some(gateway) = gateway_v4 { - s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap(); + unwrap!(s.iface.routes_mut().add_default_ipv4_route(gateway)); } else { s.iface.routes_mut().remove_default_ipv4_route(); } #[cfg(feature = "proto-ipv6")] if let Some(gateway) = gateway_v6 { - s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap(); + unwrap!(s.iface.routes_mut().add_default_ipv6_route(gateway)); } else { s.iface.routes_mut().remove_default_ipv6_route(); } diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index c92ad2d2..a12fd382 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -440,7 +440,7 @@ impl<'d> TcpIo<'d> { Poll::Ready(Err(Error::ConnectionReset)) } } else { - Poll::Ready(match s.send(f.take().unwrap()) { + Poll::Ready(match s.send(unwrap!(f.take())) { // Connection reset. TODO: this can also be timeouts etc, investigate. Err(tcp::SendError::InvalidState) => Err(Error::ConnectionReset), Ok(r) => Ok(r), @@ -468,7 +468,7 @@ impl<'d> TcpIo<'d> { Poll::Ready(Err(Error::ConnectionReset)) } } else { - Poll::Ready(match s.recv(f.take().unwrap()) { + Poll::Ready(match s.recv(unwrap!(f.take())) { // Connection reset. TODO: this can also be timeouts etc, investigate. Err(tcp::RecvError::Finished) | Err(tcp::RecvError::InvalidState) => { Err(Error::ConnectionReset) diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 62ea1307..a512e0c4 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -471,7 +471,7 @@ where } fn lock(&self, f: impl FnOnce(&mut ChannelState) -> R) -> R { - self.inner.lock(|rc| f(&mut *rc.borrow_mut())) + self.inner.lock(|rc| f(&mut *unwrap!(rc.try_borrow_mut()))) } fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result { diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs index fcf056d3..72459d66 100644 --- a/embassy-sync/src/mutex.rs +++ b/embassy-sync/src/mutex.rs @@ -149,7 +149,7 @@ where { fn drop(&mut self) { self.mutex.state.lock(|s| { - let mut s = s.borrow_mut(); + let mut s = unwrap!(s.try_borrow_mut()); s.locked = false; s.waker.wake(); }) diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs index 44f226f6..5571cdd1 100644 --- a/embassy-time/src/instant.rs +++ b/embassy-time/src/instant.rs @@ -71,7 +71,7 @@ impl Instant { /// Panics on over/underflow. pub fn duration_since(&self, earlier: Instant) -> Duration { Duration { - ticks: self.ticks.checked_sub(earlier.ticks).unwrap(), + ticks: unwrap!(self.ticks.checked_sub(earlier.ticks)), } } From 360286e67c355d23a355f83bbb6586b3fa3b3a7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 2 Sep 2023 08:50:03 +0200 Subject: [PATCH 091/233] Fix bootloader application examples --- examples/boot/application/rp/Cargo.toml | 1 + examples/boot/application/stm32f3/Cargo.toml | 3 ++- examples/boot/application/stm32f7/Cargo.toml | 3 ++- examples/boot/application/stm32h7/Cargo.toml | 1 + examples/boot/application/stm32l0/Cargo.toml | 3 ++- examples/boot/application/stm32l1/Cargo.toml | 3 ++- examples/boot/application/stm32l4/Cargo.toml | 3 ++- examples/boot/application/stm32wl/Cargo.toml | 3 ++- examples/boot/bootloader/nrf/Cargo.toml | 2 +- examples/boot/bootloader/stm32/Cargo.toml | 2 +- 10 files changed, 16 insertions(+), 8 deletions(-) diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index be85f443..23cce959 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -27,6 +27,7 @@ default = ["panic-reset"] debug = [ "embassy-rp/defmt", "embassy-boot-rp/defmt", + "embassy-sync/defmt", "panic-probe" ] skip-include = [] diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index ea878933..31ea46d9 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] } @@ -25,5 +25,6 @@ defmt = [ "dep:defmt", "embassy-stm32/defmt", "embassy-boot-stm32/defmt", + "embassy-sync/defmt", ] skip-include = [] diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index b39bc292..46f709cb 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] } @@ -26,5 +26,6 @@ defmt = [ "dep:defmt", "embassy-stm32/defmt", "embassy-boot-stm32/defmt", + "embassy-sync/defmt", ] skip-include = [] diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index f015b2ca..49743b9c 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -26,5 +26,6 @@ defmt = [ "dep:defmt", "embassy-stm32/defmt", "embassy-boot-stm32/defmt", + "embassy-sync/defmt", ] skip-include = [] diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index f221e1de..acc9e9e3 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } @@ -25,5 +25,6 @@ defmt = [ "dep:defmt", "embassy-stm32/defmt", "embassy-boot-stm32/defmt", + "embassy-sync/defmt", ] skip-include = [] diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 2896afa3..f2ff6ae0 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] } @@ -25,5 +25,6 @@ defmt = [ "dep:defmt", "embassy-stm32/defmt", "embassy-boot-stm32/defmt", + "embassy-sync/defmt", ] skip-include = [] diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 50d8967a..167f8f9e 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] } @@ -25,5 +25,6 @@ defmt = [ "dep:defmt", "embassy-stm32/defmt", "embassy-boot-stm32/defmt", + "embassy-sync/defmt", ] skip-include = [] diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 27541439..066150dd 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] } @@ -25,5 +25,6 @@ defmt = [ "dep:defmt", "embassy-stm32/defmt", "embassy-boot-stm32/defmt", + "embassy-sync/defmt", ] skip-include = [] diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index 40656f35..42391778 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -25,7 +25,7 @@ defmt = [ softdevice = [ "embassy-boot-nrf/softdevice", ] -debug = ["defmt-rtt"] +debug = ["defmt-rtt", "defmt"] [profile.dev] debug = 2 diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml index 6436f2fe..9175768d 100644 --- a/examples/boot/bootloader/stm32/Cargo.toml +++ b/examples/boot/bootloader/stm32/Cargo.toml @@ -24,7 +24,7 @@ defmt = [ "embassy-boot-stm32/defmt", "embassy-stm32/defmt", ] -debug = ["defmt-rtt"] +debug = ["defmt-rtt", "defmt"] [profile.dev] debug = 2 From 9dd58660c31371f8bdfd81f2b16fb117bf3ab647 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 3 Sep 2023 01:36:03 +0200 Subject: [PATCH 092/233] Add teleprobe cache. --- .github/ci/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ci/build.sh b/.github/ci/build.sh index 30ca1e6f..36bf7e7d 100755 --- a/.github/ci/build.sh +++ b/.github/ci/build.sh @@ -11,6 +11,7 @@ if [ -f /ci/secrets/teleprobe-token.txt ]; then echo Got teleprobe token! export TELEPROBE_HOST=https://teleprobe.embassy.dev export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt) + export TELEPROBE_CACHE=/ci/cache/teleprobe_cache.json fi hashtime restore /ci/cache/filetime.json || true From 2e6f4237f2410aa18c9866a5a1a5ed1f3bec8a4e Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 3 Sep 2023 11:40:34 -0500 Subject: [PATCH 093/233] stm32: cleanup psc design --- embassy-stm32/src/hrtim/traits.rs | 49 ++++++++++--------------------- embassy-stm32/src/rtc/v2.rs | 31 ++++++------------- 2 files changed, 24 insertions(+), 56 deletions(-) diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 158a6886..09510959 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -1,31 +1,17 @@ use crate::rcc::sealed::RccPeripheral; use crate::time::Hertz; +#[repr(u8)] #[derive(Clone, Copy)] pub(crate) enum Prescaler { - Div1, - Div2, - Div4, - Div8, - Div16, - Div32, - Div64, - Div128, -} - -impl From for u32 { - fn from(val: Prescaler) -> Self { - match val { - Prescaler::Div1 => 1, - Prescaler::Div2 => 2, - Prescaler::Div4 => 4, - Prescaler::Div8 => 8, - Prescaler::Div16 => 16, - Prescaler::Div32 => 32, - Prescaler::Div64 => 64, - Prescaler::Div128 => 128, - } - } + Div1 = 1, + Div2 = 2, + Div4 = 4, + Div8 = 8, + Div16 = 16, + Div32 = 32, + Div64 = 64, + Div128 = 128, } impl From for u8 { @@ -72,7 +58,7 @@ impl Prescaler { Prescaler::Div128, ] .iter() - .skip_while(|psc| >::into(**psc) <= val) + .skip_while(|psc| **psc as u32 <= val) .next() .unwrap() } @@ -80,7 +66,7 @@ impl Prescaler { pub fn compute_min_low_res(val: u32) -> Self { *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128] .iter() - .skip_while(|psc| >::into(**psc) <= val) + .skip_while(|psc| **psc as u32 <= val) .next() .unwrap() } @@ -126,8 +112,7 @@ foreach_interrupt! { Prescaler::compute_min_low_res(psc_min) }; - let psc_val: u32 = psc.into(); - let timer_f = 32 * (timer_f / psc_val); + let timer_f = 32 * (timer_f / psc as u32); let per: u16 = (timer_f / f) as u16; let regs = Self::regs(); @@ -148,8 +133,7 @@ foreach_interrupt! { Prescaler::compute_min_low_res(psc_min) }; - let psc_val: u32 = psc.into(); - let timer_f = 32 * (timer_f / psc_val); + let timer_f = 32 * (timer_f / psc as u32); let per: u16 = (timer_f / f) as u16; let regs = Self::regs(); @@ -163,20 +147,17 @@ foreach_interrupt! { let regs = Self::regs(); let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); - let psc_val: u32 = channel_psc.into(); - // The dead-time base clock runs 4 times slower than the hrtim base clock // u9::MAX = 511 - let psc_min = (psc_val * dead_time as u32) / (4 * 511); + let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); let psc = if Self::regs().isr().read().dllrdy() { Prescaler::compute_min_high_res(psc_min) } else { Prescaler::compute_min_low_res(psc_min) }; - let dt_psc_val: u32 = psc.into(); - let dt_val = (dt_psc_val * dead_time as u32) / (4 * psc_val); + let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); regs.tim(channel).dt().modify(|w| { w.set_dtprsc(psc.into()); diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 482b6e75..62d8d4f9 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -6,12 +6,13 @@ use crate::peripherals::RTC; use crate::rtc::sealed::Instance; #[allow(dead_code)] +#[repr(u8)] #[derive(Clone, Copy, Debug)] pub(crate) enum WakeupPrescaler { - Div2, - Div4, - Div8, - Div16, + Div2 = 2, + Div4 = 4, + Div8 = 8, + Div16 = 16, } #[cfg(any(stm32wb, stm32f4))] @@ -43,17 +44,6 @@ impl From for WakeupPrescaler { } } -impl From for u32 { - fn from(val: WakeupPrescaler) -> Self { - match val { - WakeupPrescaler::Div2 => 2, - WakeupPrescaler::Div4 => 4, - WakeupPrescaler::Div8 => 8, - WakeupPrescaler::Div16 => 16, - } - } -} - #[allow(dead_code)] impl WakeupPrescaler { pub fn compute_min(val: u32) -> Self { @@ -64,7 +54,7 @@ impl WakeupPrescaler { WakeupPrescaler::Div16, ] .iter() - .skip_while(|psc| >::into(**psc) <= val) + .skip_while(|psc| **psc as u32 <= val) .next() .unwrap_or(&WakeupPrescaler::Div16) } @@ -85,7 +75,7 @@ impl super::Rtc { let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); // adjust the rtc ticks to the prescaler and subtract one rtc tick - let rtc_ticks = rtc_ticks / (>::into(prescaler) as u64); + let rtc_ticks = rtc_ticks / prescaler as u64; let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { u16::MAX - 1 } else { @@ -106,11 +96,8 @@ impl super::Rtc { trace!( "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", - Duration::from_ticks( - rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, - ) - .as_millis(), - >::into(prescaler), + Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(), + prescaler as u32, rtc_ticks, self.instant(), ); From c5732ce2857ce4028a2e03abeb65254200473e5a Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 3 Sep 2023 11:48:41 -0500 Subject: [PATCH 094/233] ci: remove failing tests --- ci.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ci.sh b/ci.sh index db00c406..4112144b 100755 --- a/ci.sh +++ b/ci.sh @@ -180,4 +180,9 @@ if [[ -z "${TELEPROBE_TOKEN-}" ]]; then exit fi +rm out/tests/rpi-pico/ethernet_w5100s_perf +rm out/tests/nrf52840-dk/ethernet_enc28j60_perf +rm out/tests/nrf52840-dk/wifi_esp_hosted_perf +rm out/tests/rpi-pico/cyw43-perf + teleprobe client run -r out/tests From 3466c9cfa93cbcd796cd9125e4035e35546c3e9c Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 13:47:02 -0500 Subject: [PATCH 095/233] stm32: refcount peripheral enable/disable --- embassy-stm32/build.rs | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 6c364f7b..2b66e7da 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -308,6 +308,9 @@ fn main() { // ======== // Generate RccPeripheral impls + let refcounted_peripherals = HashSet::from(["ADC", "USART", "SPI", "I2C"]); + let mut refcount_statics = HashSet::new(); + for p in METADATA.peripherals { // generating RccPeripheral impl for H7 ADC3 would result in bad frequency if !singletons.contains(&p.name.to_string()) @@ -344,11 +347,40 @@ fn main() { TokenStream::new() }; + let ptype = p + .name + .replace(&['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'][..], ""); let pname = format_ident!("{}", p.name); let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); + let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype.trim_start_matches("LP")) { + let refcount_static = + format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); + + refcount_statics.insert(refcount_static.clone()); + + ( + quote! { + use atomic_polyfill::Ordering; + + if refcount_statics::#refcount_static.fetch_add(1, Ordering::SeqCst) > 0 { + return; + } + }, + quote! { + use atomic_polyfill::Ordering; + + if refcount_statics::#refcount_static.fetch_sub(1, Ordering::SeqCst) > 1 { + return; + } + }, + ) + } else { + (TokenStream::new(), TokenStream::new()) + }; + g.extend(quote! { impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { fn frequency() -> crate::time::Hertz { @@ -356,6 +388,7 @@ fn main() { } fn enable() { critical_section::with(|_| { + #before_enable #[cfg(feature = "low-power")] crate::rcc::clock_refcount_add(); crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); @@ -364,6 +397,7 @@ fn main() { } fn disable() { critical_section::with(|_| { + #before_disable crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); #[cfg(feature = "low-power")] crate::rcc::clock_refcount_sub(); @@ -379,6 +413,21 @@ fn main() { } } + let mut refcount_mod = TokenStream::new(); + for refcount_static in refcount_statics { + refcount_mod.extend(quote! { + pub(crate) static #refcount_static: AtomicU8 = AtomicU8::new(0); + }); + } + + g.extend(quote! { + mod refcount_statics { + use atomic_polyfill::AtomicU8; + + #refcount_mod + } + }); + // ======== // Generate fns to enable GPIO, DMA in RCC From a2656f402b1c59461cec5f5dc685b2692119b996 Mon Sep 17 00:00:00 2001 From: Ruben De Smet Date: Fri, 11 Aug 2023 12:04:30 +0200 Subject: [PATCH 096/233] Move embassy-net-driver-channel::zerocopy_channel to embassy_sync::zero_copy_channel --- embassy-net-driver-channel/src/lib.rs | 237 ++------------------------ embassy-sync/src/lib.rs | 1 + embassy-sync/src/zero_copy_channel.rs | 209 +++++++++++++++++++++++ 3 files changed, 223 insertions(+), 224 deletions(-) create mode 100644 embassy-sync/src/zero_copy_channel.rs diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index f2aa6b25..e8cd66f8 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -14,6 +14,7 @@ use embassy_net_driver::{Capabilities, LinkState, Medium}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_sync::waitqueue::WakerRegistration; +use embassy_sync::zero_copy_channel; pub struct State { rx: [PacketBuf; N_RX], @@ -34,8 +35,8 @@ impl State { - rx: zerocopy_channel::Channel<'d, NoopRawMutex, PacketBuf>, - tx: zerocopy_channel::Channel<'d, NoopRawMutex, PacketBuf>, + rx: zero_copy_channel::Channel<'d, NoopRawMutex, PacketBuf>, + tx: zero_copy_channel::Channel<'d, NoopRawMutex, PacketBuf>, shared: Mutex>, } @@ -47,8 +48,8 @@ struct Shared { } pub struct Runner<'d, const MTU: usize> { - tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, - rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf>, + tx_chan: zero_copy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, + rx_chan: zero_copy_channel::Sender<'d, NoopRawMutex, PacketBuf>, shared: &'d Mutex>, } @@ -58,11 +59,11 @@ pub struct StateRunner<'d> { } pub struct RxRunner<'d, const MTU: usize> { - rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf>, + rx_chan: zero_copy_channel::Sender<'d, NoopRawMutex, PacketBuf>, } pub struct TxRunner<'d, const MTU: usize> { - tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, + tx_chan: zero_copy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, } impl<'d, const MTU: usize> Runner<'d, MTU> { @@ -243,8 +244,8 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( let state_uninit: *mut MaybeUninit> = (&mut state.inner as *mut MaybeUninit>).cast(); let state = unsafe { &mut *state_uninit }.write(StateInner { - rx: zerocopy_channel::Channel::new(&mut state.rx[..]), - tx: zerocopy_channel::Channel::new(&mut state.tx[..]), + rx: zero_copy_channel::Channel::new(&mut state.rx[..]), + tx: zero_copy_channel::Channel::new(&mut state.tx[..]), shared: Mutex::new(RefCell::new(Shared { link_state: LinkState::Down, hardware_address, @@ -282,8 +283,8 @@ impl PacketBuf { } pub struct Device<'d, const MTU: usize> { - rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, - tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf>, + rx: zero_copy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, + tx: zero_copy_channel::Sender<'d, NoopRawMutex, PacketBuf>, shared: &'d Mutex>, caps: Capabilities, } @@ -328,7 +329,7 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> { } pub struct RxToken<'a, const MTU: usize> { - rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf>, + rx: zero_copy_channel::Receiver<'a, NoopRawMutex, PacketBuf>, } impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> { @@ -345,7 +346,7 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> { } pub struct TxToken<'a, const MTU: usize> { - tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf>, + tx: zero_copy_channel::Sender<'a, NoopRawMutex, PacketBuf>, } impl<'a, const MTU: usize> embassy_net_driver::TxToken for TxToken<'a, MTU> { @@ -361,215 +362,3 @@ impl<'a, const MTU: usize> embassy_net_driver::TxToken for TxToken<'a, MTU> { r } } - -mod zerocopy_channel { - use core::cell::RefCell; - use core::future::poll_fn; - use core::marker::PhantomData; - use core::task::{Context, Poll}; - - use embassy_sync::blocking_mutex::raw::RawMutex; - use embassy_sync::blocking_mutex::Mutex; - use embassy_sync::waitqueue::WakerRegistration; - - pub struct Channel<'a, M: RawMutex, T> { - buf: *mut T, - phantom: PhantomData<&'a mut T>, - state: Mutex>, - } - - impl<'a, M: RawMutex, T> Channel<'a, M, T> { - pub fn new(buf: &'a mut [T]) -> Self { - let len = buf.len(); - assert!(len != 0); - - Self { - buf: buf.as_mut_ptr(), - phantom: PhantomData, - state: Mutex::new(RefCell::new(State { - len, - front: 0, - back: 0, - full: false, - send_waker: WakerRegistration::new(), - recv_waker: WakerRegistration::new(), - })), - } - } - - pub fn split(&mut self) -> (Sender<'_, M, T>, Receiver<'_, M, T>) { - (Sender { channel: self }, Receiver { channel: self }) - } - } - - pub struct Sender<'a, M: RawMutex, T> { - channel: &'a Channel<'a, M, T>, - } - - impl<'a, M: RawMutex, T> Sender<'a, M, T> { - pub fn borrow(&mut self) -> Sender<'_, M, T> { - Sender { channel: self.channel } - } - - pub fn try_send(&mut self) -> Option<&mut T> { - self.channel.state.lock(|s| { - let s = &mut *s.borrow_mut(); - match s.push_index() { - Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }), - None => None, - } - }) - } - - pub fn poll_send(&mut self, cx: &mut Context) -> Poll<&mut T> { - self.channel.state.lock(|s| { - let s = &mut *s.borrow_mut(); - match s.push_index() { - Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }), - None => { - s.recv_waker.register(cx.waker()); - Poll::Pending - } - } - }) - } - - pub async fn send(&mut self) -> &mut T { - let i = poll_fn(|cx| { - self.channel.state.lock(|s| { - let s = &mut *s.borrow_mut(); - match s.push_index() { - Some(i) => Poll::Ready(i), - None => { - s.recv_waker.register(cx.waker()); - Poll::Pending - } - } - }) - }) - .await; - unsafe { &mut *self.channel.buf.add(i) } - } - - pub fn send_done(&mut self) { - self.channel.state.lock(|s| s.borrow_mut().push_done()) - } - } - pub struct Receiver<'a, M: RawMutex, T> { - channel: &'a Channel<'a, M, T>, - } - - impl<'a, M: RawMutex, T> Receiver<'a, M, T> { - pub fn borrow(&mut self) -> Receiver<'_, M, T> { - Receiver { channel: self.channel } - } - - pub fn try_recv(&mut self) -> Option<&mut T> { - self.channel.state.lock(|s| { - let s = &mut *s.borrow_mut(); - match s.pop_index() { - Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }), - None => None, - } - }) - } - - pub fn poll_recv(&mut self, cx: &mut Context) -> Poll<&mut T> { - self.channel.state.lock(|s| { - let s = &mut *s.borrow_mut(); - match s.pop_index() { - Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }), - None => { - s.send_waker.register(cx.waker()); - Poll::Pending - } - } - }) - } - - pub async fn recv(&mut self) -> &mut T { - let i = poll_fn(|cx| { - self.channel.state.lock(|s| { - let s = &mut *s.borrow_mut(); - match s.pop_index() { - Some(i) => Poll::Ready(i), - None => { - s.send_waker.register(cx.waker()); - Poll::Pending - } - } - }) - }) - .await; - unsafe { &mut *self.channel.buf.add(i) } - } - - pub fn recv_done(&mut self) { - self.channel.state.lock(|s| s.borrow_mut().pop_done()) - } - } - - struct State { - len: usize, - - /// Front index. Always 0..=(N-1) - front: usize, - /// Back index. Always 0..=(N-1). - back: usize, - - /// Used to distinguish "empty" and "full" cases when `front == back`. - /// May only be `true` if `front == back`, always `false` otherwise. - full: bool, - - send_waker: WakerRegistration, - recv_waker: WakerRegistration, - } - - impl State { - fn increment(&self, i: usize) -> usize { - if i + 1 == self.len { - 0 - } else { - i + 1 - } - } - - fn is_full(&self) -> bool { - self.full - } - - fn is_empty(&self) -> bool { - self.front == self.back && !self.full - } - - fn push_index(&mut self) -> Option { - match self.is_full() { - true => None, - false => Some(self.back), - } - } - - fn push_done(&mut self) { - assert!(!self.is_full()); - self.back = self.increment(self.back); - if self.back == self.front { - self.full = true; - } - self.send_waker.wake(); - } - - fn pop_index(&mut self) -> Option { - match self.is_empty() { - true => None, - false => Some(self.front), - } - } - - fn pop_done(&mut self) { - assert!(!self.is_empty()); - self.front = self.increment(self.front); - self.full = false; - self.recv_waker.wake(); - } - } -} diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index 53d95d08..48a7b13f 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -17,3 +17,4 @@ pub mod pipe; pub mod pubsub; pub mod signal; pub mod waitqueue; +pub mod zero_copy_channel; diff --git a/embassy-sync/src/zero_copy_channel.rs b/embassy-sync/src/zero_copy_channel.rs new file mode 100644 index 00000000..3701ccf1 --- /dev/null +++ b/embassy-sync/src/zero_copy_channel.rs @@ -0,0 +1,209 @@ +use core::cell::RefCell; +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::{Context, Poll}; + +use crate::blocking_mutex::raw::RawMutex; +use crate::blocking_mutex::Mutex; +use crate::waitqueue::WakerRegistration; + +pub struct Channel<'a, M: RawMutex, T> { + buf: *mut T, + phantom: PhantomData<&'a mut T>, + state: Mutex>, +} + +impl<'a, M: RawMutex, T> Channel<'a, M, T> { + pub fn new(buf: &'a mut [T]) -> Self { + let len = buf.len(); + assert!(len != 0); + + Self { + buf: buf.as_mut_ptr(), + phantom: PhantomData, + state: Mutex::new(RefCell::new(State { + len, + front: 0, + back: 0, + full: false, + send_waker: WakerRegistration::new(), + recv_waker: WakerRegistration::new(), + })), + } + } + + pub fn split(&mut self) -> (Sender<'_, M, T>, Receiver<'_, M, T>) { + (Sender { channel: self }, Receiver { channel: self }) + } +} + +pub struct Sender<'a, M: RawMutex, T> { + channel: &'a Channel<'a, M, T>, +} + +impl<'a, M: RawMutex, T> Sender<'a, M, T> { + pub fn borrow(&mut self) -> Sender<'_, M, T> { + Sender { channel: self.channel } + } + + pub fn try_send(&mut self) -> Option<&mut T> { + self.channel.state.lock(|s| { + let s = &mut *s.borrow_mut(); + match s.push_index() { + Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }), + None => None, + } + }) + } + + pub fn poll_send(&mut self, cx: &mut Context) -> Poll<&mut T> { + self.channel.state.lock(|s| { + let s = &mut *s.borrow_mut(); + match s.push_index() { + Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }), + None => { + s.recv_waker.register(cx.waker()); + Poll::Pending + } + } + }) + } + + pub async fn send(&mut self) -> &mut T { + let i = poll_fn(|cx| { + self.channel.state.lock(|s| { + let s = &mut *s.borrow_mut(); + match s.push_index() { + Some(i) => Poll::Ready(i), + None => { + s.recv_waker.register(cx.waker()); + Poll::Pending + } + } + }) + }) + .await; + unsafe { &mut *self.channel.buf.add(i) } + } + + pub fn send_done(&mut self) { + self.channel.state.lock(|s| s.borrow_mut().push_done()) + } +} +pub struct Receiver<'a, M: RawMutex, T> { + channel: &'a Channel<'a, M, T>, +} + +impl<'a, M: RawMutex, T> Receiver<'a, M, T> { + pub fn borrow(&mut self) -> Receiver<'_, M, T> { + Receiver { channel: self.channel } + } + + pub fn try_recv(&mut self) -> Option<&mut T> { + self.channel.state.lock(|s| { + let s = &mut *s.borrow_mut(); + match s.pop_index() { + Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }), + None => None, + } + }) + } + + pub fn poll_recv(&mut self, cx: &mut Context) -> Poll<&mut T> { + self.channel.state.lock(|s| { + let s = &mut *s.borrow_mut(); + match s.pop_index() { + Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }), + None => { + s.send_waker.register(cx.waker()); + Poll::Pending + } + } + }) + } + + pub async fn recv(&mut self) -> &mut T { + let i = poll_fn(|cx| { + self.channel.state.lock(|s| { + let s = &mut *s.borrow_mut(); + match s.pop_index() { + Some(i) => Poll::Ready(i), + None => { + s.send_waker.register(cx.waker()); + Poll::Pending + } + } + }) + }) + .await; + unsafe { &mut *self.channel.buf.add(i) } + } + + pub fn recv_done(&mut self) { + self.channel.state.lock(|s| s.borrow_mut().pop_done()) + } +} + +struct State { + len: usize, + + /// Front index. Always 0..=(N-1) + front: usize, + /// Back index. Always 0..=(N-1). + back: usize, + + /// Used to distinguish "empty" and "full" cases when `front == back`. + /// May only be `true` if `front == back`, always `false` otherwise. + full: bool, + + send_waker: WakerRegistration, + recv_waker: WakerRegistration, +} + +impl State { + fn increment(&self, i: usize) -> usize { + if i + 1 == self.len { + 0 + } else { + i + 1 + } + } + + fn is_full(&self) -> bool { + self.full + } + + fn is_empty(&self) -> bool { + self.front == self.back && !self.full + } + + fn push_index(&mut self) -> Option { + match self.is_full() { + true => None, + false => Some(self.back), + } + } + + fn push_done(&mut self) { + assert!(!self.is_full()); + self.back = self.increment(self.back); + if self.back == self.front { + self.full = true; + } + self.send_waker.wake(); + } + + fn pop_index(&mut self) -> Option { + match self.is_empty() { + true => None, + false => Some(self.front), + } + } + + fn pop_done(&mut self) { + assert!(!self.is_empty()); + self.front = self.increment(self.front); + self.full = false; + self.recv_waker.wake(); + } +} From 1eb03dc41a4a5fa8435f9a49d26e29ceea6d498e Mon Sep 17 00:00:00 2001 From: Ruben De Smet Date: Fri, 11 Aug 2023 12:07:30 +0200 Subject: [PATCH 097/233] Prefer `receive` over `recv` --- embassy-net-driver-channel/src/lib.rs | 22 +++++++++++----------- embassy-sync/src/zero_copy_channel.rs | 18 +++++++++--------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index e8cd66f8..a2076074 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -131,24 +131,24 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { } pub async fn tx_buf(&mut self) -> &mut [u8] { - let p = self.tx_chan.recv().await; + let p = self.tx_chan.receive().await; &mut p.buf[..p.len] } pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { - let p = self.tx_chan.try_recv()?; + let p = self.tx_chan.try_receive()?; Some(&mut p.buf[..p.len]) } pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { - match self.tx_chan.poll_recv(cx) { + match self.tx_chan.poll_receive(cx) { Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), Poll::Pending => Poll::Pending, } } pub fn tx_done(&mut self) { - self.tx_chan.recv_done(); + self.tx_chan.receive_done(); } } @@ -205,24 +205,24 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> { impl<'d, const MTU: usize> TxRunner<'d, MTU> { pub async fn tx_buf(&mut self) -> &mut [u8] { - let p = self.tx_chan.recv().await; + let p = self.tx_chan.receive().await; &mut p.buf[..p.len] } pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { - let p = self.tx_chan.try_recv()?; + let p = self.tx_chan.try_receive()?; Some(&mut p.buf[..p.len]) } pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { - match self.tx_chan.poll_recv(cx) { + match self.tx_chan.poll_receive(cx) { Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), Poll::Pending => Poll::Pending, } } pub fn tx_done(&mut self) { - self.tx_chan.recv_done(); + self.tx_chan.receive_done(); } } @@ -294,7 +294,7 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> { type TxToken<'a> = TxToken<'a, MTU> where Self: 'a ; fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { - if self.rx.poll_recv(cx).is_ready() && self.tx.poll_send(cx).is_ready() { + if self.rx.poll_receive(cx).is_ready() && self.tx.poll_send(cx).is_ready() { Some((RxToken { rx: self.rx.borrow() }, TxToken { tx: self.tx.borrow() })) } else { None @@ -338,9 +338,9 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> { F: FnOnce(&mut [u8]) -> R, { // NOTE(unwrap): we checked the queue wasn't full when creating the token. - let pkt = unwrap!(self.rx.try_recv()); + let pkt = unwrap!(self.rx.try_receive()); let r = f(&mut pkt.buf[..pkt.len]); - self.rx.recv_done(); + self.rx.receive_done(); r } } diff --git a/embassy-sync/src/zero_copy_channel.rs b/embassy-sync/src/zero_copy_channel.rs index 3701ccf1..cbb8cb52 100644 --- a/embassy-sync/src/zero_copy_channel.rs +++ b/embassy-sync/src/zero_copy_channel.rs @@ -27,7 +27,7 @@ impl<'a, M: RawMutex, T> Channel<'a, M, T> { back: 0, full: false, send_waker: WakerRegistration::new(), - recv_waker: WakerRegistration::new(), + receive_waker: WakerRegistration::new(), })), } } @@ -62,7 +62,7 @@ impl<'a, M: RawMutex, T> Sender<'a, M, T> { match s.push_index() { Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }), None => { - s.recv_waker.register(cx.waker()); + s.receive_waker.register(cx.waker()); Poll::Pending } } @@ -76,7 +76,7 @@ impl<'a, M: RawMutex, T> Sender<'a, M, T> { match s.push_index() { Some(i) => Poll::Ready(i), None => { - s.recv_waker.register(cx.waker()); + s.receive_waker.register(cx.waker()); Poll::Pending } } @@ -99,7 +99,7 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { Receiver { channel: self.channel } } - pub fn try_recv(&mut self) -> Option<&mut T> { + pub fn try_receive(&mut self) -> Option<&mut T> { self.channel.state.lock(|s| { let s = &mut *s.borrow_mut(); match s.pop_index() { @@ -109,7 +109,7 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { }) } - pub fn poll_recv(&mut self, cx: &mut Context) -> Poll<&mut T> { + pub fn poll_receive(&mut self, cx: &mut Context) -> Poll<&mut T> { self.channel.state.lock(|s| { let s = &mut *s.borrow_mut(); match s.pop_index() { @@ -122,7 +122,7 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { }) } - pub async fn recv(&mut self) -> &mut T { + pub async fn receive(&mut self) -> &mut T { let i = poll_fn(|cx| { self.channel.state.lock(|s| { let s = &mut *s.borrow_mut(); @@ -139,7 +139,7 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { unsafe { &mut *self.channel.buf.add(i) } } - pub fn recv_done(&mut self) { + pub fn receive_done(&mut self) { self.channel.state.lock(|s| s.borrow_mut().pop_done()) } } @@ -157,7 +157,7 @@ struct State { full: bool, send_waker: WakerRegistration, - recv_waker: WakerRegistration, + receive_waker: WakerRegistration, } impl State { @@ -204,6 +204,6 @@ impl State { assert!(!self.is_empty()); self.front = self.increment(self.front); self.full = false; - self.recv_waker.wake(); + self.receive_waker.wake(); } } From 6e38b0764253ba07d3106ce3d57c2fd3509d7beb Mon Sep 17 00:00:00 2001 From: Ruben De Smet Date: Fri, 11 Aug 2023 13:50:12 +0200 Subject: [PATCH 098/233] Add docs to zero-copy-channel --- embassy-sync/src/zero_copy_channel.rs | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/embassy-sync/src/zero_copy_channel.rs b/embassy-sync/src/zero_copy_channel.rs index cbb8cb52..f704cbd5 100644 --- a/embassy-sync/src/zero_copy_channel.rs +++ b/embassy-sync/src/zero_copy_channel.rs @@ -1,3 +1,22 @@ +//! A zero-copy queue for sending values between asynchronous tasks. +//! +//! It can be used concurrently by multiple producers (senders) and multiple +//! consumers (receivers), i.e. it is an "MPMC channel". +//! +//! Receivers are competing for messages. So a message that is received by +//! one receiver is not received by any other. +//! +//! This queue takes a Mutex type so that various +//! targets can be attained. For example, a ThreadModeMutex can be used +//! for single-core Cortex-M targets where messages are only passed +//! between tasks running in thread mode. Similarly, a CriticalSectionMutex +//! can also be used for single-core targets where messages are to be +//! passed from exception mode e.g. out of an interrupt handler. +//! +//! This module provides a bounded channel that has a limit on the number of +//! messages that it can store, and if this limit is reached, trying to send +//! another message will result in an error being returned. + use core::cell::RefCell; use core::future::poll_fn; use core::marker::PhantomData; @@ -7,6 +26,17 @@ use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; use crate::waitqueue::WakerRegistration; +/// A bounded zero-copy channel for communicating between asynchronous tasks +/// with backpressure. +/// +/// The channel will buffer up to the provided number of messages. Once the +/// buffer is full, attempts to `send` new messages will wait until a message is +/// received from the channel. +/// +/// All data sent will become available in the same order as it was sent. +/// +/// The channel requires a buffer of recyclable elements. Writing to the channel is done through +/// an `&mut T`. pub struct Channel<'a, M: RawMutex, T> { buf: *mut T, phantom: PhantomData<&'a mut T>, @@ -14,6 +44,10 @@ pub struct Channel<'a, M: RawMutex, T> { } impl<'a, M: RawMutex, T> Channel<'a, M, T> { + /// Initialize a new [`Channel`]. + /// + /// The provided buffer will be used and reused by the channel's logic, and thus dictates the + /// channel's capacity. pub fn new(buf: &'a mut [T]) -> Self { let len = buf.len(); assert!(len != 0); @@ -32,20 +66,27 @@ impl<'a, M: RawMutex, T> Channel<'a, M, T> { } } + /// Creates a [`Sender`] and [`Receiver`] from an existing channel. + /// + /// Further Senders and Receivers can be created through [`Sender::borrow`] and + /// [`Receiver::borrow`] respectively. pub fn split(&mut self) -> (Sender<'_, M, T>, Receiver<'_, M, T>) { (Sender { channel: self }, Receiver { channel: self }) } } +/// Send-only access to a [`Channel`]. pub struct Sender<'a, M: RawMutex, T> { channel: &'a Channel<'a, M, T>, } impl<'a, M: RawMutex, T> Sender<'a, M, T> { + /// Creates one further [`Sender`] over the same channel. pub fn borrow(&mut self) -> Sender<'_, M, T> { Sender { channel: self.channel } } + /// Attempts to send a value over the channel. pub fn try_send(&mut self) -> Option<&mut T> { self.channel.state.lock(|s| { let s = &mut *s.borrow_mut(); @@ -56,6 +97,7 @@ impl<'a, M: RawMutex, T> Sender<'a, M, T> { }) } + /// Attempts to send a value over the channel. pub fn poll_send(&mut self, cx: &mut Context) -> Poll<&mut T> { self.channel.state.lock(|s| { let s = &mut *s.borrow_mut(); @@ -69,6 +111,7 @@ impl<'a, M: RawMutex, T> Sender<'a, M, T> { }) } + /// Asynchronously send a value over the channel. pub async fn send(&mut self) -> &mut T { let i = poll_fn(|cx| { self.channel.state.lock(|s| { @@ -86,19 +129,24 @@ impl<'a, M: RawMutex, T> Sender<'a, M, T> { unsafe { &mut *self.channel.buf.add(i) } } + /// Notify the channel that the sending of the value has been finalized. pub fn send_done(&mut self) { self.channel.state.lock(|s| s.borrow_mut().push_done()) } } + +/// Receive-only access to a [`Channel`]. pub struct Receiver<'a, M: RawMutex, T> { channel: &'a Channel<'a, M, T>, } impl<'a, M: RawMutex, T> Receiver<'a, M, T> { + /// Creates one further [`Sender`] over the same channel. pub fn borrow(&mut self) -> Receiver<'_, M, T> { Receiver { channel: self.channel } } + /// Attempts to receive a value over the channel. pub fn try_receive(&mut self) -> Option<&mut T> { self.channel.state.lock(|s| { let s = &mut *s.borrow_mut(); @@ -109,6 +157,7 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { }) } + /// Attempts to asynchronously receive a value over the channel. pub fn poll_receive(&mut self, cx: &mut Context) -> Poll<&mut T> { self.channel.state.lock(|s| { let s = &mut *s.borrow_mut(); @@ -122,6 +171,7 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { }) } + /// Asynchronously receive a value over the channel. pub async fn receive(&mut self) -> &mut T { let i = poll_fn(|cx| { self.channel.state.lock(|s| { @@ -139,6 +189,7 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { unsafe { &mut *self.channel.buf.add(i) } } + /// Notify the channel that the receiving of the value has been finalized. pub fn receive_done(&mut self) { self.channel.state.lock(|s| s.borrow_mut().pop_done()) } From 615882ebd67f4e7e60fb8aa1505b1272655c4fa4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 4 Sep 2023 22:16:28 +0200 Subject: [PATCH 099/233] Rename zero_copy -> zerocopy. --- embassy-net-driver-channel/src/lib.rs | 26 +++++++++---------- embassy-sync/src/lib.rs | 2 +- ...ro_copy_channel.rs => zerocopy_channel.rs} | 0 3 files changed, 14 insertions(+), 14 deletions(-) rename embassy-sync/src/{zero_copy_channel.rs => zerocopy_channel.rs} (100%) diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index a2076074..bf7ae521 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -14,7 +14,7 @@ use embassy_net_driver::{Capabilities, LinkState, Medium}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_sync::waitqueue::WakerRegistration; -use embassy_sync::zero_copy_channel; +use embassy_sync::zerocopy_channel; pub struct State { rx: [PacketBuf; N_RX], @@ -35,8 +35,8 @@ impl State { - rx: zero_copy_channel::Channel<'d, NoopRawMutex, PacketBuf>, - tx: zero_copy_channel::Channel<'d, NoopRawMutex, PacketBuf>, + rx: zerocopy_channel::Channel<'d, NoopRawMutex, PacketBuf>, + tx: zerocopy_channel::Channel<'d, NoopRawMutex, PacketBuf>, shared: Mutex>, } @@ -48,8 +48,8 @@ struct Shared { } pub struct Runner<'d, const MTU: usize> { - tx_chan: zero_copy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, - rx_chan: zero_copy_channel::Sender<'d, NoopRawMutex, PacketBuf>, + tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, + rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf>, shared: &'d Mutex>, } @@ -59,11 +59,11 @@ pub struct StateRunner<'d> { } pub struct RxRunner<'d, const MTU: usize> { - rx_chan: zero_copy_channel::Sender<'d, NoopRawMutex, PacketBuf>, + rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf>, } pub struct TxRunner<'d, const MTU: usize> { - tx_chan: zero_copy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, + tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, } impl<'d, const MTU: usize> Runner<'d, MTU> { @@ -244,8 +244,8 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( let state_uninit: *mut MaybeUninit> = (&mut state.inner as *mut MaybeUninit>).cast(); let state = unsafe { &mut *state_uninit }.write(StateInner { - rx: zero_copy_channel::Channel::new(&mut state.rx[..]), - tx: zero_copy_channel::Channel::new(&mut state.tx[..]), + rx: zerocopy_channel::Channel::new(&mut state.rx[..]), + tx: zerocopy_channel::Channel::new(&mut state.tx[..]), shared: Mutex::new(RefCell::new(Shared { link_state: LinkState::Down, hardware_address, @@ -283,8 +283,8 @@ impl PacketBuf { } pub struct Device<'d, const MTU: usize> { - rx: zero_copy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, - tx: zero_copy_channel::Sender<'d, NoopRawMutex, PacketBuf>, + rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf>, + tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf>, shared: &'d Mutex>, caps: Capabilities, } @@ -329,7 +329,7 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> { } pub struct RxToken<'a, const MTU: usize> { - rx: zero_copy_channel::Receiver<'a, NoopRawMutex, PacketBuf>, + rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf>, } impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> { @@ -346,7 +346,7 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> { } pub struct TxToken<'a, const MTU: usize> { - tx: zero_copy_channel::Sender<'a, NoopRawMutex, PacketBuf>, + tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf>, } impl<'a, const MTU: usize> embassy_net_driver::TxToken for TxToken<'a, MTU> { diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index 48a7b13f..8a9f841e 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -17,4 +17,4 @@ pub mod pipe; pub mod pubsub; pub mod signal; pub mod waitqueue; -pub mod zero_copy_channel; +pub mod zerocopy_channel; diff --git a/embassy-sync/src/zero_copy_channel.rs b/embassy-sync/src/zerocopy_channel.rs similarity index 100% rename from embassy-sync/src/zero_copy_channel.rs rename to embassy-sync/src/zerocopy_channel.rs From 274f63a879353923feac87f399aae9c5cadd4aa3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 15:47:33 -0500 Subject: [PATCH 100/233] stm32: fix refcounts for usart, spi, and i2c --- embassy-stm32/build.rs | 18 ++++++------------ embassy-stm32/src/i2c/v1.rs | 6 ++++++ embassy-stm32/src/i2c/v2.rs | 6 ++++++ embassy-stm32/src/spi/mod.rs | 2 ++ embassy-stm32/src/usart/buffered.rs | 10 ++++++++++ embassy-stm32/src/usart/mod.rs | 18 ++++++++++++++++++ embassy-stm32/src/usart/ringbuffered.rs | 17 ++++++++++++----- 7 files changed, 60 insertions(+), 17 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 2b66e7da..d3f6452b 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -347,9 +347,7 @@ fn main() { TokenStream::new() }; - let ptype = p - .name - .replace(&['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'][..], ""); + let ptype = p.name.replace(|c| char::is_numeric(c), ""); let pname = format_ident!("{}", p.name); let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); @@ -363,16 +361,14 @@ fn main() { ( quote! { - use atomic_polyfill::Ordering; - - if refcount_statics::#refcount_static.fetch_add(1, Ordering::SeqCst) > 0 { + unsafe { refcount_statics::#refcount_static += 1 }; + if unsafe { refcount_statics::#refcount_static } > 1 { return; } }, quote! { - use atomic_polyfill::Ordering; - - if refcount_statics::#refcount_static.fetch_sub(1, Ordering::SeqCst) > 1 { + unsafe { refcount_statics::#refcount_static -= 1 }; + if unsafe { refcount_statics::#refcount_static } > 0 { return; } }, @@ -416,14 +412,12 @@ fn main() { let mut refcount_mod = TokenStream::new(); for refcount_static in refcount_statics { refcount_mod.extend(quote! { - pub(crate) static #refcount_static: AtomicU8 = AtomicU8::new(0); + pub(crate) static mut #refcount_static: u8 = 0; }); } g.extend(quote! { mod refcount_statics { - use atomic_polyfill::AtomicU8; - #refcount_mod } }); diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 618d85af..f32dd0f0 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -339,6 +339,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } +impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { + fn drop(&mut self) { + T::disable(); + } +} + impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { type Error = Error; diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 4327899b..36f70e32 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -838,6 +838,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } +impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { + fn drop(&mut self) { + T::disable(); + } +} + mod eh02 { use super::*; diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index e2bc8d7f..853de98f 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -646,6 +646,8 @@ impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { self.sck.as_ref().map(|x| x.set_as_disconnected()); self.mosi.as_ref().map(|x| x.set_as_disconnected()); self.miso.as_ref().map(|x| x.set_as_disconnected()); + + T::disable(); } } diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 596d40bf..989c8820 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -124,6 +124,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { rx_buffer: &'d mut [u8], config: Config, ) -> BufferedUart<'d, T> { + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -143,6 +145,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { ) -> BufferedUart<'d, T> { into_ref!(cts, rts); + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -169,6 +173,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { ) -> BufferedUart<'d, T> { into_ref!(de); + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -382,6 +388,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> { T::Interrupt::disable(); } } + + T::disable(); } } @@ -397,6 +405,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> { T::Interrupt::disable(); } } + + T::disable(); } } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 255ddfd4..bfb05671 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -618,6 +618,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { } } +impl<'d, T: BasicInstance, TxDma> Drop for UartTx<'d, T, TxDma> { + fn drop(&mut self) { + T::disable(); + } +} + +impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> { + fn drop(&mut self) { + T::disable(); + } +} + impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { pub fn new( peri: impl Peripheral

+ 'd, @@ -628,6 +640,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { rx_dma: impl Peripheral

+ 'd, config: Config, ) -> Self { + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -647,6 +661,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { ) -> Self { into_ref!(cts, rts); + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -672,6 +688,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { ) -> Self { into_ref!(de); + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index b3f57062..e990eaca 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -1,4 +1,5 @@ use core::future::poll_fn; +use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; @@ -24,12 +25,16 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { let request = self.rx_dma.request(); let opts = Default::default(); - let ring_buf = unsafe { ReadableRingBuffer::new_read(self.rx_dma, request, rdr(T::regs()), dma_buf, opts) }; + // Safety: we forget the struct before this function returns. + let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; + let _peri = unsafe { self._peri.clone_unchecked() }; - RingBufferedUartRx { - _peri: self._peri, - ring_buf, - } + let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; + + // Don't disable the clock + mem::forget(self); + + RingBufferedUartRx { _peri, ring_buf } } } @@ -186,6 +191,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD impl> Drop for RingBufferedUartRx<'_, T, RxDma> { fn drop(&mut self) { self.teardown_uart(); + + T::disable(); } } /// Return an error result if the Sr register has errors From bfb4cf775a81a5a674c1f80ecd68425ee2410081 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 15:54:00 -0500 Subject: [PATCH 101/233] remove adc refcount --- embassy-stm32/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index d3f6452b..09a02952 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -308,7 +308,7 @@ fn main() { // ======== // Generate RccPeripheral impls - let refcounted_peripherals = HashSet::from(["ADC", "USART", "SPI", "I2C"]); + let refcounted_peripherals = HashSet::from(["USART", "SPI", "I2C"]); let mut refcount_statics = HashSet::new(); for p in METADATA.peripherals { From 394503ab69129e79b4fe78653c67337ec4e7346e Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 15:54:23 -0500 Subject: [PATCH 102/233] ci: run HIL --- ci.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ci.sh b/ci.sh index 4112144b..db00c406 100755 --- a/ci.sh +++ b/ci.sh @@ -180,9 +180,4 @@ if [[ -z "${TELEPROBE_TOKEN-}" ]]; then exit fi -rm out/tests/rpi-pico/ethernet_w5100s_perf -rm out/tests/nrf52840-dk/ethernet_enc28j60_perf -rm out/tests/nrf52840-dk/wifi_esp_hosted_perf -rm out/tests/rpi-pico/cyw43-perf - teleprobe client run -r out/tests From 6dc56d2b35d065ba0023fb0bcad27ecd2602fb0e Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 16:04:29 -0500 Subject: [PATCH 103/233] stm32: include uart-named peripherals --- embassy-stm32/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 09a02952..7da3cdff 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -308,7 +308,8 @@ fn main() { // ======== // Generate RccPeripheral impls - let refcounted_peripherals = HashSet::from(["USART", "SPI", "I2C"]); + // TODO: maybe get this from peripheral kind? Not sure + let refcounted_peripherals = HashSet::from(["UART", "USART", "SPI", "I2C"]); let mut refcount_statics = HashSet::new(); for p in METADATA.peripherals { From 8a55adbfd865bc8912e0e2ac61c9db88f287808b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 4 Sep 2023 23:01:07 +0200 Subject: [PATCH 104/233] Revert "ci: remove failing tests" This reverts commit c5732ce2857ce4028a2e03abeb65254200473e5a. --- ci.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ci.sh b/ci.sh index 4112144b..db00c406 100755 --- a/ci.sh +++ b/ci.sh @@ -180,9 +180,4 @@ if [[ -z "${TELEPROBE_TOKEN-}" ]]; then exit fi -rm out/tests/rpi-pico/ethernet_w5100s_perf -rm out/tests/nrf52840-dk/ethernet_enc28j60_perf -rm out/tests/nrf52840-dk/wifi_esp_hosted_perf -rm out/tests/rpi-pico/cyw43-perf - teleprobe client run -r out/tests From d19e1c1dd1c8c514c375bca3ba69f636a0b19f88 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 16:18:31 -0500 Subject: [PATCH 105/233] stm32: only refcount usart and use kind direclty --- embassy-stm32/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 7da3cdff..aef0668a 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -309,7 +309,7 @@ fn main() { // Generate RccPeripheral impls // TODO: maybe get this from peripheral kind? Not sure - let refcounted_peripherals = HashSet::from(["UART", "USART", "SPI", "I2C"]); + let refcounted_peripherals = HashSet::from(["USART"]); let mut refcount_statics = HashSet::new(); for p in METADATA.peripherals { @@ -348,13 +348,13 @@ fn main() { TokenStream::new() }; - let ptype = p.name.replace(|c| char::is_numeric(c), ""); + let ptype = (if let Some(reg) = &p.registers { reg.kind } else { "" }).to_ascii_uppercase(); let pname = format_ident!("{}", p.name); let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); - let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype.trim_start_matches("LP")) { + let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype.as_str()) { let refcount_static = format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); From 49ba9c3da2b6929c5ec1fb17d8c43c271a70eb34 Mon Sep 17 00:00:00 2001 From: Daehyeok Mun Date: Sun, 20 Aug 2023 19:31:47 -0700 Subject: [PATCH 106/233] initial support for STM32G4 ADC --- embassy-stm32/Cargo.toml | 5 +- embassy-stm32/src/adc/v4.rs | 247 +++++++++++++++----------------- embassy-stm32/src/rcc/g4.rs | 54 ++++++- embassy-stm32/src/rcc/mod.rs | 6 + examples/stm32g4/Cargo.toml | 2 + examples/stm32g4/src/bin/adc.rs | 41 ++++++ 6 files changed, 219 insertions(+), 136 deletions(-) create mode 100644 examples/stm32g4/src/bin/adc.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d169107d..712996f2 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9a61a1f090462df8bd1751f89951f04934fdceb3" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7e2310f49fa123fbc3225b91be73522b212703f0" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -70,6 +70,7 @@ embedded-io-async = { version = "0.5.0", optional = true } chrono = { version = "^0.4", default-features = false, optional = true} bit_field = "0.10.2" document-features = "0.2.7" +paste = "1.0" [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } @@ -77,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9a61a1f090462df8bd1751f89951f04934fdceb3", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7e2310f49fa123fbc3225b91be73522b212703f0", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 64d0f0c7..d03f2550 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -1,8 +1,10 @@ use core::sync::atomic::{AtomicU8, Ordering}; use embedded_hal_02::blocking::delay::DelayUs; +#[allow(unused)] use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; use pac::adccommon::vals::Presc; +use paste::paste; use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; use crate::time::Hertz; @@ -13,12 +15,31 @@ pub const VREF_DEFAULT_MV: u32 = 3300; /// VREF voltage used for factory calibration of VREFINTCAL register. pub const VREF_CALIB_MV: u32 = 3300; -// NOTE: Vrefint/Temperature/Vbat are only available on ADC3 on H7, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs +/// Max single ADC operation clock frequency +#[cfg(stm32g4)] +const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); +#[cfg(stm32h7)] +const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); + +#[cfg(stm32g4)] +const VREF_CHANNEL: u8 = 18; +#[cfg(stm32g4)] +const TEMP_CHANNEL: u8 = 16; + +#[cfg(stm32h7)] +const VREF_CHANNEL: u8 = 19; +#[cfg(stm32h7)] +const TEMP_CHANNEL: u8 = 18; + +// TODO this should be 14 for H7a/b/35 +const VBAT_CHANNEL: u8 = 17; + +// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs pub struct VrefInt; impl InternalChannel for VrefInt {} impl super::sealed::InternalChannel for VrefInt { fn channel(&self) -> u8 { - 19 + VREF_CHANNEL } } @@ -26,7 +47,7 @@ pub struct Temperature; impl InternalChannel for Temperature {} impl super::sealed::InternalChannel for Temperature { fn channel(&self) -> u8 { - 18 + TEMP_CHANNEL } } @@ -34,126 +55,79 @@ pub struct Vbat; impl InternalChannel for Vbat {} impl super::sealed::InternalChannel for Vbat { fn channel(&self) -> u8 { - // TODO this should be 14 for H7a/b/35 - 17 + VBAT_CHANNEL } } static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0); +#[cfg(any(stm32g4x3, stm32g4x4))] +static ADC345_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0); + +macro_rules! rcc_peripheral { + ($adc_name:ident, $freqs:ident, $ahb:ident, $reg:ident $(, $counter:ident )? ) => { + impl crate::rcc::sealed::RccPeripheral for crate::peripherals::$adc_name { + fn frequency() -> crate::time::Hertz { + critical_section::with(|_| { + match unsafe { crate::rcc::get_freqs() }.$freqs { + Some(ck) => ck, + None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") + } + }) + } + + fn enable() { + critical_section::with(|_| { + paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](true))} + }); + $ ( $counter.fetch_add(1, Ordering::SeqCst); )? + } + + fn disable() { + $ ( if $counter.load(Ordering::SeqCst) == 1 )? { + critical_section::with(|_| { + paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](false))} + }) + } + $ ( $counter.fetch_sub(1, Ordering::SeqCst); )? + } + + fn reset() { + $ ( if $counter.load(Ordering::SeqCst) == 1 )? { + critical_section::with(|_| { + paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](true))} + paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](false))} + }); + } + } + } + + impl crate::rcc::RccPeripheral for crate::peripherals::$adc_name {} + }; +} + +#[cfg(stm32g4)] +foreach_peripheral!( + (adc, ADC1) => { rcc_peripheral!(ADC1, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); }; + (adc, ADC2) => { rcc_peripheral!(ADC2, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); }; +); + +#[cfg(stm32g4x1)] +foreach_peripheral!( + (adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345); }; +); + +#[cfg(any(stm32g4x3, stm32g4x4))] +foreach_peripheral!( + (adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; + (adc, ADC4) => { rcc_peripheral!(ADC4, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; + (adc, ADC5) => { rcc_peripheral!(ADC5, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; +); #[cfg(stm32h7)] foreach_peripheral!( - (adc, ADC1) => { - impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 { - fn frequency() -> crate::time::Hertz { - critical_section::with(|_| { - match unsafe { crate::rcc::get_freqs() }.adc { - Some(ck) => ck, - None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") - } - }) - } - - fn enable() { - critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) - }); - ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); - } - - fn disable() { - if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { - critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); - }) - } - ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst); - } - - fn reset() { - if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { - critical_section::with(|_| { - crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); - crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); - }); - } - } - } - - impl crate::rcc::RccPeripheral for crate::peripherals::ADC1 {} - }; - (adc, ADC2) => { - impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 { - fn frequency() -> crate::time::Hertz { - critical_section::with(|_| { - match unsafe { crate::rcc::get_freqs() }.adc { - Some(ck) => ck, - None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") - } - }) - } - - fn enable() { - critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) - }); - ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); - } - - fn disable() { - if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { - critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); - }) - } - ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst); - } - - fn reset() { - if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { - critical_section::with(|_| { - crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); - crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); - }); - } - } - } - - impl crate::rcc::RccPeripheral for crate::peripherals::ADC2 {} - }; - (adc, ADC3) => { - impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 { - fn frequency() -> crate::time::Hertz { - critical_section::with(|_| { - match unsafe { crate::rcc::get_freqs() }.adc { - Some(ck) => ck, - None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") - } - }) - } - - fn enable() { - critical_section::with(|_| { - crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true)) - }); - } - - fn disable() { - critical_section::with(|_| { - crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false)); - }) - } - - fn reset() { - critical_section::with(|_| { - crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true)); - crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false)); - }); - } - } - - impl crate::rcc::RccPeripheral for crate::peripherals::ADC3 {} - }; + (adc, ADC1) => { rcc_peripheral!(ADC1, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); }; + (adc, ADC2) => { rcc_peripheral!(ADC2, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); }; + (adc, ADC3) => { rcc_peripheral!(ADC3, adc, ahb4, adc3); }; ); // NOTE (unused): The prescaler enum closely copies the hardware capabilities, @@ -176,7 +150,7 @@ enum Prescaler { impl Prescaler { fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / 50_000_000; + let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; match raw_prescaler { 0 => Self::NotDivided, 1 => Self::DividedBy2, @@ -237,20 +211,23 @@ impl<'d, T: Instance> Adc<'d, T> { let frequency = Hertz(T::frequency().0 / prescaler.divisor()); info!("ADC frequency set to {} Hz", frequency.0); - if frequency > Hertz::mhz(50) { - panic!("Maximal allowed frequency for the ADC is 50 MHz and it varies with different packages, refer to ST docs for more information."); + if frequency > MAX_ADC_CLK_FREQ { + panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); } - let boost = if frequency < Hertz::khz(6_250) { - Boost::LT6_25 - } else if frequency < Hertz::khz(12_500) { - Boost::LT12_5 - } else if frequency < Hertz::mhz(25) { - Boost::LT25 - } else { - Boost::LT50 - }; - T::regs().cr().modify(|w| w.set_boost(boost)); + #[cfg(stm32h7)] + { + let boost = if frequency < Hertz::khz(6_250) { + Boost::LT6_25 + } else if frequency < Hertz::khz(12_500) { + Boost::LT12_5 + } else if frequency < Hertz::mhz(25) { + Boost::LT25 + } else { + Boost::LT50 + }; + T::regs().cr().modify(|w| w.set_boost(boost)); + } let mut s = Self { adc, sample_time: Default::default(), @@ -379,10 +356,14 @@ impl<'d, T: Instance> Adc<'d, T> { // Configure channel Self::set_channel_sample_time(channel, self.sample_time); - T::regs().cfgr2().modify(|w| w.set_lshift(0)); - T::regs() - .pcsel() - .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); + #[cfg(stm32h7)] + { + T::regs().cfgr2().modify(|w| w.set_lshift(0)); + T::regs() + .pcsel() + .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); + } + T::regs().sqr1().write(|reg| { reg.set_sq(0, channel); reg.set_l(0); diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 3b044cd1..4c95bb15 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -1,5 +1,5 @@ use stm32_metapac::flash::vals::Latency; -use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw}; +use stm32_metapac::rcc::vals::{Adcsel, Hpre, Pllsrc, Ppre, Sw}; use stm32_metapac::FLASH; pub use super::bus::{AHBPrescaler, APBPrescaler}; @@ -14,6 +14,29 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(32_000); +#[derive(Clone, Copy)] +pub enum AdcClockSource { + NoClk, + SysClk, + PllP, +} + +impl AdcClockSource { + pub fn adcsel(&self) -> Adcsel { + match self { + AdcClockSource::NoClk => Adcsel::NOCLK, + AdcClockSource::SysClk => Adcsel::SYSCLK, + AdcClockSource::PllP => Adcsel::PLLP, + } + } +} + +impl Default for AdcClockSource { + fn default() -> Self { + Self::NoClk + } +} + /// System clock mux source #[derive(Clone, Copy)] pub enum ClockSrc { @@ -327,6 +350,8 @@ pub struct Config { pub pll: Option, /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. pub clock_48mhz_src: Option, + pub adc12_clock_source: AdcClockSource, + pub adc345_clock_source: AdcClockSource, } /// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator. @@ -346,6 +371,8 @@ impl Default for Config { low_power_run: false, pll: None, clock_48mhz_src: None, + adc12_clock_source: Default::default(), + adc345_clock_source: Default::default(), } } } @@ -549,6 +576,29 @@ pub(crate) unsafe fn init(config: Config) { RCC.ccipr().modify(|w| w.set_clk48sel(source)); } + RCC.ccipr() + .modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel())); + RCC.ccipr() + .modify(|w| w.set_adc345sel(config.adc345_clock_source.adcsel())); + + let adc12_ck = match config.adc12_clock_source { + AdcClockSource::NoClk => None, + AdcClockSource::PllP => match &pll_freq { + Some(pll) => pll.pll_p, + None => None, + }, + AdcClockSource::SysClk => Some(Hertz(sys_clk)), + }; + + let adc345_ck = match config.adc345_clock_source { + AdcClockSource::NoClk => None, + AdcClockSource::PllP => match &pll_freq { + Some(pll) => pll.pll_p, + None => None, + }, + AdcClockSource::SysClk => Some(Hertz(sys_clk)), + }; + if config.low_power_run { assert!(sys_clk <= 2_000_000); PWR.cr1().modify(|w| w.set_lpr(true)); @@ -562,5 +612,7 @@ pub(crate) unsafe fn init(config: Config) { apb1_tim: Hertz(apb1_tim_freq), apb2: Hertz(apb2_freq), apb2_tim: Hertz(apb2_tim_freq), + adc12: adc12_ck, + adc345: adc345_ck, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 0430e4a7..ecabe23a 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -77,6 +77,12 @@ pub struct Clocks { #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] pub adc: Option, + #[cfg(any(rcc_g4))] + pub adc12: Option, + + #[cfg(any(rcc_g4))] + pub adc345: Option, + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 0c1cdd67..2e81d206 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -11,6 +11,8 @@ embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } +usbd-hid = "0.6.0" defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs new file mode 100644 index 00000000..a792748b --- /dev/null +++ b/examples/stm32g4/src/bin/adc.rs @@ -0,0 +1,41 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::rcc::{AdcClockSource, ClockSrc, Pll, PllM, PllN, PllR, PllSrc}; +use embassy_stm32::Config; +use embassy_time::{Delay, Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + + config.rcc.pll = Some(Pll { + source: PllSrc::HSI16, + prediv_m: PllM::Div4, + mul_n: PllN::Mul85, + div_p: None, + div_q: None, + // Main system clock at 170 MHz + div_r: Some(PllR::Div2), + }); + + config.rcc.adc12_clock_source = AdcClockSource::SysClk; + config.rcc.mux = ClockSrc::PLL; + + let mut p = embassy_stm32::init(config); + info!("Hello World!"); + + let mut adc = Adc::new(p.ADC2, &mut Delay); + adc.set_sample_time(SampleTime::Cycles32_5); + + loop { + let measured = adc.read(&mut p.PA7); + info!("measured: {}", measured); + Timer::after(Duration::from_millis(500)).await; + } +} From 1180e1770d8cbf0fe6cb1729f3a2d113d4b13dfc Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 5 Sep 2023 19:50:21 +0200 Subject: [PATCH 107/233] net-esp-hosted: add get_status() --- embassy-net-esp-hosted/src/control.rs | 85 ++++++++++++++++++++------- 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index ce6636a8..a4996b58 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -19,6 +19,8 @@ pub struct Control<'a> { } #[allow(unused)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] enum WifiMode { None = 0, Sta = 1, @@ -26,6 +28,18 @@ enum WifiMode { ApSta = 3, } +pub use proto::CtrlWifiSecProt as Security; + +#[derive(Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Status { + pub ssid: String<32>, + pub bssid: [u8; 6], + pub rssi: i32, + pub channel: u32, + pub security: Security, +} + macro_rules! ioctl { ($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => { let mut msg = proto::CtrlMsg { @@ -34,7 +48,9 @@ macro_rules! ioctl { payload: Some(proto::CtrlMsgPayload::$req_variant($req)), }; $self.ioctl(&mut msg).await?; - let Some(proto::CtrlMsgPayload::$resp_variant($resp)) = msg.payload else { + #[allow(unused_mut)] + let Some(proto::CtrlMsgPayload::$resp_variant(mut $resp)) = msg.payload + else { warn!("unexpected response variant"); return Err(Error::Internal); }; @@ -66,6 +82,19 @@ impl<'a> Control<'a> { Ok(()) } + pub async fn get_status(&mut self) -> Result { + let req = proto::CtrlMsgReqGetApConfig {}; + ioctl!(self, ReqGetApConfig, RespGetApConfig, req, resp); + trim_nulls(&mut resp.ssid); + Ok(Status { + ssid: resp.ssid, + bssid: parse_mac(&resp.bssid)?, + rssi: resp.rssi as _, + channel: resp.chnl, + security: resp.sec_prot, + }) + } + pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> { let req = proto::CtrlMsgReqConnectAp { ssid: String::from(ssid), @@ -98,27 +127,7 @@ impl<'a> Control<'a> { mode: WifiMode::Sta as _, }; ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp); - - // WHY IS THIS A STRING? WHYYYY - fn nibble_from_hex(b: u8) -> u8 { - match b { - b'0'..=b'9' => b - b'0', - b'a'..=b'f' => b + 0xa - b'a', - b'A'..=b'F' => b + 0xa - b'A', - _ => panic!("invalid hex digit {}", b), - } - } - - let mac = resp.mac.as_bytes(); - let mut res = [0; 6]; - if mac.len() != 17 { - warn!("unexpected MAC respnse length"); - return Err(Error::Internal); - } - for (i, b) in res.iter_mut().enumerate() { - *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1]) - } - Ok(res) + parse_mac(&resp.mac) } async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> { @@ -167,3 +176,35 @@ impl<'a> Control<'a> { Ok(()) } } + +// WHY IS THIS A STRING? WHYYYY +fn parse_mac(mac: &str) -> Result<[u8; 6], Error> { + fn nibble_from_hex(b: u8) -> Result { + match b { + b'0'..=b'9' => Ok(b - b'0'), + b'a'..=b'f' => Ok(b + 0xa - b'a'), + b'A'..=b'F' => Ok(b + 0xa - b'A'), + _ => { + warn!("invalid hex digit {}", b); + Err(Error::Internal) + } + } + } + + let mac = mac.as_bytes(); + let mut res = [0; 6]; + if mac.len() != 17 { + warn!("unexpected MAC length"); + return Err(Error::Internal); + } + for (i, b) in res.iter_mut().enumerate() { + *b = (nibble_from_hex(mac[i * 3])? << 4) | nibble_from_hex(mac[i * 3 + 1])? + } + Ok(res) +} + +fn trim_nulls(s: &mut String) { + while s.chars().rev().next() == Some(0 as char) { + s.pop(); + } +} From f5022719401ef15b02bfefadcf7e10719e48f06e Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 16:46:57 -0500 Subject: [PATCH 108/233] stm32: add initial adc f3 impl --- embassy-stm32/build.rs | 11 ++- embassy-stm32/src/adc/f3.rs | 126 +++++++++++++++++++++++++++ embassy-stm32/src/adc/mod.rs | 59 ++++++++++--- embassy-stm32/src/adc/resolution.rs | 8 +- embassy-stm32/src/adc/sample_time.rs | 18 +++- embassy-stm32/src/rcc/f3.rs | 93 +++++++++++++++++++- embassy-stm32/src/rcc/mod.rs | 5 +- examples/stm32f334/src/bin/adc.rs | 34 ++++++++ 8 files changed, 331 insertions(+), 23 deletions(-) create mode 100644 embassy-stm32/src/adc/f3.rs create mode 100644 examples/stm32f334/src/bin/adc.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index aef0668a..d3bfd24f 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -309,14 +309,17 @@ fn main() { // Generate RccPeripheral impls // TODO: maybe get this from peripheral kind? Not sure - let refcounted_peripherals = HashSet::from(["USART"]); + let mut refcounted_peripherals = HashSet::from(["usart"]); let mut refcount_statics = HashSet::new(); + if chip_name.starts_with("stm32f3") { + refcounted_peripherals.insert("adc"); + } + for p in METADATA.peripherals { // generating RccPeripheral impl for H7 ADC3 would result in bad frequency if !singletons.contains(&p.name.to_string()) || (p.name == "ADC3" && METADATA.line.starts_with("STM32H7")) - || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "f3")) || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "v4")) { continue; @@ -348,13 +351,13 @@ fn main() { TokenStream::new() }; - let ptype = (if let Some(reg) = &p.registers { reg.kind } else { "" }).to_ascii_uppercase(); + let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" }; let pname = format_ident!("{}", p.name); let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase()); let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); - let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype.as_str()) { + let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) { let refcount_static = format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs new file mode 100644 index 00000000..458573c0 --- /dev/null +++ b/embassy-stm32/src/adc/f3.rs @@ -0,0 +1,126 @@ +use embassy_hal_internal::into_ref; +use embedded_hal_02::blocking::delay::DelayUs; + +use crate::adc::{Adc, AdcPin, Instance, SampleTime}; +use crate::time::Hertz; +use crate::Peripheral; + +pub const VDDA_CALIB_MV: u32 = 3300; +pub const ADC_MAX: u32 = (1 << 12) - 1; +// No calibration data for F103, voltage should be 1.2v +pub const VREF_INT: u32 = 1200; + +pub struct Vref; +impl AdcPin for Vref {} +impl super::sealed::AdcPin for Vref { + fn channel(&self) -> u8 { + 18 + } +} + +pub struct Temperature; +impl AdcPin for Temperature {} +impl super::sealed::AdcPin for Temperature { + fn channel(&self) -> u8 { + 16 + } +} + +impl<'d, T: Instance> Adc<'d, T> { + pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + use crate::pac::adc::vals; + + into_ref!(adc); + + T::enable(); + T::reset(); + + // Enable the adc regulator + T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); + T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED)); + + // Wait for the regulator to stabilize + delay.delay_us(10); + + assert!(!T::regs().cr().read().aden()); + + // Begin calibration + T::regs().cr().modify(|w| w.set_adcaldif(false)); + T::regs().cr().modify(|w| w.set_adcal(true)); + + while T::regs().cr().read().adcal() {} + + // Enable the adc + T::regs().cr().modify(|w| w.set_aden(true)); + + // Wait until the adc is ready + while !T::regs().isr().read().adrdy() {} + + Self { + adc, + sample_time: Default::default(), + } + } + + fn freq() -> Hertz { + ::frequency() + } + + pub fn sample_time_for_us(&self, us: u32) -> SampleTime { + match us * Self::freq().0 / 1_000_000 { + 0..=1 => SampleTime::Cycles1_5, + 2..=4 => SampleTime::Cycles4_5, + 5..=7 => SampleTime::Cycles7_5, + 8..=19 => SampleTime::Cycles19_5, + 20..=61 => SampleTime::Cycles61_5, + 62..=181 => SampleTime::Cycles181_5, + _ => SampleTime::Cycles601_5, + } + } + + pub fn enable_vref(&self, _delay: &mut impl DelayUs) -> Vref { + T::common_regs().ccr().modify(|w| w.set_vrefen(true)); + + Vref {} + } + + pub fn enable_temperature(&self) -> Temperature { + T::common_regs().ccr().modify(|w| w.set_tsen(true)); + + Temperature {} + } + + pub fn set_sample_time(&mut self, sample_time: SampleTime) { + self.sample_time = sample_time; + } + + /// Perform a single conversion. + fn convert(&mut self) -> u16 { + T::regs().isr().write(|_| {}); + T::regs().cr().modify(|w| w.set_adstart(true)); + + while !T::regs().isr().read().eoc() && !T::regs().isr().read().eos() {} + T::regs().isr().write(|_| {}); + + T::regs().dr().read().0 as u16 + } + + pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { + // pin.set_as_analog(); + + Self::set_channel_sample_time(pin.channel(), self.sample_time); + + // Configure the channel to sample + T::regs().sqr3().write(|w| w.set_sq(0, pin.channel())); + self.convert() + } + + fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { + let sample_time = sample_time.into(); + if ch <= 9 { + T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); + } else { + T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + } + } +} diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index e57889aa..a127445d 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -1,23 +1,24 @@ #![macro_use] -#[cfg(not(any(adc_f3, adc_f3_v2)))] +#[cfg(not(adc_f3_v2))] #[cfg_attr(adc_f1, path = "f1.rs")] +#[cfg_attr(adc_f3, path = "f3.rs")] #[cfg_attr(adc_v1, path = "v1.rs")] #[cfg_attr(adc_v2, path = "v2.rs")] #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] #[cfg_attr(adc_v4, path = "v4.rs")] mod _version; -#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] +#[cfg(not(any(adc_f1, adc_f3_v2)))] mod resolution; mod sample_time; -#[cfg(not(any(adc_f3, adc_f3_v2)))] #[allow(unused)] +#[cfg(not(adc_f3_v2))] pub use _version::*; #[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] pub use resolution::Resolution; -#[cfg(not(any(adc_f3, adc_f3_v2)))] +#[cfg(not(adc_f3_v2))] pub use sample_time::SampleTime; use crate::peripherals; @@ -25,15 +26,17 @@ use crate::peripherals; pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::PeripheralRef<'d, T>, - #[cfg(not(any(adc_f3, adc_f3_v2)))] + #[cfg(not(adc_f3_v2))] sample_time: SampleTime, } pub(crate) mod sealed { pub trait Instance { fn regs() -> crate::pac::adc::Adc; - #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] + #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] fn common_regs() -> crate::pac::adccommon::AdcCommon; + #[cfg(adc_f3)] + fn frequency() -> crate::time::Hertz; } pub trait AdcPin { @@ -45,22 +48,22 @@ pub(crate) mod sealed { } } -#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4)))] +#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3)))] pub trait Instance: sealed::Instance + crate::Peripheral

{} -#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4))] +#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3))] pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc::RccPeripheral {} pub trait AdcPin: sealed::AdcPin {} pub trait InternalChannel: sealed::InternalChannel {} -#[cfg(not(stm32h7))] +#[cfg(not(any(stm32h7, adc_f3)))] foreach_peripheral!( (adc, $inst:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { fn regs() -> crate::pac::adc::Adc { crate::pac::$inst } - #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] + #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { foreach_peripheral!{ (adccommon, $common_inst:ident) => { @@ -74,7 +77,7 @@ foreach_peripheral!( }; ); -#[cfg(stm32h7)] +#[cfg(any(stm32h7, adc_f3))] foreach_peripheral!( (adc, ADC3) => { impl crate::adc::sealed::Instance for peripherals::ADC3 { @@ -89,16 +92,43 @@ foreach_peripheral!( }; } } + + #[cfg(adc_f3)] + fn frequency() -> crate::time::Hertz { + unsafe { crate::rcc::get_freqs() }.adc34.unwrap() + } } impl crate::adc::Instance for peripherals::ADC3 {} }; + (adc, ADC4) => { + impl crate::adc::sealed::Instance for peripherals::ADC4 { + fn regs() -> crate::pac::adc::Adc { + crate::pac::ADC4 + } + #[cfg(not(any(adc_f1, adc_v1)))] + fn common_regs() -> crate::pac::adccommon::AdcCommon { + foreach_peripheral!{ + (adccommon, ADC3_COMMON) => { + return crate::pac::ADC3_COMMON + }; + } + } + + #[cfg(adc_f3)] + fn frequency() -> crate::time::Hertz { + unsafe { crate::rcc::get_freqs() }.adc34.unwrap() + } + } + + impl crate::adc::Instance for peripherals::ADC4 {} + }; (adc, $inst:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { fn regs() -> crate::pac::adc::Adc { crate::pac::$inst } - #[cfg(all(not(adc_f1), not(adc_v1)))] + #[cfg(not(any(adc_f1, adc_v1)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { foreach_peripheral!{ (adccommon, ADC_COMMON) => { @@ -106,6 +136,11 @@ foreach_peripheral!( }; } } + + #[cfg(adc_f3)] + fn frequency() -> crate::time::Hertz { + unsafe { crate::rcc::get_freqs() }.adc.unwrap() + } } impl crate::adc::Instance for peripherals::$inst {} diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 67fb9b8c..5668137b 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs @@ -1,4 +1,4 @@ -#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] +#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Resolution { TwelveBit, @@ -19,7 +19,7 @@ pub enum Resolution { impl Default for Resolution { fn default() -> Self { - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] { Self::TwelveBit } @@ -40,7 +40,7 @@ impl From for crate::pac::adc::vals::Res { Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, } } @@ -56,7 +56,7 @@ impl Resolution { Resolution::TwelveBit => (1 << 12) - 1, Resolution::TenBit => (1 << 10) - 1, Resolution::EightBit => (1 << 8) - 1, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] Resolution::SixBit => (1 << 6) - 1, } } diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs index 5480e7a7..6a661929 100644 --- a/embassy-stm32/src/adc/sample_time.rs +++ b/embassy-stm32/src/adc/sample_time.rs @@ -1,4 +1,4 @@ -#[cfg(not(any(adc_f3, adc_f3_v2)))] +#[cfg(not(adc_f3_v2))] macro_rules! impl_sample_time { ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] @@ -105,3 +105,19 @@ impl_sample_time!( ("810.5", Cycles810_5, CYCLES810_5) ) ); + +#[cfg(adc_f3)] +impl_sample_time!( + "1.5", + Cycles1_5, + ( + ("1.5", Cycles1_5, CYCLES1_5), + ("2.5", Cycles2_5, CYCLES2_5), + ("4.5", Cycles4_5, CYCLES4_5), + ("7.5", Cycles7_5, CYCLES7_5), + ("19.5", Cycles19_5, CYCLES19_5), + ("61.5", Cycles61_5, CYCLES61_5), + ("181.5", Cycles181_5, CYCLES181_5), + ("601.5", Cycles601_5, CYCLES601_5) + ) +); diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 7480c039..f8726c24 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -1,5 +1,5 @@ use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; +use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -10,6 +10,46 @@ pub const HSI_FREQ: Hertz = Hertz(8_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(40_000); +#[repr(u16)] +#[derive(Clone, Copy)] +pub enum ADCPrescaler { + Div1 = 1, + Div2 = 2, + Div4 = 4, + Div6 = 6, + Div8 = 8, + Div12 = 12, + Div16 = 16, + Div32 = 32, + Div64 = 64, + Div128 = 128, + Div256 = 256, +} + +impl From for Adcpres { + fn from(value: ADCPrescaler) -> Self { + match value { + ADCPrescaler::Div1 => Adcpres::DIV1, + ADCPrescaler::Div2 => Adcpres::DIV2, + ADCPrescaler::Div4 => Adcpres::DIV4, + ADCPrescaler::Div6 => Adcpres::DIV6, + ADCPrescaler::Div8 => Adcpres::DIV8, + ADCPrescaler::Div12 => Adcpres::DIV12, + ADCPrescaler::Div16 => Adcpres::DIV16, + ADCPrescaler::Div32 => Adcpres::DIV32, + ADCPrescaler::Div64 => Adcpres::DIV64, + ADCPrescaler::Div128 => Adcpres::DIV128, + ADCPrescaler::Div256 => Adcpres::DIV256, + } + } +} + +#[derive(Clone, Copy)] +pub enum ADCClock { + AHB(ADCPrescaler), + PLL(ADCPrescaler), +} + /// Clocks configutation #[non_exhaustive] #[derive(Default)] @@ -36,9 +76,18 @@ pub struct Config { /// - The System clock frequency is either 48MHz or 72MHz /// - APB1 clock has a minimum frequency of 10MHz pub pll48: bool, + #[cfg(rcc_f3)] + /// ADC clock setup + /// - For AHB, a psc of 4 or less must be used + pub adc: Option, + #[cfg(rcc_f3)] + /// ADC clock setup + /// - For AHB, a psc of 4 or less must be used + pub adc34: Option, } // Information required to setup the PLL clock +#[derive(Clone, Copy)] struct PllConfig { pll_src: Pllsrc, pll_mul: Pllmul, @@ -148,6 +197,44 @@ pub(crate) unsafe fn init(config: Config) { }); } + #[cfg(rcc_f3)] + let adc = config.adc.map(|adc| match adc { + ADCClock::PLL(psc) => RCC.cfgr2().modify(|w| { + // Make sure that we're using the PLL + pll_config.unwrap(); + w.set_adc12pres(psc.into()); + + Hertz(sysclk / psc as u32) + }), + ADCClock::AHB(psc) => { + assert!(psc as u16 <= 4); + assert!(!(psc as u16 == 1 && hpre_bits != Hpre::DIV1)); + + // To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be + // different from ā€œ00ā€. + todo!(); + } + }); + + #[cfg(rcc_f3)] + let adc34 = config.adc34.map(|adc| match adc { + ADCClock::PLL(psc) => RCC.cfgr2().modify(|w| { + // Make sure that we're using the PLL + pll_config.unwrap(); + w.set_adc34pres(psc.into()); + + Hertz(sysclk / psc as u32) + }), + ADCClock::AHB(psc) => { + assert!(psc as u16 <= 4); + assert!(!(psc as u16 == 1 && hpre_bits != Hpre::DIV1)); + + // To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be + // different from ā€œ00ā€. + todo!(); + } + }); + // Set prescalers // CFGR has been written before (PLL, PLL48) don't overwrite these settings RCC.cfgr().modify(|w| { @@ -177,6 +264,10 @@ pub(crate) unsafe fn init(config: Config) { apb1_tim: Hertz(pclk1 * timer_mul1), apb2_tim: Hertz(pclk2 * timer_mul2), ahb1: Hertz(hclk), + #[cfg(rcc_f3)] + adc: adc, + #[cfg(rcc_f3)] + adc34: adc34, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 0430e4a7..2e1f6035 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -74,9 +74,12 @@ pub struct Clocks { #[cfg(stm32f1)] pub adc: Hertz, - #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] + #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3))] pub adc: Option, + #[cfg(rcc_f3)] + pub adc34: Option, + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs new file mode 100644 index 00000000..729497e8 --- /dev/null +++ b/examples/stm32f334/src/bin/adc.rs @@ -0,0 +1,34 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::adc::Adc; +use embassy_stm32::rcc::{ADCClock, ADCPrescaler}; +use embassy_stm32::time::Hertz; +use embassy_stm32::Config; +use embassy_time::{Delay, Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let mut config = Config::default(); + config.rcc.hse = Some(Hertz(8_000_000)); + config.rcc.sysclk = Some(Hertz(16_000_000)); + config.rcc.adc = Some(ADCClock::PLL(ADCPrescaler::Div1)); + + let mut p = embassy_stm32::init(config); + + let mut adc = Adc::new(p.ADC1, &mut Delay); + + let mut vrefint = adc.enable_vref(&mut Delay); + + let _vref = adc.read(&mut vrefint); + let _pin = adc.read(&mut p.PA0); + + loop { + info!("Hello World!"); + Timer::after(Duration::from_secs(1)).await; + } +} From 7622d2eb61c030972756a962fee65e3ab66cfa10 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 17:10:15 -0500 Subject: [PATCH 109/233] stm32: fix merge issues --- embassy-stm32/src/adc/v4.rs | 12 ++++++------ embassy-stm32/src/rcc/g4.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index d03f2550..2ff5c8f9 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -107,20 +107,20 @@ macro_rules! rcc_peripheral { #[cfg(stm32g4)] foreach_peripheral!( - (adc, ADC1) => { rcc_peripheral!(ADC1, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); }; - (adc, ADC2) => { rcc_peripheral!(ADC2, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); }; + (adc, ADC1) => { rcc_peripheral!(ADC1, adc, ahb2, adc12, ADC12_ENABLE_COUNTER); }; + (adc, ADC2) => { rcc_peripheral!(ADC2, adc, ahb2, adc12, ADC12_ENABLE_COUNTER); }; ); #[cfg(stm32g4x1)] foreach_peripheral!( - (adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345); }; + (adc, ADC3) => { rcc_peripheral!(ADC3, adc34, ahb2, adc345); }; ); #[cfg(any(stm32g4x3, stm32g4x4))] foreach_peripheral!( - (adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; - (adc, ADC4) => { rcc_peripheral!(ADC4, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; - (adc, ADC5) => { rcc_peripheral!(ADC5, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; + (adc, ADC3) => { rcc_peripheral!(ADC3, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; + (adc, ADC4) => { rcc_peripheral!(ADC4, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; + (adc, ADC5) => { rcc_peripheral!(ADC5, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; ); #[cfg(stm32h7)] diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 4c95bb15..2359f39c 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -612,7 +612,7 @@ pub(crate) unsafe fn init(config: Config) { apb1_tim: Hertz(apb1_tim_freq), apb2: Hertz(apb2_freq), apb2_tim: Hertz(apb2_tim_freq), - adc12: adc12_ck, - adc345: adc345_ck, + adc: adc12_ck, + adc34: adc345_ck, }); } From fd22f4fac5da01c8c171f2f3ed92f701bb0421d7 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 17:45:52 -0500 Subject: [PATCH 110/233] stm32: remove paste and use refcount statics --- embassy-stm32/build.rs | 17 +++------ embassy-stm32/src/adc/mod.rs | 6 ++- embassy-stm32/src/adc/v4.rs | 74 ------------------------------------ 3 files changed, 10 insertions(+), 87 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index d3bfd24f..bb81736b 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -308,20 +308,11 @@ fn main() { // ======== // Generate RccPeripheral impls - // TODO: maybe get this from peripheral kind? Not sure - let mut refcounted_peripherals = HashSet::from(["usart"]); + let refcounted_peripherals = HashSet::from(["usart", "adc"]); let mut refcount_statics = HashSet::new(); - if chip_name.starts_with("stm32f3") { - refcounted_peripherals.insert("adc"); - } - for p in METADATA.peripherals { - // generating RccPeripheral impl for H7 ADC3 would result in bad frequency - if !singletons.contains(&p.name.to_string()) - || (p.name == "ADC3" && METADATA.line.starts_with("STM32H7")) - || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "v4")) - { + if !singletons.contains(&p.name.to_string()) { continue; } @@ -711,6 +702,10 @@ fn main() { // ADC is special if regs.kind == "adc" { + if p.rcc.is_none() { + continue; + } + let peri = format_ident!("{}", p.name); let pin_name = format_ident!("{}", pin.pin); diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index a127445d..023a94f2 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -56,7 +56,7 @@ pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc: pub trait AdcPin: sealed::AdcPin {} pub trait InternalChannel: sealed::InternalChannel {} -#[cfg(not(any(stm32h7, adc_f3)))] +#[cfg(not(any(stm32h7, adc_f3, adc_v4)))] foreach_peripheral!( (adc, $inst:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { @@ -77,9 +77,10 @@ foreach_peripheral!( }; ); -#[cfg(any(stm32h7, adc_f3))] +#[cfg(any(stm32h7, adc_f3, adc_v4))] foreach_peripheral!( (adc, ADC3) => { + #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::sealed::Instance for peripherals::ADC3 { fn regs() -> crate::pac::adc::Adc { crate::pac::ADC3 @@ -99,6 +100,7 @@ foreach_peripheral!( } } + #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::Instance for peripherals::ADC3 {} }; (adc, ADC4) => { diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 2ff5c8f9..655c0cb6 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -1,10 +1,7 @@ -use core::sync::atomic::{AtomicU8, Ordering}; - use embedded_hal_02::blocking::delay::DelayUs; #[allow(unused)] use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; use pac::adccommon::vals::Presc; -use paste::paste; use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; use crate::time::Hertz; @@ -59,77 +56,6 @@ impl super::sealed::InternalChannel for Vbat { } } -static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0); -#[cfg(any(stm32g4x3, stm32g4x4))] -static ADC345_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0); - -macro_rules! rcc_peripheral { - ($adc_name:ident, $freqs:ident, $ahb:ident, $reg:ident $(, $counter:ident )? ) => { - impl crate::rcc::sealed::RccPeripheral for crate::peripherals::$adc_name { - fn frequency() -> crate::time::Hertz { - critical_section::with(|_| { - match unsafe { crate::rcc::get_freqs() }.$freqs { - Some(ck) => ck, - None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") - } - }) - } - - fn enable() { - critical_section::with(|_| { - paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](true))} - }); - $ ( $counter.fetch_add(1, Ordering::SeqCst); )? - } - - fn disable() { - $ ( if $counter.load(Ordering::SeqCst) == 1 )? { - critical_section::with(|_| { - paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](false))} - }) - } - $ ( $counter.fetch_sub(1, Ordering::SeqCst); )? - } - - fn reset() { - $ ( if $counter.load(Ordering::SeqCst) == 1 )? { - critical_section::with(|_| { - paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](true))} - paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](false))} - }); - } - } - } - - impl crate::rcc::RccPeripheral for crate::peripherals::$adc_name {} - }; -} - -#[cfg(stm32g4)] -foreach_peripheral!( - (adc, ADC1) => { rcc_peripheral!(ADC1, adc, ahb2, adc12, ADC12_ENABLE_COUNTER); }; - (adc, ADC2) => { rcc_peripheral!(ADC2, adc, ahb2, adc12, ADC12_ENABLE_COUNTER); }; -); - -#[cfg(stm32g4x1)] -foreach_peripheral!( - (adc, ADC3) => { rcc_peripheral!(ADC3, adc34, ahb2, adc345); }; -); - -#[cfg(any(stm32g4x3, stm32g4x4))] -foreach_peripheral!( - (adc, ADC3) => { rcc_peripheral!(ADC3, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; - (adc, ADC4) => { rcc_peripheral!(ADC4, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; - (adc, ADC5) => { rcc_peripheral!(ADC5, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; -); - -#[cfg(stm32h7)] -foreach_peripheral!( - (adc, ADC1) => { rcc_peripheral!(ADC1, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); }; - (adc, ADC2) => { rcc_peripheral!(ADC2, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); }; - (adc, ADC3) => { rcc_peripheral!(ADC3, adc, ahb4, adc3); }; -); - // NOTE (unused): The prescaler enum closely copies the hardware capabilities, // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. #[allow(unused)] From f4601af2a4bbedc32a3c270696a8de2ed743b6d6 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 17:48:20 -0500 Subject: [PATCH 111/233] stm32: don't generate adc4 for g4 --- embassy-stm32/src/adc/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 023a94f2..bdb1ab8a 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -104,6 +104,7 @@ foreach_peripheral!( impl crate::adc::Instance for peripherals::ADC3 {} }; (adc, ADC4) => { + #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::sealed::Instance for peripherals::ADC4 { fn regs() -> crate::pac::adc::Adc { crate::pac::ADC4 @@ -123,6 +124,7 @@ foreach_peripheral!( } } + #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::Instance for peripherals::ADC4 {} }; (adc, $inst:ident) => { From 73070987804023f50fcc4a264de8371fbba723d2 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 17:50:45 -0500 Subject: [PATCH 112/233] stm32: don't generate adc5 --- embassy-stm32/src/adc/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index bdb1ab8a..0eeadfa9 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -126,6 +126,9 @@ foreach_peripheral!( #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::Instance for peripherals::ADC4 {} + }; + (adc, ADC5) => { + }; (adc, $inst:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { From 6770d8e8a690ca42a695105303784f4fc9796f6a Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 6 Sep 2023 00:04:09 +0100 Subject: [PATCH 113/233] Allow the RTC clock source to be configured with the new RTC mechanism --- embassy-stm32/src/rcc/f2.rs | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index 9d9bc59f..8b655624 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -4,8 +4,10 @@ use core::ops::{Div, Mul}; pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; -use crate::pac::{FLASH, RCC}; +use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::bd::BackupDomain; use crate::rcc::{set_freqs, Clocks}; +use crate::rtc::RtcClockSource; use crate::time::Hertz; /// HSI speed @@ -288,6 +290,7 @@ pub struct Config { pub pll_mux: PLLSrc, pub pll: PLLConfig, pub mux: ClockSrc, + pub rtc: Option, pub voltage: VoltageScale, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, @@ -304,6 +307,7 @@ impl Default for Config { pll: PLLConfig::default(), voltage: VoltageScale::Scale3, mux: ClockSrc::HSI, + rtc: None, ahb_pre: AHBPrescaler::NotDivided, apb1_pre: APBPrescaler::NotDivided, apb2_pre: APBPrescaler::NotDivided, @@ -414,6 +418,37 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().modify(|w| w.set_hsion(false)); } + RCC.apb1enr().modify(|w| w.set_pwren(true)); + PWR.cr().read(); + + match config.rtc { + Some(RtcClockSource::LSE) => { + // 1. Unlock the backup domain + PWR.cr().modify(|w| w.set_dbp(true)); + + // 2. Setup the LSE + RCC.bdcr().modify(|w| { + // Enable LSE + w.set_lseon(true); + }); + + // Wait until LSE is running + while !RCC.bdcr().read().lserdy() {} + + BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); + } + Some(RtcClockSource::LSI) => { + // Turn on the internal 32 kHz LSI oscillator + RCC.csr().modify(|w| w.set_lsion(true)); + + // Wait until LSI is running + while !RCC.csr().read().lsirdy() {} + + BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); + } + _ => todo!(), + } + set_freqs(Clocks { sys: sys_clk, ahb1: ahb_freq, From 50116e5b27c6b685cecfcdb4bf668a71664a770c Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 18:20:17 -0500 Subject: [PATCH 114/233] remove paste dependency --- embassy-stm32/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 712996f2..30694596 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -70,7 +70,6 @@ embedded-io-async = { version = "0.5.0", optional = true } chrono = { version = "^0.4", default-features = false, optional = true} bit_field = "0.10.2" document-features = "0.2.7" -paste = "1.0" [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } From bb2d6c854273ea57eb7d898c0f67dd9f8020f3e7 Mon Sep 17 00:00:00 2001 From: Olle Sandberg Date: Tue, 5 Sep 2023 12:10:31 +0200 Subject: [PATCH 115/233] adc_v3: replace cfg(stm32g0) + friends with cfg(adc_g0) Since any MCU (not just STM32G0) using adc_g0 should probably be handled the same way. --- embassy-stm32/src/adc/mod.rs | 4 ++-- embassy-stm32/src/adc/v3.rs | 39 +++++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 0eeadfa9..013debca 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -33,7 +33,7 @@ pub struct Adc<'d, T: Instance> { pub(crate) mod sealed { pub trait Instance { fn regs() -> crate::pac::adc::Adc; - #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] + #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz; @@ -63,7 +63,7 @@ foreach_peripheral!( fn regs() -> crate::pac::adc::Adc { crate::pac::$inst } - #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] + #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { foreach_peripheral!{ (adccommon, $common_inst:ident) => { diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 821cc7f6..7d63b0ce 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -26,9 +26,9 @@ pub struct VrefInt; impl AdcPin for VrefInt {} impl super::sealed::AdcPin for VrefInt { fn channel(&self) -> u8 { - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] let val = 0; - #[cfg(stm32g0)] + #[cfg(adc_g0)] let val = 13; val } @@ -38,9 +38,9 @@ pub struct Temperature; impl AdcPin for Temperature {} impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] let val = 17; - #[cfg(stm32g0)] + #[cfg(adc_g0)] let val = 12; val } @@ -50,9 +50,9 @@ pub struct Vbat; impl AdcPin for Vbat {} impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] let val = 18; - #[cfg(stm32g0)] + #[cfg(adc_g0)] let val = 14; val } @@ -92,9 +92,14 @@ impl<'d, T: Instance> Adc<'d, T> { } pub fn enable_vrefint(&self, delay: &mut impl DelayUs) -> VrefInt { + #[cfg(not(adc_g0))] T::common_regs().ccr().modify(|reg| { reg.set_vrefen(true); }); + #[cfg(adc_g0)] + T::regs().ccr().modify(|reg| { + reg.set_vrefen(true); + }); // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us // to stabilize the internal voltage reference, we wait a little more. @@ -106,17 +111,27 @@ impl<'d, T: Instance> Adc<'d, T> { } pub fn enable_temperature(&self) -> Temperature { + #[cfg(not(adc_g0))] T::common_regs().ccr().modify(|reg| { reg.set_ch17sel(true); }); + #[cfg(adc_g0)] + T::regs().ccr().modify(|reg| { + reg.set_tsen(true); + }); Temperature {} } pub fn enable_vbat(&self) -> Vbat { + #[cfg(not(adc_g0))] T::common_regs().ccr().modify(|reg| { reg.set_ch18sel(true); }); + #[cfg(adc_g0)] + T::regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); Vbat {} } @@ -126,9 +141,9 @@ impl<'d, T: Instance> Adc<'d, T> { } pub fn set_resolution(&mut self, resolution: Resolution) { - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); - #[cfg(stm32g0)] + #[cfg(adc_g0)] T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); } @@ -182,9 +197,9 @@ impl<'d, T: Instance> Adc<'d, T> { Self::set_channel_sample_time(pin.channel(), self.sample_time); // Select channel - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); - #[cfg(stm32g0)] + #[cfg(adc_g0)] T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); // Some models are affected by an erratum: @@ -203,12 +218,12 @@ impl<'d, T: Instance> Adc<'d, T> { val } - #[cfg(stm32g0)] + #[cfg(adc_g0)] fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); } - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { let sample_time = sample_time.into(); T::regs() From 0d3ff34d80c98f62a1f6e8b4df1226f6c36337a0 Mon Sep 17 00:00:00 2001 From: Olle Sandberg Date: Tue, 5 Sep 2023 12:14:04 +0200 Subject: [PATCH 116/233] adc: enable ADC and clock selection for STM32WLx --- embassy-stm32/src/adc/v3.rs | 2 +- embassy-stm32/src/rcc/wl.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 7d63b0ce..011ecc28 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -13,7 +13,7 @@ pub const VREF_CALIB_MV: u32 = 3000; /// configuration. fn enable() { critical_section::with(|_| { - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32wl))] crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); #[cfg(stm32g0)] crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index e33690d1..47be00ad 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,4 +1,5 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; +use crate::pac::rcc::vals::Adcsel; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; @@ -106,6 +107,29 @@ impl Into for MSIRange { } } +#[derive(Clone, Copy)] +pub enum AdcClockSource { + HSI16, + PLLPCLK, + SYSCLK, +} + +impl AdcClockSource { + pub fn adcsel(&self) -> Adcsel { + match self { + AdcClockSource::HSI16 => Adcsel::HSI16, + AdcClockSource::PLLPCLK => Adcsel::PLLPCLK, + AdcClockSource::SYSCLK => Adcsel::SYSCLK, + } + } +} + +impl Default for AdcClockSource { + fn default() -> Self { + Self::HSI16 + } +} + /// Clocks configutation pub struct Config { pub mux: ClockSrc, @@ -116,6 +140,7 @@ pub struct Config { pub enable_lsi: bool, pub enable_rtc_apb: bool, pub rtc_mux: RtcClockSource, + pub adc_clock_source: AdcClockSource, } impl Default for Config { @@ -130,6 +155,7 @@ impl Default for Config { enable_lsi: false, enable_rtc_apb: false, rtc_mux: RtcClockSource::LSI, + adc_clock_source: AdcClockSource::default(), } } } @@ -299,6 +325,9 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre2(config.apb2_pre.into()); }); + // ADC clock MUX + RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel())); + // TODO: switch voltage range if config.enable_lsi { From c356585a5918f1c66f5fc0e12edd82094dacd5c9 Mon Sep 17 00:00:00 2001 From: Olle Sandberg Date: Wed, 6 Sep 2023 11:49:18 +0200 Subject: [PATCH 117/233] update metapac tag --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 30694596..ded58aee 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7e2310f49fa123fbc3225b91be73522b212703f0" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-eaa4987e523408dfb31c1b76765dd345d2761373" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -77,7 +77,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7e2310f49fa123fbc3225b91be73522b212703f0", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-eaa4987e523408dfb31c1b76765dd345d2761373", default-features = false, features = ["metadata"]} [features] default = ["rt"] From d097c99719f31aa68afdedde09149d6de1d0b600 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 6 Sep 2023 17:33:56 -0500 Subject: [PATCH 118/233] stm32/rcc: add lsi and lse bd abstraction --- embassy-stm32/src/rcc/bd.rs | 76 ++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 4d8ed82a..b4d21c35 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -1,6 +1,34 @@ +#[allow(dead_code)] +#[derive(Default)] +pub enum LseDrive { + #[cfg(any(rtc_v2f7, rtc_v2l4))] + Low = 0, + MediumLow = 0x01, + #[default] + MediumHigh = 0x02, + #[cfg(any(rtc_v2f7, rtc_v2l4))] + High = 0x03, +} + +#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] +impl From for crate::pac::rcc::vals::Lsedrv { + fn from(value: LseDrive) -> Self { + use crate::pac::rcc::vals::Lsedrv; + + match value { + #[cfg(any(rtc_v2f7, rtc_v2l4))] + LseDrive::Low => Lsedrv::LOW, + LseDrive::MediumLow => Lsedrv::MEDIUMLOW, + LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, + #[cfg(any(rtc_v2f7, rtc_v2l4))] + LseDrive::High => Lsedrv::HIGH, + } + } +} + +#[allow(dead_code)] #[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] -#[allow(dead_code)] pub enum RtcClockSource { /// 00: No clock NoClock = 0b00, @@ -66,6 +94,38 @@ impl BackupDomain { r } + #[allow(dead_code, unused_variables)] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + pub fn enable_lse(lse_drive: LseDrive) { + Self::modify(|w| { + #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] + w.set_lsedrv(lse_drive.into()); + w.set_lseon(true); + }); + + while !Self::read().lserdy() {} + } + + #[allow(dead_code)] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + pub fn enable_lsi() { + let csr = crate::pac::RCC.csr(); + + Self::modify(|_| { + #[cfg(not(rtc_v2wb))] + csr.modify(|w| w.set_lsion(true)); + + #[cfg(rtc_v2wb)] + csr.modify(|w| w.set_lsi1on(true)); + }); + + #[cfg(not(rtc_v2wb))] + while !csr.read().lsirdy() {} + + #[cfg(rtc_v2wb)] + while !csr.read().lsi1rdy() {} + } + #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5 @@ -74,7 +134,7 @@ impl BackupDomain { pub fn set_rtc_clock_source(clock_source: RtcClockSource) { let clock_source = clock_source as u8; #[cfg(any( - all(not(any(rtc_v3, rtc_v3u5)), not(rtc_v2wb)), + not(any(rtc_v3, rtc_v3u5, rtc_v2wb)), all(any(rtc_v3, rtc_v3u5), not(any(rcc_wl5, rcc_wle))) ))] let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); @@ -86,6 +146,18 @@ impl BackupDomain { }); } + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + #[allow(dead_code, unused_variables)] + pub fn configure_rtc(clock_source: RtcClockSource, lse_drive: Option) { + match clock_source { + RtcClockSource::LSI => Self::enable_lsi(), + RtcClockSource::LSE => Self::enable_lse(lse_drive.unwrap_or_default()), + _ => {} + }; + + Self::set_rtc_clock_source(clock_source); + } + #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5 From c21ad04c2ed2e5bd0c0e53ded4be8d1c4c4a1bc3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 6 Sep 2023 17:48:12 -0500 Subject: [PATCH 119/233] stm32: extract lse/lsi into bd mod --- embassy-stm32/src/rcc/bd.rs | 6 +++--- embassy-stm32/src/rcc/l4.rs | 35 +++-------------------------------- embassy-stm32/src/rcc/wb.rs | 14 +------------- embassy-stm32/src/rcc/wl.rs | 33 ++------------------------------- 4 files changed, 9 insertions(+), 79 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index b4d21c35..34b88458 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -95,7 +95,7 @@ impl BackupDomain { } #[allow(dead_code, unused_variables)] - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] pub fn enable_lse(lse_drive: LseDrive) { Self::modify(|w| { #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] @@ -107,7 +107,7 @@ impl BackupDomain { } #[allow(dead_code)] - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] pub fn enable_lsi() { let csr = crate::pac::RCC.csr(); @@ -146,7 +146,7 @@ impl BackupDomain { }); } - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] #[allow(dead_code, unused_variables)] pub fn configure_rtc(clock_source: RtcClockSource, lse_drive: Option) { match clock_source { diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index c6bccfd2..0083ae5b 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -2,13 +2,13 @@ use core::marker::PhantomData; use embassy_hal_internal::into_ref; use stm32_metapac::rcc::regs::Cfgr; -use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel}; +use stm32_metapac::rcc::vals::{Mcopre, Mcosel}; pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; -use crate::pac::{FLASH, PWR, RCC}; +use crate::pac::{FLASH, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -407,36 +407,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr1().modify(|w| w.set_pwren(true)); - match config.rtc_mux { - RtcClockSource::LSE => { - // 1. Unlock the backup domain - PWR.cr1().modify(|w| w.set_dbp(true)); - - // 2. Setup the LSE - RCC.bdcr().modify(|w| { - // Enable LSE - w.set_lseon(true); - // Max drive strength - // TODO: should probably be settable - w.set_lsedrv(Lsedrv::HIGH); - }); - - // Wait until LSE is running - while !RCC.bdcr().read().lserdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); - } - RtcClockSource::LSI => { - // Turn on the internal 32 kHz LSI oscillator - RCC.csr().modify(|w| w.set_lsion(true)); - - // Wait until LSI is running - while !RCC.csr().read().lsirdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); - } - _ => unreachable!(), - } + BackupDomain::configure_rtc(config.rtc_mux, None); let (sys_clk, sw) = match config.mux { ClockSrc::MSI(range) => { diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index 6496b41e..efd96464 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -293,18 +293,6 @@ pub(crate) fn configure_clocks(config: &Config) { while !rcc.cr().read().hsirdy() {} } - let needs_lsi = if let Some(rtc_mux) = &config.rtc { - *rtc_mux == RtcClockSource::LSI - } else { - false - }; - - if needs_lsi { - rcc.csr().modify(|w| w.set_lsi1on(true)); - - while !rcc.csr().read().lsi1rdy() {} - } - match &config.lse { Some(_) => { rcc.cfgr().modify(|w| w.set_stopwuck(true)); @@ -378,5 +366,5 @@ pub(crate) fn configure_clocks(config: &Config) { config .rtc - .map(|clock_source| BackupDomain::set_rtc_clock_source(clock_source)); + .map(|clock_source| BackupDomain::configure_rtc(clock_source, None)); } diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index e33690d1..b3ddbae6 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,5 +1,5 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; -use crate::pac::{FLASH, PWR, RCC}; +use crate::pac::{FLASH, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -208,36 +208,7 @@ pub(crate) unsafe fn init(config: Config) { while FLASH.acr().read().latency() != ws {} - match config.rtc_mux { - RtcClockSource::LSE => { - // 1. Unlock the backup domain - PWR.cr1().modify(|w| w.set_dbp(true)); - - // 2. Setup the LSE - RCC.bdcr().modify(|w| { - // Enable LSE - w.set_lseon(true); - // Max drive strength - // TODO: should probably be settable - w.set_lsedrv(Lsedrv::High as u8); //---// PAM - should not be commented - }); - - // Wait until LSE is running - while !RCC.bdcr().read().lserdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); - } - RtcClockSource::LSI => { - // Turn on the internal 32 kHz LSI oscillator - RCC.csr().modify(|w| w.set_lsion(true)); - - // Wait until LSI is running - while !RCC.csr().read().lsirdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); - } - _ => unreachable!(), - } + BackupDomain::configure_rtc(config.rtc_mux, None); match config.mux { ClockSrc::HSI16 => { From 08410432b5112536ff53b5012601649f27ca9eb1 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 6 Sep 2023 17:51:40 -0500 Subject: [PATCH 120/233] stm32: fix rcc merge --- embassy-stm32/src/rcc/wl.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 92bb0796..cd91c8a7 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,5 +1,6 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; use crate::pac::rcc::vals::Adcsel; +use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; From 4550452f43648533ea6e3a5a92a5e643d59bd617 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 6 Sep 2023 17:53:02 -0500 Subject: [PATCH 121/233] rustfmt --- embassy-stm32/src/rcc/wl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index cd91c8a7..7a03d906 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,6 +1,6 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; use crate::pac::rcc::vals::Adcsel; -use crate::pac::{FLASH, PWR, RCC}; +use crate::pac::{FLASH, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; From 9de08d56a087d946bb768ed164aed459b0a2ce3c Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 6 Sep 2023 23:15:33 +0300 Subject: [PATCH 122/233] nrf: spim: Anomaly 109 workaround for SPIM peripheral (#460) This implements SPIM TX workaround suggested from section 3.8.1 from Anomaly 109 addendum. In workaround case we first keep track of original maxcnt values, then initiate "fake" transfer with zero-length maxcnt values. Once the "fake" transfer is triggered, we handle it, fill in the original maxcnt values and restart the transmission. --- embassy-nrf/src/spim.rs | 60 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index d131a43d..a468bc30 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -68,6 +68,28 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); + #[cfg(feature = "nrf52832")] + // NRF32 Anomaly 109 workaround... NRF52832 + if r.intenset.read().started().is_enabled() && r.events_started.read().bits() != 0 { + // Handle the first "fake" transmission + r.events_started.reset(); + r.events_end.reset(); + + // Update DMA registers with correct rx/tx buffer sizes + r.rxd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) }); + r.txd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) }); + + // Disable interrupt for STARTED event... + r.intenclr.write(|w| w.started().clear()); + // ... and start actual, hopefully glitch-free transmission + r.tasks_start.write(|w| unsafe { w.bits(1) }); + return; + } + if r.events_end.read().bits() != 0 { s.end_waker.wake(); r.intenclr.write(|w| w.end().clear()); @@ -223,14 +245,33 @@ impl<'d, T: Instance> Spim<'d, T> { let r = T::regs(); // Set up the DMA write. - let (ptr, len) = slice_ptr_parts(tx); + let (ptr, tx_len) = slice_ptr_parts(tx); r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); - r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) }); // Set up the DMA read. - let (ptr, len) = slice_ptr_parts_mut(rx); + let (ptr, rx_len) = slice_ptr_parts_mut(rx); r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); + + // ANOMALY 109 workaround + #[cfg(feature = "nrf52832")] + { + let s = T::state(); + + r.events_started.reset(); + + // Set rx/tx buffer lengths to 0... + r.txd.maxcnt.reset(); + r.rxd.maxcnt.reset(); + + // ...and keep track of original buffer lengths... + s.tx.store(tx_len as _, Ordering::Relaxed); + s.rx.store(rx_len as _, Ordering::Relaxed); + + // ...signalling the start of the fake transfer. + r.intenset.write(|w| w.started().bit(true)); + } // Reset and enable the event r.events_end.reset(); @@ -386,18 +427,29 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { } pub(crate) mod sealed { + #[cfg(feature = "nrf52832")] + use core::sync::atomic::AtomicU8; + use embassy_sync::waitqueue::AtomicWaker; use super::*; pub struct State { pub end_waker: AtomicWaker, + #[cfg(feature = "nrf52832")] + pub rx: AtomicU8, + #[cfg(feature = "nrf52832")] + pub tx: AtomicU8, } impl State { pub const fn new() -> Self { Self { end_waker: AtomicWaker::new(), + #[cfg(feature = "nrf52832")] + rx: AtomicU8::new(0), + #[cfg(feature = "nrf52832")] + tx: AtomicU8::new(0), } } } From d6a1118406deb1cb4cf6317dfbbacf12ff9c7d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Thu, 7 Sep 2023 21:02:33 +0200 Subject: [PATCH 123/233] fix some spelling --- embassy-net-adin1110/src/lib.rs | 4 ++-- embassy-net-adin1110/src/mdio.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index e0af7bde..78bf9fb8 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -427,9 +427,9 @@ impl mdio::MdioBus for ADIN1110 { } } -/// Background runner for the ADIN110. +/// Background runner for the ADIN1110. /// -/// You must call `.run()` in a background task for the ADIN1100 to operate. +/// You must call `.run()` in a background task for the ADIN1110 to operate. pub struct Runner<'d, SPI, INT, RST> { mac: ADIN1110, ch: ch::Runner<'d, MTU>, diff --git a/embassy-net-adin1110/src/mdio.rs b/embassy-net-adin1110/src/mdio.rs index 68477006..60abbe16 100644 --- a/embassy-net-adin1110/src/mdio.rs +++ b/embassy-net-adin1110/src/mdio.rs @@ -36,7 +36,7 @@ enum Reg13Op { /// Driver needs to implement the Clause 22 /// Optional Clause 45 is the device supports this. /// -/// Claus 45 methodes are bases on +/// Clause 45 methodes are bases on pub trait MdioBus { type Error; From 336ae54a5636bf02c0c7b98b0dd59e4cff5d5192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Thu, 7 Sep 2023 21:08:49 +0200 Subject: [PATCH 124/233] mdio: reenable and async the tests --- embassy-net-adin1110/src/mdio.rs | 147 ++++++++++++++++--------------- 1 file changed, 74 insertions(+), 73 deletions(-) diff --git a/embassy-net-adin1110/src/mdio.rs b/embassy-net-adin1110/src/mdio.rs index 60abbe16..1ae5f004 100644 --- a/embassy-net-adin1110/src/mdio.rs +++ b/embassy-net-adin1110/src/mdio.rs @@ -32,6 +32,7 @@ enum Reg13Op { PostReadIncAddr = 0b10 << 14, Read = 0b11 << 14, } + /// `MdioBus` trait /// Driver needs to implement the Clause 22 /// Optional Clause 45 is the device supports this. @@ -87,89 +88,89 @@ pub trait MdioBus { } } -// #[cfg(test)] -// mod tests { -// use core::convert::Infallible; +#[cfg(test)] +mod tests { + use core::convert::Infallible; -// use super::{MdioBus, PhyAddr, RegC22, RegVal}; + use super::{MdioBus, PhyAddr, RegC22, RegVal}; -// #[derive(Debug, PartialEq, Eq)] -// enum A { -// Read(PhyAddr, RegC22), -// Write(PhyAddr, RegC22, RegVal), -// } + #[derive(Debug, PartialEq, Eq)] + enum A { + Read(PhyAddr, RegC22), + Write(PhyAddr, RegC22, RegVal), + } -// struct MockMdioBus(Vec); + struct MockMdioBus(Vec); -// impl MockMdioBus { -// pub fn clear(&mut self) { -// self.0.clear(); -// } -// } + impl MockMdioBus { + pub fn clear(&mut self) { + self.0.clear(); + } + } -// impl MdioBus for MockMdioBus { -// type Error = Infallible; + impl MdioBus for MockMdioBus { + type Error = Infallible; -// fn write_cl22( -// &mut self, -// phy_id: super::PhyAddr, -// reg: super::RegC22, -// reg_val: super::RegVal, -// ) -> Result<(), Self::Error> { -// self.0.push(A::Write(phy_id, reg, reg_val)); -// Ok(()) -// } + async fn write_cl22( + &mut self, + phy_id: super::PhyAddr, + reg: super::RegC22, + reg_val: super::RegVal, + ) -> Result<(), Self::Error> { + self.0.push(A::Write(phy_id, reg, reg_val)); + Ok(()) + } -// fn read_cl22( -// &mut self, -// phy_id: super::PhyAddr, -// reg: super::RegC22, -// ) -> Result { -// self.0.push(A::Read(phy_id, reg)); -// Ok(0) -// } -// } + async fn read_cl22( + &mut self, + phy_id: super::PhyAddr, + reg: super::RegC22, + ) -> Result { + self.0.push(A::Read(phy_id, reg)); + Ok(0) + } + } -// #[test] -// fn read_test() { -// let mut mdiobus = MockMdioBus(Vec::with_capacity(20)); + #[futures_test::test] + async fn read_test() { + let mut mdiobus = MockMdioBus(Vec::with_capacity(20)); -// mdiobus.clear(); -// mdiobus.read_cl22(0x01, 0x00).unwrap(); -// assert_eq!(mdiobus.0, vec![A::Read(0x01, 0x00)]); + mdiobus.clear(); + mdiobus.read_cl22(0x01, 0x00).await.unwrap(); + assert_eq!(mdiobus.0, vec![A::Read(0x01, 0x00)]); -// mdiobus.clear(); -// mdiobus.read_cl45(0x01, (0xBB, 0x1234)).unwrap(); -// assert_eq!( -// mdiobus.0, -// vec![ -// #[allow(clippy::identity_op)] -// A::Write(0x01, 13, (0b00 << 14) | 27), -// A::Write(0x01, 14, 0x1234), -// A::Write(0x01, 13, (0b11 << 14) | 27), -// A::Read(0x01, 14) -// ] -// ); -// } + mdiobus.clear(); + mdiobus.read_cl45(0x01, (0xBB, 0x1234)).await.unwrap(); + assert_eq!( + mdiobus.0, + vec![ + #[allow(clippy::identity_op)] + A::Write(0x01, 13, (0b00 << 14) | 27), + A::Write(0x01, 14, 0x1234), + A::Write(0x01, 13, (0b11 << 14) | 27), + A::Read(0x01, 14) + ] + ); + } -// #[test] -// fn write_test() { -// let mut mdiobus = MockMdioBus(Vec::with_capacity(20)); + #[futures_test::test] + async fn write_test() { + let mut mdiobus = MockMdioBus(Vec::with_capacity(20)); -// mdiobus.clear(); -// mdiobus.write_cl22(0x01, 0x00, 0xABCD).unwrap(); -// assert_eq!(mdiobus.0, vec![A::Write(0x01, 0x00, 0xABCD)]); + mdiobus.clear(); + mdiobus.write_cl22(0x01, 0x00, 0xABCD).await.unwrap(); + assert_eq!(mdiobus.0, vec![A::Write(0x01, 0x00, 0xABCD)]); -// mdiobus.clear(); -// mdiobus.write_cl45(0x01, (0xBB, 0x1234), 0xABCD).unwrap(); -// assert_eq!( -// mdiobus.0, -// vec![ -// A::Write(0x01, 13, 27), -// A::Write(0x01, 14, 0x1234), -// A::Write(0x01, 13, (0b01 << 14) | 27), -// A::Write(0x01, 14, 0xABCD) -// ] -// ); -// } -// } + mdiobus.clear(); + mdiobus.write_cl45(0x01, (0xBB, 0x1234), 0xABCD).await.unwrap(); + assert_eq!( + mdiobus.0, + vec![ + A::Write(0x01, 13, 27), + A::Write(0x01, 14, 0x1234), + A::Write(0x01, 13, (0b01 << 14) | 27), + A::Write(0x01, 14, 0xABCD) + ] + ); + } +} From c27b0296fe5abcdff87df31adcbe9774c54d239b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Thu, 7 Sep 2023 22:32:20 +0200 Subject: [PATCH 125/233] Add more documentation and comment --- embassy-net-adin1110/src/lib.rs | 7 +++++++ embassy-net-adin1110/src/phy.rs | 1 + 2 files changed, 8 insertions(+) diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 78bf9fb8..53f36128 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -32,6 +32,7 @@ pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1}; use crate::fmt::Bytes; use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader}; +/// ADIN1110 intern PHY ID pub const PHYID: u32 = 0x0283_BC91; /// Error values ADIN1110 @@ -53,7 +54,9 @@ pub enum AdinError { MDIO_ACC_TIMEOUT, } +/// Type alias `Result` type with `AdinError` as error type. pub type AEResult = core::result::Result>; + /// Internet PHY address pub const MDIO_PHY_ADDR: u8 = 0x01; @@ -104,6 +107,7 @@ impl State { } } +/// ADIN1110 embassy-net driver #[derive(Debug)] pub struct ADIN1110 { /// SPI bus @@ -116,6 +120,7 @@ pub struct ADIN1110 { } impl ADIN1110 { + /// Create a new ADIN1110 instance. pub fn new(spi: SPI, spi_crc: bool, append_fcs_on_tx: bool) -> Self { Self { spi, @@ -124,6 +129,7 @@ impl ADIN1110 { } } + /// Read a SPI register pub async fn read_reg(&mut self, reg: sr) -> AEResult { let mut tx_buf = Vec::::new(); @@ -162,6 +168,7 @@ impl ADIN1110 { Ok(value) } + /// Write a SPI register pub async fn write_reg(&mut self, reg: sr, value: u32) -> AEResult<(), SPI::Error> { let mut tx_buf = Vec::::new(); diff --git a/embassy-net-adin1110/src/phy.rs b/embassy-net-adin1110/src/phy.rs index 176ad019..d54d843d 100644 --- a/embassy-net-adin1110/src/phy.rs +++ b/embassy-net-adin1110/src/phy.rs @@ -111,6 +111,7 @@ pub mod RegsC45 { } } +/// 10-BASE-T1x PHY functions. pub struct Phy10BaseT1x(u8); impl Default for Phy10BaseT1x { From a4f8d82ef51b7c0c775168472829ecd18d8f84d8 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:58:47 +0200 Subject: [PATCH 126/233] wait_config_up first steps --- embassy-net/src/lib.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index c2575267..8289ecdd 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -226,6 +226,7 @@ struct Inner { static_v6: Option, #[cfg(feature = "dhcpv4")] dhcp_socket: Option, + config_waker: WakerRegistration, #[cfg(feature = "dns")] dns_socket: SocketHandle, #[cfg(feature = "dns")] @@ -297,6 +298,7 @@ impl Stack { static_v6: None, #[cfg(feature = "dhcpv4")] dhcp_socket: None, + config_waker: WakerRegistration::new(), #[cfg(feature = "dns")] dns_socket: socket.sockets.add(dns::Socket::new( &[], @@ -363,6 +365,28 @@ impl Stack { v4_up || v6_up } + /// Get for the network stack to obtainer a valid IP configuration. + pub async fn wait_config_up(&self) { + if self.is_config_up() { + return; + } + + poll_fn(|cx| { + self.with_mut(|_, i| { + debug!("poll_fn called"); + if self.is_config_up() { + debug!("poll_fn ready"); + Poll::Ready(()) + } else { + debug!("poll_fn pending"); + i.config_waker.register(cx.waker()); + Poll::Pending + } + }) + }) + .await; + } + /// Get the current IPv4 configuration. /// /// If using DHCP, this will be None if DHCP hasn't been able to @@ -706,6 +730,8 @@ impl Inner { s.sockets .get_mut::(self.dns_socket) .update_servers(&dns_servers[..]); + + s.waker.wake(); } fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { From 6070d61d8ce2d9ce416467ac6aac8ffdd89a59b9 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:59:46 +0200 Subject: [PATCH 127/233] fix typos --- embassy-net/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 8289ecdd..9eea8cb4 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -365,7 +365,7 @@ impl Stack { v4_up || v6_up } - /// Get for the network stack to obtainer a valid IP configuration. + /// Wait for the network stack to obtaine a valid IP configuration. pub async fn wait_config_up(&self) { if self.is_config_up() { return; From 3e0b752befd492229bfb4c6f9fd3213cfd69a0fc Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 8 Sep 2023 17:26:01 +0200 Subject: [PATCH 128/233] fix poll_fn, add documentation --- embassy-net/src/lib.rs | 53 ++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 9eea8cb4..4922490d 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -172,6 +172,7 @@ impl Config { /// /// # Example /// ```rust + /// # use embassy_net::Config; /// let _cfg = Config::dhcpv4(Default::default()); /// ``` #[cfg(feature = "dhcpv4")] @@ -365,24 +366,52 @@ impl Stack { v4_up || v6_up } - /// Wait for the network stack to obtaine a valid IP configuration. + /// Wait for the network stack to obtain a valid IP configuration. + /// Returns instantly if [`Stack::is_config_up`] returns `true`. + /// + /// ## Watch out: + /// The Future is polled only when the [`Stack`] is running, + /// e.g. call `spawner.spawn(net_task(stack))`. + /// + /// `await`ing before will never yield! + /// + /// ## Example + /// ```ignore + /// let config = embassy_net::Config::dhcpv4(Default::default()); + ///// Init network stack + /// let stack = &*make_static!(embassy_net::Stack::new( + /// device, + /// config, + /// make_static!(embassy_net::StackResources::<2>::new()), + /// seed + /// )); + /// // Launch network task + /// spawner.spawn(net_task(stack)).unwrap(); + /// // Wait for DHCP config + /// stack.wait_config_up().await; + /// // use the network stack + /// // ... + /// ``` pub async fn wait_config_up(&self) { + // If the config is up already, we can return immediately. if self.is_config_up() { return; } poll_fn(|cx| { - self.with_mut(|_, i| { - debug!("poll_fn called"); - if self.is_config_up() { - debug!("poll_fn ready"); - Poll::Ready(()) - } else { - debug!("poll_fn pending"); + if self.is_config_up() { + Poll::Ready(()) + } else { + // If the config is not up, we register a waker that is woken up + // when a config is applied (static or DHCP). + trace!("Waiting for config up"); + + self.with_mut(|_, i| { i.config_waker.register(cx.waker()); - Poll::Pending - } - }) + }); + + Poll::Pending + } }) .await; } @@ -731,7 +760,7 @@ impl Inner { .get_mut::(self.dns_socket) .update_servers(&dns_servers[..]); - s.waker.wake(); + self.config_waker.wake(); } fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { From cf2d4eca7c3a3f53aa57a7d9a53de490962019cf Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 8 Sep 2023 17:40:20 +0200 Subject: [PATCH 129/233] add wait_config_up to examples --- examples/stm32f4/src/bin/eth.rs | 5 ++++- examples/stm32f7/src/bin/eth.rs | 5 ++++- examples/stm32h5/src/bin/eth.rs | 3 +++ examples/stm32h7/src/bin/eth.rs | 3 +++ examples/stm32h7/src/bin/eth_client.rs | 8 ++++---- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 393e60b7..5f1e62d0 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -79,7 +79,10 @@ async fn main(spawner: Spawner) -> ! { )); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(stack))); + + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; info!("Network task initialized"); diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index f0e280c3..01c38106 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -80,7 +80,10 @@ async fn main(spawner: Spawner) -> ! { )); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(stack))); + + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; info!("Network task initialized"); diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 763520ab..c32e0fdb 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -101,6 +101,9 @@ async fn main(spawner: Spawner) -> ! { // Launch network task unwrap!(spawner.spawn(net_task(&stack))); + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; + info!("Network task initialized"); // Then we can use it! diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 26a386e4..e691c6d0 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -83,6 +83,9 @@ async fn main(spawner: Spawner) -> ! { // Launch network task unwrap!(spawner.spawn(net_task(&stack))); + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; + info!("Network task initialized"); // Then we can use it! diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 6664410c..ebef54c3 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -82,13 +82,13 @@ async fn main(spawner: Spawner) -> ! { )); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(stack))); + + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; info!("Network task initialized"); - // To ensure DHCP configuration before trying connect - Timer::after(Duration::from_secs(20)).await; - static STATE: TcpClientState<1, 1024, 1024> = TcpClientState::new(); let client = TcpClient::new(&stack, &STATE); From 11a78fb1e4885604b6819253f97c20762fc0a23b Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 8 Sep 2023 18:20:58 -0500 Subject: [PATCH 130/233] rcc: more cleanup --- embassy-stm32/src/rcc/bd.rs | 73 ++++++++++++------------ embassy-stm32/src/rcc/f2.rs | 30 +--------- embassy-stm32/src/rcc/f4.rs | 14 +---- embassy-stm32/src/rcc/l4.rs | 2 +- embassy-stm32/src/rcc/wb.rs | 19 ++---- embassy-stm32/src/rcc/wl.rs | 23 +------- embassy-stm32/src/rtc/mod.rs | 2 +- embassy-stm32/src/rtc/v2.rs | 9 +++ embassy-stm32/src/rtc/v3.rs | 17 ++++++ examples/stm32wl/src/bin/lora_lorawan.rs | 2 +- examples/stm32wl/src/bin/random.rs | 2 +- examples/stm32wl/src/bin/rtc.rs | 1 - 12 files changed, 79 insertions(+), 115 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 34b88458..76d0f3a3 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -94,36 +94,49 @@ impl BackupDomain { r } + #[cfg(any( + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, + rtc_v3u5 + ))] #[allow(dead_code, unused_variables)] - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] - pub fn enable_lse(lse_drive: LseDrive) { - Self::modify(|w| { - #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] - w.set_lsedrv(lse_drive.into()); - w.set_lseon(true); - }); + pub fn configure_ls(clock_source: RtcClockSource, lse_drive: Option) { + match clock_source { + RtcClockSource::LSI => { + #[cfg(rtc_v3u5)] + let csr = crate::pac::RCC.bdcr(); - while !Self::read().lserdy() {} - } + #[cfg(not(rtc_v3u5))] + let csr = crate::pac::RCC.csr(); - #[allow(dead_code)] - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] - pub fn enable_lsi() { - let csr = crate::pac::RCC.csr(); + Self::modify(|_| { + #[cfg(not(rtc_v2wb))] + csr.modify(|w| w.set_lsion(true)); - Self::modify(|_| { - #[cfg(not(rtc_v2wb))] - csr.modify(|w| w.set_lsion(true)); + #[cfg(rtc_v2wb)] + csr.modify(|w| w.set_lsi1on(true)); + }); - #[cfg(rtc_v2wb)] - csr.modify(|w| w.set_lsi1on(true)); - }); + #[cfg(not(rtc_v2wb))] + while !csr.read().lsirdy() {} - #[cfg(not(rtc_v2wb))] - while !csr.read().lsirdy() {} + #[cfg(rtc_v2wb)] + while !csr.read().lsi1rdy() {} + } + RtcClockSource::LSE => { + let lse_drive = lse_drive.unwrap_or_default(); - #[cfg(rtc_v2wb)] - while !csr.read().lsi1rdy() {} + Self::modify(|w| { + #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] + w.set_lsedrv(lse_drive.into()); + w.set_lseon(true); + }); + + while !Self::read().lserdy() {} + } + _ => {} + }; + + Self::configure_rtc(clock_source); } #[cfg(any( @@ -131,7 +144,7 @@ impl BackupDomain { rtc_v3u5 ))] #[allow(dead_code, unused_variables)] - pub fn set_rtc_clock_source(clock_source: RtcClockSource) { + pub fn configure_rtc(clock_source: RtcClockSource) { let clock_source = clock_source as u8; #[cfg(any( not(any(rtc_v3, rtc_v3u5, rtc_v2wb)), @@ -146,18 +159,6 @@ impl BackupDomain { }); } - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] - #[allow(dead_code, unused_variables)] - pub fn configure_rtc(clock_source: RtcClockSource, lse_drive: Option) { - match clock_source { - RtcClockSource::LSI => Self::enable_lsi(), - RtcClockSource::LSE => Self::enable_lse(lse_drive.unwrap_or_default()), - _ => {} - }; - - Self::set_rtc_clock_source(clock_source); - } - #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5 diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index 8b655624..b821f958 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -421,33 +421,9 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr().modify(|w| w.set_pwren(true)); PWR.cr().read(); - match config.rtc { - Some(RtcClockSource::LSE) => { - // 1. Unlock the backup domain - PWR.cr().modify(|w| w.set_dbp(true)); - - // 2. Setup the LSE - RCC.bdcr().modify(|w| { - // Enable LSE - w.set_lseon(true); - }); - - // Wait until LSE is running - while !RCC.bdcr().read().lserdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); - } - Some(RtcClockSource::LSI) => { - // Turn on the internal 32 kHz LSI oscillator - RCC.csr().modify(|w| w.set_lsion(true)); - - // Wait until LSI is running - while !RCC.csr().read().lsirdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); - } - _ => todo!(), - } + config + .rtc + .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); set_freqs(Clocks { sys: sys_clk, diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index c2c78a45..f7bc0d99 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -461,17 +461,9 @@ pub(crate) unsafe fn init(config: Config) { }) }); - match config.rtc { - Some(RtcClockSource::LSI) => { - RCC.csr().modify(|w| w.set_lsion(true)); - while !RCC.csr().read().lsirdy() {} - } - _ => {} - } - - config.rtc.map(|clock_source| { - BackupDomain::set_rtc_clock_source(clock_source); - }); + config + .rtc + .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); let rtc = match config.rtc { Some(RtcClockSource::LSI) => Some(LSI_FREQ), diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 0083ae5b..41dbff01 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -407,7 +407,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr1().modify(|w| w.set_pwren(true)); - BackupDomain::configure_rtc(config.rtc_mux, None); + BackupDomain::configure_ls(config.rtc_mux, None); let (sys_clk, sw) = match config.mux { ClockSrc::MSI(range) => { diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index efd96464..d90a50cf 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -276,7 +276,6 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { } pub(crate) fn configure_clocks(config: &Config) { - let pwr = crate::pac::PWR; let rcc = crate::pac::RCC; let needs_hsi = if let Some(pll_mux) = &config.mux { @@ -293,17 +292,11 @@ pub(crate) fn configure_clocks(config: &Config) { while !rcc.cr().read().hsirdy() {} } - match &config.lse { - Some(_) => { - rcc.cfgr().modify(|w| w.set_stopwuck(true)); + rcc.cfgr().modify(|w| w.set_stopwuck(true)); - pwr.cr1().modify(|w| w.set_dbp(true)); - pwr.cr1().modify(|w| w.set_dbp(true)); - - rcc.bdcr().modify(|w| w.set_lseon(true)); - } - _ => {} - } + config + .rtc + .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); match &config.hse { Some(hse) => { @@ -363,8 +356,4 @@ pub(crate) fn configure_clocks(config: &Config) { w.set_c2hpre(config.ahb2_pre.into()); w.set_shdhpre(config.ahb3_pre.into()); }); - - config - .rtc - .map(|clock_source| BackupDomain::configure_rtc(clock_source, None)); } diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 7a03d906..6035f50b 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -137,8 +137,6 @@ pub struct Config { pub shd_ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, - pub enable_lsi: bool, - pub enable_rtc_apb: bool, pub rtc_mux: RtcClockSource, pub adc_clock_source: AdcClockSource, } @@ -152,8 +150,6 @@ impl Default for Config { shd_ahb_pre: AHBPrescaler::NotDivided, apb1_pre: APBPrescaler::NotDivided, apb2_pre: APBPrescaler::NotDivided, - enable_lsi: false, - enable_rtc_apb: false, rtc_mux: RtcClockSource::LSI, adc_clock_source: AdcClockSource::default(), } @@ -234,7 +230,8 @@ pub(crate) unsafe fn init(config: Config) { while FLASH.acr().read().latency() != ws {} - BackupDomain::configure_rtc(config.rtc_mux, None); + // Enables the LSI if configured + BackupDomain::configure_ls(config.rtc_mux, None); match config.mux { ClockSrc::HSI16 => { @@ -269,14 +266,6 @@ pub(crate) unsafe fn init(config: Config) { } } - if config.enable_rtc_apb { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); - - // read to allow the pwr clock to enable - crate::pac::PWR.cr1().read(); - } - RCC.extcfgr().modify(|w| { if config.shd_ahb_pre == AHBPrescaler::NotDivided { w.set_shdhpre(0); @@ -301,14 +290,6 @@ pub(crate) unsafe fn init(config: Config) { // TODO: switch voltage range - if config.enable_lsi { - let csr = RCC.csr().read(); - if !csr.lsion() { - RCC.csr().modify(|w| w.set_lsion(true)); - while !RCC.csr().read().lsirdy() {} - } - } - set_freqs(Clocks { sys: Hertz(sys_clk), ahb1: Hertz(ahb_freq), diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 9db4f69c..a1133a80 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -268,7 +268,7 @@ pub(crate) mod sealed { crate::pac::RTC } - fn enable_peripheral_clk() {} + fn enable_peripheral_clk(); /// Read content of the backup register. /// diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 62d8d4f9..9037389e 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -270,9 +270,18 @@ impl sealed::Instance for crate::peripherals::RTC { } #[cfg(any(rtc_v2f2))] { + // enable peripheral clock for communication crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); + + // read to allow the pwr clock to enable crate::pac::PWR.cr().read(); } + + #[cfg(any(rtc_v2f0))] + { + // enable peripheral clock for communication + crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); + } } fn read_backup_register(rtc: &Rtc, register: usize) -> Option { diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index a6b2655d..9ac9f9f8 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -128,6 +128,23 @@ impl super::Rtc { impl sealed::Instance for crate::peripherals::RTC { const BACKUP_REGISTER_COUNT: usize = 32; + fn enable_peripheral_clk() { + #[cfg(any(rcc_wle, rcc_wl5, rcc_g4))] + { + // enable peripheral clock for communication + crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); + } + + #[cfg(rcc_g0)] + { + // enable peripheral clock for communication + crate::pac::RCC.apbenr1().modify(|w| w.set_rtcapben(true)); + } + + // read to allow the pwr clock to enable + crate::pac::PWR.cr1().read(); + } + fn read_backup_register(_rtc: &Rtc, register: usize) -> Option { #[allow(clippy::if_same_then_else)] if register < Self::BACKUP_REGISTER_COUNT { diff --git a/examples/stm32wl/src/bin/lora_lorawan.rs b/examples/stm32wl/src/bin/lora_lorawan.rs index 2c9c9886..230df475 100644 --- a/examples/stm32wl/src/bin/lora_lorawan.rs +++ b/examples/stm32wl/src/bin/lora_lorawan.rs @@ -33,7 +33,7 @@ bind_interrupts!(struct Irqs{ async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; - config.rcc.enable_lsi = true; // enable RNG + config.rcc.rtc_mux = embassy_stm32::rcc::RtcClockSource::LSI; let p = embassy_stm32::init(config); pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)); diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs index 592e65f4..18eeac4f 100644 --- a/examples/stm32wl/src/bin/random.rs +++ b/examples/stm32wl/src/bin/random.rs @@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs{ async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; - config.rcc.enable_lsi = true; //Needed for RNG to work + config.rcc.rtc_mux = embassy_stm32::rcc::RtcClockSource::LSI; let p = embassy_stm32::init(config); pac::RCC.ccipr().modify(|w| { diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index 2be6c7b9..e123425a 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs @@ -17,7 +17,6 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.mux = ClockSrc::HSE32; config.rcc.rtc_mux = RtcClockSource::LSE; - config.rcc.enable_rtc_apb = true; embassy_stm32::init(config) }; info!("Hello World!"); From 40a18b075dc80048233c54f5cff80658405a9050 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sat, 9 Sep 2023 09:50:24 +0200 Subject: [PATCH 131/233] improve docstring --- embassy-net/src/lib.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 4922490d..87247c8e 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -367,13 +367,12 @@ impl Stack { } /// Wait for the network stack to obtain a valid IP configuration. - /// Returns instantly if [`Stack::is_config_up`] returns `true`. /// - /// ## Watch out: - /// The Future is polled only when the [`Stack`] is running, - /// e.g. call `spawner.spawn(net_task(stack))`. + /// ## Notes: + /// - Ensure [`Stack::run`] has been called before using this function. /// - /// `await`ing before will never yield! + /// - This function may never yield (e.g. if no configuration is obtained through DHCP). + /// The caller is supposed to handle a timeout for this case. /// /// ## Example /// ```ignore @@ -385,7 +384,7 @@ impl Stack { /// make_static!(embassy_net::StackResources::<2>::new()), /// seed /// )); - /// // Launch network task + /// // Launch network task that runs `stack.run().await` /// spawner.spawn(net_task(stack)).unwrap(); /// // Wait for DHCP config /// stack.wait_config_up().await; From 0e9131fd1465d8fc765c4da05ce63d9dfbf950c7 Mon Sep 17 00:00:00 2001 From: Julian <20155974+JuliDi@users.noreply.github.com> Date: Sat, 9 Sep 2023 12:36:57 +0200 Subject: [PATCH 132/233] yield -> return Co-authored-by: Dario Nieuwenhuis --- embassy-net/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 87247c8e..de32edc2 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -371,7 +371,7 @@ impl Stack { /// ## Notes: /// - Ensure [`Stack::run`] has been called before using this function. /// - /// - This function may never yield (e.g. if no configuration is obtained through DHCP). + /// - This function may never return (e.g. if no configuration is obtained through DHCP). /// The caller is supposed to handle a timeout for this case. /// /// ## Example From 70a4a193c51876b994cbeea547747b6cfcaf2e9a Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 9 Sep 2023 22:01:51 -0500 Subject: [PATCH 133/233] stm32: fix adc f3 and example --- embassy-stm32/src/adc/f3.rs | 9 +++------ examples/stm32f334/src/bin/adc.rs | 23 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 458573c0..8f16c6ab 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -7,8 +7,7 @@ use crate::Peripheral; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; -// No calibration data for F103, voltage should be 1.2v -pub const VREF_INT: u32 = 1200; +pub const VREF_INT: u32 = 1230; pub struct Vref; impl AdcPin for Vref {} @@ -102,16 +101,14 @@ impl<'d, T: Instance> Adc<'d, T> { while !T::regs().isr().read().eoc() && !T::regs().isr().read().eos() {} T::regs().isr().write(|_| {}); - T::regs().dr().read().0 as u16 + T::regs().dr().read().rdata() } pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { - // pin.set_as_analog(); - Self::set_channel_sample_time(pin.channel(), self.sample_time); // Configure the channel to sample - T::regs().sqr3().write(|w| w.set_sq(0, pin.channel())); + T::regs().sqr1().write(|w| w.set_sq(0, pin.channel())); self.convert() } diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index 729497e8..6dffd673 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -4,7 +4,7 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::adc::Adc; +use embassy_stm32::adc::{Adc, VREF_INT}; use embassy_stm32::rcc::{ADCClock, ADCPrescaler}; use embassy_stm32::time::Hertz; use embassy_stm32::Config; @@ -20,15 +20,28 @@ async fn main(_spawner: Spawner) -> ! { let mut p = embassy_stm32::init(config); + info!("create adc..."); + let mut adc = Adc::new(p.ADC1, &mut Delay); - let mut vrefint = adc.enable_vref(&mut Delay); + info!("enable vrefint..."); - let _vref = adc.read(&mut vrefint); - let _pin = adc.read(&mut p.PA0); + let mut vrefint = adc.enable_vref(&mut Delay); + let mut temperature = adc.enable_temperature(); loop { - info!("Hello World!"); + let vref = adc.read(&mut vrefint); + info!("read vref: {}", vref); + + let temp = adc.read(&mut temperature); + info!("read temperature: {}", temp); + + let pin = adc.read(&mut p.PA0); + info!("read pin: {}", pin); + + let pin_mv = pin as u32 * VREF_INT as u32 / vref as u32; + info!("computed pin mv: {}", pin_mv); + Timer::after(Duration::from_secs(1)).await; } } From d6a1b567ee1eeaa98f9e8938227c0f3be3559670 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:13:56 +0200 Subject: [PATCH 134/233] add SocketNotBound error message --- embassy-net/src/udp.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 0a5a7b8f..61058c1b 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -29,6 +29,8 @@ pub enum BindError { pub enum Error { /// No route to host. NoRoute, + /// Socket not bound to an outgoing port. + SocketNotBound, } /// An UDP socket. @@ -155,7 +157,14 @@ impl<'a> UdpSocket<'a> { s.register_send_waker(cx.waker()); Poll::Pending } - Err(udp::SendError::Unaddressable) => Poll::Ready(Err(Error::NoRoute)), + Err(udp::SendError::Unaddressable) => { + // If no sender/outgoing port is specified, there is not really "no route" + if s.endpoint().port == 0 { + Poll::Ready(Err(Error::SocketNotBound)) + } else { + Poll::Ready(Err(Error::NoRoute)) + } + } }) } From 08415e001e93a35579a8fc8e41147df96d80da84 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 10 Sep 2023 13:33:17 -0500 Subject: [PATCH 135/233] stm32/f3: add high res for hrtim and misc. --- embassy-stm32/src/adc/f1.rs | 2 +- embassy-stm32/src/hrtim/mod.rs | 36 ++++-- embassy-stm32/src/hrtim/traits.rs | 12 ++ embassy-stm32/src/rcc/f1.rs | 2 +- embassy-stm32/src/rcc/f3.rs | 199 +++++++++++++++++++----------- embassy-stm32/src/rcc/mod.rs | 8 +- examples/stm32f334/src/bin/adc.rs | 16 ++- examples/stm32f334/src/bin/pwm.rs | 2 + 8 files changed, 184 insertions(+), 93 deletions(-) diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index e577ec28..147349de 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -60,7 +60,7 @@ impl<'d, T: Instance> Adc<'d, T> { } fn freq() -> Hertz { - unsafe { get_freqs() }.adc + unsafe { get_freqs() }.adc.unwrap() } pub fn sample_time_for_us(&self, us: u32) -> SampleTime { diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 31c48814..c47b0c09 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -8,6 +8,8 @@ pub use traits::Instance; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; use crate::gpio::AnyPin; +#[cfg(stm32f334)] +use crate::rcc::get_freqs; use crate::time::Hertz; use crate::Peripheral; @@ -158,17 +160,29 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { T::enable(); ::reset(); - // // Enable and and stabilize the DLL - // T::regs().dllcr().modify(|w| { - // // w.set_calen(true); - // // w.set_calrte(11); - // w.set_cal(true); - // }); - // - // debug!("wait for dll calibration"); - // while !T::regs().isr().read().dllrdy() {} - // - // debug!("dll calibration complete"); + #[cfg(stm32f334)] + if unsafe { get_freqs() }.hrtim.is_some() { + // Enable and and stabilize the DLL + T::regs().dllcr().modify(|w| { + w.set_cal(true); + }); + + trace!("hrtim: wait for dll calibration"); + while !T::regs().isr().read().dllrdy() {} + + trace!("hrtim: dll calibration complete"); + + // Enable periodic calibration + // Cal must be disabled before we can enable it + T::regs().dllcr().modify(|w| { + w.set_cal(false); + }); + + T::regs().dllcr().modify(|w| { + w.set_calen(true); + w.set_calrte(11); + }); + } Self { _inner: tim, diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 09510959..37cfb9b9 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -104,7 +104,13 @@ foreach_interrupt! { use crate::rcc::sealed::RccPeripheral; let f = frequency.0; + #[cfg(not(stm32f334))] let timer_f = Self::frequency().0; + #[cfg(stm32f334)] + let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or( + Self::frequency() + ).0; + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); let psc = if Self::regs().isr().read().dllrdy() { Prescaler::compute_min_high_res(psc_min) @@ -125,7 +131,13 @@ foreach_interrupt! { use crate::rcc::sealed::RccPeripheral; let f = frequency.0; + #[cfg(not(stm32f334))] let timer_f = Self::frequency().0; + #[cfg(stm32f334)] + let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or( + Self::frequency() + ).0; + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); let psc = if Self::regs().isr().read().dllrdy() { Prescaler::compute_min_high_res(psc_min) diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index b6200231..304d8f50 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs @@ -184,6 +184,6 @@ pub(crate) unsafe fn init(config: Config) { apb1_tim: Hertz(pclk1 * timer_mul1), apb2_tim: Hertz(pclk2 * timer_mul2), ahb1: Hertz(hclk), - adc: Hertz(adcclk), + adc: Some(Hertz(adcclk)), }); } diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index f8726c24..cbbe4f98 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -1,3 +1,5 @@ +#[cfg(rcc_f3)] +use crate::pac::adccommon::vals::Ckmode; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; use crate::pac::{FLASH, RCC}; @@ -10,44 +12,80 @@ pub const HSI_FREQ: Hertz = Hertz(8_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(40_000); -#[repr(u16)] -#[derive(Clone, Copy)] -pub enum ADCPrescaler { - Div1 = 1, - Div2 = 2, - Div4 = 4, - Div6 = 6, - Div8 = 8, - Div12 = 12, - Div16 = 16, - Div32 = 32, - Div64 = 64, - Div128 = 128, - Div256 = 256, +impl From for Adcpres { + fn from(value: AdcClockSource) -> Self { + match value { + AdcClockSource::PllDiv1 => Adcpres::DIV1, + AdcClockSource::PllDiv2 => Adcpres::DIV2, + AdcClockSource::PllDiv4 => Adcpres::DIV4, + AdcClockSource::PllDiv6 => Adcpres::DIV6, + AdcClockSource::PllDiv8 => Adcpres::DIV8, + AdcClockSource::PllDiv12 => Adcpres::DIV12, + AdcClockSource::PllDiv16 => Adcpres::DIV16, + AdcClockSource::PllDiv32 => Adcpres::DIV32, + AdcClockSource::PllDiv64 => Adcpres::DIV64, + AdcClockSource::PllDiv128 => Adcpres::DIV128, + AdcClockSource::PllDiv256 => Adcpres::DIV256, + _ => unreachable!(), + } + } } -impl From for Adcpres { - fn from(value: ADCPrescaler) -> Self { +#[cfg(rcc_f3)] +impl From for Ckmode { + fn from(value: AdcClockSource) -> Self { match value { - ADCPrescaler::Div1 => Adcpres::DIV1, - ADCPrescaler::Div2 => Adcpres::DIV2, - ADCPrescaler::Div4 => Adcpres::DIV4, - ADCPrescaler::Div6 => Adcpres::DIV6, - ADCPrescaler::Div8 => Adcpres::DIV8, - ADCPrescaler::Div12 => Adcpres::DIV12, - ADCPrescaler::Div16 => Adcpres::DIV16, - ADCPrescaler::Div32 => Adcpres::DIV32, - ADCPrescaler::Div64 => Adcpres::DIV64, - ADCPrescaler::Div128 => Adcpres::DIV128, - ADCPrescaler::Div256 => Adcpres::DIV256, + AdcClockSource::BusDiv1 => Ckmode::SYNCDIV1, + AdcClockSource::BusDiv2 => Ckmode::SYNCDIV2, + AdcClockSource::BusDiv4 => Ckmode::SYNCDIV4, + _ => unreachable!(), } } } #[derive(Clone, Copy)] -pub enum ADCClock { - AHB(ADCPrescaler), - PLL(ADCPrescaler), +pub enum AdcClockSource { + PllDiv1 = 1, + PllDiv2 = 2, + PllDiv4 = 4, + PllDiv6 = 6, + PllDiv8 = 8, + PllDiv12 = 12, + PllDiv16 = 16, + PllDiv32 = 32, + PllDiv64 = 64, + PllDiv128 = 128, + PllDiv256 = 256, + BusDiv1, + BusDiv2, + BusDiv4, +} + +impl AdcClockSource { + pub fn is_bus(&self) -> bool { + match self { + Self::BusDiv1 => true, + Self::BusDiv2 => true, + Self::BusDiv4 => true, + _ => false, + } + } + + pub fn bus_div(&self) -> u32 { + match self { + Self::BusDiv1 => 1, + Self::BusDiv2 => 2, + Self::BusDiv4 => 4, + _ => unreachable!(), + } + } +} + +#[derive(Default)] +pub enum HrtimClockSource { + #[default] + BusClk, + PllClk, } /// Clocks configutation @@ -79,11 +117,13 @@ pub struct Config { #[cfg(rcc_f3)] /// ADC clock setup /// - For AHB, a psc of 4 or less must be used - pub adc: Option, + pub adc: Option, #[cfg(rcc_f3)] /// ADC clock setup /// - For AHB, a psc of 4 or less must be used - pub adc34: Option, + pub adc34: Option, + #[cfg(stm32f334)] + pub hrtim: HrtimClockSource, } // Information required to setup the PLL clock @@ -197,44 +237,6 @@ pub(crate) unsafe fn init(config: Config) { }); } - #[cfg(rcc_f3)] - let adc = config.adc.map(|adc| match adc { - ADCClock::PLL(psc) => RCC.cfgr2().modify(|w| { - // Make sure that we're using the PLL - pll_config.unwrap(); - w.set_adc12pres(psc.into()); - - Hertz(sysclk / psc as u32) - }), - ADCClock::AHB(psc) => { - assert!(psc as u16 <= 4); - assert!(!(psc as u16 == 1 && hpre_bits != Hpre::DIV1)); - - // To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be - // different from ā€œ00ā€. - todo!(); - } - }); - - #[cfg(rcc_f3)] - let adc34 = config.adc34.map(|adc| match adc { - ADCClock::PLL(psc) => RCC.cfgr2().modify(|w| { - // Make sure that we're using the PLL - pll_config.unwrap(); - w.set_adc34pres(psc.into()); - - Hertz(sysclk / psc as u32) - }), - ADCClock::AHB(psc) => { - assert!(psc as u16 <= 4); - assert!(!(psc as u16 == 1 && hpre_bits != Hpre::DIV1)); - - // To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be - // different from ā€œ00ā€. - todo!(); - } - }); - // Set prescalers // CFGR has been written before (PLL, PLL48) don't overwrite these settings RCC.cfgr().modify(|w| { @@ -257,6 +259,61 @@ pub(crate) unsafe fn init(config: Config) { }) }); + #[cfg(rcc_f3)] + let adc = config.adc.map(|adc| { + if !adc.is_bus() { + RCC.cfgr2().modify(|w| { + // Make sure that we're using the PLL + pll_config.unwrap(); + w.set_adc12pres(adc.into()); + + Hertz(sysclk / adc as u32) + }) + } else { + crate::pac::ADC_COMMON.ccr().modify(|w| { + assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1)); + + w.set_ckmode(adc.into()); + + Hertz(sysclk / adc.bus_div() as u32) + }) + } + }); + + #[cfg(rcc_f3)] + let adc34 = config.adc.map(|adc| { + if !adc.is_bus() { + RCC.cfgr2().modify(|w| { + // Make sure that we're using the PLL + pll_config.unwrap(); + w.set_adc12pres(adc.into()); + + Hertz(sysclk / adc as u32) + }) + } else { + // TODO: need to use only if adc32_common is present + + todo!() + } + }); + + #[cfg(stm32f334)] + let hrtim = match config.hrtim { + // Must be configured after the bus is ready, otherwise it won't work + HrtimClockSource::BusClk => None, + HrtimClockSource::PllClk => { + use crate::pac::rcc::vals::Timsw; + + // Make sure that we're using the PLL + pll_config.unwrap(); + assert!((pclk2 == sysclk) || (pclk2 * 2 == sysclk)); + + RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL)); + + Some(Hertz(sysclk * 2)) + } + }; + set_freqs(Clocks { sys: Hertz(sysclk), apb1: Hertz(pclk1), @@ -268,6 +325,8 @@ pub(crate) unsafe fn init(config: Config) { adc: adc, #[cfg(rcc_f3)] adc34: adc34, + #[cfg(stm32f334)] + hrtim: hrtim, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 535ab6ad..4f0b7fd0 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -71,15 +71,15 @@ pub struct Clocks { #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] pub pllsai: Option, - #[cfg(stm32f1)] - pub adc: Hertz, - - #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))] + #[cfg(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))] pub adc: Option, #[cfg(any(rcc_f3, rcc_g4))] pub adc34: Option, + #[cfg(stm32f334)] + pub hrtim: Option, + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index 6dffd673..e8b2cd8a 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -4,9 +4,9 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, VREF_INT}; -use embassy_stm32::rcc::{ADCClock, ADCPrescaler}; -use embassy_stm32::time::Hertz; +use embassy_stm32::adc::{Adc, SampleTime, VREF_INT}; +use embassy_stm32::rcc::AdcClockSource; +use embassy_stm32::time::mhz; use embassy_stm32::Config; use embassy_time::{Delay, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -14,9 +14,11 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let mut config = Config::default(); - config.rcc.hse = Some(Hertz(8_000_000)); - config.rcc.sysclk = Some(Hertz(16_000_000)); - config.rcc.adc = Some(ADCClock::PLL(ADCPrescaler::Div1)); + config.rcc.sysclk = Some(mhz(64)); + config.rcc.hclk = Some(mhz(64)); + config.rcc.pclk1 = Some(mhz(32)); + config.rcc.pclk2 = Some(mhz(64)); + config.rcc.adc = Some(AdcClockSource::PllDiv1); let mut p = embassy_stm32::init(config); @@ -24,6 +26,8 @@ async fn main(_spawner: Spawner) -> ! { let mut adc = Adc::new(p.ADC1, &mut Delay); + adc.set_sample_time(SampleTime::Cycles601_5); + info!("enable vrefint..."); let mut vrefint = adc.enable_vref(&mut Delay); diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 2660b10c..aebc421b 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -5,6 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::hrtim::*; +use embassy_stm32::rcc::HrtimClockSource; use embassy_stm32::time::{khz, mhz}; use embassy_stm32::Config; use embassy_time::{Duration, Timer}; @@ -17,6 +18,7 @@ async fn main(_spawner: Spawner) { config.rcc.hclk = Some(mhz(64)); config.rcc.pclk1 = Some(mhz(32)); config.rcc.pclk2 = Some(mhz(64)); + config.rcc.hrtim = HrtimClockSource::PllClk; let p = embassy_stm32::init(config); info!("Hello World!"); From 1bae34d37cbcb1df014699ea2bbc8c0323e25d0c Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 10 Sep 2023 13:50:28 -0500 Subject: [PATCH 136/233] stm32: fix docs --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ded58aee..ff41f0ba 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -8,13 +8,13 @@ license = "MIT OR Apache-2.0" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-v$VERSION/embassy-stm32/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32/src/" -features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time", "low-power"] +features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "time"] flavors = [ { regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, { regex_feature = "stm32f2.*", target = "thumbv7m-none-eabi" }, { regex_feature = "stm32f3.*", target = "thumbv7em-none-eabi" }, - { regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi" }, + { regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi", features = ["low-power"] }, { regex_feature = "stm32f7.*", target = "thumbv7em-none-eabi" }, { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" }, From 268da2fcde429887a7df879deb90d2383d9d754e Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sun, 10 Sep 2023 14:51:59 +0100 Subject: [PATCH 137/233] Handle stbiterr in 4bit wide mode for sdmmc_v1 --- embassy-stm32/Cargo.toml | 4 +-- embassy-stm32/src/sdmmc/mod.rs | 56 ++++++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ded58aee..bd9b406a 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-eaa4987e523408dfb31c1b76765dd345d2761373" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e667107cf81934383ec5744f49b2cda0599ec749" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -77,7 +77,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-eaa4987e523408dfb31c1b76765dd345d2761373", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e667107cf81934383ec5744f49b2cda0599ec749", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 6b532363..9fb380fd 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -33,6 +33,8 @@ impl InterruptHandler { w.set_dtimeoutie(enable); w.set_dataendie(enable); + #[cfg(sdmmc_v1)] + w.set_stbiterre(enable); #[cfg(sdmmc_v2)] w.set_dabortie(enable); }); @@ -102,6 +104,8 @@ pub enum Error { BadClock, SignalingSwitchFailed, PeripheralBusy, + #[cfg(sdmmc_v1)] + StBitErr, } /// A SD command @@ -707,9 +711,15 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); - } else if status.dtimeout() { + } + if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); - } else if status.dataend() { + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { return Poll::Ready(Ok(())); } Poll::Pending @@ -782,9 +792,15 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); - } else if status.dtimeout() { + } + if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); - } else if status.dataend() { + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { return Poll::Ready(Ok(())); } Poll::Pending @@ -836,6 +852,8 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { w.set_dataendc(true); w.set_dbckendc(true); w.set_sdioitc(true); + #[cfg(sdmmc_v1)] + w.set_stbiterrc(true); #[cfg(sdmmc_v2)] { @@ -873,9 +891,15 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); - } else if status.dtimeout() { + } + if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); - } else if status.dataend() { + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { return Poll::Ready(Ok(())); } Poll::Pending @@ -1156,9 +1180,15 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); - } else if status.dtimeout() { + } + if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); - } else if status.dataend() { + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { return Poll::Ready(Ok(())); } Poll::Pending @@ -1207,9 +1237,15 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); - } else if status.dtimeout() { + } + if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); - } else if status.dataend() { + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { return Poll::Ready(Ok(())); } Poll::Pending From 26e0823c3507a537d72fa5d6d7e97126314c0f0c Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 14 Aug 2023 16:50:57 -0400 Subject: [PATCH 138/233] rp2040 I2cDevice Move i2c to mod, split device and controller Remove mode generic: I don't think it's reasonable to use the i2c in device mode while blocking, so I'm cutting the generic. --- embassy-rp/src/{ => i2c}/i2c.rs | 171 +---------------- embassy-rp/src/i2c/i2c_device.rs | 313 +++++++++++++++++++++++++++++++ embassy-rp/src/i2c/mod.rs | 175 +++++++++++++++++ tests/rp/src/bin/i2c.rs | 215 +++++++++++++++++++++ 4 files changed, 709 insertions(+), 165 deletions(-) rename embassy-rp/src/{ => i2c}/i2c.rs (83%) create mode 100644 embassy-rp/src/i2c/i2c_device.rs create mode 100644 embassy-rp/src/i2c/mod.rs create mode 100644 tests/rp/src/bin/i2c.rs diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c/i2c.rs similarity index 83% rename from embassy-rp/src/i2c.rs rename to embassy-rp/src/i2c/i2c.rs index 7a5ddd32..13124dd8 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c/i2c.rs @@ -3,45 +3,19 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::{into_ref, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; use pac::i2c; +use super::{ + i2c_reserved_addr, AbortReason, Async, Blocking, Error, Instance, InterruptHandler, Mode, SclPin, SdaPin, FIFO_SIZE, +}; use crate::gpio::sealed::Pin; use crate::gpio::AnyPin; use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{interrupt, pac, peripherals, Peripheral}; - -/// I2C error abort reason -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum AbortReason { - /// A bus operation was not acknowledged, e.g. due to the addressed device - /// not being available on the bus or the device not being ready to process - /// requests at the moment - NoAcknowledge, - /// The arbitration was lost, e.g. electrical problems with the clock signal - ArbitrationLoss, - Other(u32), -} - -/// I2C error -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Error { - /// I2C abort with error - Abort(AbortReason), - /// User passed in a read buffer that was 0 length - InvalidReadBufferLength, - /// User passed in a write buffer that was 0 length - InvalidWriteBufferLength, - /// Target i2c address is out of range - AddressOutOfRange(u16), - /// Target i2c address is reserved - AddressReserved(u16), -} +use crate::{pac, Peripheral}; #[non_exhaustive] #[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Config { pub frequency: u32, } @@ -52,8 +26,6 @@ impl Default for Config { } } -const FIFO_SIZE: u8 = 16; - pub struct I2c<'d, T: Instance, M: Mode> { phantom: PhantomData<(&'d mut T, M)>, } @@ -302,20 +274,6 @@ impl<'d, T: Instance> I2c<'d, T, Async> { } } -pub struct InterruptHandler { - _uart: PhantomData, -} - -impl interrupt::typelevel::Handler for InterruptHandler { - // Mask interrupts and wake any task waiting for this interrupt - unsafe fn on_interrupt() { - let i2c = T::regs(); - i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default()); - - T::waker().wake(); - } -} - impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { fn new_inner( _peri: impl Peripheral

+ 'd, @@ -636,6 +594,7 @@ mod eh1 { Self::Abort(AbortReason::NoAcknowledge) => { embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) } + Self::Abort(AbortReason::TxNotEmpty(_)) => embedded_hal_1::i2c::ErrorKind::Other, Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other, Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other, Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other, @@ -737,121 +696,3 @@ mod nightly { } } } - -fn i2c_reserved_addr(addr: u16) -> bool { - (addr & 0x78) == 0 || (addr & 0x78) == 0x78 -} - -mod sealed { - use embassy_sync::waitqueue::AtomicWaker; - - use crate::interrupt; - - pub trait Instance { - const TX_DREQ: u8; - const RX_DREQ: u8; - - type Interrupt: interrupt::typelevel::Interrupt; - - fn regs() -> crate::pac::i2c::I2c; - fn reset() -> crate::pac::resets::regs::Peripherals; - fn waker() -> &'static AtomicWaker; - } - - pub trait Mode {} - - pub trait SdaPin {} - pub trait SclPin {} -} - -pub trait Mode: sealed::Mode {} - -macro_rules! impl_mode { - ($name:ident) => { - impl sealed::Mode for $name {} - impl Mode for $name {} - }; -} - -pub struct Blocking; -pub struct Async; - -impl_mode!(Blocking); -impl_mode!(Async); - -pub trait Instance: sealed::Instance {} - -macro_rules! impl_instance { - ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => { - impl sealed::Instance for peripherals::$type { - const TX_DREQ: u8 = $tx_dreq; - const RX_DREQ: u8 = $rx_dreq; - - type Interrupt = crate::interrupt::typelevel::$irq; - - #[inline] - fn regs() -> pac::i2c::I2c { - pac::$type - } - - #[inline] - fn reset() -> pac::resets::regs::Peripherals { - let mut ret = pac::resets::regs::Peripherals::default(); - ret.$reset(true); - ret - } - - #[inline] - fn waker() -> &'static AtomicWaker { - static WAKER: AtomicWaker = AtomicWaker::new(); - - &WAKER - } - } - impl Instance for peripherals::$type {} - }; -} - -impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); -impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); - -pub trait SdaPin: sealed::SdaPin + crate::gpio::Pin {} -pub trait SclPin: sealed::SclPin + crate::gpio::Pin {} - -macro_rules! impl_pin { - ($pin:ident, $instance:ident, $function:ident) => { - impl sealed::$function for peripherals::$pin {} - impl $function for peripherals::$pin {} - }; -} - -impl_pin!(PIN_0, I2C0, SdaPin); -impl_pin!(PIN_1, I2C0, SclPin); -impl_pin!(PIN_2, I2C1, SdaPin); -impl_pin!(PIN_3, I2C1, SclPin); -impl_pin!(PIN_4, I2C0, SdaPin); -impl_pin!(PIN_5, I2C0, SclPin); -impl_pin!(PIN_6, I2C1, SdaPin); -impl_pin!(PIN_7, I2C1, SclPin); -impl_pin!(PIN_8, I2C0, SdaPin); -impl_pin!(PIN_9, I2C0, SclPin); -impl_pin!(PIN_10, I2C1, SdaPin); -impl_pin!(PIN_11, I2C1, SclPin); -impl_pin!(PIN_12, I2C0, SdaPin); -impl_pin!(PIN_13, I2C0, SclPin); -impl_pin!(PIN_14, I2C1, SdaPin); -impl_pin!(PIN_15, I2C1, SclPin); -impl_pin!(PIN_16, I2C0, SdaPin); -impl_pin!(PIN_17, I2C0, SclPin); -impl_pin!(PIN_18, I2C1, SdaPin); -impl_pin!(PIN_19, I2C1, SclPin); -impl_pin!(PIN_20, I2C0, SdaPin); -impl_pin!(PIN_21, I2C0, SclPin); -impl_pin!(PIN_22, I2C1, SdaPin); -impl_pin!(PIN_23, I2C1, SclPin); -impl_pin!(PIN_24, I2C0, SdaPin); -impl_pin!(PIN_25, I2C0, SclPin); -impl_pin!(PIN_26, I2C1, SdaPin); -impl_pin!(PIN_27, I2C1, SclPin); -impl_pin!(PIN_28, I2C0, SdaPin); -impl_pin!(PIN_29, I2C0, SclPin); diff --git a/embassy-rp/src/i2c/i2c_device.rs b/embassy-rp/src/i2c/i2c_device.rs new file mode 100644 index 00000000..915c0424 --- /dev/null +++ b/embassy-rp/src/i2c/i2c_device.rs @@ -0,0 +1,313 @@ +use core::future; +use core::marker::PhantomData; +use core::task::Poll; + +use embassy_hal_internal::into_ref; +use pac::i2c; + +use super::{i2c_reserved_addr, AbortReason, Error, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE}; +use crate::interrupt::typelevel::{Binding, Interrupt}; +use crate::{pac, Peripheral}; + +/// Received command +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Command { + /// General Call + GeneralCall(usize), + /// Read + Read, + /// Write+read + WriteRead(usize), + /// Write + Write(usize), +} + +/// Possible responses to responding to a read +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ReadStatus { + /// Transaction Complete, controller naked our last byte + Done, + /// Transaction Incomplete, controller trying to read more bytes than were provided + NeedMoreBytes, + /// Transaction Complere, but controller stopped reading bytes before we ran out + LeftoverBytes(u16), +} + +/// Device Configuration +#[non_exhaustive] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DeviceConfig { + /// Target Address + pub addr: u16, +} + +impl Default for DeviceConfig { + fn default() -> Self { + Self { addr: 0x55 } + } +} + +pub struct I2cDevice<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, +} + +impl<'d, T: Instance> I2cDevice<'d, T> { + pub fn new( + _peri: impl Peripheral

+ 'd, + scl: impl Peripheral

> + 'd, + sda: impl Peripheral

> + 'd, + _irq: impl Binding>, + config: DeviceConfig, + ) -> Self { + into_ref!(_peri, scl, sda); + + assert!(!i2c_reserved_addr(config.addr)); + assert!(config.addr != 0); + + let p = T::regs(); + + let reset = T::reset(); + crate::reset::reset(reset); + crate::reset::unreset_wait(reset); + + p.ic_enable().write(|w| w.set_enable(false)); + + p.ic_sar().write(|w| w.set_ic_sar(config.addr)); + p.ic_con().modify(|w| { + w.set_master_mode(false); + w.set_ic_slave_disable(false); + w.set_tx_empty_ctrl(true); + }); + + // Set FIFO watermarks to 1 to make things simpler. This is encoded + // by a register value of 0. Rx watermark should never change, but Tx watermark will be + // adjusted in operation. + p.ic_tx_tl().write(|w| w.set_tx_tl(0)); + p.ic_rx_tl().write(|w| w.set_rx_tl(0)); + + // Configure SCL & SDA pins + scl.gpio().ctrl().write(|w| w.set_funcsel(3)); + sda.gpio().ctrl().write(|w| w.set_funcsel(3)); + + scl.pad_ctrl().write(|w| { + w.set_schmitt(true); + w.set_ie(true); + w.set_od(false); + w.set_pue(true); + w.set_pde(false); + }); + sda.pad_ctrl().write(|w| { + w.set_schmitt(true); + w.set_ie(true); + w.set_od(false); + w.set_pue(true); + w.set_pde(false); + }); + + // Clear interrupts + p.ic_clr_intr().read(); + + // Enable I2C block + p.ic_enable().write(|w| w.set_enable(true)); + + // mask everything initially + p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + Self { phantom: PhantomData } + } + + /// Calls `f` to check if we are ready or not. + /// If not, `g` is called once the waker is set (to eg enable the required interrupts). + #[inline(always)] + async fn wait_on(&mut self, mut f: F, mut g: G) -> U + where + F: FnMut(&mut Self) -> Poll, + G: FnMut(&mut Self), + { + future::poll_fn(|cx| { + let r = f(self); + + trace!("intr p: {:013b}", T::regs().ic_raw_intr_stat().read().0); + + if r.is_pending() { + T::waker().register(cx.waker()); + g(self); + } + + r + }) + .await + } + + #[inline(always)] + fn drain_fifo(&mut self, buffer: &mut [u8], offset: usize) -> usize { + let p = T::regs(); + let len = p.ic_rxflr().read().rxflr() as usize; + let end = offset + len; + for i in offset..end { + buffer[i] = p.ic_data_cmd().read().dat(); + } + end + } + + #[inline(always)] + fn write_to_fifo(&mut self, buffer: &[u8]) { + let p = T::regs(); + for byte in buffer { + p.ic_data_cmd().write(|w| w.set_dat(*byte)); + } + } + + /// Wait asynchronously for commands from an I2C master. + /// `buffer` is provided in case master does a 'write' and is unused for 'read'. + pub async fn listen(&mut self, buffer: &mut [u8]) -> Result { + let p = T::regs(); + + p.ic_clr_intr().read(); + // set rx fifo watermark to 1 byte + p.ic_rx_tl().write(|w| w.set_rx_tl(0)); + + let mut len = 0; + let ret = self + .wait_on( + |me| { + let stat = p.ic_raw_intr_stat().read(); + if p.ic_rxflr().read().rxflr() > 0 { + len = me.drain_fifo(buffer, len); + // we're recieving data, set rx fifo watermark to 12 bytes to reduce interrupt noise + p.ic_rx_tl().write(|w| w.set_rx_tl(11)); + } + + if stat.restart_det() && stat.rd_req() { + Poll::Ready(Ok(Command::WriteRead(len))) + } else if stat.gen_call() && stat.stop_det() && len > 0 { + Poll::Ready(Ok(Command::GeneralCall(len))) + } else if stat.stop_det() { + Poll::Ready(Ok(Command::Write(len))) + } else if stat.rd_req() { + Poll::Ready(Ok(Command::Read)) + } else { + Poll::Pending + } + }, + |_me| { + p.ic_intr_mask().modify(|w| { + w.set_m_stop_det(true); + w.set_m_restart_det(true); + w.set_m_gen_call(true); + w.set_m_rd_req(true); + w.set_m_rx_full(true); + }); + }, + ) + .await; + + p.ic_clr_intr().read(); + + ret + } + + /// Respond to an I2C master READ command, asynchronously. + pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result { + let p = T::regs(); + + info!("buff: {}", buffer); + let mut chunks = buffer.chunks(FIFO_SIZE as usize); + + let ret = self + .wait_on( + |me| { + if let Err(abort_reason) = me.read_and_clear_abort_reason() { + info!("ar: {}", abort_reason); + if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { + return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); + } else { + return Poll::Ready(Err(abort_reason)); + } + } + + if let Some(chunk) = chunks.next() { + me.write_to_fifo(chunk); + + Poll::Pending + } else { + let stat = p.ic_raw_intr_stat().read(); + + if stat.rx_done() && stat.stop_det() { + Poll::Ready(Ok(ReadStatus::Done)) + } else if stat.rd_req() { + Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) + } else { + Poll::Pending + } + } + }, + |_me| { + p.ic_intr_mask().modify(|w| { + w.set_m_stop_det(true); + w.set_m_rx_done(true); + w.set_m_tx_empty(true); + w.set_m_tx_abrt(true); + }) + }, + ) + .await; + + p.ic_clr_intr().read(); + + ret + } + + /// Respond to reads with the fill byte until the controller stops asking + pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> { + loop { + match self.respond_to_read(&[fill]).await { + Ok(ReadStatus::NeedMoreBytes) => (), + Ok(_) => break Ok(()), + Err(e) => break Err(e), + } + } + } + + #[inline(always)] + fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { + let p = T::regs(); + let mut abort_reason = p.ic_tx_abrt_source().read(); + + // Mask off fifo flush count + let tx_flush_cnt = abort_reason.tx_flush_cnt(); + abort_reason.set_tx_flush_cnt(0); + + // Mask off master_dis + abort_reason.set_abrt_master_dis(false); + + if abort_reason.0 != 0 { + // Note clearing the abort flag also clears the reason, and this + // instance of flag is clear-on-read! Note also the + // IC_CLR_TX_ABRT register always reads as 0. + p.ic_clr_tx_abrt().read(); + + let reason = if abort_reason.abrt_7b_addr_noack() + | abort_reason.abrt_10addr1_noack() + | abort_reason.abrt_10addr2_noack() + { + AbortReason::NoAcknowledge + } else if abort_reason.arb_lost() { + AbortReason::ArbitrationLoss + } else if abort_reason.abrt_slvflush_txfifo() { + AbortReason::TxNotEmpty(tx_flush_cnt) + } else { + AbortReason::Other(abort_reason.0) + }; + + Err(Error::Abort(reason)) + } else { + Ok(()) + } + } +} diff --git a/embassy-rp/src/i2c/mod.rs b/embassy-rp/src/i2c/mod.rs new file mode 100644 index 00000000..2b3523d6 --- /dev/null +++ b/embassy-rp/src/i2c/mod.rs @@ -0,0 +1,175 @@ +mod i2c; +mod i2c_device; + +use core::marker::PhantomData; + +use embassy_sync::waitqueue::AtomicWaker; +pub use i2c::{Config, I2c}; +pub use i2c_device::{Command, DeviceConfig, I2cDevice, ReadStatus}; + +use crate::{interrupt, pac, peripherals}; + +const FIFO_SIZE: u8 = 16; + +/// I2C error abort reason +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum AbortReason { + /// A bus operation was not acknowledged, e.g. due to the addressed device + /// not being available on the bus or the device not being ready to process + /// requests at the moment + NoAcknowledge, + /// The arbitration was lost, e.g. electrical problems with the clock signal + ArbitrationLoss, + /// Transmit ended with data still in fifo + TxNotEmpty(u16), + Other(u32), +} + +/// I2C error +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + /// I2C abort with error + Abort(AbortReason), + /// User passed in a read buffer that was 0 length + InvalidReadBufferLength, + /// User passed in a write buffer that was 0 length + InvalidWriteBufferLength, + /// Target i2c address is out of range + AddressOutOfRange(u16), + /// Target i2c address is reserved + AddressReserved(u16), +} + +pub struct InterruptHandler { + _uart: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + // Mask interrupts and wake any task waiting for this interrupt + unsafe fn on_interrupt() { + let i2c = T::regs(); + i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default()); + + T::waker().wake(); + } +} + +fn i2c_reserved_addr(addr: u16) -> bool { + ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 +} + +mod sealed { + use embassy_sync::waitqueue::AtomicWaker; + + use crate::interrupt; + + pub trait Instance { + const TX_DREQ: u8; + const RX_DREQ: u8; + + type Interrupt: interrupt::typelevel::Interrupt; + + fn regs() -> crate::pac::i2c::I2c; + fn reset() -> crate::pac::resets::regs::Peripherals; + fn waker() -> &'static AtomicWaker; + } + + pub trait Mode {} + + pub trait SdaPin {} + pub trait SclPin {} +} + +pub trait Mode: sealed::Mode {} + +macro_rules! impl_mode { + ($name:ident) => { + impl sealed::Mode for $name {} + impl Mode for $name {} + }; +} + +pub struct Blocking; +pub struct Async; + +impl_mode!(Blocking); +impl_mode!(Async); + +pub trait Instance: sealed::Instance {} + +macro_rules! impl_instance { + ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => { + impl sealed::Instance for peripherals::$type { + const TX_DREQ: u8 = $tx_dreq; + const RX_DREQ: u8 = $rx_dreq; + + type Interrupt = crate::interrupt::typelevel::$irq; + + #[inline] + fn regs() -> pac::i2c::I2c { + pac::$type + } + + #[inline] + fn reset() -> pac::resets::regs::Peripherals { + let mut ret = pac::resets::regs::Peripherals::default(); + ret.$reset(true); + ret + } + + #[inline] + fn waker() -> &'static AtomicWaker { + static WAKER: AtomicWaker = AtomicWaker::new(); + + &WAKER + } + } + impl Instance for peripherals::$type {} + }; +} + +impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); +impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); + +pub trait SdaPin: sealed::SdaPin + crate::gpio::Pin {} +pub trait SclPin: sealed::SclPin + crate::gpio::Pin {} + +macro_rules! impl_pin { + ($pin:ident, $instance:ident, $function:ident) => { + impl sealed::$function for peripherals::$pin {} + impl $function for peripherals::$pin {} + }; +} + +impl_pin!(PIN_0, I2C0, SdaPin); +impl_pin!(PIN_1, I2C0, SclPin); +impl_pin!(PIN_2, I2C1, SdaPin); +impl_pin!(PIN_3, I2C1, SclPin); +impl_pin!(PIN_4, I2C0, SdaPin); +impl_pin!(PIN_5, I2C0, SclPin); +impl_pin!(PIN_6, I2C1, SdaPin); +impl_pin!(PIN_7, I2C1, SclPin); +impl_pin!(PIN_8, I2C0, SdaPin); +impl_pin!(PIN_9, I2C0, SclPin); +impl_pin!(PIN_10, I2C1, SdaPin); +impl_pin!(PIN_11, I2C1, SclPin); +impl_pin!(PIN_12, I2C0, SdaPin); +impl_pin!(PIN_13, I2C0, SclPin); +impl_pin!(PIN_14, I2C1, SdaPin); +impl_pin!(PIN_15, I2C1, SclPin); +impl_pin!(PIN_16, I2C0, SdaPin); +impl_pin!(PIN_17, I2C0, SclPin); +impl_pin!(PIN_18, I2C1, SdaPin); +impl_pin!(PIN_19, I2C1, SclPin); +impl_pin!(PIN_20, I2C0, SdaPin); +impl_pin!(PIN_21, I2C0, SclPin); +impl_pin!(PIN_22, I2C1, SdaPin); +impl_pin!(PIN_23, I2C1, SclPin); +impl_pin!(PIN_24, I2C0, SdaPin); +impl_pin!(PIN_25, I2C0, SclPin); +impl_pin!(PIN_26, I2C1, SdaPin); +impl_pin!(PIN_27, I2C1, SclPin); +impl_pin!(PIN_28, I2C0, SdaPin); +impl_pin!(PIN_29, I2C0, SclPin); diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs new file mode 100644 index 00000000..63dd0023 --- /dev/null +++ b/tests/rp/src/bin/i2c.rs @@ -0,0 +1,215 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{assert_eq, info, panic, unwrap}; +use embassy_executor::Executor; +use embassy_executor::_export::StaticCell; +use embassy_rp::bind_interrupts; +use embassy_rp::i2c::{self, Async, InterruptHandler}; +use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::peripherals::{I2C0, I2C1}; +use embedded_hal_1::i2c::Operation; +use embedded_hal_async::i2c::I2c; +use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _}; + +static mut CORE1_STACK: Stack<1024> = Stack::new(); +static EXECUTOR0: StaticCell = StaticCell::new(); +static EXECUTOR1: StaticCell = StaticCell::new(); + +use crate::i2c::AbortReason; + +bind_interrupts!(struct Irqs { + I2C0_IRQ => InterruptHandler; + I2C1_IRQ => InterruptHandler; +}); + +const DEV_ADDR: u8 = 0x42; + +#[embassy_executor::task] +async fn device_task(mut dev: i2c::I2cDevice<'static, I2C1>) -> ! { + info!("Device start"); + + let mut count = 0xD0; + + loop { + let mut buf = [0u8; 128]; + match dev.listen(&mut buf).await { + Ok(i2c::Command::GeneralCall(len)) => { + assert_eq!(buf[..len], [0xCA, 0x11], "recieving the general call failed"); + info!("General Call - OK"); + } + Ok(i2c::Command::Read) => { + loop { + //info!("Responding to read, count {}", count); + let a = dev.respond_to_read(&[count]).await; + //info!("x {}", a); + match a { + Ok(x) => match x { + i2c::ReadStatus::Done => break, + i2c::ReadStatus::NeedMoreBytes => count += 1, + i2c::ReadStatus::LeftoverBytes(x) => { + info!("tried to write {} extra bytes", x); + break; + } + }, + Err(e) => match e { + embassy_rp::i2c::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n), + _ => panic!("{}", e), + }, + } + } + count += 1; + } + Ok(i2c::Command::Write(len)) => match len { + 1 => { + assert_eq!(buf[..len], [0xAA], "recieving a single byte failed"); + info!("Single Byte Write - OK") + } + 4 => { + assert_eq!(buf[..len], [0xAA, 0xBB, 0xCC, 0xDD], "recieving 4 bytes failed"); + info!("4 Byte Write - OK") + } + 32 => { + assert_eq!( + buf[..len], + [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31 + ], + "recieving 32 bytes failed" + ); + info!("32 Byte Write - OK") + } + _ => panic!("Invalid write length {}", len), + }, + Ok(i2c::Command::WriteRead(len)) => { + info!("device recieved write read: {:x}", buf[..len]); + match buf[0] { + 0xC2 => { + let resp_buff = [0xD1, 0xD2, 0xD3, 0xD4]; + dev.respond_to_read(&resp_buff).await.unwrap(); + } + 0xC8 => { + let mut resp_buff = [0u8; 32]; + for i in 0..32 { + resp_buff[i] = i as u8; + } + dev.respond_to_read(&resp_buff).await.unwrap(); + } + x => panic!("Invalid Write Read {:x}", x), + } + } + Err(e) => match e { + embassy_rp::i2c::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n), + _ => panic!("{}", e), + }, + } + } +} + +#[embassy_executor::task] +async fn controller_task(mut con: i2c::I2c<'static, I2C0, Async>) { + info!("Device start"); + + { + let buf = [0xCA, 0x11]; + con.write(0u16, &buf).await.unwrap(); + info!("Controler general call write"); + embassy_futures::yield_now().await; + } + + { + let mut buf = [0u8]; + con.read(DEV_ADDR, &mut buf).await.unwrap(); + assert_eq!(buf, [0xD0], "single byte read failed"); + info!("single byte read - OK"); + embassy_futures::yield_now().await; + } + + { + let mut buf = [0u8; 4]; + con.read(DEV_ADDR, &mut buf).await.unwrap(); + assert_eq!(buf, [0xD1, 0xD2, 0xD3, 0xD4], "single byte read failed"); + info!("4 byte read - OK"); + embassy_futures::yield_now().await; + } + + { + let buf = [0xAA]; + con.write(DEV_ADDR, &buf).await.unwrap(); + info!("Controler single byte write"); + embassy_futures::yield_now().await; + } + + { + let buf = [0xAA, 0xBB, 0xCC, 0xDD]; + con.write(DEV_ADDR, &buf).await.unwrap(); + info!("Controler 4 byte write"); + embassy_futures::yield_now().await; + } + + { + let mut buf = [0u8; 32]; + for i in 0..32 { + buf[i] = i as u8; + } + con.write(DEV_ADDR, &buf).await.unwrap(); + info!("Controler 32 byte write"); + embassy_futures::yield_now().await; + } + + { + let mut buf = [0u8; 4]; + let mut ops = [Operation::Write(&[0xC2]), Operation::Read(&mut buf)]; + con.transaction(DEV_ADDR, &mut ops).await.unwrap(); + assert_eq!(buf, [0xD1, 0xD2, 0xD3, 0xD4], "write_read failed"); + info!("write_read - OK"); + embassy_futures::yield_now().await; + } + + { + let mut buf = [0u8; 32]; + let mut ops = [Operation::Write(&[0xC8]), Operation::Read(&mut buf)]; + con.transaction(DEV_ADDR, &mut ops).await.unwrap(); + assert_eq!( + buf, + [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31 + ], + "write_read of 32 bytes failed" + ); + info!("large write_read - OK") + } + + info!("Test OK"); + cortex_m::asm::bkpt(); +} + +#[cortex_m_rt::entry] +fn main() -> ! { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + let d_sda = p.PIN_19; + let d_scl = p.PIN_18; + let mut config = i2c::DeviceConfig::default(); + config.addr = DEV_ADDR as u16; + let device = i2c::I2cDevice::new(p.I2C1, d_sda, d_scl, Irqs, config); + + spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { + let executor1 = EXECUTOR1.init(Executor::new()); + executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device)))); + }); + + let executor0 = EXECUTOR0.init(Executor::new()); + + let c_sda = p.PIN_21; + let c_scl = p.PIN_20; + let mut config = i2c::Config::default(); + config.frequency = 5_000; + let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); + + executor0.run(|spawner| unwrap!(spawner.spawn(controller_task(controller)))); +} From 28e25705339e5c275c5025634aab919d52459770 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 31 Aug 2023 08:19:00 -0400 Subject: [PATCH 139/233] Remove debug prints --- embassy-rp/src/i2c/i2c_device.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-rp/src/i2c/i2c_device.rs b/embassy-rp/src/i2c/i2c_device.rs index 915c0424..5c78a86e 100644 --- a/embassy-rp/src/i2c/i2c_device.rs +++ b/embassy-rp/src/i2c/i2c_device.rs @@ -216,14 +216,12 @@ impl<'d, T: Instance> I2cDevice<'d, T> { pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result { let p = T::regs(); - info!("buff: {}", buffer); let mut chunks = buffer.chunks(FIFO_SIZE as usize); let ret = self .wait_on( |me| { if let Err(abort_reason) = me.read_and_clear_abort_reason() { - info!("ar: {}", abort_reason); if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); } else { From 18da91e2529b7973d0476e5c239709b3851db14b Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 4 Sep 2023 16:51:13 -0400 Subject: [PATCH 140/233] Rename to match upstream docs --- embassy-rp/src/i2c/{i2c_device.rs => i2c_slave.rs} | 12 ++++++------ embassy-rp/src/i2c/mod.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) rename embassy-rp/src/i2c/{i2c_device.rs => i2c_slave.rs} (98%) diff --git a/embassy-rp/src/i2c/i2c_device.rs b/embassy-rp/src/i2c/i2c_slave.rs similarity index 98% rename from embassy-rp/src/i2c/i2c_device.rs rename to embassy-rp/src/i2c/i2c_slave.rs index 5c78a86e..154a0f32 100644 --- a/embassy-rp/src/i2c/i2c_device.rs +++ b/embassy-rp/src/i2c/i2c_slave.rs @@ -35,32 +35,32 @@ pub enum ReadStatus { LeftoverBytes(u16), } -/// Device Configuration +/// Slave Configuration #[non_exhaustive] #[derive(Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DeviceConfig { +pub struct SlaveConfig { /// Target Address pub addr: u16, } -impl Default for DeviceConfig { +impl Default for SlaveConfig { fn default() -> Self { Self { addr: 0x55 } } } -pub struct I2cDevice<'d, T: Instance> { +pub struct I2cSlave<'d, T: Instance> { phantom: PhantomData<&'d mut T>, } -impl<'d, T: Instance> I2cDevice<'d, T> { +impl<'d, T: Instance> I2cSlave<'d, T> { pub fn new( _peri: impl Peripheral

+ 'd, scl: impl Peripheral

> + 'd, sda: impl Peripheral

> + 'd, _irq: impl Binding>, - config: DeviceConfig, + config: SlaveConfig, ) -> Self { into_ref!(_peri, scl, sda); diff --git a/embassy-rp/src/i2c/mod.rs b/embassy-rp/src/i2c/mod.rs index 2b3523d6..05662fa6 100644 --- a/embassy-rp/src/i2c/mod.rs +++ b/embassy-rp/src/i2c/mod.rs @@ -1,11 +1,11 @@ mod i2c; -mod i2c_device; +mod i2c_slave; use core::marker::PhantomData; use embassy_sync::waitqueue::AtomicWaker; pub use i2c::{Config, I2c}; -pub use i2c_device::{Command, DeviceConfig, I2cDevice, ReadStatus}; +pub use i2c_slave::{Command, I2cSlave, ReadStatus, SlaveConfig}; use crate::{interrupt, pac, peripherals}; From 2d9f50addc5f509f5549e69f594c382cebe739e6 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sat, 9 Sep 2023 18:25:23 -0400 Subject: [PATCH 141/233] I2c slave take 2 refactored to split modules renamed to match upstream docs slight improvement to slave error handling --- embassy-rp/src/i2c/i2c.rs | 155 ++++++++++++++++- embassy-rp/src/i2c_slave.rs | 326 ++++++++++++++++++++++++++++++++++++ embassy-rp/src/lib.rs | 1 + tests/rp/src/bin/i2c.rs | 33 ++-- 4 files changed, 497 insertions(+), 18 deletions(-) create mode 100644 embassy-rp/src/i2c_slave.rs diff --git a/embassy-rp/src/i2c/i2c.rs b/embassy-rp/src/i2c/i2c.rs index 13124dd8..facc7185 100644 --- a/embassy-rp/src/i2c/i2c.rs +++ b/embassy-rp/src/i2c/i2c.rs @@ -11,7 +11,38 @@ use super::{ use crate::gpio::sealed::Pin; use crate::gpio::AnyPin; use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{pac, Peripheral}; +use crate::{interrupt, pac, peripherals, Peripheral}; + +/// I2C error abort reason +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum AbortReason { + /// A bus operation was not acknowledged, e.g. due to the addressed device + /// not being available on the bus or the device not being ready to process + /// requests at the moment + NoAcknowledge, + /// The arbitration was lost, e.g. electrical problems with the clock signal + ArbitrationLoss, + /// Transmit ended with data still in fifo + TxNotEmpty(u16), + Other(u32), +} + +/// I2C error +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + /// I2C abort with error + Abort(AbortReason), + /// User passed in a read buffer that was 0 length + InvalidReadBufferLength, + /// User passed in a write buffer that was 0 length + InvalidWriteBufferLength, + /// Target i2c address is out of range + AddressOutOfRange(u16), + /// Target i2c address is reserved + AddressReserved(u16), +} #[non_exhaustive] #[derive(Copy, Clone)] @@ -26,6 +57,8 @@ impl Default for Config { } } +pub const FIFO_SIZE: u8 = 16; + pub struct I2c<'d, T: Instance, M: Mode> { phantom: PhantomData<(&'d mut T, M)>, } @@ -696,3 +729,123 @@ mod nightly { } } } +<<<<<<< HEAD:embassy-rp/src/i2c/i2c.rs +======= + +pub fn i2c_reserved_addr(addr: u16) -> bool { + ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 +} + +mod sealed { + use embassy_sync::waitqueue::AtomicWaker; + + use crate::interrupt; + + pub trait Instance { + const TX_DREQ: u8; + const RX_DREQ: u8; + + type Interrupt: interrupt::typelevel::Interrupt; + + fn regs() -> crate::pac::i2c::I2c; + fn reset() -> crate::pac::resets::regs::Peripherals; + fn waker() -> &'static AtomicWaker; + } + + pub trait Mode {} + + pub trait SdaPin {} + pub trait SclPin {} +} + +pub trait Mode: sealed::Mode {} + +macro_rules! impl_mode { + ($name:ident) => { + impl sealed::Mode for $name {} + impl Mode for $name {} + }; +} + +pub struct Blocking; +pub struct Async; + +impl_mode!(Blocking); +impl_mode!(Async); + +pub trait Instance: sealed::Instance {} + +macro_rules! impl_instance { + ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => { + impl sealed::Instance for peripherals::$type { + const TX_DREQ: u8 = $tx_dreq; + const RX_DREQ: u8 = $rx_dreq; + + type Interrupt = crate::interrupt::typelevel::$irq; + + #[inline] + fn regs() -> pac::i2c::I2c { + pac::$type + } + + #[inline] + fn reset() -> pac::resets::regs::Peripherals { + let mut ret = pac::resets::regs::Peripherals::default(); + ret.$reset(true); + ret + } + + #[inline] + fn waker() -> &'static AtomicWaker { + static WAKER: AtomicWaker = AtomicWaker::new(); + + &WAKER + } + } + impl Instance for peripherals::$type {} + }; +} + +impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); +impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); + +pub trait SdaPin: sealed::SdaPin + crate::gpio::Pin {} +pub trait SclPin: sealed::SclPin + crate::gpio::Pin {} + +macro_rules! impl_pin { + ($pin:ident, $instance:ident, $function:ident) => { + impl sealed::$function for peripherals::$pin {} + impl $function for peripherals::$pin {} + }; +} + +impl_pin!(PIN_0, I2C0, SdaPin); +impl_pin!(PIN_1, I2C0, SclPin); +impl_pin!(PIN_2, I2C1, SdaPin); +impl_pin!(PIN_3, I2C1, SclPin); +impl_pin!(PIN_4, I2C0, SdaPin); +impl_pin!(PIN_5, I2C0, SclPin); +impl_pin!(PIN_6, I2C1, SdaPin); +impl_pin!(PIN_7, I2C1, SclPin); +impl_pin!(PIN_8, I2C0, SdaPin); +impl_pin!(PIN_9, I2C0, SclPin); +impl_pin!(PIN_10, I2C1, SdaPin); +impl_pin!(PIN_11, I2C1, SclPin); +impl_pin!(PIN_12, I2C0, SdaPin); +impl_pin!(PIN_13, I2C0, SclPin); +impl_pin!(PIN_14, I2C1, SdaPin); +impl_pin!(PIN_15, I2C1, SclPin); +impl_pin!(PIN_16, I2C0, SdaPin); +impl_pin!(PIN_17, I2C0, SclPin); +impl_pin!(PIN_18, I2C1, SdaPin); +impl_pin!(PIN_19, I2C1, SclPin); +impl_pin!(PIN_20, I2C0, SdaPin); +impl_pin!(PIN_21, I2C0, SclPin); +impl_pin!(PIN_22, I2C1, SdaPin); +impl_pin!(PIN_23, I2C1, SclPin); +impl_pin!(PIN_24, I2C0, SdaPin); +impl_pin!(PIN_25, I2C0, SclPin); +impl_pin!(PIN_26, I2C1, SdaPin); +impl_pin!(PIN_27, I2C1, SclPin); +impl_pin!(PIN_28, I2C0, SdaPin); +impl_pin!(PIN_29, I2C0, SclPin); diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs new file mode 100644 index 00000000..a6525011 --- /dev/null +++ b/embassy-rp/src/i2c_slave.rs @@ -0,0 +1,326 @@ +use core::future; +use core::marker::PhantomData; +use core::task::Poll; + +use embassy_hal_internal::into_ref; +use pac::i2c; + +use crate::i2c::{i2c_reserved_addr, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE}; +use crate::interrupt::typelevel::{Binding, Interrupt}; +use crate::{pac, Peripheral}; + +/// I2C error +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + /// I2C abort with error + Abort(AbortReason), + /// User passed in a response buffer that was 0 length + InvalidResponseBufferLength, +} + +/// Received command +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Command { + /// General Call + GeneralCall(usize), + /// Read + Read, + /// Write+read + WriteRead(usize), + /// Write + Write(usize), +} + +/// Possible responses to responding to a read +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ReadStatus { + /// Transaction Complete, controller naked our last byte + Done, + /// Transaction Incomplete, controller trying to read more bytes than were provided + NeedMoreBytes, + /// Transaction Complere, but controller stopped reading bytes before we ran out + LeftoverBytes(u16), +} + +/// Slave Configuration +#[non_exhaustive] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Config { + /// Target Address + pub addr: u16, +} + +impl Default for Config { + fn default() -> Self { + Self { addr: 0x55 } + } +} + +pub struct I2cSlave<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, +} + +impl<'d, T: Instance> I2cSlave<'d, T> { + pub fn new( + _peri: impl Peripheral

+ 'd, + scl: impl Peripheral

> + 'd, + sda: impl Peripheral

> + 'd, + _irq: impl Binding>, + config: Config, + ) -> Self { + into_ref!(_peri, scl, sda); + + assert!(!i2c_reserved_addr(config.addr)); + assert!(config.addr != 0); + + let p = T::regs(); + + let reset = T::reset(); + crate::reset::reset(reset); + crate::reset::unreset_wait(reset); + + p.ic_enable().write(|w| w.set_enable(false)); + + p.ic_sar().write(|w| w.set_ic_sar(config.addr)); + p.ic_con().modify(|w| { + w.set_master_mode(false); + w.set_ic_slave_disable(false); + w.set_tx_empty_ctrl(true); + }); + + // Set FIFO watermarks to 1 to make things simpler. This is encoded + // by a register value of 0. Rx watermark should never change, but Tx watermark will be + // adjusted in operation. + p.ic_tx_tl().write(|w| w.set_tx_tl(0)); + p.ic_rx_tl().write(|w| w.set_rx_tl(0)); + + // Configure SCL & SDA pins + scl.gpio().ctrl().write(|w| w.set_funcsel(3)); + sda.gpio().ctrl().write(|w| w.set_funcsel(3)); + + scl.pad_ctrl().write(|w| { + w.set_schmitt(true); + w.set_ie(true); + w.set_od(false); + w.set_pue(true); + w.set_pde(false); + }); + sda.pad_ctrl().write(|w| { + w.set_schmitt(true); + w.set_ie(true); + w.set_od(false); + w.set_pue(true); + w.set_pde(false); + }); + + // Clear interrupts + p.ic_clr_intr().read(); + + // Enable I2C block + p.ic_enable().write(|w| w.set_enable(true)); + + // mask everything initially + p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + Self { phantom: PhantomData } + } + + /// Calls `f` to check if we are ready or not. + /// If not, `g` is called once the waker is set (to eg enable the required interrupts). + #[inline(always)] + async fn wait_on(&mut self, mut f: F, mut g: G) -> U + where + F: FnMut(&mut Self) -> Poll, + G: FnMut(&mut Self), + { + future::poll_fn(|cx| { + let r = f(self); + + trace!("intr p: {:013b}", T::regs().ic_raw_intr_stat().read().0); + + if r.is_pending() { + T::waker().register(cx.waker()); + g(self); + } + + r + }) + .await + } + + #[inline(always)] + fn drain_fifo(&mut self, buffer: &mut [u8], offset: usize) -> usize { + let p = T::regs(); + let len = p.ic_rxflr().read().rxflr() as usize; + let end = offset + len; + for i in offset..end { + buffer[i] = p.ic_data_cmd().read().dat(); + } + end + } + + #[inline(always)] + fn write_to_fifo(&mut self, buffer: &[u8]) { + let p = T::regs(); + for byte in buffer { + p.ic_data_cmd().write(|w| w.set_dat(*byte)); + } + } + + /// Wait asynchronously for commands from an I2C master. + /// `buffer` is provided in case master does a 'write' and is unused for 'read'. + pub async fn listen(&mut self, buffer: &mut [u8]) -> Result { + let p = T::regs(); + + p.ic_clr_intr().read(); + // set rx fifo watermark to 1 byte + p.ic_rx_tl().write(|w| w.set_rx_tl(0)); + + let mut len = 0; + let ret = self + .wait_on( + |me| { + let stat = p.ic_raw_intr_stat().read(); + if p.ic_rxflr().read().rxflr() > 0 { + len = me.drain_fifo(buffer, len); + // we're recieving data, set rx fifo watermark to 12 bytes to reduce interrupt noise + p.ic_rx_tl().write(|w| w.set_rx_tl(11)); + } + + if stat.restart_det() && stat.rd_req() { + Poll::Ready(Ok(Command::WriteRead(len))) + } else if stat.gen_call() && stat.stop_det() && len > 0 { + Poll::Ready(Ok(Command::GeneralCall(len))) + } else if stat.stop_det() { + Poll::Ready(Ok(Command::Write(len))) + } else if stat.rd_req() { + Poll::Ready(Ok(Command::Read)) + } else { + Poll::Pending + } + }, + |_me| { + p.ic_intr_mask().modify(|w| { + w.set_m_stop_det(true); + w.set_m_restart_det(true); + w.set_m_gen_call(true); + w.set_m_rd_req(true); + w.set_m_rx_full(true); + }); + }, + ) + .await; + + p.ic_clr_intr().read(); + + ret + } + + /// Respond to an I2C master READ command, asynchronously. + pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result { + let p = T::regs(); + + if buffer.len() == 0 { + return Err(Error::InvalidResponseBufferLength); + } + + let mut chunks = buffer.chunks(FIFO_SIZE as usize); + + let ret = self + .wait_on( + |me| { + if let Err(abort_reason) = me.read_and_clear_abort_reason() { + if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { + return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); + } else { + return Poll::Ready(Err(abort_reason)); + } + } + + if let Some(chunk) = chunks.next() { + me.write_to_fifo(chunk); + + Poll::Pending + } else { + let stat = p.ic_raw_intr_stat().read(); + + if stat.rx_done() && stat.stop_det() { + Poll::Ready(Ok(ReadStatus::Done)) + } else if stat.rd_req() { + Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) + } else { + Poll::Pending + } + } + }, + |_me| { + p.ic_intr_mask().modify(|w| { + w.set_m_stop_det(true); + w.set_m_rx_done(true); + w.set_m_tx_empty(true); + w.set_m_tx_abrt(true); + }) + }, + ) + .await; + + p.ic_clr_intr().read(); + + ret + } + + /// Respond to reads with the fill byte until the controller stops asking + pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> { + loop { + match self.respond_to_read(&[fill]).await { + Ok(ReadStatus::NeedMoreBytes) => (), + Ok(_) => break Ok(()), + Err(e) => break Err(e), + } + } + } + + #[inline(always)] + fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { + let p = T::regs(); + let mut abort_reason = p.ic_tx_abrt_source().read(); + + // Mask off fifo flush count + let tx_flush_cnt = abort_reason.tx_flush_cnt(); + abort_reason.set_tx_flush_cnt(0); + + // Mask off master_dis + abort_reason.set_abrt_master_dis(false); + + if abort_reason.0 != 0 { + // Note clearing the abort flag also clears the reason, and this + // instance of flag is clear-on-read! Note also the + // IC_CLR_TX_ABRT register always reads as 0. + p.ic_clr_tx_abrt().read(); + + let reason = if abort_reason.abrt_7b_addr_noack() + | abort_reason.abrt_10addr1_noack() + | abort_reason.abrt_10addr2_noack() + { + AbortReason::NoAcknowledge + } else if abort_reason.arb_lost() { + AbortReason::ArbitrationLoss + } else if abort_reason.abrt_slvflush_txfifo() { + AbortReason::TxNotEmpty(tx_flush_cnt) + } else { + AbortReason::Other(abort_reason.0) + }; + + Err(Error::Abort(reason)) + } else { + Ok(()) + } + } +} diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 49bd3533..2a1bca4b 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -16,6 +16,7 @@ pub mod flash; mod float; pub mod gpio; pub mod i2c; +pub mod i2c_slave; pub mod multicore; pub mod pwm; mod reset; diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs index 63dd0023..a6cf48af 100644 --- a/tests/rp/src/bin/i2c.rs +++ b/tests/rp/src/bin/i2c.rs @@ -5,10 +5,9 @@ use defmt::{assert_eq, info, panic, unwrap}; use embassy_executor::Executor; use embassy_executor::_export::StaticCell; -use embassy_rp::bind_interrupts; -use embassy_rp::i2c::{self, Async, InterruptHandler}; use embassy_rp::multicore::{spawn_core1, Stack}; use embassy_rp::peripherals::{I2C0, I2C1}; +use embassy_rp::{bind_interrupts, i2c, i2c_slave}; use embedded_hal_1::i2c::Operation; use embedded_hal_async::i2c::I2c; use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _}; @@ -20,14 +19,14 @@ static EXECUTOR1: StaticCell = StaticCell::new(); use crate::i2c::AbortReason; bind_interrupts!(struct Irqs { - I2C0_IRQ => InterruptHandler; - I2C1_IRQ => InterruptHandler; + I2C0_IRQ => i2c::InterruptHandler; + I2C1_IRQ => i2c::InterruptHandler; }); const DEV_ADDR: u8 = 0x42; #[embassy_executor::task] -async fn device_task(mut dev: i2c::I2cDevice<'static, I2C1>) -> ! { +async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { info!("Device start"); let mut count = 0xD0; @@ -35,33 +34,33 @@ async fn device_task(mut dev: i2c::I2cDevice<'static, I2C1>) -> ! { loop { let mut buf = [0u8; 128]; match dev.listen(&mut buf).await { - Ok(i2c::Command::GeneralCall(len)) => { + Ok(i2c_slave::Command::GeneralCall(len)) => { assert_eq!(buf[..len], [0xCA, 0x11], "recieving the general call failed"); info!("General Call - OK"); } - Ok(i2c::Command::Read) => { + Ok(i2c_slave::Command::Read) => { loop { //info!("Responding to read, count {}", count); let a = dev.respond_to_read(&[count]).await; //info!("x {}", a); match a { Ok(x) => match x { - i2c::ReadStatus::Done => break, - i2c::ReadStatus::NeedMoreBytes => count += 1, - i2c::ReadStatus::LeftoverBytes(x) => { + i2c_slave::ReadStatus::Done => break, + i2c_slave::ReadStatus::NeedMoreBytes => count += 1, + i2c_slave::ReadStatus::LeftoverBytes(x) => { info!("tried to write {} extra bytes", x); break; } }, Err(e) => match e { - embassy_rp::i2c::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n), + embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n), _ => panic!("{}", e), }, } } count += 1; } - Ok(i2c::Command::Write(len)) => match len { + Ok(i2c_slave::Command::Write(len)) => match len { 1 => { assert_eq!(buf[..len], [0xAA], "recieving a single byte failed"); info!("Single Byte Write - OK") @@ -83,7 +82,7 @@ async fn device_task(mut dev: i2c::I2cDevice<'static, I2C1>) -> ! { } _ => panic!("Invalid write length {}", len), }, - Ok(i2c::Command::WriteRead(len)) => { + Ok(i2c_slave::Command::WriteRead(len)) => { info!("device recieved write read: {:x}", buf[..len]); match buf[0] { 0xC2 => { @@ -101,7 +100,7 @@ async fn device_task(mut dev: i2c::I2cDevice<'static, I2C1>) -> ! { } } Err(e) => match e { - embassy_rp::i2c::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n), + embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n), _ => panic!("{}", e), }, } @@ -109,7 +108,7 @@ async fn device_task(mut dev: i2c::I2cDevice<'static, I2C1>) -> ! { } #[embassy_executor::task] -async fn controller_task(mut con: i2c::I2c<'static, I2C0, Async>) { +async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) { info!("Device start"); { @@ -194,9 +193,9 @@ fn main() -> ! { let d_sda = p.PIN_19; let d_scl = p.PIN_18; - let mut config = i2c::DeviceConfig::default(); + let mut config = i2c_slave::Config::default(); config.addr = DEV_ADDR as u16; - let device = i2c::I2cDevice::new(p.I2C1, d_sda, d_scl, Irqs, config); + let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { let executor1 = EXECUTOR1.init(Executor::new()); From 8201979d719f7f2647c7cb83b8e28bfc636b9d4a Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sun, 10 Sep 2023 02:05:58 -0400 Subject: [PATCH 142/233] Add example, fix small bug in respond_and_fill --- embassy-rp/src/i2c_slave.rs | 12 ++++ examples/rp/src/bin/i2c_slave.rs | 118 +++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 examples/rp/src/bin/i2c_slave.rs diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index a6525011..6136d69c 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -287,6 +287,18 @@ impl<'d, T: Instance> I2cSlave<'d, T> { } } + /// Respond to a master read, then fill any remaining read bytes with `fill` + pub async fn respond_and_fill(&mut self, buffer: &[u8], fill: u8) -> Result { + let resp_stat = self.respond_to_read(buffer).await?; + + if resp_stat == ReadStatus::NeedMoreBytes { + self.respond_till_stop(fill).await?; + Ok(ReadStatus::Done) + } else { + Ok(resp_stat) + } + } + #[inline(always)] fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { let p = T::regs(); diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs new file mode 100644 index 00000000..7de300fb --- /dev/null +++ b/examples/rp/src/bin/i2c_slave.rs @@ -0,0 +1,118 @@ +//! This example shows how to use the 2040 as an i2c slave. +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::peripherals::{I2C0, I2C1}; +use embassy_rp::{bind_interrupts, i2c, i2c_slave}; +use embassy_time::{Duration, Timer}; +use embedded_hal_async::i2c::I2c; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + I2C0_IRQ => i2c::InterruptHandler; + I2C1_IRQ => i2c::InterruptHandler; +}); + +const DEV_ADDR: u8 = 0x42; + +#[embassy_executor::task] +async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { + info!("Device start"); + + let mut state = 0; + + loop { + let mut buf = [0u8; 128]; + match dev.listen(&mut buf).await { + Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device recieved general call write: {}", buf[..len]), + Ok(i2c_slave::Command::Read) => loop { + match dev.respond_to_read(&[state]).await { + Ok(x) => match x { + i2c_slave::ReadStatus::Done => break, + i2c_slave::ReadStatus::NeedMoreBytes => (), + i2c_slave::ReadStatus::LeftoverBytes(x) => { + info!("tried to write {} extra bytes", x); + break; + } + }, + Err(e) => error!("error while responding {}", e), + } + }, + Ok(i2c_slave::Command::Write(len)) => info!("Device recieved write: {}", buf[..len]), + Ok(i2c_slave::Command::WriteRead(len)) => { + info!("device recieved write read: {:x}", buf[..len]); + match buf[0] { + // Set the state + 0xC2 => { + state = buf[1]; + match dev.respond_and_fill(&[state], 0x00).await { + Ok(read_status) => info!("response read status {}", read_status), + Err(e) => error!("error while responding {}", e), + } + } + // Reset State + 0xC8 => { + state = 0; + match dev.respond_and_fill(&[state], 0x00).await { + Ok(read_status) => info!("response read status {}", read_status), + Err(e) => error!("error while responding {}", e), + } + } + x => error!("Invalid Write Read {:x}", x), + } + } + Err(e) => error!("{}", e), + } + } +} + +#[embassy_executor::task] +async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) { + info!("Controller start"); + + loop { + let mut resp_buff = [0u8; 2]; + for i in 0..10 { + match con.write_read(DEV_ADDR, &[0xC2, i], &mut resp_buff).await { + Ok(_) => info!("write_read response: {}", resp_buff), + Err(e) => error!("Error writing {}", e), + } + + Timer::after(Duration::from_millis(100)).await; + } + match con.read(DEV_ADDR, &mut resp_buff).await { + Ok(_) => info!("read response: {}", resp_buff), + Err(e) => error!("Error writing {}", e), + } + match con.write_read(DEV_ADDR, &[0xC8], &mut resp_buff).await { + Ok(_) => info!("write_read response: {}", resp_buff), + Err(e) => error!("Error writing {}", e), + } + Timer::after(Duration::from_millis(100)).await; + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + let d_sda = p.PIN_3; + let d_scl = p.PIN_2; + let mut config = i2c_slave::Config::default(); + config.addr = DEV_ADDR as u16; + let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); + + unwrap!(spawner.spawn(device_task(device))); + + let c_sda = p.PIN_1; + let c_scl = p.PIN_0; + let mut config = i2c::Config::default(); + config.frequency = 5_000; + let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); + + unwrap!(spawner.spawn(controller_task(controller))); +} From 8900f5f52b1140de960511f4ee6a13203d5c7b38 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sun, 10 Sep 2023 02:34:16 -0400 Subject: [PATCH 143/233] Fixing my git-based mistakes --- embassy-rp/src/{i2c => }/i2c.rs | 21 ++- embassy-rp/src/i2c/i2c_slave.rs | 311 -------------------------------- embassy-rp/src/i2c/mod.rs | 175 ------------------ 3 files changed, 15 insertions(+), 492 deletions(-) rename embassy-rp/src/{i2c => }/i2c.rs (98%) delete mode 100644 embassy-rp/src/i2c/i2c_slave.rs delete mode 100644 embassy-rp/src/i2c/mod.rs diff --git a/embassy-rp/src/i2c/i2c.rs b/embassy-rp/src/i2c.rs similarity index 98% rename from embassy-rp/src/i2c/i2c.rs rename to embassy-rp/src/i2c.rs index facc7185..c358682c 100644 --- a/embassy-rp/src/i2c/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -3,11 +3,9 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; use pac::i2c; -use super::{ - i2c_reserved_addr, AbortReason, Async, Blocking, Error, Instance, InterruptHandler, Mode, SclPin, SdaPin, FIFO_SIZE, -}; use crate::gpio::sealed::Pin; use crate::gpio::AnyPin; use crate::interrupt::typelevel::{Binding, Interrupt}; @@ -46,7 +44,6 @@ pub enum Error { #[non_exhaustive] #[derive(Copy, Clone)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Config { pub frequency: u32, } @@ -307,6 +304,20 @@ impl<'d, T: Instance> I2c<'d, T, Async> { } } +pub struct InterruptHandler { + _uart: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + // Mask interrupts and wake any task waiting for this interrupt + unsafe fn on_interrupt() { + let i2c = T::regs(); + i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default()); + + T::waker().wake(); + } +} + impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { fn new_inner( _peri: impl Peripheral

+ 'd, @@ -729,8 +740,6 @@ mod nightly { } } } -<<<<<<< HEAD:embassy-rp/src/i2c/i2c.rs -======= pub fn i2c_reserved_addr(addr: u16) -> bool { ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 diff --git a/embassy-rp/src/i2c/i2c_slave.rs b/embassy-rp/src/i2c/i2c_slave.rs deleted file mode 100644 index 154a0f32..00000000 --- a/embassy-rp/src/i2c/i2c_slave.rs +++ /dev/null @@ -1,311 +0,0 @@ -use core::future; -use core::marker::PhantomData; -use core::task::Poll; - -use embassy_hal_internal::into_ref; -use pac::i2c; - -use super::{i2c_reserved_addr, AbortReason, Error, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE}; -use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{pac, Peripheral}; - -/// Received command -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Command { - /// General Call - GeneralCall(usize), - /// Read - Read, - /// Write+read - WriteRead(usize), - /// Write - Write(usize), -} - -/// Possible responses to responding to a read -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum ReadStatus { - /// Transaction Complete, controller naked our last byte - Done, - /// Transaction Incomplete, controller trying to read more bytes than were provided - NeedMoreBytes, - /// Transaction Complere, but controller stopped reading bytes before we ran out - LeftoverBytes(u16), -} - -/// Slave Configuration -#[non_exhaustive] -#[derive(Copy, Clone)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct SlaveConfig { - /// Target Address - pub addr: u16, -} - -impl Default for SlaveConfig { - fn default() -> Self { - Self { addr: 0x55 } - } -} - -pub struct I2cSlave<'d, T: Instance> { - phantom: PhantomData<&'d mut T>, -} - -impl<'d, T: Instance> I2cSlave<'d, T> { - pub fn new( - _peri: impl Peripheral

+ 'd, - scl: impl Peripheral

> + 'd, - sda: impl Peripheral

> + 'd, - _irq: impl Binding>, - config: SlaveConfig, - ) -> Self { - into_ref!(_peri, scl, sda); - - assert!(!i2c_reserved_addr(config.addr)); - assert!(config.addr != 0); - - let p = T::regs(); - - let reset = T::reset(); - crate::reset::reset(reset); - crate::reset::unreset_wait(reset); - - p.ic_enable().write(|w| w.set_enable(false)); - - p.ic_sar().write(|w| w.set_ic_sar(config.addr)); - p.ic_con().modify(|w| { - w.set_master_mode(false); - w.set_ic_slave_disable(false); - w.set_tx_empty_ctrl(true); - }); - - // Set FIFO watermarks to 1 to make things simpler. This is encoded - // by a register value of 0. Rx watermark should never change, but Tx watermark will be - // adjusted in operation. - p.ic_tx_tl().write(|w| w.set_tx_tl(0)); - p.ic_rx_tl().write(|w| w.set_rx_tl(0)); - - // Configure SCL & SDA pins - scl.gpio().ctrl().write(|w| w.set_funcsel(3)); - sda.gpio().ctrl().write(|w| w.set_funcsel(3)); - - scl.pad_ctrl().write(|w| { - w.set_schmitt(true); - w.set_ie(true); - w.set_od(false); - w.set_pue(true); - w.set_pde(false); - }); - sda.pad_ctrl().write(|w| { - w.set_schmitt(true); - w.set_ie(true); - w.set_od(false); - w.set_pue(true); - w.set_pde(false); - }); - - // Clear interrupts - p.ic_clr_intr().read(); - - // Enable I2C block - p.ic_enable().write(|w| w.set_enable(true)); - - // mask everything initially - p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; - - Self { phantom: PhantomData } - } - - /// Calls `f` to check if we are ready or not. - /// If not, `g` is called once the waker is set (to eg enable the required interrupts). - #[inline(always)] - async fn wait_on(&mut self, mut f: F, mut g: G) -> U - where - F: FnMut(&mut Self) -> Poll, - G: FnMut(&mut Self), - { - future::poll_fn(|cx| { - let r = f(self); - - trace!("intr p: {:013b}", T::regs().ic_raw_intr_stat().read().0); - - if r.is_pending() { - T::waker().register(cx.waker()); - g(self); - } - - r - }) - .await - } - - #[inline(always)] - fn drain_fifo(&mut self, buffer: &mut [u8], offset: usize) -> usize { - let p = T::regs(); - let len = p.ic_rxflr().read().rxflr() as usize; - let end = offset + len; - for i in offset..end { - buffer[i] = p.ic_data_cmd().read().dat(); - } - end - } - - #[inline(always)] - fn write_to_fifo(&mut self, buffer: &[u8]) { - let p = T::regs(); - for byte in buffer { - p.ic_data_cmd().write(|w| w.set_dat(*byte)); - } - } - - /// Wait asynchronously for commands from an I2C master. - /// `buffer` is provided in case master does a 'write' and is unused for 'read'. - pub async fn listen(&mut self, buffer: &mut [u8]) -> Result { - let p = T::regs(); - - p.ic_clr_intr().read(); - // set rx fifo watermark to 1 byte - p.ic_rx_tl().write(|w| w.set_rx_tl(0)); - - let mut len = 0; - let ret = self - .wait_on( - |me| { - let stat = p.ic_raw_intr_stat().read(); - if p.ic_rxflr().read().rxflr() > 0 { - len = me.drain_fifo(buffer, len); - // we're recieving data, set rx fifo watermark to 12 bytes to reduce interrupt noise - p.ic_rx_tl().write(|w| w.set_rx_tl(11)); - } - - if stat.restart_det() && stat.rd_req() { - Poll::Ready(Ok(Command::WriteRead(len))) - } else if stat.gen_call() && stat.stop_det() && len > 0 { - Poll::Ready(Ok(Command::GeneralCall(len))) - } else if stat.stop_det() { - Poll::Ready(Ok(Command::Write(len))) - } else if stat.rd_req() { - Poll::Ready(Ok(Command::Read)) - } else { - Poll::Pending - } - }, - |_me| { - p.ic_intr_mask().modify(|w| { - w.set_m_stop_det(true); - w.set_m_restart_det(true); - w.set_m_gen_call(true); - w.set_m_rd_req(true); - w.set_m_rx_full(true); - }); - }, - ) - .await; - - p.ic_clr_intr().read(); - - ret - } - - /// Respond to an I2C master READ command, asynchronously. - pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result { - let p = T::regs(); - - let mut chunks = buffer.chunks(FIFO_SIZE as usize); - - let ret = self - .wait_on( - |me| { - if let Err(abort_reason) = me.read_and_clear_abort_reason() { - if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { - return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); - } else { - return Poll::Ready(Err(abort_reason)); - } - } - - if let Some(chunk) = chunks.next() { - me.write_to_fifo(chunk); - - Poll::Pending - } else { - let stat = p.ic_raw_intr_stat().read(); - - if stat.rx_done() && stat.stop_det() { - Poll::Ready(Ok(ReadStatus::Done)) - } else if stat.rd_req() { - Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) - } else { - Poll::Pending - } - } - }, - |_me| { - p.ic_intr_mask().modify(|w| { - w.set_m_stop_det(true); - w.set_m_rx_done(true); - w.set_m_tx_empty(true); - w.set_m_tx_abrt(true); - }) - }, - ) - .await; - - p.ic_clr_intr().read(); - - ret - } - - /// Respond to reads with the fill byte until the controller stops asking - pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> { - loop { - match self.respond_to_read(&[fill]).await { - Ok(ReadStatus::NeedMoreBytes) => (), - Ok(_) => break Ok(()), - Err(e) => break Err(e), - } - } - } - - #[inline(always)] - fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { - let p = T::regs(); - let mut abort_reason = p.ic_tx_abrt_source().read(); - - // Mask off fifo flush count - let tx_flush_cnt = abort_reason.tx_flush_cnt(); - abort_reason.set_tx_flush_cnt(0); - - // Mask off master_dis - abort_reason.set_abrt_master_dis(false); - - if abort_reason.0 != 0 { - // Note clearing the abort flag also clears the reason, and this - // instance of flag is clear-on-read! Note also the - // IC_CLR_TX_ABRT register always reads as 0. - p.ic_clr_tx_abrt().read(); - - let reason = if abort_reason.abrt_7b_addr_noack() - | abort_reason.abrt_10addr1_noack() - | abort_reason.abrt_10addr2_noack() - { - AbortReason::NoAcknowledge - } else if abort_reason.arb_lost() { - AbortReason::ArbitrationLoss - } else if abort_reason.abrt_slvflush_txfifo() { - AbortReason::TxNotEmpty(tx_flush_cnt) - } else { - AbortReason::Other(abort_reason.0) - }; - - Err(Error::Abort(reason)) - } else { - Ok(()) - } - } -} diff --git a/embassy-rp/src/i2c/mod.rs b/embassy-rp/src/i2c/mod.rs deleted file mode 100644 index 05662fa6..00000000 --- a/embassy-rp/src/i2c/mod.rs +++ /dev/null @@ -1,175 +0,0 @@ -mod i2c; -mod i2c_slave; - -use core::marker::PhantomData; - -use embassy_sync::waitqueue::AtomicWaker; -pub use i2c::{Config, I2c}; -pub use i2c_slave::{Command, I2cSlave, ReadStatus, SlaveConfig}; - -use crate::{interrupt, pac, peripherals}; - -const FIFO_SIZE: u8 = 16; - -/// I2C error abort reason -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum AbortReason { - /// A bus operation was not acknowledged, e.g. due to the addressed device - /// not being available on the bus or the device not being ready to process - /// requests at the moment - NoAcknowledge, - /// The arbitration was lost, e.g. electrical problems with the clock signal - ArbitrationLoss, - /// Transmit ended with data still in fifo - TxNotEmpty(u16), - Other(u32), -} - -/// I2C error -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Error { - /// I2C abort with error - Abort(AbortReason), - /// User passed in a read buffer that was 0 length - InvalidReadBufferLength, - /// User passed in a write buffer that was 0 length - InvalidWriteBufferLength, - /// Target i2c address is out of range - AddressOutOfRange(u16), - /// Target i2c address is reserved - AddressReserved(u16), -} - -pub struct InterruptHandler { - _uart: PhantomData, -} - -impl interrupt::typelevel::Handler for InterruptHandler { - // Mask interrupts and wake any task waiting for this interrupt - unsafe fn on_interrupt() { - let i2c = T::regs(); - i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default()); - - T::waker().wake(); - } -} - -fn i2c_reserved_addr(addr: u16) -> bool { - ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 -} - -mod sealed { - use embassy_sync::waitqueue::AtomicWaker; - - use crate::interrupt; - - pub trait Instance { - const TX_DREQ: u8; - const RX_DREQ: u8; - - type Interrupt: interrupt::typelevel::Interrupt; - - fn regs() -> crate::pac::i2c::I2c; - fn reset() -> crate::pac::resets::regs::Peripherals; - fn waker() -> &'static AtomicWaker; - } - - pub trait Mode {} - - pub trait SdaPin {} - pub trait SclPin {} -} - -pub trait Mode: sealed::Mode {} - -macro_rules! impl_mode { - ($name:ident) => { - impl sealed::Mode for $name {} - impl Mode for $name {} - }; -} - -pub struct Blocking; -pub struct Async; - -impl_mode!(Blocking); -impl_mode!(Async); - -pub trait Instance: sealed::Instance {} - -macro_rules! impl_instance { - ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => { - impl sealed::Instance for peripherals::$type { - const TX_DREQ: u8 = $tx_dreq; - const RX_DREQ: u8 = $rx_dreq; - - type Interrupt = crate::interrupt::typelevel::$irq; - - #[inline] - fn regs() -> pac::i2c::I2c { - pac::$type - } - - #[inline] - fn reset() -> pac::resets::regs::Peripherals { - let mut ret = pac::resets::regs::Peripherals::default(); - ret.$reset(true); - ret - } - - #[inline] - fn waker() -> &'static AtomicWaker { - static WAKER: AtomicWaker = AtomicWaker::new(); - - &WAKER - } - } - impl Instance for peripherals::$type {} - }; -} - -impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); -impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); - -pub trait SdaPin: sealed::SdaPin + crate::gpio::Pin {} -pub trait SclPin: sealed::SclPin + crate::gpio::Pin {} - -macro_rules! impl_pin { - ($pin:ident, $instance:ident, $function:ident) => { - impl sealed::$function for peripherals::$pin {} - impl $function for peripherals::$pin {} - }; -} - -impl_pin!(PIN_0, I2C0, SdaPin); -impl_pin!(PIN_1, I2C0, SclPin); -impl_pin!(PIN_2, I2C1, SdaPin); -impl_pin!(PIN_3, I2C1, SclPin); -impl_pin!(PIN_4, I2C0, SdaPin); -impl_pin!(PIN_5, I2C0, SclPin); -impl_pin!(PIN_6, I2C1, SdaPin); -impl_pin!(PIN_7, I2C1, SclPin); -impl_pin!(PIN_8, I2C0, SdaPin); -impl_pin!(PIN_9, I2C0, SclPin); -impl_pin!(PIN_10, I2C1, SdaPin); -impl_pin!(PIN_11, I2C1, SclPin); -impl_pin!(PIN_12, I2C0, SdaPin); -impl_pin!(PIN_13, I2C0, SclPin); -impl_pin!(PIN_14, I2C1, SdaPin); -impl_pin!(PIN_15, I2C1, SclPin); -impl_pin!(PIN_16, I2C0, SdaPin); -impl_pin!(PIN_17, I2C0, SclPin); -impl_pin!(PIN_18, I2C1, SdaPin); -impl_pin!(PIN_19, I2C1, SclPin); -impl_pin!(PIN_20, I2C0, SdaPin); -impl_pin!(PIN_21, I2C0, SclPin); -impl_pin!(PIN_22, I2C1, SdaPin); -impl_pin!(PIN_23, I2C1, SclPin); -impl_pin!(PIN_24, I2C0, SdaPin); -impl_pin!(PIN_25, I2C0, SclPin); -impl_pin!(PIN_26, I2C1, SdaPin); -impl_pin!(PIN_27, I2C1, SclPin); -impl_pin!(PIN_28, I2C0, SdaPin); -impl_pin!(PIN_29, I2C0, SclPin); From 8edb7bb012b43977ee57f9ebff9b57436a0a904f Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sun, 10 Sep 2023 03:05:54 -0400 Subject: [PATCH 144/233] Test cleanup --- tests/rp/src/bin/i2c.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs index a6cf48af..4b6becba 100644 --- a/tests/rp/src/bin/i2c.rs +++ b/tests/rp/src/bin/i2c.rs @@ -40,10 +40,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { } Ok(i2c_slave::Command::Read) => { loop { - //info!("Responding to read, count {}", count); - let a = dev.respond_to_read(&[count]).await; - //info!("x {}", a); - match a { + match dev.respond_to_read(&[count]).await { Ok(x) => match x { i2c_slave::ReadStatus::Done => break, i2c_slave::ReadStatus::NeedMoreBytes => count += 1, From 5cf494113f7681ac6436bdbd7972e0074d1d26b7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 10 Sep 2023 22:20:05 +0200 Subject: [PATCH 145/233] tests/rp: add teleprobe meta. --- tests/rp/src/bin/i2c.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs index 4b6becba..425f2d08 100644 --- a/tests/rp/src/bin/i2c.rs +++ b/tests/rp/src/bin/i2c.rs @@ -1,6 +1,7 @@ #![no_std] #![no_main] #![feature(type_alias_impl_trait)] +teleprobe_meta::target!(b"rpi-pico"); use defmt::{assert_eq, info, panic, unwrap}; use embassy_executor::Executor; From db717d9c81c76709ea84727a31fc4a201e947014 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 6 Sep 2023 16:42:04 +0300 Subject: [PATCH 146/233] nrf: Remove unneeded include from Temp's example Fixes doctest when `time` feature is not enabled. --- embassy-nrf/src/temp.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index cec46d8d..5e2998b1 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs @@ -57,7 +57,6 @@ impl<'d> Temp<'d> { /// ```no_run /// use embassy_nrf::{bind_interrupts, temp}; /// use embassy_nrf::temp::Temp; - /// use embassy_time::{Duration, Timer}; /// /// bind_interrupts!(struct Irqs { /// TEMP => temp::InterruptHandler; From 8413a89752b672cf21a7cd4e07a9d0f3cccfac33 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 6 Sep 2023 16:44:02 +0300 Subject: [PATCH 147/233] nrf: spim: Use SetConfig trait internally to reduce duplication --- embassy-nrf/src/spim.rs | 40 ++++------------------------------------ 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index a468bc30..99a195a6 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -189,42 +189,10 @@ impl<'d, T: Instance> Spim<'d, T> { // Enable SPIM instance. r.enable.write(|w| w.enable().enabled()); - // Configure mode. - let mode = config.mode; - r.config.write(|w| { - match mode { - MODE_0 => { - w.order().msb_first(); - w.cpol().active_high(); - w.cpha().leading(); - } - MODE_1 => { - w.order().msb_first(); - w.cpol().active_high(); - w.cpha().trailing(); - } - MODE_2 => { - w.order().msb_first(); - w.cpol().active_low(); - w.cpha().leading(); - } - MODE_3 => { - w.order().msb_first(); - w.cpol().active_low(); - w.cpha().trailing(); - } - } + let mut spim = Self { _p: spim }; - w - }); - - // Configure frequency. - let frequency = config.frequency; - r.frequency.write(|w| w.frequency().variant(frequency)); - - // Set over-read character - let orc = config.orc; - r.orc.write(|w| unsafe { w.orc().bits(orc) }); + // Apply runtime peripheral configuration + Self::set_config(&mut spim, &config); // Disable all events interrupts r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); @@ -232,7 +200,7 @@ impl<'d, T: Instance> Spim<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { _p: spim } + spim } fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { From 93d4cfe7c10cfacc8ac88dd75a88d76e71476db0 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 6 Sep 2023 16:46:17 +0300 Subject: [PATCH 148/233] nrf: spis: Use SetConfig trait internally to reduce duplication --- embassy-nrf/src/spis.rs | 45 ++++------------------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 21282512..e695ba6b 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -169,47 +169,10 @@ impl<'d, T: Instance> Spis<'d, T> { // Enable SPIS instance. r.enable.write(|w| w.enable().enabled()); - // Configure mode. - let mode = config.mode; - r.config.write(|w| { - match mode { - MODE_0 => { - w.order().msb_first(); - w.cpol().active_high(); - w.cpha().leading(); - } - MODE_1 => { - w.order().msb_first(); - w.cpol().active_high(); - w.cpha().trailing(); - } - MODE_2 => { - w.order().msb_first(); - w.cpol().active_low(); - w.cpha().leading(); - } - MODE_3 => { - w.order().msb_first(); - w.cpol().active_low(); - w.cpha().trailing(); - } - } + let mut spis = Self { _p: spis }; - w - }); - - // Set over-read character. - let orc = config.orc; - r.orc.write(|w| unsafe { w.orc().bits(orc) }); - - // Set default character. - let def = config.def; - r.def.write(|w| unsafe { w.def().bits(def) }); - - // Configure auto-acquire on 'transfer end' event. - if config.auto_acquire { - r.shorts.write(|w| w.end_acquire().bit(true)); - } + // Apply runtime peripheral configuration + Self::set_config(&mut spis, &config); // Disable all events interrupts. r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); @@ -217,7 +180,7 @@ impl<'d, T: Instance> Spis<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { _p: spis } + spis } fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { From 521970535e119f7535d6d4d4760e1d76b2231753 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 6 Sep 2023 16:48:22 +0300 Subject: [PATCH 149/233] nrf: twim: Use SetConfig trait to reduce code duplication --- embassy-nrf/src/twim.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index fdea480e..fe38fb10 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -167,9 +167,10 @@ impl<'d, T: Instance> Twim<'d, T> { // Enable TWIM instance. r.enable.write(|w| w.enable().enabled()); - // Configure frequency. - r.frequency - .write(|w| unsafe { w.frequency().bits(config.frequency as u32) }); + let mut twim = Self { _p: twim }; + + // Apply runtime peripheral configuration + Self::set_config(&mut twim, &config); // Disable all events interrupts r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); @@ -177,7 +178,7 @@ impl<'d, T: Instance> Twim<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { _p: twim } + twim } /// Set TX buffer, checking that it is in RAM and has suitable length. From 527bdc57b9c4d5a77f725111570c5add9e646a6b Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Mon, 11 Sep 2023 08:04:06 +0200 Subject: [PATCH 150/233] Fixed formating. --- embassy-time/src/timer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 88134bc6..07ddf473 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -133,7 +133,7 @@ impl Ticker { Self { expires_at, duration } } - /// Resets the ticker back to its original state. + /// Resets the ticker back to its original state. /// This causes the ticker to go back to zero, even if the current tick isn't over yet. pub fn reset(&mut self) { self.expires_at = Instant::now() + self.duration; From b9889ad3b568b54b029422a039b7e9bf73b60a39 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 11 Sep 2023 17:12:54 -0500 Subject: [PATCH 151/233] stm32: add g4 adc345 and misc. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/mod.rs | 38 ++++++++++++++++++++++++++++++++---- embassy-stm32/src/adc/v2.rs | 2 +- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4ba47764..948ed3ca 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e667107cf81934383ec5744f49b2cda0599ec749" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4e6a74f69c4bc5d2d4872ba50d805e75bfe55cad" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -77,7 +77,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e667107cf81934383ec5744f49b2cda0599ec749", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4e6a74f69c4bc5d2d4872ba50d805e75bfe55cad", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 013debca..d1cfd8fb 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -80,17 +80,21 @@ foreach_peripheral!( #[cfg(any(stm32h7, adc_f3, adc_v4))] foreach_peripheral!( (adc, ADC3) => { - #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::sealed::Instance for peripherals::ADC3 { fn regs() -> crate::pac::adc::Adc { crate::pac::ADC3 } #[cfg(all(not(adc_f1), not(adc_v1)))] + #[allow(unreachable_code)] fn common_regs() -> crate::pac::adccommon::AdcCommon { foreach_peripheral!{ (adccommon, ADC3_COMMON) => { return crate::pac::ADC3_COMMON }; + // Fall back to ADC_COMMON if ADC3_COMMON does not exist + (adccommon, ADC_COMMON) => { + return crate::pac::ADC_COMMON + }; } } @@ -100,21 +104,24 @@ foreach_peripheral!( } } - #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::Instance for peripherals::ADC3 {} }; (adc, ADC4) => { - #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::sealed::Instance for peripherals::ADC4 { fn regs() -> crate::pac::adc::Adc { crate::pac::ADC4 } #[cfg(not(any(adc_f1, adc_v1)))] + #[allow(unreachable_code)] fn common_regs() -> crate::pac::adccommon::AdcCommon { foreach_peripheral!{ (adccommon, ADC3_COMMON) => { return crate::pac::ADC3_COMMON }; + // Fall back to ADC_COMMON if ADC3_COMMON does not exist + (adccommon, ADC_COMMON) => { + return crate::pac::ADC_COMMON + }; } } @@ -124,11 +131,34 @@ foreach_peripheral!( } } - #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::Instance for peripherals::ADC4 {} }; (adc, ADC5) => { + impl crate::adc::sealed::Instance for peripherals::ADC5 { + fn regs() -> crate::pac::adc::Adc { + crate::pac::ADC5 + } + #[cfg(not(any(adc_f1, adc_v1)))] + #[allow(unreachable_code)] + fn common_regs() -> crate::pac::adccommon::AdcCommon { + foreach_peripheral!{ + (adccommon, ADC3_COMMON) => { + return crate::pac::ADC3_COMMON + }; + // Fall back to ADC_COMMON if ADC3_COMMON does not exist + (adccommon, ADC_COMMON) => { + return crate::pac::ADC_COMMON + }; + } + } + #[cfg(adc_f3)] + fn frequency() -> crate::time::Hertz { + unsafe { crate::rcc::get_freqs() }.adc34.unwrap() + } + } + + impl crate::adc::Instance for peripherals::ADC5 {} }; (adc, $inst:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 9a7acea5..4fbd1cfa 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -102,7 +102,7 @@ where let presc = Prescaler::from_pclk2(T::frequency()); T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); T::regs().cr2().modify(|reg| { - reg.set_adon(crate::pac::adc::vals::Adon::ENABLED); + reg.set_adon(true); }); delay.delay_us(ADC_POWERUP_TIME_US); From 44a5c32ea460a7fb1c125b0f487bc1d705f077e1 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 11 Sep 2023 17:27:47 -0500 Subject: [PATCH 152/233] adc/f3: fix startup bug --- embassy-stm32/src/adc/f3.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 8f16c6ab..c7b876fe 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -49,6 +49,9 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} + // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223) + delay.delay_us(6 * Self::freq().0 / 1_000_000); + // Enable the adc T::regs().cr().modify(|w| w.set_aden(true)); From 4072a16af636d2943b41323aabf0e0c73a80b893 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 11 Sep 2023 17:50:08 -0500 Subject: [PATCH 153/233] ci: remove wpan_ble for hil --- ci.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci.sh b/ci.sh index db00c406..ba684e44 100755 --- a/ci.sh +++ b/ci.sh @@ -180,4 +180,6 @@ if [[ -z "${TELEPROBE_TOKEN-}" ]]; then exit fi +rm out/tests/stm32wb55rg/wpan_ble + teleprobe client run -r out/tests From f877a5889d8b2a89b09a0bda1bb740cfb7eae64c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 12 Sep 2023 01:43:01 +0200 Subject: [PATCH 154/233] ci: fix colliding files warning. --- ci.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index ba684e44..45cc7e6e 100755 --- a/ci.sh +++ b/ci.sh @@ -145,8 +145,8 @@ cargo batch \ --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \ --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ - --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf \ - --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf \ + --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \ + --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \ --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \ --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \ --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \ From e11db9fa5934882dbf332aaacb676bbe370c1aa1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 12 Sep 2023 01:43:57 +0200 Subject: [PATCH 155/233] ci: disable stm32 docs build temporarily because it's bringing CI down for some reason. --- .github/ci/doc.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index c317a12e..d889f922 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -48,8 +48,9 @@ kubectl cp webroot/static $POD:/data # build and upload stm32 last # so that it doesn't prevent other crates from getting docs updates when it breaks. -rm -rf webroot -docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup -POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) -kubectl cp webroot/crates $POD:/data +# temporarily disabled because it's bringing CI down. +#rm -rf webroot +#docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup +#POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) +#kubectl cp webroot/crates $POD:/data From d36e7abb71bb95907e69bd32359b21b44fe2150b Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 11 Sep 2023 18:52:52 -0500 Subject: [PATCH 156/233] adc/f3: fix delay calculation --- embassy-stm32/src/adc/f3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index c7b876fe..2971ad52 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -50,7 +50,7 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223) - delay.delay_us(6 * Self::freq().0 / 1_000_000); + delay.delay_us(6 * 1_000_000 / Self::freq().0); // Enable the adc T::regs().cr().modify(|w| w.set_aden(true)); From af59fa0a7e1ef98e773822a5629b212c0f27f96a Mon Sep 17 00:00:00 2001 From: ceekdee Date: Tue, 12 Sep 2023 17:53:27 -0500 Subject: [PATCH 157/233] Wait for high for DIO1 for rp2040-based LoRa boards. --- embassy-lora/src/iv.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/embassy-lora/src/iv.rs b/embassy-lora/src/iv.rs index 136973fe..de6a1834 100644 --- a/embassy-lora/src/iv.rs +++ b/embassy-lora/src/iv.rs @@ -284,11 +284,7 @@ where self.busy.wait_for_low().await.map_err(|_| Busy) } async fn await_irq(&mut self) -> Result<(), RadioError> { - if self.board_type != BoardType::RpPicoWaveshareSx1262 { - self.dio1.wait_for_high().await.map_err(|_| DIO1)?; - } else { - self.dio1.wait_for_rising_edge().await.map_err(|_| DIO1)?; - } + self.dio1.wait_for_high().await.map_err(|_| DIO1)?; Ok(()) } From 582ef9099405947ae621e923ba40bd6fd3789285 Mon Sep 17 00:00:00 2001 From: cumthugo Date: Wed, 13 Sep 2023 00:18:18 +0800 Subject: [PATCH 158/233] stm32/usart: fix usart not wake up issue --- embassy-stm32/src/usart/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index bfb05671..2d744322 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -545,6 +545,13 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { unsafe { rdr(r).read_volatile() }; clear_interrupt_flags(r, sr); + if enable_idle_line_detection { + // enable idle interrupt + r.cr1().modify(|w| { + w.set_idleie(true); + }); + } + compiler_fence(Ordering::SeqCst); let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore(); From 3a1ed823f87d6e823763419245d229a0edb09db8 Mon Sep 17 00:00:00 2001 From: Hailey Somerville Date: Thu, 14 Sep 2023 13:03:38 +1000 Subject: [PATCH 159/233] write to TaskStorage::future via inline(never) fn to encourage RVO --- embassy-executor/src/raw/mod.rs | 2 +- embassy-executor/src/raw/util.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index c1d82e18..6d2c1c18 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -203,7 +203,7 @@ impl AvailableTask { fn initialize_impl(self, future: impl FnOnce() -> F) -> SpawnToken { unsafe { self.task.raw.poll_fn.set(Some(TaskStorage::::poll)); - self.task.future.write(future()); + self.task.future.write_in_place(future); let task = TaskRef::new(self.task); diff --git a/embassy-executor/src/raw/util.rs b/embassy-executor/src/raw/util.rs index e2e8f4df..c46085e4 100644 --- a/embassy-executor/src/raw/util.rs +++ b/embassy-executor/src/raw/util.rs @@ -17,8 +17,9 @@ impl UninitCell { &mut *self.as_mut_ptr() } - pub unsafe fn write(&self, val: T) { - ptr::write(self.as_mut_ptr(), val) + #[inline(never)] + pub unsafe fn write_in_place(&self, func: impl FnOnce() -> T) { + ptr::write(self.as_mut_ptr(), func()) } pub unsafe fn drop_in_place(&self) { From b9d4b18f14ad477c4b554498282ac467ff9cb823 Mon Sep 17 00:00:00 2001 From: Hailey Somerville Date: Thu, 14 Sep 2023 13:59:24 +1000 Subject: [PATCH 160/233] update UninitCell::write call in arch::wasm too --- embassy-executor/src/arch/wasm.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index 934fd69e..15aed867 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs @@ -73,9 +73,10 @@ mod thread { pub fn start(&'static mut self, init: impl FnOnce(Spawner)) { unsafe { let executor = &self.inner; - self.ctx.closure.write(Closure::new(move |_| { + let future = Closure::new(move |_| { executor.poll(); - })); + }); + self.ctx.closure.write_in_place(|| future); init(self.inner.spawner()); } } From 49847ff4320daaae16a7e46c43bfb70f9ea3e3d6 Mon Sep 17 00:00:00 2001 From: Mathias Date: Thu, 14 Sep 2023 10:09:09 +0200 Subject: [PATCH 161/233] Implement blocking embedded-io::Write for Uart & UartTx --- embassy-stm32/src/usart/buffered.rs | 6 --- embassy-stm32/src/usart/mod.rs | 70 +++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 989c8820..b88eebc7 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -410,12 +410,6 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> { } } -impl embedded_io_async::Error for Error { - fn kind(&self) -> embedded_io_async::ErrorKind { - embedded_io_async::ErrorKind::Other - } -} - impl<'d, T: BasicInstance> embedded_io_async::ErrorType for BufferedUart<'d, T> { type Error = Error; } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 2d744322..c6d6cc59 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1037,20 +1037,61 @@ mod eh1 { } } -#[cfg(all(feature = "unstable-traits", feature = "nightly"))] -mod eio { - use embedded_io_async::{ErrorType, Write}; +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} - use super::*; +impl embedded_io::ErrorType for Uart<'_, T, TxDma, RxDma> +where + T: BasicInstance, +{ + type Error = Error; +} - impl ErrorType for Uart<'_, T, TxDma, RxDma> - where - T: BasicInstance, - { - type Error = Error; +impl embedded_io::ErrorType for UartTx<'_, T, TxDma> +where + T: BasicInstance, +{ + type Error = Error; +} + +impl embedded_io::Write for Uart<'_, T, TxDma, RxDma> +where + T: BasicInstance, + TxDma: crate::usart::TxDma, +{ + fn write(&mut self, buf: &[u8]) -> Result { + self.blocking_write(buf)?; + Ok(buf.len()) } - impl Write for Uart<'_, T, TxDma, RxDma> + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } +} + +impl embedded_io::Write for UartTx<'_, T, TxDma> +where + T: BasicInstance, + TxDma: crate::usart::TxDma, +{ + fn write(&mut self, buf: &[u8]) -> Result { + self.blocking_write(buf)?; + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } +} + +#[cfg(all(feature = "unstable-traits", feature = "nightly"))] +mod eio { + use super::*; + + impl embedded_io_async::Write for Uart<'_, T, TxDma, RxDma> where T: BasicInstance, TxDma: super::TxDma, @@ -1065,14 +1106,7 @@ mod eio { } } - impl ErrorType for UartTx<'_, T, TxDma> - where - T: BasicInstance, - { - type Error = Error; - } - - impl Write for UartTx<'_, T, TxDma> + impl embedded_io_async::Write for UartTx<'_, T, TxDma> where T: BasicInstance, TxDma: super::TxDma, From dcd1a91966fab1c02f8d66abc2be6e6259b1cc6b Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Thu, 14 Sep 2023 14:07:15 +0200 Subject: [PATCH 162/233] stm32: bump fmc version --- embassy-stm32/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 948ed3ca..c89839a3 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -62,7 +62,7 @@ stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", ta vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" -stm32-fmc = "0.2.4" +stm32-fmc = "0.3.0" seq-macro = "0.3.0" cfg-if = "1.0.0" embedded-io = { version = "0.5.0" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index d4b7d18c..05aacb61 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -29,7 +29,7 @@ heapless = { version = "0.7.5", default-features = false } rand_core = "0.6.3" critical-section = "1.1" micromath = "2.0.0" -stm32-fmc = "0.2.4" +stm32-fmc = "0.3.0" embedded-storage = "0.3.0" static_cell = { version = "1.1", features = ["nightly"]} diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index eda04e44..6c4da09b 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -29,7 +29,7 @@ heapless = { version = "0.7.5", default-features = false } rand_core = "0.6.3" critical-section = "1.1" micromath = "2.0.0" -stm32-fmc = "0.2.4" +stm32-fmc = "0.3.0" embedded-storage = "0.3.0" static_cell = { version = "1.1", features = ["nightly"]} From 7bcc7e89620c5aac197207bb6d646e0e19ff6972 Mon Sep 17 00:00:00 2001 From: Polly Date: Thu, 14 Sep 2023 16:08:37 +0200 Subject: [PATCH 163/233] Fix doc typo --- embassy-net/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index de32edc2..f48d3372 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -168,7 +168,7 @@ impl Config { } } - /// IPv6 configuration with dynamic addressing. + /// IPv4 configuration with dynamic addressing. /// /// # Example /// ```rust From e8b961232b80c8169eecb62c508bcf46abcd3705 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 14 Sep 2023 17:24:28 +0200 Subject: [PATCH 164/233] Fix gpiote when waking up from systemoff --- embassy-nrf/src/gpiote.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 7488bc08..d16b4a43 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -86,7 +86,6 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { unsafe { irq.enable() }; let g = regs(); - g.events_port.write(|w| w); g.intenset.write(|w| w.port().set()); } From 1b20ba27b12a93ae94b4eff39160da884c592db4 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 14 Sep 2023 18:26:00 +0200 Subject: [PATCH 165/233] feat: bump embassy-sync version to 0.3.0 Update changelog in preparation for release --- cyw43/Cargo.toml | 2 +- embassy-boot/boot/Cargo.toml | 2 +- embassy-embedded-hal/Cargo.toml | 2 +- embassy-lora/Cargo.toml | 2 +- embassy-net-driver-channel/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-ppp/Cargo.toml | 2 +- embassy-net/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-sync/CHANGELOG.md | 9 ++++++++- embassy-sync/Cargo.toml | 2 +- embassy-usb-logger/Cargo.toml | 2 +- embassy-usb/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 55 files changed, 62 insertions(+), 55 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 59b297e0..dae7419c 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -12,7 +12,7 @@ firmware-logs = [] [dependencies] embassy-time = { version = "0.1.3", path = "../embassy-time"} -embassy-sync = { version = "0.2.0", path = "../embassy-sync"} +embassy-sync = { version = "0.3.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} atomic-polyfill = "0.1.5" diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml index 415d7960..6a334f01 100644 --- a/embassy-boot/boot/Cargo.toml +++ b/embassy-boot/boot/Cargo.toml @@ -28,7 +28,7 @@ digest = "0.10" log = { version = "0.4", optional = true } ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync" } embedded-storage = "0.3.0" embedded-storage-async = { version = "0.4.0", optional = true } salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true } diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index b311b591..62a95ed9 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -20,7 +20,7 @@ default = ["time"] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true } -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index fa445a39..81b389d8 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml @@ -21,7 +21,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } embedded-hal-async = { version = "=1.0.0-rc.1" } embedded-hal = { version = "0.2", features = ["unproven"] } diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index bee2e302..4588af02 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -24,6 +24,6 @@ features = ["defmt"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 67c86936..54cd8859 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -8,7 +8,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } embassy-time = { version = "0.1.3", path = "../embassy-time" } -embassy-sync = { version = "0.2.0", path = "../embassy-sync"} +embassy-sync = { version = "0.3.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index 191577b5..da09f780 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -19,7 +19,7 @@ embedded-io-async = { version = "0.5.0" } embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } ppproto = { version = "0.1.2"} -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION/embassy-net-ppp/src/" diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index c763d41c..8aca92a6 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -52,7 +52,7 @@ smoltcp = { version = "0.10.0", default-features = false, features = [ embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } embassy-time = { version = "0.1.3", path = "../embassy-time" } -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embedded-io-async = { version = "0.5.0", optional = true } managed = { version = "0.8.0", default-features = false, features = [ "map" ] } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index e7afef26..eee92721 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -92,7 +92,7 @@ _gpio-p1 = [] [dependencies] embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index eebb6e3b..094b528f 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -59,7 +59,7 @@ nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "em unstable-traits = ["embedded-hal-1", "embedded-hal-nb"] [dependencies] -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-time = { version = "0.1.3", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 7a4d3ec6..3b10b7c5 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -12,7 +12,7 @@ features = ["stm32wb55rg"] [dependencies] embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index c89839a3..dfc9022b 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -31,7 +31,7 @@ flavors = [ ] [dependencies] -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index a60f3f7c..2c53dd0f 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.3.0 - 2023-09-14 + +- switch to embedded-io 0.5 +- add api for polling channels with context +- standardise fn names on channels +- add zero-copy channel + ## 0.2.0 - 2023-04-13 - pubsub: Fix messages not getting popped when the last subscriber that needed them gets dropped. @@ -19,4 +26,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.1.0 - 2022-08-26 -- First release \ No newline at end of file +- First release diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 94d6799e..f7739f30 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-sync" -version = "0.2.0" +version = "0.3.0" edition = "2021" description = "no-std, no-alloc synchronization primitives with async support" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml index 0f91cd36..944a48a5 100644 --- a/embassy-usb-logger/Cargo.toml +++ b/embassy-usb-logger/Cargo.toml @@ -10,7 +10,7 @@ target = "thumbv7em-none-eabi" [dependencies] embassy-usb = { version = "0.1.0", path = "../embassy-usb" } -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } futures = { version = "0.3", default-features = false } static_cell = "1" diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index 03cf96a1..0e7e0e70 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -41,7 +41,7 @@ max-handler-count-8 = [] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } -embassy-sync = { version = "0.2.0", path = "../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 49f6eb13..435a3391 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly"] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 322a8b30..01cfc599 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly"] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 530099a2..a0649cf8 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index 597a468c..ca1c0c42 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 78bfd501..e50c8c41 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 2b99f0db..1f1a0f3c 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index b26de22c..45b12813 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 7db65540..d0d0d0fb 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 8ba7abbc..3265b9f1 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index ed6aca81..e402e49f 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -16,7 +16,7 @@ log = [ ] [dependencies] -embassy-sync = { version = "0.2.0", path = "../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time" } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 02a7f98b..c588b807 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nightly", "unstable-traits", "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 8b7121ab..a40a9dc1 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -29,7 +29,7 @@ nightly = [ [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index e423ad95..86d969ed 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = [ +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = [ "defmt", ] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 3b086133..4b125ed8 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index ca061d68..e54f3698 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["log", "std", "nightly"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index a691be42..89ecc499 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 894681d0..db9a24d7 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -14,7 +14,7 @@ cortex-m-rt = "0.7.0" defmt = "0.3" defmt-rtt = "0.4" panic-probe = "0.3" -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = { version = "1.1", features = ["nightly"]} diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index bec7bf65..b032ba81 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 7cc5747d..1314b6b1 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index ffacece5..534e783d 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 65183b88..239c58b3 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index ca517df7..4b4fb479 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index f7a7fb8c..bf8f413d 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f767zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 474c2af8..b4b423d5 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g071rb to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 2e81d206..59da0628 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 05aacb61..42a42618 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 6c4da09b..c1d49963 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index d33e0378..befebcce 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -12,7 +12,7 @@ nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstab [dependencies] # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 9bf633ce..a75275a0 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 92337e71..59e89c53 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "unstable-traits", "chrono"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index d387ee62..583e1a77 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 403e5714..e361856c 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u585ai to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 81d9ec69..320678dd 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wb55rg to your chip name in both dependencies, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 3ea76cbb..155c6dbc 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 2999dc52..12b2e2bd 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" crate-type = ["cdylib"] [dependencies] -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["log", "wasm", "nightly"] } diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 867bf272..b3d21468 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt", "nightly"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt", "nightly"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index 66ab34ec..490f037b 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] critical-section = { version = "1.1.1", features = ["restore-state-bool"] } -embassy-sync = { version = "0.2.0", path = "../../embassy-sync" } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-riscv32", "nightly", "executor-thread"] } embassy-time = { version = "0.1.3", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index d71db8bb..26e2473c 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] teleprobe-meta = "1.1" -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index c96b5a5a..f78cb509 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -29,7 +29,7 @@ dac-adc-pin = [] [dependencies] teleprobe-meta = "1" -embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } From 309c3d6b472aa07bdf8b96f57eef5c0b5a686844 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 14 Sep 2023 18:36:03 -0500 Subject: [PATCH 166/233] update metapac --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/v2.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index dfc9022b..24d0912f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -58,7 +58,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4e6a74f69c4bc5d2d4872ba50d805e75bfe55cad" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4d58d2d6648d526feb6bc45748dc73a05d41a5f3" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -77,7 +77,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4e6a74f69c4bc5d2d4872ba50d805e75bfe55cad", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4d58d2d6648d526feb6bc45748dc73a05d41a5f3", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 4fbd1cfa..f583c08a 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -125,7 +125,7 @@ where /// [Adc::read_internal()] to perform conversion. pub fn enable_vrefint(&self) -> VrefInt { T::common_regs().ccr().modify(|reg| { - reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); + reg.set_tsvrefe(true); }); VrefInt {} @@ -138,7 +138,7 @@ where /// temperature sensor will return vbat value. pub fn enable_temperature(&self) -> Temperature { T::common_regs().ccr().modify(|reg| { - reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); + reg.set_tsvrefe(true); }); Temperature {} @@ -148,7 +148,7 @@ where /// [Adc::read_internal()] to perform conversion. pub fn enable_vbat(&self) -> Vbat { T::common_regs().ccr().modify(|reg| { - reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED); + reg.set_vbate(true); }); Vbat {} From 9fb14379c3d24f68a1f0715d61a54e31b7b53d2a Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 14 Sep 2023 18:53:27 -0500 Subject: [PATCH 167/233] stm32: add lp to l0 --- embassy-stm32/Cargo.toml | 2 +- embassy-stm32/src/low_power.rs | 15 ++++++++++++++- embassy-stm32/src/rcc/bd.rs | 4 ++-- embassy-stm32/src/rcc/l0.rs | 8 ++++++++ embassy-stm32/src/rtc/v2.rs | 25 +++++++++++++++++++++++-- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 24d0912f..51909e43 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -21,7 +21,7 @@ flavors = [ { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" }, { regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" }, - { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi" }, + { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi", features = ["low-power"] }, { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" }, { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" }, diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 7e678d32..b42b674e 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -95,8 +95,21 @@ impl Executor { self.time_driver.set_rtc(rtc); + #[cfg(not(stm32l0))] crate::interrupt::typelevel::RTC_WKUP::unpend(); - unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; + + #[cfg(not(stm32l0))] + unsafe { + crate::interrupt::typelevel::RTC_WKUP::enable() + }; + + #[cfg(stm32l0)] + crate::interrupt::typelevel::RTC::unpend(); + + #[cfg(stm32l0)] + unsafe { + crate::interrupt::typelevel::RTC::enable() + }; rtc.enable_wakeup_line(); } diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 76d0f3a3..059a3211 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -58,13 +58,13 @@ impl BackupDomain { ))] #[allow(dead_code, unused_variables)] fn modify(f: impl FnOnce(&mut Bdcr) -> R) -> R { - #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] + #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1, rtc_v2l0))] let cr = crate::pac::PWR.cr(); #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] let cr = crate::pac::PWR.cr1(); // TODO: Missing from PAC for l0 and f0? - #[cfg(not(any(rtc_v2f0, rtc_v2l0, rtc_v3u5)))] + #[cfg(not(any(rtc_v2f0, rtc_v3u5)))] { cr.modify(|w| w.set_dbp(true)); while !cr.read().dbp() {} diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 7f9ab01f..3c8511ff 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -1,4 +1,6 @@ +use super::bd::BackupDomain; pub use super::bus::{AHBPrescaler, APBPrescaler}; +use super::RtcClockSource; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; use crate::pac::RCC; #[cfg(crs)] @@ -135,6 +137,7 @@ pub struct Config { pub apb2_pre: APBPrescaler, #[cfg(crs)] pub enable_hsi48: bool, + pub rtc: Option, } impl Default for Config { @@ -147,6 +150,7 @@ impl Default for Config { apb2_pre: APBPrescaler::NotDivided, #[cfg(crs)] enable_hsi48: false, + rtc: None, } } } @@ -231,6 +235,10 @@ pub(crate) unsafe fn init(config: Config) { } }; + config.rtc.map(|rtc| { + BackupDomain::configure_ls(rtc, None); + }); + RCC.cfgr().modify(|w| { w.set_sw(sw); w.set_hpre(config.ahb_pre.into()); diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 9037389e..1fa9f2fe 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -15,7 +15,7 @@ pub(crate) enum WakeupPrescaler { Div16 = 16, } -#[cfg(any(stm32wb, stm32f4))] +#[cfg(any(stm32wb, stm32f4, stm32l0))] impl From for crate::pac::rtc::vals::Wucksel { fn from(val: WakeupPrescaler) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -29,7 +29,7 @@ impl From for crate::pac::rtc::vals::Wucksel { } } -#[cfg(any(stm32wb, stm32f4))] +#[cfg(any(stm32wb, stm32f4, stm32l0))] impl From for WakeupPrescaler { fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -67,10 +67,15 @@ impl super::Rtc { pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { use embassy_time::{Duration, TICK_HZ}; + #[cfg(not(stm32l0))] use crate::rcc::get_freqs; + #[cfg(not(stm32l0))] let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; + #[cfg(stm32l0)] + let rtc_hz = 32_768u64; + let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); @@ -109,7 +114,14 @@ impl super::Rtc { pub(crate) fn enable_wakeup_line(&self) { use crate::pac::EXTI; + #[cfg(stm32l0)] + EXTI.rtsr(0).modify(|w| w.set_line(20, true)); + #[cfg(stm32l0)] + EXTI.imr(0).modify(|w| w.set_line(20, true)); + + #[cfg(not(stm32l0))] EXTI.rtsr(0).modify(|w| w.set_line(22, true)); + #[cfg(not(stm32l0))] EXTI.imr(0).modify(|w| w.set_line(22, true)); } @@ -126,8 +138,17 @@ impl super::Rtc { regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); + #[cfg(not(stm32l0))] crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); + + #[cfg(stm32l0)] + crate::pac::EXTI.pr(0).modify(|w| w.set_line(20, true)); + + #[cfg(not(stm32l0))] crate::interrupt::typelevel::RTC_WKUP::unpend(); + + #[cfg(stm32l0)] + crate::interrupt::typelevel::RTC::unpend(); }); critical_section::with(|cs| { From 07233ca5b44a1b2022c05ee66815f60a2da761cf Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 14 Sep 2023 19:09:35 -0500 Subject: [PATCH 168/233] ci: build low-power on l0 --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index 45cc7e6e..da35c5a4 100755 --- a/ci.sh +++ b/ci.sh @@ -92,6 +92,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l073cz,defmt,exti,time-driver-any,unstable-traits,low-power \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits \ From 7c77d2bd94afcc5dc174f9b3e5c2ce947c6fabb0 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 15 Sep 2023 03:43:46 +0200 Subject: [PATCH 169/233] ci: reenable stm32 docs. --- .github/ci/doc.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index d889f922..66caa915 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -49,8 +49,7 @@ kubectl cp webroot/static $POD:/data # build and upload stm32 last # so that it doesn't prevent other crates from getting docs updates when it breaks. -# temporarily disabled because it's bringing CI down. -#rm -rf webroot -#docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup -#POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) -#kubectl cp webroot/crates $POD:/data +rm -rf webroot +docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup +POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) +kubectl cp webroot/crates $POD:/data From 45e9e51bdc5c3657c44a0951932e5f5a87d5f175 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Fri, 15 Sep 2023 15:13:52 +0200 Subject: [PATCH 170/233] Fix low-power feature for STM32L0 --- embassy-stm32/src/rtc/v2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 1fa9f2fe..726886f1 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -298,7 +298,7 @@ impl sealed::Instance for crate::peripherals::RTC { crate::pac::PWR.cr().read(); } - #[cfg(any(rtc_v2f0))] + #[cfg(any(rtc_v2f0, rtc_v2l0))] { // enable peripheral clock for communication crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); From c28a6bdd0b6cde56c5b1b40a4c57d9b31e05d531 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 15 Sep 2023 17:35:53 -0500 Subject: [PATCH 171/233] stm32: generate adc_common --- embassy-stm32/build.rs | 29 +++++++++ embassy-stm32/src/adc/mod.rs | 116 ++--------------------------------- embassy-stm32/src/rcc/f3.rs | 14 +++-- 3 files changed, 44 insertions(+), 115 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index bb81736b..6d7f788d 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -817,6 +817,17 @@ fn main() { let mut peripherals_table: Vec> = Vec::new(); let mut pins_table: Vec> = Vec::new(); let mut dma_channels_table: Vec> = Vec::new(); + let mut adc_common_table: Vec> = Vec::new(); + + /* + If ADC3_COMMON exists, ADC3 and higher are assigned to it + All other ADCs are assigned to ADC_COMMON + + ADC3 and higher are assigned to the adc34 clock in the table + The adc3_common cfg directive is added if ADC3_COMMON exists + */ + let has_adc3 = METADATA.peripherals.iter().find(|p| p.name == "ADC3_COMMON").is_some(); + let set_adc345 = HashSet::from(["ADC3", "ADC4", "ADC5"]); for m in METADATA .memory @@ -854,6 +865,17 @@ fn main() { } } + if regs.kind == "adc" { + let (adc_common, adc_clock) = if set_adc345.contains(p.name) && has_adc3 { + ("ADC3_COMMON", "adc34") + } else { + ("ADC_COMMON", "adc") + }; + + let row = vec![p.name.to_string(), adc_common.to_string(), adc_clock.to_string()]; + adc_common_table.push(row); + } + for irq in p.interrupts { let row = vec![ p.name.to_string(), @@ -932,6 +954,7 @@ fn main() { make_table(&mut m, "foreach_peripheral", &peripherals_table); make_table(&mut m, "foreach_pin", &pins_table); make_table(&mut m, "foreach_dma_channel", &dma_channels_table); + make_table(&mut m, "foreach_adc", &adc_common_table); let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out_file = out_dir.join("_macros.rs").to_string_lossy().to_string(); @@ -973,6 +996,12 @@ fn main() { println!("cargo:rustc-cfg={}x{}", &chip_name[..9], &chip_name[10..11]); } + // ======= + // ADC3_COMMON is present + if has_adc3 { + println!("cargo:rustc-cfg={}", "adc3_common"); + } + // ======= // Features for targeting groups of chips diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index d1cfd8fb..9334deac 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -56,127 +56,21 @@ pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc: pub trait AdcPin: sealed::AdcPin {} pub trait InternalChannel: sealed::InternalChannel {} -#[cfg(not(any(stm32h7, adc_f3, adc_v4)))] -foreach_peripheral!( - (adc, $inst:ident) => { +foreach_adc!( + ($inst:ident, $common_inst:ident, $clock:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { fn regs() -> crate::pac::adc::Adc { crate::pac::$inst } + #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { - foreach_peripheral!{ - (adccommon, $common_inst:ident) => { - return crate::pac::$common_inst - }; - } - } - } - - impl crate::adc::Instance for peripherals::$inst {} - }; -); - -#[cfg(any(stm32h7, adc_f3, adc_v4))] -foreach_peripheral!( - (adc, ADC3) => { - impl crate::adc::sealed::Instance for peripherals::ADC3 { - fn regs() -> crate::pac::adc::Adc { - crate::pac::ADC3 - } - #[cfg(all(not(adc_f1), not(adc_v1)))] - #[allow(unreachable_code)] - fn common_regs() -> crate::pac::adccommon::AdcCommon { - foreach_peripheral!{ - (adccommon, ADC3_COMMON) => { - return crate::pac::ADC3_COMMON - }; - // Fall back to ADC_COMMON if ADC3_COMMON does not exist - (adccommon, ADC_COMMON) => { - return crate::pac::ADC_COMMON - }; - } + return crate::pac::$common_inst } #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs() }.adc34.unwrap() - } - } - - impl crate::adc::Instance for peripherals::ADC3 {} - }; - (adc, ADC4) => { - impl crate::adc::sealed::Instance for peripherals::ADC4 { - fn regs() -> crate::pac::adc::Adc { - crate::pac::ADC4 - } - #[cfg(not(any(adc_f1, adc_v1)))] - #[allow(unreachable_code)] - fn common_regs() -> crate::pac::adccommon::AdcCommon { - foreach_peripheral!{ - (adccommon, ADC3_COMMON) => { - return crate::pac::ADC3_COMMON - }; - // Fall back to ADC_COMMON if ADC3_COMMON does not exist - (adccommon, ADC_COMMON) => { - return crate::pac::ADC_COMMON - }; - } - } - - #[cfg(adc_f3)] - fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs() }.adc34.unwrap() - } - } - - impl crate::adc::Instance for peripherals::ADC4 {} - }; - (adc, ADC5) => { - impl crate::adc::sealed::Instance for peripherals::ADC5 { - fn regs() -> crate::pac::adc::Adc { - crate::pac::ADC5 - } - #[cfg(not(any(adc_f1, adc_v1)))] - #[allow(unreachable_code)] - fn common_regs() -> crate::pac::adccommon::AdcCommon { - foreach_peripheral!{ - (adccommon, ADC3_COMMON) => { - return crate::pac::ADC3_COMMON - }; - // Fall back to ADC_COMMON if ADC3_COMMON does not exist - (adccommon, ADC_COMMON) => { - return crate::pac::ADC_COMMON - }; - } - } - - #[cfg(adc_f3)] - fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs() }.adc34.unwrap() - } - } - - impl crate::adc::Instance for peripherals::ADC5 {} - }; - (adc, $inst:ident) => { - impl crate::adc::sealed::Instance for peripherals::$inst { - fn regs() -> crate::pac::adc::Adc { - crate::pac::$inst - } - #[cfg(not(any(adc_f1, adc_v1)))] - fn common_regs() -> crate::pac::adccommon::AdcCommon { - foreach_peripheral!{ - (adccommon, ADC_COMMON) => { - return crate::pac::ADC_COMMON - }; - } - } - - #[cfg(adc_f3)] - fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs() }.adc.unwrap() + unsafe { crate::rcc::get_freqs() }.$clock.unwrap() } } diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index cbbe4f98..630dbd4f 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -280,7 +280,7 @@ pub(crate) unsafe fn init(config: Config) { } }); - #[cfg(rcc_f3)] + #[cfg(all(rcc_f3, adc3_common))] let adc34 = config.adc.map(|adc| { if !adc.is_bus() { RCC.cfgr2().modify(|w| { @@ -291,9 +291,13 @@ pub(crate) unsafe fn init(config: Config) { Hertz(sysclk / adc as u32) }) } else { - // TODO: need to use only if adc32_common is present + crate::pac::ADC3_COMMON.ccr().modify(|w| { + assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1)); - todo!() + w.set_ckmode(adc.into()); + + Hertz(sysclk / adc.bus_div() as u32) + }) } }); @@ -323,8 +327,10 @@ pub(crate) unsafe fn init(config: Config) { ahb1: Hertz(hclk), #[cfg(rcc_f3)] adc: adc, - #[cfg(rcc_f3)] + #[cfg(all(rcc_f3, adc3_common))] adc34: adc34, + #[cfg(all(rcc_f3, not(adc3_common)))] + adc34: None, #[cfg(stm32f334)] hrtim: hrtim, }); From aa2fa29b89c120ec23d64252d3f1b036c1369b00 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 15 Sep 2023 17:36:21 -0500 Subject: [PATCH 172/233] stm32: fix adc f3 startup time closes #1888. --- embassy-stm32/src/adc/f3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 2971ad52..b39d6ac8 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -50,7 +50,7 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223) - delay.delay_us(6 * 1_000_000 / Self::freq().0); + delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0)); // Enable the adc T::regs().cr().modify(|w| w.set_aden(true)); From 6da75ea285482bd950b04ae00dde25303f160705 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 15 Sep 2023 18:41:33 -0500 Subject: [PATCH 173/233] stm32: rtc/low-power cleanup --- embassy-stm32/src/exti.rs | 3 ++ embassy-stm32/src/low_power.rs | 47 +++++------------------------- embassy-stm32/src/rtc/mod.rs | 40 ++++++++++++++----------- embassy-stm32/src/rtc/v2.rs | 50 +++++++++++++++----------------- embassy-stm32/src/time_driver.rs | 6 ++++ 5 files changed, 63 insertions(+), 83 deletions(-) diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 925cf39b..bd4bab1f 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -39,6 +39,9 @@ fn exticr_regs() -> pac::afio::Afio { } pub unsafe fn on_irq() { + #[cfg(feature = "low-power")] + crate::low_power::on_wakeup_irq(); + #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] let bits = EXTI.pr(0).read().0; #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index b42b674e..ce8afb57 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -5,7 +5,6 @@ use cortex_m::peripheral::SCB; use embassy_executor::*; use crate::interrupt; -use crate::interrupt::typelevel::Interrupt; use crate::rcc::low_power_ready; use crate::time_driver::{get_driver, RtcDriver}; @@ -19,36 +18,20 @@ foreach_interrupt! { (RTC, rtc, $block:ident, WKUP, $irq:ident) => { #[interrupt] unsafe fn $irq() { - unsafe { EXECUTOR.as_mut().unwrap() }.on_wakeup_irq(); + EXECUTOR.as_mut().unwrap().on_wakeup_irq(); } }; } -// pub fn timer_driver_pause_time() { -// pause_time(); -// } +#[allow(dead_code)] +pub(crate) unsafe fn on_wakeup_irq() { + EXECUTOR.as_mut().unwrap().on_wakeup_irq(); +} pub fn stop_with_rtc(rtc: &'static Rtc) { unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) } -// pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) { -// let rtc_instant = unsafe { EXECUTOR.as_mut().unwrap() } -// .rtc -// .unwrap() -// .start_wakeup_alarm(requested_duration); -// -// unsafe { EXECUTOR.as_mut().unwrap() }.last_stop = Some(rtc_instant); -// } -// -// pub fn set_sleepdeep() { -// unsafe { EXECUTOR.as_mut().unwrap() }.scb.set_sleepdeep(); -// } -// -// pub fn stop_wakeup_alarm() -> RtcInstant { -// unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm() -// } - /// Thread mode executor, using WFE/SEV. /// /// This is the simplest and most common kind of executor. It runs on @@ -91,27 +74,11 @@ impl Executor { } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { - trace!("low power: stop with rtc configured"); - self.time_driver.set_rtc(rtc); - #[cfg(not(stm32l0))] - crate::interrupt::typelevel::RTC_WKUP::unpend(); - - #[cfg(not(stm32l0))] - unsafe { - crate::interrupt::typelevel::RTC_WKUP::enable() - }; - - #[cfg(stm32l0)] - crate::interrupt::typelevel::RTC::unpend(); - - #[cfg(stm32l0)] - unsafe { - crate::interrupt::typelevel::RTC::enable() - }; - rtc.enable_wakeup_line(); + + trace!("low power: stop with rtc configured"); } fn configure_pwr(&mut self) { diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index a1133a80..32a5cc12 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -124,9 +124,6 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { - #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - use crate::rcc::get_freqs; - RTC::enable_peripheral_clk(); BackupDomain::enable_rtc(); @@ -135,20 +132,7 @@ impl Rtc { stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }; - #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - let freqs = unsafe { get_freqs() }; - - // Load the clock frequency from the rcc mod, if supported - #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - let frequency = match freqs.rtc { - Some(hertz) => hertz, - None => freqs.rtc_hse.unwrap(), - }; - - // Assume the default value, if not supported - #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))] - let frequency = Hertz(32_768); - + let frequency = Self::frequency(); let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8; let sync_psc = (rtc_config.frequency.0 - 1) as u16; @@ -157,6 +141,22 @@ impl Rtc { this } + fn frequency() -> Hertz { + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + let freqs = unsafe { crate::rcc::get_freqs() }; + + // Load the clock frequency from the rcc mod, if supported + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + match freqs.rtc { + Some(hertz) => hertz, + None => freqs.rtc_hse.unwrap(), + } + + // Assume the default value, if not supported + #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))] + Hertz(32_768) + } + /// Set the datetime to a new value. /// /// # Errors @@ -264,6 +264,12 @@ pub(crate) mod sealed { pub trait Instance { const BACKUP_REGISTER_COUNT: usize; + #[cfg(feature = "low-power")] + const EXTI_WAKEUP_LINE: usize; + + #[cfg(feature = "low-power")] + type WakeupInterrupt: crate::interrupt::typelevel::Interrupt; + fn regs() -> Rtc { crate::pac::RTC } diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 726886f1..aa3c31ee 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -67,15 +67,10 @@ impl super::Rtc { pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { use embassy_time::{Duration, TICK_HZ}; - #[cfg(not(stm32l0))] - use crate::rcc::get_freqs; - - #[cfg(not(stm32l0))] - let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; - - #[cfg(stm32l0)] - let rtc_hz = 32_768u64; + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); + let rtc_hz = Self::frequency().0 as u64; let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); @@ -112,17 +107,14 @@ impl super::Rtc { #[cfg(feature = "low-power")] pub(crate) fn enable_wakeup_line(&self) { + use crate::interrupt::typelevel::Interrupt; use crate::pac::EXTI; - #[cfg(stm32l0)] - EXTI.rtsr(0).modify(|w| w.set_line(20, true)); - #[cfg(stm32l0)] - EXTI.imr(0).modify(|w| w.set_line(20, true)); + ::WakeupInterrupt::unpend(); + unsafe { ::WakeupInterrupt::enable() }; - #[cfg(not(stm32l0))] - EXTI.rtsr(0).modify(|w| w.set_line(22, true)); - #[cfg(not(stm32l0))] - EXTI.imr(0).modify(|w| w.set_line(22, true)); + EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); } #[cfg(feature = "low-power")] @@ -138,17 +130,11 @@ impl super::Rtc { regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); - #[cfg(not(stm32l0))] - crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); + crate::pac::EXTI + .pr(0) + .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); - #[cfg(stm32l0)] - crate::pac::EXTI.pr(0).modify(|w| w.set_line(20, true)); - - #[cfg(not(stm32l0))] - crate::interrupt::typelevel::RTC_WKUP::unpend(); - - #[cfg(stm32l0)] - crate::interrupt::typelevel::RTC::unpend(); + ::WakeupInterrupt::unpend(); }); critical_section::with(|cs| { @@ -280,6 +266,18 @@ impl super::Rtc { impl sealed::Instance for crate::peripherals::RTC { const BACKUP_REGISTER_COUNT: usize = 20; + #[cfg(all(feature = "low-power", stm32f4))] + const EXTI_WAKEUP_LINE: usize = 22; + + #[cfg(all(feature = "low-power", stm32l0))] + const EXTI_WAKEUP_LINE: usize = 20; + + #[cfg(all(feature = "low-power", stm32f4))] + type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; + + #[cfg(all(feature = "low-power", stm32l0))] + type WakeupInterrupt = crate::interrupt::typelevel::RTC; + fn enable_peripheral_clk() { #[cfg(any(rtc_v2l4, rtc_v2wb))] { diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 99d423d0..887e54f6 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -372,6 +372,12 @@ impl RtcDriver { #[cfg(feature = "low-power")] /// Resume the timer with the given offset pub(crate) fn resume_time(&self) { + if T::regs_gp16().cr1().read().cen() { + // Time isn't currently stopped + + return; + } + self.stop_wakeup_alarm(); T::regs_gp16().cr1().modify(|w| w.set_cen(true)); From a2a26f489b81a0ad34c5244f2acfde2ecb9951fe Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 14 Sep 2023 18:04:43 +0200 Subject: [PATCH 174/233] ci: set net.git-fetch-with-cli=true --- .github/ci/build-stable.sh | 4 ++++ .github/ci/build.sh | 4 ++++ .github/ci/test.sh | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/.github/ci/build-stable.sh b/.github/ci/build-stable.sh index 0dadd610..8012f692 100755 --- a/.github/ci/build-stable.sh +++ b/.github/ci/build-stable.sh @@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target +# needed for "dumb HTTP" transport support +# used when pointing stm32-metapac to a CI-built one. +export CARGO_NET_GIT_FETCH_WITH_CLI=true + hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json diff --git a/.github/ci/build.sh b/.github/ci/build.sh index 36bf7e7d..78ab976d 100755 --- a/.github/ci/build.sh +++ b/.github/ci/build.sh @@ -14,6 +14,10 @@ if [ -f /ci/secrets/teleprobe-token.txt ]; then export TELEPROBE_CACHE=/ci/cache/teleprobe_cache.json fi +# needed for "dumb HTTP" transport support +# used when pointing stm32-metapac to a CI-built one. +export CARGO_NET_GIT_FETCH_WITH_CLI=true + hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 04f4fc7c..af0f21c2 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target +# needed for "dumb HTTP" transport support +# used when pointing stm32-metapac to a CI-built one. +export CARGO_NET_GIT_FETCH_WITH_CLI=true + hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json From 8315cf064eab133006e1397819b50f072fec6398 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 16 Sep 2023 03:44:01 +0200 Subject: [PATCH 175/233] stm32: add stm32wba support. --- ci.sh | 1 + embassy-stm32/Cargo.toml | 9 +- embassy-stm32/build.rs | 13 +- embassy-stm32/src/lib.rs | 2 +- embassy-stm32/src/rcc/bd.rs | 120 ++++++--------- embassy-stm32/src/rcc/bus.rs | 6 - embassy-stm32/src/rcc/mod.rs | 8 +- embassy-stm32/src/rcc/u5.rs | 2 +- embassy-stm32/src/rcc/wba.rs | 184 +++++++++++++++++++++++ embassy-stm32/src/rtc/mod.rs | 2 - examples/stm32wba/.cargo/config.toml | 8 + examples/stm32wba/Cargo.toml | 26 ++++ examples/stm32wba/build.rs | 10 ++ examples/stm32wba/src/bin/blinky.rs | 27 ++++ examples/stm32wba/src/bin/button_exti.rs | 27 ++++ 15 files changed, 354 insertions(+), 91 deletions(-) create mode 100644 embassy-stm32/src/rcc/wba.rs create mode 100644 examples/stm32wba/.cargo/config.toml create mode 100644 examples/stm32wba/Cargo.toml create mode 100644 examples/stm32wba/build.rs create mode 100644 examples/stm32wba/src/bin/blinky.rs create mode 100644 examples/stm32wba/src/bin/button_exti.rs diff --git a/ci.sh b/ci.sh index da35c5a4..a3d9ef81 100755 --- a/ci.sh +++ b/ci.sh @@ -145,6 +145,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \ + --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \ --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \ diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 51909e43..699995bc 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -27,6 +27,7 @@ flavors = [ { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" }, + { regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" }, ] @@ -58,7 +59,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4d58d2d6648d526feb6bc45748dc73a05d41a5f3" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-546aead07086342605102d66dec49c5e2d459a0c" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -77,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4d58d2d6648d526feb6bc45748dc73a05d41a5f3", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-546aead07086342605102d66dec49c5e2d459a0c", default-features = false, features = ["metadata"]} [features] default = ["rt"] @@ -1454,6 +1455,10 @@ stm32wb55vc = [ "stm32-metapac/stm32wb55vc" ] stm32wb55ve = [ "stm32-metapac/stm32wb55ve" ] stm32wb55vg = [ "stm32-metapac/stm32wb55vg" ] stm32wb55vy = [ "stm32-metapac/stm32wb55vy" ] +stm32wba52ce = [ "stm32-metapac/stm32wba52ce" ] +stm32wba52cg = [ "stm32-metapac/stm32wba52cg" ] +stm32wba52ke = [ "stm32-metapac/stm32wba52ke" ] +stm32wba52kg = [ "stm32-metapac/stm32wba52kg" ] stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4" ] stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ] stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 6d7f788d..b36af479 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1005,10 +1005,15 @@ fn main() { // ======= // Features for targeting groups of chips - println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4 - println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429 - println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x - println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9 + if &chip_name[..8] == "stm32wba" { + println!("cargo:rustc-cfg={}", &chip_name[..8]); // stm32wba + println!("cargo:rustc-cfg={}", &chip_name[..10]); // stm32wba52 + } else { + println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4 + println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429 + println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x + println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9 + } // Handle time-driver-XXXX features. if env::var("CARGO_FEATURE_TIME_DRIVER_ANY").is_ok() {} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index ec8648ee..6a53f876 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -154,7 +154,7 @@ pub fn init(config: Config) -> Peripherals { #[cfg(dbgmcu)] if config.enable_debug_during_sleep { crate::pac::DBGMCU.cr().modify(|cr| { - #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))] + #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] { cr.set_dbg_stop(true); cr.set_dbg_standby(true); diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 059a3211..d774b993 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -26,19 +26,7 @@ impl From for crate::pac::rcc::vals::Lsedrv { } } -#[allow(dead_code)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[repr(u8)] -pub enum RtcClockSource { - /// 00: No clock - NoClock = 0b00, - /// 01: LSE oscillator clock used as RTC clock - LSE = 0b01, - /// 10: LSI oscillator clock used as RTC clock - LSI = 0b10, - /// 11: HSE oscillator clock divided by 32 used as RTC clock - HSE = 0b11, -} +pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; #[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] #[allow(dead_code)] @@ -109,17 +97,17 @@ impl BackupDomain { let csr = crate::pac::RCC.csr(); Self::modify(|_| { - #[cfg(not(rtc_v2wb))] + #[cfg(not(any(rcc_wb, rcc_wba)))] csr.modify(|w| w.set_lsion(true)); - #[cfg(rtc_v2wb)] + #[cfg(any(rcc_wb, rcc_wba))] csr.modify(|w| w.set_lsi1on(true)); }); - #[cfg(not(rtc_v2wb))] + #[cfg(not(any(rcc_wb, rcc_wba)))] while !csr.read().lsirdy() {} - #[cfg(rtc_v2wb)] + #[cfg(any(rcc_wb, rcc_wba))] while !csr.read().lsi1rdy() {} } RtcClockSource::LSE => { @@ -136,64 +124,50 @@ impl BackupDomain { _ => {} }; - Self::configure_rtc(clock_source); - } - - #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, - rtc_v3u5 - ))] - #[allow(dead_code, unused_variables)] - pub fn configure_rtc(clock_source: RtcClockSource) { - let clock_source = clock_source as u8; - #[cfg(any( - not(any(rtc_v3, rtc_v3u5, rtc_v2wb)), - all(any(rtc_v3, rtc_v3u5), not(any(rcc_wl5, rcc_wle))) - ))] - let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); - - #[cfg(not(rtc_v2wb))] - Self::modify(|w| { - // Select RTC source - w.set_rtcsel(clock_source); - }); - } - - #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, - rtc_v3u5 - ))] - #[allow(dead_code)] - pub fn enable_rtc() { - let reg = Self::read(); - - #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() { - #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] - Self::modify(|w| w.set_bdrst(true)); - + if clock_source == RtcClockSource::NOCLOCK { + // disable it Self::modify(|w| { - // Reset - #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] - w.set_bdrst(false); - - w.set_rtcen(true); - w.set_rtcsel(reg.rtcsel()); - - // Restore bcdr - #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lscosel(reg.lscosel()); - #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - - #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); + #[cfg(not(rcc_wba))] + w.set_rtcen(false); + w.set_rtcsel(clock_source); }); + } else { + // check if it's already enabled and in the source we want. + let reg = Self::read(); + let ok = reg.rtcsel() == clock_source; + #[cfg(not(rcc_wba))] + let ok = ok & reg.rtcen(); + + // if not, configure it. + if !ok { + #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] + assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); + + #[cfg(not(any(rcc_l0, rcc_l1)))] + Self::modify(|w| w.set_bdrst(true)); + + Self::modify(|w| { + // Reset + #[cfg(not(any(rcc_l0, rcc_l1)))] + w.set_bdrst(false); + + #[cfg(not(rcc_wba))] + w.set_rtcen(true); + w.set_rtcsel(clock_source); + + // Restore bcdr + #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] + w.set_lscosel(reg.lscosel()); + #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] + w.set_lscoen(reg.lscoen()); + + w.set_lseon(reg.lseon()); + + #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] + w.set_lsedrv(reg.lsedrv()); + w.set_lsebyp(reg.lsebyp()); + }); + } } } } diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs index 62736a43..32e10b7e 100644 --- a/embassy-stm32/src/rcc/bus.rs +++ b/embassy-stm32/src/rcc/bus.rs @@ -79,10 +79,7 @@ impl From for rcc::vals::Hpre { use rcc::vals::Hpre; match val { - #[cfg(not(rcc_u5))] AHBPrescaler::NotDivided => Hpre::DIV1, - #[cfg(rcc_u5)] - AHBPrescaler::NotDivided => Hpre::NONE, AHBPrescaler::Div2 => Hpre::DIV2, AHBPrescaler::Div4 => Hpre::DIV4, AHBPrescaler::Div8 => Hpre::DIV8, @@ -148,10 +145,7 @@ impl From for rcc::vals::Ppre { use rcc::vals::Ppre; match val { - #[cfg(not(rcc_u5))] APBPrescaler::NotDivided => Ppre::DIV1, - #[cfg(rcc_u5)] - APBPrescaler::NotDivided => Ppre::NONE, APBPrescaler::Div2 => Ppre::DIV2, APBPrescaler::Div4 => Ppre::DIV4, APBPrescaler::Div8 => Ppre::DIV8, diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 4f0b7fd0..b8c12b99 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,6 +1,7 @@ #![macro_use] pub(crate) mod bd; +#[cfg(not(rcc_wba))] pub mod bus; use core::mem::MaybeUninit; @@ -23,6 +24,7 @@ use crate::time::Hertz; #[cfg_attr(rcc_l5, path = "l5.rs")] #[cfg_attr(rcc_u5, path = "u5.rs")] #[cfg_attr(rcc_wb, path = "wb.rs")] +#[cfg_attr(rcc_wba, path = "wba.rs")] #[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] #[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")] mod _version; @@ -46,12 +48,14 @@ pub struct Clocks { pub apb3: Hertz, #[cfg(any(rcc_h7, rcc_h7ab))] pub apb4: Hertz, + #[cfg(any(rcc_wba))] + pub apb7: Hertz, // AHB pub ahb1: Hertz, #[cfg(any( rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, - rcc_wl5, rcc_wle + rcc_wba, rcc_wl5, rcc_wle ))] pub ahb2: Hertz, #[cfg(any( @@ -59,7 +63,7 @@ pub struct Clocks { rcc_wle ))] pub ahb3: Hertz, - #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] + #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_wba))] pub ahb4: Hertz, #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 4aca9cd3..6540b1f5 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -165,7 +165,7 @@ impl Into for ClockSrc { ClockSrc::MSI(..) => Sw::MSIS, ClockSrc::HSE(..) => Sw::HSE, ClockSrc::HSI16 => Sw::HSI16, - ClockSrc::PLL1R(..) => Sw::PLL1R, + ClockSrc::PLL1R(..) => Sw::PLL1_R, } } } diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs new file mode 100644 index 00000000..2a11c9a2 --- /dev/null +++ b/embassy-stm32/src/rcc/wba.rs @@ -0,0 +1,184 @@ +use stm32_metapac::rcc::vals::{Pllsrc, Sw}; + +use crate::pac::{FLASH, RCC}; +use crate::rcc::{set_freqs, Clocks}; +use crate::time::Hertz; + +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); + +pub use crate::pac::pwr::vals::Vos as VoltageScale; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; + +#[derive(Copy, Clone)] +pub enum ClockSrc { + HSE(Hertz), + HSI16, +} + +#[derive(Clone, Copy, Debug)] +pub enum PllSrc { + HSE(Hertz), + HSI16, +} + +impl Into for PllSrc { + fn into(self) -> Pllsrc { + match self { + PllSrc::HSE(..) => Pllsrc::HSE32, + PllSrc::HSI16 => Pllsrc::HSI16, + } + } +} + +impl Into for ClockSrc { + fn into(self) -> Sw { + match self { + ClockSrc::HSE(..) => Sw::HSE32, + ClockSrc::HSI16 => Sw::HSI16, + } + } +} + +trait Div { + fn div(&self) -> u8; +} + +impl Div for APBPrescaler { + fn div(&self) -> u8 { + match self { + Self::DIV1 => 1, + Self::DIV2 => 2, + Self::DIV4 => 4, + Self::DIV8 => 8, + Self::DIV16 => 16, + _ => unreachable!(), + } + } +} + +impl Div for AHBPrescaler { + fn div(&self) -> u8 { + match self { + Self::DIV1 => 1, + Self::DIV2 => 2, + Self::DIV4 => 4, + Self::DIV8 => 8, + Self::DIV16 => 16, + _ => unreachable!(), + } + } +} + +#[derive(Copy, Clone)] +pub struct Config { + pub mux: ClockSrc, + pub ahb_pre: AHBPrescaler, + pub apb1_pre: APBPrescaler, + pub apb2_pre: APBPrescaler, + pub apb7_pre: APBPrescaler, +} + +impl Default for Config { + fn default() -> Self { + Self { + mux: ClockSrc::HSI16, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + apb7_pre: APBPrescaler::DIV1, + } + } +} + +pub(crate) unsafe fn init(config: Config) { + let sys_clk = match config.mux { + ClockSrc::HSE(freq) => { + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + + freq.0 + } + ClockSrc::HSI16 => { + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + + HSI_FREQ.0 + } + }; + + // TODO make configurable + let power_vos = VoltageScale::RANGE1; + + // states and programming delay + let wait_states = match power_vos { + VoltageScale::RANGE1 => match sys_clk { + ..=32_000_000 => 0, + ..=64_000_000 => 1, + ..=96_000_000 => 2, + ..=100_000_000 => 3, + _ => 4, + }, + VoltageScale::RANGE2 => match sys_clk { + ..=8_000_000 => 0, + ..=16_000_000 => 1, + _ => 2, + }, + }; + + FLASH.acr().modify(|w| { + w.set_latency(wait_states); + }); + + RCC.cfgr1().modify(|w| { + w.set_sw(config.mux.into()); + }); + + RCC.cfgr2().modify(|w| { + w.set_hpre(config.ahb_pre.into()); + w.set_ppre1(config.apb1_pre.into()); + w.set_ppre2(config.apb2_pre.into()); + }); + + RCC.cfgr3().modify(|w| { + w.set_ppre7(config.apb7_pre.into()); + }); + + let ahb_freq: u32 = sys_clk / config.ahb_pre.div() as u32; + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre.div() { + 1 => (ahb_freq, ahb_freq), + div => { + let freq = ahb_freq / div as u32; + (freq, freq * 2) + } + }; + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre.div() { + 1 => (ahb_freq, ahb_freq), + div => { + let freq = ahb_freq / div as u32; + (freq, freq * 2) + } + }; + let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre.div() { + 1 => (ahb_freq, ahb_freq), + div => { + let freq = ahb_freq / div as u32; + (freq, freq * 2) + } + }; + + set_freqs(Clocks { + sys: Hertz(sys_clk), + ahb1: Hertz(ahb_freq), + ahb2: Hertz(ahb_freq), + ahb4: Hertz(ahb_freq), + apb1: Hertz(apb1_freq), + apb2: Hertz(apb2_freq), + apb7: Hertz(apb7_freq), + apb1_tim: Hertz(apb1_tim_freq), + apb2_tim: Hertz(apb2_tim_freq), + }); +} diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 32a5cc12..3ecf477d 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -10,7 +10,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; -use crate::rcc::bd::BackupDomain; pub use crate::rcc::RtcClockSource; use crate::time::Hertz; @@ -125,7 +124,6 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { RTC::enable_peripheral_clk(); - BackupDomain::enable_rtc(); let mut this = Self { #[cfg(feature = "low-power")] diff --git a/examples/stm32wba/.cargo/config.toml b/examples/stm32wba/.cargo/config.toml new file mode 100644 index 00000000..47741339 --- /dev/null +++ b/examples/stm32wba/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = "probe-rs run --chip STM32WBA52CGUxT" + +[build] +target = "thumbv8m.main-none-eabihf" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml new file mode 100644 index 00000000..26fcce26 --- /dev/null +++ b/examples/stm32wba/Cargo.toml @@ -0,0 +1,26 @@ +[package] +edition = "2021" +name = "embassy-stm32wba-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } +embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +panic-probe = { version = "0.3", features = ["print-defmt"] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +heapless = { version = "0.7.5", default-features = false } +static_cell = { version = "1.1", features = ["nightly"]} + +[profile.release] +debug = 2 diff --git a/examples/stm32wba/build.rs b/examples/stm32wba/build.rs new file mode 100644 index 00000000..8fc6faab --- /dev/null +++ b/examples/stm32wba/build.rs @@ -0,0 +1,10 @@ +use std::error::Error; + +fn main() -> Result<(), Box> { + println!("cargo:rerun-if-changed=link.x"); + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + + Ok(()) +} diff --git a/examples/stm32wba/src/bin/blinky.rs b/examples/stm32wba/src/bin/blinky.rs new file mode 100644 index 00000000..53074629 --- /dev/null +++ b/examples/stm32wba/src/bin/blinky.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut led = Output::new(p.PB4, Level::High, Speed::Low); + + loop { + info!("high"); + led.set_high(); + Timer::after(Duration::from_millis(500)).await; + + info!("low"); + led.set_low(); + Timer::after(Duration::from_millis(500)).await; + } +} diff --git a/examples/stm32wba/src/bin/button_exti.rs b/examples/stm32wba/src/bin/button_exti.rs new file mode 100644 index 00000000..ef32d4c4 --- /dev/null +++ b/examples/stm32wba/src/bin/button_exti.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::{Input, Pull}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let button = Input::new(p.PC13, Pull::Up); + let mut button = ExtiInput::new(button, p.EXTI13); + + info!("Press the USER button..."); + + loop { + button.wait_for_falling_edge().await; + info!("Pressed!"); + button.wait_for_rising_edge().await; + info!("Released!"); + } +} From 537e2f3b444290c9732c2e98354f6084a91b5d23 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 16 Sep 2023 08:19:49 -0500 Subject: [PATCH 176/233] update docs --- docs/modules/ROOT/nav.adoc | 2 + docs/modules/ROOT/pages/developer.adoc | 1 + docs/modules/ROOT/pages/developer_stm32.adoc | 79 ++++++++++++++++++++ docs/modules/ROOT/pages/index.adoc | 9 +-- 4 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 docs/modules/ROOT/pages/developer.adoc create mode 100644 docs/modules/ROOT/pages/developer_stm32.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 86f2996f..261a3c19 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -8,3 +8,5 @@ * xref:bootloader.adoc[Bootloader] * xref:examples.adoc[Examples] +* xref:developer.adoc[Developer] +** xref:developer_stm32.adoc[Developer: STM32] \ No newline at end of file diff --git a/docs/modules/ROOT/pages/developer.adoc b/docs/modules/ROOT/pages/developer.adoc new file mode 100644 index 00000000..e03ee51a --- /dev/null +++ b/docs/modules/ROOT/pages/developer.adoc @@ -0,0 +1 @@ += Developer Documentation \ No newline at end of file diff --git a/docs/modules/ROOT/pages/developer_stm32.adoc b/docs/modules/ROOT/pages/developer_stm32.adoc new file mode 100644 index 00000000..7c04ab1a --- /dev/null +++ b/docs/modules/ROOT/pages/developer_stm32.adoc @@ -0,0 +1,79 @@ += Developer Documentation: STM32 + +== Understanding metapac + +When a project that imports `embassy-stm32` is compiled, that project selects the feature corresponding to the chip that project is using. Based on that feature, `embassy-stm32` selects supported link:https://anysilicon.com/ip-intellectual-property-core-semiconductors/[IP] for the chip, and enables the corresponding HAL implementations. But how does `embassy-stm32` know what IP the chip contains, out of the hundreds of chips that we support? It's a long story that starts with `stm32-data-sources`. + +== `stm32-data-sources` + +link:https://github.com/embassy-rs/stm32-data-sources[`stm32-data-sources`] is as mostly barren repository. It has no README, no documentation, and few watchers. But it's the core of what makes `embassy-stm32` possible. The data for every chip that we support is taken in part from a corresponding XML file like link:https://github.com/embassy-rs/stm32-data-sources/blob/b8b85202e22a954d6c59d4a43d9795d34cff05cf/cubedb/mcu/STM32F051K4Ux.xml[`STM32F051K4Ux.xml`]. In that file, you'll see lines like the following: + +[source,xml] +---- + + + +---- + +These lines indicate that this chip has an i2c, and that it's version is "v1_1". It also indicates that it has a general purpose timer that with a version of "v2_x". From this data, it's possible to determine which implementations should be included in `embassy-stm32`. But actually doing that is another matter. + + +== `stm32-data` + +While all users of this project are familiar with `embassy-stm32`, fewer are familiar with the project that powers it: `stm32-data`. This project doesn't just aim to generate data for `embassy-stm32`, but for machine consumption in general. To acheive this, information from multiple files from the `stm32-data-sources` project are combined and parsed to assign register block implementations for each supported IP. The core of this matching resides in `chips.rs`: + +[source,rust] +---- + (".*:I2C:i2c2_v1_1", ("i2c", "v2", "I2C")), + // snip + (r".*TIM\d.*:gptimer.*", ("timer", "v1", "TIM_GP16")), +---- + +In this case, the i2c version corresponds to our "v2" and the general purpose timer version corresponds to our "v1". Therefore, the `i2c_v2.yaml` and `timer_v1.yaml` register block implementations are assigned to those IP, respectively. The result is that these lines arr generated in `STM32F051K4.json`: + +[source,json] +---- + { + "name": "I2C1", + "address": 1073763328, + "registers": { + "kind": "i2c", + "version": "v2", + "block": "I2C" + }, + // snip + } + // snip + { + "name": "TIM1", + "address": 1073818624, + "registers": { + "kind": "timer", + "version": "v1", + "block": "TIM_ADV" + }, + // snip + } +---- + +In addition to register blocks, data for pin and RCC mapping is also generated and consumed by `embassy-stm32`. `stm32-metapac-gen` is used to package and publish the data as a crate. + + +== `embassy-stm32` + +In the `lib.rs` file located in the root of `embassy-stm32`, you'll see this line: + +[source,rust] +---- +#[cfg(i2c)] +pub mod i2c; +---- + +And in the `mod.rs` of the i2c mod, you'll see this: + +[source,rust] +---- +#[cfg_attr(i2c_v2, path = "v2.rs")] +---- + +Because i2c is supported for STM32F051K4 and its version corresponds to our "v2", the `i2c` and `i2c_v2`, configuration directives will be present, and `embassy-stm32` will include these files, respectively. This and other configuration directives and tables are generated from the data for chip, allowing `embassy-stm32` to expressively and clearly adapt logic and implementations to what is required for each chip. Compared to other projects across the embedded ecosystem, `embassy-stm32` is the only project that can re-use code across the entire stm32 lineup and remove difficult-to-implement unsafe logic to the HAL. \ No newline at end of file diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 0a17c673..805a1e70 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -4,14 +4,9 @@ Embassy is a project to make async/await a first-class option for embedded devel == What is async? -Software written without async may block on I/O operations. In an std environment, such as a PC, software can handle this either by using threads or non-blocking operations. +When handling I/O, software must call functions that block program execution until the I/O operation completes. When running inside of an OS such as Linux, such functions generally transfer control to the kernel so that another task, known as a thread, can be executed if available, or the CPU can be put to sleep until another such task is ready to perform more work. Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted they do not transfer control back to the kernel within an allotted time. But if tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread. In Rust, these lightweight tasks, known as 'coroutines' or 'goroutines' in other languages, are implemented with async. -With threads, one thread blocks on an I/O operation, another is able to take its place. However, even on a PC, threads are relatively heavy, and therefore some programming languages, such as Go, have implemented a concept called coroutines or 'goroutines' that are much lighter and less-intensive than threads. - -The other way to handle blocking I/O operations is to support polling the state of the underlying peripherals to check whether it is available to perform the requested operation. In programming languages without builtin async support, -this requires building a complex loop checking for events. - -In Rust, non-blocking operations can be implemented using async-await. Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size. +Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size. == What is Embassy? From ad0a306ea52f7d842efa8ce40c89f462501ed018 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 16 Sep 2023 10:19:09 -0500 Subject: [PATCH 177/233] stm32: fix wpan_ble test --- ci.sh | 2 -- embassy-stm32/src/rcc/wb.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index a3d9ef81..87f47487 100755 --- a/ci.sh +++ b/ci.sh @@ -182,6 +182,4 @@ if [[ -z "${TELEPROBE_TOKEN-}" ]]; then exit fi -rm out/tests/stm32wb55rg/wpan_ble - teleprobe client run -r out/tests diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index d90a50cf..f003f6d7 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -135,7 +135,7 @@ pub const WPAN_DEFAULT: Config = Config { prediv: 2, }), pll48: None, - rtc: None, + rtc: Some(RtcClockSource::LSE), pll: Some(Pll { mul: 12, From 09f087e53eff3e2dc48a79cab9726dd916537625 Mon Sep 17 00:00:00 2001 From: Will Farrell <2183550+wkf@users.noreply.github.com> Date: Sat, 16 Sep 2023 16:31:02 -0400 Subject: [PATCH 178/233] Update stm32wb examples to use ble/mac firmware. --- examples/stm32wb/src/bin/eddystone_beacon.rs | 4 ++-- examples/stm32wb/src/bin/gatt_server.rs | 4 ++-- examples/stm32wb/src/bin/tl_mbox.rs | 4 ++-- examples/stm32wb/src/bin/tl_mbox_ble.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs index ea150c67..e58da8e3 100644 --- a/examples/stm32wb/src/bin/eddystone_beacon.rs +++ b/examples/stm32wb/src/bin/eddystone_beacon.rs @@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) { - Obtain a NUCLEO-STM32WB55 from your preferred supplier. - Download and Install STM32CubeProgrammer. - - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from + - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Mac_802_15_4_fw.bin, and Release_Notes.html from gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x - Open STM32CubeProgrammer - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. @@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) { - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file - Select that file, the memory address, "verify download", and then "Firmware Upgrade". - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the - stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. + stm32wb5x_BLE_Mac_802_15_4_fw.bin file. It should not be the same memory address. - Select that file, the memory address, "verify download", and then "Firmware Upgrade". - Select "Start Wireless Stack". - Disconnect from the device. diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs index dd67249c..80e835c1 100644 --- a/examples/stm32wb/src/bin/gatt_server.rs +++ b/examples/stm32wb/src/bin/gatt_server.rs @@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) { - Obtain a NUCLEO-STM32WB55 from your preferred supplier. - Download and Install STM32CubeProgrammer. - - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from + - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Mac_802_15_4_fw.bin, and Release_Notes.html from gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x - Open STM32CubeProgrammer - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. @@ -53,7 +53,7 @@ async fn main(_spawner: Spawner) { - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file - Select that file, the memory address, "verify download", and then "Firmware Upgrade". - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the - stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. + stm32wb5x_BLE_Mac_802_15_4_fw.bin file. It should not be the same memory address. - Select that file, the memory address, "verify download", and then "Firmware Upgrade". - Select "Start Wireless Stack". - Disconnect from the device. diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs index fc49c3c4..2f53f5df 100644 --- a/examples/stm32wb/src/bin/tl_mbox.rs +++ b/examples/stm32wb/src/bin/tl_mbox.rs @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { - Obtain a NUCLEO-STM32WB55 from your preferred supplier. - Download and Install STM32CubeProgrammer. - - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from + - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Mac_802_15_4_fw.bin, and Release_Notes.html from gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x - Open STM32CubeProgrammer - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. @@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) { - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file - Select that file, the memory address, "verify download", and then "Firmware Upgrade". - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the - stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. + stm32wb5x_BLE_Mac_802_15_4_fw.bin file. It should not be the same memory address. - Select that file, the memory address, "verify download", and then "Firmware Upgrade". - Select "Start Wireless Stack". - Disconnect from the device. diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs index 5745ebd0..12c6aeeb 100644 --- a/examples/stm32wb/src/bin/tl_mbox_ble.rs +++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { - Obtain a NUCLEO-STM32WB55 from your preferred supplier. - Download and Install STM32CubeProgrammer. - - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from + - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Mac_802_15_4_fw.bin, and Release_Notes.html from gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x - Open STM32CubeProgrammer - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. @@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) { - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file - Select that file, the memory address, "verify download", and then "Firmware Upgrade". - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the - stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. + stm32wb5x_BLE_Mac_802_15_4_fw.bin file. It should not be the same memory address. - Select that file, the memory address, "verify download", and then "Firmware Upgrade". - Select "Start Wireless Stack". - Disconnect from the device. From de2773afdd3f2d06cad0632ee075e1b88aa71515 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 16 Sep 2023 17:41:11 -0500 Subject: [PATCH 179/233] stm32/rcc: convert bus prescalers to pac enums --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/rcc/bus.rs | 144 ++++--------------------- embassy-stm32/src/rcc/c0.rs | 25 ++--- embassy-stm32/src/rcc/f1.rs | 4 +- embassy-stm32/src/rcc/f2.rs | 10 +- embassy-stm32/src/rcc/g0.rs | 6 +- embassy-stm32/src/rcc/g4.rs | 90 ++++++---------- embassy-stm32/src/rcc/h5.rs | 50 ++++----- embassy-stm32/src/rcc/h7.rs | 10 +- embassy-stm32/src/rcc/l0.rs | 12 +-- embassy-stm32/src/rcc/l1.rs | 12 +-- embassy-stm32/src/rcc/l4.rs | 12 +-- embassy-stm32/src/rcc/l5.rs | 12 +-- embassy-stm32/src/rcc/u5.rs | 56 ++-------- embassy-stm32/src/rcc/wb.rs | 30 +++--- embassy-stm32/src/rcc/wl.rs | 24 ++--- examples/stm32f2/src/bin/pll.rs | 4 +- examples/stm32h5/src/bin/eth.rs | 8 +- examples/stm32h5/src/bin/usb_serial.rs | 8 +- 19 files changed, 174 insertions(+), 347 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 699995bc..0cae981c 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -59,7 +59,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-546aead07086342605102d66dec49c5e2d459a0c" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-907dd82c848bc912252c61509944e85c2a48c919" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-546aead07086342605102d66dec49c5e2d459a0c", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-907dd82c848bc912252c61509944e85c2a48c919", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs index 32e10b7e..fb6dcb01 100644 --- a/embassy-stm32/src/rcc/bus.rs +++ b/embassy-stm32/src/rcc/bus.rs @@ -2,6 +2,7 @@ use core::ops::Div; #[allow(unused_imports)] use crate::pac::rcc; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; use crate::time::Hertz; /// Voltage Scale @@ -20,149 +21,48 @@ pub enum VoltageScale { Scale3, } -/// AHB prescaler -#[derive(Clone, Copy, PartialEq)] -pub enum AHBPrescaler { - NotDivided, - Div2, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div3, - Div4, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div5, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div6, - Div8, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div10, - Div16, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div32, - Div64, - Div128, - Div256, - Div512, -} - impl Div for Hertz { type Output = Hertz; fn div(self, rhs: AHBPrescaler) -> Self::Output { let divisor = match rhs { - AHBPrescaler::NotDivided => 1, - AHBPrescaler::Div2 => 2, + AHBPrescaler::DIV1 => 1, + AHBPrescaler::DIV2 => 2, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div3 => 3, - AHBPrescaler::Div4 => 4, + AHBPrescaler::DIV3 => 3, + AHBPrescaler::DIV4 => 4, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div5 => 5, + AHBPrescaler::DIV5 => 5, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div6 => 6, - AHBPrescaler::Div8 => 8, + AHBPrescaler::DIV6 => 6, + AHBPrescaler::DIV8 => 8, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div10 => 10, - AHBPrescaler::Div16 => 16, + AHBPrescaler::DIV10 => 10, + AHBPrescaler::DIV16 => 16, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div32 => 32, - AHBPrescaler::Div64 => 64, - AHBPrescaler::Div128 => 128, - AHBPrescaler::Div256 => 256, - AHBPrescaler::Div512 => 512, + AHBPrescaler::DIV32 => 32, + AHBPrescaler::DIV64 => 64, + AHBPrescaler::DIV128 => 128, + AHBPrescaler::DIV256 => 256, + AHBPrescaler::DIV512 => 512, + _ => unreachable!(), }; Hertz(self.0 / divisor) } } -#[cfg(not(any(rcc_g4, rcc_wb, rcc_wl5, rcc_wle)))] -impl From for rcc::vals::Hpre { - fn from(val: AHBPrescaler) -> rcc::vals::Hpre { - use rcc::vals::Hpre; - - match val { - AHBPrescaler::NotDivided => Hpre::DIV1, - AHBPrescaler::Div2 => Hpre::DIV2, - AHBPrescaler::Div4 => Hpre::DIV4, - AHBPrescaler::Div8 => Hpre::DIV8, - AHBPrescaler::Div16 => Hpre::DIV16, - AHBPrescaler::Div64 => Hpre::DIV64, - AHBPrescaler::Div128 => Hpre::DIV128, - AHBPrescaler::Div256 => Hpre::DIV256, - AHBPrescaler::Div512 => Hpre::DIV512, - } - } -} - -#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] -impl From for u8 { - fn from(val: AHBPrescaler) -> u8 { - match val { - AHBPrescaler::NotDivided => 0x0, - AHBPrescaler::Div2 => 0x08, - AHBPrescaler::Div3 => 0x01, - AHBPrescaler::Div4 => 0x09, - AHBPrescaler::Div5 => 0x02, - AHBPrescaler::Div6 => 0x05, - AHBPrescaler::Div8 => 0x0a, - AHBPrescaler::Div10 => 0x06, - AHBPrescaler::Div16 => 0x0b, - AHBPrescaler::Div32 => 0x07, - AHBPrescaler::Div64 => 0x0c, - AHBPrescaler::Div128 => 0x0d, - AHBPrescaler::Div256 => 0x0e, - AHBPrescaler::Div512 => 0x0f, - } - } -} - -/// APB prescaler -#[derive(Clone, Copy)] -pub enum APBPrescaler { - NotDivided, - Div2, - Div4, - Div8, - Div16, -} - impl Div for Hertz { type Output = Hertz; fn div(self, rhs: APBPrescaler) -> Self::Output { let divisor = match rhs { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 2, - APBPrescaler::Div4 => 4, - APBPrescaler::Div8 => 8, - APBPrescaler::Div16 => 16, + APBPrescaler::DIV1 => 1, + APBPrescaler::DIV2 => 2, + APBPrescaler::DIV4 => 4, + APBPrescaler::DIV8 => 8, + APBPrescaler::DIV16 => 16, + _ => unreachable!(), }; Hertz(self.0 / divisor) } } - -#[cfg(not(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_g4, rcc_h7, rcc_h7ab, rcc_wb, rcc_wl5, rcc_wle)))] -impl From for rcc::vals::Ppre { - fn from(val: APBPrescaler) -> rcc::vals::Ppre { - use rcc::vals::Ppre; - - match val { - APBPrescaler::NotDivided => Ppre::DIV1, - APBPrescaler::Div2 => Ppre::DIV2, - APBPrescaler::Div4 => Ppre::DIV4, - APBPrescaler::Div8 => Ppre::DIV8, - APBPrescaler::Div16 => Ppre::DIV16, - } - } -} - -#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] -impl From for u8 { - fn from(val: APBPrescaler) -> u8 { - match val { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 0x04, - APBPrescaler::Div4 => 0x05, - APBPrescaler::Div8 => 0x06, - APBPrescaler::Div16 => 0x07, - } - } -} diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index d8579079..8f45e7c0 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -58,8 +58,8 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::HSI(HSIPrescaler::NotDivided), - ahb_pre: AHBPrescaler::NotDivided, - apb_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb_pre: APBPrescaler::DIV1, } } } @@ -151,20 +151,21 @@ pub(crate) unsafe fn init(config: Config) { } let ahb_div = match config.ahb_pre { - AHBPrescaler::NotDivided => 1, - AHBPrescaler::Div2 => 2, - AHBPrescaler::Div4 => 4, - AHBPrescaler::Div8 => 8, - AHBPrescaler::Div16 => 16, - AHBPrescaler::Div64 => 64, - AHBPrescaler::Div128 => 128, - AHBPrescaler::Div256 => 256, - AHBPrescaler::Div512 => 512, + AHBPrescaler::DIV1 => 1, + AHBPrescaler::DIV2 => 2, + AHBPrescaler::DIV4 => 4, + AHBPrescaler::DIV8 => 8, + AHBPrescaler::DIV16 => 16, + AHBPrescaler::DIV64 => 64, + AHBPrescaler::DIV128 => 128, + AHBPrescaler::DIV256 => 256, + AHBPrescaler::DIV512 => 512, + _ => unreachable!(), }; let ahb_freq = sys_clk / ahb_div; let (apb_freq, apb_tim_freq) = match config.apb_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index 304d8f50..081c0c76 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs @@ -163,8 +163,8 @@ pub(crate) unsafe fn init(config: Config) { // Only needed for stm32f103? RCC.cfgr().modify(|w| { w.set_adcpre(Adcpre::from_bits(apre_bits)); - w.set_ppre2(Ppre1::from_bits(ppre2_bits)); - w.set_ppre1(Ppre1::from_bits(ppre1_bits)); + w.set_ppre2(Ppre::from_bits(ppre2_bits)); + w.set_ppre1(Ppre::from_bits(ppre1_bits)); w.set_hpre(Hpre::from_bits(hpre_bits)); #[cfg(not(rcc_f100))] w.set_usbpre(Usbpre::from_bits(usbpre as u8)); diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index b821f958..da88e44d 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -308,9 +308,9 @@ impl Default for Config { voltage: VoltageScale::Scale3, mux: ClockSrc::HSI, rtc: None, - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, } } } @@ -383,7 +383,7 @@ pub(crate) unsafe fn init(config: Config) { assert!(ahb_freq <= Hertz(120_000_000)); let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let freq = ahb_freq / pre; (freq, Hertz(freq.0 * 2)) @@ -393,7 +393,7 @@ pub(crate) unsafe fn init(config: Config) { assert!(apb1_freq <= Hertz(30_000_000)); let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let freq = ahb_freq / pre; (freq, Hertz(freq.0 * 2)) diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 7fdbcb00..7f0a2c7f 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -186,8 +186,8 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), - ahb_pre: AHBPrescaler::NotDivided, - apb_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb_pre: APBPrescaler::DIV1, low_power_run: false, } } @@ -377,7 +377,7 @@ pub(crate) unsafe fn init(config: Config) { let ahb_freq = Hertz(sys_clk) / config.ahb_pre; let (apb_freq, apb_tim_freq) = match config.apb_pre { - APBPrescaler::NotDivided => (ahb_freq.0, ahb_freq.0), + APBPrescaler::DIV1 => (ahb_freq.0, ahb_freq.0), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 2359f39c..41bebc91 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -1,5 +1,5 @@ use stm32_metapac::flash::vals::Latency; -use stm32_metapac::rcc::vals::{Adcsel, Hpre, Pllsrc, Ppre, Sw}; +use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw}; use stm32_metapac::FLASH; pub use super::bus::{AHBPrescaler, APBPrescaler}; @@ -261,59 +261,29 @@ pub struct Pll { pub div_r: Option, } -impl AHBPrescaler { - const fn div(self) -> u32 { - match self { - AHBPrescaler::NotDivided => 1, - AHBPrescaler::Div2 => 2, - AHBPrescaler::Div4 => 4, - AHBPrescaler::Div8 => 8, - AHBPrescaler::Div16 => 16, - AHBPrescaler::Div64 => 64, - AHBPrescaler::Div128 => 128, - AHBPrescaler::Div256 => 256, - AHBPrescaler::Div512 => 512, - } +fn ahb_div(ahb: AHBPrescaler) -> u32 { + match ahb { + AHBPrescaler::DIV1 => 1, + AHBPrescaler::DIV2 => 2, + AHBPrescaler::DIV4 => 4, + AHBPrescaler::DIV8 => 8, + AHBPrescaler::DIV16 => 16, + AHBPrescaler::DIV64 => 64, + AHBPrescaler::DIV128 => 128, + AHBPrescaler::DIV256 => 256, + AHBPrescaler::DIV512 => 512, + _ => unreachable!(), } } -impl APBPrescaler { - const fn div(self) -> u32 { - match self { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 2, - APBPrescaler::Div4 => 4, - APBPrescaler::Div8 => 8, - APBPrescaler::Div16 => 16, - } - } -} - -impl Into for APBPrescaler { - fn into(self) -> Ppre { - match self { - APBPrescaler::NotDivided => Ppre::DIV1, - APBPrescaler::Div2 => Ppre::DIV2, - APBPrescaler::Div4 => Ppre::DIV4, - APBPrescaler::Div8 => Ppre::DIV8, - APBPrescaler::Div16 => Ppre::DIV16, - } - } -} - -impl Into for AHBPrescaler { - fn into(self) -> Hpre { - match self { - AHBPrescaler::NotDivided => Hpre::DIV1, - AHBPrescaler::Div2 => Hpre::DIV2, - AHBPrescaler::Div4 => Hpre::DIV4, - AHBPrescaler::Div8 => Hpre::DIV8, - AHBPrescaler::Div16 => Hpre::DIV16, - AHBPrescaler::Div64 => Hpre::DIV64, - AHBPrescaler::Div128 => Hpre::DIV128, - AHBPrescaler::Div256 => Hpre::DIV256, - AHBPrescaler::Div512 => Hpre::DIV512, - } +fn apb_div(apb: APBPrescaler) -> u32 { + match apb { + APBPrescaler::DIV1 => 1, + APBPrescaler::DIV2 => 2, + APBPrescaler::DIV4 => 4, + APBPrescaler::DIV8 => 8, + APBPrescaler::DIV16 => 16, + _ => unreachable!(), } } @@ -365,9 +335,9 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::HSI16, - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, low_power_run: false, pll: None, clock_48mhz_src: None, @@ -512,22 +482,22 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, - pre => sys_clk / pre.div(), + AHBPrescaler::DIV1 => sys_clk, + pre => sys_clk / ahb_div(pre), }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { - let freq = ahb_freq / pre.div(); + let freq = ahb_freq / apb_div(pre); (freq, freq * 2) } }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { - let freq = ahb_freq / pre.div(); + let freq = ahb_freq / apb_div(pre); (freq, freq * 2) } }; diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs index 5741cdf9..ac45605f 100644 --- a/embassy-stm32/src/rcc/h5.rs +++ b/embassy-stm32/src/rcc/h5.rs @@ -91,25 +91,25 @@ pub struct Pll { pub divr: Option, } -impl APBPrescaler { - fn div_tim(&self, clk: Hertz, tim: TimerPrescaler) -> Hertz { - match (tim, self) { - // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a - // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 - (TimerPrescaler::DefaultX2, Self::NotDivided) => clk, - (TimerPrescaler::DefaultX2, Self::Div2) => clk, - (TimerPrescaler::DefaultX2, Self::Div4) => clk / 2u32, - (TimerPrescaler::DefaultX2, Self::Div8) => clk / 4u32, - (TimerPrescaler::DefaultX2, Self::Div16) => clk / 8u32, - // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2 - // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2 - // this makes NO SENSE and is different than in the H7. Mistake in the RM?? - (TimerPrescaler::DefaultX4, Self::NotDivided) => clk * 2u32, - (TimerPrescaler::DefaultX4, Self::Div2) => clk, - (TimerPrescaler::DefaultX4, Self::Div4) => clk / 2u32, - (TimerPrescaler::DefaultX4, Self::Div8) => clk / 2u32, - (TimerPrescaler::DefaultX4, Self::Div16) => clk / 4u32, - } +fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { + match (tim, apb) { + // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a + // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 + (TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32, + // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2 + // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2 + // this makes NO SENSE and is different than in the H7. Mistake in the RM?? + (TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk * 2u32, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk / 2u32, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32, + + _ => unreachable!(), } } @@ -165,10 +165,10 @@ impl Default for Config { #[cfg(rcc_h5)] pll3: None, - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, - apb3_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + apb3_pre: APBPrescaler::DIV1, timer_prescaler: TimerPrescaler::DefaultX2, voltage_scale: VoltageScale::Scale3, @@ -317,9 +317,9 @@ pub(crate) unsafe fn init(config: Config) { let hclk = sys / config.ahb_pre; let apb1 = hclk / config.apb1_pre; - let apb1_tim = config.apb1_pre.div_tim(hclk, config.timer_prescaler); + let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler); let apb2 = hclk / config.apb2_pre; - let apb2_tim = config.apb2_pre.div_tim(hclk, config.timer_prescaler); + let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler); let apb3 = hclk / config.apb3_pre; flash_setup(hclk, config.voltage_scale); diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index a6e69461..23e18694 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -6,7 +6,7 @@ use stm32_metapac::rcc::vals::{Mco1, Mco2}; use crate::gpio::sealed::AFType; use crate::gpio::Speed; -use crate::pac::rcc::vals::{Adcsel, Ckpersel, Dppre, Hpre, Hsidiv, Pllsrc, Sw, Timpre}; +use crate::pac::rcc::vals::{Adcsel, Ckpersel, Hpre, Hsidiv, Pllsrc, Ppre, Sw, Timpre}; use crate::pac::{PWR, RCC, SYSCFG}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -631,7 +631,7 @@ pub(crate) unsafe fn init(mut config: Config) { // Core Prescaler / AHB Prescaler / APB3 Prescaler RCC.d1cfgr().modify(|w| { w.set_d1cpre(Hpre::from_bits(d1cpre_bits)); - w.set_d1ppre(Dppre::from_bits(ppre3_bits)); + w.set_d1ppre(Ppre::from_bits(ppre3_bits)); w.set_hpre(hpre_bits) }); // Ensure core prescaler value is valid before future lower @@ -642,12 +642,12 @@ pub(crate) unsafe fn init(mut config: Config) { // APB1 / APB2 Prescaler RCC.d2cfgr().modify(|w| { - w.set_d2ppre1(Dppre::from_bits(ppre1_bits)); - w.set_d2ppre2(Dppre::from_bits(ppre2_bits)); + w.set_d2ppre1(Ppre::from_bits(ppre1_bits)); + w.set_d2ppre2(Ppre::from_bits(ppre2_bits)); }); // APB4 Prescaler - RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits))); + RCC.d3cfgr().modify(|w| w.set_d3ppre(Ppre::from_bits(ppre4_bits))); // Peripheral Clock (per_ck) RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 3c8511ff..2dfd0232 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -145,9 +145,9 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::MSI(MSIRange::default()), - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, #[cfg(crs)] enable_hsi48: false, rtc: None, @@ -247,7 +247,7 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: Hpre = pre.into(); let pre = 1 << (pre.to_bits() as u32 - 7); @@ -256,7 +256,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); @@ -266,7 +266,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs index ed949ea6..90524fb3 100644 --- a/embassy-stm32/src/rcc/l1.rs +++ b/embassy-stm32/src/rcc/l1.rs @@ -138,9 +138,9 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::MSI(MSIRange::default()), - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, } } } @@ -240,7 +240,7 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: Hpre = pre.into(); let pre = 1 << (pre.to_bits() as u32 - 7); @@ -249,7 +249,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); @@ -259,7 +259,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 41dbff01..447a57b2 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -248,9 +248,9 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::MSI(MSIRange::Range6), - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, pllsai1: None, #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] hsi48: false, @@ -576,7 +576,7 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: Hpre = pre.into(); let pre = 1 << (pre.to_bits() as u32 - 7); @@ -585,7 +585,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); @@ -595,7 +595,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index 9e4e0fc7..553b1619 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs @@ -238,9 +238,9 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::MSI(MSIRange::Range6), - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, pllsai1: None, hsi48: false, } @@ -407,7 +407,7 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: Hpre = pre.into(); let pre = 1 << (pre.to_bits() as u32 - 7); @@ -416,7 +416,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); @@ -426,7 +426,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 6540b1f5..ff43c5eb 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -119,46 +119,6 @@ impl Into for PllM { } } -impl Into for AHBPrescaler { - fn into(self) -> u8 { - match self { - AHBPrescaler::NotDivided => 1, - AHBPrescaler::Div2 => 0x08, - AHBPrescaler::Div4 => 0x09, - AHBPrescaler::Div8 => 0x0a, - AHBPrescaler::Div16 => 0x0b, - AHBPrescaler::Div64 => 0x0c, - AHBPrescaler::Div128 => 0x0d, - AHBPrescaler::Div256 => 0x0e, - AHBPrescaler::Div512 => 0x0f, - } - } -} - -impl Default for AHBPrescaler { - fn default() -> Self { - AHBPrescaler::NotDivided - } -} - -impl Default for APBPrescaler { - fn default() -> Self { - APBPrescaler::NotDivided - } -} - -impl Into for APBPrescaler { - fn into(self) -> u8 { - match self { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 0x04, - APBPrescaler::Div4 => 0x05, - APBPrescaler::Div8 => 0x06, - APBPrescaler::Div16 => 0x07, - } - } -} - impl Into for ClockSrc { fn into(self) -> Sw { match self { @@ -239,10 +199,10 @@ impl Default for Config { fn default() -> Self { Self { mux: ClockSrc::MSI(MSIRange::default()), - ahb_pre: Default::default(), - apb1_pre: Default::default(), - apb2_pre: Default::default(), - apb3_pre: Default::default(), + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + apb3_pre: APBPrescaler::DIV1, hsi48: false, } } @@ -395,7 +355,7 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1 << (pre as u32 - 7); @@ -404,7 +364,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); @@ -414,7 +374,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); @@ -424,7 +384,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index f003f6d7..3f4c3742 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -145,11 +145,11 @@ pub const WPAN_DEFAULT: Config = Config { }), pllsai: None, - ahb1_pre: AHBPrescaler::NotDivided, - ahb2_pre: AHBPrescaler::Div2, - ahb3_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb1_pre: AHBPrescaler::DIV1, + ahb2_pre: AHBPrescaler::DIV2, + ahb3_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, }; impl Default for Config { @@ -165,11 +165,11 @@ impl Default for Config { pllsai: None, rtc: None, - ahb1_pre: AHBPrescaler::NotDivided, - ahb2_pre: AHBPrescaler::NotDivided, - ahb3_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb1_pre: AHBPrescaler::DIV1, + ahb2_pre: AHBPrescaler::DIV1, + ahb3_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, } } } @@ -209,7 +209,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { }; let ahb1_clk = match config.ahb1_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1u32 << (pre as u32 - 7); @@ -218,7 +218,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { }; let ahb2_clk = match config.ahb2_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1u32 << (pre as u32 - 7); @@ -227,7 +227,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { }; let ahb3_clk = match config.ahb3_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1u32 << (pre as u32 - 7); @@ -236,7 +236,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { }; let (apb1_clk, apb1_tim_clk) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk), + APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); @@ -246,7 +246,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { }; let (apb2_clk, apb2_tim_clk) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk), + APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 6035f50b..07856a28 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -146,10 +146,10 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::MSI(MSIRange::default()), - ahb_pre: AHBPrescaler::NotDivided, - shd_ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + shd_ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, rtc_mux: RtcClockSource::LSI, adc_clock_source: AdcClockSource::default(), } @@ -172,7 +172,7 @@ pub(crate) unsafe fn init(config: Config) { }; let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1 << (pre as u32 - 7); @@ -181,7 +181,7 @@ pub(crate) unsafe fn init(config: Config) { }; let shd_ahb_freq: u32 = match config.shd_ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1 << (pre as u32 - 7); @@ -190,7 +190,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); @@ -200,7 +200,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); @@ -267,7 +267,7 @@ pub(crate) unsafe fn init(config: Config) { } RCC.extcfgr().modify(|w| { - if config.shd_ahb_pre == AHBPrescaler::NotDivided { + if config.shd_ahb_pre == AHBPrescaler::DIV1 { w.set_shdhpre(0); } else { w.set_shdhpre(config.shd_ahb_pre.into()); @@ -276,11 +276,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.cfgr().modify(|w| { w.set_sw(sw.into()); - if config.ahb_pre == AHBPrescaler::NotDivided { - w.set_hpre(0); - } else { - w.set_hpre(config.ahb_pre.into()); - } + w.set_hpre(config.ahb_pre); w.set_ppre1(config.apb1_pre.into()); w.set_ppre2(config.apb2_pre.into()); }); diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs index 17f09538..89493761 100644 --- a/examples/stm32f2/src/bin/pll.rs +++ b/examples/stm32f2/src/bin/pll.rs @@ -39,9 +39,9 @@ async fn main(_spawner: Spawner) { // System clock comes from PLL (= the 120 MHz main PLL output) config.rcc.mux = ClockSrc::PLL; // 120 MHz / 4 = 30 MHz APB1 frequency - config.rcc.apb1_pre = APBPrescaler::Div4; + config.rcc.apb1_pre = APBPrescaler::DIV4; // 120 MHz / 2 = 60 MHz APB2 frequency - config.rcc.apb2_pre = APBPrescaler::Div2; + config.rcc.apb2_pre = APBPrescaler::DIV2; let _p = embassy_stm32::init(config); diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index c32e0fdb..fdba6cd5 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -48,10 +48,10 @@ async fn main(spawner: Spawner) -> ! { divq: Some(2), divr: None, }); - config.rcc.ahb_pre = AHBPrescaler::NotDivided; - config.rcc.apb1_pre = APBPrescaler::NotDivided; - config.rcc.apb2_pre = APBPrescaler::NotDivided; - config.rcc.apb3_pre = APBPrescaler::NotDivided; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.apb3_pre = APBPrescaler::DIV1; config.rcc.sys = Sysclk::Pll1P; config.rcc.voltage_scale = VoltageScale::Scale0; let p = embassy_stm32::init(config); diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 336eed64..cbe540a0 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -35,10 +35,10 @@ async fn main(_spawner: Spawner) { divq: None, divr: None, }); - config.rcc.ahb_pre = AHBPrescaler::Div2; - config.rcc.apb1_pre = APBPrescaler::Div4; - config.rcc.apb2_pre = APBPrescaler::Div2; - config.rcc.apb3_pre = APBPrescaler::Div4; + config.rcc.ahb_pre = AHBPrescaler::DIV2; + config.rcc.apb1_pre = APBPrescaler::DIV4; + config.rcc.apb2_pre = APBPrescaler::DIV2; + config.rcc.apb3_pre = APBPrescaler::DIV4; config.rcc.sys = Sysclk::Pll1P; config.rcc.voltage_scale = VoltageScale::Scale0; let p = embassy_stm32::init(config); From bbe1d96045a0669a1658617c28c9cbb26ad6e76c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 17 Sep 2023 02:30:50 +0200 Subject: [PATCH 180/233] stm32/rcc: use AHBPrescaler div impls in stm32wba --- embassy-stm32/src/rcc/bus.rs | 4 ++ embassy-stm32/src/rcc/mod.rs | 1 - embassy-stm32/src/rcc/wba.rs | 88 ++++++++++++------------------------ 3 files changed, 33 insertions(+), 60 deletions(-) diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs index fb6dcb01..9c9de548 100644 --- a/embassy-stm32/src/rcc/bus.rs +++ b/embassy-stm32/src/rcc/bus.rs @@ -41,9 +41,13 @@ impl Div for Hertz { AHBPrescaler::DIV16 => 16, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] AHBPrescaler::DIV32 => 32, + #[cfg(not(rcc_wba))] AHBPrescaler::DIV64 => 64, + #[cfg(not(rcc_wba))] AHBPrescaler::DIV128 => 128, + #[cfg(not(rcc_wba))] AHBPrescaler::DIV256 => 256, + #[cfg(not(rcc_wba))] AHBPrescaler::DIV512 => 512, _ => unreachable!(), }; diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index b8c12b99..892dcf93 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,7 +1,6 @@ #![macro_use] pub(crate) mod bd; -#[cfg(not(rcc_wba))] pub mod bus; use core::mem::MaybeUninit; diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 2a11c9a2..c5d7ab62 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -43,36 +43,6 @@ impl Into for ClockSrc { } } -trait Div { - fn div(&self) -> u8; -} - -impl Div for APBPrescaler { - fn div(&self) -> u8 { - match self { - Self::DIV1 => 1, - Self::DIV2 => 2, - Self::DIV4 => 4, - Self::DIV8 => 8, - Self::DIV16 => 16, - _ => unreachable!(), - } - } -} - -impl Div for AHBPrescaler { - fn div(&self) -> u8 { - match self { - Self::DIV1 => 1, - Self::DIV2 => 2, - Self::DIV4 => 4, - Self::DIV8 => 8, - Self::DIV16 => 16, - _ => unreachable!(), - } - } -} - #[derive(Copy, Clone)] pub struct Config { pub mux: ClockSrc, @@ -100,13 +70,13 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - freq.0 + freq } ClockSrc::HSI16 => { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - HSI_FREQ.0 + HSI_FREQ } }; @@ -115,14 +85,14 @@ pub(crate) unsafe fn init(config: Config) { // states and programming delay let wait_states = match power_vos { - VoltageScale::RANGE1 => match sys_clk { + VoltageScale::RANGE1 => match sys_clk.0 { ..=32_000_000 => 0, ..=64_000_000 => 1, ..=96_000_000 => 2, ..=100_000_000 => 3, _ => 4, }, - VoltageScale::RANGE2 => match sys_clk { + VoltageScale::RANGE2 => match sys_clk.0 { ..=8_000_000 => 0, ..=16_000_000 => 1, _ => 2, @@ -147,38 +117,38 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre7(config.apb7_pre.into()); }); - let ahb_freq: u32 = sys_clk / config.ahb_pre.div() as u32; - let (apb1_freq, apb1_tim_freq) = match config.apb1_pre.div() { - 1 => (ahb_freq, ahb_freq), - div => { - let freq = ahb_freq / div as u32; - (freq, freq * 2) + let ahb_freq = sys_clk / config.ahb_pre; + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), + pre => { + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; - let (apb2_freq, apb2_tim_freq) = match config.apb2_pre.div() { - 1 => (ahb_freq, ahb_freq), - div => { - let freq = ahb_freq / div as u32; - (freq, freq * 2) + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), + pre => { + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; - let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre.div() { - 1 => (ahb_freq, ahb_freq), - div => { - let freq = ahb_freq / div as u32; - (freq, freq * 2) + let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre { + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), + pre => { + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; set_freqs(Clocks { - sys: Hertz(sys_clk), - ahb1: Hertz(ahb_freq), - ahb2: Hertz(ahb_freq), - ahb4: Hertz(ahb_freq), - apb1: Hertz(apb1_freq), - apb2: Hertz(apb2_freq), - apb7: Hertz(apb7_freq), - apb1_tim: Hertz(apb1_tim_freq), - apb2_tim: Hertz(apb2_tim_freq), + sys: sys_clk, + ahb1: ahb_freq, + ahb2: ahb_freq, + ahb4: ahb_freq, + apb1: apb1_freq, + apb2: apb2_freq, + apb7: apb7_freq, + apb1_tim: apb1_tim_freq, + apb2_tim: apb2_tim_freq, }); } From 087ef918bf9444b41d1260be5f2b475d3499f640 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sun, 17 Sep 2023 18:04:05 +0100 Subject: [PATCH 181/233] stm32: Add RtcTimeProvider struct to Rtc module This struct allows users to acquire the current time without putting `Rtc` in a mutex and passing that around. This is allowed because reading from the rtc registers is atomic. --- embassy-stm32/src/rtc/mod.rs | 51 +++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 3ecf477d..a588c8b1 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -82,12 +82,42 @@ impl core::ops::Sub for RtcInstant { } } +#[non_exhaustive] +pub struct RtcTimeProvider; + +impl RtcTimeProvider { + /// Return the current datetime. + /// + /// # Errors + /// + /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. + pub fn now(&self) -> Result { + let r = RTC::regs(); + let tr = r.tr().read(); + let second = bcd2_to_byte((tr.st(), tr.su())); + let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); + let hour = bcd2_to_byte((tr.ht(), tr.hu())); + // Reading either RTC_SSR or RTC_TR locks the values in the higher-order + // calendar shadow registers until RTC_DR is read. + let dr = r.dr().read(); + + let weekday = dr.wdu(); + let day = bcd2_to_byte((dr.dt(), dr.du())); + let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); + let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; + + self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) + } +} + +#[non_exhaustive] /// RTC Abstraction pub struct Rtc { #[cfg(feature = "low-power")] stop_time: Mutex>>, } +#[non_exhaustive] #[derive(Copy, Clone, PartialEq)] pub struct RtcConfig { /// The subsecond counter frequency; default is 256 @@ -155,6 +185,11 @@ impl Rtc { Hertz(32_768) } + /// Acquire a [`RtcTimeProvider`] instance. + pub fn time_provider(&self) -> RtcTimeProvider { + RtcTimeProvider + } + /// Set the datetime to a new value. /// /// # Errors @@ -187,21 +222,7 @@ impl Rtc { /// /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. pub fn now(&self) -> Result { - let r = RTC::regs(); - let tr = r.tr().read(); - let second = bcd2_to_byte((tr.st(), tr.su())); - let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); - let hour = bcd2_to_byte((tr.ht(), tr.hu())); - // Reading either RTC_SSR or RTC_TR locks the values in the higher-order - // calendar shadow registers until RTC_DR is read. - let dr = r.dr().read(); - - let weekday = dr.wdu(); - let day = bcd2_to_byte((dr.dt(), dr.du())); - let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); - let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; - - self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) + RtcTimeProvider.now() } /// Check if daylight savings time is active. From 88eb5cca71a470cca93001943e962b63e15168af Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sat, 16 Sep 2023 22:32:14 +0100 Subject: [PATCH 182/233] stm32: Implement `set_config` for Uart structs --- embassy-stm32/src/spi/mod.rs | 4 +- embassy-stm32/src/usart/buffered.rs | 36 ++++++++++++++++++ embassy-stm32/src/usart/mod.rs | 49 +++++++++++++++++++++++++ embassy-stm32/src/usart/ringbuffered.rs | 16 +++++++- 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 853de98f..f40bce78 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -323,7 +323,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { } /// Reconfigures it with the supplied config. - pub fn reconfigure(&mut self, config: Config) { + pub fn set_config(&mut self, config: Config) { let cpha = config.raw_phase(); let cpol = config.raw_polarity(); @@ -1062,6 +1062,6 @@ foreach_peripheral!( impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.reconfigure(*config); + self.set_config(*config); } } diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index b88eebc7..323d8381 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -114,6 +114,30 @@ pub struct BufferedUartRx<'d, T: BasicInstance> { phantom: PhantomData<&'d mut T>, } +impl<'d, T: BasicInstance> SetConfig for BufferedUart<'d, T> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config) + } +} + +impl<'d, T: BasicInstance> SetConfig for BufferedUartRx<'d, T> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config) + } +} + +impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config) + } +} + impl<'d, T: BasicInstance> BufferedUart<'d, T> { pub fn new( peri: impl Peripheral

+ 'd, @@ -228,6 +252,10 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { (self.tx, self.rx) } + + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } } impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { @@ -304,6 +332,10 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { T::Interrupt::pend(); } } + + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } } impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { @@ -374,6 +406,10 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { } } } + + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } } impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> { diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index c6d6cc59..ff02d0a6 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -5,6 +5,7 @@ use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; +use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use futures::future::{select, Either}; @@ -168,11 +169,28 @@ pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { rx: UartRx<'d, T, RxDma>, } +impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.tx.set_config(config); + self.rx.set_config(config); + } +} + pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { phantom: PhantomData<&'d mut T>, tx_dma: PeripheralRef<'d, TxDma>, } +impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config); + } +} + pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { _peri: PeripheralRef<'d, T>, rx_dma: PeripheralRef<'d, RxDma>, @@ -181,6 +199,14 @@ pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { buffered_sr: stm32_metapac::usart::regs::Sr, } +impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config); + } +} + impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. pub fn new( @@ -237,6 +263,10 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { } } + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> where TxDma: crate::usart::TxDma, @@ -334,6 +364,10 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { } } + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } + #[cfg(any(usart_v1, usart_v2))] fn check_rx_flags(&mut self) -> Result { let r = T::regs(); @@ -759,6 +793,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> where TxDma: crate::usart::TxDma, @@ -804,6 +842,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } +fn reconfigure(config: &Config) { + T::Interrupt::disable(); + let r = T::regs(); + + let cr = r.cr1().read(); + configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te()); + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; +} + fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) { if !enable_rx && !enable_tx { panic!("USART: At least one of RX or TX should be enabled"); diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index e990eaca..eed5ef5d 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -3,10 +3,11 @@ use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; +use embassy_embedded_hal::SetConfig; use embassy_hal_internal::PeripheralRef; use futures::future::{select, Either}; -use super::{clear_interrupt_flags, rdr, sr, BasicInstance, Error, UartRx}; +use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, Error, UartRx}; use crate::dma::ReadableRingBuffer; use crate::usart::{Regs, Sr}; @@ -15,6 +16,14 @@ pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma> { ring_buf: ReadableRingBuffer<'d, RxDma, u8>, } +impl<'d, T: BasicInstance, RxDma: super::RxDma> SetConfig for RingBufferedUartRx<'d, T, RxDma> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config); + } +} + impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { /// Turn the `UartRx` into a buffered uart which can continously receive in the background /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the @@ -54,6 +63,11 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD Err(err) } + pub fn set_config(&mut self, config: &Config) { + self.teardown_uart(); + reconfigure::(config) + } + /// Start uart background receive fn setup_uart(&mut self) { // fence before starting DMA. From a6ef314be150fd2e8adbfefe5f2b38126f97551a Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 17 Sep 2023 18:41:45 -0500 Subject: [PATCH 183/233] stm32: update configure_ls as agreed --- embassy-stm32/src/rcc/bd.rs | 58 +++++++++++++++++++----------------- embassy-stm32/src/rcc/f2.rs | 12 ++++++-- embassy-stm32/src/rcc/f4.rs | 11 +++++-- embassy-stm32/src/rcc/l0.rs | 12 ++++++-- embassy-stm32/src/rcc/l4.rs | 6 +++- embassy-stm32/src/rcc/mod.rs | 10 +++++++ embassy-stm32/src/rcc/wb.rs | 11 +++++-- embassy-stm32/src/rcc/wl.rs | 6 +++- 8 files changed, 84 insertions(+), 42 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index d774b993..762e8435 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -1,5 +1,5 @@ #[allow(dead_code)] -#[derive(Default)] +#[derive(Default, Clone, Copy)] pub enum LseDrive { #[cfg(any(rtc_v2f7, rtc_v2l4))] Low = 0, @@ -87,40 +87,42 @@ impl BackupDomain { rtc_v3u5 ))] #[allow(dead_code, unused_variables)] - pub fn configure_ls(clock_source: RtcClockSource, lse_drive: Option) { - match clock_source { - RtcClockSource::LSI => { - #[cfg(rtc_v3u5)] - let csr = crate::pac::RCC.bdcr(); + pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option) { + if lsi { + #[cfg(rtc_v3u5)] + let csr = crate::pac::RCC.bdcr(); - #[cfg(not(rtc_v3u5))] - let csr = crate::pac::RCC.csr(); - - Self::modify(|_| { - #[cfg(not(any(rcc_wb, rcc_wba)))] - csr.modify(|w| w.set_lsion(true)); - - #[cfg(any(rcc_wb, rcc_wba))] - csr.modify(|w| w.set_lsi1on(true)); - }); + #[cfg(not(rtc_v3u5))] + let csr = crate::pac::RCC.csr(); + Self::modify(|_| { #[cfg(not(any(rcc_wb, rcc_wba)))] - while !csr.read().lsirdy() {} + csr.modify(|w| w.set_lsion(true)); #[cfg(any(rcc_wb, rcc_wba))] - while !csr.read().lsi1rdy() {} - } - RtcClockSource::LSE => { - let lse_drive = lse_drive.unwrap_or_default(); + csr.modify(|w| w.set_lsi1on(true)); + }); - Self::modify(|w| { - #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] - w.set_lsedrv(lse_drive.into()); - w.set_lseon(true); - }); + #[cfg(not(any(rcc_wb, rcc_wba)))] + while !csr.read().lsirdy() {} - while !Self::read().lserdy() {} - } + #[cfg(any(rcc_wb, rcc_wba))] + while !csr.read().lsi1rdy() {} + } + + if let Some(lse_drive) = lse { + Self::modify(|w| { + #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] + w.set_lsedrv(lse_drive.into()); + w.set_lseon(true); + }); + + while !Self::read().lserdy() {} + } + + match clock_source { + RtcClockSource::LSI => assert!(lsi), + RtcClockSource::LSE => assert!(&lse.is_some()), _ => {} }; diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index da88e44d..56ccdcbd 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -291,6 +291,8 @@ pub struct Config { pub pll: PLLConfig, pub mux: ClockSrc, pub rtc: Option, + pub lsi: bool, + pub lse: Option, pub voltage: VoltageScale, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, @@ -308,6 +310,8 @@ impl Default for Config { voltage: VoltageScale::Scale3, mux: ClockSrc::HSI, rtc: None, + lsi: false, + lse: None, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, @@ -421,9 +425,11 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr().modify(|w| w.set_pwren(true)); PWR.cr().read(); - config - .rtc - .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); + BackupDomain::configure_ls( + config.rtc.unwrap_or(RtcClockSource::NOCLOCK), + config.lsi, + config.lse.map(|_| Default::default()), + ); set_freqs(Clocks { sys: sys_clk, diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index f7bc0d99..d8d0312b 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -35,6 +35,8 @@ pub struct Config { pub pll48: bool, pub rtc: Option, + pub lsi: bool, + pub lse: Option, } #[cfg(stm32f410)] @@ -461,12 +463,15 @@ pub(crate) unsafe fn init(config: Config) { }) }); - config - .rtc - .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); + BackupDomain::configure_ls( + config.rtc.unwrap_or(RtcClockSource::NOCLOCK), + config.lsi, + config.lse.map(|_| Default::default()), + ); let rtc = match config.rtc { Some(RtcClockSource::LSI) => Some(LSI_FREQ), + Some(RtcClockSource::LSE) => Some(config.lse.unwrap()), _ => None, }; diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 2dfd0232..1c655592 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -138,6 +138,8 @@ pub struct Config { #[cfg(crs)] pub enable_hsi48: bool, pub rtc: Option, + pub lse: Option, + pub lsi: bool, } impl Default for Config { @@ -151,6 +153,8 @@ impl Default for Config { #[cfg(crs)] enable_hsi48: false, rtc: None, + lse: None, + lsi: false, } } } @@ -235,9 +239,11 @@ pub(crate) unsafe fn init(config: Config) { } }; - config.rtc.map(|rtc| { - BackupDomain::configure_ls(rtc, None); - }); + BackupDomain::configure_ls( + config.rtc.unwrap_or(RtcClockSource::NOCLOCK), + config.lsi, + config.lse.map(|_| Default::default()), + ); RCC.cfgr().modify(|w| { w.set_sw(sw); diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 447a57b2..f7b9354a 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -241,6 +241,8 @@ pub struct Config { #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] pub hsi48: bool, pub rtc_mux: RtcClockSource, + pub lse: Option, + pub lsi: bool, } impl Default for Config { @@ -255,6 +257,8 @@ impl Default for Config { #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] hsi48: false, rtc_mux: RtcClockSource::LSI, + lsi: true, + lse: None, } } } @@ -407,7 +411,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr1().modify(|w| w.set_pwren(true)); - BackupDomain::configure_ls(config.rtc_mux, None); + BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); let (sys_clk, sw) = match config.mux { ClockSrc::MSI(range) => { diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 892dcf93..ff9b9bac 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -31,6 +31,16 @@ pub use _version::*; #[cfg(feature = "low-power")] use atomic_polyfill::{AtomicU32, Ordering}; +// Model Clock Configuration +// +// pub struct Clocks { +// hse: Option, +// hsi: bool, +// lse: Option, +// lsi: bool, +// rtc: RtcSource, +// } + #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Clocks { diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index 3f4c3742..ee45a342 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -108,6 +108,7 @@ pub struct Pll { pub struct Config { pub hse: Option, pub lse: Option, + pub lsi: bool, pub sys: Sysclk, pub mux: Option, pub pll48: Option, @@ -136,6 +137,7 @@ pub const WPAN_DEFAULT: Config = Config { }), pll48: None, rtc: Some(RtcClockSource::LSE), + lsi: false, pll: Some(Pll { mul: 12, @@ -164,6 +166,7 @@ impl Default for Config { pll: None, pllsai: None, rtc: None, + lsi: false, ahb1_pre: AHBPrescaler::DIV1, ahb2_pre: AHBPrescaler::DIV1, @@ -294,9 +297,11 @@ pub(crate) fn configure_clocks(config: &Config) { rcc.cfgr().modify(|w| w.set_stopwuck(true)); - config - .rtc - .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); + BackupDomain::configure_ls( + config.rtc.unwrap_or(RtcClockSource::NOCLOCK), + config.lsi, + config.lse.map(|_| Default::default()), + ); match &config.hse { Some(hse) => { diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 07856a28..5db942fc 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -138,6 +138,8 @@ pub struct Config { pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, pub rtc_mux: RtcClockSource, + pub lse: Option, + pub lsi: bool, pub adc_clock_source: AdcClockSource, } @@ -151,6 +153,8 @@ impl Default for Config { apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, rtc_mux: RtcClockSource::LSI, + lsi: true, + lse: None, adc_clock_source: AdcClockSource::default(), } } @@ -231,7 +235,7 @@ pub(crate) unsafe fn init(config: Config) { while FLASH.acr().read().latency() != ws {} // Enables the LSI if configured - BackupDomain::configure_ls(config.rtc_mux, None); + BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); match config.mux { ClockSrc::HSI16 => { From feaeee1e835bf3e2a6b36fc8d2d45d4cbc5c27a3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 17 Sep 2023 18:47:22 -0500 Subject: [PATCH 184/233] stm32: misc. cleanup --- embassy-stm32-wpan/src/sub/ble.rs | 5 ++--- embassy-stm32-wpan/src/sub/mac.rs | 5 ++--- embassy-stm32-wpan/src/sub/mm.rs | 5 ++--- embassy-stm32-wpan/src/sub/sys.rs | 5 ++--- embassy-stm32/src/rtc/mod.rs | 11 ++++++----- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs index cd32692e..c5f2334f 100644 --- a/embassy-stm32-wpan/src/sub/ble.rs +++ b/embassy-stm32-wpan/src/sub/ble.rs @@ -1,4 +1,3 @@ -use core::marker::PhantomData; use core::ptr; use embassy_stm32::ipcc::Ipcc; @@ -13,7 +12,7 @@ use crate::unsafe_linked_list::LinkedListNode; use crate::{channels, evt}; pub struct Ble { - phantom: PhantomData, + _private: (), } impl Ble { @@ -29,7 +28,7 @@ impl Ble { }); } - Self { phantom: PhantomData } + Self { _private: () } } /// `HW_IPCC_BLE_EvtNot` pub async fn tl_read(&self) -> EvtBox { diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs index b0cf0248..baf4da97 100644 --- a/embassy-stm32-wpan/src/sub/mac.rs +++ b/embassy-stm32-wpan/src/sub/mac.rs @@ -1,5 +1,4 @@ use core::future::poll_fn; -use core::marker::PhantomData; use core::ptr; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; @@ -21,12 +20,12 @@ static MAC_WAKER: AtomicWaker = AtomicWaker::new(); static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); pub struct Mac { - phantom: PhantomData, + _private: (), } impl Mac { pub(crate) fn new() -> Self { - Self { phantom: PhantomData } + Self { _private: () } } /// `HW_IPCC_MAC_802_15_4_EvtNot` diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs index da05ad1d..4e4d2f85 100644 --- a/embassy-stm32-wpan/src/sub/mm.rs +++ b/embassy-stm32-wpan/src/sub/mm.rs @@ -1,6 +1,5 @@ //! Memory manager routines use core::future::poll_fn; -use core::marker::PhantomData; use core::mem::MaybeUninit; use core::task::Poll; @@ -21,7 +20,7 @@ static MM_WAKER: AtomicWaker = AtomicWaker::new(); static mut LOCAL_FREE_BUF_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); pub struct MemoryManager { - phantom: PhantomData, + _private: (), } impl MemoryManager { @@ -44,7 +43,7 @@ impl MemoryManager { }); } - Self { phantom: PhantomData } + Self { _private: () } } pub async fn run_queue(&self) { diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs index c17fd531..bd2ea3f7 100644 --- a/embassy-stm32-wpan/src/sub/sys.rs +++ b/embassy-stm32-wpan/src/sub/sys.rs @@ -1,4 +1,3 @@ -use core::marker::PhantomData; use core::ptr; use crate::cmd::CmdPacket; @@ -12,7 +11,7 @@ use crate::unsafe_linked_list::LinkedListNode; use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; pub struct Sys { - phantom: PhantomData, + _private: (), } impl Sys { @@ -27,7 +26,7 @@ impl Sys { }); } - Self { phantom: PhantomData } + Self { _private: () } } /// Returns CPU2 wireless firmware information (if present). diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index a588c8b1..07b4fe1f 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -82,8 +82,9 @@ impl core::ops::Sub for RtcInstant { } } -#[non_exhaustive] -pub struct RtcTimeProvider; +pub struct RtcTimeProvider { + _private: (), +} impl RtcTimeProvider { /// Return the current datetime. @@ -186,8 +187,8 @@ impl Rtc { } /// Acquire a [`RtcTimeProvider`] instance. - pub fn time_provider(&self) -> RtcTimeProvider { - RtcTimeProvider + pub const fn time_provider(&self) -> RtcTimeProvider { + RtcTimeProvider { _private: () } } /// Set the datetime to a new value. @@ -222,7 +223,7 @@ impl Rtc { /// /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. pub fn now(&self) -> Result { - RtcTimeProvider.now() + self.time_provider().now() } /// Check if daylight savings time is active. From 0dcb34fc7d6134ff8d8c4795209d2feb217920dc Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 17 Sep 2023 19:03:45 -0500 Subject: [PATCH 185/233] ci: fix tests --- tests/stm32/src/bin/rtc.rs | 4 +++- tests/stm32/src/bin/stop.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs index 1a64dd38..22be6fac 100644 --- a/tests/stm32/src/bin/rtc.rs +++ b/tests/stm32/src/bin/rtc.rs @@ -12,13 +12,15 @@ use defmt::assert; use embassy_executor::Spawner; use embassy_stm32::rcc::RtcClockSource; use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_stm32::time::Hertz; use embassy_time::{Duration, Timer}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = config(); - config.rcc.rtc = Some(RtcClockSource::LSI); + config.rcc.lse = Some(Hertz(32_768)); + config.rcc.rtc = Some(RtcClockSource::LSE); let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index a490d7b8..f60ab271 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -13,6 +13,7 @@ use embassy_executor::Spawner; use embassy_stm32::low_power::{stop_with_rtc, Executor}; use embassy_stm32::rcc::RtcClockSource; use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_stm32::time::Hertz; use embassy_time::{Duration, Timer}; use static_cell::make_static; @@ -28,7 +29,8 @@ fn main() -> ! { async fn async_main(_spawner: Spawner) { let mut config = config(); - config.rcc.rtc = Some(RtcClockSource::LSI); + config.rcc.lse = Some(Hertz(32_768)); + config.rcc.rtc = Some(RtcClockSource::LSE); let p = embassy_stm32::init(config); info!("Hello World!"); From 4bfbcd6c72fadd97ef71403a1406ff437f4aa6e8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 18 Sep 2023 03:00:59 +0200 Subject: [PATCH 186/233] stm32: use PAC enums for VOS. --- ci.sh | 2 + embassy-lora/src/iv.rs | 14 ++-- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/rcc/bus.rs | 16 ----- embassy-stm32/src/rcc/f2.rs | 25 +++++-- embassy-stm32/src/rcc/h5.rs | 64 ++++++++--------- embassy-stm32/src/rcc/h7.rs | 97 ++++++++++++++++++++------ embassy-stm32/src/rcc/u5.rs | 20 +++--- embassy-stm32/src/rcc/wl.rs | 16 +++-- examples/stm32h5/src/bin/eth.rs | 2 +- examples/stm32h5/src/bin/usb_serial.rs | 2 +- 11 files changed, 156 insertions(+), 106 deletions(-) diff --git a/ci.sh b/ci.sh index 87f47487..37d3e778 100755 --- a/ci.sh +++ b/ci.sh @@ -85,6 +85,8 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h753zi,defmt,exti,time-driver-any,unstable-traits \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \ diff --git a/embassy-lora/src/iv.rs b/embassy-lora/src/iv.rs index de6a1834..d22beb33 100644 --- a/embassy-lora/src/iv.rs +++ b/embassy-lora/src/iv.rs @@ -67,24 +67,20 @@ where self.board_type = board_type; } async fn set_nss_low(&mut self) -> Result<(), RadioError> { - let pwr = pac::PWR; - pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW)); + pac::PWR.subghzspicr().modify(|w| w.set_nss(false)); Ok(()) } async fn set_nss_high(&mut self) -> Result<(), RadioError> { - let pwr = pac::PWR; - pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH)); + pac::PWR.subghzspicr().modify(|w| w.set_nss(true)); Ok(()) } async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> { - let rcc = pac::RCC; - rcc.csr().modify(|w| w.set_rfrst(true)); - rcc.csr().modify(|w| w.set_rfrst(false)); + pac::RCC.csr().modify(|w| w.set_rfrst(true)); + pac::RCC.csr().modify(|w| w.set_rfrst(false)); Ok(()) } async fn wait_on_busy(&mut self) -> Result<(), RadioError> { - let pwr = pac::PWR; - while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {} + while pac::PWR.sr2().read().rfbusys() {} Ok(()) } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 0cae981c..1a024e9a 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -59,7 +59,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-907dd82c848bc912252c61509944e85c2a48c919" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2dba1f1ddee697e616aff2a4db57a6ffaf1b29b7" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-907dd82c848bc912252c61509944e85c2a48c919", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2dba1f1ddee697e616aff2a4db57a6ffaf1b29b7", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs index 9c9de548..495cf7fe 100644 --- a/embassy-stm32/src/rcc/bus.rs +++ b/embassy-stm32/src/rcc/bus.rs @@ -5,22 +5,6 @@ use crate::pac::rcc; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; use crate::time::Hertz; -/// Voltage Scale -/// -/// Represents the voltage range feeding the CPU core. The maximum core -/// clock frequency depends on this value. -/// -/// Scale0 represents the highest voltage range -#[derive(Copy, Clone, PartialEq)] -pub enum VoltageScale { - Scale0, - Scale1, - #[cfg(not(any(rcc_wl5, rcc_wle)))] - Scale2, - #[cfg(not(any(rcc_wl5, rcc_wle)))] - Scale3, -} - impl Div for Hertz { type Output = Hertz; diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index 56ccdcbd..af90a9c3 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -203,7 +203,20 @@ pub struct PLLClocks { pub pll48_freq: Hertz, } -pub use super::bus::VoltageScale; +/// Voltage range of the power supply used. +/// +/// Used to calculate flash waitstates. See +/// RM0033 - Table 3. Number of wait states according to CortexĀ®-M3 clock frequency +pub enum VoltageScale { + /// 2.7v to 4.6v + Range0, + /// 2.4v to 2.7v + Range1, + /// 2.1v to 2.4v + Range2, + /// 1.8v to 2.1v + Range3, +} impl VoltageScale { const fn wait_states(&self, ahb_freq: Hertz) -> Option { @@ -211,7 +224,7 @@ impl VoltageScale { // Reference: RM0033 - Table 3. Number of wait states according to CortexĀ®-M3 clock // frequency match self { - VoltageScale::Scale3 => { + VoltageScale::Range3 => { if ahb_freq <= 16_000_000 { Some(Latency::WS0) } else if ahb_freq <= 32_000_000 { @@ -232,7 +245,7 @@ impl VoltageScale { None } } - VoltageScale::Scale2 => { + VoltageScale::Range2 => { if ahb_freq <= 18_000_000 { Some(Latency::WS0) } else if ahb_freq <= 36_000_000 { @@ -251,7 +264,7 @@ impl VoltageScale { None } } - VoltageScale::Scale1 => { + VoltageScale::Range1 => { if ahb_freq <= 24_000_000 { Some(Latency::WS0) } else if ahb_freq <= 48_000_000 { @@ -266,7 +279,7 @@ impl VoltageScale { None } } - VoltageScale::Scale0 => { + VoltageScale::Range0 => { if ahb_freq <= 30_000_000 { Some(Latency::WS0) } else if ahb_freq <= 60_000_000 { @@ -307,7 +320,7 @@ impl Default for Config { hsi: true, pll_mux: PLLSrc::HSI, pll: PLLConfig::default(), - voltage: VoltageScale::Scale3, + voltage: VoltageScale::Range3, mux: ClockSrc::HSI, rtc: None, lsi: false, diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs index ac45605f..15f28c5d 100644 --- a/embassy-stm32/src/rcc/h5.rs +++ b/embassy-stm32/src/rcc/h5.rs @@ -2,7 +2,6 @@ use core::marker::PhantomData; use stm32_metapac::rcc::vals::Timpre; -use crate::pac::pwr::vals::Vos; use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw}; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; @@ -26,7 +25,8 @@ const VCO_MAX: u32 = 420_000_000; const VCO_WIDE_MIN: u32 = 128_000_000; const VCO_WIDE_MAX: u32 = 560_000_000; -pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; +pub use crate::pac::pwr::vals::Vos as VoltageScale; pub enum HseMode { /// crystal/ceramic oscillator (HSEBYP=0) @@ -171,7 +171,7 @@ impl Default for Config { apb3_pre: APBPrescaler::DIV1, timer_prescaler: TimerPrescaler::DefaultX2, - voltage_scale: VoltageScale::Scale3, + voltage_scale: VoltageScale::SCALE3, } } } @@ -222,15 +222,15 @@ impl<'d, T: McoInstance> Mco<'d, T> { } pub(crate) unsafe fn init(config: Config) { - let (vos, max_clk) = match config.voltage_scale { - VoltageScale::Scale0 => (Vos::SCALE0, Hertz(250_000_000)), - VoltageScale::Scale1 => (Vos::SCALE1, Hertz(200_000_000)), - VoltageScale::Scale2 => (Vos::SCALE2, Hertz(150_000_000)), - VoltageScale::Scale3 => (Vos::SCALE3, Hertz(100_000_000)), + let max_clk = match config.voltage_scale { + VoltageScale::SCALE0 => Hertz(250_000_000), + VoltageScale::SCALE1 => Hertz(200_000_000), + VoltageScale::SCALE2 => Hertz(150_000_000), + VoltageScale::SCALE3 => Hertz(100_000_000), }; // Configure voltage scale. - PWR.voscr().modify(|w| w.set_vos(vos)); + PWR.voscr().modify(|w| w.set_vos(config.voltage_scale)); while !PWR.vossr().read().vosrdy() {} // Configure HSI @@ -472,36 +472,36 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) { // See RM0433 Rev 7 Table 17. FLASH recommended number of wait // states and programming delay let (latency, wrhighfreq) = match (vos, clk.0) { - (VoltageScale::Scale0, ..=42_000_000) => (0, 0), - (VoltageScale::Scale0, ..=84_000_000) => (1, 0), - (VoltageScale::Scale0, ..=126_000_000) => (2, 1), - (VoltageScale::Scale0, ..=168_000_000) => (3, 1), - (VoltageScale::Scale0, ..=210_000_000) => (4, 2), - (VoltageScale::Scale0, ..=250_000_000) => (5, 2), + (VoltageScale::SCALE0, ..=42_000_000) => (0, 0), + (VoltageScale::SCALE0, ..=84_000_000) => (1, 0), + (VoltageScale::SCALE0, ..=126_000_000) => (2, 1), + (VoltageScale::SCALE0, ..=168_000_000) => (3, 1), + (VoltageScale::SCALE0, ..=210_000_000) => (4, 2), + (VoltageScale::SCALE0, ..=250_000_000) => (5, 2), - (VoltageScale::Scale1, ..=34_000_000) => (0, 0), - (VoltageScale::Scale1, ..=68_000_000) => (1, 0), - (VoltageScale::Scale1, ..=102_000_000) => (2, 1), - (VoltageScale::Scale1, ..=136_000_000) => (3, 1), - (VoltageScale::Scale1, ..=170_000_000) => (4, 2), - (VoltageScale::Scale1, ..=200_000_000) => (5, 2), + (VoltageScale::SCALE1, ..=34_000_000) => (0, 0), + (VoltageScale::SCALE1, ..=68_000_000) => (1, 0), + (VoltageScale::SCALE1, ..=102_000_000) => (2, 1), + (VoltageScale::SCALE1, ..=136_000_000) => (3, 1), + (VoltageScale::SCALE1, ..=170_000_000) => (4, 2), + (VoltageScale::SCALE1, ..=200_000_000) => (5, 2), - (VoltageScale::Scale2, ..=30_000_000) => (0, 0), - (VoltageScale::Scale2, ..=60_000_000) => (1, 0), - (VoltageScale::Scale2, ..=90_000_000) => (2, 1), - (VoltageScale::Scale2, ..=120_000_000) => (3, 1), - (VoltageScale::Scale2, ..=150_000_000) => (4, 2), + (VoltageScale::SCALE2, ..=30_000_000) => (0, 0), + (VoltageScale::SCALE2, ..=60_000_000) => (1, 0), + (VoltageScale::SCALE2, ..=90_000_000) => (2, 1), + (VoltageScale::SCALE2, ..=120_000_000) => (3, 1), + (VoltageScale::SCALE2, ..=150_000_000) => (4, 2), - (VoltageScale::Scale3, ..=20_000_000) => (0, 0), - (VoltageScale::Scale3, ..=40_000_000) => (1, 0), - (VoltageScale::Scale3, ..=60_000_000) => (2, 1), - (VoltageScale::Scale3, ..=80_000_000) => (3, 1), - (VoltageScale::Scale3, ..=100_000_000) => (4, 2), + (VoltageScale::SCALE3, ..=20_000_000) => (0, 0), + (VoltageScale::SCALE3, ..=40_000_000) => (1, 0), + (VoltageScale::SCALE3, ..=60_000_000) => (2, 1), + (VoltageScale::SCALE3, ..=80_000_000) => (3, 1), + (VoltageScale::SCALE3, ..=100_000_000) => (4, 2), _ => unreachable!(), }; - defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); + debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); FLASH.acr().write(|w| { w.set_wrhighfreq(wrhighfreq); diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index 23e18694..585e1faa 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -1,9 +1,10 @@ use core::marker::PhantomData; use embassy_hal_internal::into_ref; -pub use pll::PllConfig; +use stm32_metapac::pwr::vals::Vos; use stm32_metapac::rcc::vals::{Mco1, Mco2}; +pub use self::pll::PllConfig; use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Adcsel, Ckpersel, Hpre, Hsidiv, Pllsrc, Ppre, Sw, Timpre}; @@ -24,7 +25,13 @@ pub const HSI48_FREQ: Hertz = Hertz(48_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(32_000); -pub use super::bus::VoltageScale; +#[derive(Clone, Copy)] +pub enum VoltageScale { + Scale0, + Scale1, + Scale2, + Scale3, +} #[derive(Clone, Copy)] pub enum AdcClockSource { @@ -85,7 +92,6 @@ pub struct CoreClocks { /// Configuration of the core clocks #[non_exhaustive] -#[derive(Default)] pub struct Config { pub hse: Option, pub bypass_hse: bool, @@ -100,6 +106,28 @@ pub struct Config { pub pll2: PllConfig, pub pll3: PllConfig, pub adc_clock_source: AdcClockSource, + pub voltage_scale: VoltageScale, +} + +impl Default for Config { + fn default() -> Self { + Self { + hse: None, + bypass_hse: false, + sys_ck: None, + per_ck: None, + hclk: None, + pclk1: None, + pclk2: None, + pclk3: None, + pclk4: None, + pll1: Default::default(), + pll2: Default::default(), + pll3: Default::default(), + adc_clock_source: Default::default(), + voltage_scale: VoltageScale::Scale1, + } + } } /// Setup traceclk @@ -431,9 +459,6 @@ impl<'d, T: McoInstance> Mco<'d, T> { } pub(crate) unsafe fn init(mut config: Config) { - // TODO make configurable? - let enable_overdrive = false; - // NB. The lower bytes of CR3 can only be written once after // POR, and must be written with a valid combination. Refer to // RM0433 Rev 7 6.8.4. This is partially enforced by dropping @@ -461,21 +486,49 @@ pub(crate) unsafe fn init(mut config: Config) { // 1.0V. while !PWR.csr1().read().actvosrdy() {} - // Go to Scale 1 - PWR.d3cr().modify(|w| w.set_vos(0b11)); - while !PWR.d3cr().read().vosrdy() {} - - let pwr_vos = if !enable_overdrive { - VoltageScale::Scale1 - } else { - critical_section::with(|_| { - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - - SYSCFG.pwrcr().modify(|w| w.set_oden(1)); + #[cfg(syscfg_h7)] + { + // in chips without the overdrive bit, we can go from any scale to any scale directly. + PWR.d3cr().modify(|w| { + w.set_vos(match config.voltage_scale { + VoltageScale::Scale0 => Vos::SCALE0, + VoltageScale::Scale1 => Vos::SCALE1, + VoltageScale::Scale2 => Vos::SCALE2, + VoltageScale::Scale3 => Vos::SCALE3, + }) }); while !PWR.d3cr().read().vosrdy() {} - VoltageScale::Scale0 - }; + } + + #[cfg(syscfg_h7od)] + { + match config.voltage_scale { + VoltageScale::Scale0 => { + // to go to scale0, we must go to Scale1 first... + PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1)); + while !PWR.d3cr().read().vosrdy() {} + + // Then enable overdrive. + critical_section::with(|_| { + RCC.apb4enr().modify(|w| w.set_syscfgen(true)); + SYSCFG.pwrcr().modify(|w| w.set_oden(1)); + }); + while !PWR.d3cr().read().vosrdy() {} + } + _ => { + // for all other scales, we can go directly. + PWR.d3cr().modify(|w| { + w.set_vos(match config.voltage_scale { + VoltageScale::Scale0 => unreachable!(), + VoltageScale::Scale1 => Vos::SCALE1, + VoltageScale::Scale2 => Vos::SCALE2, + VoltageScale::Scale3 => Vos::SCALE3, + }) + }); + while !PWR.d3cr().read().vosrdy() {} + } + } + } // Freeze the core clocks, returning a Core Clocks Distribution // and Reset (CCDR) structure. The actual frequency of the clocks @@ -538,11 +591,11 @@ pub(crate) unsafe fn init(mut config: Config) { // Refer to part datasheet "General operating conditions" // table for (rev V). We do not assert checks for earlier // revisions which may have lower limits. - let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos { + let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match config.voltage_scale { VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), - _ => (200_000_000, 100_000_000, 50_000_000), + VoltageScale::Scale3 => (200_000_000, 100_000_000, 50_000_000), }; assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max); @@ -638,7 +691,7 @@ pub(crate) unsafe fn init(mut config: Config) { // core voltage while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {} - flash_setup(rcc_aclk, pwr_vos); + flash_setup(rcc_aclk, config.voltage_scale); // APB1 / APB2 Prescaler RCC.d2cfgr().modify(|w| { diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index ff43c5eb..d9a53128 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -11,7 +11,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(32_000); -pub use super::bus::VoltageScale; +pub use crate::pac::pwr::vals::Vos as VoltageScale; #[derive(Copy, Clone)] pub enum ClockSrc { @@ -286,12 +286,12 @@ pub(crate) unsafe fn init(config: Config) { } // TODO make configurable - let power_vos = VoltageScale::Scale3; + let power_vos = VoltageScale::RANGE3; // states and programming delay let wait_states = match power_vos { - // VOS 0 range VCORE 1.26V - 1.40V - VoltageScale::Scale0 => { + // VOS 1 range VCORE 1.26V - 1.40V + VoltageScale::RANGE1 => { if sys_clk < 32_000_000 { 0 } else if sys_clk < 64_000_000 { @@ -304,8 +304,8 @@ pub(crate) unsafe fn init(config: Config) { 4 } } - // VOS 1 range VCORE 1.15V - 1.26V - VoltageScale::Scale1 => { + // VOS 2 range VCORE 1.15V - 1.26V + VoltageScale::RANGE2 => { if sys_clk < 30_000_000 { 0 } else if sys_clk < 60_000_000 { @@ -316,8 +316,8 @@ pub(crate) unsafe fn init(config: Config) { 3 } } - // VOS 2 range VCORE 1.05V - 1.15V - VoltageScale::Scale2 => { + // VOS 3 range VCORE 1.05V - 1.15V + VoltageScale::RANGE3 => { if sys_clk < 24_000_000 { 0 } else if sys_clk < 48_000_000 { @@ -326,8 +326,8 @@ pub(crate) unsafe fn init(config: Config) { 2 } } - // VOS 3 range VCORE 0.95V - 1.05V - VoltageScale::Scale3 => { + // VOS 4 range VCORE 0.95V - 1.05V + VoltageScale::RANGE4 => { if sys_clk < 12_000_000 { 0 } else { diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 5db942fc..6643d278 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,4 +1,5 @@ -pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; +pub use crate::pac::pwr::vals::Vos as VoltageScale; use crate::pac::rcc::vals::Adcsel; use crate::pac::{FLASH, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; @@ -75,9 +76,9 @@ impl MSIRange { fn vos(&self) -> VoltageScale { if self > &MSIRange::Range8 { - VoltageScale::Scale0 + VoltageScale::RANGE1 } else { - VoltageScale::Scale1 + VoltageScale::RANGE2 } } } @@ -170,8 +171,8 @@ pub enum Lsedrv { pub(crate) unsafe fn init(config: Config) { let (sys_clk, sw, vos) = match config.mux { - ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Scale1), - ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::Scale0), + ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::RANGE2), + ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::RANGE1), ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()), }; @@ -216,16 +217,17 @@ pub(crate) unsafe fn init(config: Config) { // Adjust flash latency let flash_clk_src_freq: u32 = shd_ahb_freq; let ws = match vos { - VoltageScale::Scale0 => match flash_clk_src_freq { + VoltageScale::RANGE1 => match flash_clk_src_freq { 0..=18_000_000 => 0b000, 18_000_001..=36_000_000 => 0b001, _ => 0b010, }, - VoltageScale::Scale1 => match flash_clk_src_freq { + VoltageScale::RANGE2 => match flash_clk_src_freq { 0..=6_000_000 => 0b000, 6_000_001..=12_000_000 => 0b001, _ => 0b010, }, + _ => unreachable!(), }; FLASH.acr().modify(|w| { diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index fdba6cd5..41ef2aca 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -53,7 +53,7 @@ async fn main(spawner: Spawner) -> ! { config.rcc.apb2_pre = APBPrescaler::DIV1; config.rcc.apb3_pre = APBPrescaler::DIV1; config.rcc.sys = Sysclk::Pll1P; - config.rcc.voltage_scale = VoltageScale::Scale0; + config.rcc.voltage_scale = VoltageScale::SCALE0; let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index cbe540a0..63c694af 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb2_pre = APBPrescaler::DIV2; config.rcc.apb3_pre = APBPrescaler::DIV4; config.rcc.sys = Sysclk::Pll1P; - config.rcc.voltage_scale = VoltageScale::Scale0; + config.rcc.voltage_scale = VoltageScale::SCALE0; let p = embassy_stm32::init(config); info!("Hello World!"); From 5d0c40f61d4a58614f3e489bc366a87da3757457 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 18 Sep 2023 03:30:17 +0200 Subject: [PATCH 187/233] rp: remove paste macro. --- embassy-rp/Cargo.toml | 1 - embassy-rp/src/pio.rs | 41 +++++++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 094b528f..1147286f 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -89,7 +89,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = embedded-hal-async = { version = "=1.0.0-rc.1", optional = true} embedded-hal-nb = { version = "=1.0.0-rc.1", optional = true} -paste = "1.0" pio-proc = {version= "0.2" } pio = {version= "0.2.1" } rp2040-boot2 = "0.3" diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index c09d0914..97dfce2e 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -1079,18 +1079,43 @@ impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); pub trait PioPin: sealed::PioPin + gpio::Pin {} macro_rules! impl_pio_pin { - ($( $num:tt )*) => { + ($( $pin:ident, )*) => { $( - paste::paste!{ - impl sealed::PioPin for peripherals::[< PIN_ $num >] {} - impl PioPin for peripherals::[< PIN_ $num >] {} - } + impl sealed::PioPin for peripherals::$pin {} + impl PioPin for peripherals::$pin {} )* }; } impl_pio_pin! { - 0 1 2 3 4 5 6 7 8 9 - 10 11 12 13 14 15 16 17 18 19 - 20 21 22 23 24 25 26 27 28 29 + PIN_0, + PIN_1, + PIN_2, + PIN_3, + PIN_4, + PIN_5, + PIN_6, + PIN_7, + PIN_8, + PIN_9, + PIN_10, + PIN_11, + PIN_12, + PIN_13, + PIN_14, + PIN_15, + PIN_16, + PIN_17, + PIN_18, + PIN_19, + PIN_20, + PIN_21, + PIN_22, + PIN_23, + PIN_24, + PIN_25, + PIN_26, + PIN_27, + PIN_28, + PIN_29, } From e640933e2f0c8fb0b5a6df645002f69b55f51d8a Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 18 Sep 2023 16:31:20 -0500 Subject: [PATCH 188/233] stm32/adc: add async conversion --- embassy-stm32/src/adc/f3.rs | 65 +++++++++++++++++++++++++++---- embassy-stm32/src/adc/mod.rs | 39 ++++++++++++++++++- examples/stm32f334/src/bin/adc.rs | 23 ++++++----- 3 files changed, 109 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index b39d6ac8..5d2ea1da 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -1,14 +1,36 @@ +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; + use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; +use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; pub const VREF_INT: u32 = 1230; +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + if T::regs().isr().read().eoc() { + T::regs().ier().modify(|w| w.set_eocie(false)); + } else { + return; + } + + T::state().waker.wake(); + } +} + pub struct Vref; impl AdcPin for Vref {} impl super::sealed::AdcPin for Vref { @@ -17,6 +39,13 @@ impl super::sealed::AdcPin for Vref { } } +impl Vref { + /// The value that vref would be if vdda was at 3300mv + pub fn value(&self) -> u16 { + crate::pac::VREFINTCAL.data().read().value() + } +} + pub struct Temperature; impl AdcPin for Temperature {} impl super::sealed::AdcPin for Temperature { @@ -26,7 +55,11 @@ impl super::sealed::AdcPin for Temperature { } impl<'d, T: Instance> Adc<'d, T> { - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + pub fn new( + adc: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + delay: &mut impl DelayUs, + ) -> Self { use crate::pac::adc::vals; into_ref!(adc); @@ -58,6 +91,11 @@ impl<'d, T: Instance> Adc<'d, T> { // Wait until the adc is ready while !T::regs().isr().read().adrdy() {} + T::Interrupt::unpend(); + unsafe { + T::Interrupt::enable(); + } + Self { adc, sample_time: Default::default(), @@ -97,30 +135,41 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Perform a single conversion. - fn convert(&mut self) -> u16 { + async fn convert(&mut self) -> u16 { T::regs().isr().write(|_| {}); + T::regs().ier().modify(|w| w.set_eocie(true)); T::regs().cr().modify(|w| w.set_adstart(true)); - while !T::regs().isr().read().eoc() && !T::regs().isr().read().eos() {} + poll_fn(|cx| { + T::state().waker.register(cx.waker()); + + if T::regs().isr().read().eoc() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + T::regs().isr().write(|_| {}); T::regs().dr().read().rdata() } - pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { + pub async fn read(&mut self, pin: &mut impl AdcPin) -> u16 { Self::set_channel_sample_time(pin.channel(), self.sample_time); // Configure the channel to sample T::regs().sqr1().write(|w| w.set_sq(0, pin.channel())); - self.convert() + self.convert().await } fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { let sample_time = sample_time.into(); if ch <= 9 { - T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); + T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); } else { - T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); } } } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 9334deac..e74913da 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -31,12 +31,35 @@ pub struct Adc<'d, T: Instance> { } pub(crate) mod sealed { - pub trait Instance { + #[cfg(adc_f3)] + use embassy_sync::waitqueue::AtomicWaker; + + #[cfg(adc_f3)] + pub struct State { + pub waker: AtomicWaker, + } + + #[cfg(adc_f3)] + impl State { + pub const fn new() -> Self { + Self { + waker: AtomicWaker::new(), + } + } + } + + pub trait InterruptableInstance { + type Interrupt: crate::interrupt::typelevel::Interrupt; + } + + pub trait Instance: InterruptableInstance { fn regs() -> crate::pac::adc::Adc; #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz; + #[cfg(adc_f3)] + fn state() -> &'static State; } pub trait AdcPin { @@ -72,8 +95,22 @@ foreach_adc!( fn frequency() -> crate::time::Hertz { unsafe { crate::rcc::get_freqs() }.$clock.unwrap() } + + #[cfg(adc_f3)] + fn state() -> &'static sealed::State { + static STATE: sealed::State = sealed::State::new(); + &STATE + } } + foreach_interrupt!( + ($inst,adc,ADC,GLOBAL,$irq:ident) => { + impl sealed::InterruptableInstance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } + }; + ); + impl crate::adc::Instance for peripherals::$inst {} }; ); diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index e8b2cd8a..ed246a7d 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -4,13 +4,18 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, SampleTime, VREF_INT}; +use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::peripherals::ADC1; use embassy_stm32::rcc::AdcClockSource; use embassy_stm32::time::mhz; -use embassy_stm32::Config; +use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_time::{Delay, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + ADC1_2 => adc::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let mut config = Config::default(); @@ -24,7 +29,7 @@ async fn main(_spawner: Spawner) -> ! { info!("create adc..."); - let mut adc = Adc::new(p.ADC1, &mut Delay); + let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay); adc.set_sample_time(SampleTime::Cycles601_5); @@ -34,18 +39,18 @@ async fn main(_spawner: Spawner) -> ! { let mut temperature = adc.enable_temperature(); loop { - let vref = adc.read(&mut vrefint); - info!("read vref: {}", vref); + let vref = adc.read(&mut vrefint).await; + info!("read vref: {} (should be {})", vref, vrefint.value()); - let temp = adc.read(&mut temperature); + let temp = adc.read(&mut temperature).await; info!("read temperature: {}", temp); - let pin = adc.read(&mut p.PA0); + let pin = adc.read(&mut p.PA0).await; info!("read pin: {}", pin); - let pin_mv = pin as u32 * VREF_INT as u32 / vref as u32; + let pin_mv = (pin as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095; info!("computed pin mv: {}", pin_mv); - Timer::after(Duration::from_secs(1)).await; + Timer::after(Duration::from_millis(500)).await; } } From 561696dfadba90c2b24a1fddd5f8b4370ab9cc0b Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Tue, 19 Sep 2023 10:20:25 +0200 Subject: [PATCH 189/233] Fix typo in F2 RCC voltage ranges --- embassy-stm32/src/rcc/f2.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index af90a9c3..1a34c2cb 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -208,13 +208,13 @@ pub struct PLLClocks { /// Used to calculate flash waitstates. See /// RM0033 - Table 3. Number of wait states according to CortexĀ®-M3 clock frequency pub enum VoltageScale { - /// 2.7v to 4.6v + /// 2.7 to 3.6 V Range0, - /// 2.4v to 2.7v + /// 2.4 to 2.7 V Range1, - /// 2.1v to 2.4v + /// 2.1 to 2.4 V Range2, - /// 1.8v to 2.1v + /// 1.8 to 2.1 V Range3, } From 2405aff11f466d1c3fc07bca70c07d11fc96c3be Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Tue, 19 Sep 2023 23:23:14 +0200 Subject: [PATCH 190/233] Add get_level() to ExtiInput --- embassy-stm32/src/exti.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index bd4bab1f..efa51fb2 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -6,7 +6,7 @@ use core::task::{Context, Poll}; use embassy_hal_internal::impl_peripheral; use embassy_sync::waitqueue::AtomicWaker; -use crate::gpio::{AnyPin, Input, Pin as GpioPin}; +use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin}; use crate::pac::exti::regs::Lines; use crate::pac::EXTI; use crate::{interrupt, pac, peripherals, Peripheral}; @@ -101,6 +101,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { self.pin.is_low() } + pub fn get_level(&self) -> Level { + self.pin.get_level() + } + pub async fn wait_for_high<'a>(&'a mut self) { let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); if self.is_high() { From d46920dce692859e0818a6171c930af270a7a02f Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 20 Sep 2023 16:07:35 -0500 Subject: [PATCH 191/233] stm32/adc: make v1 async and leave en --- embassy-stm32/src/adc/mod.rs | 10 +-- embassy-stm32/src/adc/v1.rs | 145 ++++++++++++++++++++------------ examples/stm32f0/src/bin/adc.rs | 12 ++- 3 files changed, 104 insertions(+), 63 deletions(-) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index e74913da..2f8f8f9e 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -31,15 +31,15 @@ pub struct Adc<'d, T: Instance> { } pub(crate) mod sealed { - #[cfg(adc_f3)] + #[cfg(any(adc_f3, adc_v1))] use embassy_sync::waitqueue::AtomicWaker; - #[cfg(adc_f3)] + #[cfg(any(adc_f3, adc_v1))] pub struct State { pub waker: AtomicWaker, } - #[cfg(adc_f3)] + #[cfg(any(adc_f3, adc_v1))] impl State { pub const fn new() -> Self { Self { @@ -58,7 +58,7 @@ pub(crate) mod sealed { fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz; - #[cfg(adc_f3)] + #[cfg(any(adc_f3, adc_v1))] fn state() -> &'static State; } @@ -96,7 +96,7 @@ foreach_adc!( unsafe { crate::rcc::get_freqs() }.$clock.unwrap() } - #[cfg(adc_f3)] + #[cfg(any(adc_f3, adc_v1))] fn state() -> &'static sealed::State { static STATE: sealed::State = sealed::State::new(); &STATE diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index e8245884..15b2dc59 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -1,13 +1,35 @@ +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; + use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; +use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; pub const VDDA_CALIB_MV: u32 = 3300; pub const VREF_INT: u32 = 1230; +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + if T::regs().isr().read().eoc() { + T::regs().ier().modify(|w| w.set_eocie(false)); + } else { + return; + } + + T::state().waker.wake(); + } +} + pub struct Vbat; impl InternalChannel for Vbat {} impl super::sealed::InternalChannel for Vbat { @@ -33,7 +55,11 @@ impl super::sealed::InternalChannel for Temperature { } impl<'d, T: Instance> Adc<'d, T> { - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + pub fn new( + adc: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + delay: &mut impl DelayUs, + ) -> Self { into_ref!(adc); T::enable(); T::reset(); @@ -44,12 +70,32 @@ impl<'d, T: Instance> Adc<'d, T> { // tstab = 14 * 1/fadc delay.delay_us(1); - let s = Self { + // A.7.1 ADC calibration code example + T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); + T::regs().cr().modify(|reg| reg.set_adcal(true)); + while T::regs().cr().read().adcal() {} + + // A.7.2 ADC enable sequence code example + if T::regs().isr().read().adrdy() { + T::regs().isr().modify(|reg| reg.set_adrdy(true)); + } + T::regs().cr().modify(|reg| reg.set_aden(true)); + while !T::regs().isr().read().adrdy() { + // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration + // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the + // ADEN bit until the ADRDY flag goes high. + T::regs().cr().modify(|reg| reg.set_aden(true)); + } + + T::Interrupt::unpend(); + unsafe { + T::Interrupt::enable(); + } + + Self { adc, sample_time: Default::default(), - }; - s.calibrate(); - s + } } pub fn enable_vbat(&self, _delay: &mut impl DelayUs) -> Vbat { @@ -80,21 +126,6 @@ impl<'d, T: Instance> Adc<'d, T> { Temperature } - fn calibrate(&self) { - // A.7.1 ADC calibration code example - if T::regs().cr().read().aden() { - T::regs().cr().modify(|reg| reg.set_addis(true)); - } - while T::regs().cr().read().aden() { - // spin - } - T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); - T::regs().cr().modify(|reg| reg.set_adcal(true)); - while T::regs().cr().read().adcal() { - // spin - } - } - pub fn set_sample_time(&mut self, sample_time: SampleTime) { self.sample_time = sample_time; } @@ -103,57 +134,61 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); } - pub fn read

(&mut self, pin: &mut P) -> u16 + pub async fn read

(&mut self, pin: &mut P) -> u16 where P: AdcPin + crate::gpio::sealed::Pin, { let channel = pin.channel(); pin.set_as_analog(); - self.read_channel(channel) + self.read_channel(channel).await } - pub fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { + pub async fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { let channel = channel.channel(); - self.read_channel(channel) + self.read_channel(channel).await } - fn read_channel(&mut self, channel: u8) -> u16 { - // A.7.2 ADC enable sequence code example - if T::regs().isr().read().adrdy() { - T::regs().isr().modify(|reg| reg.set_adrdy(true)); - } - T::regs().cr().modify(|reg| reg.set_aden(true)); - while !T::regs().isr().read().adrdy() { - // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration - // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the - // ADEN bit until the ADRDY flag goes high. - T::regs().cr().modify(|reg| reg.set_aden(true)); - } - + async fn convert(&mut self) -> u16 { T::regs().isr().modify(|reg| { reg.set_eoc(true); reg.set_eosmp(true); }); + T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); + T::regs().ier().modify(|w| w.set_eocie(true)); + T::regs().cr().modify(|reg| reg.set_adstart(true)); + + poll_fn(|cx| { + T::state().waker.register(cx.waker()); + + if T::regs().isr().read().eoc() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + T::regs().dr().read().data() + } + + async fn read_channel(&mut self, channel: u8) -> u16 { // A.7.5 Single conversion sequence code example - Software trigger T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); - T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); - T::regs().cr().modify(|reg| reg.set_adstart(true)); - while !T::regs().isr().read().eoc() { - // spin - } - let value = T::regs().dr().read().0 as u16; - // A.7.3 ADC disable code example - T::regs().cr().modify(|reg| reg.set_adstp(true)); - while T::regs().cr().read().adstp() { - // spin - } - T::regs().cr().modify(|reg| reg.set_addis(true)); - while T::regs().cr().read().aden() { - // spin - } - - value + self.convert().await + } +} + +impl<'d, T: Instance> Drop for Adc<'d, T> { + fn drop(&mut self) { + // A.7.3 ADC disable code example + T::regs().cr().modify(|reg| reg.set_adstp(true)); + while T::regs().cr().read().adstp() {} + + T::regs().cr().modify(|reg| reg.set_addis(true)); + while T::regs().cr().read().aden() {} + + T::disable(); } } diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index 8ed9f98f..2ed46a94 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -5,20 +5,26 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::peripherals::ADC; +use embassy_stm32::{adc, bind_interrupts}; use embassy_time::{Delay, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + ADC1_COMP => adc::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC, &mut Delay); + let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); adc.set_sample_time(SampleTime::Cycles71_5); let mut pin = p.PA1; let mut vrefint = adc.enable_vref(&mut Delay); - let vrefint_sample = adc.read_internal(&mut vrefint); + let vrefint_sample = adc.read_internal(&mut vrefint).await; let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf // 6.3.4 Embedded reference voltage @@ -28,7 +34,7 @@ async fn main(_spawner: Spawner) { }; loop { - let v = adc.read(&mut pin); + let v = adc.read(&mut pin).await; info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after(Duration::from_millis(100)).await; } From 00b9f9acef129155e0c9d1fa7d021104103a897b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 21 Sep 2023 00:23:56 +0200 Subject: [PATCH 192/233] stm32/h7: fix bad PWR reg versions. --- embassy-stm32/src/rcc/h7.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index 585e1faa..ea26c26c 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -464,14 +464,14 @@ pub(crate) unsafe fn init(mut config: Config) { // RM0433 Rev 7 6.8.4. This is partially enforced by dropping // `self` at the end of this method, but of course we cannot // know what happened between the previous POR and here. - #[cfg(pwr_h7)] + #[cfg(pwr_h7rm0433)] PWR.cr3().modify(|w| { w.set_scuen(true); w.set_ldoen(true); w.set_bypass(false); }); - #[cfg(pwr_h7smps)] + #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] PWR.cr3().modify(|w| { // hardcode "Direct SPMS" for now, this is what works on nucleos with the // default solderbridge configuration. @@ -484,7 +484,9 @@ pub(crate) unsafe fn init(mut config: Config) { // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset // VOS = Scale 3, so check that the voltage on the VCAP pins = // 1.0V. + info!("a"); while !PWR.csr1().read().actvosrdy() {} + info!("b"); #[cfg(syscfg_h7)] { From ad64d7b20b26e0854c4d1302f562df51e67a022b Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 21 Sep 2023 17:17:58 +0200 Subject: [PATCH 193/233] fix low-power: APB1 needed for LSE --- embassy-stm32/src/rcc/bd.rs | 5 +++++ embassy-stm32/src/rtc/mod.rs | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 762e8435..4915d5e2 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -88,6 +88,11 @@ impl BackupDomain { ))] #[allow(dead_code, unused_variables)] pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option) { + if lsi || lse.is_some() { + use crate::rtc::sealed::Instance; + crate::peripherals::RTC::enable_peripheral_clk(); + } + if lsi { #[cfg(rtc_v3u5)] let csr = crate::pac::RCC.bdcr(); diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 07b4fe1f..7eafedec 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -154,8 +154,6 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { - RTC::enable_peripheral_clk(); - let mut this = Self { #[cfg(feature = "low-power")] stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), From 83b4c0127337c55c6a445abee6ab5eac4c993f9c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Sep 2023 04:22:57 +0200 Subject: [PATCH 194/233] stm32/rcc: unify h5 and h7. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/rcc/h.rs | 777 +++++++++++++++ embassy-stm32/src/rcc/h5.rs | 511 ---------- embassy-stm32/src/rcc/h7.rs | 934 ------------------ embassy-stm32/src/rcc/mco.rs | 71 ++ embassy-stm32/src/rcc/mod.rs | 14 +- examples/stm32f4/src/bin/eth.rs | 3 +- examples/stm32f7/src/bin/eth.rs | 3 +- examples/stm32h5/src/bin/eth.rs | 4 +- examples/stm32h5/src/bin/usb_serial.rs | 2 +- examples/stm32h7/src/bin/adc.rs | 34 +- examples/stm32h7/src/bin/camera.rs | 33 +- examples/stm32h7/src/bin/dac.rs | 32 +- examples/stm32h7/src/bin/dac_dma.rs | 33 +- examples/stm32h7/src/bin/eth.rs | 28 +- examples/stm32h7/src/bin/eth_client.rs | 27 +- examples/stm32h7/src/bin/fmc.rs | 24 +- .../stm32h7/src/bin/low_level_timer_api.rs | 30 +- examples/stm32h7/src/bin/mco.rs | 4 +- examples/stm32h7/src/bin/pwm.rs | 29 +- examples/stm32h7/src/bin/rng.rs | 6 +- examples/stm32h7/src/bin/sdmmc.rs | 21 +- examples/stm32h7/src/bin/spi.rs | 23 +- examples/stm32h7/src/bin/spi_dma.rs | 23 +- examples/stm32h7/src/bin/usb_serial.rs | 25 +- tests/stm32/src/common.rs | 29 +- 26 files changed, 1195 insertions(+), 1529 deletions(-) create mode 100644 embassy-stm32/src/rcc/h.rs delete mode 100644 embassy-stm32/src/rcc/h5.rs delete mode 100644 embassy-stm32/src/rcc/h7.rs create mode 100644 embassy-stm32/src/rcc/mco.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 1a024e9a..67f3f526 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -59,7 +59,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2dba1f1ddee697e616aff2a4db57a6ffaf1b29b7" } +stm32-metapac = { git = "https://ci.embassy.dev/jobs/7d2e0e63527f/artifacts/generated.git" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2dba1f1ddee697e616aff2a4db57a6ffaf1b29b7", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://ci.embassy.dev/jobs/7d2e0e63527f/artifacts/generated.git", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs new file mode 100644 index 00000000..a4730ed4 --- /dev/null +++ b/embassy-stm32/src/rcc/h.rs @@ -0,0 +1,777 @@ +use core::ops::RangeInclusive; + +use crate::pac; +use crate::pac::pwr::vals::Vos; +#[cfg(stm32h5)] +pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; +#[cfg(stm32h7)] +pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; +pub use crate::pac::rcc::vals::Ckpersel as PerClockSource; +use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre}; +use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::{set_freqs, Clocks}; +use crate::time::Hertz; + +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(64_000_000); + +/// CSI speed +pub const CSI_FREQ: Hertz = Hertz(4_000_000); + +/// HSI48 speed +pub const HSI48_FREQ: Hertz = Hertz(48_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); + +const VCO_RANGE: RangeInclusive = 150_000_000..=420_000_000; +#[cfg(any(stm32h5, pwr_h7rm0455))] +const VCO_WIDE_RANGE: RangeInclusive = 128_000_000..=560_000_000; +#[cfg(pwr_h7rm0468)] +const VCO_WIDE_RANGE: RangeInclusive = 192_000_000..=836_000_000; +#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))] +const VCO_WIDE_RANGE: RangeInclusive = 192_000_000..=960_000_000; + +pub use super::bus::{AHBPrescaler, APBPrescaler}; + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum VoltageScale { + Scale0, + Scale1, + Scale2, + Scale3, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum HseMode { + /// crystal/ceramic oscillator (HSEBYP=0) + Oscillator, + /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) + Bypass, + /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) + #[cfg(any(rcc_h5, rcc_h50))] + BypassDigital, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum Hsi { + /// 64Mhz + Mhz64, + /// 32Mhz (divided by 2) + Mhz32, + /// 16Mhz (divided by 4) + Mhz16, + /// 8Mhz (divided by 8) + Mhz8, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum Sysclk { + /// HSI selected as sysclk + HSI, + /// HSE selected as sysclk + HSE, + /// CSI selected as sysclk + CSI, + /// PLL1_P selected as sysclk + Pll1P, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum PllSource { + Hsi, + Csi, + Hse, +} + +#[derive(Clone, Copy)] +pub struct Pll { + /// Source clock selection. + #[cfg(stm32h5)] + pub source: PllSource, + + /// PLL pre-divider (DIVM). Must be between 1 and 63. + pub prediv: u8, + + /// PLL multiplication factor. Must be between 4 and 512. + pub mul: u16, + + /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. + /// On PLL1, it must be even (in particular, it cannot be 1.) + pub divp: Option, + /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. + pub divq: Option, + /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. + pub divr: Option, +} + +fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { + match (tim, apb) { + (TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32, + + (TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32, + + _ => unreachable!(), + } +} + +/// Timer prescaler +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum TimerPrescaler { + /// The timers kernel clock is equal to hclk if PPREx corresponds to a + /// division by 1 or 2, else it is equal to 2*pclk + DefaultX2, + + /// The timers kernel clock is equal to hclk if PPREx corresponds to a + /// division by 1, 2 or 4, else it is equal to 4*pclk + DefaultX4, +} + +impl From for Timpre { + fn from(value: TimerPrescaler) -> Self { + match value { + TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2, + TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4, + } + } +} + +/// Configuration of the core clocks +#[non_exhaustive] +pub struct Config { + pub hsi: Option, + pub hse: Option, + pub csi: bool, + pub hsi48: bool, + pub sys: Sysclk, + + #[cfg(stm32h7)] + pub pll_src: PllSource, + + pub pll1: Option, + pub pll2: Option, + #[cfg(any(rcc_h5, stm32h7))] + pub pll3: Option, + + pub d1c_pre: AHBPrescaler, + pub ahb_pre: AHBPrescaler, + pub apb1_pre: APBPrescaler, + pub apb2_pre: APBPrescaler, + pub apb3_pre: APBPrescaler, + #[cfg(stm32h7)] + pub apb4_pre: APBPrescaler, + + pub per_clock_source: PerClockSource, + pub adc_clock_source: AdcClockSource, + pub timer_prescaler: TimerPrescaler, + pub voltage_scale: VoltageScale, +} + +impl Default for Config { + fn default() -> Self { + Self { + hsi: Some(Hsi::Mhz64), + hse: None, + csi: false, + hsi48: false, + sys: Sysclk::HSI, + #[cfg(stm32h7)] + pll_src: PllSource::Hsi, + pll1: None, + pll2: None, + #[cfg(any(rcc_h5, stm32h7))] + pll3: None, + + d1c_pre: AHBPrescaler::DIV1, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + apb3_pre: APBPrescaler::DIV1, + #[cfg(stm32h7)] + apb4_pre: APBPrescaler::DIV1, + + per_clock_source: PerClockSource::HSI, + adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5 + timer_prescaler: TimerPrescaler::DefaultX2, + voltage_scale: VoltageScale::Scale0, + } + } +} + +pub(crate) unsafe fn init(config: Config) { + #[cfg(stm32h7)] + RCC.apb4enr().modify(|w| w.set_syscfgen(true)); + #[cfg(stm32h5)] + RCC.apb3enr().modify(|w| w.set_sbsen(true)); + + // NB. The lower bytes of CR3 can only be written once after + // POR, and must be written with a valid combination. Refer to + // RM0433 Rev 7 6.8.4. This is partially enforced by dropping + // `self` at the end of this method, but of course we cannot + // know what happened between the previous POR and here. + #[cfg(pwr_h7rm0433)] + PWR.cr3().modify(|w| { + w.set_scuen(true); + w.set_ldoen(true); + w.set_bypass(false); + }); + + #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] + PWR.cr3().modify(|w| { + // hardcode "Direct SPMS" for now, this is what works on nucleos with the + // default solderbridge configuration. + w.set_sden(true); + w.set_ldoen(false); + }); + + // Validate the supply configuration. If you are stuck here, it is + // because the voltages on your board do not match those specified + // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset + // VOS = Scale 3, so check that the voltage on the VCAP pins = + // 1.0V. + #[cfg(any(pwr_h7rm0433, pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] + while !PWR.csr1().read().actvosrdy() {} + + // Configure voltage scale. + #[cfg(any(pwr_h5, pwr_h50))] + { + PWR.voscr().modify(|w| { + w.set_vos(match config.voltage_scale { + VoltageScale::Scale0 => Vos::SCALE0, + VoltageScale::Scale1 => Vos::SCALE1, + VoltageScale::Scale2 => Vos::SCALE2, + VoltageScale::Scale3 => Vos::SCALE3, + }) + }); + while !PWR.vossr().read().vosrdy() {} + } + + #[cfg(syscfg_h7)] + { + // in chips without the overdrive bit, we can go from any scale to any scale directly. + PWR.d3cr().modify(|w| { + w.set_vos(match config.voltage_scale { + VoltageScale::Scale0 => Vos::SCALE0, + VoltageScale::Scale1 => Vos::SCALE1, + VoltageScale::Scale2 => Vos::SCALE2, + VoltageScale::Scale3 => Vos::SCALE3, + }) + }); + while !PWR.d3cr().read().vosrdy() {} + } + + #[cfg(syscfg_h7od)] + { + match config.voltage_scale { + VoltageScale::Scale0 => { + // to go to scale0, we must go to Scale1 first... + PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1)); + while !PWR.d3cr().read().vosrdy() {} + + // Then enable overdrive. + critical_section::with(|_| pac::SYSCFG.pwrcr().modify(|w| w.set_oden(1))); + while !PWR.d3cr().read().vosrdy() {} + } + _ => { + // for all other scales, we can go directly. + PWR.d3cr().modify(|w| { + w.set_vos(match config.voltage_scale { + VoltageScale::Scale0 => unreachable!(), + VoltageScale::Scale1 => Vos::SCALE1, + VoltageScale::Scale2 => Vos::SCALE2, + VoltageScale::Scale3 => Vos::SCALE3, + }) + }); + while !PWR.d3cr().read().vosrdy() {} + } + } + } + + // Configure HSI + let hsi = match config.hsi { + None => { + RCC.cr().modify(|w| w.set_hsion(false)); + None + } + Some(hsi) => { + let (freq, hsidiv) = match hsi { + Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1), + Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2), + Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4), + Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8), + }; + RCC.cr().modify(|w| { + w.set_hsidiv(hsidiv); + w.set_hsion(true); + }); + while !RCC.cr().read().hsirdy() {} + Some(freq) + } + }; + + // Configure HSE + let hse = match config.hse { + None => { + RCC.cr().modify(|w| w.set_hseon(false)); + None + } + Some(hse) => { + RCC.cr().modify(|w| { + w.set_hsebyp(hse.mode != HseMode::Oscillator); + #[cfg(any(rcc_h5, rcc_h50))] + w.set_hseext(match hse.mode { + HseMode::Oscillator | HseMode::Bypass => pac::rcc::vals::Hseext::ANALOG, + HseMode::BypassDigital => pac::rcc::vals::Hseext::DIGITAL, + }); + }); + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + Some(hse.freq) + } + }; + + // Configure HSI48. + RCC.cr().modify(|w| w.set_hsi48on(config.hsi48)); + let _hsi48 = match config.hsi48 { + false => None, + true => { + while !RCC.cr().read().hsi48rdy() {} + Some(CSI_FREQ) + } + }; + + // Configure CSI. + RCC.cr().modify(|w| w.set_csion(config.csi)); + let csi = match config.csi { + false => None, + true => { + while !RCC.cr().read().csirdy() {} + Some(CSI_FREQ) + } + }; + + // Configure PLLs. + let pll_input = PllInput { + csi, + hse, + hsi, + #[cfg(stm32h7)] + source: config.pll_src, + }; + let pll1 = init_pll(0, config.pll1, &pll_input); + let pll2 = init_pll(1, config.pll2, &pll_input); + #[cfg(any(rcc_h5, stm32h7))] + let _pll3 = init_pll(2, config.pll3, &pll_input); + + // Configure sysclk + let (sys, sw) = match config.sys { + Sysclk::HSI => (unwrap!(hsi), Sw::HSI), + Sysclk::HSE => (unwrap!(hse), Sw::HSE), + Sysclk::CSI => (unwrap!(csi), Sw::CSI), + Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1), + }; + + // Check limits. + #[cfg(stm32h5)] + let (hclk_max, pclk_max) = match config.voltage_scale { + VoltageScale::Scale0 => (Hertz(250_000_000), Hertz(250_000_000)), + VoltageScale::Scale1 => (Hertz(200_000_000), Hertz(200_000_000)), + VoltageScale::Scale2 => (Hertz(150_000_000), Hertz(150_000_000)), + VoltageScale::Scale3 => (Hertz(100_000_000), Hertz(100_000_000)), + }; + #[cfg(stm32h7)] + let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { + VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)), + VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), + VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), + VoltageScale::Scale3 => (Hertz(200_000_000), Hertz(100_000_000), Hertz(50_000_000)), + }; + + #[cfg(stm32h7)] + let hclk = { + let d1cpre_clk = sys / config.d1c_pre; + assert!(d1cpre_clk <= d1cpre_clk_max); + sys / config.ahb_pre + }; + #[cfg(stm32h5)] + let hclk = sys / config.ahb_pre; + assert!(hclk <= hclk_max); + + let apb1 = hclk / config.apb1_pre; + let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler); + assert!(apb1 <= pclk_max); + let apb2 = hclk / config.apb2_pre; + let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler); + assert!(apb2 <= pclk_max); + let apb3 = hclk / config.apb3_pre; + assert!(apb3 <= pclk_max); + #[cfg(stm32h7)] + let apb4 = hclk / config.apb4_pre; + #[cfg(stm32h7)] + assert!(apb4 <= pclk_max); + + let _per_ck = match config.per_clock_source { + Ckpersel::HSI => hsi, + Ckpersel::CSI => csi, + Ckpersel::HSE => hse, + _ => unreachable!(), + }; + + #[cfg(stm32h7)] + let adc = match config.adc_clock_source { + AdcClockSource::PLL2_P => pll2.p, + AdcClockSource::PLL3_R => _pll3.r, + AdcClockSource::PER => _per_ck, + _ => unreachable!(), + }; + #[cfg(stm32h5)] + let adc = match config.adc_clock_source { + AdcClockSource::HCLK => Some(hclk), + AdcClockSource::SYSCLK => Some(sys), + AdcClockSource::PLL2_R => pll2.r, + AdcClockSource::HSE => hse, + AdcClockSource::HSI_KER => hsi, + AdcClockSource::CSI_KER => csi, + _ => unreachable!(), + }; + + flash_setup(hclk, config.voltage_scale); + + #[cfg(stm32h7)] + { + RCC.d1cfgr().modify(|w| { + w.set_d1cpre(config.d1c_pre); + w.set_d1ppre(config.apb3_pre); + w.set_hpre(config.ahb_pre); + }); + // Ensure core prescaler value is valid before future lower core voltage + while RCC.d1cfgr().read().d1cpre() != config.d1c_pre {} + + RCC.d2cfgr().modify(|w| { + w.set_d2ppre1(config.apb1_pre); + w.set_d2ppre2(config.apb2_pre); + }); + RCC.d3cfgr().modify(|w| { + w.set_d3ppre(config.apb4_pre); + }); + + RCC.d1ccipr().modify(|w| { + w.set_ckpersel(config.per_clock_source); + }); + RCC.d3ccipr().modify(|w| { + w.set_adcsel(config.adc_clock_source); + }); + } + #[cfg(stm32h5)] + { + // Set hpre + RCC.cfgr2().modify(|w| w.set_hpre(config.ahb_pre)); + while RCC.cfgr2().read().hpre() != config.ahb_pre {} + + // set ppre + RCC.cfgr2().modify(|w| { + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); + w.set_ppre3(config.apb3_pre); + }); + + RCC.ccipr5().modify(|w| { + w.set_ckpersel(config.per_clock_source); + w.set_adcdacsel(config.adc_clock_source) + }); + } + + RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); + + RCC.cfgr().modify(|w| w.set_sw(sw)); + while RCC.cfgr().read().sws() != sw {} + + // IO compensation cell - Requires CSI clock and SYSCFG + #[cfg(stm32h7)] // TODO h5 + if csi.is_some() { + // Enable the compensation cell, using back-bias voltage code + // provide by the cell. + critical_section::with(|_| { + pac::SYSCFG.cccsr().modify(|w| { + w.set_en(true); + w.set_cs(false); + w.set_hslv(false); + }) + }); + while !pac::SYSCFG.cccsr().read().ready() {} + } + + set_freqs(Clocks { + sys, + ahb1: hclk, + ahb2: hclk, + ahb3: hclk, + ahb4: hclk, + apb1, + apb2, + apb3, + #[cfg(stm32h7)] + apb4, + apb1_tim, + apb2_tim, + adc: adc, + }); +} + +struct PllInput { + hsi: Option, + hse: Option, + csi: Option, + #[cfg(stm32h7)] + source: PllSource, +} + +struct PllOutput { + p: Option, + #[allow(dead_code)] + q: Option, + #[allow(dead_code)] + r: Option, +} + +fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { + let Some(config) = config else { + // Stop PLL + RCC.cr().modify(|w| w.set_pllon(num, false)); + while RCC.cr().read().pllrdy(num) {} + + // "To save power when PLL1 is not used, the value of PLL1M must be set to 0."" + #[cfg(stm32h7)] + RCC.pllckselr().write(|w| w.set_divm(num, 0)); + #[cfg(stm32h5)] + RCC.pllcfgr(num).write(|w| w.set_divm(0)); + + return PllOutput { + p: None, + q: None, + r: None, + }; + }; + + assert!(1 <= config.prediv && config.prediv <= 63); + assert!(4 <= config.mul && config.mul <= 512); + + #[cfg(stm32h5)] + let source = config.source; + #[cfg(stm32h7)] + let source = input.source; + + let (in_clk, src) = match source { + PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI), + PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE), + PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI), + }; + + let ref_clk = in_clk / config.prediv as u32; + + let ref_range = match ref_clk.0 { + ..=1_999_999 => Pllrge::RANGE1, + ..=3_999_999 => Pllrge::RANGE2, + ..=7_999_999 => Pllrge::RANGE4, + ..=16_000_000 => Pllrge::RANGE8, + x => panic!("pll ref_clk out of range: {} mhz", x), + }; + + // The smaller range (150 to 420 MHz) must + // be chosen when the reference clock frequency is lower than 2 MHz. + let wide_allowed = ref_range != Pllrge::RANGE1; + + let vco_clk = ref_clk * config.mul; + let vco_range = if VCO_RANGE.contains(&vco_clk.0) { + Pllvcosel::MEDIUMVCO + } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) { + Pllvcosel::WIDEVCO + } else { + panic!("pll vco_clk out of range: {} mhz", vco_clk.0) + }; + + let p = config.divp.map(|div| { + assert!(1 <= div && div <= 128); + if num == 0 { + // on PLL1, DIVP must be even. + assert!(div % 2 == 0); + } + + vco_clk / div + }); + let q = config.divq.map(|div| { + assert!(1 <= div && div <= 128); + vco_clk / div + }); + let r = config.divr.map(|div| { + assert!(1 <= div && div <= 128); + vco_clk / div + }); + + #[cfg(stm32h5)] + RCC.pllcfgr(num).write(|w| { + w.set_pllsrc(src); + w.set_divm(config.prediv); + w.set_pllvcosel(vco_range); + w.set_pllrge(ref_range); + w.set_pllfracen(false); + w.set_pllpen(p.is_some()); + w.set_pllqen(q.is_some()); + w.set_pllren(r.is_some()); + }); + + #[cfg(stm32h7)] + { + RCC.pllckselr().modify(|w| { + w.set_divm(num, config.prediv); + w.set_pllsrc(src); + }); + RCC.pllcfgr().modify(|w| { + w.set_pllvcosel(num, vco_range); + w.set_pllrge(num, ref_range); + w.set_pllfracen(num, false); + w.set_divpen(num, p.is_some()); + w.set_divqen(num, q.is_some()); + w.set_divren(num, r.is_some()); + }); + } + + RCC.plldivr(num).write(|w| { + w.set_plln(config.mul - 1); + w.set_pllp((config.divp.unwrap_or(1) - 1) as u8); + w.set_pllq((config.divq.unwrap_or(1) - 1) as u8); + w.set_pllr((config.divr.unwrap_or(1) - 1) as u8); + }); + + RCC.cr().modify(|w| w.set_pllon(num, true)); + while !RCC.cr().read().pllrdy(num) {} + + PllOutput { p, q, r } +} + +fn flash_setup(clk: Hertz, vos: VoltageScale) { + // RM0481 Rev 1, table 37 + // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0 + // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz + // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz + // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz + // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz + // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz + // 5 2 170 to 200 MHz 210 to 250 MHz + #[cfg(stm32h5)] + let (latency, wrhighfreq) = match (vos, clk.0) { + (VoltageScale::Scale0, ..=42_000_000) => (0, 0), + (VoltageScale::Scale0, ..=84_000_000) => (1, 0), + (VoltageScale::Scale0, ..=126_000_000) => (2, 1), + (VoltageScale::Scale0, ..=168_000_000) => (3, 1), + (VoltageScale::Scale0, ..=210_000_000) => (4, 2), + (VoltageScale::Scale0, ..=250_000_000) => (5, 2), + + (VoltageScale::Scale1, ..=34_000_000) => (0, 0), + (VoltageScale::Scale1, ..=68_000_000) => (1, 0), + (VoltageScale::Scale1, ..=102_000_000) => (2, 1), + (VoltageScale::Scale1, ..=136_000_000) => (3, 1), + (VoltageScale::Scale1, ..=170_000_000) => (4, 2), + (VoltageScale::Scale1, ..=200_000_000) => (5, 2), + + (VoltageScale::Scale2, ..=30_000_000) => (0, 0), + (VoltageScale::Scale2, ..=60_000_000) => (1, 0), + (VoltageScale::Scale2, ..=90_000_000) => (2, 1), + (VoltageScale::Scale2, ..=120_000_000) => (3, 1), + (VoltageScale::Scale2, ..=150_000_000) => (4, 2), + + (VoltageScale::Scale3, ..=20_000_000) => (0, 0), + (VoltageScale::Scale3, ..=40_000_000) => (1, 0), + (VoltageScale::Scale3, ..=60_000_000) => (2, 1), + (VoltageScale::Scale3, ..=80_000_000) => (3, 1), + (VoltageScale::Scale3, ..=100_000_000) => (4, 2), + + _ => unreachable!(), + }; + + #[cfg(flash_h7)] + let (latency, wrhighfreq) = match (vos, clk.0) { + // VOS 0 range VCORE 1.26V - 1.40V + (VoltageScale::Scale0, ..=70_000_000) => (0, 0), + (VoltageScale::Scale0, ..=140_000_000) => (1, 1), + (VoltageScale::Scale0, ..=185_000_000) => (2, 1), + (VoltageScale::Scale0, ..=210_000_000) => (2, 2), + (VoltageScale::Scale0, ..=225_000_000) => (3, 2), + (VoltageScale::Scale0, ..=240_000_000) => (4, 2), + // VOS 1 range VCORE 1.15V - 1.26V + (VoltageScale::Scale1, ..=70_000_000) => (0, 0), + (VoltageScale::Scale1, ..=140_000_000) => (1, 1), + (VoltageScale::Scale1, ..=185_000_000) => (2, 1), + (VoltageScale::Scale1, ..=210_000_000) => (2, 2), + (VoltageScale::Scale1, ..=225_000_000) => (3, 2), + // VOS 2 range VCORE 1.05V - 1.15V + (VoltageScale::Scale2, ..=55_000_000) => (0, 0), + (VoltageScale::Scale2, ..=110_000_000) => (1, 1), + (VoltageScale::Scale2, ..=165_000_000) => (2, 1), + (VoltageScale::Scale2, ..=224_000_000) => (3, 2), + // VOS 3 range VCORE 0.95V - 1.05V + (VoltageScale::Scale3, ..=45_000_000) => (0, 0), + (VoltageScale::Scale3, ..=90_000_000) => (1, 1), + (VoltageScale::Scale3, ..=135_000_000) => (2, 1), + (VoltageScale::Scale3, ..=180_000_000) => (3, 2), + (VoltageScale::Scale3, ..=224_000_000) => (4, 2), + _ => unreachable!(), + }; + + // See RM0455 Rev 10 Table 16. FLASH recommended number of wait + // states and programming delay + #[cfg(flash_h7ab)] + let (latency, wrhighfreq) = match (vos, clk.0) { + // VOS 0 range VCORE 1.25V - 1.35V + (VoltageScale::Scale0, ..=42_000_000) => (0, 0), + (VoltageScale::Scale0, ..=84_000_000) => (1, 0), + (VoltageScale::Scale0, ..=126_000_000) => (2, 1), + (VoltageScale::Scale0, ..=168_000_000) => (3, 1), + (VoltageScale::Scale0, ..=210_000_000) => (4, 2), + (VoltageScale::Scale0, ..=252_000_000) => (5, 2), + (VoltageScale::Scale0, ..=280_000_000) => (6, 3), + // VOS 1 range VCORE 1.15V - 1.25V + (VoltageScale::Scale1, ..=38_000_000) => (0, 0), + (VoltageScale::Scale1, ..=76_000_000) => (1, 0), + (VoltageScale::Scale1, ..=114_000_000) => (2, 1), + (VoltageScale::Scale1, ..=152_000_000) => (3, 1), + (VoltageScale::Scale1, ..=190_000_000) => (4, 2), + (VoltageScale::Scale1, ..=225_000_000) => (5, 2), + // VOS 2 range VCORE 1.05V - 1.15V + (VoltageScale::Scale2, ..=34) => (0, 0), + (VoltageScale::Scale2, ..=68) => (1, 0), + (VoltageScale::Scale2, ..=102) => (2, 1), + (VoltageScale::Scale2, ..=136) => (3, 1), + (VoltageScale::Scale2, ..=160) => (4, 2), + // VOS 3 range VCORE 0.95V - 1.05V + (VoltageScale::Scale3, ..=22) => (0, 0), + (VoltageScale::Scale3, ..=44) => (1, 0), + (VoltageScale::Scale3, ..=66) => (2, 1), + (VoltageScale::Scale3, ..=88) => (3, 1), + _ => unreachable!(), + }; + + debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); + + FLASH.acr().write(|w| { + w.set_wrhighfreq(wrhighfreq); + w.set_latency(latency); + }); + while FLASH.acr().read().latency() != latency {} +} diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs deleted file mode 100644 index 15f28c5d..00000000 --- a/embassy-stm32/src/rcc/h5.rs +++ /dev/null @@ -1,511 +0,0 @@ -use core::marker::PhantomData; - -use stm32_metapac::rcc::vals::Timpre; - -use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw}; -use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::{set_freqs, Clocks}; -use crate::time::Hertz; -use crate::{peripherals, Peripheral}; - -/// HSI speed -pub const HSI_FREQ: Hertz = Hertz(64_000_000); - -/// CSI speed -pub const CSI_FREQ: Hertz = Hertz(4_000_000); - -/// HSI48 speed -pub const HSI48_FREQ: Hertz = Hertz(48_000_000); - -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); - -const VCO_MIN: u32 = 150_000_000; -const VCO_MAX: u32 = 420_000_000; -const VCO_WIDE_MIN: u32 = 128_000_000; -const VCO_WIDE_MAX: u32 = 560_000_000; - -pub use super::bus::{AHBPrescaler, APBPrescaler}; -pub use crate::pac::pwr::vals::Vos as VoltageScale; - -pub enum HseMode { - /// crystal/ceramic oscillator (HSEBYP=0) - Oscillator, - /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) - BypassAnalog, - /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) - BypassDigital, -} - -pub struct Hse { - /// HSE frequency. - pub freq: Hertz, - /// HSE mode. - pub mode: HseMode, -} - -pub enum Hsi { - /// 64Mhz - Mhz64, - /// 32Mhz (divided by 2) - Mhz32, - /// 16Mhz (divided by 4) - Mhz16, - /// 8Mhz (divided by 8) - Mhz8, -} - -pub enum Sysclk { - /// HSI selected as sysclk - HSI, - /// HSE selected as sysclk - HSE, - /// CSI selected as sysclk - CSI, - /// PLL1_P selected as sysclk - Pll1P, -} - -pub enum PllSource { - Hsi, - Csi, - Hse, -} - -pub struct Pll { - /// Source clock selection. - pub source: PllSource, - - /// PLL pre-divider (DIVM). Must be between 1 and 63. - pub prediv: u8, - - /// PLL multiplication factor. Must be between 4 and 512. - pub mul: u16, - - /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. - /// On PLL1, it must be even (in particular, it cannot be 1.) - pub divp: Option, - /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. - pub divq: Option, - /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. - pub divr: Option, -} - -fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { - match (tim, apb) { - // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a - // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 - (TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk, - (TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk, - (TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32, - (TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32, - (TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32, - // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2 - // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2 - // this makes NO SENSE and is different than in the H7. Mistake in the RM?? - (TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk * 2u32, - (TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk, - (TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk / 2u32, - (TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32, - (TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32, - - _ => unreachable!(), - } -} - -/// APB prescaler -#[derive(Clone, Copy)] -pub enum TimerPrescaler { - DefaultX2, - DefaultX4, -} - -impl From for Timpre { - fn from(value: TimerPrescaler) -> Self { - match value { - TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2, - TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4, - } - } -} - -/// Configuration of the core clocks -#[non_exhaustive] -pub struct Config { - pub hsi: Option, - pub hse: Option, - pub csi: bool, - pub hsi48: bool, - pub sys: Sysclk, - - pub pll1: Option, - pub pll2: Option, - #[cfg(rcc_h5)] - pub pll3: Option, - - pub ahb_pre: AHBPrescaler, - pub apb1_pre: APBPrescaler, - pub apb2_pre: APBPrescaler, - pub apb3_pre: APBPrescaler, - pub timer_prescaler: TimerPrescaler, - - pub voltage_scale: VoltageScale, -} - -impl Default for Config { - fn default() -> Self { - Self { - hsi: Some(Hsi::Mhz64), - hse: None, - csi: false, - hsi48: false, - sys: Sysclk::HSI, - pll1: None, - pll2: None, - #[cfg(rcc_h5)] - pll3: None, - - ahb_pre: AHBPrescaler::DIV1, - apb1_pre: APBPrescaler::DIV1, - apb2_pre: APBPrescaler::DIV1, - apb3_pre: APBPrescaler::DIV1, - timer_prescaler: TimerPrescaler::DefaultX2, - - voltage_scale: VoltageScale::SCALE3, - } - } -} - -pub(crate) mod sealed { - pub trait McoInstance { - type Source; - unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); - } -} - -pub trait McoInstance: sealed::McoInstance + 'static {} - -pin_trait!(McoPin, McoInstance); - -macro_rules! impl_peri { - ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { - impl sealed::McoInstance for peripherals::$peri { - type Source = $source; - - unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { - RCC.cfgr().modify(|w| { - w.$set_source(source); - w.$set_prescaler(prescaler); - }); - } - } - - impl McoInstance for peripherals::$peri {} - }; -} - -impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre); -impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre); - -pub struct Mco<'d, T: McoInstance> { - phantom: PhantomData<&'d mut T>, -} - -impl<'d, T: McoInstance> Mco<'d, T> { - pub fn new( - _peri: impl Peripheral

+ 'd, - _pin: impl Peripheral

> + 'd, - _source: T::Source, - ) -> Self { - todo!(); - } -} - -pub(crate) unsafe fn init(config: Config) { - let max_clk = match config.voltage_scale { - VoltageScale::SCALE0 => Hertz(250_000_000), - VoltageScale::SCALE1 => Hertz(200_000_000), - VoltageScale::SCALE2 => Hertz(150_000_000), - VoltageScale::SCALE3 => Hertz(100_000_000), - }; - - // Configure voltage scale. - PWR.voscr().modify(|w| w.set_vos(config.voltage_scale)); - while !PWR.vossr().read().vosrdy() {} - - // Configure HSI - let hsi = match config.hsi { - None => { - RCC.cr().modify(|w| w.set_hsion(false)); - None - } - Some(hsi) => { - let (freq, hsidiv) = match hsi { - Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1), - Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2), - Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4), - Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8), - }; - RCC.cr().modify(|w| { - w.set_hsidiv(hsidiv); - w.set_hsion(true); - }); - while !RCC.cr().read().hsirdy() {} - Some(freq) - } - }; - - // Configure HSE - let hse = match config.hse { - None => { - RCC.cr().modify(|w| w.set_hseon(false)); - None - } - Some(hse) => { - let (byp, ext) = match hse.mode { - HseMode::Oscillator => (false, Hseext::ANALOG), - HseMode::BypassAnalog => (true, Hseext::ANALOG), - HseMode::BypassDigital => (true, Hseext::DIGITAL), - }; - - RCC.cr().modify(|w| { - w.set_hsebyp(byp); - w.set_hseext(ext); - }); - RCC.cr().modify(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} - Some(hse.freq) - } - }; - - // Configure HSI48. - RCC.cr().modify(|w| w.set_hsi48on(config.hsi48)); - let _hsi48 = match config.hsi48 { - false => None, - true => { - while !RCC.cr().read().hsi48rdy() {} - Some(CSI_FREQ) - } - }; - - // Configure CSI. - RCC.cr().modify(|w| w.set_csion(config.csi)); - let csi = match config.csi { - false => None, - true => { - while !RCC.cr().read().csirdy() {} - Some(CSI_FREQ) - } - }; - - // Configure PLLs. - let pll_input = PllInput { csi, hse, hsi }; - let pll1 = init_pll(0, config.pll1, &pll_input); - let _pll2 = init_pll(1, config.pll2, &pll_input); - #[cfg(rcc_h5)] - let _pll3 = init_pll(2, config.pll3, &pll_input); - - // Configure sysclk - let (sys, sw) = match config.sys { - Sysclk::HSI => (unwrap!(hsi), Sw::HSI), - Sysclk::HSE => (unwrap!(hse), Sw::HSE), - Sysclk::CSI => (unwrap!(csi), Sw::CSI), - Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1), - }; - assert!(sys <= max_clk); - - let hclk = sys / config.ahb_pre; - - let apb1 = hclk / config.apb1_pre; - let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler); - let apb2 = hclk / config.apb2_pre; - let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler); - let apb3 = hclk / config.apb3_pre; - - flash_setup(hclk, config.voltage_scale); - - // Set hpre - let hpre = config.ahb_pre.into(); - RCC.cfgr2().modify(|w| w.set_hpre(hpre)); - while RCC.cfgr2().read().hpre() != hpre {} - - // set ppre - RCC.cfgr2().modify(|w| { - w.set_ppre1(config.apb1_pre.into()); - w.set_ppre2(config.apb2_pre.into()); - w.set_ppre3(config.apb3_pre.into()); - }); - - RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); - - RCC.cfgr().modify(|w| w.set_sw(sw)); - while RCC.cfgr().read().sws() != sw {} - - set_freqs(Clocks { - sys, - ahb1: hclk, - ahb2: hclk, - ahb3: hclk, - ahb4: hclk, - apb1, - apb2, - apb3, - apb1_tim, - apb2_tim, - adc: None, - }); -} - -struct PllInput { - hsi: Option, - hse: Option, - csi: Option, -} - -struct PllOutput { - p: Option, - #[allow(dead_code)] - q: Option, - #[allow(dead_code)] - r: Option, -} - -fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { - let Some(config) = config else { - // Stop PLL - RCC.cr().modify(|w| w.set_pllon(num, false)); - while RCC.cr().read().pllrdy(num) {} - - // "To save power when PLL1 is not used, the value of PLL1M must be set to 0."" - RCC.pllcfgr(num).write(|w| { - w.set_divm(0); - }); - - return PllOutput { - p: None, - q: None, - r: None, - }; - }; - - assert!(1 <= config.prediv && config.prediv <= 63); - assert!(4 <= config.mul && config.mul <= 512); - - let (in_clk, src) = match config.source { - PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI), - PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE), - PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI), - }; - - let ref_clk = in_clk / config.prediv as u32; - - let ref_range = match ref_clk.0 { - ..=1_999_999 => Pllrge::RANGE1, - ..=3_999_999 => Pllrge::RANGE2, - ..=7_999_999 => Pllrge::RANGE4, - ..=16_000_000 => Pllrge::RANGE8, - x => panic!("pll ref_clk out of range: {} mhz", x), - }; - - // The smaller range (150 to 420 MHz) must - // be chosen when the reference clock frequency is lower than 2 MHz. - let wide_allowed = ref_range != Pllrge::RANGE1; - - let vco_clk = ref_clk * config.mul; - let vco_range = match vco_clk.0 { - VCO_MIN..=VCO_MAX => Pllvcosel::MEDIUMVCO, - VCO_WIDE_MIN..=VCO_WIDE_MAX if wide_allowed => Pllvcosel::WIDEVCO, - x => panic!("pll vco_clk out of range: {} mhz", x), - }; - - let p = config.divp.map(|div| { - assert!(1 <= div && div <= 128); - if num == 0 { - // on PLL1, DIVP must be even. - assert!(div % 2 == 0); - } - - vco_clk / div - }); - let q = config.divq.map(|div| { - assert!(1 <= div && div <= 128); - vco_clk / div - }); - let r = config.divr.map(|div| { - assert!(1 <= div && div <= 128); - vco_clk / div - }); - - RCC.pllcfgr(num).write(|w| { - w.set_pllsrc(src); - w.set_divm(config.prediv); - w.set_pllvcosel(vco_range); - w.set_pllrge(ref_range); - w.set_pllfracen(false); - w.set_pllpen(p.is_some()); - w.set_pllqen(q.is_some()); - w.set_pllren(r.is_some()); - }); - RCC.plldivr(num).write(|w| { - w.set_plln(config.mul - 1); - w.set_pllp((config.divp.unwrap_or(1) - 1) as u8); - w.set_pllq((config.divq.unwrap_or(1) - 1) as u8); - w.set_pllr((config.divr.unwrap_or(1) - 1) as u8); - }); - - RCC.cr().modify(|w| w.set_pllon(num, true)); - while !RCC.cr().read().pllrdy(num) {} - - PllOutput { p, q, r } -} - -fn flash_setup(clk: Hertz, vos: VoltageScale) { - // RM0481 Rev 1, table 37 - // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0 - // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz - // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz - // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz - // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz - // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz - // 5 2 170 to 200 MHz 210 to 250 MHz - - // See RM0433 Rev 7 Table 17. FLASH recommended number of wait - // states and programming delay - let (latency, wrhighfreq) = match (vos, clk.0) { - (VoltageScale::SCALE0, ..=42_000_000) => (0, 0), - (VoltageScale::SCALE0, ..=84_000_000) => (1, 0), - (VoltageScale::SCALE0, ..=126_000_000) => (2, 1), - (VoltageScale::SCALE0, ..=168_000_000) => (3, 1), - (VoltageScale::SCALE0, ..=210_000_000) => (4, 2), - (VoltageScale::SCALE0, ..=250_000_000) => (5, 2), - - (VoltageScale::SCALE1, ..=34_000_000) => (0, 0), - (VoltageScale::SCALE1, ..=68_000_000) => (1, 0), - (VoltageScale::SCALE1, ..=102_000_000) => (2, 1), - (VoltageScale::SCALE1, ..=136_000_000) => (3, 1), - (VoltageScale::SCALE1, ..=170_000_000) => (4, 2), - (VoltageScale::SCALE1, ..=200_000_000) => (5, 2), - - (VoltageScale::SCALE2, ..=30_000_000) => (0, 0), - (VoltageScale::SCALE2, ..=60_000_000) => (1, 0), - (VoltageScale::SCALE2, ..=90_000_000) => (2, 1), - (VoltageScale::SCALE2, ..=120_000_000) => (3, 1), - (VoltageScale::SCALE2, ..=150_000_000) => (4, 2), - - (VoltageScale::SCALE3, ..=20_000_000) => (0, 0), - (VoltageScale::SCALE3, ..=40_000_000) => (1, 0), - (VoltageScale::SCALE3, ..=60_000_000) => (2, 1), - (VoltageScale::SCALE3, ..=80_000_000) => (3, 1), - (VoltageScale::SCALE3, ..=100_000_000) => (4, 2), - - _ => unreachable!(), - }; - - debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); - - FLASH.acr().write(|w| { - w.set_wrhighfreq(wrhighfreq); - w.set_latency(latency); - }); - while FLASH.acr().read().latency() != latency {} -} diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs deleted file mode 100644 index ea26c26c..00000000 --- a/embassy-stm32/src/rcc/h7.rs +++ /dev/null @@ -1,934 +0,0 @@ -use core::marker::PhantomData; - -use embassy_hal_internal::into_ref; -use stm32_metapac::pwr::vals::Vos; -use stm32_metapac::rcc::vals::{Mco1, Mco2}; - -pub use self::pll::PllConfig; -use crate::gpio::sealed::AFType; -use crate::gpio::Speed; -use crate::pac::rcc::vals::{Adcsel, Ckpersel, Hpre, Hsidiv, Pllsrc, Ppre, Sw, Timpre}; -use crate::pac::{PWR, RCC, SYSCFG}; -use crate::rcc::{set_freqs, Clocks}; -use crate::time::Hertz; -use crate::{peripherals, Peripheral}; - -/// HSI speed -pub const HSI_FREQ: Hertz = Hertz(64_000_000); - -/// CSI speed -pub const CSI_FREQ: Hertz = Hertz(4_000_000); - -/// HSI48 speed -pub const HSI48_FREQ: Hertz = Hertz(48_000_000); - -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); - -#[derive(Clone, Copy)] -pub enum VoltageScale { - Scale0, - Scale1, - Scale2, - Scale3, -} - -#[derive(Clone, Copy)] -pub enum AdcClockSource { - Pll2PCk, - Pll3RCk, - PerCk, -} - -impl AdcClockSource { - pub fn adcsel(&self) -> Adcsel { - match self { - AdcClockSource::Pll2PCk => Adcsel::PLL2_P, - AdcClockSource::Pll3RCk => Adcsel::PLL3_R, - AdcClockSource::PerCk => Adcsel::PER, - } - } -} - -impl Default for AdcClockSource { - fn default() -> Self { - Self::Pll2PCk - } -} - -/// Core clock frequencies -#[derive(Clone, Copy)] -pub struct CoreClocks { - pub hclk: Hertz, - pub pclk1: Hertz, - pub pclk2: Hertz, - pub pclk3: Hertz, - pub pclk4: Hertz, - pub ppre1: u8, - pub ppre2: u8, - pub ppre3: u8, - pub ppre4: u8, - pub csi_ck: Option, - pub hsi_ck: Option, - pub hsi48_ck: Option, - pub lsi_ck: Option, - pub per_ck: Option, - pub hse_ck: Option, - pub pll1_p_ck: Option, - pub pll1_q_ck: Option, - pub pll1_r_ck: Option, - pub pll2_p_ck: Option, - pub pll2_q_ck: Option, - pub pll2_r_ck: Option, - pub pll3_p_ck: Option, - pub pll3_q_ck: Option, - pub pll3_r_ck: Option, - pub timx_ker_ck: Option, - pub timy_ker_ck: Option, - pub adc_ker_ck: Option, - pub sys_ck: Hertz, - pub c_ck: Hertz, -} - -/// Configuration of the core clocks -#[non_exhaustive] -pub struct Config { - pub hse: Option, - pub bypass_hse: bool, - pub sys_ck: Option, - pub per_ck: Option, - pub hclk: Option, - pub pclk1: Option, - pub pclk2: Option, - pub pclk3: Option, - pub pclk4: Option, - pub pll1: PllConfig, - pub pll2: PllConfig, - pub pll3: PllConfig, - pub adc_clock_source: AdcClockSource, - pub voltage_scale: VoltageScale, -} - -impl Default for Config { - fn default() -> Self { - Self { - hse: None, - bypass_hse: false, - sys_ck: None, - per_ck: None, - hclk: None, - pclk1: None, - pclk2: None, - pclk3: None, - pclk4: None, - pll1: Default::default(), - pll2: Default::default(), - pll3: Default::default(), - adc_clock_source: Default::default(), - voltage_scale: VoltageScale::Scale1, - } - } -} - -/// Setup traceclk -/// Returns a pll1_r_ck -fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) { - let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) { - // pll1_p_ck selected as system clock but pll1_r_ck not - // set. The traceclk mux is synchronous with the system - // clock mux, but has pll1_r_ck as an input. In order to - // keep traceclk running, we force a pll1_r_ck. - (true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)), - - // Either pll1 not selected as system clock, free choice - // of pll1_r_ck. Or pll1 is selected, assume user has set - // a suitable pll1_r_ck frequency. - _ => config.pll1.r_ck, - }; - config.pll1.r_ck = pll1_r_ck; -} - -/// Divider calculator for pclk 1 - 4 -/// -/// Returns real pclk, bits, ppre and the timer kernel clock -fn ppre_calculate( - requested_pclk: u32, - hclk: u32, - max_pclk: u32, - tim_pre: Option, -) -> (u32, u8, u8, Option) { - let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk { - 0 => panic!(), - 1 => (0b000, 1), - 2 => (0b100, 2), - 3..=5 => (0b101, 4), - 6..=11 => (0b110, 8), - _ => (0b111, 16), - }; - let real_pclk = hclk / u32::from(ppre); - assert!(real_pclk <= max_pclk); - - let tim_ker_clk = if let Some(tim_pre) = tim_pre { - let clk = match (bits, tim_pre) { - (0b101, Timpre::DEFAULTX2) => hclk / 2, - (0b110, Timpre::DEFAULTX4) => hclk / 2, - (0b110, Timpre::DEFAULTX2) => hclk / 4, - (0b111, Timpre::DEFAULTX4) => hclk / 4, - (0b111, Timpre::DEFAULTX2) => hclk / 8, - _ => hclk, - }; - Some(clk) - } else { - None - }; - (real_pclk, bits, ppre, tim_ker_clk) -} - -/// Setup sys_ck -/// Returns sys_ck frequency, and a pll1_p_ck -fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) { - // Compare available with wanted clocks - let sys_ck = config.sys_ck.unwrap_or(srcclk); - - if sys_ck != srcclk { - // The requested system clock is not the immediately available - // HSE/HSI clock. Perhaps there are other ways of obtaining - // the requested system clock (such as `HSIDIV`) but we will - // ignore those for now. - // - // Therefore we must use pll1_p_ck - let pll1_p_ck = match config.pll1.p_ck { - Some(p_ck) => { - assert!( - p_ck == sys_ck, - "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck" - ); - Some(p_ck) - } - None => Some(sys_ck), - }; - config.pll1.p_ck = pll1_p_ck; - - (sys_ck, true) - } else { - // sys_ck is derived directly from a source clock - // (HSE/HSI). pll1_p_ck can be as requested - (sys_ck, false) - } -} - -fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { - use crate::pac::FLASH; - - // ACLK in MHz, round down and subtract 1 from integers. eg. - // 61_999_999 -> 61MHz - // 62_000_000 -> 61MHz - // 62_000_001 -> 62MHz - let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000; - - // See RM0433 Rev 7 Table 17. FLASH recommended number of wait - // states and programming delay - #[cfg(flash_h7)] - let (wait_states, progr_delay) = match vos { - // VOS 0 range VCORE 1.26V - 1.40V - VoltageScale::Scale0 => match rcc_aclk_mhz { - 0..=69 => (0, 0), - 70..=139 => (1, 1), - 140..=184 => (2, 1), - 185..=209 => (2, 2), - 210..=224 => (3, 2), - 225..=239 => (4, 2), - _ => (7, 3), - }, - // VOS 1 range VCORE 1.15V - 1.26V - VoltageScale::Scale1 => match rcc_aclk_mhz { - 0..=69 => (0, 0), - 70..=139 => (1, 1), - 140..=184 => (2, 1), - 185..=209 => (2, 2), - 210..=224 => (3, 2), - _ => (7, 3), - }, - // VOS 2 range VCORE 1.05V - 1.15V - VoltageScale::Scale2 => match rcc_aclk_mhz { - 0..=54 => (0, 0), - 55..=109 => (1, 1), - 110..=164 => (2, 1), - 165..=224 => (3, 2), - _ => (7, 3), - }, - // VOS 3 range VCORE 0.95V - 1.05V - VoltageScale::Scale3 => match rcc_aclk_mhz { - 0..=44 => (0, 0), - 45..=89 => (1, 1), - 90..=134 => (2, 1), - 135..=179 => (3, 2), - 180..=224 => (4, 2), - _ => (7, 3), - }, - }; - - // See RM0455 Rev 10 Table 16. FLASH recommended number of wait - // states and programming delay - #[cfg(flash_h7ab)] - let (wait_states, progr_delay) = match vos { - // VOS 0 range VCORE 1.25V - 1.35V - VoltageScale::Scale0 => match rcc_aclk_mhz { - 0..=42 => (0, 0), - 43..=84 => (1, 0), - 85..=126 => (2, 1), - 127..=168 => (3, 1), - 169..=210 => (4, 2), - 211..=252 => (5, 2), - 253..=280 => (6, 3), - _ => (7, 3), - }, - // VOS 1 range VCORE 1.15V - 1.25V - VoltageScale::Scale1 => match rcc_aclk_mhz { - 0..=38 => (0, 0), - 39..=76 => (1, 0), - 77..=114 => (2, 1), - 115..=152 => (3, 1), - 153..=190 => (4, 2), - 191..=225 => (5, 2), - _ => (7, 3), - }, - // VOS 2 range VCORE 1.05V - 1.15V - VoltageScale::Scale2 => match rcc_aclk_mhz { - 0..=34 => (0, 0), - 35..=68 => (1, 0), - 69..=102 => (2, 1), - 103..=136 => (3, 1), - 137..=160 => (4, 2), - _ => (7, 3), - }, - // VOS 3 range VCORE 0.95V - 1.05V - VoltageScale::Scale3 => match rcc_aclk_mhz { - 0..=22 => (0, 0), - 23..=44 => (1, 0), - 45..=66 => (2, 1), - 67..=88 => (3, 1), - _ => (7, 3), - }, - }; - - FLASH.acr().write(|w| { - w.set_wrhighfreq(progr_delay); - w.set_latency(wait_states) - }); - while FLASH.acr().read().latency() != wait_states {} -} - -pub enum McoClock { - Disabled, - Bypassed, - Divided(u8), -} - -impl McoClock { - fn into_raw(&self) -> u8 { - match self { - McoClock::Disabled => 0, - McoClock::Bypassed => 1, - McoClock::Divided(divisor) => { - if *divisor > 15 { - panic!("Mco divisor must be less than 15. Refer to the reference manual for more information.") - } - *divisor - } - } - } -} - -#[derive(Copy, Clone)] -pub enum Mco1Source { - Hsi, - Lse, - Hse, - Pll1Q, - Hsi48, -} - -impl Default for Mco1Source { - fn default() -> Self { - Self::Hsi - } -} - -pub trait McoSource { - type Raw; - - fn into_raw(&self) -> Self::Raw; -} - -impl McoSource for Mco1Source { - type Raw = Mco1; - fn into_raw(&self) -> Self::Raw { - match self { - Mco1Source::Hsi => Mco1::HSI, - Mco1Source::Lse => Mco1::LSE, - Mco1Source::Hse => Mco1::HSE, - Mco1Source::Pll1Q => Mco1::PLL1_Q, - Mco1Source::Hsi48 => Mco1::HSI48, - } - } -} - -#[derive(Copy, Clone)] -pub enum Mco2Source { - SysClk, - Pll2Q, - Hse, - Pll1Q, - Csi, - Lsi, -} - -impl Default for Mco2Source { - fn default() -> Self { - Self::SysClk - } -} - -impl McoSource for Mco2Source { - type Raw = Mco2; - fn into_raw(&self) -> Self::Raw { - match self { - Mco2Source::SysClk => Mco2::SYSCLK, - Mco2Source::Pll2Q => Mco2::PLL2_P, - Mco2Source::Hse => Mco2::HSE, - Mco2Source::Pll1Q => Mco2::PLL1_P, - Mco2Source::Csi => Mco2::CSI, - Mco2Source::Lsi => Mco2::LSI, - } - } -} - -pub(crate) mod sealed { - pub trait McoInstance { - type Source; - unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); - } -} - -pub trait McoInstance: sealed::McoInstance + 'static {} - -pin_trait!(McoPin, McoInstance); - -macro_rules! impl_peri { - ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { - impl sealed::McoInstance for peripherals::$peri { - type Source = $source; - - unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { - RCC.cfgr().modify(|w| { - w.$set_source(source); - w.$set_prescaler(prescaler); - }); - } - } - - impl McoInstance for peripherals::$peri {} - }; -} - -impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre); -impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre); - -pub struct Mco<'d, T: McoInstance> { - phantom: PhantomData<&'d mut T>, -} - -impl<'d, T: McoInstance> Mco<'d, T> { - pub fn new( - _peri: impl Peripheral

+ 'd, - pin: impl Peripheral

> + 'd, - source: impl McoSource, - prescaler: McoClock, - ) -> Self { - into_ref!(pin); - - critical_section::with(|_| unsafe { - T::apply_clock_settings(source.into_raw(), prescaler.into_raw()); - pin.set_as_af(pin.af_num(), AFType::OutputPushPull); - pin.set_speed(Speed::VeryHigh); - }); - - Self { phantom: PhantomData } - } -} - -pub(crate) unsafe fn init(mut config: Config) { - // NB. The lower bytes of CR3 can only be written once after - // POR, and must be written with a valid combination. Refer to - // RM0433 Rev 7 6.8.4. This is partially enforced by dropping - // `self` at the end of this method, but of course we cannot - // know what happened between the previous POR and here. - #[cfg(pwr_h7rm0433)] - PWR.cr3().modify(|w| { - w.set_scuen(true); - w.set_ldoen(true); - w.set_bypass(false); - }); - - #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] - PWR.cr3().modify(|w| { - // hardcode "Direct SPMS" for now, this is what works on nucleos with the - // default solderbridge configuration. - w.set_sden(true); - w.set_ldoen(false); - }); - - // Validate the supply configuration. If you are stuck here, it is - // because the voltages on your board do not match those specified - // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset - // VOS = Scale 3, so check that the voltage on the VCAP pins = - // 1.0V. - info!("a"); - while !PWR.csr1().read().actvosrdy() {} - info!("b"); - - #[cfg(syscfg_h7)] - { - // in chips without the overdrive bit, we can go from any scale to any scale directly. - PWR.d3cr().modify(|w| { - w.set_vos(match config.voltage_scale { - VoltageScale::Scale0 => Vos::SCALE0, - VoltageScale::Scale1 => Vos::SCALE1, - VoltageScale::Scale2 => Vos::SCALE2, - VoltageScale::Scale3 => Vos::SCALE3, - }) - }); - while !PWR.d3cr().read().vosrdy() {} - } - - #[cfg(syscfg_h7od)] - { - match config.voltage_scale { - VoltageScale::Scale0 => { - // to go to scale0, we must go to Scale1 first... - PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1)); - while !PWR.d3cr().read().vosrdy() {} - - // Then enable overdrive. - critical_section::with(|_| { - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - SYSCFG.pwrcr().modify(|w| w.set_oden(1)); - }); - while !PWR.d3cr().read().vosrdy() {} - } - _ => { - // for all other scales, we can go directly. - PWR.d3cr().modify(|w| { - w.set_vos(match config.voltage_scale { - VoltageScale::Scale0 => unreachable!(), - VoltageScale::Scale1 => Vos::SCALE1, - VoltageScale::Scale2 => Vos::SCALE2, - VoltageScale::Scale3 => Vos::SCALE3, - }) - }); - while !PWR.d3cr().read().vosrdy() {} - } - } - } - - // Freeze the core clocks, returning a Core Clocks Distribution - // and Reset (CCDR) structure. The actual frequency of the clocks - // configured is returned in the `clocks` member of the CCDR - // structure. - // - // Note that `freeze` will never result in a clock _faster_ than - // that specified. It may result in a clock that is a factor of [1, - // 2) slower. - // - // `syscfg` is required to enable the I/O compensation cell. - // - // # Panics - // - // If a clock specification cannot be achieved within the - // hardware specification then this function will panic. This - // function may also panic if a clock specification can be - // achieved, but the mechanism for doing so is not yet - // implemented here. - - let srcclk = config.hse.unwrap_or(HSI_FREQ); // Available clocks - let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk); - - // Configure traceclk from PLL if needed - traceclk_setup(&mut config, sys_use_pll1_p); - - let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0); - let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1); - let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2); - - let sys_ck = if sys_use_pll1_p { - Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup - } else { - sys_ck - }; - - // This routine does not support HSIDIV != 1. To - // do so it would need to ensure all PLLxON bits are clear - // before changing the value of HSIDIV - let cr = RCC.cr().read(); - assert!(cr.hsion()); - assert!(cr.hsidiv() == Hsidiv::DIV1); - - RCC.csr().modify(|w| w.set_lsion(true)); - while !RCC.csr().read().lsirdy() {} - - // per_ck from HSI by default - let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) { - (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE - (_, Some(CSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI - _ => (HSI_FREQ, Ckpersel::HSI), // HSI - }; - - // D1 Core Prescaler - // Set to 1 - let d1cpre_bits = 0; - let d1cpre_div = 1; - let sys_d1cpre_ck = sys_ck.0 / d1cpre_div; - - // Refer to part datasheet "General operating conditions" - // table for (rev V). We do not assert checks for earlier - // revisions which may have lower limits. - let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match config.voltage_scale { - VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), - VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), - VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), - VoltageScale::Scale3 => (200_000_000, 100_000_000, 50_000_000), - }; - assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max); - - let rcc_hclk = config.hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2); - assert!(rcc_hclk <= rcc_hclk_max); - - // Estimate divisor - let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk { - 0 => panic!(), - 1 => (Hpre::DIV1, 1), - 2 => (Hpre::DIV2, 2), - 3..=5 => (Hpre::DIV4, 4), - 6..=11 => (Hpre::DIV8, 8), - 12..=39 => (Hpre::DIV16, 16), - 40..=95 => (Hpre::DIV64, 64), - 96..=191 => (Hpre::DIV128, 128), - 192..=383 => (Hpre::DIV256, 256), - _ => (Hpre::DIV512, 512), - }; - // Calculate real AXI and AHB clock - let rcc_hclk = sys_d1cpre_ck / hpre_div; - assert!(rcc_hclk <= rcc_hclk_max); - let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7 - // Timer prescaler selection - let timpre = Timpre::DEFAULTX2; - - let requested_pclk1 = config.pclk1.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) = - ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre)); - - let requested_pclk2 = config.pclk2.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) = - ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre)); - - let requested_pclk3 = config.pclk3.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk3, ppre3_bits, ppre3, _) = ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None); - - let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); - - // Start switching clocks ------------------- - - // Ensure CSI is on and stable - RCC.cr().modify(|w| w.set_csion(true)); - while !RCC.cr().read().csirdy() {} - - // Ensure HSI48 is on and stable - RCC.cr().modify(|w| w.set_hsi48on(true)); - while !RCC.cr().read().hsi48on() {} - - // XXX: support MCO ? - - let hse_ck = match config.hse { - Some(hse) => { - // Ensure HSE is on and stable - RCC.cr().modify(|w| { - w.set_hseon(true); - w.set_hsebyp(config.bypass_hse); - }); - while !RCC.cr().read().hserdy() {} - Some(hse) - } - None => None, - }; - - let pllsrc = if config.hse.is_some() { Pllsrc::HSE } else { Pllsrc::HSI }; - RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc)); - - let enable_pll = |pll| { - RCC.cr().modify(|w| w.set_pllon(pll, true)); - while !RCC.cr().read().pllrdy(pll) {} - }; - - if pll1_p_ck.is_some() { - enable_pll(0); - } - - if pll2_p_ck.is_some() { - enable_pll(1); - } - - if pll3_p_ck.is_some() { - enable_pll(2); - } - - // Core Prescaler / AHB Prescaler / APB3 Prescaler - RCC.d1cfgr().modify(|w| { - w.set_d1cpre(Hpre::from_bits(d1cpre_bits)); - w.set_d1ppre(Ppre::from_bits(ppre3_bits)); - w.set_hpre(hpre_bits) - }); - // Ensure core prescaler value is valid before future lower - // core voltage - while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {} - - flash_setup(rcc_aclk, config.voltage_scale); - - // APB1 / APB2 Prescaler - RCC.d2cfgr().modify(|w| { - w.set_d2ppre1(Ppre::from_bits(ppre1_bits)); - w.set_d2ppre2(Ppre::from_bits(ppre2_bits)); - }); - - // APB4 Prescaler - RCC.d3cfgr().modify(|w| w.set_d3ppre(Ppre::from_bits(ppre4_bits))); - - // Peripheral Clock (per_ck) - RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); - - // ADC clock MUX - RCC.d3ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel())); - - let adc_ker_ck = match config.adc_clock_source { - AdcClockSource::Pll2PCk => pll2_p_ck.map(Hertz), - AdcClockSource::Pll3RCk => pll3_r_ck.map(Hertz), - AdcClockSource::PerCk => Some(per_ck), - }; - - // Set timer clocks prescaler setting - RCC.cfgr().modify(|w| w.set_timpre(timpre)); - - // Select system clock source - let sw = match (sys_use_pll1_p, config.hse.is_some()) { - (true, _) => Sw::PLL1, - (false, true) => Sw::HSE, - _ => Sw::HSI, - }; - RCC.cfgr().modify(|w| w.set_sw(sw)); - while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} - - // IO compensation cell - Requires CSI clock and SYSCFG - assert!(RCC.cr().read().csirdy()); - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - - // Enable the compensation cell, using back-bias voltage code - // provide by the cell. - critical_section::with(|_| { - SYSCFG.cccsr().modify(|w| { - w.set_en(true); - w.set_cs(false); - w.set_hslv(false); - }) - }); - while !SYSCFG.cccsr().read().ready() {} - - let core_clocks = CoreClocks { - hclk: Hertz(rcc_hclk), - pclk1: Hertz(rcc_pclk1), - pclk2: Hertz(rcc_pclk2), - pclk3: Hertz(rcc_pclk3), - pclk4: Hertz(rcc_pclk4), - ppre1, - ppre2, - ppre3, - ppre4, - csi_ck: Some(CSI_FREQ), - hsi_ck: Some(HSI_FREQ), - hsi48_ck: Some(HSI48_FREQ), - lsi_ck: Some(LSI_FREQ), - per_ck: Some(per_ck), - hse_ck, - pll1_p_ck: pll1_p_ck.map(Hertz), - pll1_q_ck: pll1_q_ck.map(Hertz), - pll1_r_ck: pll1_r_ck.map(Hertz), - pll2_p_ck: pll2_p_ck.map(Hertz), - pll2_q_ck: pll2_q_ck.map(Hertz), - pll2_r_ck: pll2_r_ck.map(Hertz), - pll3_p_ck: pll3_p_ck.map(Hertz), - pll3_q_ck: pll3_q_ck.map(Hertz), - pll3_r_ck: pll3_r_ck.map(Hertz), - timx_ker_ck: rcc_timerx_ker_ck.map(Hertz), - timy_ker_ck: rcc_timery_ker_ck.map(Hertz), - adc_ker_ck, - sys_ck, - c_ck: Hertz(sys_d1cpre_ck), - }; - - set_freqs(Clocks { - sys: core_clocks.c_ck, - ahb1: core_clocks.hclk, - ahb2: core_clocks.hclk, - ahb3: core_clocks.hclk, - ahb4: core_clocks.hclk, - apb1: core_clocks.pclk1, - apb2: core_clocks.pclk2, - apb4: core_clocks.pclk4, - apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1), - apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2), - adc: core_clocks.adc_ker_ck, - }); -} - -mod pll { - use super::{Hertz, RCC}; - - const VCO_MIN: u32 = 150_000_000; - const VCO_MAX: u32 = 420_000_000; - - #[derive(Default)] - pub struct PllConfig { - pub p_ck: Option, - pub q_ck: Option, - pub r_ck: Option, - } - - pub(super) struct PllConfigResults { - pub ref_x_ck: u32, - pub pll_x_m: u32, - pub pll_x_p: u32, - pub vco_ck_target: u32, - } - - fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) { - let pll_x_p = if plln == 0 { - if output > VCO_MAX / 2 { - 1 - } else { - ((VCO_MAX / output) | 1) - 1 // Must be even or unity - } - } else { - // Specific to PLL2/3, will subtract 1 later - if output > VCO_MAX / 2 { - 1 - } else { - VCO_MAX / output - } - }; - - let vco_ck = output * pll_x_p; - - assert!(pll_x_p < 128); - assert!(vco_ck >= VCO_MIN); - assert!(vco_ck <= VCO_MAX); - - (vco_ck, pll_x_p) - } - - /// # Safety - /// - /// Must have exclusive access to the RCC register block - fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults { - use crate::pac::rcc::vals::{Pllrge, Pllvcosel}; - - let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln); - - // Input divisor, resulting in a reference clock in the range - // 1 to 2 MHz. Choose the highest reference clock (lowest m) - let pll_x_m = (pll_src + 1_999_999) / 2_000_000; - assert!(pll_x_m < 64); - - // Calculate resulting reference clock - let ref_x_ck = pll_src / pll_x_m; - assert!((1_000_000..=2_000_000).contains(&ref_x_ck)); - - RCC.pllcfgr().modify(|w| { - w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO); - w.set_pllrge(plln, Pllrge::RANGE1); - }); - PllConfigResults { - ref_x_ck, - pll_x_m, - pll_x_p, - vco_ck_target, - } - } - - /// # Safety - /// - /// Must have exclusive access to the RCC register block - pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option, Option, Option) { - use crate::pac::rcc::vals::Divp; - - match config.p_ck { - Some(requested_output) => { - let config_results = vco_setup(pll_src, requested_output.0, plln); - let PllConfigResults { - ref_x_ck, - pll_x_m, - pll_x_p, - vco_ck_target, - } = config_results; - - RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8)); - - // Feedback divider. Integer only - let pll_x_n = vco_ck_target / ref_x_ck; - assert!(pll_x_n >= 4); - assert!(pll_x_n <= 512); - RCC.plldivr(plln).modify(|w| w.set_divn1((pll_x_n - 1) as u16)); - - // No FRACN - RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false)); - let vco_ck = ref_x_ck * pll_x_n; - - RCC.plldivr(plln) - .modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8))); - RCC.pllcfgr().modify(|w| w.set_divpen(plln, true)); - - // Calulate additional output dividers - let q_ck = match config.q_ck { - Some(Hertz(ck)) if ck > 0 => { - let div = (vco_ck + ck - 1) / ck; - RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8)); - RCC.pllcfgr().modify(|w| w.set_divqen(plln, true)); - Some(vco_ck / div) - } - _ => None, - }; - let r_ck = match config.r_ck { - Some(Hertz(ck)) if ck > 0 => { - let div = (vco_ck + ck - 1) / ck; - RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8)); - RCC.pllcfgr().modify(|w| w.set_divren(plln, true)); - Some(vco_ck / div) - } - _ => None, - }; - - (Some(vco_ck / pll_x_p), q_ck, r_ck) - } - None => { - assert!( - config.q_ck.is_none(), - "Must set PLL P clock for Q clock to take effect!" - ); - assert!( - config.r_ck.is_none(), - "Must set PLL P clock for R clock to take effect!" - ); - (None, None, None) - } - } - } -} diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs new file mode 100644 index 00000000..2453ed82 --- /dev/null +++ b/embassy-stm32/src/rcc/mco.rs @@ -0,0 +1,71 @@ +use core::marker::PhantomData; + +use embassy_hal_internal::into_ref; + +use crate::gpio::sealed::AFType; +use crate::gpio::Speed; +pub use crate::pac::rcc::vals::{Mco1 as Mco1Source, Mco2 as Mco2Source}; +use crate::pac::RCC; +use crate::{peripherals, Peripheral}; + +pub(crate) mod sealed { + pub trait McoInstance { + type Source; + unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); + } +} + +pub trait McoInstance: sealed::McoInstance + 'static {} + +pin_trait!(McoPin, McoInstance); + +macro_rules! impl_peri { + ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { + impl sealed::McoInstance for peripherals::$peri { + type Source = $source; + + unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { + RCC.cfgr().modify(|w| { + w.$set_source(source); + w.$set_prescaler(prescaler); + }); + } + } + + impl McoInstance for peripherals::$peri {} + }; +} + +impl_peri!(MCO1, Mco1Source, set_mco1, set_mco1pre); +impl_peri!(MCO2, Mco2Source, set_mco2, set_mco2pre); + +pub struct Mco<'d, T: McoInstance> { + phantom: PhantomData<&'d mut T>, +} + +impl<'d, T: McoInstance> Mco<'d, T> { + /// Create a new MCO instance. + /// + /// `prescaler` must be between 1 and 15. + pub fn new( + _peri: impl Peripheral

+ 'd, + pin: impl Peripheral

> + 'd, + source: T::Source, + prescaler: u8, + ) -> Self { + into_ref!(pin); + + assert!( + 1 <= prescaler && prescaler <= 15, + "Mco prescaler must be between 1 and 15. Refer to the reference manual for more information." + ); + + critical_section::with(|_| unsafe { + T::apply_clock_settings(source, prescaler); + pin.set_as_af(pin.af_num(), AFType::OutputPushPull); + pin.set_speed(Speed::VeryHigh); + }); + + Self { phantom: PhantomData } + } +} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index ff9b9bac..0d6b0e30 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,12 +1,17 @@ #![macro_use] -pub(crate) mod bd; -pub mod bus; use core::mem::MaybeUninit; pub use crate::rcc::bd::RtcClockSource; use crate::time::Hertz; +pub(crate) mod bd; +mod bus; +#[cfg(any(stm32h5, stm32h7))] +mod mco; +#[cfg(any(stm32h5, stm32h7))] +pub use mco::*; + #[cfg_attr(rcc_f0, path = "f0.rs")] #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] #[cfg_attr(rcc_f2, path = "f2.rs")] @@ -16,7 +21,7 @@ use crate::time::Hertz; #[cfg_attr(rcc_c0, path = "c0.rs")] #[cfg_attr(rcc_g0, path = "g0.rs")] #[cfg_attr(rcc_g4, path = "g4.rs")] -#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")] +#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")] #[cfg_attr(rcc_l0, path = "l0.rs")] #[cfg_attr(rcc_l1, path = "l1.rs")] #[cfg_attr(rcc_l4, path = "l4.rs")] @@ -25,7 +30,6 @@ use crate::time::Hertz; #[cfg_attr(rcc_wb, path = "wb.rs")] #[cfg_attr(rcc_wba, path = "wba.rs")] #[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] -#[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")] mod _version; pub use _version::*; #[cfg(feature = "low-power")] @@ -53,7 +57,7 @@ pub struct Clocks { pub apb2: Hertz, #[cfg(not(any(rcc_c0, rcc_g0)))] pub apb2_tim: Hertz, - #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_u5))] + #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))] pub apb3: Hertz, #[cfg(any(rcc_h7, rcc_h7ab))] pub apb4: Hertz, diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 5f1e62d0..16bf5d94 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -100,6 +100,7 @@ async fn main(spawner: Spawner) -> ! { let r = socket.connect(remote_endpoint).await; if let Err(e) = r { info!("connect error: {:?}", e); + Timer::after(Duration::from_secs(1)).await; continue; } info!("connected!"); @@ -108,7 +109,7 @@ async fn main(spawner: Spawner) -> ! { let r = socket.write_all(&buf).await; if let Err(e) = r { info!("write error: {:?}", e); - continue; + break; } Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 01c38106..93c97c8e 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -101,6 +101,7 @@ async fn main(spawner: Spawner) -> ! { let r = socket.connect(remote_endpoint).await; if let Err(e) = r { info!("connect error: {:?}", e); + Timer::after(Duration::from_secs(1)).await; continue; } info!("connected!"); @@ -109,7 +110,7 @@ async fn main(spawner: Spawner) -> ! { let r = socket.write_all(&buf).await; if let Err(e) = r { info!("write error: {:?}", e); - continue; + break; } Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 41ef2aca..4e92d064 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -53,7 +53,7 @@ async fn main(spawner: Spawner) -> ! { config.rcc.apb2_pre = APBPrescaler::DIV1; config.rcc.apb3_pre = APBPrescaler::DIV1; config.rcc.sys = Sysclk::Pll1P; - config.rcc.voltage_scale = VoltageScale::SCALE0; + config.rcc.voltage_scale = VoltageScale::Scale0; let p = embassy_stm32::init(config); info!("Hello World!"); @@ -128,7 +128,7 @@ async fn main(spawner: Spawner) -> ! { let r = socket.write_all(b"Hello\n").await; if let Err(e) = r { info!("write error: {:?}", e); - continue; + break; } Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 63c694af..cbe540a0 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb2_pre = APBPrescaler::DIV2; config.rcc.apb3_pre = APBPrescaler::DIV4; config.rcc.sys = Sysclk::Pll1P; - config.rcc.voltage_scale = VoltageScale::SCALE0; + config.rcc.voltage_scale = VoltageScale::Scale0; let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index 0e1e28c7..77922d4b 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -5,8 +5,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; -use embassy_stm32::rcc::AdcClockSource; -use embassy_stm32::time::mhz; use embassy_stm32::Config; use embassy_time::{Delay, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -14,10 +12,34 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(200)); - config.rcc.per_ck = Some(mhz(64)); - config.rcc.adc_clock_source = AdcClockSource::PerCk; + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: Some(8), // SPI1 cksel defaults to pll1_q + divr: None, + }); + config.rcc.pll2 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(8), // 100mhz + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + } let mut p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index 6f75a063..de8ddc29 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs @@ -6,8 +6,8 @@ use embassy_executor::Spawner; use embassy_stm32::dcmi::{self, *}; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::i2c::I2c; -use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; -use embassy_stm32::time::{khz, mhz}; +use embassy_stm32::rcc::{Mco, Mco1Source}; +use embassy_stm32::time::khz; use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; use embassy_time::{Duration, Timer}; use ov7725::*; @@ -26,17 +26,30 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(400)); - config.rcc.pll1.q_ck = Some(mhz(100)); - config.rcc.pclk1 = Some(mhz(100)); - config.rcc.pclk2 = Some(mhz(100)); - config.rcc.pclk3 = Some(mhz(100)); - config.rcc.pclk4 = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: Some(8), // 100mhz + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } let p = embassy_stm32::init(config); defmt::info!("Hello World!"); - let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(3)); + let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 3); let mut led = Output::new(p.PE3, Level::High, Speed::Low); let cam_i2c = I2c::new( diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index ee078286..93df7a31 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -6,7 +6,6 @@ use cortex_m_rt::entry; use defmt::*; use embassy_stm32::dac::{DacCh1, DacChannel, Value}; use embassy_stm32::dma::NoDma; -use embassy_stm32::time::mhz; use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; @@ -15,9 +14,34 @@ fn main() -> ! { info!("Hello World, dude!"); let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(200)); - config.rcc.pll1.q_ck = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: Some(8), // SPI1 cksel defaults to pll1_q + divr: None, + }); + config.rcc.pll2 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(8), // 100mhz + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + } let p = embassy_stm32::init(config); let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index a9cb5d1e..8c921abc 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -8,7 +8,7 @@ use embassy_stm32::dac::{DacChannel, ValueArray}; use embassy_stm32::pac::timer::vals::{Mms, Opm}; use embassy_stm32::peripherals::{TIM6, TIM7}; use embassy_stm32::rcc::low_level::RccPeripheral; -use embassy_stm32::time::{mhz, Hertz}; +use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Basic16bitInstance; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; @@ -22,9 +22,34 @@ pub type Dac2Type = #[embassy_executor::main] async fn main(spawner: Spawner) { let mut config = embassy_stm32::Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(100)); - config.rcc.pll1.q_ck = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: Some(8), // SPI1 cksel defaults to pll1_q + divr: None, + }); + config.rcc.pll2 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(8), // 100mhz + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + config.rcc.adc_clock_source = AdcClockSource::PLL2_P; + } // Initialize the board and obtain a Peripherals instance let p: embassy_stm32::Peripherals = embassy_stm32::init(config); diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index e691c6d0..1b5d71ed 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -10,7 +10,6 @@ use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; -use embassy_stm32::time::mhz; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; @@ -33,9 +32,27 @@ async fn net_task(stack: &'static Stack) -> ! { #[embassy_executor::main] async fn main(spawner: Spawner) -> ! { let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(200)); - config.rcc.pll1.q_ck = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.hsi48 = true; // needed for RNG + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } let p = embassy_stm32::init(config); info!("Hello World!"); @@ -102,6 +119,7 @@ async fn main(spawner: Spawner) -> ! { let r = socket.connect(remote_endpoint).await; if let Err(e) = r { info!("connect error: {:?}", e); + Timer::after(Duration::from_secs(1)).await; continue; } info!("connected!"); @@ -109,7 +127,7 @@ async fn main(spawner: Spawner) -> ! { let r = socket.write_all(b"Hello\n").await; if let Err(e) = r { info!("write error: {:?}", e); - continue; + break; } Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index ebef54c3..3abd31c7 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -10,7 +10,6 @@ use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; -use embassy_stm32::time::mhz; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; @@ -34,9 +33,27 @@ async fn net_task(stack: &'static Stack) -> ! { #[embassy_executor::main] async fn main(spawner: Spawner) -> ! { let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(200)); - config.rcc.pll1.q_ck = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.hsi48 = true; // needed for RNG + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } let p = embassy_stm32::init(config); info!("Hello World!"); @@ -108,7 +125,7 @@ async fn main(spawner: Spawner) -> ! { let r = connection.write_all(b"Hello\n").await; if let Err(e) = r { info!("write error: {:?}", e); - continue; + break; } Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/stm32h7/src/bin/fmc.rs b/examples/stm32h7/src/bin/fmc.rs index 85c690fe..de0b351d 100644 --- a/examples/stm32h7/src/bin/fmc.rs +++ b/examples/stm32h7/src/bin/fmc.rs @@ -5,7 +5,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::fmc::Fmc; -use embassy_stm32::time::mhz; use embassy_stm32::Config; use embassy_time::{Delay, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -13,9 +12,26 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(200)); - config.rcc.pll1.q_ck = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: Some(8), // 100mhz + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 45b0872b..a1e955c3 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -6,7 +6,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::low_level::AFType; use embassy_stm32::gpio::Speed; -use embassy_stm32::time::{khz, mhz, Hertz}; +use embassy_stm32::time::{khz, Hertz}; use embassy_stm32::timer::*; use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; use embassy_time::{Duration, Timer}; @@ -15,13 +15,27 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(400)); - config.rcc.pll1.q_ck = Some(mhz(100)); - config.rcc.pclk1 = Some(mhz(100)); - config.rcc.pclk2 = Some(mhz(100)); - config.rcc.pclk3 = Some(mhz(100)); - config.rcc.pclk4 = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.hsi48 = true; // needed for RNG + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: Some(8), // 100 Mhz + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32h7/src/bin/mco.rs b/examples/stm32h7/src/bin/mco.rs index 036455d5..9d6d805a 100644 --- a/examples/stm32h7/src/bin/mco.rs +++ b/examples/stm32h7/src/bin/mco.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; +use embassy_stm32::rcc::{Mco, Mco1Source}; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) { let mut led = Output::new(p.PB14, Level::High, Speed::Low); - let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(8)); + let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 8); loop { info!("high"); diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index aa5ec1bc..5c8e57aa 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; -use embassy_stm32::time::{khz, mhz}; +use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; use embassy_stm32::timer::Channel; use embassy_stm32::Config; @@ -15,13 +15,26 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(400)); - config.rcc.pll1.q_ck = Some(mhz(100)); - config.rcc.pclk1 = Some(mhz(100)); - config.rcc.pclk2 = Some(mhz(100)); - config.rcc.pclk3 = Some(mhz(100)); - config.rcc.pclk4 = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32h7/src/bin/rng.rs b/examples/stm32h7/src/bin/rng.rs index 7c8c50ec..af1d6ebb 100644 --- a/examples/stm32h7/src/bin/rng.rs +++ b/examples/stm32h7/src/bin/rng.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng}; +use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -14,7 +14,9 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let mut config = Config::default(); + config.rcc.hsi48 = true; // needed for RNG. + let p = embassy_stm32::init(config); info!("Hello World!"); let mut rng = Rng::new(p.RNG, Irqs); diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index ce91b6b1..752aefdf 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -16,7 +16,26 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(200)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: Some(4), // default clock chosen by SDMMCSEL. 200 Mhz + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs index 28bba2b8..9fe46f03 100644 --- a/examples/stm32h7/src/bin/spi.rs +++ b/examples/stm32h7/src/bin/spi.rs @@ -38,9 +38,26 @@ fn main() -> ! { info!("Hello World!"); let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(200)); - config.rcc.pll1.q_ck = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: Some(4), // used by SPI3. 100Mhz. + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } let p = embassy_stm32::init(config); let mut spi_config = spi::Config::default(); diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index f6e30cfa..88d65d5b 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs @@ -34,9 +34,26 @@ fn main() -> ! { info!("Hello World!"); let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(200)); - config.rcc.pll1.q_ck = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: Some(4), // used by SPI3. 100Mhz. + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } let p = embassy_stm32::init(config); let mut spi_config = spi::Config::default(); diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 97291f60..14de4356 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -4,7 +4,6 @@ use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_stm32::time::mhz; use embassy_stm32::usb_otg::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; @@ -22,9 +21,27 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut config = Config::default(); - config.rcc.sys_ck = Some(mhz(400)); - config.rcc.hclk = Some(mhz(200)); - config.rcc.pll1.q_ck = Some(mhz(100)); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.hsi48 = true; // needed for USB + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } let p = embassy_stm32::init(config); // Create the driver, from the HAL. diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index ca5cb43a..3a1b5c3e 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -31,9 +31,32 @@ pub fn config() -> Config { #[cfg(feature = "stm32h755zi")] { - config.rcc.sys_ck = Some(Hertz(400_000_000)); - config.rcc.pll1.q_ck = Some(Hertz(100_000_000)); - config.rcc.adc_clock_source = embassy_stm32::rcc::AdcClockSource::PerCk; + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(Hsi::Mhz64); + config.rcc.csi = true; + config.rcc.pll_src = PllSource::Hsi; + config.rcc.pll1 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(2), + divq: Some(8), // SPI1 cksel defaults to pll1_q + divr: None, + }); + config.rcc.pll2 = Some(Pll { + prediv: 4, + mul: 50, + divp: Some(8), // 100mhz + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::Pll1P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + config.rcc.adc_clock_source = AdcClockSource::PLL2_P; } #[cfg(feature = "stm32u585ai")] From 47175198c028d5782515737a019cb94bc1a61ad5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 22 Sep 2023 00:13:57 +0200 Subject: [PATCH 195/233] stm32: update metapac. --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 67f3f526..dd19db24 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -59,7 +59,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://ci.embassy.dev/jobs/7d2e0e63527f/artifacts/generated.git" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2bdbec6dc0fd5fcef5d9fb473de1fc5050a054c2" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://ci.embassy.dev/jobs/7d2e0e63527f/artifacts/generated.git", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2bdbec6dc0fd5fcef5d9fb473de1fc5050a054c2", default-features = false, features = ["metadata"]} [features] default = ["rt"] From 7cf327130e97f2569e1be73054a778ba5bf39d5b Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 21 Sep 2023 19:32:48 -0500 Subject: [PATCH 196/233] stm32/low-power: create one critical-section for all time ops --- embassy-stm32/src/rtc/v2.rs | 46 +++++++------- embassy-stm32/src/time_driver.rs | 100 ++++++++++++++++--------------- tests/stm32/src/bin/stop.rs | 33 ++++++---- 3 files changed, 99 insertions(+), 80 deletions(-) diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index aa3c31ee..d139f2f4 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -64,7 +64,11 @@ impl super::Rtc { #[cfg(feature = "low-power")] /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started - pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { + pub(crate) fn start_wakeup_alarm( + &self, + requested_duration: embassy_time::Duration, + cs: critical_section::CriticalSection, + ) { use embassy_time::{Duration, TICK_HZ}; #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] @@ -102,25 +106,13 @@ impl super::Rtc { self.instant(), ); - critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) - } - - #[cfg(feature = "low-power")] - pub(crate) fn enable_wakeup_line(&self) { - use crate::interrupt::typelevel::Interrupt; - use crate::pac::EXTI; - - ::WakeupInterrupt::unpend(); - unsafe { ::WakeupInterrupt::enable() }; - - EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); - EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none()) } #[cfg(feature = "low-power")] /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` /// was called, otherwise none - pub(crate) fn stop_wakeup_alarm(&self) -> Option { + pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option { use crate::interrupt::typelevel::Interrupt; trace!("rtc: stop wakeup alarm at {}", self.instant()); @@ -137,13 +129,23 @@ impl super::Rtc { ::WakeupInterrupt::unpend(); }); - critical_section::with(|cs| { - if let Some(stop_time) = self.stop_time.borrow(cs).take() { - Some(self.instant() - stop_time) - } else { - None - } - }) + if let Some(stop_time) = self.stop_time.borrow(cs).take() { + Some(self.instant() - stop_time) + } else { + None + } + } + + #[cfg(feature = "low-power")] + pub(crate) fn enable_wakeup_line(&self) { + use crate::interrupt::typelevel::Interrupt; + use crate::pac::EXTI; + + ::WakeupInterrupt::unpend(); + unsafe { ::WakeupInterrupt::enable() }; + + EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); } /// Applies the RTC config diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 887e54f6..5b01937f 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -266,32 +266,28 @@ impl RtcDriver { f(alarm.ctx.get()); } - #[cfg(feature = "low-power")] - /// Set the rtc but panic if it's already been set - pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { - critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())); - } + /* + Low-power private functions: all operate within a critical seciton + */ #[cfg(feature = "low-power")] /// Compute the approximate amount of time until the next alarm - fn time_until_next_alarm(&self) -> embassy_time::Duration { - critical_section::with(|cs| { - let now = self.now() + 32; + fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration { + let now = self.now() + 32; - embassy_time::Duration::from_ticks( - self.alarms - .borrow(cs) - .iter() - .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now)) - .min() - .unwrap_or(u64::MAX), - ) - }) + embassy_time::Duration::from_ticks( + self.alarms + .borrow(cs) + .iter() + .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now)) + .min() + .unwrap_or(u64::MAX), + ) } #[cfg(feature = "low-power")] /// Add the given offset to the current time - fn add_time(&self, offset: embassy_time::Duration) { + fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { let offset = offset.as_ticks(); let cnt = T::regs_gp16().cnt().read().cnt() as u32; let period = self.period.load(Ordering::SeqCst); @@ -322,51 +318,57 @@ impl RtcDriver { T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); // Now, recompute all alarms - critical_section::with(|cs| { - for i in 0..ALARM_COUNT { - let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; - let alarm = self.get_alarm(cs, alarm_handle); + for i in 0..ALARM_COUNT { + let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; + let alarm = self.get_alarm(cs, alarm_handle); - self.set_alarm(alarm_handle, alarm.timestamp.get()); - } - }) + self.set_alarm(alarm_handle, alarm.timestamp.get()); + } } #[cfg(feature = "low-power")] /// Stop the wakeup alarm, if enabled, and add the appropriate offset - fn stop_wakeup_alarm(&self) { - critical_section::with(|cs| { - if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm() { - self.add_time(offset); - } - }); + fn stop_wakeup_alarm(&self, cs: CriticalSection) { + if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) { + self.add_time(offset, cs); + } + } + + /* + Low-power public functions: all create a critical section + */ + #[cfg(feature = "low-power")] + /// Set the rtc but panic if it's already been set + pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { + critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())); } #[cfg(feature = "low-power")] /// Pause the timer if ready; return err if not pub(crate) fn pause_time(&self) -> Result<(), ()> { - /* - If the wakeup timer is currently running, then we need to stop it and - add the elapsed time to the current time - */ - self.stop_wakeup_alarm(); + critical_section::with(|cs| { + /* + If the wakeup timer is currently running, then we need to stop it and + add the elapsed time to the current time, as this will impact the result + of `time_until_next_alarm`. + */ + self.stop_wakeup_alarm(cs); - let time_until_next_alarm = self.time_until_next_alarm(); - if time_until_next_alarm < embassy_time::Duration::from_millis(250) { - Err(()) - } else { - critical_section::with(|cs| { + let time_until_next_alarm = self.time_until_next_alarm(cs); + if time_until_next_alarm < embassy_time::Duration::from_millis(250) { + Err(()) + } else { self.rtc .borrow(cs) .get() .unwrap() - .start_wakeup_alarm(time_until_next_alarm); - }); + .start_wakeup_alarm(time_until_next_alarm, cs); - T::regs_gp16().cr1().modify(|w| w.set_cen(false)); + T::regs_gp16().cr1().modify(|w| w.set_cen(false)); - Ok(()) - } + Ok(()) + } + }) } #[cfg(feature = "low-power")] @@ -378,9 +380,11 @@ impl RtcDriver { return; } - self.stop_wakeup_alarm(); + critical_section::with(|cs| { + self.stop_wakeup_alarm(cs); - T::regs_gp16().cr1().modify(|w| w.set_cen(true)); + T::regs_gp16().cr1().modify(|w| w.set_cen(true)); + }) } } diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index f60ab271..48d59b79 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -19,14 +19,32 @@ use static_cell::make_static; #[entry] fn main() -> ! { - let executor = Executor::take(); - executor.run(|spawner| { + Executor::take().run(|spawner| { unwrap!(spawner.spawn(async_main(spawner))); }); } #[embassy_executor::task] -async fn async_main(_spawner: Spawner) { +async fn task_1() { + for _ in 0..9 { + info!("task 1: waiting for 500ms..."); + Timer::after(Duration::from_millis(500)).await; + } +} + +#[embassy_executor::task] +async fn task_2() { + for _ in 0..5 { + info!("task 2: waiting for 1000ms..."); + Timer::after(Duration::from_millis(1000)).await; + } + + info!("Test OK"); + cortex_m::asm::bkpt(); +} + +#[embassy_executor::task] +async fn async_main(spawner: Spawner) { let mut config = config(); config.rcc.lse = Some(Hertz(32_768)); @@ -48,11 +66,6 @@ async fn async_main(_spawner: Spawner) { stop_with_rtc(rtc); - info!("Waiting..."); - Timer::after(Duration::from_secs(2)).await; - info!("Waiting..."); - Timer::after(Duration::from_secs(3)).await; - - info!("Test OK"); - cortex_m::asm::bkpt(); + spawner.spawn(task_1()).unwrap(); + spawner.spawn(task_2()).unwrap(); } From 2b7b7a917d0fc5917cb968c52bd19d710675f540 Mon Sep 17 00:00:00 2001 From: Nils Fitinghoff Date: Fri, 22 Sep 2023 16:12:57 +0300 Subject: [PATCH 197/233] spim: Fix SPIM with polling executors Co-authored-by: Priit Laes --- embassy-nrf/src/spim.rs | 67 +++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 99a195a6..a0d2c8eb 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -69,29 +69,13 @@ impl interrupt::typelevel::Handler for InterruptHandl let s = T::state(); #[cfg(feature = "nrf52832")] - // NRF32 Anomaly 109 workaround... NRF52832 - if r.intenset.read().started().is_enabled() && r.events_started.read().bits() != 0 { - // Handle the first "fake" transmission - r.events_started.reset(); - r.events_end.reset(); - - // Update DMA registers with correct rx/tx buffer sizes - r.rxd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) }); - r.txd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) }); - - // Disable interrupt for STARTED event... + if r.events_started.read().bits() != 0 { + s.waker.wake(); r.intenclr.write(|w| w.started().clear()); - // ... and start actual, hopefully glitch-free transmission - r.tasks_start.write(|w| unsafe { w.bits(1) }); - return; } if r.events_end.read().bits() != 0 { - s.end_waker.wake(); + s.waker.wake(); r.intenclr.write(|w| w.end().clear()); } } @@ -254,6 +238,9 @@ impl<'d, T: Instance> Spim<'d, T> { fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { self.prepare(rx, tx)?; + #[cfg(feature = "nrf52832")] + while let Poll::Pending = self.nrf52832_dma_workaround_status() {} + // Wait for 'end' event. while T::regs().events_end.read().bits() == 0 {} @@ -278,9 +265,19 @@ impl<'d, T: Instance> Spim<'d, T> { async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { self.prepare(rx, tx)?; + #[cfg(feature = "nrf52832")] + poll_fn(|cx| { + let s = T::state(); + + s.waker.register(cx.waker()); + + self.nrf52832_dma_workaround_status() + }) + .await; + // Wait for 'end' event. poll_fn(|cx| { - T::state().end_waker.register(cx.waker()); + T::state().waker.register(cx.waker()); if T::regs().events_end.read().bits() != 0 { return Poll::Ready(()); } @@ -371,6 +368,32 @@ impl<'d, T: Instance> Spim<'d, T> { pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> { self.async_inner_from_ram(&mut [], data).await } + + #[cfg(feature = "nrf52832")] + fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> { + let r = T::regs(); + if r.events_started.read().bits() != 0 { + let s = T::state(); + + // Handle the first "fake" transmission + r.events_started.reset(); + r.events_end.reset(); + + // Update DMA registers with correct rx/tx buffer sizes + r.rxd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) }); + r.txd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) }); + + r.intenset.write(|w| w.end().set()); + // ... and start actual, hopefully glitch-free transmission + r.tasks_start.write(|w| unsafe { w.bits(1) }); + return Poll::Ready(()); + } + Poll::Pending + } } impl<'d, T: Instance> Drop for Spim<'d, T> { @@ -403,7 +426,7 @@ pub(crate) mod sealed { use super::*; pub struct State { - pub end_waker: AtomicWaker, + pub waker: AtomicWaker, #[cfg(feature = "nrf52832")] pub rx: AtomicU8, #[cfg(feature = "nrf52832")] @@ -413,7 +436,7 @@ pub(crate) mod sealed { impl State { pub const fn new() -> Self { Self { - end_waker: AtomicWaker::new(), + waker: AtomicWaker::new(), #[cfg(feature = "nrf52832")] rx: AtomicU8::new(0), #[cfg(feature = "nrf52832")] From 6f83acc010786d89400426c3395f871ac7199d32 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 22 Sep 2023 17:30:09 +0300 Subject: [PATCH 198/233] Add separate work-around specific flag for DMA errata on NRF52832 --- embassy-nrf/Cargo.toml | 5 ++++- embassy-nrf/src/spim.rs | 21 ++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index eee92721..3c706b47 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -51,7 +51,7 @@ nrf52805 = ["nrf52805-pac", "_nrf52"] nrf52810 = ["nrf52810-pac", "_nrf52"] nrf52811 = ["nrf52811-pac", "_nrf52"] nrf52820 = ["nrf52820-pac", "_nrf52"] -nrf52832 = ["nrf52832-pac", "_nrf52"] +nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"] nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] nrf5340-app-s = ["_nrf5340-app", "_s"] @@ -90,6 +90,9 @@ _ppi = [] _dppi = [] _gpio-p1 = [] +# Errata workarounds +_nrf52832_anomaly_109 = [] + [dependencies] embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-sync = { version = "0.3.0", path = "../embassy-sync" } diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index a0d2c8eb..4828af43 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -68,7 +68,7 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] if r.events_started.read().bits() != 0 { s.waker.wake(); r.intenclr.write(|w| w.started().clear()); @@ -206,8 +206,7 @@ impl<'d, T: Instance> Spim<'d, T> { r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); - // ANOMALY 109 workaround - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] { let s = T::state(); @@ -238,7 +237,7 @@ impl<'d, T: Instance> Spim<'d, T> { fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { self.prepare(rx, tx)?; - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] while let Poll::Pending = self.nrf52832_dma_workaround_status() {} // Wait for 'end' event. @@ -265,7 +264,7 @@ impl<'d, T: Instance> Spim<'d, T> { async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { self.prepare(rx, tx)?; - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] poll_fn(|cx| { let s = T::state(); @@ -369,7 +368,7 @@ impl<'d, T: Instance> Spim<'d, T> { self.async_inner_from_ram(&mut [], data).await } - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> { let r = T::regs(); if r.events_started.read().bits() != 0 { @@ -418,7 +417,7 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { } pub(crate) mod sealed { - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] use core::sync::atomic::AtomicU8; use embassy_sync::waitqueue::AtomicWaker; @@ -427,9 +426,9 @@ pub(crate) mod sealed { pub struct State { pub waker: AtomicWaker, - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] pub rx: AtomicU8, - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] pub tx: AtomicU8, } @@ -437,9 +436,9 @@ pub(crate) mod sealed { pub const fn new() -> Self { Self { waker: AtomicWaker::new(), - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] rx: AtomicU8::new(0), - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] tx: AtomicU8::new(0), } } From c849620cd6bfc1aec6999109e818a91cb061a578 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 22 Sep 2023 15:35:20 -0500 Subject: [PATCH 199/233] stm32/lp: clamp requested_duration to avoid overflow --- embassy-stm32/src/rtc/v2.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index d139f2f4..05b85ef4 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -71,21 +71,27 @@ impl super::Rtc { ) { use embassy_time::{Duration, TICK_HZ}; + // Panic if the rcc mod knows we're not using low-power rtc #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); + /* + If the requested duration is u64::MAX, don't even set the alarm + + Otherwise clamp the requested duration to u32::MAX so that we can do math + */ + if requested_duration.as_ticks() == u64::MAX { + return; + } + + let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); let rtc_hz = Self::frequency().0 as u64; - let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; + let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); // adjust the rtc ticks to the prescaler and subtract one rtc tick let rtc_ticks = rtc_ticks / prescaler as u64; - let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { - u16::MAX - 1 - } else { - rtc_ticks as u16 - } - .saturating_sub(1); + let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16; self.write(false, |regs| { regs.cr().modify(|w| w.set_wute(false)); From 347ff186444d7b7d3dd1027d3428b891e870e6fc Mon Sep 17 00:00:00 2001 From: luveti <4952718+luveti@users.noreply.github.com> Date: Sun, 24 Sep 2023 01:11:58 -0400 Subject: [PATCH 200/233] stm32: fix rtc example lsi must be enabled otherwise a assertion fails --- examples/stm32f4/src/bin/rtc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs index 23ff8ac4..e3374600 100644 --- a/examples/stm32f4/src/bin/rtc.rs +++ b/examples/stm32f4/src/bin/rtc.rs @@ -13,6 +13,7 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); + config.rcc.lsi = true; config.rcc.rtc = Option::Some(RtcClockSource::LSI); let p = embassy_stm32::init(config); From 7d5e62d4a7764c80a9378e34e755239838081a00 Mon Sep 17 00:00:00 2001 From: ceekdee Date: Sun, 24 Sep 2023 10:33:03 -0500 Subject: [PATCH 201/233] Update for rust-lorawan and lora-phy version 2. --- embassy-lora/Cargo.toml | 4 ++-- examples/nrf52840/Cargo.toml | 5 +++-- examples/nrf52840/src/bin/lora_cad.rs | 4 +--- examples/nrf52840/src/bin/lora_lorawan.rs | 11 +++++------ examples/nrf52840/src/bin/lora_p2p_receive.rs | 6 ++---- .../src/bin/lora_p2p_receive_duty_cycle.rs | 8 ++------ examples/nrf52840/src/bin/lora_p2p_send.rs | 6 ++---- examples/rp/Cargo.toml | 5 +++-- examples/rp/src/bin/lora_lorawan.rs | 17 +++++------------ examples/rp/src/bin/lora_p2p_receive.rs | 12 ++---------- examples/rp/src/bin/lora_p2p_send.rs | 12 ++---------- examples/rp/src/bin/lora_p2p_send_multicore.rs | 11 ++--------- examples/stm32l0/Cargo.toml | 5 +++-- examples/stm32l0/src/bin/lora_cad.rs | 4 +--- examples/stm32l0/src/bin/lora_lorawan.rs | 11 +++++------ examples/stm32l0/src/bin/lora_p2p_receive.rs | 6 ++---- examples/stm32l0/src/bin/lora_p2p_send.rs | 6 ++---- examples/stm32wl/Cargo.toml | 5 +++-- examples/stm32wl/src/bin/lora_lorawan.rs | 11 +++++------ examples/stm32wl/src/bin/lora_p2p_receive.rs | 6 ++---- examples/stm32wl/src/bin/lora_p2p_send.rs | 6 ++---- 21 files changed, 56 insertions(+), 105 deletions(-) diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index 81b389d8..7022e935 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml @@ -27,8 +27,8 @@ embedded-hal-async = { version = "=1.0.0-rc.1" } embedded-hal = { version = "0.2", features = ["unproven"] } futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } -lora-phy = { version = "1" } +lora-phy = { version = "2" } lorawan-device = { version = "0.10.0", default-features = false, features = ["async"], optional = true } [patch.crates-io] -lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} +lorawan-device = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index a40a9dc1..d54847ff 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -38,7 +38,7 @@ embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defm embedded-io = { version = "0.5.0", features = ["defmt-03"] } embedded-io-async = { version = "0.5.0", optional = true, features = ["defmt-03"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } -lora-phy = { version = "1", optional = true } +lora-phy = { version = "2", optional = true } lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true } @@ -67,4 +67,5 @@ microfft = "0.5.0" debug = 2 [patch.crates-io] -lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} +lorawan-device = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} +lorawan = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} diff --git a/examples/nrf52840/src/bin/lora_cad.rs b/examples/nrf52840/src/bin/lora_cad.rs index beca061e..3a98133c 100644 --- a/examples/nrf52840/src/bin/lora_cad.rs +++ b/examples/nrf52840/src/bin/lora_cad.rs @@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) { let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { + match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); diff --git a/examples/nrf52840/src/bin/lora_lorawan.rs b/examples/nrf52840/src/bin/lora_lorawan.rs index c953680c..666330ba 100644 --- a/examples/nrf52840/src/bin/lora_lorawan.rs +++ b/examples/nrf52840/src/bin/lora_lorawan.rs @@ -20,6 +20,7 @@ use lora_phy::LoRa; use lorawan::default_crypto::DefaultFactory as Crypto; use lorawan_device::async_device::lora_radio::LoRaRadio; use lorawan_device::async_device::{region, Device, JoinMode}; +use lorawan_device::{AppEui, AppKey, DevEui}; use {defmt_rtt as _, panic_probe as _}; const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region @@ -47,10 +48,8 @@ async fn main(_spawner: Spawner) { let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); - let mut delay = Delay; - let lora = { - match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), true, &mut delay).await { + match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), true, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -68,9 +67,9 @@ async fn main(_spawner: Spawner) { // TODO: Adjust the EUI and Keys according to your network credentials match device .join(&JoinMode::OTAA { - deveui: [0, 0, 0, 0, 0, 0, 0, 0], - appeui: [0, 0, 0, 0, 0, 0, 0, 0], - appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + deveui: DevEui::from([0, 0, 0, 0, 0, 0, 0, 0]), + appeui: AppEui::from([0, 0, 0, 0, 0, 0, 0, 0]), + appkey: AppKey::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), }) .await { diff --git a/examples/nrf52840/src/bin/lora_p2p_receive.rs b/examples/nrf52840/src/bin/lora_p2p_receive.rs index 563fe42e..1d293c6b 100644 --- a/examples/nrf52840/src/bin/lora_p2p_receive.rs +++ b/examples/nrf52840/src/bin/lora_p2p_receive.rs @@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) { let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { + match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -88,7 +86,7 @@ async fn main(_spawner: Spawner) { }; match lora - .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32) + .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, None, false) .await { Ok(()) => {} diff --git a/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs index 1fd8f61a..eee4d20e 100644 --- a/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs +++ b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs @@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) { let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { + match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -92,14 +90,12 @@ async fn main(_spawner: Spawner) { .prepare_for_rx( &mdltn_params, &rx_pkt_params, + None, Some(&DutyCycleParams { rx_time: 300_000, // 300_000 units * 15.625 us/unit = 4.69 s sleep_time: 200_000, // 200_000 units * 15.625 us/unit = 3.13 s }), false, - false, - 0, - 0, ) .await { diff --git a/examples/nrf52840/src/bin/lora_p2p_send.rs b/examples/nrf52840/src/bin/lora_p2p_send.rs index 1c8bbc27..676221a2 100644 --- a/examples/nrf52840/src/bin/lora_p2p_send.rs +++ b/examples/nrf52840/src/bin/lora_p2p_send.rs @@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) { let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { + match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -97,7 +95,7 @@ async fn main(_spawner: Spawner) { } }; - match lora.sleep(&mut delay).await { + match lora.sleep(false).await { Ok(()) => info!("Sleep successful"), Err(err) => info!("Sleep unsuccessful = {}", err), } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 4b125ed8..5fe08fb0 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -17,7 +17,7 @@ embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", fea embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"] } -lora-phy = { version = "1" } +lora-phy = { version = "2" } lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"] } lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"] } cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } @@ -57,4 +57,5 @@ rand = { version = "0.8.5", default-features = false } debug = 2 [patch.crates-io] -lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} +lorawan-device = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} +lorawan = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} diff --git a/examples/rp/src/bin/lora_lorawan.rs b/examples/rp/src/bin/lora_lorawan.rs index d631fafa..e7e81863 100644 --- a/examples/rp/src/bin/lora_lorawan.rs +++ b/examples/rp/src/bin/lora_lorawan.rs @@ -19,6 +19,7 @@ use lora_phy::LoRa; use lorawan::default_crypto::DefaultFactory as Crypto; use lorawan_device::async_device::lora_radio::LoRaRadio; use lorawan_device::async_device::{region, Device, JoinMode}; +use lorawan_device::{AppEui, AppKey, DevEui}; use {defmt_rtt as _, panic_probe as _}; const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region @@ -39,16 +40,8 @@ async fn main(_spawner: Spawner) { let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap(); - let mut delay = Delay; - let lora = { - match LoRa::new( - SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), - true, - &mut delay, - ) - .await - { + match LoRa::new(SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), true, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -66,9 +59,9 @@ async fn main(_spawner: Spawner) { // TODO: Adjust the EUI and Keys according to your network credentials match device .join(&JoinMode::OTAA { - deveui: [0, 0, 0, 0, 0, 0, 0, 0], - appeui: [0, 0, 0, 0, 0, 0, 0, 0], - appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + deveui: DevEui::from([0, 0, 0, 0, 0, 0, 0, 0]), + appeui: AppEui::from([0, 0, 0, 0, 0, 0, 0, 0]), + appkey: AppKey::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), }) .await { diff --git a/examples/rp/src/bin/lora_p2p_receive.rs b/examples/rp/src/bin/lora_p2p_receive.rs index 396d669d..5891826f 100644 --- a/examples/rp/src/bin/lora_p2p_receive.rs +++ b/examples/rp/src/bin/lora_p2p_receive.rs @@ -35,16 +35,8 @@ async fn main(_spawner: Spawner) { let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new( - SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), - false, - &mut delay, - ) - .await - { + match LoRa::new(SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -83,7 +75,7 @@ async fn main(_spawner: Spawner) { }; match lora - .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32) + .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, None, false) .await { Ok(()) => {} diff --git a/examples/rp/src/bin/lora_p2p_send.rs b/examples/rp/src/bin/lora_p2p_send.rs index a0f70fa5..94bdb4e9 100644 --- a/examples/rp/src/bin/lora_p2p_send.rs +++ b/examples/rp/src/bin/lora_p2p_send.rs @@ -35,16 +35,8 @@ async fn main(_spawner: Spawner) { let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new( - SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), - false, - &mut delay, - ) - .await - { + match LoRa::new(SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -97,7 +89,7 @@ async fn main(_spawner: Spawner) { } }; - match lora.sleep(&mut delay).await { + match lora.sleep(false).await { Ok(()) => info!("Sleep successful"), Err(err) => info!("Sleep unsuccessful = {}", err), } diff --git a/examples/rp/src/bin/lora_p2p_send_multicore.rs b/examples/rp/src/bin/lora_p2p_send_multicore.rs index b54cc92f..e31aa62a 100644 --- a/examples/rp/src/bin/lora_p2p_send_multicore.rs +++ b/examples/rp/src/bin/lora_p2p_send_multicore.rs @@ -69,16 +69,9 @@ async fn core1_task( iv: GenericSx126xInterfaceVariant, Input<'static, AnyPin>>, ) { info!("Hello from core 1"); - let mut delay = Delay; let mut lora = { - match LoRa::new( - SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), - false, - &mut delay, - ) - .await - { + match LoRa::new(SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -132,7 +125,7 @@ async fn core1_task( } }; - match lora.sleep(&mut delay).await { + match lora.sleep(false).await { Ok(()) => info!("Sleep successful"), Err(err) => info!("Sleep unsuccessful = {}", err), } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index befebcce..71ec4f5a 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -16,7 +16,7 @@ embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } -lora-phy = { version = "1", optional = true } +lora-phy = { version = "2", optional = true } lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } @@ -39,4 +39,5 @@ static_cell = "1.1" debug = 2 [patch.crates-io] -lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} +lorawan-device = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} +lorawan = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} diff --git a/examples/stm32l0/src/bin/lora_cad.rs b/examples/stm32l0/src/bin/lora_cad.rs index 7729b416..900848fd 100644 --- a/examples/stm32l0/src/bin/lora_cad.rs +++ b/examples/stm32l0/src/bin/lora_cad.rs @@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) { let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, &mut delay).await { + match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); diff --git a/examples/stm32l0/src/bin/lora_lorawan.rs b/examples/stm32l0/src/bin/lora_lorawan.rs index 10608aeb..7a93737e 100644 --- a/examples/stm32l0/src/bin/lora_lorawan.rs +++ b/examples/stm32l0/src/bin/lora_lorawan.rs @@ -21,6 +21,7 @@ use lora_phy::LoRa; use lorawan::default_crypto::DefaultFactory as Crypto; use lorawan_device::async_device::lora_radio::LoRaRadio; use lorawan_device::async_device::{region, Device, JoinMode}; +use lorawan_device::{AppEui, AppKey, DevEui}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -50,10 +51,8 @@ async fn main(_spawner: Spawner) { let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap(); - let mut delay = Delay; - let lora = { - match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), true, &mut delay).await { + match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), true, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -71,9 +70,9 @@ async fn main(_spawner: Spawner) { // TODO: Adjust the EUI and Keys according to your network credentials match device .join(&JoinMode::OTAA { - deveui: [0, 0, 0, 0, 0, 0, 0, 0], - appeui: [0, 0, 0, 0, 0, 0, 0, 0], - appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + deveui: DevEui::from([0, 0, 0, 0, 0, 0, 0, 0]), + appeui: AppEui::from([0, 0, 0, 0, 0, 0, 0, 0]), + appkey: AppKey::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), }) .await { diff --git a/examples/stm32l0/src/bin/lora_p2p_receive.rs b/examples/stm32l0/src/bin/lora_p2p_receive.rs index 0f9f6095..edd14bb8 100644 --- a/examples/stm32l0/src/bin/lora_p2p_receive.rs +++ b/examples/stm32l0/src/bin/lora_p2p_receive.rs @@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) { let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, &mut delay).await { + match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -88,7 +86,7 @@ async fn main(_spawner: Spawner) { }; match lora - .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32) + .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, None, false) .await { Ok(()) => {} diff --git a/examples/stm32l0/src/bin/lora_p2p_send.rs b/examples/stm32l0/src/bin/lora_p2p_send.rs index c85c3c2b..23cc1c6f 100644 --- a/examples/stm32l0/src/bin/lora_p2p_send.rs +++ b/examples/stm32l0/src/bin/lora_p2p_send.rs @@ -41,10 +41,8 @@ async fn main(_spawner: Spawner) { let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, &mut delay).await { + match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -97,7 +95,7 @@ async fn main(_spawner: Spawner) { } }; - match lora.sleep(&mut delay).await { + match lora.sleep(false).await { Ok(()) => info!("Sleep successful"), Err(err) => info!("Sleep unsuccessful = {}", err), } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 155c6dbc..69abf53f 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.3.0", path = "../../embassy-executor", feature embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } -lora-phy = { version = "1" } +lora-phy = { version = "2" } lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"] } lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"] } @@ -32,4 +32,5 @@ chrono = { version = "^0.4", default-features = false } debug = 2 [patch.crates-io] -lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} +lorawan-device = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} +lorawan = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} diff --git a/examples/stm32wl/src/bin/lora_lorawan.rs b/examples/stm32wl/src/bin/lora_lorawan.rs index 230df475..fb249532 100644 --- a/examples/stm32wl/src/bin/lora_lorawan.rs +++ b/examples/stm32wl/src/bin/lora_lorawan.rs @@ -20,6 +20,7 @@ use lora_phy::LoRa; use lorawan::default_crypto::DefaultFactory as Crypto; use lorawan_device::async_device::lora_radio::LoRaRadio; use lorawan_device::async_device::{region, Device, JoinMode}; +use lorawan_device::{AppEui, AppKey, DevEui}; use {defmt_rtt as _, panic_probe as _}; const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region @@ -46,10 +47,8 @@ async fn main(_spawner: Spawner) { let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High); let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap(); - let mut delay = Delay; - let lora = { - match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), true, &mut delay).await { + match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), true, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -66,9 +65,9 @@ async fn main(_spawner: Spawner) { // TODO: Adjust the EUI and Keys according to your network credentials match device .join(&JoinMode::OTAA { - deveui: [0, 0, 0, 0, 0, 0, 0, 0], - appeui: [0, 0, 0, 0, 0, 0, 0, 0], - appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + deveui: DevEui::from([0, 0, 0, 0, 0, 0, 0, 0]), + appeui: AppEui::from([0, 0, 0, 0, 0, 0, 0, 0]), + appkey: AppKey::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), }) .await { diff --git a/examples/stm32wl/src/bin/lora_p2p_receive.rs b/examples/stm32wl/src/bin/lora_p2p_receive.rs index d3f051b1..3d8c31ff 100644 --- a/examples/stm32wl/src/bin/lora_p2p_receive.rs +++ b/examples/stm32wl/src/bin/lora_p2p_receive.rs @@ -37,10 +37,8 @@ async fn main(_spawner: Spawner) { let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High); let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), false, &mut delay).await { + match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -84,7 +82,7 @@ async fn main(_spawner: Spawner) { }; match lora - .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32) + .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, None, false) .await { Ok(()) => {} diff --git a/examples/stm32wl/src/bin/lora_p2p_send.rs b/examples/stm32wl/src/bin/lora_p2p_send.rs index fc5205c8..fbd0b032 100644 --- a/examples/stm32wl/src/bin/lora_p2p_send.rs +++ b/examples/stm32wl/src/bin/lora_p2p_send.rs @@ -37,10 +37,8 @@ async fn main(_spawner: Spawner) { let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High); let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap(); - let mut delay = Delay; - let mut lora = { - match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), false, &mut delay).await { + match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), false, Delay).await { Ok(l) => l, Err(err) => { info!("Radio error = {}", err); @@ -93,7 +91,7 @@ async fn main(_spawner: Spawner) { } }; - match lora.sleep(&mut delay).await { + match lora.sleep(false).await { Ok(()) => info!("Sleep successful"), Err(err) => info!("Sleep unsuccessful = {}", err), } From e03239e88d7f2d01f31de5e5eef2b4d79522679d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 24 Sep 2023 23:54:32 +0200 Subject: [PATCH 202/233] stm32: centralize enabling pwr, syscfg, flash. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/eth/v1/mod.rs | 1 - embassy-stm32/src/eth/v2/mod.rs | 1 - embassy-stm32/src/exti.rs | 5 ----- embassy-stm32/src/gpio.rs | 3 +++ embassy-stm32/src/lib.rs | 10 ++++++++++ embassy-stm32/src/rcc/f2.rs | 5 +---- embassy-stm32/src/rcc/f4.rs | 3 --- embassy-stm32/src/rcc/f7.rs | 8 +------- embassy-stm32/src/rcc/h.rs | 5 ----- embassy-stm32/src/rcc/l0.rs | 7 ------- embassy-stm32/src/rcc/l4.rs | 4 ---- embassy-stm32/src/rtc/v2.rs | 14 -------------- embassy-stm32/src/usb/usb.rs | 5 +---- embassy-stm32/src/usb_otg/usb.rs | 12 ++---------- 15 files changed, 20 insertions(+), 67 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index dd19db24..ef0ef229 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -59,7 +59,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2bdbec6dc0fd5fcef5d9fb473de1fc5050a054c2" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-74025d56c0ba061703f360558ce80f51d1165060" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2bdbec6dc0fd5fcef5d9fb473de1fc5050a054c2", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-74025d56c0ba061703f360558ce80f51d1165060", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index a1e0240c..4d19103d 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -129,7 +129,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { #[cfg(any(eth_v1b, eth_v1c))] critical_section::with(|_| { - RCC.apb2enr().modify(|w| w.set_syscfgen(true)); RCC.ahb1enr().modify(|w| { w.set_ethen(true); w.set_ethtxen(true); diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index ada495fd..f03ea2e3 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -80,7 +80,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { // Enable the necessary Clocks #[cfg(not(rcc_h5))] critical_section::with(|_| { - crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true)); crate::pac::RCC.ahb1enr().modify(|w| { w.set_eth1macen(true); w.set_eth1txen(true); diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index efa51fb2..62f32170 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -371,9 +371,4 @@ pub(crate) unsafe fn init() { use crate::interrupt::typelevel::Interrupt; foreach_exti_irq!(enable_irq); - - #[cfg(not(any(rcc_wb, rcc_wl5, rcc_wle, stm32f1, exti_h5, exti_h50)))] - ::enable(); - #[cfg(stm32f1)] - ::enable(); } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index a382cb74..c709d46d 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -758,6 +758,9 @@ foreach_pin!( ); pub(crate) unsafe fn init() { + #[cfg(afio)] + ::enable(); + crate::_generated::init_gpio(); } diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 6a53f876..9231aa0f 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -117,6 +117,7 @@ pub(crate) use stm32_metapac as pac; use crate::interrupt::Priority; #[cfg(feature = "rt")] pub use crate::pac::NVIC_PRIO_BITS; +use crate::rcc::sealed::RccPeripheral; #[non_exhaustive] pub struct Config { @@ -179,6 +180,15 @@ pub fn init(config: Config) -> Peripherals { }); } + #[cfg(not(any(stm32f1, stm32h5, stm32wb, stm32wl)))] + peripherals::SYSCFG::enable(); + #[cfg(sbs)] + peripherals::SBS::enable(); + #[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))] + peripherals::PWR::enable(); + #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] + peripherals::FLASH::enable(); + unsafe { gpio::init(); dma::init( diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index 1a34c2cb..44de5bf1 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -4,7 +4,7 @@ use core::ops::{Div, Mul}; pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; -use crate::pac::{FLASH, PWR, RCC}; +use crate::pac::{FLASH, RCC}; use crate::rcc::bd::BackupDomain; use crate::rcc::{set_freqs, Clocks}; use crate::rtc::RtcClockSource; @@ -435,9 +435,6 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().modify(|w| w.set_hsion(false)); } - RCC.apb1enr().modify(|w| w.set_pwren(true)); - PWR.cr().read(); - BackupDomain::configure_ls( config.rtc.unwrap_or(RtcClockSource::NOCLOCK), config.lsi, diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index d8d0312b..5914c926 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -3,7 +3,6 @@ use core::marker::PhantomData; use embassy_hal_internal::into_ref; use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre}; -use super::sealed::RccPeripheral; use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; @@ -332,8 +331,6 @@ fn flash_setup(sysclk: u32) { } pub(crate) unsafe fn init(config: Config) { - crate::peripherals::PWR::enable(); - let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0); let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); let sysclk_on_pll = sysclk != pllsrcclk; diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs index 85cb9c66..234511b0 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs @@ -1,4 +1,3 @@ -use super::sealed::RccPeripheral; use crate::pac::pwr::vals::Vos; use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; @@ -111,8 +110,6 @@ fn flash_setup(sysclk: u32) { } pub(crate) unsafe fn init(config: Config) { - crate::peripherals::PWR::enable(); - if let Some(hse) = config.hse { if config.bypass_hse { assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); @@ -212,10 +209,7 @@ pub(crate) unsafe fn init(config: Config) { if plls.use_pll { RCC.cr().modify(|w| w.set_pllon(false)); - // enable PWR and setup VOSScale - - RCC.apb1enr().modify(|w| w.set_pwren(true)); - + // setup VOSScale let vos_scale = if sysclk <= 144_000_000 { 3 } else if sysclk <= 168_000_000 { diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index a4730ed4..43e8db22 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -215,11 +215,6 @@ impl Default for Config { } pub(crate) unsafe fn init(config: Config) { - #[cfg(stm32h7)] - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - #[cfg(stm32h5)] - RCC.apb3enr().modify(|w| w.set_sbsen(true)); - // NB. The lower bytes of CR3 can only be written once after // POR, and must be written with a valid combination. Refer to // RM0433 Rev 7 6.8.4. This is partially enforced by dropping diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 1c655592..67355afb 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -283,13 +283,6 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(crs)] if config.enable_hsi48 { - // Reset SYSCFG peripheral - RCC.apb2rstr().modify(|w| w.set_syscfgrst(true)); - RCC.apb2rstr().modify(|w| w.set_syscfgrst(false)); - - // Enable SYSCFG peripheral - RCC.apb2enr().modify(|w| w.set_syscfgen(true)); - // Reset CRS peripheral RCC.apb1rstr().modify(|w| w.set_crsrst(true)); RCC.apb1rstr().modify(|w| w.set_crsrst(false)); diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index f7b9354a..6f1f7458 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -409,8 +409,6 @@ pub(crate) unsafe fn init(config: Config) { while RCC.cfgr().read().sws() != Sw::MSI {} } - RCC.apb1enr1().modify(|w| w.set_pwren(true)); - BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); let (sys_clk, sw) = match config.mux { @@ -608,8 +606,6 @@ pub(crate) unsafe fn init(config: Config) { } }; - RCC.apb1enr1().modify(|w| w.set_pwren(true)); - set_freqs(Clocks { sys: Hertz(sys_clk), ahb1: Hertz(ahb_freq), diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 05b85ef4..ab562d2b 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -295,20 +295,6 @@ impl sealed::Instance for crate::peripherals::RTC { // read to allow the pwr clock to enable crate::pac::PWR.cr1().read(); } - #[cfg(any(rtc_v2f2))] - { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); - - // read to allow the pwr clock to enable - crate::pac::PWR.cr().read(); - } - - #[cfg(any(rtc_v2f0, rtc_v2l0))] - { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); - } } fn read_backup_register(rtc: &Rtc, register: usize) -> Option { diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index cef19635..b24fc74e 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -264,10 +264,7 @@ impl<'d, T: Instance> Driver<'d, T> { let regs = T::regs(); #[cfg(stm32l5)] - { - crate::peripherals::PWR::enable(); - crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); - } + crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); #[cfg(pwr_h5)] crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)); diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 348f0f79..1fe010bb 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -540,10 +540,7 @@ impl<'d, T: Instance> Bus<'d, T> { impl<'d, T: Instance> Bus<'d, T> { fn init(&mut self) { #[cfg(stm32l4)] - { - crate::peripherals::PWR::enable(); - critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); - } + critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); #[cfg(stm32f7)] { @@ -618,15 +615,10 @@ impl<'d, T: Instance> Bus<'d, T> { { // Enable USB power critical_section::with(|_| { - crate::pac::RCC.ahb3enr().modify(|w| { - w.set_pwren(true); - }); - cortex_m::asm::delay(2); - crate::pac::PWR.svmcr().modify(|w| { w.set_usv(true); w.set_uvmen(true); - }); + }) }); // Wait for USB power to stabilize From 9f2fc04caa2da6a6739e8dfd0dbef96bc10cc56a Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 24 Sep 2023 18:37:09 -0500 Subject: [PATCH 203/233] stm32: fix bd lsi --- embassy-stm32/src/rcc/bd.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 4915d5e2..5bae3edd 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -100,13 +100,14 @@ impl BackupDomain { #[cfg(not(rtc_v3u5))] let csr = crate::pac::RCC.csr(); - Self::modify(|_| { - #[cfg(not(any(rcc_wb, rcc_wba)))] - csr.modify(|w| w.set_lsion(true)); + // Disable backup domain write protection + Self::modify(|_| {}); - #[cfg(any(rcc_wb, rcc_wba))] - csr.modify(|w| w.set_lsi1on(true)); - }); + #[cfg(not(any(rcc_wb, rcc_wba)))] + csr.modify(|w| w.set_lsion(true)); + + #[cfg(any(rcc_wb, rcc_wba))] + csr.modify(|w| w.set_lsi1on(true)); #[cfg(not(any(rcc_wb, rcc_wba)))] while !csr.read().lsirdy() {} From 70acc093dddc35491db297d8f85dd369d7ea9d2b Mon Sep 17 00:00:00 2001 From: ceekdee Date: Mon, 25 Sep 2023 10:45:53 -0500 Subject: [PATCH 204/233] Update rust-lorawan crate versions. --- embassy-lora/Cargo.toml | 5 +---- examples/nrf52840/Cargo.toml | 8 ++------ examples/rp/Cargo.toml | 8 ++------ examples/stm32l0/Cargo.toml | 8 ++------ examples/stm32wl/Cargo.toml | 8 ++------ 5 files changed, 9 insertions(+), 28 deletions(-) diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index 7022e935..88f815cd 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml @@ -28,7 +28,4 @@ embedded-hal = { version = "0.2", features = ["unproven"] } futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } lora-phy = { version = "2" } -lorawan-device = { version = "0.10.0", default-features = false, features = ["async"], optional = true } - -[patch.crates-io] -lorawan-device = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} +lorawan-device = { version = "0.11.0", default-features = false, features = ["async"], optional = true } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index d54847ff..d45e006c 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -39,8 +39,8 @@ embedded-io = { version = "0.5.0", features = ["defmt-03"] } embedded-io-async = { version = "0.5.0", optional = true, features = ["defmt-03"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } lora-phy = { version = "2", optional = true } -lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } -lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } +lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } +lorawan = { version = "0.7.4", default-features = false, features = ["default-crypto"], optional = true } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true } embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"], optional = true } @@ -65,7 +65,3 @@ microfft = "0.5.0" [profile.release] debug = 2 - -[patch.crates-io] -lorawan-device = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} -lorawan = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 5fe08fb0..2677e040 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -18,8 +18,8 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"] } lora-phy = { version = "2" } -lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"] } -lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"] } +lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"] } +lorawan = { version = "0.7.4", default-features = false, features = ["default-crypto"] } cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } @@ -55,7 +55,3 @@ rand = { version = "0.8.5", default-features = false } [profile.release] debug = 2 - -[patch.crates-io] -lorawan-device = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} -lorawan = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 71ec4f5a..502ebfc8 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -17,8 +17,8 @@ embassy-executor = { version = "0.3.0", path = "../../embassy-executor", feature embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } lora-phy = { version = "2", optional = true } -lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } -lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } +lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } +lorawan = { version = "0.7.4", default-features = false, features = ["default-crypto"], optional = true } defmt = "0.3" defmt-rtt = "0.4" @@ -37,7 +37,3 @@ static_cell = "1.1" [profile.release] debug = 2 - -[patch.crates-io] -lorawan-device = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} -lorawan = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 69abf53f..f47a9a90 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -13,8 +13,8 @@ embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["ni embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } lora-phy = { version = "2" } -lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"] } -lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"] } +lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"] } +lorawan = { version = "0.7.4", default-features = false, features = ["default-crypto"] } defmt = "0.3" defmt-rtt = "0.4" @@ -30,7 +30,3 @@ chrono = { version = "^0.4", default-features = false } [profile.release] debug = 2 - -[patch.crates-io] -lorawan-device = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} -lorawan = { git = "https://github.com/ivajloip/rust-lorawan", rev = "b0502c1a802427638cc8bcd928fc632d13b778b6"} From bd9021ca1db721334a518c0cfab42cfa6e373c74 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 25 Sep 2023 22:34:41 +0200 Subject: [PATCH 205/233] Make irq token Copy+Clone --- embassy-nrf/src/lib.rs | 1 + embassy-rp/src/lib.rs | 3 ++- embassy-stm32/src/lib.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 355a0049..9c4b6569 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -102,6 +102,7 @@ mod chip; #[macro_export] macro_rules! bind_interrupts { ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + #[derive(Copy, Clone)] $vis struct $name; $( diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 2a1bca4b..c3561bbe 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -90,7 +90,8 @@ embassy_hal_internal::interrupt_mod!( #[macro_export] macro_rules! bind_interrupts { ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { - $vis struct $name; + #[derive(Copy, Clone)] + $vis struct $name; $( #[allow(non_snake_case)] diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 9231aa0f..db79546b 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -88,6 +88,7 @@ pub use crate::_generated::interrupt; #[macro_export] macro_rules! bind_interrupts { ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + #[derive(Copy, Clone)] $vis struct $name; $( From 4b695120fce8bb434bf8f20eb964358e37417765 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 25 Sep 2023 22:34:18 +0200 Subject: [PATCH 206/233] tests/stm32: centralize pin configuration. --- tests/stm32/src/bin/gpio.rs | 20 +--- tests/stm32/src/bin/spi.rs | 22 +--- tests/stm32/src/bin/spi_dma.rs | 24 ++--- tests/stm32/src/bin/usart.rs | 55 ++-------- tests/stm32/src/bin/usart_dma.rs | 51 ++------- tests/stm32/src/bin/usart_rx_ringbuffered.rs | 105 ++----------------- tests/stm32/src/common.rs | 85 +++++++++++++++ 7 files changed, 119 insertions(+), 243 deletions(-) diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs index aad17443..49d9a60f 100644 --- a/tests/stm32/src/bin/gpio.rs +++ b/tests/stm32/src/bin/gpio.rs @@ -16,24 +16,8 @@ async fn main(_spawner: Spawner) { // Arduino pins D0 and D1 // They're connected together with a 1K resistor. - #[cfg(feature = "stm32f103c8")] - let (mut a, mut b) = (p.PA9, p.PA10); - #[cfg(feature = "stm32g491re")] - let (mut a, mut b) = (p.PC4, p.PC5); - #[cfg(feature = "stm32g071rb")] - let (mut a, mut b) = (p.PC4, p.PC5); - #[cfg(feature = "stm32f429zi")] - let (mut a, mut b) = (p.PG14, p.PG9); - #[cfg(feature = "stm32wb55rg")] - let (mut a, mut b) = (p.PA3, p.PA2); - #[cfg(feature = "stm32h755zi")] - let (mut a, mut b) = (p.PB6, p.PB7); - #[cfg(feature = "stm32u585ai")] - let (mut a, mut b) = (p.PD9, p.PD8); - #[cfg(feature = "stm32h563zi")] - let (mut a, mut b) = (p.PB6, p.PB7); - #[cfg(feature = "stm32c031c6")] - let (mut a, mut b) = (p.PB6, p.PB7); + let mut a = peri!(p, UART_RX); + let mut b = peri!(p, UART_TX); // Test initial output { diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs index e51dd5bf..b0fb75d6 100644 --- a/tests/stm32/src/bin/spi.rs +++ b/tests/stm32/src/bin/spi.rs @@ -16,24 +16,10 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config()); info!("Hello World!"); - #[cfg(feature = "stm32f103c8")] - let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); - #[cfg(feature = "stm32f429zi")] - let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); - #[cfg(feature = "stm32h755zi")] - let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PB5, p.PA6); - #[cfg(feature = "stm32g491re")] - let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); - #[cfg(feature = "stm32g071rb")] - let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); - #[cfg(feature = "stm32wb55rg")] - let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); - #[cfg(feature = "stm32u585ai")] - let (spi, sck, mosi, miso) = (p.SPI1, p.PE13, p.PE15, p.PE14); - #[cfg(feature = "stm32h563zi")] - let (spi, sck, mosi, miso) = (p.SPI4, p.PE12, p.PE14, p.PE13); - #[cfg(feature = "stm32c031c6")] - let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); + let spi = peri!(p, SPI); + let sck = peri!(p, SPI_SCK); + let mosi = peri!(p, SPI_MOSI); + let miso = peri!(p, SPI_MISO); let mut spi_config = spi::Config::default(); spi_config.frequency = Hertz(1_000_000); diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs index d45cbe45..212cfae5 100644 --- a/tests/stm32/src/bin/spi_dma.rs +++ b/tests/stm32/src/bin/spi_dma.rs @@ -15,24 +15,12 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config()); info!("Hello World!"); - #[cfg(feature = "stm32f103c8")] - let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH3, p.DMA1_CH2); - #[cfg(feature = "stm32f429zi")] - let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA2_CH3, p.DMA2_CH2); - #[cfg(feature = "stm32h755zi")] - let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PB5, p.PA6, p.DMA1_CH0, p.DMA1_CH1); - #[cfg(feature = "stm32g491re")] - let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); - #[cfg(feature = "stm32g071rb")] - let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); - #[cfg(feature = "stm32wb55rg")] - let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); - #[cfg(feature = "stm32u585ai")] - let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PE13, p.PE15, p.PE14, p.GPDMA1_CH0, p.GPDMA1_CH1); - #[cfg(feature = "stm32h563zi")] - let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI4, p.PE12, p.PE14, p.PE13, p.GPDMA1_CH0, p.GPDMA1_CH1); - #[cfg(feature = "stm32c031c6")] - let (spi, sck, mosi, miso, tx_dma, rx_dma) = (p.SPI1, p.PA5, p.PA7, p.PA6, p.DMA1_CH1, p.DMA1_CH2); + let spi = peri!(p, SPI); + let sck = peri!(p, SPI_SCK); + let mosi = peri!(p, SPI_MOSI); + let miso = peri!(p, SPI_MISO); + let tx_dma = peri!(p, SPI_TX_DMA); + let rx_dma = peri!(p, SPI_RX_DMA); let mut spi_config = spi::Config::default(); spi_config.frequency = Hertz(1_000_000); diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 394005b8..e789e543 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -9,35 +9,8 @@ use defmt::assert_eq; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Error, Uart}; -use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_time::{Duration, Instant}; -#[cfg(any( - feature = "stm32f103c8", - feature = "stm32g491re", - feature = "stm32g071rb", - feature = "stm32h755zi", - feature = "stm32c031c6", -))] -bind_interrupts!(struct Irqs { - USART1 => usart::InterruptHandler; -}); - -#[cfg(feature = "stm32u585ai")] -bind_interrupts!(struct Irqs { - USART3 => usart::InterruptHandler; -}); - -#[cfg(feature = "stm32f429zi")] -bind_interrupts!(struct Irqs { - USART6 => usart::InterruptHandler; -}); - -#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))] -bind_interrupts!(struct Irqs { - LPUART1 => usart::InterruptHandler; -}); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config()); @@ -45,28 +18,14 @@ async fn main(_spawner: Spawner) { // Arduino pins D0 and D1 // They're connected together with a 1K resistor. - #[cfg(feature = "stm32f103c8")] - let (mut tx, mut rx, mut usart) = (p.PA9, p.PA10, p.USART1); - #[cfg(feature = "stm32g491re")] - let (mut tx, mut rx, mut usart) = (p.PC4, p.PC5, p.USART1); - #[cfg(feature = "stm32g071rb")] - let (mut tx, mut rx, mut usart) = (p.PC4, p.PC5, p.USART1); - #[cfg(feature = "stm32f429zi")] - let (mut tx, mut rx, mut usart) = (p.PG14, p.PG9, p.USART6); - #[cfg(feature = "stm32wb55rg")] - let (mut tx, mut rx, mut usart) = (p.PA2, p.PA3, p.LPUART1); - #[cfg(feature = "stm32h755zi")] - let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.USART1); - #[cfg(feature = "stm32u585ai")] - let (mut tx, mut rx, mut usart) = (p.PD8, p.PD9, p.USART3); - #[cfg(feature = "stm32h563zi")] - let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.LPUART1); - #[cfg(feature = "stm32c031c6")] - let (mut tx, mut rx, mut usart) = (p.PB6, p.PB7, p.USART1); + let mut usart = peri!(p, UART); + let mut rx = peri!(p, UART_RX); + let mut tx = peri!(p, UART_TX); + let irq = irqs!(UART); { let config = Config::default(); - let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config); + let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config); // We can't send too many bytes, they have to fit in the FIFO. // This is because we aren't sending+receiving at the same time. @@ -82,7 +41,7 @@ async fn main(_spawner: Spawner) { // Test error handling with with an overflow error { let config = Config::default(); - let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config); + let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config); // Send enough bytes to fill the RX FIFOs off all USART versions. let data = [0xC0, 0xDE, 0x12, 0x23, 0x34]; @@ -116,7 +75,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.baudrate = baudrate; - let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, Irqs, NoDma, NoDma, config); + let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config); let n = (baudrate as usize / 100).max(64); diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index c34d9574..f203ebb5 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs @@ -9,33 +9,6 @@ use defmt::assert_eq; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usart::{Config, Uart}; -use embassy_stm32::{bind_interrupts, peripherals, usart}; - -#[cfg(any( - feature = "stm32f103c8", - feature = "stm32g491re", - feature = "stm32g071rb", - feature = "stm32h755zi", - feature = "stm32c031c6", -))] -bind_interrupts!(struct Irqs { - USART1 => usart::InterruptHandler; -}); - -#[cfg(feature = "stm32u585ai")] -bind_interrupts!(struct Irqs { - USART3 => usart::InterruptHandler; -}); - -#[cfg(feature = "stm32f429zi")] -bind_interrupts!(struct Irqs { - USART6 => usart::InterruptHandler; -}); - -#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))] -bind_interrupts!(struct Irqs { - LPUART1 => usart::InterruptHandler; -}); #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -44,24 +17,12 @@ async fn main(_spawner: Spawner) { // Arduino pins D0 and D1 // They're connected together with a 1K resistor. - #[cfg(feature = "stm32f103c8")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, Irqs, p.DMA1_CH4, p.DMA1_CH5); - #[cfg(feature = "stm32g491re")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2); - #[cfg(feature = "stm32g071rb")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2); - #[cfg(feature = "stm32f429zi")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, Irqs, p.DMA2_CH6, p.DMA2_CH1); - #[cfg(feature = "stm32wb55rg")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, Irqs, p.DMA1_CH1, p.DMA1_CH2); - #[cfg(feature = "stm32h755zi")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, Irqs, p.DMA1_CH0, p.DMA1_CH1); - #[cfg(feature = "stm32u585ai")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1); - #[cfg(feature = "stm32h563zi")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.LPUART1, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1); - #[cfg(feature = "stm32c031c6")] - let (tx, rx, usart, irq, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, Irqs, p.DMA1_CH1, p.DMA1_CH2); + let usart = peri!(p, UART); + let rx = peri!(p, UART_RX); + let tx = peri!(p, UART_TX); + let rx_dma = peri!(p, UART_RX_DMA); + let tx_dma = peri!(p, UART_TX_DMA); + let irq = irqs!(UART); let config = Config::default(); let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs index c8dd2643..fdbeb9f6 100644 --- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs @@ -10,87 +10,10 @@ use common::*; use defmt::{assert_eq, panic}; use embassy_executor::Spawner; use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx}; -use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_time::{Duration, Timer}; use rand_chacha::ChaCha8Rng; use rand_core::{RngCore, SeedableRng}; -#[cfg(any( - feature = "stm32f103c8", - feature = "stm32g491re", - feature = "stm32g071rb", - feature = "stm32h755zi", - feature = "stm32c031c6", -))] -bind_interrupts!(struct Irqs { - USART1 => usart::InterruptHandler; -}); - -#[cfg(feature = "stm32u585ai")] -bind_interrupts!(struct Irqs { - USART3 => usart::InterruptHandler; -}); - -#[cfg(feature = "stm32f429zi")] -bind_interrupts!(struct Irqs { - USART1 => usart::InterruptHandler; - USART6 => usart::InterruptHandler; -}); - -#[cfg(any(feature = "stm32wb55rg", feature = "stm32h563zi"))] -bind_interrupts!(struct Irqs { - LPUART1 => usart::InterruptHandler; -}); - -#[cfg(feature = "stm32f103c8")] -mod board { - pub type Uart = embassy_stm32::peripherals::USART1; - pub type TxDma = embassy_stm32::peripherals::DMA1_CH4; - pub type RxDma = embassy_stm32::peripherals::DMA1_CH5; -} -#[cfg(feature = "stm32g491re")] -mod board { - pub type Uart = embassy_stm32::peripherals::USART1; - pub type TxDma = embassy_stm32::peripherals::DMA1_CH1; - pub type RxDma = embassy_stm32::peripherals::DMA1_CH2; -} -#[cfg(feature = "stm32g071rb")] -mod board { - pub type Uart = embassy_stm32::peripherals::USART1; - pub type TxDma = embassy_stm32::peripherals::DMA1_CH1; - pub type RxDma = embassy_stm32::peripherals::DMA1_CH2; -} -#[cfg(feature = "stm32f429zi")] -mod board { - pub type Uart = embassy_stm32::peripherals::USART6; - pub type TxDma = embassy_stm32::peripherals::DMA2_CH6; - pub type RxDma = embassy_stm32::peripherals::DMA2_CH1; -} -#[cfg(feature = "stm32wb55rg")] -mod board { - pub type Uart = embassy_stm32::peripherals::LPUART1; - pub type TxDma = embassy_stm32::peripherals::DMA1_CH1; - pub type RxDma = embassy_stm32::peripherals::DMA1_CH2; -} -#[cfg(feature = "stm32h755zi")] -mod board { - pub type Uart = embassy_stm32::peripherals::USART1; - pub type TxDma = embassy_stm32::peripherals::DMA1_CH0; - pub type RxDma = embassy_stm32::peripherals::DMA1_CH1; -} -#[cfg(feature = "stm32u585ai")] -mod board { - pub type Uart = embassy_stm32::peripherals::USART3; - pub type TxDma = embassy_stm32::peripherals::GPDMA1_CH0; - pub type RxDma = embassy_stm32::peripherals::GPDMA1_CH1; -} -#[cfg(feature = "stm32c031c6")] -mod board { - pub type Uart = embassy_stm32::peripherals::USART1; - pub type TxDma = embassy_stm32::peripherals::DMA1_CH1; - pub type RxDma = embassy_stm32::peripherals::DMA1_CH2; -} - const DMA_BUF_SIZE: usize = 256; #[embassy_executor::main] @@ -100,22 +23,12 @@ async fn main(spawner: Spawner) { // Arduino pins D0 and D1 // They're connected together with a 1K resistor. - #[cfg(feature = "stm32f103c8")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5); - #[cfg(feature = "stm32g491re")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); - #[cfg(feature = "stm32g071rb")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); - #[cfg(feature = "stm32f429zi")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1); - #[cfg(feature = "stm32wb55rg")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2); - #[cfg(feature = "stm32h755zi")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); - #[cfg(feature = "stm32u585ai")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1); - #[cfg(feature = "stm32c031c6")] - let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH1, p.DMA1_CH2); + let usart = peri!(p, UART); + let rx = peri!(p, UART_RX); + let tx = peri!(p, UART_TX); + let rx_dma = peri!(p, UART_RX_DMA); + let tx_dma = peri!(p, UART_TX_DMA); + let irq = irqs!(UART); // To run this test, use the saturating_serial test utility to saturate the serial port @@ -127,7 +40,7 @@ async fn main(spawner: Spawner) { config.stop_bits = StopBits::STOP1; config.parity = Parity::ParityNone; - let usart = Uart::new(usart, rx, tx, Irqs, tx_dma, rx_dma, config); + let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); let (tx, rx) = usart.split(); static mut DMA_BUF: [u8; DMA_BUF_SIZE] = [0; DMA_BUF_SIZE]; let dma_buf = unsafe { DMA_BUF.as_mut() }; @@ -139,7 +52,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) { +async fn transmit_task(mut tx: UartTx<'static, peris::UART, peris::UART_TX_DMA>) { // workaround https://github.com/embassy-rs/embassy/issues/1426 Timer::after(Duration::from_millis(100) as _).await; @@ -162,7 +75,7 @@ async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) { } #[embassy_executor::task] -async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::RxDma>) { +async fn receive_task(mut rx: RingBufferedUartRx<'static, peris::UART, peris::UART_RX_DMA>) { info!("Ready to receive..."); let mut rng = ChaCha8Rng::seed_from_u64(1337); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 3a1b5c3e..055eade6 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -25,6 +25,91 @@ teleprobe_meta::target!(b"nucleo-stm32h563zi"); #[cfg(feature = "stm32c031c6")] teleprobe_meta::target!(b"nucleo-stm32c031c6"); +macro_rules! define_peris { + ($($name:ident = $peri:ident,)* $(@irq $irq_name:ident = $irq_code:tt,)*) => { + #[allow(unused_macros)] + macro_rules! peri { + $( + ($p:expr, $name) => { + $p.$peri + }; + )* + } + #[allow(unused_macros)] + macro_rules! irqs { + $( + ($irq_name) => {{ + embassy_stm32::bind_interrupts!(struct Irqs $irq_code); + Irqs + }}; + )* + } + + #[allow(unused)] + #[allow(non_camel_case_types)] + pub mod peris { + $( + pub type $name = embassy_stm32::peripherals::$peri; + )* + } + }; +} + +#[cfg(feature = "stm32f103c8")] +define_peris!( + UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32g491re")] +define_peris!( + UART = USART1, UART_TX = PC4, UART_RX = PC5, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32g071rb")] +define_peris!( + UART = USART1, UART_TX = PC4, UART_RX = PC5, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32f429zi")] +define_peris!( + UART = USART6, UART_TX = PG14, UART_RX = PG9, UART_TX_DMA = DMA2_CH6, UART_RX_DMA = DMA2_CH1, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2, + @irq UART = {USART6 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32wb55rg")] +define_peris!( + UART = LPUART1, UART_TX = PA2, UART_RX = PA3, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, + @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32h755zi")] +define_peris!( + UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH0, UART_RX_DMA = DMA1_CH1, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PB5, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH0, SPI_RX_DMA = DMA1_CH1, + @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32u585ai")] +define_peris!( + UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, + SPI = SPI1, SPI_SCK = PE13, SPI_MOSI = PE15, SPI_MISO = PE14, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, + @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32h563zi")] +define_peris!( + UART = LPUART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = GPDMA1_CH0, UART_RX_DMA = GPDMA1_CH1, + SPI = SPI4, SPI_SCK = PE12, SPI_MOSI = PE14, SPI_MISO = PE13, SPI_TX_DMA = GPDMA1_CH0, SPI_RX_DMA = GPDMA1_CH1, + @irq UART = {LPUART1 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32c031c6")] +define_peris!( + UART = USART1, UART_TX = PB6, UART_RX = PB7, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, +); + pub fn config() -> Config { #[allow(unused_mut)] let mut config = Config::default(); From 04b09a2acb465dbb87dfc4e8b24b4c587f21b472 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 25 Sep 2023 16:26:29 -0500 Subject: [PATCH 207/233] stm32/rtc: use rccperi enable --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/rcc/bd.rs | 5 ----- embassy-stm32/src/rtc/mod.rs | 10 +++++++--- embassy-stm32/src/rtc/v2.rs | 11 ----------- embassy-stm32/src/rtc/v3.rs | 17 ----------------- 5 files changed, 9 insertions(+), 38 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ef0ef229..660ab053 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -59,7 +59,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-74025d56c0ba061703f360558ce80f51d1165060" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-1551a1c01a993bb5ffc603311f80097c14e03f85" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-74025d56c0ba061703f360558ce80f51d1165060", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-1551a1c01a993bb5ffc603311f80097c14e03f85", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 5bae3edd..de27130f 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -88,11 +88,6 @@ impl BackupDomain { ))] #[allow(dead_code, unused_variables)] pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option) { - if lsi || lse.is_some() { - use crate::rtc::sealed::Instance; - crate::peripherals::RTC::enable_peripheral_clk(); - } - if lsi { #[cfg(rtc_v3u5)] let csr = crate::pac::RCC.bdcr(); diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 7eafedec..b26b5ef3 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -10,6 +10,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; +use crate::rcc::sealed::RccPeripheral; pub use crate::rcc::RtcClockSource; use crate::time::Hertz; @@ -111,11 +112,12 @@ impl RtcTimeProvider { } } -#[non_exhaustive] /// RTC Abstraction pub struct Rtc { #[cfg(feature = "low-power")] stop_time: Mutex>>, + #[cfg(not(feature = "low-power"))] + _private: (), } #[non_exhaustive] @@ -154,9 +156,13 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { + RTC::enable(); + let mut this = Self { #[cfg(feature = "low-power")] stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), + #[cfg(not(feature = "low-power"))] + _private: (), }; let frequency = Self::frequency(); @@ -292,8 +298,6 @@ pub(crate) mod sealed { crate::pac::RTC } - fn enable_peripheral_clk(); - /// Read content of the backup register. /// /// The registers retain their values during wakes from standby mode or system resets. They also diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index ab562d2b..331792a0 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -286,17 +286,6 @@ impl sealed::Instance for crate::peripherals::RTC { #[cfg(all(feature = "low-power", stm32l0))] type WakeupInterrupt = crate::interrupt::typelevel::RTC; - fn enable_peripheral_clk() { - #[cfg(any(rtc_v2l4, rtc_v2wb))] - { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); - - // read to allow the pwr clock to enable - crate::pac::PWR.cr1().read(); - } - } - fn read_backup_register(rtc: &Rtc, register: usize) -> Option { if register < Self::BACKUP_REGISTER_COUNT { Some(rtc.bkpr(register).read().bkp()) diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 9ac9f9f8..a6b2655d 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -128,23 +128,6 @@ impl super::Rtc { impl sealed::Instance for crate::peripherals::RTC { const BACKUP_REGISTER_COUNT: usize = 32; - fn enable_peripheral_clk() { - #[cfg(any(rcc_wle, rcc_wl5, rcc_g4))] - { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); - } - - #[cfg(rcc_g0)] - { - // enable peripheral clock for communication - crate::pac::RCC.apbenr1().modify(|w| w.set_rtcapben(true)); - } - - // read to allow the pwr clock to enable - crate::pac::PWR.cr1().read(); - } - fn read_backup_register(_rtc: &Rtc, register: usize) -> Option { #[allow(clippy::if_same_then_else)] if register < Self::BACKUP_REGISTER_COUNT { From dc400a05393fa9765a9ecb91cbbec10300a5e238 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 25 Sep 2023 16:27:08 -0500 Subject: [PATCH 208/233] stm32/rtc: always set wakeup alarm --- embassy-stm32/src/rtc/v2.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 331792a0..4608d311 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -75,15 +75,6 @@ impl super::Rtc { #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); - /* - If the requested duration is u64::MAX, don't even set the alarm - - Otherwise clamp the requested duration to u32::MAX so that we can do math - */ - if requested_duration.as_ticks() == u64::MAX { - return; - } - let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); let rtc_hz = Self::frequency().0 as u64; let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; From 96edbd84fbdc10a5b9b37a343941bc057be59467 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 25 Sep 2023 16:38:30 -0500 Subject: [PATCH 209/233] rtc: use enable on known working chips only --- embassy-stm32/src/rtc/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index b26b5ef3..73b78f25 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -10,7 +10,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; -use crate::rcc::sealed::RccPeripheral; pub use crate::rcc::RtcClockSource; use crate::time::Hertz; @@ -156,7 +155,8 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { - RTC::enable(); + #[cfg(any(rcc_wle, rcc_wl5, rcc_g4, rcc_g0, rtc_v2l4, rtc_v2wb))] + ::enable(); let mut this = Self { #[cfg(feature = "low-power")] From 5d8817d1095589e1916a92adc9db3feb1a3b91b5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Sep 2023 00:14:52 +0200 Subject: [PATCH 210/233] stm32/usart: return error instead of panicking on bad baudrate. --- embassy-stm32/src/usart/buffered.rs | 26 +++--- embassy-stm32/src/usart/mod.rs | 87 ++++++++++++-------- embassy-stm32/src/usart/ringbuffered.rs | 6 +- examples/stm32f3/src/bin/usart_dma.rs | 2 +- examples/stm32f4/src/bin/usart.rs | 2 +- examples/stm32f4/src/bin/usart_buffered.rs | 2 +- examples/stm32f4/src/bin/usart_dma.rs | 2 +- examples/stm32f7/src/bin/usart_dma.rs | 2 +- examples/stm32h5/src/bin/usart.rs | 2 +- examples/stm32h5/src/bin/usart_dma.rs | 2 +- examples/stm32h5/src/bin/usart_split.rs | 2 +- examples/stm32h7/src/bin/usart.rs | 2 +- examples/stm32h7/src/bin/usart_dma.rs | 2 +- examples/stm32h7/src/bin/usart_split.rs | 2 +- examples/stm32l0/src/bin/usart_dma.rs | 2 +- examples/stm32l0/src/bin/usart_irq.rs | 8 +- examples/stm32l4/src/bin/usart.rs | 2 +- examples/stm32l4/src/bin/usart_dma.rs | 2 +- examples/stm32wl/src/bin/uart_async.rs | 4 +- tests/stm32/src/bin/usart.rs | 6 +- tests/stm32/src/bin/usart_dma.rs | 2 +- tests/stm32/src/bin/usart_rx_ringbuffered.rs | 2 +- 22 files changed, 94 insertions(+), 75 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 323d8381..e2d6e42a 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -118,7 +118,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUart<'d, T> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config) + unwrap!(self.set_config(config)) } } @@ -126,7 +126,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartRx<'d, T> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config) + unwrap!(self.set_config(config)) } } @@ -134,7 +134,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config) + unwrap!(self.set_config(config)) } } @@ -147,7 +147,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, - ) -> BufferedUart<'d, T> { + ) -> Result { // UartRx and UartTx have one refcount ea. T::enable(); T::enable(); @@ -166,7 +166,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, - ) -> BufferedUart<'d, T> { + ) -> Result { into_ref!(cts, rts); // UartRx and UartTx have one refcount ea. @@ -194,7 +194,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, - ) -> BufferedUart<'d, T> { + ) -> Result { into_ref!(de); // UartRx and UartTx have one refcount ea. @@ -217,7 +217,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, - ) -> BufferedUart<'d, T> { + ) -> Result { into_ref!(_peri, rx, tx); let state = T::buffered_state(); @@ -230,7 +230,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - configure(r, &config, T::frequency(), T::KIND, true, true); + configure(r, &config, T::frequency(), T::KIND, true, true)?; r.cr1().modify(|w| { #[cfg(lpuart_v2)] @@ -243,17 +243,17 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { + Ok(Self { rx: BufferedUartRx { phantom: PhantomData }, tx: BufferedUartTx { phantom: PhantomData }, - } + }) } pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { (self.tx, self.rx) } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } } @@ -333,7 +333,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { } } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } } @@ -407,7 +407,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { } } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index ff02d0a6..45580fe3 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -13,11 +13,10 @@ use futures::future::{select, Either}; use crate::dma::{NoDma, Transfer}; use crate::gpio::sealed::AFType; use crate::interrupt::typelevel::Interrupt; -#[cfg(not(any(usart_v1, usart_v2)))] #[allow(unused_imports)] +#[cfg(not(any(usart_v1, usart_v2)))] use crate::pac::usart::regs::Isr as Sr; #[cfg(any(usart_v1, usart_v2))] -#[allow(unused_imports)] use crate::pac::usart::regs::Sr; #[cfg(not(any(usart_v1, usart_v2)))] use crate::pac::usart::Lpuart as Regs; @@ -76,12 +75,14 @@ impl interrupt::typelevel::Handler for Interrupt } #[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum DataBits { DataBits8, DataBits9, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Parity { ParityNone, ParityEven, @@ -89,6 +90,7 @@ pub enum Parity { } #[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum StopBits { #[doc = "1 stop bit"] STOP1, @@ -100,6 +102,14 @@ pub enum StopBits { STOP1P5, } +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ConfigError { + BaudrateTooLow, + BaudrateTooHigh, +} + #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Config { @@ -173,8 +183,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.tx.set_config(config); - self.rx.set_config(config); + unwrap!(self.tx.set_config(config)); + unwrap!(self.rx.set_config(config)); } } @@ -187,7 +197,7 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config); + unwrap!(self.set_config(config)); } } @@ -203,7 +213,7 @@ impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config); + unwrap!(self.set_config(config)); } } @@ -214,7 +224,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { tx: impl Peripheral

> + 'd, tx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { T::enable(); T::reset(); @@ -227,7 +237,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { cts: impl Peripheral

> + 'd, tx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(cts); T::enable(); @@ -245,25 +255,25 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { tx: impl Peripheral

> + 'd, tx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(_peri, tx, tx_dma); let r = T::regs(); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - configure(r, &config, T::frequency(), T::KIND, false, true); + configure(r, &config, T::frequency(), T::KIND, false, true)?; // create state once! let _s = T::state(); - Self { + Ok(Self { tx_dma, phantom: PhantomData, - } + }) } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } @@ -307,7 +317,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { rx: impl Peripheral

> + 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { T::enable(); T::reset(); @@ -321,7 +331,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { rts: impl Peripheral

> + 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(rts); T::enable(); @@ -340,14 +350,14 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { rx: impl Peripheral

> + 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(peri, rx, rx_dma); let r = T::regs(); rx.set_as_af(rx.af_num(), AFType::Input); - configure(r, &config, T::frequency(), T::KIND, true, false); + configure(r, &config, T::frequency(), T::KIND, true, false)?; T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -355,16 +365,16 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { // create state once! let _s = T::state(); - Self { + Ok(Self { _peri: peri, rx_dma, detect_previous_overrun: config.detect_previous_overrun, #[cfg(any(usart_v1, usart_v2))] buffered_sr: stm32_metapac::usart::regs::Sr(0), - } + }) } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } @@ -680,7 +690,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { // UartRx and UartTx have one refcount ea. T::enable(); T::enable(); @@ -699,7 +709,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(cts, rts); // UartRx and UartTx have one refcount ea. @@ -726,7 +736,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(de); // UartRx and UartTx have one refcount ea. @@ -748,7 +758,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(peri, rx, tx, tx_dma, rx_dma); let r = T::regs(); @@ -770,7 +780,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } - configure(r, &config, T::frequency(), T::KIND, true, true); + configure(r, &config, T::frequency(), T::KIND, true, true)?; T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -778,7 +788,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { // create state once! let _s = T::state(); - Self { + Ok(Self { tx: UartTx { tx_dma, phantom: PhantomData, @@ -790,10 +800,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { #[cfg(any(usart_v1, usart_v2))] buffered_sr: stm32_metapac::usart::regs::Sr(0), }, - } + }) } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } @@ -842,18 +852,27 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } -fn reconfigure(config: &Config) { +fn reconfigure(config: &Config) -> Result<(), ConfigError> { T::Interrupt::disable(); let r = T::regs(); let cr = r.cr1().read(); - configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te()); + configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te())?; T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; + + Ok(()) } -fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) { +fn configure( + r: Regs, + config: &Config, + pclk_freq: Hertz, + kind: Kind, + enable_rx: bool, + enable_tx: bool, +) -> Result<(), ConfigError> { if !enable_rx && !enable_tx { panic!("USART: At least one of RX or TX should be enabled"); } @@ -921,7 +940,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: found_brr = Some(brr); break; } - panic!("USART: baudrate too high"); + return Err(ConfigError::BaudrateTooHigh); } if brr < brr_max { @@ -933,7 +952,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: } } - let brr = found_brr.expect("USART: baudrate too low"); + let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?; #[cfg(not(usart_v1))] let oversampling = if over8 { "8 bit" } else { "16 bit" }; @@ -985,6 +1004,8 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: r.cr3().modify(|w| { w.set_onebit(config.assume_noise_free); }); + + Ok(()) } mod eh02 { diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index eed5ef5d..347aae7c 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -7,7 +7,7 @@ use embassy_embedded_hal::SetConfig; use embassy_hal_internal::PeripheralRef; use futures::future::{select, Either}; -use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, Error, UartRx}; +use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx}; use crate::dma::ReadableRingBuffer; use crate::usart::{Regs, Sr}; @@ -20,7 +20,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> SetConfig for RingBufferedUar type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config); + unwrap!(self.set_config(config)); } } @@ -63,7 +63,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD Err(err) } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { self.teardown_uart(); reconfigure::(config) } diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs index 85f01a69..ce8c212a 100644 --- a/examples/stm32f3/src/bin/usart_dma.rs +++ b/examples/stm32f3/src/bin/usart_dma.rs @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config); + let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index 7680fe84..45e94715 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs @@ -20,7 +20,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config).unwrap(); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs index c0a64d94..71abc289 100644 --- a/examples/stm32f4/src/bin/usart_buffered.rs +++ b/examples/stm32f4/src/bin/usart_buffered.rs @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { let mut tx_buf = [0u8; 32]; let mut rx_buf = [0u8; 32]; - let mut buf_usart = BufferedUart::new(p.USART3, Irqs, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config); + let mut buf_usart = BufferedUart::new(p.USART3, Irqs, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config).unwrap(); loop { let buf = buf_usart.fill_buf().await.unwrap(); diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index 3408ec37..dca25a78 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs index 4700287a..ba064081 100644 --- a/examples/stm32f7/src/bin/usart_dma.rs +++ b/examples/stm32f7/src/bin/usart_dma.rs @@ -20,7 +20,7 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs index 0abb94ab..db04d4e5 100644 --- a/examples/stm32h5/src/bin/usart.rs +++ b/examples/stm32h5/src/bin/usart.rs @@ -20,7 +20,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs index 48264f88..bafe5083 100644 --- a/examples/stm32h5/src/bin/usart_dma.rs +++ b/examples/stm32h5/src/bin/usart_dma.rs @@ -23,7 +23,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs index a6b2e690..d9037c01 100644 --- a/examples/stm32h5/src/bin/usart_split.rs +++ b/examples/stm32h5/src/bin/usart_split.rs @@ -36,7 +36,7 @@ async fn main(spawner: Spawner) -> ! { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); let (mut tx, rx) = usart.split(); diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs index 0abb94ab..db04d4e5 100644 --- a/examples/stm32h7/src/bin/usart.rs +++ b/examples/stm32h7/src/bin/usart.rs @@ -20,7 +20,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs index f1fe7fce..249050fd 100644 --- a/examples/stm32h7/src/bin/usart_dma.rs +++ b/examples/stm32h7/src/bin/usart_dma.rs @@ -23,7 +23,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs index aa075345..61c9f195 100644 --- a/examples/stm32h7/src/bin/usart_split.rs +++ b/examples/stm32h7/src/bin/usart_split.rs @@ -36,7 +36,7 @@ async fn main(spawner: Spawner) -> ! { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config).unwrap(); unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); let (mut tx, rx) = usart.split(); diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs index eae8f345..62c9b559 100644 --- a/examples/stm32l0/src/bin/usart_dma.rs +++ b/examples/stm32l0/src/bin/usart_dma.rs @@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH2, p.DMA1_CH3, Config::default()); + let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH2, p.DMA1_CH3, Config::default()).unwrap(); usart.write(b"Hello Embassy World!\r\n").await.unwrap(); info!("wrote Hello, starting echo"); diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs index f5dabcc4..5107a1a0 100644 --- a/examples/stm32l0/src/bin/usart_irq.rs +++ b/examples/stm32l0/src/bin/usart_irq.rs @@ -18,13 +18,11 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hi!"); - static mut TX_BUFFER: [u8; 8] = [0; 8]; - static mut RX_BUFFER: [u8; 256] = [0; 256]; - let mut config = Config::default(); config.baudrate = 9600; - - let mut usart = unsafe { BufferedUart::new(p.USART2, Irqs, p.PA3, p.PA2, &mut TX_BUFFER, &mut RX_BUFFER, config) }; + let mut tx_buf = [0u8; 256]; + let mut rx_buf = [0u8; 256]; + let mut usart = BufferedUart::new(p.USART2, Irqs, p.PA3, p.PA2, &mut tx_buf, &mut rx_buf, config).unwrap(); usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); info!("wrote Hello, starting echo"); diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index beb5ec55..f4da6b5a 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs @@ -19,7 +19,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config); + let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config).unwrap(); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index b7d4cb01..2f3b2a0f 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config); + let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs index 07b0f9d2..2c9b7c69 100644 --- a/examples/stm32wl/src/bin/uart_async.rs +++ b/examples/stm32wl/src/bin/uart_async.rs @@ -33,10 +33,10 @@ async fn main(_spawner: Spawner) { config2.baudrate = 9600; //RX/TX connected to USB/UART Bridge on LoRa-E5 mini v1.0 - let mut usart1 = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH3, p.DMA1_CH4, config1); + let mut usart1 = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH3, p.DMA1_CH4, config1).unwrap(); //RX1/TX1 (LPUART) on LoRa-E5 mini v1.0 - let mut usart2 = Uart::new(p.LPUART1, p.PC0, p.PC1, Irqs, p.DMA1_CH5, p.DMA1_CH6, config2); + let mut usart2 = Uart::new(p.LPUART1, p.PC0, p.PC1, Irqs, p.DMA1_CH5, p.DMA1_CH6, config2).unwrap(); unwrap!(usart1.write(b"Hello Embassy World!\r\n").await); unwrap!(usart2.write(b"Hello Embassy World!\r\n").await); diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index e789e543..fece2fb3 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -25,7 +25,7 @@ async fn main(_spawner: Spawner) { { let config = Config::default(); - let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config); + let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap(); // We can't send too many bytes, they have to fit in the FIFO. // This is because we aren't sending+receiving at the same time. @@ -41,7 +41,7 @@ async fn main(_spawner: Spawner) { // Test error handling with with an overflow error { let config = Config::default(); - let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config); + let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap(); // Send enough bytes to fill the RX FIFOs off all USART versions. let data = [0xC0, 0xDE, 0x12, 0x23, 0x34]; @@ -75,7 +75,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.baudrate = baudrate; - let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config); + let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap(); let n = (baudrate as usize / 100).max(64); diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index f203ebb5..1421f660 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs @@ -25,7 +25,7 @@ async fn main(_spawner: Spawner) { let irq = irqs!(UART); let config = Config::default(); - let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); + let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config).unwrap(); const LEN: usize = 128; let mut tx_buf = [0; LEN]; diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs index fdbeb9f6..1ee7e596 100644 --- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs @@ -40,7 +40,7 @@ async fn main(spawner: Spawner) { config.stop_bits = StopBits::STOP1; config.parity = Parity::ParityNone; - let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); + let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config).unwrap(); let (tx, rx) = usart.split(); static mut DMA_BUF: [u8; DMA_BUF_SIZE] = [0; DMA_BUF_SIZE]; let dma_buf = unsafe { DMA_BUF.as_mut() }; From 44bb40568302c6c7d766bfc7e42a15f02bdf89cd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Sep 2023 04:22:25 +0200 Subject: [PATCH 211/233] stm32/usart: enable fifo mode on usartv4. --- embassy-stm32/src/usart/mod.rs | 2 ++ tests/stm32/src/bin/usart.rs | 42 +++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 45580fe3..9835f1ac 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -998,6 +998,8 @@ fn configure( }); #[cfg(not(usart_v1))] w.set_over8(vals::Over8::from_bits(over8 as _)); + #[cfg(usart_v4)] + w.set_fifoen(true); }); #[cfg(not(usart_v1))] diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index fece2fb3..74a81b4e 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -5,11 +5,11 @@ mod common; use common::*; -use defmt::assert_eq; +use defmt::{assert, assert_eq, unreachable}; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; -use embassy_stm32::usart::{Config, Error, Uart}; -use embassy_time::{Duration, Instant}; +use embassy_stm32::usart::{Config, ConfigError, Error, Uart}; +use embassy_time::{block_for, Duration, Instant}; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -44,10 +44,16 @@ async fn main(_spawner: Spawner) { let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap(); // Send enough bytes to fill the RX FIFOs off all USART versions. - let data = [0xC0, 0xDE, 0x12, 0x23, 0x34]; + let data = [0; 64]; usart.blocking_write(&data).unwrap(); usart.blocking_flush().unwrap(); + // USART can still take up to 1 bit time (?) to receive the last byte + // that we just flushed, so wait a bit. + // otherwise, we might clear the overrun flag from an *earlier* byte and + // it gets set again when receiving the last byte is done. + block_for(Duration::from_millis(1)); + // The error should be reported first. let mut buf = [0; 1]; let err = usart.blocking_read(&mut buf); @@ -60,22 +66,25 @@ async fn main(_spawner: Spawner) { // Test that baudrate divider is calculated correctly. // Do it by comparing the time it takes to send a known number of bytes. - for baudrate in [ - 300, - 9600, - 115200, - 250_000, - 337_934, - #[cfg(not(feature = "stm32f103c8"))] - 1_000_000, - #[cfg(not(feature = "stm32f103c8"))] - 2_000_000, - ] { + for baudrate in [300, 9600, 115200, 250_000, 337_934, 1_000_000, 2_000_000] { info!("testing baudrate {}", baudrate); let mut config = Config::default(); config.baudrate = baudrate; - let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap(); + let mut usart = match Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config) { + Ok(x) => x, + Err(ConfigError::BaudrateTooHigh) => { + info!("baudrate too high"); + assert!(baudrate >= 1_000_000); + continue; + } + Err(ConfigError::BaudrateTooLow) => { + info!("baudrate too low"); + assert!(baudrate <= 300); + continue; + } + Err(_) => unreachable!(), + }; let n = (baudrate as usize / 100).max(64); @@ -83,6 +92,7 @@ async fn main(_spawner: Spawner) { for _ in 0..n { usart.blocking_write(&[0x00]).unwrap(); } + usart.blocking_flush().unwrap(); let dur = Instant::now() - start; let want_dur = Duration::from_micros(n as u64 * 10 * 1_000_000 / (baudrate as u64)); let fuzz = want_dur / 5; From c604d8a8f1b633874117fcf01018121f4fe05867 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Sep 2023 05:14:05 +0200 Subject: [PATCH 212/233] stm32/rcc: add voltage_scale, flash waitstates. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/rcc/l0.rs | 26 +++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 660ab053..08b9b3a3 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -59,7 +59,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-1551a1c01a993bb5ffc603311f80097c14e03f85" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-bdbf126746919e1c07730d80f9345b1a494c72a6" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-1551a1c01a993bb5ffc603311f80097c14e03f85", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-bdbf126746919e1c07730d80f9345b1a494c72a6", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 67355afb..7358be31 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -1,10 +1,11 @@ use super::bd::BackupDomain; pub use super::bus::{AHBPrescaler, APBPrescaler}; use super::RtcClockSource; +pub use crate::pac::pwr::vals::Vos as VoltageScale; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; -use crate::pac::RCC; #[cfg(crs)] use crate::pac::{crs, CRS, SYSCFG}; +use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -140,6 +141,7 @@ pub struct Config { pub rtc: Option, pub lse: Option, pub lsi: bool, + pub voltage_scale: VoltageScale, } impl Default for Config { @@ -155,11 +157,17 @@ impl Default for Config { rtc: None, lse: None, lsi: false, + voltage_scale: VoltageScale::RANGE1, } } } pub(crate) unsafe fn init(config: Config) { + // Set voltage scale + while PWR.csr().read().vosf() {} + PWR.cr().write(|w| w.set_vos(config.voltage_scale)); + while PWR.csr().read().vosf() {} + let (sys_clk, sw) = match config.mux { ClockSrc::MSI(range) => { // Set MSI range @@ -245,6 +253,22 @@ pub(crate) unsafe fn init(config: Config) { config.lse.map(|_| Default::default()), ); + let wait_states = match config.voltage_scale { + VoltageScale::RANGE1 => match sys_clk { + ..=16_000_000 => 0, + _ => 1, + }, + VoltageScale::RANGE2 => match sys_clk { + ..=8_000_000 => 0, + _ => 1, + }, + VoltageScale::RANGE3 => 0, + _ => unreachable!(), + }; + FLASH.acr().modify(|w| { + w.set_latency(wait_states != 0); + }); + RCC.cfgr().modify(|w| { w.set_sw(sw); w.set_hpre(config.ahb_pre.into()); From a57e48459eadff1776574f284a2d0a5d0b58a375 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Sep 2023 05:14:21 +0200 Subject: [PATCH 213/233] stm32/rcc: remove bad limits on l5. --- embassy-stm32/src/rcc/l5.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index 553b1619..652bdcb7 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs @@ -317,11 +317,6 @@ pub(crate) unsafe fn init(config: Config) { let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div(); - #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] - assert!(freq <= 120_000_000); - #[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))] - assert!(freq <= 80_000_000); - RCC.pllcfgr().write(move |w| { w.set_plln(mul.into()); w.set_pllm(prediv.into()); From 8b5fb254c04ec479b8a7f3bd5880a944313abbf7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Sep 2023 05:16:26 +0200 Subject: [PATCH 214/233] tests/stm32: add L0, L1, L4, L4+, L5 --- ci.sh | 5 +++ tests/stm32/Cargo.toml | 5 +++ tests/stm32/build.rs | 3 +- tests/stm32/src/common.rs | 91 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index 37d3e778..db5f4d80 100755 --- a/ci.sh +++ b/ci.sh @@ -173,6 +173,11 @@ cargo batch \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r5zi --out-dir out/tests/stm32l4r5zi \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze --out-dir out/tests/stm32l552ze \ --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \ --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index f78cb509..bfe5bc82 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -15,6 +15,11 @@ stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma", "dac-adc-pin"] # Nu stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # Nucleo stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board +stm32l073rz = ["embassy-stm32/stm32l073rz", "not-gpdma"] # Nucleo +stm32l152re = ["embassy-stm32/stm32l152re", "not-gpdma"] # Nucleo +stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "not-gpdma"] # Nucleo +stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "not-gpdma"] # Nucleo +stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma"] # Nucleo sdmmc = [] stop = ["embassy-stm32/low-power"] diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs index 2e71954d..9aabf854 100644 --- a/tests/stm32/build.rs +++ b/tests/stm32/build.rs @@ -12,7 +12,8 @@ fn main() -> Result<(), Box> { if cfg!(any( feature = "stm32f103c8", feature = "stm32c031c6", - feature = "stm32wb55rg" + feature = "stm32wb55rg", + feature = "stm32l073rz", )) { println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rerun-if-changed=link.x"); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 055eade6..9c0b8c39 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -24,6 +24,16 @@ teleprobe_meta::target!(b"iot-stm32u585ai"); teleprobe_meta::target!(b"nucleo-stm32h563zi"); #[cfg(feature = "stm32c031c6")] teleprobe_meta::target!(b"nucleo-stm32c031c6"); +#[cfg(feature = "stm32l073rz")] +teleprobe_meta::target!(b"nucleo-stm32l073rz"); +#[cfg(feature = "stm32l152re")] +teleprobe_meta::target!(b"nucleo-stm32l152re"); +#[cfg(feature = "stm32l4a6zg")] +teleprobe_meta::target!(b"nucleo-stm32l4a6zg"); +#[cfg(feature = "stm32l4r5zi")] +teleprobe_meta::target!(b"nucleo-stm32l4r5zi"); +#[cfg(feature = "stm32l552ze")] +teleprobe_meta::target!(b"nucleo-stm32l552ze"); macro_rules! define_peris { ($($name:ident = $peri:ident,)* $(@irq $irq_name:ident = $irq_code:tt,)*) => { @@ -109,6 +119,36 @@ define_peris!( SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, ); +#[cfg(feature = "stm32l4a6zg")] +define_peris!( + UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32l4r5zi")] +define_peris!( + UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32l073rz")] +define_peris!( + UART = USART4, UART_TX = PA0, UART_RX = PA1, UART_TX_DMA = DMA1_CH3, UART_RX_DMA = DMA1_CH2, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART4_5 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32l152re")] +define_peris!( + UART = USART3, UART_TX = PB10, UART_RX = PB11, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32l552ze")] +define_peris!( + UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH1, UART_RX_DMA = DMA1_CH2, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, +); pub fn config() -> Config { #[allow(unused_mut)] @@ -144,9 +184,58 @@ pub fn config() -> Config { config.rcc.adc_clock_source = AdcClockSource::PLL2_P; } + #[cfg(any(feature = "stm32l4a6zg", feature = "stm32l4r5zi"))] + { + use embassy_stm32::rcc::*; + config.rcc.mux = ClockSrc::PLL( + // 72Mhz clock (16 / 1 * 18 / 4) + PLLSource::HSI16, + PLLClkDiv::Div4, + PLLSrcDiv::Div1, + PLLMul::Mul18, + Some(PLLClkDiv::Div6), // 48Mhz (16 / 1 * 18 / 6) + ); + } + + #[cfg(any(feature = "stm32l552ze"))] + { + use embassy_stm32::rcc::*; + config.rcc.mux = ClockSrc::PLL( + // 110Mhz clock (16 / 4 * 55 / 2) + PLLSource::HSI16, + PLLClkDiv::Div2, + PLLSrcDiv::Div4, + PLLMul::Mul55, + None, + ); + } + #[cfg(feature = "stm32u585ai")] { - config.rcc.mux = embassy_stm32::rcc::ClockSrc::MSI(embassy_stm32::rcc::MSIRange::Range48mhz); + use embassy_stm32::rcc::*; + config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz); + } + + #[cfg(feature = "stm32l073rz")] + { + use embassy_stm32::rcc::*; + config.rcc.mux = ClockSrc::PLL( + // 32Mhz clock (16 * 4 / 2) + PLLSource::HSI16, + PLLMul::Mul4, + PLLDiv::Div2, + ); + } + + #[cfg(any(feature = "stm32l152re"))] + { + use embassy_stm32::rcc::*; + config.rcc.mux = ClockSrc::PLL( + // 32Mhz clock (16 * 4 / 2) + PLLSource::HSI, + PLLMul::Mul4, + PLLDiv::Div2, + ); } config From e1951f3ddffdeffab03bd0d20ebc1f7210738002 Mon Sep 17 00:00:00 2001 From: Mateusz Butkiewicz Date: Wed, 27 Sep 2023 15:13:43 +0200 Subject: [PATCH 215/233] feat(stm32f7): restore rtc configuration for stm32f7 series --- embassy-stm32/src/rcc/f7.rs | 18 ++++++++++++++++++ embassy-stm32/src/rcc/mod.rs | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs index 234511b0..f32559e2 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs @@ -1,6 +1,7 @@ use crate::pac::pwr::vals::Vos; use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -22,6 +23,9 @@ pub struct Config { pub pclk2: Option, pub pll48: bool, + pub rtc: Option, + pub lsi: bool, + pub lse: Option, } fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48clk: bool) -> PllResults { @@ -259,6 +263,18 @@ pub(crate) unsafe fn init(config: Config) { }) }); + BackupDomain::configure_ls( + config.rtc.unwrap_or(RtcClockSource::NOCLOCK), + config.lsi, + config.lse.map(|_| Default::default()), + ); + + let rtc = match config.rtc { + Some(RtcClockSource::LSI) => Some(LSI_FREQ), + Some(RtcClockSource::LSE) => Some(config.lse.unwrap()), + _ => None, + }; + set_freqs(Clocks { sys: Hertz(sysclk), apb1: Hertz(pclk1), @@ -272,6 +288,8 @@ pub(crate) unsafe fn init(config: Config) { ahb3: Hertz(hclk), pll48: plls.pll48clk.map(Hertz), + + rtc, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 0d6b0e30..9ccf2ac4 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -97,7 +97,7 @@ pub struct Clocks { #[cfg(stm32f334)] pub hrtim: Option, - #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7))] /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, From f866735802e142530491086adcb3f173c38ec570 Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Wed, 27 Sep 2023 20:15:24 -0400 Subject: [PATCH 216/233] Add support for input capture function --- embassy-stm32/src/timer/mod.rs | 231 +++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 839548a5..ea72b36a 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -15,6 +15,7 @@ pub mod low_level { } pub(crate) mod sealed { + use super::*; pub trait Basic16bitInstance: RccPeripheral { type Interrupt: interrupt::typelevel::Interrupt; @@ -32,10 +33,16 @@ pub(crate) mod sealed { fn clear_update_interrupt(&mut self) -> bool; fn enable_update_interrupt(&mut self, enable: bool); + + fn set_autoreload_preload(&mut self, enable: vals::Arpe); } pub trait GeneralPurpose16bitInstance: Basic16bitInstance { fn regs_gp16() -> crate::pac::timer::TimGp16; + + fn set_count_direction(&mut self, direction: vals::Dir); + + fn set_clock_division(&mut self, ckd: vals::Ckd); } pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { @@ -49,6 +56,16 @@ pub(crate) mod sealed { } pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { + fn clear_input_interrupt(&mut self, channel: Channel); + + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool); + + fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8); + + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection); + + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode); + /// Global output enable. Does not do anything on non-advanced timers. fn enable_outputs(&mut self, enable: bool); @@ -60,6 +77,8 @@ pub(crate) mod sealed { fn set_compare_value(&mut self, channel: Channel, value: u16); + fn get_capture_value(&mut self, channel: Channel) -> u16; + fn get_max_compare_value(&self) -> u16; } @@ -74,6 +93,16 @@ pub(crate) mod sealed { } pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { + fn clear_input_interrupt(&mut self, channel: Channel); + + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool); + + fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8); + + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection); + + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode); + fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity); @@ -82,6 +111,8 @@ pub(crate) mod sealed { fn set_compare_value(&mut self, channel: Channel, value: u32); + fn get_capture_value(&mut self, channel: Channel) -> u32; + fn get_max_compare_value(&self) -> u32; } } @@ -105,6 +136,30 @@ impl Channel { } } +#[derive(Clone, Copy)] +pub enum InputCaptureMode { + Rising, + Falling, + BothEdges, +} + +#[derive(Clone, Copy)] +pub enum InputTISelection { + Normal, + Alternate, + TRC, +} + +impl From for stm32_metapac::timer::vals::CcmrInputCcs { + fn from(tisel: InputTISelection) -> Self { + match tisel { + InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4, + InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3, + InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC, + } + } +} + #[derive(Clone, Copy)] pub enum OutputCompareMode { Frozen, @@ -242,6 +297,10 @@ macro_rules! impl_basic_16bit_timer { fn enable_update_interrupt(&mut self, enable: bool) { Self::regs().dier().write(|r| r.set_uie(enable)); } + + fn set_autoreload_preload(&mut self, enable: vals::Arpe) { + Self::regs().cr1().modify(|r| r.set_arpe(enable)); + } } }; } @@ -279,6 +338,51 @@ macro_rules! impl_32bit_timer { macro_rules! impl_compare_capable_16bit { ($inst:ident) => { impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn clear_input_interrupt(&mut self, channel: Channel) { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16() + .sr() + .modify(|r| r.set_ccif(channel.raw(), false)); + } + + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16() + .dier() + .modify(|r| r.set_ccie(channel.raw(), enable)); + } + fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + use sealed::GeneralPurpose16bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + use sealed::GeneralPurpose16bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.raw(), true); + r.set_ccp(channel.raw(), true); + } + }); + } fn enable_outputs(&mut self, _enable: bool) {} fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { @@ -308,6 +412,11 @@ macro_rules! impl_compare_capable_16bit { Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); } + fn get_capture_value(&mut self, channel: Channel) -> u16 { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16().ccr(channel.raw()).read().ccr() + } + fn get_max_compare_value(&self) -> u16 { use sealed::GeneralPurpose16bitInstance; Self::regs_gp16().arr().read().arr() @@ -332,6 +441,14 @@ foreach_interrupt! { fn regs_gp16() -> crate::pac::timer::TimGp16 { crate::pac::$inst } + + fn set_count_direction(&mut self, direction: vals::Dir) { + Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); + } + + fn set_clock_division(&mut self, ckd: vals::Ckd) { + Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); + } } }; @@ -346,6 +463,51 @@ foreach_interrupt! { impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { + fn clear_input_interrupt(&mut self, channel: Channel) { + use sealed::GeneralPurpose32bitInstance; + Self::regs_gp32() + .sr() + .modify(|r| r.set_ccif(channel.raw(), false)); + } + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + use sealed::GeneralPurpose32bitInstance; + Self::regs_gp32() + .dier() + .modify(|r| r.set_ccie(channel.raw(), enable)); + } + fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + use crate::timer::sealed::GeneralPurpose32bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp32() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + use crate::timer::sealed::GeneralPurpose32bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp32() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + use crate::timer::sealed::GeneralPurpose32bitInstance; + Self::regs_gp32().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.raw(), true); + r.set_ccp(channel.raw(), true); + } + }); + } fn set_output_compare_mode( &mut self, channel: Channel, @@ -373,6 +535,11 @@ foreach_interrupt! { Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); } + fn get_capture_value(&mut self, channel: Channel) -> u32 { + use crate::timer::sealed::GeneralPurpose32bitInstance; + Self::regs_gp32().ccr(channel.raw()).read().ccr() + } + fn get_max_compare_value(&self) -> u32 { use crate::timer::sealed::GeneralPurpose32bitInstance; Self::regs_gp32().arr().read().arr() as u32 @@ -383,6 +550,14 @@ foreach_interrupt! { fn regs_gp16() -> crate::pac::timer::TimGp16 { unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } } + + fn set_count_direction(&mut self, direction: vals::Dir) { + Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); + } + + fn set_clock_division(&mut self, ckd: vals::Ckd) { + Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); + } } }; @@ -399,6 +574,14 @@ foreach_interrupt! { fn regs_gp16() -> crate::pac::timer::TimGp16 { unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } } + + fn set_count_direction(&mut self, direction: vals::Dir) { + Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); + } + + fn set_clock_division(&mut self, ckd: vals::Ckd) { + Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); + } } impl sealed::AdvancedControlInstance for crate::peripherals::$inst { @@ -408,6 +591,49 @@ foreach_interrupt! { } impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn clear_input_interrupt(&mut self, channel: Channel) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced() + .sr() + .modify(|r| r.set_ccif(channel.raw(), false)); + } + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced() + .dier() + .modify(|r| r.set_ccie(channel.raw(), enable)); + } + fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + use crate::timer::sealed::AdvancedControlInstance; + let raw_channel = channel.raw(); + Self::regs_advanced() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + use crate::timer::sealed::AdvancedControlInstance; + let raw_channel = channel.raw(); + Self::regs_advanced() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.raw(), true); + r.set_ccp(channel.raw(), true); + } + }); + } fn enable_outputs(&mut self, enable: bool) { use crate::timer::sealed::AdvancedControlInstance; let r = Self::regs_advanced(); @@ -440,6 +666,11 @@ foreach_interrupt! { .modify(|w| w.set_cce(channel.raw(), enable)); } + fn get_capture_value(&mut self, channel: Channel) -> u16 { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced().ccr(channel.raw()).read().ccr() + } + fn set_compare_value(&mut self, channel: Channel, value: u16) { use crate::timer::sealed::AdvancedControlInstance; Self::regs_advanced() From 901f0257bd4b64d6ed846de701a0b71b1de4b16d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Sep 2023 03:46:48 +0200 Subject: [PATCH 217/233] net: allow non-'static drivers. --- embassy-net/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index f48d3372..0d7ac47a 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -258,7 +258,7 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> HardwareAddress } } -impl Stack { +impl Stack { /// Create a new network stack. pub fn new( mut device: D, @@ -555,7 +555,7 @@ impl Stack { } #[cfg(feature = "igmp")] -impl Stack { +impl Stack { /// Join a multicast group. pub async fn join_multicast_group(&self, addr: T) -> Result where @@ -645,7 +645,7 @@ impl SocketStack { } } -impl Inner { +impl Inner { #[cfg(feature = "proto-ipv4")] pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) { // Handle static config. From 3d1b4116eccec80ecdaacb1fab9f2a6dbe5800f4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Sep 2023 03:45:52 +0200 Subject: [PATCH 218/233] test: set DEFMT_LOG not too verbose so net perf tests pass with `cargo run`. --- tests/nrf/.cargo/config.toml | 2 +- tests/rp/.cargo/config.toml | 2 +- tests/stm32/.cargo/config.toml | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/nrf/.cargo/config.toml b/tests/nrf/.cargo/config.toml index 03995f96..9d6b0313 100644 --- a/tests/nrf/.cargo/config.toml +++ b/tests/nrf/.cargo/config.toml @@ -6,4 +6,4 @@ runner = "teleprobe client run" target = "thumbv7em-none-eabi" [env] -DEFMT_LOG = "trace" +DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,smoltcp=info" diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml index bc92e788..40b5d700 100644 --- a/tests/rp/.cargo/config.toml +++ b/tests/rp/.cargo/config.toml @@ -19,4 +19,4 @@ rustflags = [ target = "thumbv6m-none-eabi" [env] -DEFMT_LOG = "trace" +DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info" diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml index 07761b01..2e3f055d 100644 --- a/tests/stm32/.cargo/config.toml +++ b/tests/stm32/.cargo/config.toml @@ -14,7 +14,10 @@ rustflags = [ ] [build] -target = "thumbv7m-none-eabi" +target = "thumbv6m-none-eabi" +#target = "thumbv7m-none-eabi" +#target = "thumbv7em-none-eabi" +#target = "thumbv8m.main-none-eabihf" [env] -DEFMT_LOG = "trace" \ No newline at end of file +DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,smoltcp=info" \ No newline at end of file From d9eae79f3eea8bf968f61e476b599e9f8dc97aa8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Sep 2023 03:46:33 +0200 Subject: [PATCH 219/233] test: deduplicate net perf test code. --- tests/nrf/Cargo.toml | 1 + tests/nrf/src/bin/ethernet_enc28j60_perf.rs | 182 ++----------------- tests/nrf/src/bin/wifi_esp_hosted_perf.rs | 190 ++------------------ tests/perf-client/Cargo.toml | 12 ++ tests/perf-client/src/lib.rs | 179 ++++++++++++++++++ tests/rp/Cargo.toml | 1 + tests/rp/src/bin/cyw43-perf.rs | 189 ++----------------- tests/rp/src/bin/ethernet_w5100s_perf.rs | 182 ++----------------- 8 files changed, 248 insertions(+), 688 deletions(-) create mode 100644 tests/perf-client/Cargo.toml create mode 100644 tests/perf-client/src/lib.rs diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index b3d21468..08fe1a4b 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -19,6 +19,7 @@ embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", embedded-hal-async = { version = "1.0.0-rc.1" } embedded-hal-bus = { version = "0.1.0-rc.1", features = ["async"] } static_cell = { version = "1.1", features = [ "nightly" ] } +perf-client = { path = "../perf-client" } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs index 0446d39a..60d30a2f 100644 --- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs +++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs @@ -4,17 +4,15 @@ teleprobe_meta::target!(b"ak-gwe-r7"); teleprobe_meta::timeout!(120); -use defmt::{error, info, unwrap}; +use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_futures::join::join; -use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Stack, StackResources}; use embassy_net_enc28j60::Enc28j60; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; use embassy_nrf::{bind_interrupts, peripherals}; -use embassy_time::{with_timeout, Delay, Duration, Timer}; +use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; use static_cell::make_static; use {defmt_rtt as _, panic_probe as _}; @@ -79,172 +77,16 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); - info!("Waiting for DHCP up..."); - while stack.config_v4().is_none() { - Timer::after(Duration::from_millis(100)).await; - } - info!("IP addressing up!"); - - let down = test_download(stack).await; - let up = test_upload(stack).await; - let updown = test_upload_download(stack).await; - - assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS); - assert!(up > TEST_EXPECTED_UPLOAD_KBPS); - assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS); + perf_client::run( + stack, + perf_client::Expected { + down_kbps: 200, + up_kbps: 200, + updown_kbps: 150, + }, + ) + .await; info!("Test OK"); cortex_m::asm::bkpt(); } - -const TEST_DURATION: usize = 10; -const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 200; -const TEST_EXPECTED_UPLOAD_KBPS: usize = 200; -const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 150; -const RX_BUFFER_SIZE: usize = 4096; -const TX_BUFFER_SIZE: usize = 4096; -const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); -const DOWNLOAD_PORT: u16 = 4321; -const UPLOAD_PORT: u16 = 4322; -const UPLOAD_DOWNLOAD_PORT: u16 = 4323; - -async fn test_download(stack: &'static Stack) -> usize { - info!("Testing download..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let mut rx_buf = [0; 4096]; - let mut total: usize = 0; - with_timeout(Duration::from_secs(TEST_DURATION as _), async { - loop { - match socket.read(&mut rx_buf).await { - Ok(0) => { - error!("read EOF"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("read error: {:?}", e); - return 0; - } - } - } - }) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("download: {} kB/s", kbps); - kbps -} - -async fn test_upload(stack: &'static Stack) -> usize { - info!("Testing upload..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let buf = [0; 4096]; - let mut total: usize = 0; - with_timeout(Duration::from_secs(TEST_DURATION as _), async { - loop { - match socket.write(&buf).await { - Ok(0) => { - error!("write zero?!??!?!"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("write error: {:?}", e); - return 0; - } - } - } - }) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("upload: {} kB/s", kbps); - kbps -} - -async fn test_upload_download(stack: &'static Stack) -> usize { - info!("Testing upload+download..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let (mut reader, mut writer) = socket.split(); - - let tx_buf = [0; 4096]; - let mut rx_buf = [0; 4096]; - let mut total: usize = 0; - let tx_fut = async { - loop { - match writer.write(&tx_buf).await { - Ok(0) => { - error!("write zero?!??!?!"); - return 0; - } - Ok(_) => {} - Err(e) => { - error!("write error: {:?}", e); - return 0; - } - } - } - }; - - let rx_fut = async { - loop { - match reader.read(&mut rx_buf).await { - Ok(0) => { - error!("read EOF"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("read error: {:?}", e); - return 0; - } - } - } - }; - - with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("upload+download: {} kB/s", kbps); - kbps -} diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs index 97ebafec..9eee39cc 100644 --- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -4,16 +4,14 @@ teleprobe_meta::target!(b"nrf52840-dk"); teleprobe_meta::timeout!(120); -use defmt::{error, info, unwrap}; +use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_futures::join::join; -use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Ipv4Address, Stack, StackResources}; +use embassy_net::{Config, Stack, StackResources}; use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; use embassy_nrf::{bind_interrupts, peripherals}; -use embassy_time::{with_timeout, Delay, Duration, Timer}; +use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; use static_cell::make_static; use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; @@ -23,6 +21,10 @@ bind_interrupts!(struct Irqs { RNG => embassy_nrf::rng::InterruptHandler; }); +// Test-only wifi network, no internet access! +const WIFI_NETWORK: &str = "EmbassyTest"; +const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; + #[embassy_executor::task] async fn wifi_task( runner: hosted::Runner< @@ -92,176 +94,16 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); - info!("Waiting for DHCP up..."); - while stack.config_v4().is_none() { - Timer::after(Duration::from_millis(100)).await; - } - info!("IP addressing up!"); - - let down = test_download(stack).await; - let up = test_upload(stack).await; - let updown = test_upload_download(stack).await; - - assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS); - assert!(up > TEST_EXPECTED_UPLOAD_KBPS); - assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS); + perf_client::run( + stack, + perf_client::Expected { + down_kbps: 50, + up_kbps: 50, + updown_kbps: 50, + }, + ) + .await; info!("Test OK"); cortex_m::asm::bkpt(); } - -// Test-only wifi network, no internet access! -const WIFI_NETWORK: &str = "EmbassyTest"; -const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; - -const TEST_DURATION: usize = 10; -const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 50; -const TEST_EXPECTED_UPLOAD_KBPS: usize = 50; -const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 50; -const RX_BUFFER_SIZE: usize = 4096; -const TX_BUFFER_SIZE: usize = 4096; -const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); -const DOWNLOAD_PORT: u16 = 4321; -const UPLOAD_PORT: u16 = 4322; -const UPLOAD_DOWNLOAD_PORT: u16 = 4323; - -async fn test_download(stack: &'static Stack) -> usize { - info!("Testing download..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let mut rx_buf = [0; 4096]; - let mut total: usize = 0; - with_timeout(Duration::from_secs(TEST_DURATION as _), async { - loop { - match socket.read(&mut rx_buf).await { - Ok(0) => { - error!("read EOF"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("read error: {:?}", e); - return 0; - } - } - } - }) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("download: {} kB/s", kbps); - kbps -} - -async fn test_upload(stack: &'static Stack) -> usize { - info!("Testing upload..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let buf = [0; 4096]; - let mut total: usize = 0; - with_timeout(Duration::from_secs(TEST_DURATION as _), async { - loop { - match socket.write(&buf).await { - Ok(0) => { - error!("write zero?!??!?!"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("write error: {:?}", e); - return 0; - } - } - } - }) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("upload: {} kB/s", kbps); - kbps -} - -async fn test_upload_download(stack: &'static Stack) -> usize { - info!("Testing upload+download..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let (mut reader, mut writer) = socket.split(); - - let tx_buf = [0; 4096]; - let mut rx_buf = [0; 4096]; - let mut total: usize = 0; - let tx_fut = async { - loop { - match writer.write(&tx_buf).await { - Ok(0) => { - error!("write zero?!??!?!"); - return 0; - } - Ok(_) => {} - Err(e) => { - error!("write error: {:?}", e); - return 0; - } - } - } - }; - - let rx_fut = async { - loop { - match reader.read(&mut rx_buf).await { - Ok(0) => { - error!("read EOF"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("read error: {:?}", e); - return 0; - } - } - } - }; - - with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("upload+download: {} kB/s", kbps); - kbps -} diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml new file mode 100644 index 00000000..3284664d --- /dev/null +++ b/tests/perf-client/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "perf-client" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } +embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } +defmt = "0.3.0" diff --git a/tests/perf-client/src/lib.rs b/tests/perf-client/src/lib.rs new file mode 100644 index 00000000..a36147db --- /dev/null +++ b/tests/perf-client/src/lib.rs @@ -0,0 +1,179 @@ +#![no_std] + +use defmt::{assert, *}; +use embassy_futures::join::join; +use embassy_net::driver::Driver; +use embassy_net::tcp::TcpSocket; +use embassy_net::{Ipv4Address, Stack}; +use embassy_time::{with_timeout, Duration, Timer}; + +pub struct Expected { + pub down_kbps: usize, + pub up_kbps: usize, + pub updown_kbps: usize, +} + +pub async fn run(stack: &Stack, expected: Expected) { + info!("Waiting for DHCP up..."); + while stack.config_v4().is_none() { + Timer::after(Duration::from_millis(100)).await; + } + info!("IP addressing up!"); + + let down = test_download(stack).await; + let up = test_upload(stack).await; + let updown = test_upload_download(stack).await; + + assert!(down > expected.down_kbps); + assert!(up > expected.up_kbps); + assert!(updown > expected.updown_kbps); +} + +const TEST_DURATION: usize = 10; +const RX_BUFFER_SIZE: usize = 4096; +const TX_BUFFER_SIZE: usize = 4096; +const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); +const DOWNLOAD_PORT: u16 = 4321; +const UPLOAD_PORT: u16 = 4322; +const UPLOAD_DOWNLOAD_PORT: u16 = 4323; + +async fn test_download(stack: &Stack) -> usize { + info!("Testing download..."); + + let mut rx_buffer = [0; RX_BUFFER_SIZE]; + let mut tx_buffer = [0; TX_BUFFER_SIZE]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); + if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { + error!("connect error: {:?}", e); + return 0; + } + info!("connected, testing..."); + + let mut rx_buf = [0; 4096]; + let mut total: usize = 0; + with_timeout(Duration::from_secs(TEST_DURATION as _), async { + loop { + match socket.read(&mut rx_buf).await { + Ok(0) => { + error!("read EOF"); + return 0; + } + Ok(n) => total += n, + Err(e) => { + error!("read error: {:?}", e); + return 0; + } + } + } + }) + .await + .ok(); + + let kbps = (total + 512) / 1024 / TEST_DURATION; + info!("download: {} kB/s", kbps); + kbps +} + +async fn test_upload(stack: &Stack) -> usize { + info!("Testing upload..."); + + let mut rx_buffer = [0; RX_BUFFER_SIZE]; + let mut tx_buffer = [0; TX_BUFFER_SIZE]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); + if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { + error!("connect error: {:?}", e); + return 0; + } + info!("connected, testing..."); + + let buf = [0; 4096]; + let mut total: usize = 0; + with_timeout(Duration::from_secs(TEST_DURATION as _), async { + loop { + match socket.write(&buf).await { + Ok(0) => { + error!("write zero?!??!?!"); + return 0; + } + Ok(n) => total += n, + Err(e) => { + error!("write error: {:?}", e); + return 0; + } + } + } + }) + .await + .ok(); + + let kbps = (total + 512) / 1024 / TEST_DURATION; + info!("upload: {} kB/s", kbps); + kbps +} + +async fn test_upload_download(stack: &Stack) -> usize { + info!("Testing upload+download..."); + + let mut rx_buffer = [0; RX_BUFFER_SIZE]; + let mut tx_buffer = [0; TX_BUFFER_SIZE]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); + if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { + error!("connect error: {:?}", e); + return 0; + } + info!("connected, testing..."); + + let (mut reader, mut writer) = socket.split(); + + let tx_buf = [0; 4096]; + let mut rx_buf = [0; 4096]; + let mut total: usize = 0; + let tx_fut = async { + loop { + match writer.write(&tx_buf).await { + Ok(0) => { + error!("write zero?!??!?!"); + return 0; + } + Ok(_) => {} + Err(e) => { + error!("write error: {:?}", e); + return 0; + } + } + } + }; + + let rx_fut = async { + loop { + match reader.read(&mut rx_buf).await { + Ok(0) => { + error!("read EOF"); + return 0; + } + Ok(n) => total += n, + Err(e) => { + error!("read error: {:?}", e); + return 0; + } + } + } + }; + + with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) + .await + .ok(); + + let kbps = (total + 512) / 1024 / TEST_DURATION; + info!("upload+download: {} kB/s", kbps); + kbps +} diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 26e2473c..8bb0de6c 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -16,6 +16,7 @@ embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defm embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } +perf-client = { path = "../perf-client" } defmt = "0.3.0" defmt-rtt = "0.4" diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 1c665f95..de29c06d 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -4,16 +4,13 @@ teleprobe_meta::target!(b"rpi-pico"); use cyw43_pio::PioSpi; -use defmt::{assert, panic, *}; +use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_futures::join::join; -use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Ipv4Address, Stack, StackResources}; +use embassy_net::{Config, Stack, StackResources}; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::{bind_interrupts, rom_data}; -use embassy_time::{with_timeout, Duration, Timer}; use static_cell::make_static; use {defmt_rtt as _, panic_probe as _}; @@ -23,6 +20,10 @@ bind_interrupts!(struct Irqs { teleprobe_meta::timeout!(120); +// Test-only wifi network, no internet access! +const WIFI_NETWORK: &str = "EmbassyTest"; +const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; + #[embassy_executor::task] async fn wifi_task( runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, @@ -88,176 +89,16 @@ async fn main(spawner: Spawner) { } } - info!("Waiting for DHCP up..."); - while stack.config_v4().is_none() { - Timer::after(Duration::from_millis(100)).await; - } - info!("IP addressing up!"); - - let down = test_download(stack).await; - let up = test_upload(stack).await; - let updown = test_upload_download(stack).await; - - assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS); - assert!(up > TEST_EXPECTED_UPLOAD_KBPS); - assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS); + perf_client::run( + stack, + perf_client::Expected { + down_kbps: 300, + up_kbps: 300, + updown_kbps: 300, + }, + ) + .await; info!("Test OK"); cortex_m::asm::bkpt(); } - -// Test-only wifi network, no internet access! -const WIFI_NETWORK: &str = "EmbassyTest"; -const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; - -const TEST_DURATION: usize = 10; -const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 300; -const TEST_EXPECTED_UPLOAD_KBPS: usize = 300; -const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 300; -const RX_BUFFER_SIZE: usize = 4096; -const TX_BUFFER_SIZE: usize = 4096; -const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); -const DOWNLOAD_PORT: u16 = 4321; -const UPLOAD_PORT: u16 = 4322; -const UPLOAD_DOWNLOAD_PORT: u16 = 4323; - -async fn test_download(stack: &'static Stack>) -> usize { - info!("Testing download..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let mut rx_buf = [0; 4096]; - let mut total: usize = 0; - with_timeout(Duration::from_secs(TEST_DURATION as _), async { - loop { - match socket.read(&mut rx_buf).await { - Ok(0) => { - error!("read EOF"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("read error: {:?}", e); - return 0; - } - } - } - }) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("download: {} kB/s", kbps); - kbps -} - -async fn test_upload(stack: &'static Stack>) -> usize { - info!("Testing upload..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let buf = [0; 4096]; - let mut total: usize = 0; - with_timeout(Duration::from_secs(TEST_DURATION as _), async { - loop { - match socket.write(&buf).await { - Ok(0) => { - error!("write zero?!??!?!"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("write error: {:?}", e); - return 0; - } - } - } - }) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("upload: {} kB/s", kbps); - kbps -} - -async fn test_upload_download(stack: &'static Stack>) -> usize { - info!("Testing upload+download..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let (mut reader, mut writer) = socket.split(); - - let tx_buf = [0; 4096]; - let mut rx_buf = [0; 4096]; - let mut total: usize = 0; - let tx_fut = async { - loop { - match writer.write(&tx_buf).await { - Ok(0) => { - error!("write zero?!??!?!"); - return 0; - } - Ok(_) => {} - Err(e) => { - error!("write error: {:?}", e); - return 0; - } - } - } - }; - - let rx_fut = async { - loop { - match reader.read(&mut rx_buf).await { - Ok(0) => { - error!("read EOF"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("read error: {:?}", e); - return 0; - } - } - } - }; - - with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("upload+download: {} kB/s", kbps); - kbps -} diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs index faa8638c..a4d253b3 100644 --- a/tests/rp/src/bin/ethernet_w5100s_perf.rs +++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs @@ -4,18 +4,16 @@ teleprobe_meta::target!(b"w5100s-evb-pico"); teleprobe_meta::timeout!(120); -use defmt::{assert, *}; +use defmt::*; use embassy_executor::Spawner; -use embassy_futures::join::join; -use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Stack, StackResources}; use embassy_net_wiznet::chip::W5100S; use embassy_net_wiznet::*; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Level, Output, Pull}; use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; -use embassy_time::{with_timeout, Delay, Duration, Timer}; +use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; use rand::RngCore; use static_cell::make_static; @@ -78,172 +76,16 @@ async fn main(spawner: Spawner) { // Launch network task unwrap!(spawner.spawn(net_task(&stack))); - info!("Waiting for DHCP up..."); - while stack.config_v4().is_none() { - Timer::after(Duration::from_millis(100)).await; - } - info!("IP addressing up!"); - - let down = test_download(stack).await; - let up = test_upload(stack).await; - let updown = test_upload_download(stack).await; - - assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS); - assert!(up > TEST_EXPECTED_UPLOAD_KBPS); - assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS); + perf_client::run( + stack, + perf_client::Expected { + down_kbps: 500, + up_kbps: 500, + updown_kbps: 300, + }, + ) + .await; info!("Test OK"); cortex_m::asm::bkpt(); } - -const TEST_DURATION: usize = 10; -const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 500; -const TEST_EXPECTED_UPLOAD_KBPS: usize = 500; -const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 300; -const RX_BUFFER_SIZE: usize = 4096; -const TX_BUFFER_SIZE: usize = 4096; -const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); -const DOWNLOAD_PORT: u16 = 4321; -const UPLOAD_PORT: u16 = 4322; -const UPLOAD_DOWNLOAD_PORT: u16 = 4323; - -async fn test_download(stack: &'static Stack>) -> usize { - info!("Testing download..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let mut rx_buf = [0; 4096]; - let mut total: usize = 0; - with_timeout(Duration::from_secs(TEST_DURATION as _), async { - loop { - match socket.read(&mut rx_buf).await { - Ok(0) => { - error!("read EOF"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("read error: {:?}", e); - return 0; - } - } - } - }) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("download: {} kB/s", kbps); - kbps -} - -async fn test_upload(stack: &'static Stack>) -> usize { - info!("Testing upload..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let buf = [0; 4096]; - let mut total: usize = 0; - with_timeout(Duration::from_secs(TEST_DURATION as _), async { - loop { - match socket.write(&buf).await { - Ok(0) => { - error!("write zero?!??!?!"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("write error: {:?}", e); - return 0; - } - } - } - }) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("upload: {} kB/s", kbps); - kbps -} - -async fn test_upload_download(stack: &'static Stack>) -> usize { - info!("Testing upload+download..."); - - let mut rx_buffer = [0; RX_BUFFER_SIZE]; - let mut tx_buffer = [0; TX_BUFFER_SIZE]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); - if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { - error!("connect error: {:?}", e); - return 0; - } - info!("connected, testing..."); - - let (mut reader, mut writer) = socket.split(); - - let tx_buf = [0; 4096]; - let mut rx_buf = [0; 4096]; - let mut total: usize = 0; - let tx_fut = async { - loop { - match writer.write(&tx_buf).await { - Ok(0) => { - error!("write zero?!??!?!"); - return 0; - } - Ok(_) => {} - Err(e) => { - error!("write error: {:?}", e); - return 0; - } - } - } - }; - - let rx_fut = async { - loop { - match reader.read(&mut rx_buf).await { - Ok(0) => { - error!("read EOF"); - return 0; - } - Ok(n) => total += n, - Err(e) => { - error!("read error: {:?}", e); - return 0; - } - } - } - }; - - with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) - .await - .ok(); - - let kbps = (total + 512) / 1024 / TEST_DURATION; - info!("upload+download: {} kB/s", kbps); - kbps -} From 79146c4bd5cdbd8337d0dbdfd93219b9cb330c47 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 27 Sep 2023 20:58:46 -0500 Subject: [PATCH 220/233] stm32/adc: cleanup f1, f3, v1, and v2 --- embassy-stm32/src/adc/f1.rs | 51 +++++++++++++++++++++++++++++---- embassy-stm32/src/adc/f3.rs | 20 +++++++++++++ embassy-stm32/src/adc/mod.rs | 18 ++++++++---- embassy-stm32/src/adc/v1.rs | 35 ++++++++-------------- embassy-stm32/src/adc/v2.rs | 36 +++++++++-------------- examples/stm32f0/src/bin/adc.rs | 2 +- examples/stm32f1/src/bin/adc.rs | 10 +++++-- examples/stm32f4/src/bin/adc.rs | 6 ++-- examples/stm32f7/src/bin/adc.rs | 2 +- 9 files changed, 116 insertions(+), 64 deletions(-) diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 147349de..c1326481 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -1,16 +1,37 @@ +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; + use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; use crate::rcc::get_freqs; use crate::time::Hertz; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; // No calibration data for F103, voltage should be 1.2v pub const VREF_INT: u32 = 1200; +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + if T::regs().sr().read().eoc() { + T::regs().cr1().modify(|w| w.set_eocie(false)); + } else { + return; + } + + T::state().waker.wake(); + } +} + pub struct Vref; impl AdcPin for Vref {} impl super::sealed::AdcPin for Vref { @@ -95,18 +116,28 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Perform a single conversion. - fn convert(&mut self) -> u16 { + async fn convert(&mut self) -> u16 { T::regs().cr2().modify(|reg| { reg.set_adon(true); reg.set_swstart(true); }); - while T::regs().cr2().read().swstart() {} - while !T::regs().sr().read().eoc() {} + T::regs().cr1().modify(|w| w.set_eocie(true)); + + poll_fn(|cx| { + T::state().waker.register(cx.waker()); + + if !T::regs().cr2().read().swstart() && T::regs().sr().read().eoc() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; T::regs().dr().read().0 as u16 } - pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { + pub async fn read(&mut self, pin: &mut impl AdcPin) -> u16 { Self::set_channel_sample_time(pin.channel(), self.sample_time); T::regs().cr1().modify(|reg| { reg.set_scan(false); @@ -123,7 +154,7 @@ impl<'d, T: Instance> Adc<'d, T> { // Configure the channel to sample T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())); - self.convert() + self.convert().await } fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { @@ -135,3 +166,11 @@ impl<'d, T: Instance> Adc<'d, T> { } } } + +impl<'d, T: Instance> Drop for Adc<'d, T> { + fn drop(&mut self) { + T::regs().cr2().modify(|reg| reg.set_adon(false)); + + T::disable(); + } +} diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 5d2ea1da..7c13f810 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -173,3 +173,23 @@ impl<'d, T: Instance> Adc<'d, T> { } } } + +impl<'d, T: Instance> Drop for Adc<'d, T> { + fn drop(&mut self) { + use crate::pac::adc::vals; + + T::regs().cr().modify(|w| w.set_adstp(true)); + + while T::regs().cr().read().adstp() {} + + T::regs().cr().modify(|w| w.set_addis(true)); + + while T::regs().cr().read().aden() {} + + // Disable the adc regulator + T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); + T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED)); + + T::disable(); + } +} diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 2f8f8f9e..365738a3 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -31,15 +31,15 @@ pub struct Adc<'d, T: Instance> { } pub(crate) mod sealed { - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] use embassy_sync::waitqueue::AtomicWaker; - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] pub struct State { pub waker: AtomicWaker, } - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] impl State { pub const fn new() -> Self { Self { @@ -58,11 +58,14 @@ pub(crate) mod sealed { fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz; - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] fn state() -> &'static State; } pub trait AdcPin { + #[cfg(any(adc_v1, adc_v2))] + fn set_as_analog(&mut self) {} + fn channel(&self) -> u8; } @@ -96,7 +99,7 @@ foreach_adc!( unsafe { crate::rcc::get_freqs() }.$clock.unwrap() } - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] fn state() -> &'static sealed::State { static STATE: sealed::State = sealed::State::new(); &STATE @@ -120,6 +123,11 @@ macro_rules! impl_adc_pin { impl crate::adc::AdcPin for crate::peripherals::$pin {} impl crate::adc::sealed::AdcPin for crate::peripherals::$pin { + #[cfg(any(adc_v1, adc_v2))] + fn set_as_analog(&mut self) { + ::set_as_analog(self); + } + fn channel(&self) -> u8 { $ch } diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 15b2dc59..fded26e4 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -5,7 +5,7 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; +use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; use crate::{interrupt, Peripheral}; @@ -31,24 +31,24 @@ impl interrupt::typelevel::Handler for InterruptHandl } pub struct Vbat; -impl InternalChannel for Vbat {} -impl super::sealed::InternalChannel for Vbat { +impl AdcPin for Vbat {} +impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { 18 } } pub struct Vref; -impl InternalChannel for Vref {} -impl super::sealed::InternalChannel for Vref { +impl AdcPin for Vref {} +impl super::sealed::AdcPin for Vref { fn channel(&self) -> u8 { 17 } } pub struct Temperature; -impl InternalChannel for Temperature {} -impl super::sealed::InternalChannel for Temperature { +impl AdcPin for Temperature {} +impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { 16 } @@ -134,18 +134,14 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); } - pub async fn read

(&mut self, pin: &mut P) -> u16 - where - P: AdcPin + crate::gpio::sealed::Pin, - { + pub async fn read(&mut self, pin: &mut impl AdcPin) -> u16 { let channel = pin.channel(); pin.set_as_analog(); - self.read_channel(channel).await - } - pub async fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { - let channel = channel.channel(); - self.read_channel(channel).await + // A.7.5 Single conversion sequence code example - Software trigger + T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); + + self.convert().await } async fn convert(&mut self) -> u16 { @@ -171,13 +167,6 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().data() } - - async fn read_channel(&mut self, channel: u8) -> u16 { - // A.7.5 Single conversion sequence code example - Software trigger - T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); - - self.convert().await - } } impl<'d, T: Instance> Drop for Adc<'d, T> { diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index f583c08a..a669013c 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,7 +1,6 @@ use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use super::InternalChannel; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; use crate::time::Hertz; @@ -16,8 +15,8 @@ pub const VREF_CALIB_MV: u32 = 3300; pub const ADC_POWERUP_TIME_US: u32 = 3; pub struct VrefInt; -impl InternalChannel for VrefInt {} -impl super::sealed::InternalChannel for VrefInt { +impl AdcPin for VrefInt {} +impl super::sealed::AdcPin for VrefInt { fn channel(&self) -> u8 { 17 } @@ -31,8 +30,8 @@ impl VrefInt { } pub struct Temperature; -impl InternalChannel for Temperature {} -impl super::sealed::InternalChannel for Temperature { +impl AdcPin for Temperature {} +impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { cfg_if::cfg_if! { if #[cfg(any(stm32f40, stm32f41))] { @@ -52,8 +51,8 @@ impl Temperature { } pub struct Vbat; -impl InternalChannel for Vbat {} -impl super::sealed::InternalChannel for Vbat { +impl AdcPin for Vbat {} +impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { 18 } @@ -176,22 +175,11 @@ where T::regs().dr().read().0 as u16 } - pub fn read

(&mut self, pin: &mut P) -> u16 - where - P: AdcPin, - P: crate::gpio::sealed::Pin, - { + pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { pin.set_as_analog(); - self.read_channel(pin.channel()) - } - - pub fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { - self.read_channel(channel.channel()) - } - - fn read_channel(&mut self, channel: u8) -> u16 { // Configure ADC + let channel = pin.channel(); // Select channel T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); @@ -199,9 +187,7 @@ where // Configure channel Self::set_channel_sample_time(channel, self.sample_time); - let val = self.convert(); - - val + self.convert() } fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { @@ -216,6 +202,10 @@ where impl<'d, T: Instance> Drop for Adc<'d, T> { fn drop(&mut self) { + T::regs().cr2().modify(|reg| { + reg.set_adon(false); + }); + T::disable(); } } diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index 2ed46a94..1564ecfc 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { let mut pin = p.PA1; let mut vrefint = adc.enable_vref(&mut Delay); - let vrefint_sample = adc.read_internal(&mut vrefint).await; + let vrefint_sample = adc.read(&mut vrefint).await; let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf // 6.3.4 Embedded reference voltage diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs index ed59e279..30947c3c 100644 --- a/examples/stm32f1/src/bin/adc.rs +++ b/examples/stm32f1/src/bin/adc.rs @@ -5,9 +5,15 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::Adc; +use embassy_stm32::peripherals::ADC1; +use embassy_stm32::{adc, bind_interrupts}; use embassy_time::{Delay, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + ADC1_2 => adc::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); @@ -17,7 +23,7 @@ async fn main(_spawner: Spawner) { let mut pin = p.PB1; let mut vrefint = adc.enable_vref(&mut Delay); - let vrefint_sample = adc.read(&mut vrefint); + let vrefint_sample = adc.read(&mut vrefint).await; let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/CD00161566.pdf // 5.3.4 Embedded reference voltage @@ -27,7 +33,7 @@ async fn main(_spawner: Spawner) { }; loop { - let v = adc.read(&mut pin); + let v = adc.read(&mut pin).await; info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after(Duration::from_millis(100)).await; } diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs index 1c9a0b35..dd10385c 100644 --- a/examples/stm32f4/src/bin/adc.rs +++ b/examples/stm32f4/src/bin/adc.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { // Startup delay can be combined to the maximum of either delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); - let vrefint_sample = adc.read_internal(&mut vrefint); + let vrefint_sample = adc.read(&mut vrefint); let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/DM00071990.pdf @@ -55,12 +55,12 @@ async fn main(_spawner: Spawner) { info!("PC1: {} ({} mV)", v, convert_to_millivolts(v)); // Read internal temperature - let v = adc.read_internal(&mut temp); + let v = adc.read(&mut temp); let celcius = convert_to_celcius(v); info!("Internal temp: {} ({} C)", v, celcius); // Read internal voltage reference - let v = adc.read_internal(&mut vrefint); + let v = adc.read(&mut vrefint); info!("VrefInt: {}", v); Timer::after(Duration::from_millis(100)).await; diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs index 70b3b2a7..bc4ed289 100644 --- a/examples/stm32f7/src/bin/adc.rs +++ b/examples/stm32f7/src/bin/adc.rs @@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) { let mut pin = p.PA3; let mut vrefint = adc.enable_vrefint(); - let vrefint_sample = adc.read_internal(&mut vrefint); + let vrefint_sample = adc.read(&mut vrefint); let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/DM00273119.pdf // 6.3.27 Reference voltage From 6200d22438be21a014d95b9d4dde872fab18a51b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Sep 2023 05:12:35 +0200 Subject: [PATCH 221/233] stm32/eth: fix receiving large frames on v2. --- embassy-stm32/src/eth/v2/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index f03ea2e3..b7fe4766 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -34,8 +34,6 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet - pub struct Ethernet<'d, T: Instance, P: PHY> { _peri: PeripheralRef<'d, T>, pub(crate) tx: TDesRing<'d>, @@ -163,7 +161,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ? dma.dmacrx_cr().modify(|w| { w.set_rxpbl(1); // 32 ? - w.set_rbsz(MTU as u16); + w.set_rbsz(RX_BUFFER_SIZE as u16); }); // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called From 6b3745fc4741b536b111f6e9bbc39e108d8a2eef Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Sep 2023 05:17:22 +0200 Subject: [PATCH 222/233] temporarily disable wifi_esp_hosted_perf test. --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index db5f4d80..af98d6ed 100755 --- a/ci.sh +++ b/ci.sh @@ -183,6 +183,7 @@ cargo batch \ --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ $BUILD_EXTRA +rm out/tests/nrf52840-dk/wifi_esp_hosted_perf if [[ -z "${TELEPROBE_TOKEN-}" ]]; then echo No teleprobe token found, skipping running HIL tests From b9ef831ff780526e6bbc24b60aa69bdcbd82880e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 28 Sep 2023 09:39:12 +0200 Subject: [PATCH 223/233] Add 80MHz tick rate --- embassy-time/CHANGELOG.md | 4 ++++ embassy-time/Cargo.toml | 3 ++- embassy-time/gen_tick.py | 1 + embassy-time/src/tick.rs | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index 8bf02dbc..4389e6ce 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.1.4 - ??? + +- Added `tick-hz-80_000_000` + ## 0.1.3 - 2023-08-28 - Update `embedded-hal-async` to `1.0.0-rc.1` diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 03aa6ca2..a290509d 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-time" -version = "0.1.3" +version = "0.1.4" edition = "2021" description = "Instant and Duration for embedded no-std systems, with async timer support" repository = "https://github.com/embassy-rs/embassy" @@ -145,6 +145,7 @@ tick-hz-384_000_000 = [] tick-hz-512_000_000 = [] tick-hz-576_000_000 = [] tick-hz-768_000_000 = [] +tick-hz-80_000_000 = [] # END TICKS [dependencies] diff --git a/embassy-time/gen_tick.py b/embassy-time/gen_tick.py index 15e65187..804b6bb4 100644 --- a/embassy-time/gen_tick.py +++ b/embassy-time/gen_tick.py @@ -17,6 +17,7 @@ for i in range(1, 10): ticks.append(2**i * 1000000) ticks.append(2**i * 9 // 8 * 1000000) ticks.append(2**i * 3 // 2 * 1000000) +ticks.append(80_000_000) seen = set() ticks = [x for x in ticks if not (x in seen or seen.add(x))] diff --git a/embassy-time/src/tick.rs b/embassy-time/src/tick.rs index 608bc44f..0a4a0276 100644 --- a/embassy-time/src/tick.rs +++ b/embassy-time/src/tick.rs @@ -156,6 +156,8 @@ pub const TICK_HZ: u64 = 512_000_000; pub const TICK_HZ: u64 = 576_000_000; #[cfg(feature = "tick-hz-768_000_000")] pub const TICK_HZ: u64 = 768_000_000; +#[cfg(feature = "tick-hz-80_000_000")] +pub const TICK_HZ: u64 = 80_000_000; #[cfg(not(any( feature = "tick-hz-1", feature = "tick-hz-10", @@ -235,5 +237,6 @@ pub const TICK_HZ: u64 = 768_000_000; feature = "tick-hz-512_000_000", feature = "tick-hz-576_000_000", feature = "tick-hz-768_000_000", + feature = "tick-hz-80_000_000", )))] pub const TICK_HZ: u64 = 1_000_000; From 23f3889167903c6e800f056517c2c831e73ed081 Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Thu, 28 Sep 2023 09:35:43 -0400 Subject: [PATCH 224/233] Add support for STM32 input capture filter --- embassy-stm32/src/timer/mod.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index ea72b36a..1d642ed3 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -56,6 +56,8 @@ pub(crate) mod sealed { } pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf); + fn clear_input_interrupt(&mut self, channel: Channel); fn enable_input_interrupt(&mut self, channel: Channel, enable: bool); @@ -93,6 +95,8 @@ pub(crate) mod sealed { } pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf); + fn clear_input_interrupt(&mut self, channel: Channel); fn enable_input_interrupt(&mut self, channel: Channel, enable: bool); @@ -338,6 +342,14 @@ macro_rules! impl_32bit_timer { macro_rules! impl_compare_capable_16bit { ($inst:ident) => { impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { + use sealed::GeneralPurpose16bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + fn clear_input_interrupt(&mut self, channel: Channel) { use sealed::GeneralPurpose16bitInstance; Self::regs_gp16() @@ -463,6 +475,14 @@ foreach_interrupt! { impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { + use sealed::GeneralPurpose32bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp32() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + fn clear_input_interrupt(&mut self, channel: Channel) { use sealed::GeneralPurpose32bitInstance; Self::regs_gp32() @@ -591,6 +611,14 @@ foreach_interrupt! { } impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { + use crate::timer::sealed::AdvancedControlInstance; + let raw_channel = channel.raw(); + Self::regs_advanced() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + fn clear_input_interrupt(&mut self, channel: Channel) { use crate::timer::sealed::AdvancedControlInstance; Self::regs_advanced() From fa2e63f74baf625b5547d5362a5237b279a643c7 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 28 Sep 2023 18:28:46 +0200 Subject: [PATCH 225/233] enc28j60: return packet length from receive() instead of mut slice --- embassy-net-enc28j60/src/lib.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/embassy-net-enc28j60/src/lib.rs b/embassy-net-enc28j60/src/lib.rs index b44cefaf..72229dc0 100644 --- a/embassy-net-enc28j60/src/lib.rs +++ b/embassy-net-enc28j60/src/lib.rs @@ -197,7 +197,7 @@ where /// Flushes the transmit buffer, ensuring all pending transmissions have completed /// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always /// return `None` on subsequent invocations - pub fn receive<'a>(&mut self, buf: &'a mut [u8]) -> Option<&'a mut [u8]> { + pub fn receive(&mut self, buf: &mut [u8]) -> Option { if self.pending_packets() == 0 { // Errata #6: we can't rely on PKTIF so we check PKTCNT return None; @@ -241,7 +241,7 @@ where self.next_packet = next_packet; - Some(&mut buf[..len as usize]) + Some(len as usize) } fn wait_tx_ready(&mut self) { @@ -642,9 +642,8 @@ where fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { let rx_buf = unsafe { &mut RX_BUF }; let tx_buf = unsafe { &mut TX_BUF }; - if let Some(pkt) = self.receive(rx_buf) { - let n = pkt.len(); - Some((RxToken { buf: &mut pkt[..n] }, TxToken { buf: tx_buf, eth: self })) + if let Some(n) = self.receive(rx_buf) { + Some((RxToken { buf: &mut rx_buf[..n] }, TxToken { buf: tx_buf, eth: self })) } else { cx.waker().wake_by_ref(); None From e8a462768e42871eb721274c3b950f51c6f65b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 28 Sep 2023 18:56:16 +0200 Subject: [PATCH 226/233] Add more tick rates --- embassy-time/CHANGELOG.md | 2 +- embassy-time/Cargo.toml | 61 +++++++++++++ embassy-time/gen_tick.py | 5 +- embassy-time/src/tick.rs | 183 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 249 insertions(+), 2 deletions(-) diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index 4389e6ce..e3b38455 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.1.4 - ??? -- Added `tick-hz-80_000_000` +- Added more tick rates ## 0.1.3 - 2023-08-28 diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index a290509d..8f034a9d 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -145,7 +145,68 @@ tick-hz-384_000_000 = [] tick-hz-512_000_000 = [] tick-hz-576_000_000 = [] tick-hz-768_000_000 = [] +tick-hz-20_000_000 = [] +tick-hz-30_000_000 = [] +tick-hz-40_000_000 = [] +tick-hz-50_000_000 = [] +tick-hz-60_000_000 = [] +tick-hz-70_000_000 = [] tick-hz-80_000_000 = [] +tick-hz-90_000_000 = [] +tick-hz-110_000_000 = [] +tick-hz-120_000_000 = [] +tick-hz-130_000_000 = [] +tick-hz-140_000_000 = [] +tick-hz-150_000_000 = [] +tick-hz-160_000_000 = [] +tick-hz-170_000_000 = [] +tick-hz-180_000_000 = [] +tick-hz-190_000_000 = [] +tick-hz-200_000_000 = [] +tick-hz-210_000_000 = [] +tick-hz-220_000_000 = [] +tick-hz-230_000_000 = [] +tick-hz-240_000_000 = [] +tick-hz-250_000_000 = [] +tick-hz-260_000_000 = [] +tick-hz-270_000_000 = [] +tick-hz-280_000_000 = [] +tick-hz-290_000_000 = [] +tick-hz-300_000_000 = [] +tick-hz-320_000_000 = [] +tick-hz-340_000_000 = [] +tick-hz-360_000_000 = [] +tick-hz-380_000_000 = [] +tick-hz-400_000_000 = [] +tick-hz-420_000_000 = [] +tick-hz-440_000_000 = [] +tick-hz-460_000_000 = [] +tick-hz-480_000_000 = [] +tick-hz-500_000_000 = [] +tick-hz-520_000_000 = [] +tick-hz-540_000_000 = [] +tick-hz-560_000_000 = [] +tick-hz-580_000_000 = [] +tick-hz-600_000_000 = [] +tick-hz-620_000_000 = [] +tick-hz-640_000_000 = [] +tick-hz-660_000_000 = [] +tick-hz-680_000_000 = [] +tick-hz-700_000_000 = [] +tick-hz-720_000_000 = [] +tick-hz-740_000_000 = [] +tick-hz-760_000_000 = [] +tick-hz-780_000_000 = [] +tick-hz-800_000_000 = [] +tick-hz-820_000_000 = [] +tick-hz-840_000_000 = [] +tick-hz-860_000_000 = [] +tick-hz-880_000_000 = [] +tick-hz-900_000_000 = [] +tick-hz-920_000_000 = [] +tick-hz-940_000_000 = [] +tick-hz-960_000_000 = [] +tick-hz-980_000_000 = [] # END TICKS [dependencies] diff --git a/embassy-time/gen_tick.py b/embassy-time/gen_tick.py index 804b6bb4..67a4c79c 100644 --- a/embassy-time/gen_tick.py +++ b/embassy-time/gen_tick.py @@ -17,7 +17,10 @@ for i in range(1, 10): ticks.append(2**i * 1000000) ticks.append(2**i * 9 // 8 * 1000000) ticks.append(2**i * 3 // 2 * 1000000) -ticks.append(80_000_000) +for i in range(1, 30): + ticks.append(10 * i * 1_000_000) +for i in range(15, 50): + ticks.append(20 * i * 1_000_000) seen = set() ticks = [x for x in ticks if not (x in seen or seen.add(x))] diff --git a/embassy-time/src/tick.rs b/embassy-time/src/tick.rs index 0a4a0276..be544181 100644 --- a/embassy-time/src/tick.rs +++ b/embassy-time/src/tick.rs @@ -156,8 +156,130 @@ pub const TICK_HZ: u64 = 512_000_000; pub const TICK_HZ: u64 = 576_000_000; #[cfg(feature = "tick-hz-768_000_000")] pub const TICK_HZ: u64 = 768_000_000; +#[cfg(feature = "tick-hz-20_000_000")] +pub const TICK_HZ: u64 = 20_000_000; +#[cfg(feature = "tick-hz-30_000_000")] +pub const TICK_HZ: u64 = 30_000_000; +#[cfg(feature = "tick-hz-40_000_000")] +pub const TICK_HZ: u64 = 40_000_000; +#[cfg(feature = "tick-hz-50_000_000")] +pub const TICK_HZ: u64 = 50_000_000; +#[cfg(feature = "tick-hz-60_000_000")] +pub const TICK_HZ: u64 = 60_000_000; +#[cfg(feature = "tick-hz-70_000_000")] +pub const TICK_HZ: u64 = 70_000_000; #[cfg(feature = "tick-hz-80_000_000")] pub const TICK_HZ: u64 = 80_000_000; +#[cfg(feature = "tick-hz-90_000_000")] +pub const TICK_HZ: u64 = 90_000_000; +#[cfg(feature = "tick-hz-110_000_000")] +pub const TICK_HZ: u64 = 110_000_000; +#[cfg(feature = "tick-hz-120_000_000")] +pub const TICK_HZ: u64 = 120_000_000; +#[cfg(feature = "tick-hz-130_000_000")] +pub const TICK_HZ: u64 = 130_000_000; +#[cfg(feature = "tick-hz-140_000_000")] +pub const TICK_HZ: u64 = 140_000_000; +#[cfg(feature = "tick-hz-150_000_000")] +pub const TICK_HZ: u64 = 150_000_000; +#[cfg(feature = "tick-hz-160_000_000")] +pub const TICK_HZ: u64 = 160_000_000; +#[cfg(feature = "tick-hz-170_000_000")] +pub const TICK_HZ: u64 = 170_000_000; +#[cfg(feature = "tick-hz-180_000_000")] +pub const TICK_HZ: u64 = 180_000_000; +#[cfg(feature = "tick-hz-190_000_000")] +pub const TICK_HZ: u64 = 190_000_000; +#[cfg(feature = "tick-hz-200_000_000")] +pub const TICK_HZ: u64 = 200_000_000; +#[cfg(feature = "tick-hz-210_000_000")] +pub const TICK_HZ: u64 = 210_000_000; +#[cfg(feature = "tick-hz-220_000_000")] +pub const TICK_HZ: u64 = 220_000_000; +#[cfg(feature = "tick-hz-230_000_000")] +pub const TICK_HZ: u64 = 230_000_000; +#[cfg(feature = "tick-hz-240_000_000")] +pub const TICK_HZ: u64 = 240_000_000; +#[cfg(feature = "tick-hz-250_000_000")] +pub const TICK_HZ: u64 = 250_000_000; +#[cfg(feature = "tick-hz-260_000_000")] +pub const TICK_HZ: u64 = 260_000_000; +#[cfg(feature = "tick-hz-270_000_000")] +pub const TICK_HZ: u64 = 270_000_000; +#[cfg(feature = "tick-hz-280_000_000")] +pub const TICK_HZ: u64 = 280_000_000; +#[cfg(feature = "tick-hz-290_000_000")] +pub const TICK_HZ: u64 = 290_000_000; +#[cfg(feature = "tick-hz-300_000_000")] +pub const TICK_HZ: u64 = 300_000_000; +#[cfg(feature = "tick-hz-320_000_000")] +pub const TICK_HZ: u64 = 320_000_000; +#[cfg(feature = "tick-hz-340_000_000")] +pub const TICK_HZ: u64 = 340_000_000; +#[cfg(feature = "tick-hz-360_000_000")] +pub const TICK_HZ: u64 = 360_000_000; +#[cfg(feature = "tick-hz-380_000_000")] +pub const TICK_HZ: u64 = 380_000_000; +#[cfg(feature = "tick-hz-400_000_000")] +pub const TICK_HZ: u64 = 400_000_000; +#[cfg(feature = "tick-hz-420_000_000")] +pub const TICK_HZ: u64 = 420_000_000; +#[cfg(feature = "tick-hz-440_000_000")] +pub const TICK_HZ: u64 = 440_000_000; +#[cfg(feature = "tick-hz-460_000_000")] +pub const TICK_HZ: u64 = 460_000_000; +#[cfg(feature = "tick-hz-480_000_000")] +pub const TICK_HZ: u64 = 480_000_000; +#[cfg(feature = "tick-hz-500_000_000")] +pub const TICK_HZ: u64 = 500_000_000; +#[cfg(feature = "tick-hz-520_000_000")] +pub const TICK_HZ: u64 = 520_000_000; +#[cfg(feature = "tick-hz-540_000_000")] +pub const TICK_HZ: u64 = 540_000_000; +#[cfg(feature = "tick-hz-560_000_000")] +pub const TICK_HZ: u64 = 560_000_000; +#[cfg(feature = "tick-hz-580_000_000")] +pub const TICK_HZ: u64 = 580_000_000; +#[cfg(feature = "tick-hz-600_000_000")] +pub const TICK_HZ: u64 = 600_000_000; +#[cfg(feature = "tick-hz-620_000_000")] +pub const TICK_HZ: u64 = 620_000_000; +#[cfg(feature = "tick-hz-640_000_000")] +pub const TICK_HZ: u64 = 640_000_000; +#[cfg(feature = "tick-hz-660_000_000")] +pub const TICK_HZ: u64 = 660_000_000; +#[cfg(feature = "tick-hz-680_000_000")] +pub const TICK_HZ: u64 = 680_000_000; +#[cfg(feature = "tick-hz-700_000_000")] +pub const TICK_HZ: u64 = 700_000_000; +#[cfg(feature = "tick-hz-720_000_000")] +pub const TICK_HZ: u64 = 720_000_000; +#[cfg(feature = "tick-hz-740_000_000")] +pub const TICK_HZ: u64 = 740_000_000; +#[cfg(feature = "tick-hz-760_000_000")] +pub const TICK_HZ: u64 = 760_000_000; +#[cfg(feature = "tick-hz-780_000_000")] +pub const TICK_HZ: u64 = 780_000_000; +#[cfg(feature = "tick-hz-800_000_000")] +pub const TICK_HZ: u64 = 800_000_000; +#[cfg(feature = "tick-hz-820_000_000")] +pub const TICK_HZ: u64 = 820_000_000; +#[cfg(feature = "tick-hz-840_000_000")] +pub const TICK_HZ: u64 = 840_000_000; +#[cfg(feature = "tick-hz-860_000_000")] +pub const TICK_HZ: u64 = 860_000_000; +#[cfg(feature = "tick-hz-880_000_000")] +pub const TICK_HZ: u64 = 880_000_000; +#[cfg(feature = "tick-hz-900_000_000")] +pub const TICK_HZ: u64 = 900_000_000; +#[cfg(feature = "tick-hz-920_000_000")] +pub const TICK_HZ: u64 = 920_000_000; +#[cfg(feature = "tick-hz-940_000_000")] +pub const TICK_HZ: u64 = 940_000_000; +#[cfg(feature = "tick-hz-960_000_000")] +pub const TICK_HZ: u64 = 960_000_000; +#[cfg(feature = "tick-hz-980_000_000")] +pub const TICK_HZ: u64 = 980_000_000; #[cfg(not(any( feature = "tick-hz-1", feature = "tick-hz-10", @@ -237,6 +359,67 @@ pub const TICK_HZ: u64 = 80_000_000; feature = "tick-hz-512_000_000", feature = "tick-hz-576_000_000", feature = "tick-hz-768_000_000", + feature = "tick-hz-20_000_000", + feature = "tick-hz-30_000_000", + feature = "tick-hz-40_000_000", + feature = "tick-hz-50_000_000", + feature = "tick-hz-60_000_000", + feature = "tick-hz-70_000_000", feature = "tick-hz-80_000_000", + feature = "tick-hz-90_000_000", + feature = "tick-hz-110_000_000", + feature = "tick-hz-120_000_000", + feature = "tick-hz-130_000_000", + feature = "tick-hz-140_000_000", + feature = "tick-hz-150_000_000", + feature = "tick-hz-160_000_000", + feature = "tick-hz-170_000_000", + feature = "tick-hz-180_000_000", + feature = "tick-hz-190_000_000", + feature = "tick-hz-200_000_000", + feature = "tick-hz-210_000_000", + feature = "tick-hz-220_000_000", + feature = "tick-hz-230_000_000", + feature = "tick-hz-240_000_000", + feature = "tick-hz-250_000_000", + feature = "tick-hz-260_000_000", + feature = "tick-hz-270_000_000", + feature = "tick-hz-280_000_000", + feature = "tick-hz-290_000_000", + feature = "tick-hz-300_000_000", + feature = "tick-hz-320_000_000", + feature = "tick-hz-340_000_000", + feature = "tick-hz-360_000_000", + feature = "tick-hz-380_000_000", + feature = "tick-hz-400_000_000", + feature = "tick-hz-420_000_000", + feature = "tick-hz-440_000_000", + feature = "tick-hz-460_000_000", + feature = "tick-hz-480_000_000", + feature = "tick-hz-500_000_000", + feature = "tick-hz-520_000_000", + feature = "tick-hz-540_000_000", + feature = "tick-hz-560_000_000", + feature = "tick-hz-580_000_000", + feature = "tick-hz-600_000_000", + feature = "tick-hz-620_000_000", + feature = "tick-hz-640_000_000", + feature = "tick-hz-660_000_000", + feature = "tick-hz-680_000_000", + feature = "tick-hz-700_000_000", + feature = "tick-hz-720_000_000", + feature = "tick-hz-740_000_000", + feature = "tick-hz-760_000_000", + feature = "tick-hz-780_000_000", + feature = "tick-hz-800_000_000", + feature = "tick-hz-820_000_000", + feature = "tick-hz-840_000_000", + feature = "tick-hz-860_000_000", + feature = "tick-hz-880_000_000", + feature = "tick-hz-900_000_000", + feature = "tick-hz-920_000_000", + feature = "tick-hz-940_000_000", + feature = "tick-hz-960_000_000", + feature = "tick-hz-980_000_000", )))] pub const TICK_HZ: u64 = 1_000_000; From 322a4a8401480de8d51fa85ac6cedfabd033c743 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 28 Sep 2023 15:48:46 -0500 Subject: [PATCH 227/233] stm32/hrtim: move traits out of macro def'n --- embassy-stm32/src/hrtim/traits.rs | 148 ++++++++++++++---------------- 1 file changed, 67 insertions(+), 81 deletions(-) diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 37cfb9b9..34a363a1 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -78,12 +78,76 @@ pub(crate) mod sealed { pub trait Instance: RccPeripheral { fn regs() -> crate::pac::hrtim::Hrtim; - fn set_master_frequency(frequency: Hertz); + fn set_master_frequency(frequency: Hertz) { + let f = frequency.0; + #[cfg(not(stm32f334))] + let timer_f = Self::frequency().0; + #[cfg(stm32f334)] + let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; - fn set_channel_frequency(channnel: usize, frequency: Hertz); + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); + let psc = if Self::regs().isr().read().dllrdy() { + Prescaler::compute_min_high_res(psc_min) + } else { + Prescaler::compute_min_low_res(psc_min) + }; + + let timer_f = 32 * (timer_f / psc as u32); + let per: u16 = (timer_f / f) as u16; + + let regs = Self::regs(); + + regs.mcr().modify(|w| w.set_ckpsc(psc.into())); + regs.mper().modify(|w| w.set_mper(per)); + } + + fn set_channel_frequency(channel: usize, frequency: Hertz) { + let f = frequency.0; + #[cfg(not(stm32f334))] + let timer_f = Self::frequency().0; + #[cfg(stm32f334)] + let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0; + + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); + let psc = if Self::regs().isr().read().dllrdy() { + Prescaler::compute_min_high_res(psc_min) + } else { + Prescaler::compute_min_low_res(psc_min) + }; + + let timer_f = 32 * (timer_f / psc as u32); + let per: u16 = (timer_f / f) as u16; + + let regs = Self::regs(); + + regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); + regs.tim(channel).per().modify(|w| w.set_per(per)); + } /// Set the dead time as a proportion of max_duty - fn set_channel_dead_time(channnel: usize, dead_time: u16); + + fn set_channel_dead_time(channel: usize, dead_time: u16) { + let regs = Self::regs(); + + let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); + + // The dead-time base clock runs 4 times slower than the hrtim base clock + // u9::MAX = 511 + let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); + let psc = if Self::regs().isr().read().dllrdy() { + Prescaler::compute_min_high_res(psc_min) + } else { + Prescaler::compute_min_low_res(psc_min) + }; + + let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); + + regs.tim(channel).dt().modify(|w| { + w.set_dtprsc(psc.into()); + w.set_dtf(dt_val as u16); + w.set_dtr(dt_val as u16); + }); + } // fn enable_outputs(enable: bool); // @@ -99,84 +163,6 @@ foreach_interrupt! { fn regs() -> crate::pac::hrtim::Hrtim { crate::pac::$inst } - - fn set_master_frequency(frequency: Hertz) { - use crate::rcc::sealed::RccPeripheral; - - let f = frequency.0; - #[cfg(not(stm32f334))] - let timer_f = Self::frequency().0; - #[cfg(stm32f334)] - let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or( - Self::frequency() - ).0; - - let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); - let psc = if Self::regs().isr().read().dllrdy() { - Prescaler::compute_min_high_res(psc_min) - } else { - Prescaler::compute_min_low_res(psc_min) - }; - - let timer_f = 32 * (timer_f / psc as u32); - let per: u16 = (timer_f / f) as u16; - - let regs = Self::regs(); - - regs.mcr().modify(|w| w.set_ckpsc(psc.into())); - regs.mper().modify(|w| w.set_mper(per)); - } - - fn set_channel_frequency(channel: usize, frequency: Hertz) { - use crate::rcc::sealed::RccPeripheral; - - let f = frequency.0; - #[cfg(not(stm32f334))] - let timer_f = Self::frequency().0; - #[cfg(stm32f334)] - let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or( - Self::frequency() - ).0; - - let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); - let psc = if Self::regs().isr().read().dllrdy() { - Prescaler::compute_min_high_res(psc_min) - } else { - Prescaler::compute_min_low_res(psc_min) - }; - - let timer_f = 32 * (timer_f / psc as u32); - let per: u16 = (timer_f / f) as u16; - - let regs = Self::regs(); - - regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); - regs.tim(channel).per().modify(|w| w.set_per(per)); - } - - fn set_channel_dead_time(channel: usize, dead_time: u16) { - - let regs = Self::regs(); - - let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); - - // The dead-time base clock runs 4 times slower than the hrtim base clock - // u9::MAX = 511 - let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); - let psc = if Self::regs().isr().read().dllrdy() { - Prescaler::compute_min_high_res(psc_min) - } else { - Prescaler::compute_min_low_res(psc_min) - }; - - let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); - - regs.tim(channel).dt().modify(|w| { - w.set_dtprsc(psc.into()); - w.set_dtf(dt_val as u16); - w.set_dtr(dt_val as u16); - }); - } } impl Instance for crate::peripherals::$inst { From e70143ef8f5303b5916a160f9d43d04d7ab55cd7 Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Thu, 28 Sep 2023 17:04:19 -0400 Subject: [PATCH 228/233] Forgot set_count_direction and set_clock_division in 32 bit instance --- embassy-stm32/src/timer/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 1d642ed3..9b79f9b4 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -49,6 +49,10 @@ pub(crate) mod sealed { fn regs_gp32() -> crate::pac::timer::TimGp32; fn set_frequency(&mut self, frequency: Hertz); + + fn set_count_direction(&mut self, direction: vals::Dir); + + fn set_clock_division(&mut self, ckd: vals::Ckd); } pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { @@ -317,6 +321,14 @@ macro_rules! impl_32bit_timer { crate::pac::$inst } + fn set_count_direction(&mut self, direction: vals::Dir) { + Self::regs_gp32().cr1().modify(|r| r.set_dir(direction)); + } + + fn set_clock_division(&mut self, ckd: vals::Ckd) { + Self::regs_gp32().cr1().modify(|r| r.set_ckd(ckd)); + } + fn set_frequency(&mut self, frequency: Hertz) { use core::convert::TryInto; let f = frequency.0; From 39f1b26a3954a3ffbc2a0960a8c7fd952f928648 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 28 Sep 2023 19:21:02 -0500 Subject: [PATCH 229/233] stm32: update metapac and remove sbs --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/eth/v2/mod.rs | 4 ++-- embassy-stm32/src/lib.rs | 4 +--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 08b9b3a3..1ef92430 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -59,7 +59,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-bdbf126746919e1c07730d80f9345b1a494c72a6" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-735cab337aad6161f3d6bcf3e49cd1f034bc3130" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-bdbf126746919e1c07730d80f9345b1a494c72a6", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-735cab337aad6161f3d6bcf3e49cd1f034bc3130", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index b7fe4766..6efd40e3 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -99,9 +99,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { }); // RMII - crate::pac::SBS + crate::pac::SYSCFG .pmcr() - .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4)); + .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); }); config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index db79546b..1e184f9d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -181,10 +181,8 @@ pub fn init(config: Config) -> Peripherals { }); } - #[cfg(not(any(stm32f1, stm32h5, stm32wb, stm32wl)))] + #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] peripherals::SYSCFG::enable(); - #[cfg(sbs)] - peripherals::SBS::enable(); #[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))] peripherals::PWR::enable(); #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] From dffdb9268bfb32580efe32067bab50fe62900c5f Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Thu, 28 Sep 2023 21:56:18 -0400 Subject: [PATCH 230/233] Revert "Forgot set_count_direction and set_clock_division in 32 bit instance" --- embassy-stm32/src/timer/mod.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 9b79f9b4..1d642ed3 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -49,10 +49,6 @@ pub(crate) mod sealed { fn regs_gp32() -> crate::pac::timer::TimGp32; fn set_frequency(&mut self, frequency: Hertz); - - fn set_count_direction(&mut self, direction: vals::Dir); - - fn set_clock_division(&mut self, ckd: vals::Ckd); } pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { @@ -321,14 +317,6 @@ macro_rules! impl_32bit_timer { crate::pac::$inst } - fn set_count_direction(&mut self, direction: vals::Dir) { - Self::regs_gp32().cr1().modify(|r| r.set_dir(direction)); - } - - fn set_clock_division(&mut self, ckd: vals::Ckd) { - Self::regs_gp32().cr1().modify(|r| r.set_ckd(ckd)); - } - fn set_frequency(&mut self, frequency: Hertz) { use core::convert::TryInto; let f = frequency.0; From e1a8caffa441644089e8f904acb460e79cb44e99 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Fri, 29 Sep 2023 17:23:39 +0200 Subject: [PATCH 231/233] enc28j60: expose a the MAC address via `address()` getter --- embassy-net-enc28j60/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-net-enc28j60/src/lib.rs b/embassy-net-enc28j60/src/lib.rs index 72229dc0..f96a6ff1 100644 --- a/embassy-net-enc28j60/src/lib.rs +++ b/embassy-net-enc28j60/src/lib.rs @@ -194,6 +194,11 @@ where self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen()); } + /// Returns the device's MAC address + pub fn address(&self) -> [u8; 6] { + self.mac_addr + } + /// Flushes the transmit buffer, ensuring all pending transmissions have completed /// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always /// return `None` on subsequent invocations From f1e7205055499651f51f6f7af86e407201dc1b1c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 30 Sep 2023 00:12:19 +0200 Subject: [PATCH 232/233] stm32/rtc: enable lse in examples. --- examples/stm32l4/src/bin/rtc.rs | 1 + examples/stm32wl/src/bin/rtc.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index f3f8aa46..eb1eed01 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs @@ -23,6 +23,7 @@ async fn main(_spawner: Spawner) { PLLMul::Mul20, None, ); + config.rcc.lse = Some(Hertz(32_768)); config.rcc.rtc_mux = rcc::RtcClockSource::LSE; embassy_stm32::init(config) }; diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index e123425a..11734e4b 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs @@ -7,6 +7,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rcc::ClockSrc; use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; +use embassy_stm32::time::Hertz; use embassy_stm32::Config; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -16,6 +17,7 @@ async fn main(_spawner: Spawner) { let p = { let mut config = Config::default(); config.rcc.mux = ClockSrc::HSE32; + config.rcc.lse = Some(Hertz(32_768)); config.rcc.rtc_mux = RtcClockSource::LSE; embassy_stm32::init(config) }; From a35d149cb151d53fd95b5073cef927116b34fe0d Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 29 Sep 2023 21:07:09 -0500 Subject: [PATCH 233/233] Revert metapac change in Cargo.toml --- embassy-stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index b3b3cd81..1ef92430 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -59,7 +59,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = "12" +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-735cab337aad6161f3d6bcf3e49cd1f034bc3130" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0"