From dd5bdec36faf9fe2f49c7bd48efa92c934204c1e Mon Sep 17 00:00:00 2001 From: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed, 14 Dec 2022 04:24:49 -0500 Subject: [PATCH] Update mod.rs remove const def of base registers fix to hard code Can clock source to OSC see: https://github.com/imxrt-rs/imxrt-hal/pull/122#discussion_r1046330159 Squashed commit of the following: commit 68677eb9ed5bb7da677ef4cf8a05a3f18ce706e2 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Dec 12 16:21:30 2022 -0500 resolve PR Issues artifacts of non-existent feature: https://github.com/imxrt-rs/imxrt-hal/pull/122#discussion_r1046263777 remove constrain function and use core::cmp::Ordering::clamp trait: https://github.com/imxrt-rs/imxrt-hal/pull/122#discussion_r1046269628 commit 081d027ad2edd5a757d71fa59df96522cb85b428 Merge: 2ab80a7 6da6c97 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Dec 12 16:00:55 2022 -0500 Merge branch 'dev/can' into maint-v0.4 commit 6da6c9743fb6bbb05120ee46389098d2d4d6ef3f Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Dec 12 10:03:39 2022 -0500 package update commit 111f429d72cfe3594e3d2889f6282c8fd3d761d7 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Dec 12 09:59:11 2022 -0500 rename package commit e071a4dfe2249e9cf8c8a8741aa39ab5c53f9fab Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Dec 12 07:28:15 2022 -0500 update commit 13b396c1a1c8f2f2072f302578f35cb8b085da25 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Sat Dec 10 13:12:28 2022 -0500 Update frame.rs commit 118d51efb2292e77068f664e6ce74c78dd64f0dd Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Sat Dec 10 11:53:47 2022 -0500 update commit e51d7dc534cb2b1363a73d90fea87f85a0f5cafc Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Fri Dec 9 13:24:22 2022 -0500 updates commit e9d8df8eabd16fed81cc0a59e2041ce695575621 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Thu Dec 8 07:34:16 2022 -0500 init refactor commit 8831af2e168cb61d55ff853e64d7d2fffaa91018 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed Dec 7 14:40:45 2022 -0500 update commit b4b52d1228acce8dab51815367533677cb9123a8 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed Dec 7 07:03:21 2022 -0500 mask update commit fef52231a0cf7f6f6633e78c8fc76693a57ee090 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Tue Dec 6 20:04:47 2022 -0500 update commit bc428c06262ed1e61804670b582f1d29f8dfa9da Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Tue Dec 6 05:39:18 2022 -0500 Update mod.rs commit adbd1bdd9421db85db54088a0765b07c78c64c50 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Fri Dec 2 07:48:31 2022 -0500 update commit 4ab5ee04308c908892182e6937612b7af5b0fdcf Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Thu Dec 1 16:07:04 2022 -0500 Update mod.rs commit 8026f2ab49159bf6a7a2002ec8fc3cb90ce2a5a3 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Thu Dec 1 12:14:10 2022 -0500 update commit 588ac9b6acaca685ab7ada800c35e43502edd7c8 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Thu Dec 1 08:35:08 2022 -0500 update commit 486a7c44357de0a761e299d88e92764dc21e9719 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed Nov 30 13:22:08 2022 -0500 Update id.rs commit b0e15d78d7940c321118c9e941f9b9534a35f9b7 Merge: 687af5b 0ec2e73 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed Nov 30 06:43:22 2022 -0500 Merge branch 'dev/can' of https://github.com/dstric-aqueduct/imxrt-hal into dev/can commit 687af5bb7a94a0f1a5d50e41c9f285845cbb2c2c Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed Nov 30 06:43:20 2022 -0500 update commit 0ec2e738471fdb796035e4a28cf9c274a56c800b Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed Nov 30 06:41:53 2022 -0500 update commit a12871c2524da8d88de9c0a153bb708d2d2336fd Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Nov 28 10:21:22 2022 -0500 Update isotp.rs commit 52934a6dfc728c95bb776b25f2dca19dfdb3445c Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Sun Nov 27 08:02:55 2022 -0500 update commit 78183fc2fd114657fe36e048d26ae0c9e3774e40 Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Sun Nov 27 07:09:41 2022 -0500 Update mod.rs commit c367a4e8266e4b02296e8cc4c91bda50202f5b4f Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Sun Nov 27 06:53:55 2022 -0500 Update mod.rs commit ff2294381292a725cbaf6e2b5f6ab559b7869824 Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Sat Nov 26 18:41:20 2022 -0500 update commit 037b404b237034b07323ee03e59900e91ab5a086 Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Sat Nov 26 07:11:48 2022 -0500 update commit ae00b212ae2c5fdea21aa8a2f316fa2c6b77d1a8 Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Sat Nov 26 06:08:08 2022 -0500 Update mod.rs commit a9e80e8b2ba65d5cc50dedb059d401695af50ac7 Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Fri Nov 25 06:03:13 2022 -0500 Update mod.rs commit 284997fddf73cfe5115e07629309c11702013e3e Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Thu Nov 24 10:51:20 2022 -0500 Update mod.rs commit ecca971806de8721e34ea3db45e638af46ac07e1 Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed Nov 23 18:25:35 2022 -0500 Update mod.rs commit 1de0d0ce5bdec11e3e8ef5174c3ef3a10506f51f Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed Nov 23 18:23:39 2022 -0500 Update mod.rs commit 5bf1d987cc16d080e2b3b8236e9aaae9d084e641 Merge: 1ebb9e6 0ef6987 Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed Nov 23 05:51:14 2022 -0500 Merge branch 'dev/can' of https://github.com/dstric-aqueduct/imxrt-hal into dev/can commit 1ebb9e666aa05c356ced016589838af2665bab82 Author: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Wed Nov 23 05:48:57 2022 -0500 Update mod.rs commit 0ef6987c38c50561123c2180de7768687a892eff Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Nov 21 19:22:07 2022 -0500 Update mod.rs commit 83c0c2afcb59d08255c8cf7c000ed5c15fc7f283 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Nov 21 15:43:32 2022 -0500 Update mod.rs commit 6e16125122f735347dcce35a04108b559478cabc Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Nov 21 14:24:56 2022 -0500 Update mod.rs commit e27f4d548f9540a3b2dbe24f09532423e6356067 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Nov 21 10:04:34 2022 -0500 Update mod.rs commit 10a66d2eb33d2c06bd9660e7fb2532d56f9f48e0 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Mon Nov 21 07:23:49 2022 -0500 updates commit 6362ad6d1a708f319200c3dcc1646ff45724e184 Author: djstrickland <96876452+dstric-aqueduct@users.noreply.github.com> Date: Thu Nov 17 13:52:52 2022 -0500 init commit 2ab80a74462ead8c0e6deaa6574a4598f865fd77 Author: Alex Halemba Date: Sun Jan 9 23:21:22 2022 +0100 impr. docs commit 90f36efb8fa63f1f02d1462f16b9ee25adf2448c Author: Alex Halemba Date: Sat Jan 8 23:03:38 2022 +0100 review commit 1322f918175278cc87b24bd8d1206e1e24c676b8 Author: Alex Halemba Date: Thu Jan 6 20:02:23 2022 +0100 use modify_reg commit 386b6805458bb455e76db23a542e0714cc9dc780 Author: Alex Halemba Date: Thu Jan 6 18:07:02 2022 +0100 review fixes commit 229d3aee240db34df601fbfc45b5f329df50ae38 Author: Alex Halemba Date: Wed Jan 5 21:27:43 2022 +0100 figuring out that ```ignore fixed the pipeline commit be68c9c9c0a715eaf00d7e6ba6656ca93c45ad5a Author: Alex Halemba Date: Wed Jan 5 11:16:16 2022 +0100 fixing documentation commit 173b525ad6e889b43350317e3186a6155a4e4636 Author: Alex Halemba Date: Wed Jan 5 11:08:00 2022 +0100 changing to mC to avoid f32 commit 5daf3ccb750c991d53f190ccaa240b577178cb6f Author: Alex Halemba Date: Tue Jan 4 19:52:55 2022 +0100 add tempmon support commit 9b8561484933bb93af50f808e0ec23eeeaec6ff4 Author: Alex Halemba Date: Tue Jan 4 19:00:32 2022 +0100 add tempmon commit 08aa861d84b3ddd14f888c0e6d8bdb833bbf6723 Author: Ian McIntyre Date: Thu Dec 2 19:15:32 2021 -0500 Bump HAL version to 0.4.5 commit 74374824fc752f3f7baef6cadba250caa12e3eb7 Author: Ian McIntyre Date: Thu Dec 2 19:11:59 2021 -0500 Document 0.4.5 release in CHANGELOG commit 50d3677a714fbdacdf69dab29e2cc606534b3c4e Author: Ian McIntyre Date: Thu Dec 2 19:04:01 2021 -0500 Update CHANGELOG with TRNG error code fix commit 18fabf32bb1381bc5f10596d33e7763515381403 Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Thu Dec 2 00:08:59 2021 -0800 Follow rand_core API commit 9a3727f73fe1902b265091b55327f5fd3f0c4aad Author: Ian McIntyre Date: Sat Sep 18 13:24:38 2021 -0400 Add GPIO interrupt documentation, code snippet Documentation and examples came from development discussions. See discussions on #109 for details. commit 71217356a4187d1911434a41215d5bab4ee3e908 Author: Ian McIntyre Date: Sat Sep 18 12:40:25 2021 -0400 Update CHANGELOG commit 44c76a726854c0c23989d3bf973878525b73fd1c Author: Ian McIntyre Date: Sat Sep 18 11:10:37 2021 -0400 Implement icr_mask for GPIO inputs commit f69bd80bf215f405d5578a30b8f56210e09fb020 Author: Martin Algesten Date: Mon Jul 12 22:51:50 2021 +0200 Update imxrt1060-hal/src/gpio.rs Co-authored-by: Ian McIntyre commit 7218aa2ed6956120d69e96d7f83a19be73af30f9 Author: Martin Algesten Date: Mon Jul 5 22:37:45 2021 +0200 Fix error 032 vs 0u32 commit 87bc829a48f1724d2fae1a0318c30f6432fce73e Author: Martin Algesten Date: Sun Jul 4 11:13:08 2021 +0200 Clear out interrupt config when transitioning to output commit 7259132dfce90b43f8caf91c8bce13ce0a2293a3 Author: Martin Algesten Date: Sun Jul 4 11:12:45 2021 +0200 Preserve interrupt config on set_fast() commit 5a158ffb8b199b144b5534cb02f423b04f1394cd Author: Martin Algesten Date: Sun Jul 4 10:50:35 2021 +0200 Amends after PR feedback commit 1703b8172153cb4759c1f32dcadcb87ee7800d39 Author: Martin Algesten Date: Sun Jul 4 10:43:24 2021 +0200 Update imxrt1060-hal/src/gpio.rs Co-authored-by: Ian McIntyre commit 9bab8d3a7b7b829137b0debb8f49c74a26011fea Author: Martin Algesten Date: Wed Jun 30 17:22:02 2021 +0200 GPIO functions to enable / configure interrupts cortex_m_rt provides the hook for the ISR and the `NVIC::unmask`, however to configure a GPIO interrupt there are some additional steps needed. This commit provides set_interrupt_enable, set_interrupt_configuration and clear_interrupt_status (and some additional query functions). commit e6e9e47fcb10de9dafd0c11dea08da3fbd0bb8ed Author: Ian McIntyre Date: Mon Jun 28 22:11:08 2021 -0400 Isolate fast / normal GPIO configuration copy The new implementation is consistent with the previous behavior. We're setting the stage for copying over interrupt settings. commit b79b4de229f876d9cdbf8b40f85def5e80b1c48c Author: Ian McIntyre Date: Mon Jun 28 21:57:31 2021 -0400 Rename GPIO "offset" to "mask" The usage resembles a bitmask with a single set bit. The name is easier to reason about. commit cd6e3f50c4f6d513047cec149007b4eac4f1f9a3 Author: Ian McIntyre Date: Fri Apr 23 18:42:43 2021 -0400 Bump imxrt-ral to 0.4.4 commit f9c58fec2d960e9642a867ab379835f9d40a43a7 Author: Ian McIntyre Date: Fri Apr 23 18:41:09 2021 -0400 Document 0.4.4 release date in CHANGELOG Fix 0.4.3 release date (wrong year). commit 418e97cfe3516c9f556b75f33076581314064294 Author: Ian McIntyre Date: Thu Apr 22 20:33:53 2021 -0400 Update CHANGELOG with PWM fix commit 29cc21a10c62df3960cf763a87e6c3d990298137 Author: Ian McIntyre Date: Thu Apr 22 20:25:23 2021 -0400 Prepare PWM pins when constructing outputs In the 0.3 HAL, we relied on the user to set the pin alternate settings. But after introducing the IOMUXC crate in 0.4, we made pin muxing part of the driver's responsibility, and added calls to prepare pins. We missed the requirement in the PWM driver. This commit corrects the PWM driver, which has been broken since the 0.4 release. Tested in the teensy4-rs repo. Users who are not able to adopt the next patch release could add equivalent iomuxc calls before constructing their PWM driver. commit 124a811023a86db480db56c1a2af4901c8706b24 Author: Ian McIntyre Date: Mon Apr 5 20:20:00 2021 -0400 Bump imxrt-hal to 0.4.3 commit 98c8cbdf0f1646f0e54782e448a0a73b058abc33 Author: Ian McIntyre Date: Mon Apr 5 20:19:35 2021 -0400 Add 0.4.3 CHANGELOG entry commit 2a97740471ef543ed76928f1fcaaf47bd1ced14c Author: Ian McIntyre Date: Wed Mar 31 22:50:56 2021 -0400 Update CHANGELOG commit 4935e6a6a96dd6e263f22f5d4844306158a0e4ec Author: Ian McIntyre Date: Wed Mar 31 22:21:23 2021 -0400 Allow deprecated atomic::spin_loop_hint() Clippy suggests that we start using core::hint::spin_loop(). This new function was introduced in Rust 1.49, and replaces spin_loop_hint(). We're not going to issue that breaking change right now. So, we'll mark the existing usages as OK. TODO: - Pin a clippy, compiler, toolchain version in CI - Figure out a MSRV, maybe commit 27d85189d62b1694cc446a6f275077dd9cfacfd4 Author: Ian McIntyre Date: Wed Mar 31 22:18:32 2021 -0400 Allow upper case names, acronyms New clippy is very aggressive about proper naming. We're not following proper naming in the 0.4 HAL. Disable the warnings for now. commit 2658b74d9d1d98d9872e9e2357aa2bf5eed8fe7a Author: Ian McIntyre Date: Wed Mar 31 21:33:38 2021 -0400 Address clippy warnings in AdcSource commit be6006e06748585150f5e2a162a4af922f88348b Author: Lane Kolbly Date: Sun Mar 28 10:15:10 2021 -0500 Implement ADC DMA source This commit makes the ADCs a possible source for DMA operations. commit 8f457edaad37cfd294e6eaeae42605f3214a1b2e Author: Ian McIntyre Date: Mon Mar 22 20:10:44 2021 -0400 Update CHANGELOG commit 227f37562ae0e124a5f7940abf3260ac4d52f2b9 Author: Ian McIntyre Date: Mon Mar 22 20:06:14 2021 -0400 Add CI for 1061, 1064 features commit e3c77a0269f3ff1c7231b49606a413c587f14bec Author: Ian McIntyre Date: Mon Mar 22 19:59:05 2021 -0400 Add support for the 1061 See the data sheet for differences. One notable change is that the 1061 doesn't have the graphics features (LCD, CSI, pixel pipeline). We don't have drivers for these peripherals today, so the HAL can support these features without issue. commit 5256dd954fd68ca88997f2fe7962095ea2a6c4ee Author: Ian McIntyre Date: Sat Mar 20 19:46:39 2021 -0400 Enable the imxrt1064 feature The HAL builds with the `imxrt1064` feature: cd imxrt-hal cargo build --features imxrt1064 It has not been tested on hardware. Only thing that seems to change is the FlexSPI2 IOMUXC registers are reserved. Everything else is the same. commit 357a71a897b72a0b9572719c3229581de758b001 Author: Ian McIntyre Date: Tue Nov 17 19:36:06 2020 -0500 Bump imxrt-hal to 0.4.2 commit f8514f9c852c545d5fad1df0183634aabf231c48 Author: Ian McIntyre Date: Tue Nov 17 19:40:10 2020 -0500 Update CHANGELOG commit 61dccd9624d66fad0a445ecf33dd799e25919822 Author: Ian McIntyre Date: Tue Nov 17 19:33:40 2020 -0500 Explicitly depend on imxrt-iomuxc 0.1.2 That release introduces the ADC pins, which are required for the current HAL. commit c4a4111382d1ad6370c391018eba6302003bd081 Author: Ian McIntyre Date: Tue Nov 17 19:30:58 2020 -0500 Update README and release docs The documentation in this branch should still be useful. This commit revises our documentation to reflect the broader imxrt-rs org. commit 0567ab45ff4d5d4e8116d35591c0afb3c45ccdff Author: Ian McIntyre Date: Tue Nov 17 19:08:25 2020 -0500 Remove iomuxc crate from 0.4 branch It's been moved to a separate repo. This change is to prevent someone from accidentally releasing the iomuxc crate from this repo. commit 8efe35c1447d8ab93599d84f651fd09c3fd2fc75 Author: Ian McIntyre Date: Mon Nov 16 20:44:37 2020 -0500 Remove RAL from 0.4 branch Manually removing the RAL, since it's already been removed in master. This is to ensure that we don't accidentally depend on something in this 0.4 maintenance branch that isn't correctly reflected in our RAL repo. commit bf0bbfa5dd7667b59aa1b6d6b28e4e6e31a8216d Author: Ian McIntyre Date: Mon Nov 16 19:39:22 2020 -0500 Fix CHANGELOG entrie for unreleased fixes Added the error correction to the wrong "Fix" header commit f1301cce8935a86f7dcf80dd0dec1de0008c9747 Author: Ian McIntyre Date: Mon Nov 16 19:27:38 2020 -0500 Update CHANGELOG describing fix for errors commit 429b9fab62db37d3c5880f0c1ea60d36605190dc Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Sun Nov 15 08:41:46 2020 -0800 Only allow HAL to create I2C/SPI config errors commit 0878f7aa8d21ef25073dbe4a9dd19aec2da2c1be Author: Ian McIntyre Date: Mon Nov 16 19:34:32 2020 -0500 Update CHANGELOG with TRNG addition commit c697e69603b47135f3a146496cec2b6fff930801 Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Tue Nov 17 11:43:32 2020 -0800 Fix comment, don't preserve bad value commit 74706422b423fda7c588ea46c5bd4b73b365b961 Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Sun Nov 15 08:33:16 2020 -0800 Preserve settings, fix error privacy commit 12dba785d252a54d72484d11c64bc173d694798c Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Sat Nov 14 06:05:44 2020 -0800 Add optional RngCore impl commit 51f4644114d3d271b7e5b52528fa31af7e5d4bf8 Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Fri Oct 9 03:23:32 2020 -0700 Implement basic support for the TRNG Limited configurability but it works. commit f819cc53912d491bf72a3f93c3a0338a77416819 Author: Ian McIntyre Date: Thu Oct 15 18:52:25 2020 -0400 hal: add CHANGELOG entry for ADC feature commit de9cdca1d502fcc708bb74938caccf270282e61b Author: DavidTheFighter <19dallen@gmail.com> Date: Wed Oct 14 21:46:21 2020 -0400 (Hopefully) removed Cargo.toml from changes commit 93bb6cd49203c725e7966e6d8d3cd6ce463205a3 Author: DavidTheFighter <19dallen@gmail.com> Date: Wed Oct 14 20:40:34 2020 -0400 Implemented suggestions commit fdae6ed800354e8f64ade1632dcb0cefda349443 Author: DavidTheFighter <19dallen@gmail.com> Date: Wed Oct 7 13:06:54 2020 -0400 3rd time's a charm, fix CI issues commit b2335df9dbfdc9488bb8e5d51a7ca0abce8c9bab Author: DavidTheFighter <19dallen@gmail.com> Date: Wed Oct 7 12:41:52 2020 -0400 Hopefully actually fixed build issues commit 8a966bc17a3274b659d4f34174a4fce3856e8c08 Author: DavidTheFighter <19dallen@gmail.com> Date: Tue Oct 6 22:54:22 2020 -0400 Fixed issues from checks commit 88d02cdb9075f7c59b88407761091b2040bfbf23 Author: DavidTheFighter <19dallen@gmail.com> Date: Tue Oct 6 22:36:58 2020 -0400 Finished up comments & example commit 1f6aa15a93d0d49283dd025557d88dbbb281f0ed Author: DavidTheFighter <19dallen@gmail.com> Date: Tue Oct 6 00:16:22 2020 -0400 Changed AnalogPin creation commit 22ac89b84d9aa2b60ff24f7fc6be8f7a22e07976 Author: DavidTheFighter <19dallen@gmail.com> Date: Mon Oct 5 21:12:12 2020 -0400 Added adc to peripherals commit 684592ef73d5b1e84c234adcedb22576a3828ad2 Author: DavidTheFighter <19dallen@gmail.com> Date: Mon Oct 5 21:05:44 2020 -0400 Added input data for all IMXRT106x pins commit 744ce7072015ca8bb8d483d6f5e7e6c54c078b77 Author: DavidTheFighter <19dallen@gmail.com> Date: Mon Oct 5 20:58:36 2020 -0400 Potential ADC implementation take 1 commit 3f98a204b9356299486c28c77d74b6029e7265db Author: DavidTheFighter <19dallen@gmail.com> Date: Sun Oct 4 23:54:02 2020 -0400 Transfer work to fork commit b7a1a56fc8a36ea75f13f41333998ea382521e3c Author: Ian McIntyre Date: Sat Oct 10 20:58:36 2020 -0400 imxrt-hal: add CHANGELOG entry for SRTC commit 24b73db611e16ea67f16ba064bca40b9411668cc Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Thu Oct 8 22:32:09 2020 -0700 Update following review commit f9b71bd4ff12832b4834239d540b6325a00a8ea4 Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Tue Oct 6 17:00:38 2020 -0700 Use microseconds, add get_with_micros commit 0bea36d87659c4f2e204efae01cc948734d7b764 Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Tue Oct 6 14:02:07 2020 -0700 Revert "Add get_f64" This reverts commit aec0ed6731828b2826eef4839658e97f4dc78dfc. commit 597a113a5fd247ae074f41456bcacac8720c72d3 Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Sun Oct 4 22:37:34 2020 -0700 Add get_f64 commit 665e1c815e94486412d2f0d8cb27200239d1fb40 Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Sun Oct 4 21:28:19 2020 -0700 Update for review and sub-second times Now exclusively enables and uses the SRTC. commit 72f57aa8adefb537e978783e320d5940ad73ace7 Author: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Fri Oct 2 17:04:38 2020 -0700 Implement basic RTC support Supports enabling and setting the clocks. commit f77c16a1969f1644ea7316861444e16dfb5cfda8 Author: Ian McIntyre Date: Sun Sep 13 08:01:34 2020 -0400 hal: Prepare release 0.4.1 commit c1a7d3268a0df96aa0d58e3dc88fba481aebcf99 Author: Ian McIntyre Date: Sun Sep 13 07:51:33 2020 -0400 hal: Add CHANGELOG entry for GPIO fast mode fix commit c8ff33fc141eeea137035731b951355cc7acbc2b Author: Ian McIntyre Date: Sun Sep 13 07:48:16 2020 -0400 gpio: Clarify 'state' in set_fast() documentation commit 887a8e1dffa90a51320826c12169899571d16039 Author: Ian McIntyre Date: Sun Sep 13 07:33:48 2020 -0400 gpio: Fix GPIO high-speed state inconsistency There are two valid ways to prepare a high-speed GPIO output: ```rust pub fn configure_led(pad: LedPadType) -> LED { let mut led = hal::gpio::GPIO::new(pad); led.set_fast(true); led.output() } ``` and ```rust pub fn configure_led(pad: LedPadType) -> LED { let mut led = hal::gpio::GPIO::new(pad).output(); led.set_fast(true); led } ``` the former will put the GPIO into high-speed, or 'fast,' mode before setting 'output mode.' The latter will put the GPIO into output mode before fast mode. After transitioning into fast mode, the GPIO will start to reference a different GPIO register block. The issue is that, after entering fast mode, the output / input state of the pin is not maintained. In the second snippet, the set_fast(true) call ends up reverting the GPIO state back to 'input,' since the newly-referenced register block does not maintain the same GPIO input / output configuration. This commit updates the set_fast() method to maintain the GPIO I/O state for the new register block. It makes it so that either of the above patterns work. --- .github/workflows/rust.yml | 44 +--- README.md | 24 +- docs/RELEASE.md | 17 +- imxrt-hal/CHANGELOG.md | 5 + imxrt-hal/Cargo.toml | 4 +- imxrt-hal/README.md | 28 +-- imxrt-hal/src/adc.rs | 17 +- imxrt-hal/src/can/mod.rs | 120 ++++++++- imxrt-hal/src/ccm.rs | 30 +-- imxrt-hal/src/dma.rs | 433 +++----------------------------- imxrt-hal/src/dma/peripheral.rs | 143 +++++++++-- imxrt-hal/src/gpio.rs | 8 +- imxrt-hal/src/lib.rs | 14 +- imxrt-hal/src/srtc.rs | 4 +- imxrt-hal/src/tempmon.rs | 395 +++++++++++++++++++++++++++++ imxrt-hal/src/trng.rs | 13 - 16 files changed, 721 insertions(+), 578 deletions(-) create mode 100644 imxrt-hal/src/tempmon.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 96e928a6..4a372fcb 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -3,42 +3,18 @@ name: All Checks on: [push, pull_request] jobs: - build-hals: + build-hal: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Build HAL(s) - run: cargo build --verbose - - name: Run HAL(s) tests - run: cargo test --verbose - - name: Check format for HAL(s) - run: cargo fmt --all -- --check - - name: Run clippy for HAL(s) - run: cargo clippy -- -D warnings - - # imxrt1060-hal feature checks - imxrt1060-features: strategy: matrix: - features: ["rand_core", "rtic", "rt", "rand_core,rtic,rt"] - env: - RUSTFLAGS: -D warnings - runs-on: ubuntu-latest + feature: ["imxrt1061", "imxrt1062", "imxrt1064"] steps: - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - target: thumbv7em-none-eabihf - override: true - profile: minimal - - name: Check imxrt-hal with features '${{ matrix.features }}' - uses: actions-rs/cargo@v1 - with: - command: check - args: > - --features=${{ matrix.features }} - --manifest-path=imxrt-hal/Cargo.toml - --target=thumbv7em-none-eabihf - --verbose - + - name: Build imxrt-hal for (${{ matrix.feature }}) HAL + run: cd imxrt-hal && cargo build --verbose --features ${{ matrix.feature }} + - name: Run tests (${{ matrix.feature }}) for HAL + run: cd imxrt-hal && cargo test --verbose --features ${{ matrix.feature }} + - name: Check format (${{ matrix.feature }}) for HAL + run: cd imxrt-hal && cargo fmt --all -- --check + - name: Run clippy (${{ matrix.feature }}) for HAL + run: cd imxrt-hal && cargo clippy --features ${{ matrix.feature }} -- -D warnings diff --git a/README.md b/README.md index 404de44c..3b9287d4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# imxrt-hal +# imxrt-rs A Rust hardware abstraction layer (HAL) for NXP i.MX RT processors. @@ -9,19 +9,6 @@ A Rust hardware abstraction layer (HAL) for NXP i.MX RT processors. [imxrt-hal-badge]: https://img.shields.io/crates/v/imxrt-hal [imxrt-hal-url]: https://crates.io/crates/imxrt-hal -[matrix-chat](https://matrix.to/#/#imxrt-rs:matrix.org) - -## Goals - -- Create *the* collaborative group to support using Rust on NXP's i.MX RT series. -- Simple but useful register level access. It compiles quickly, and it's intuitive for existing embedded developers. Every hal republishes the RAL. -- Embedded HAL support. -- RTIC support. -- NXP EVK board support -- Supporting popular boards such as the Teensy 4. - -## Getting Started - ### HAL If you want to develop Rust libraries and applications for an i.MX RT-based system, use the `imxrt-hal` crate. The `imxrt-hal` crate provides implementations of the [`embedded-hal` traits](https://crates.io/crates/embedded-hal) specific to i.MX RT processors. Use the HAL if you want to @@ -33,7 +20,7 @@ If you want to develop Rust libraries and applications for an i.MX RT-based syst - read and write serial data (UART) - send and receive data over SPI -The publicly-supported HAL is on [crates.io](https://crates.io/crates/imxrt-hal). Include the HAL in your Rust library or binary: +The HAL is on [crates.io](https://crates.io/crates/imxrt-hal). Include the HAL in your Rust library or binary: ```toml [dependencies.imxrt-hal] @@ -52,11 +39,6 @@ The `"rt"` feature flag is recommended for users who are Enabling the `"rt"` feature-flag will link in the i.MX RT interrupt table. If you're familiar with crates that are generated from `svd2rust`, [the `"rt"` feature](https://docs.rs/svd2rust/0.17.0/svd2rust/#the-rt-feature) has the same behaviors in the `imxrt-hal` as it does in `svd2rust`-generated crates. -#### Future of the HAL - -Follow #56 to understand how we're breaking `imxrt-hal` into separate crates. If you'd like to try the new HAL crate(s), depend on `imxrt1060-hal`, and skip the feature flag that describes your i.MX RT variant. - - ## Q/A #### *Are there any board support packages (BSP) that use the `imxrt-hal` crate?* @@ -94,4 +76,4 @@ Licensed under either of http://www.apache.org/licenses/LICENSE-2.0) - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) -at your option. +at your option. \ No newline at end of file diff --git a/docs/RELEASE.md b/docs/RELEASE.md index a79f5fb9..ef20b3af 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -1,22 +1,17 @@ ## Publish a release -From a clean repository, at the root: +Ensure that all other imxrt-rs dependencies, like `imxrt-ral` and +`imxrt-iomuxc`, are already published. Then, publish the HAL: -1. If needed, publish a new imxrt-ral following instructions there for release. -2. In each HAL such as imxrt1060-hal/Cargo.toml`, update both - - the version of the HAL - - the HAL's dependency of the RAL -3. Commit the changes, and create a tag. -4. Publish the HAL(s): - ``` - cargo publish --manifest-path imxrt1060-hal/Cargo.toml - ``` +``` +cargo publish --manifest-path imxrt-hal/Cargo.toml --features imxrt1062 +``` ## Maintaining older releases This section describes how imxrt-rs project maintainers support older releases. If there is a bug fix that you would like to apply to an older version of the -RAL or HAL crates, follow the process below to create a new patch +RAL, HAL, or IOMUXC crates, follow the process below to create a new patch release. - Integrate bug fixes on the main branch. diff --git a/imxrt-hal/CHANGELOG.md b/imxrt-hal/CHANGELOG.md index 41c8b070..bf2d150b 100644 --- a/imxrt-hal/CHANGELOG.md +++ b/imxrt-hal/CHANGELOG.md @@ -2,6 +2,11 @@ ## [Unreleased] +### Added + +Abstraction layer for `tempmon` module. Incl. auto measurement and +alarm interrupts (only available for `"imxrt106x"`) + ## [0.4.5] 2021-12-02 ### Added diff --git a/imxrt-hal/Cargo.toml b/imxrt-hal/Cargo.toml index 2f3b3342..1397ee22 100644 --- a/imxrt-hal/Cargo.toml +++ b/imxrt-hal/Cargo.toml @@ -23,8 +23,8 @@ rand_core = { version = "0.5", default-features = false, optional = true } [dependencies.imxrt-iomuxc] version = "0.1.2" -git = "https://github.com/dstric-aqueduct/imxrt-iomuxc.git" -branch = "v0.1.2/can" +git = "https://github.com/imxrt-rs/imxrt-iomuxc.git" +branch = "v0.1" [dev-dependencies.cortex-m-rt] version = "0.6" diff --git a/imxrt-hal/README.md b/imxrt-hal/README.md index 802a47b8..7eb42111 100644 --- a/imxrt-hal/README.md +++ b/imxrt-hal/README.md @@ -1,22 +1,18 @@ -# imxrt-hal +# imxrt1060-hal -This project provides a Rust HAL (hardware abstraction layer) for all NXP i.MX RT -microcontrollers based on the imxrt-ral crate. +`imxrt1060-hal` is a Rust hardware abstraction layer that's specific to i.MX +RT 1060 processors. This includes some of the following processor parts: -A feature flag needs to be set for any of the supported i.MX RT SoC. +- i.MX RT 1061 +- i.MX RT 1062 -## What is it? +It is the successor to `imxrt-hal`, version 0.4, with `feature = "imxrt1062"`. -imxrt-hal is an experiment into a lightweight hardware abstraction layer. It -provides access to some of the peripherals of the i.MX RT series processors -from NXP using embedded-hal and other community driven hardware APIs. +## Features -The main aims are fast compilation, compactness, and simplicity. +The table below describes the optional features supported by `imxrt1060-hal`. -Please consider trying it out and contributing or leaving feedback! - -## Goals - -* Simple to use and hard to use incorrectly -* All peripherals and busses supported -* Support the entire i.MX RT Series with a single crate to maximize code reuse +| Feature | Description | +| -------- | ---------------------------------- | +| `"rt"` | Runtime support with `cortex-m-rt` | +| `"rtic"` | Support for RTIC | diff --git a/imxrt-hal/src/adc.rs b/imxrt-hal/src/adc.rs index 75d23fc3..98bf9072 100644 --- a/imxrt-hal/src/adc.rs +++ b/imxrt-hal/src/adc.rs @@ -4,10 +4,10 @@ //! //! # Example //! ```no_run -//! use imxrt1060_hal::{self, adc}; +//! use imxrt_hal::{self, adc}; //! use embedded_hal::adc::OneShot; //! -//! let mut peripherals = imxrt1060_hal::Peripherals::take().unwrap(); +//! let mut peripherals = imxrt_hal::Peripherals::take().unwrap(); //! let (adc1_builder, _) = peripherals.adc.clock(&mut peripherals.ccm.handle); //! //! let mut adc1 = adc1_builder.build(adc::ClockSelect::default(), adc::ClockDivision::default()); @@ -258,26 +258,27 @@ where } } -unsafe impl crate::dma::peripheral::Source for AdcSource +impl crate::dma::peripheral::Source for AdcSource where ADCx: adc::ADC + AdcDmaSource, P: Pin, { - fn source_signal(&self) -> u32 { - ADCx::SOURCE_REQUEST_SIGNAL - } + type Error = (); + + const SOURCE_REQUEST_SIGNAL: u32 = ADCx::SOURCE_REQUEST_SIGNAL; fn source(&self) -> *const u16 { &self.adc.reg.R0 as *const _ as *const u16 } - fn enable_source(&self) { + fn enable_source(&mut self) -> Result<(), Self::Error> { let channel =

>::Input::U32; ral::modify_reg!(ral::adc, self.adc.reg, GC, ADCO: 1, DMAEN: 1); ral::modify_reg!(ral::adc, self.adc.reg, HC0, |_| channel); + Ok(()) } - fn disable_source(&self) { + fn disable_source(&mut self) { ral::modify_reg!(ral::adc, self.adc.reg, GC, ADCO: 0, DMAEN: 0); } } diff --git a/imxrt-hal/src/can/mod.rs b/imxrt-hal/src/can/mod.rs index e5bdcb88..51cdb5ce 100644 --- a/imxrt-hal/src/can/mod.rs +++ b/imxrt-hal/src/can/mod.rs @@ -9,7 +9,6 @@ use ral::{modify_reg, read_reg, write_reg}; use crate::ccm; use crate::iomuxc::consts::{Unsigned, U1, U2}; -use crate::iomuxc::can; use crate::ral; use core::convert::Infallible; @@ -104,14 +103,7 @@ where /// Builds a Can peripheral. The return /// is a configured FlexCan peripheral running at 24MHz. - pub fn build(self, mut tx: TX, mut rx: RX) -> CAN - where - TX: can::Pin, - RX: can::Pin, - { - crate::iomuxc::can::prepare(&mut tx); - crate::iomuxc::can::prepare(&mut rx); - + pub fn build(self) -> CAN { CAN::new(self.source_clock, self.reg) } } @@ -193,6 +185,8 @@ where pub fn begin(&mut self) { self.set_ccm_ccg(); + self.set_tx(); + self.set_rx(); ral::modify_reg!(ral::can, self.reg, MCR, MDIS: MDIS_0); @@ -294,6 +288,114 @@ where } } + fn set_tx(&mut self) { + match self.instance_number() { + 1 => { + unsafe { + modify_reg!( + ral::iomuxc, + IOMUXC, + SW_MUX_CTL_PAD_GPIO_AD_B1_08, + MUX_MODE: ALT2, + SION: ENABLED + ) + }; + unsafe { + write_reg!( + ral::iomuxc, + IOMUXC, + SW_PAD_CTL_PAD_GPIO_AD_B1_08, + 0x10B0_u32 + ) + }; + } + 2 => { + unsafe { + modify_reg!( + ral::iomuxc, + IOMUXC, + SW_MUX_CTL_PAD_GPIO_AD_B0_02, + MUX_MODE: ALT0, + SION: ENABLED + ) + }; + unsafe { + write_reg!( + ral::iomuxc, + IOMUXC, + SW_PAD_CTL_PAD_GPIO_AD_B0_02, + 0x10B0_u32 + ) + }; + } + u => { + log::error!("Invalid Can instance (set_tx): {:?}", u); + } + } + } + + fn set_rx(&mut self) { + match self.instance_number() { + 1 => { + unsafe { + modify_reg!( + ral::iomuxc, + IOMUXC, + FLEXCAN1_RX_SELECT_INPUT, + DAISY: GPIO_AD_B1_09_ALT2 + ) + }; + unsafe { + modify_reg!( + ral::iomuxc, + IOMUXC, + SW_MUX_CTL_PAD_GPIO_AD_B1_09, + MUX_MODE: ALT2, + SION: ENABLED + ) + }; + unsafe { + write_reg!( + ral::iomuxc, + IOMUXC, + SW_PAD_CTL_PAD_GPIO_AD_B1_09, + 0x10B0_u32 + ) + }; + } + 2 => { + unsafe { + modify_reg!( + ral::iomuxc, + IOMUXC, + FLEXCAN2_RX_SELECT_INPUT, + DAISY: GPIO_AD_B0_03_ALT0 + ) + }; + unsafe { + modify_reg!( + ral::iomuxc, + IOMUXC, + SW_MUX_CTL_PAD_GPIO_AD_B0_03, + MUX_MODE: ALT0, + SION: ENABLED + ) + }; + unsafe { + write_reg!( + ral::iomuxc, + IOMUXC, + SW_PAD_CTL_PAD_GPIO_AD_B0_03, + 0x10B0_u32 + ) + }; + } + u => { + log::error!("Invalid Can instance (set_rx): {:?}", u); + } + } + } + pub fn get_clock(&self) -> u32 { self.source_clock.0 } diff --git a/imxrt-hal/src/ccm.rs b/imxrt-hal/src/ccm.rs index 593b3d89..dfc2be3d 100644 --- a/imxrt-hal/src/ccm.rs +++ b/imxrt-hal/src/ccm.rs @@ -57,10 +57,6 @@ impl PLL1 { PLL1(()) } - #[cfg(any(feature = "imxrt1011", feature = "imxrt1015"))] - pub const ARM_HZ: u32 = 500_000_000; - - #[cfg(any(feature = "imxrt1064", feature = "imxrt1062", feature = "imxrt1061"))] pub const ARM_HZ: u32 = 600_000_000; /// Set the clock speed for the ARM core. This represents the base processor frequency. @@ -925,30 +921,6 @@ pub mod spi { LPSPI_PODF_6 = ccm::CBCMR::LPSPI_PODF::RW::LPSPI_PODF_6, /// 0b0111: divide by 8 LPSPI_PODF_7 = ccm::CBCMR::LPSPI_PODF::RW::LPSPI_PODF_7, - /// 0b1000: divide by 9 - #[cfg(features = "imxrt1011")] - LPSPI_PODF_8 = ccm::CBCMR::LPSPI_PODF::RW::LPSPI_PODF_8, - /// 0b1001: divide by 10 - #[cfg(features = "imxrt1011")] - LPSPI_PODF_9 = ccm::CBCMR::LPSPI_PODF::RW::LPSPI_PODF_9, - /// 0b1010: divide by 11 - #[cfg(features = "imxrt1011")] - LPSPI_PODF_10 = ccm::CBCMR::LPSPI_PODF::RW::LPSPI_PODF_10, - /// 0b1011: divide by 12 - #[cfg(features = "imxrt1011")] - LPSPI_PODF_11 = ccm::CBCMR::LPSPI_PODF::RW::LPSPI_PODF_11, - /// 0b1100: divide by 13 - #[cfg(features = "imxrt1011")] - LPSPI_PODF_12 = ccm::CBCMR::LPSPI_PODF::RW::LPSPI_PODF_12, - /// 0b1101: divide by 14 - #[cfg(features = "imxrt1011")] - LPSPI_PODF_13 = ccm::CBCMR::LPSPI_PODF::RW::LPSPI_PODF_13, - /// 0b1110: divide by 15 - #[cfg(features = "imxrt1011")] - LPSPI_PODF_14 = ccm::CBCMR::LPSPI_PODF::RW::LPSPI_PODF_14, - /// 0b1111: divide by 16 - #[cfg(features = "imxrt1011")] - LPSPI_PODF_15 = ccm::CBCMR::LPSPI_PODF::RW::LPSPI_PODF_15, } impl From for Frequency { @@ -1123,4 +1095,4 @@ pub mod can { Divider((prescalar_select as u32) + 1) } } -} \ No newline at end of file +} diff --git a/imxrt-hal/src/dma.rs b/imxrt-hal/src/dma.rs index 25c63321..4ad641ff 100644 --- a/imxrt-hal/src/dma.rs +++ b/imxrt-hal/src/dma.rs @@ -34,7 +34,7 @@ //! handler, since we're enabling an interrupt when the receive completes. //! //! ```no_run -//! use imxrt_hal::dma::{Circular, Buffer, Linear, Peripheral, bidirectional_u16}; +//! use imxrt1060_hal::dma::{Circular, Buffer, Linear, Peripheral, bidirectional_u16}; //! //! // Circular buffers have alignment requirements //! #[repr(align(512))] @@ -44,7 +44,7 @@ //! static RX_BUFFER: Buffer<[u16; 256]> = Buffer::new([0; 256]); //! static TX_BUFFER: Align = Align(Buffer::new([0; 256])); //! -//! let mut peripherals = imxrt_hal::Peripherals::take().unwrap(); +//! let mut peripherals = imxrt1060_hal::Peripherals::take().unwrap(); //! //! // //! // SPI setup... @@ -52,8 +52,8 @@ //! //! let (_, _, _, spi4_builder) = peripherals.spi.clock( //! &mut peripherals.ccm.handle, -//! imxrt_hal::ccm::spi::ClockSelect::Pll2, -//! imxrt_hal::ccm::spi::PrescalarSelect::LPSPI_PODF_5, +//! imxrt1060_hal::ccm::spi::ClockSelect::Pll2, +//! imxrt1060_hal::ccm::spi::PrescalarSelect::LPSPI_PODF_5, //! ); //! //! let mut spi4 = spi4_builder.build( @@ -150,314 +150,55 @@ //! - Channel priority, and channel priority swapping //! - Channel chaining -#![allow(non_snake_case)] // Compatibility with RAL - mod buffer; -mod element; mod memcpy; pub(crate) mod peripheral; -mod register; + +use imxrt_dma::Transfer; +pub use imxrt_dma::{Channel, Element, ErrorStatus}; pub use buffer::{Buffer, Circular, CircularError, Drain, Linear, ReadHalf, WriteHalf}; -pub use element::Element; pub use memcpy::Memcpy; pub use peripheral::{helpers::*, Peripheral}; use crate::{ccm, ral}; -use core::{ - fmt::{self, Debug, Display}, - mem, -}; -pub use register::tcd::BandwidthControl; -use register::{DMARegisters, MultiplexerRegisters, Static, DMA, MULTIPLEXER}; - -/// A DMA channel -/// -/// DMA channels provide one-way transfers of data. They accept a source of data, -/// and a destination of data. They copy data from the source to the destination. -/// When the transfer is complete, a DMA channel signals completion by changing a -/// value in a register, or triggering an interrupt. -/// -/// DMA channels have very little public interface. They're best used when paired with a -/// [`Peripheral`](struct.Peripheral.html) or a [`Memcpy`](struct.Memcpy.html). -pub struct Channel { - /// Our channel number, expected to be between 0 to 31 - index: usize, - /// Reference to the DMA registers - registers: Static, - /// Reference to the DMA multiplexer - multiplexer: Static, -} - -impl Channel { - /// Set the channel's bandwidth control - /// - /// The bandwidth control will be used in any [`Memcpy`](struct.Memcpy.html) or - /// [`Peripheral`](struct.Peripheral.html) DMA transfers. - /// - /// - `None` disables bandwidth control (default setting) - /// - `Some(bwc)` sets the bandwidth control to `bwc` - pub fn set_bandwidth_control(&mut self, bandwidth: Option) { - let raw = BandwidthControl::raw(bandwidth); - let tcd = self.tcd(); - ral::modify_reg!(register::tcd, tcd, CSR, BWC: raw); - } - - /// Returns the DMA channel number - /// - /// Channels are unique and numbered within the half-open range `[0, 32)`. - pub fn channel(&self) -> usize { - self.index - } - - /// Allocates a DMA channel, and sets the initial state for - /// the channel. - fn new(index: usize) -> Self { - let channel = Channel { - index, - registers: DMA, - multiplexer: MULTIPLEXER, - }; - channel.registers.TCD[channel.index].reset(); - channel - } - - /// Returns a handle to this channel's transfer control descriptor - fn tcd(&self) -> ®ister::TransferControlDescriptor { - &self.registers.TCD[self.index] - } - - /// Prepare the source of a transfer; see [`Transfer`](struct.Transfer.html) for details. - /// - /// # Safety - /// - /// Address pointer must be valid for lifetime of the transfer. - unsafe fn set_source_transfer>, E: Element>(&mut self, transfer: T) { - let tcd = self.tcd(); - let transfer = transfer.into(); - ral::write_reg!(register::tcd, tcd, SADDR, transfer.address as u32); - ral::write_reg!(register::tcd, tcd, SOFF, transfer.offset); - ral::modify_reg!(register::tcd, tcd, ATTR, SSIZE: E::DATA_TRANSFER_ID, SMOD: transfer.modulo); - ral::write_reg!(register::tcd, tcd, SLAST, transfer.last_address_adjustment); - } - - /// Prepare the destination for a transfer; see [`Transfer`](struct.Transfer.html) for details. - /// - /// # Safety - /// - /// Address pointer must be valid for lifetime of the transfer. - unsafe fn set_destination_transfer>, E: Element>(&mut self, transfer: T) { - let tcd = self.tcd(); - let transfer = transfer.into(); - ral::write_reg!(register::tcd, tcd, DADDR, transfer.address as u32); - ral::write_reg!(register::tcd, tcd, DOFF, transfer.offset); - ral::modify_reg!(register::tcd, tcd, ATTR, DSIZE: E::DATA_TRANSFER_ID, DMOD: transfer.modulo); - ral::write_reg!( - register::tcd, - tcd, - DLAST_SGA, - transfer.last_address_adjustment - ); - } - - /// Set the number of *bytes* to transfer per minor loop - /// - /// Describes how many bytes we should transfer for each DMA service request. - fn set_minor_loop_bytes(&mut self, nbytes: u32) { - let tcd = self.tcd(); - ral::write_reg!(register::tcd, tcd, NBYTES, nbytes); - } - - /// Se the number of elements to move in each minor loop - /// - /// Describes how many elements we should transfer for each DMA service request. - fn set_minor_loop_elements(&mut self, len: usize) { - self.set_minor_loop_bytes((mem::size_of::() * len) as u32); - } - - /// Tells the DMA channel how many transfer iterations to perform - /// - /// A 'transfer iteration' is a read from a source, and a write to a destination, with - /// read and write sizes described by a minor loop. Each iteration requires a DMA - /// service request, either from hardware or from software. - fn set_transfer_iterations(&mut self, iterations: u16) { - let tcd = self.tcd(); - ral::write_reg!(register::tcd, tcd, CITER, iterations); - ral::write_reg!(register::tcd, tcd, BITER, iterations); - } - /// Enable or disabling triggering from hardware - /// - /// If source is `Some(value)`, we trigger from hardware identified by the source identifier. - /// If `source` is `None`, we disable hardware triggering. - fn set_trigger_from_hardware(&mut self, source: Option) { - let chcfg = &self.multiplexer.chcfg[self.index]; - chcfg.write(0); - if let Some(source) = source { - chcfg.write(MultiplexerRegisters::ENBL | source); - } - } - - /// Set this DMA channel as always on - /// - /// Use `set_always_on()` so that the DMA multiplexer drives the transfer with no - /// throttling. Specifically, an "always-on" transfer will not need explicit re-activiation - /// between major loops. - /// - /// Use an always-on channel for memory-to-memory transfers, so that you don't need explicit - /// software re-activation to maintain the transfer. On the other hand, most peripheral transfers - /// should not use an always-on channel, since the peripheral should control the data flow through - /// explicit activation. - fn set_always_on(&mut self) { - let chcfg = &self.multiplexer.chcfg[self.index]; - chcfg.write(0); - chcfg.write(MultiplexerRegisters::ENBL | MultiplexerRegisters::A_ON); - } - - /// Returns `true` if the DMA channel is receiving a service signal from hardware - fn is_hardware_signaling(&self) -> bool { - self.registers.HRS.read() & (1 << self.index) != 0 - } - - /// Enable or disable the DMA's multiplexer request - /// - /// In this DMA implementation, all peripheral transfers and memcpy requests - /// go through the DMA multiplexer. So, this needs to be set for the multiplexer - /// to service the channel. - fn set_enable(&mut self, enable: bool) { - if enable { - self.registers.SERQ.write(self.index as u8); - } else { - self.registers.CERQ.write(self.index as u8); - } - } - - /// Returns `true` if this DMA channel generated an interrupt - fn is_interrupt(&self) -> bool { - self.registers.INT.read() & (1 << self.index) != 0 - } - - /// Clear the interrupt flag from this DMA channel - fn clear_interrupt(&mut self) { - self.registers.CINT.write(self.index as u8); - } - - /// Enable or disable 'disable on completion' - /// - /// 'Disable on completion' lets the DMA channel automatically clear the request signal - /// when it completes a transfer. - fn set_disable_on_completion(&mut self, dreq: bool) { - let tcd = self.tcd(); - ral::modify_reg!(register::tcd, tcd, CSR, DREQ: dreq as u16); - } - - /// Enable or disable interrupt generation when the transfer completes - /// - /// You're responsible for registering your interrupt handler. - pub fn set_interrupt_on_completion(&mut self, intr: bool) { - let tcd = self.tcd(); - ral::modify_reg!(register::tcd, tcd, CSR, INTMAJOR: intr as u16); - } - - /// Returns `true` if this channel's completion will generate an interrupt - pub fn is_interrupt_on_completion(&self) -> bool { - let tcd = self.tcd(); - ral::read_reg!(register::tcd, tcd, CSR, INTMAJOR == 1) - } - - /// Enable or disable interrupt generation when the transfer is half complete - /// - /// You're responsible for registering your interrupt handler. - pub fn set_interrupt_on_half(&mut self, intr: bool) { - let tcd = self.tcd(); - ral::modify_reg!(register::tcd, tcd, CSR, INTHALF: intr as u16); - } - - /// Returns `true` if this channel will generate an interrupt halfway through transfer - pub fn is_interrupt_on_half(&self) -> bool { - let tcd = self.tcd(); - ral::read_reg!(register::tcd, tcd, CSR, INTHALF == 1) - } - - /// Indicates if the DMA transfer has completed - fn is_complete(&self) -> bool { - let tcd = self.tcd(); - ral::read_reg!(register::tcd, tcd, CSR, DONE == 1) - } - - /// Clears completion indication - fn clear_complete(&mut self) { - self.registers.CDNE.write(self.index as u8); - } - - /// Indicates if the DMA channel is in an error state - fn is_error(&self) -> bool { - self.registers.ERR.read() & (1 << self.index) != 0 - } - - /// Clears the error flag - fn clear_error(&mut self) { - self.registers.CERR.write(self.index as u8); - } - - /// Indicates if this DMA channel is actively transferring data - fn is_active(&self) -> bool { - let tcd = self.tcd(); - ral::read_reg!(register::tcd, tcd, CSR, ACTIVE == 1) - } - - /// Indicates if this DMA channel is enabled - fn is_enabled(&self) -> bool { - self.registers.ERQ.read() & (1 << self.index) != 0 - } - - /// Returns the value from the **global** error status register - /// - /// It may reflect the last channel that produced an error, and that - /// may not be related to this channel. - fn error_status(&self) -> u32 { - self.registers.ES.read() - } - - /// Start a DMA transfer - /// - /// `start()` should be used to request service from the DMA controller. It's - /// necessary for in-memory DMA transfers. Do not use it for hardware-initiated - /// DMA transfers. DMA transfers that involve hardware will rely on the hardware - /// to request DMA service. - /// - /// Flag is automatically cleared by hardware after it's asserted. - fn start(&mut self) { - self.registers.SSRT.write(self.index as u8); - } -} +/// The number of DMA channels +pub const CHANNEL_COUNT: usize = 32; /// An error when preparing a transfer #[derive(Debug)] #[non_exhaustive] -pub enum Error

{ +pub enum Error { /// There is already a scheduled transfer /// /// Cancel the transfer and try again. ScheduledTransfer, - /// The peripheral returned an error - Peripheral(P), /// Error setting up the DMA transfer Setup(ErrorStatus), } +/// Helper symbol to support DMA channel initialization +/// +/// We always provide users with an array of 32 channels. But, only the first `CHANNEL_COUNT` +/// channels are initialized. +const DMA_CHANNEL_INIT: [Option; 32] = [ + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, +]; + /// Unclocked, uninitialized DMA channels /// /// Use [`clock()`](struct.Unclocked.html#method.clock) to initialize and acquire all DMA channels /// /// ```no_run -/// let mut peripherals = imxrt_hal::Peripherals::take().unwrap(); +/// let mut peripherals = imxrt1060_hal::Peripherals::take().unwrap(); /// /// let mut dma_channels = peripherals.dma.clock(&mut peripherals.ccm.handle); /// let channel_27 = dma_channels[27].take().unwrap(); /// let channel_0 = dma_channels[0].take().unwrap(); /// ``` -pub struct Unclocked([Option; 32]); +pub struct Unclocked([Option; CHANNEL_COUNT]); impl Unclocked { pub(crate) fn new(dma: ral::dma0::Instance, mux: ral::dmamux::Instance) -> Self { // Explicitly dropping instances @@ -467,134 +208,24 @@ impl Unclocked { drop(dma); drop(mux); - Unclocked([ - None, None, None, None, None, None, None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, None, None, None, None, None, None, - None, None, None, None, - ]) + Unclocked(DMA_CHANNEL_INIT) } /// Enable the clocks for the DMA peripheral /// - /// The return is 32 channels, each being initialized as `Some(Channel)`. Users may take channels as needed. - /// The index in the array maps to the DMA channel number. + /// The return is an array of 32 channels. However, **only the first [`CHANNEL_COUNT`](constant.CHANNEL_COUNT.html) channels + /// are initialized to `Some(channel)`. The rest are `None`.** + /// + /// Users may take channels as needed. The index in the array maps to the DMA channel number. pub fn clock(mut self, ccm: &mut ccm::Handle) -> [Option; 32] { let (ccm, _) = ccm.raw(); ral::modify_reg!(ral::ccm, ccm, CCGR5, CG3: 0x03); - for (idx, channel) in self.0.iter_mut().enumerate() { - *channel = Some(Channel::new(idx)); + for (idx, channel) in self.0.iter_mut().take(CHANNEL_COUNT).enumerate() { + // Safety: because we have the DMA instance, we assume that we own the DMA + // peripheral. That means we own all the DMA channels. + let mut chan = unsafe { Channel::new(idx) }; + chan.reset(); + *channel = Some(chan); } self.0 } } - -/// A wrapper around a DMA error status value -/// -/// The wrapper contains a copy of the DMA controller's -/// error status register at the point of an error. The -/// wrapper implements both `Debug` and `Display`. The -/// type may be printed to understand why there was a -/// DMA error. -#[derive(Clone, Copy)] -pub struct ErrorStatus { - /// The raw error status - es: u32, -} - -impl ErrorStatus { - const fn new(es: u32) -> Self { - ErrorStatus { es } - } -} - -impl Debug for ErrorStatus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "DMA_ES({:#010X})", self.es) - } -} - -impl Display for ErrorStatus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, - "DMA_ES: VLD {vld} ECX {ecx} GPE {gpe} CPE {cpe} ERRCHN {errchn} SAE {sae} SOE {soe} DAE {dae} DOE {doe} NCE {nce} SGE {sge} SBE {sbe} DBE {dbe}", - vld = (self.es >> 31) & 0x1, - ecx = (self.es >> 16) & 0x1, - gpe = (self.es >> 15) & 0x1, - cpe = (self.es >> 14) & 0x1, - errchn = (self.es >> 8) & 0x1F, - sae = (self.es >> 7) & 0x1, - soe = (self.es >> 6) & 0x1, - dae = (self.es >> 5) & 0x1, - doe = (self.es >> 4) & 0x1, - nce = (self.es >> 3) & 0x1, - sge = (self.es >> 2) & 0x1, - sbe = (self.es >> 1) & 0x1, - dbe = self.es & 0x1 - ) - } -} - -/// Describes a DMA transfer -/// -/// `Transfer` describes a source or a destination of a DMA transfer. See the member -/// documentation for details. -#[derive(Clone, Copy, Debug)] -struct Transfer { - /// The starting address for the DMA transfer - /// - /// If this describes a source, `address` will be the first - /// address read. If this describes a destination, `address` - /// will be the first address written. - address: *const E, - - /// Offsets to perform for each read / write of a memory address. - /// - /// When defining a transfer for a peripheral source or destination, - /// `offset` should be zero. Otherwise, `offset` should represent the - /// size of the data element, `E`. - /// - /// Negative (backwards) adjustments are permitted, if you'd like to read - /// a buffer backwards or something. - offset: i16, - - /* size: u16, // Not needed; captured in E: Element type */ - /// Defines the strategy for reading / writing linear or circular buffers - /// - /// `modulo` should be zero if this definition defines a transfer from linear - /// memory or a peripheral. `modulo` will be non-zero when defining a transfer - /// from a circular buffer. The non-zero value is the number of high bits to freeze - /// when performing address offsets (see `offset`). Given that we're only supporting - /// power-of-two buffer sizes, `modulo` will be `31 - clz(cap * sizeof(E))`, where `cap` is the - /// total size of the circular buffer, `clz` is "count leading zeros," and `sizeof(E)` is - /// the size of the element, in bytes. - modulo: u16, - - /// Perform any last-address adjustments when we complete the transfer - /// - /// Once we complete moving data from a linear buffer, we should set our pointer back to the - /// initial address. For this case, `last_address_adjustment` should be a negative number that - /// describes how may *bytes* to move backwards from our current address to reach our starting - /// address. Alternatively, it could describe how to move to a completely new address, like - /// a nearby buffer that we're using for a double-buffer. Or, set it to zero, which means "keep - /// your current position." "Keep your current position" is important when working with a - /// peripheral address! - last_address_adjustment: i32, -} - -impl Transfer { - fn hardware(address: *const E) -> Self { - Transfer { - address, - // Don't move the address pointer - offset: 0, - // We're not a circular buffer - modulo: 0, - // Don't move the address pointer - last_address_adjustment: 0, - } - } -} - -// It's OK to send a channel across an execution context. -// They can't be cloned or copied, so there's no chance of -// them being (mutably) shared. -unsafe impl Send for Channel {} diff --git a/imxrt-hal/src/dma/peripheral.rs b/imxrt-hal/src/dma/peripheral.rs index 9066275e..f2c33182 100644 --- a/imxrt-hal/src/dma/peripheral.rs +++ b/imxrt-hal/src/dma/peripheral.rs @@ -15,9 +15,100 @@ //! See the [Rust API guidelines on future-proofing](https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed) //! to learn about the 'Sealed' pattern. Use the UART peripheral as an example. -use super::{buffer, Channel, Circular, Element, Error, ReadHalf, Transfer, WriteHalf}; +use super::{ + buffer, Channel, Circular, Element, Error, ErrorStatus, ReadHalf, Transfer, WriteHalf, +}; use core::sync::atomic::{compiler_fence, Ordering}; -pub use imxrt_dma::{Destination, Source}; + +/// Describes a peripheral that can be the source of DMA data +/// +/// By 'source,' we mean that it provides data for a DMA transfer. +/// A 'source,' would be a hardware device sending data into our +/// memory. +/// +/// This trait may only be implemented by HAL authors. Users will find +/// that [HAL peripherals already implement `Source`](trait.Source.html#implementors). +pub trait Source: private::Sealed { + type Error; + /// Peripheral source request signal + /// + /// See Table 4-3 of the reference manual. A source probably + /// has something like 'receive' in the name. + const SOURCE_REQUEST_SIGNAL: u32; + /// Returns a pointer to the register from which the DMA channel + /// reads data + /// + /// This is the register that software reads to acquire data from + /// a device. The type of the pointer describes the type of reads + /// the DMA channel performs when transferring data. + /// + /// This memory is assumed to be static. + fn source(&self) -> *const E; + /// Perform any actions necessary to enable DMA transfers + /// + /// Callers use this method to put the peripheral in a state where + /// it can supply the DMA channel with data. + fn enable_source(&mut self) -> Result<(), Self::Error>; + /// Perform any actions necessary to disable or cancel DMA transfers + /// + /// This may include undoing the actions in `enable_source()`. + fn disable_source(&mut self); +} + +/// Describes a peripheral that can be the destination for DMA data +/// +/// By 'destination,' we mean that it receives data from a DMA transfer. +/// Software is sending data from memory to a device using DMA. +/// +/// The trait may only be implemented by HAL authors. Users will find +/// that [HAL peripherals already implement `Destination`](trait.Destination.html#implementors). +pub trait Destination: private::Sealed { + type Error; + /// Peripheral destination request signal + /// + /// See Table 4-3 of the reference manual. A destination probably + /// has something like 'transfer' in the name. + const DESTINATION_REQUEST_SIGNAL: u32; + /// Returns a pointer to the register into which the DMA channel + /// writes data + /// + /// This is the register that software writes to when sending data to a + /// device. The type of the pointer describes the type of reads the + /// DMA channel performs when transferring data. + fn destination(&self) -> *const E; + /// Perform any actions necessary to enable DMA transfers + /// + /// Callers use this method to put the peripheral into a state where + /// it can accept transfers from a DMA channel. + fn enable_destination(&mut self) -> Result<(), Self::Error>; + /// Perform any actions necessary to disable or cancel DMA transfers + /// + /// This may include undoing the actions in `enable_destination()`. + fn disable_destination(&mut self); +} + +/// Preventing crate users from implementing `Source` and `Destination` +/// for arbitrary types. +mod private { + pub trait Sealed {} + + use crate::uart; + impl Sealed for uart::UART where M: crate::iomuxc::consts::Unsigned {} + impl Sealed for uart::Rx where M: crate::iomuxc::consts::Unsigned {} + impl Sealed for uart::Tx where M: crate::iomuxc::consts::Unsigned {} + + use crate::adc; + impl Sealed for adc::AdcSource {} + + use crate::spi; + impl Sealed for spi::SPI where M: crate::iomuxc::consts::Unsigned {} +} + +impl

From

for Error

{ + fn from(error: P) -> Self { + Error::Peripheral(error) + } +} /// A DMA-capable peripheral /// @@ -74,12 +165,12 @@ where } fn init_receive(&mut self, mut channel: Channel) { - channel.set_trigger_from_hardware(Some(self.peripheral.source_signal())); + channel.set_trigger_from_hardware(Some(P::SOURCE_REQUEST_SIGNAL)); // Safety: Source trait is only implemented on peripherals within // this crate. We may study those implementations to show that the // pointers point to valid memory. unsafe { - channel.set_source_transfer(&Transfer::hardware(self.peripheral.source())); + channel.set_source_transfer(Transfer::hardware(self.peripheral.source())); } channel.set_disable_on_completion(true); self.rx_channel = Some(channel); @@ -88,28 +179,28 @@ where /// Start a DMA transfer that transfers data from the peripheral into the supplied buffer /// /// A complete transfer is signaled by `is_receive_complete()`, and possibly an interrupt. - pub fn start_receive(&mut self, mut buffer: D) -> Result<(), (D, Error)> { + pub fn start_receive(&mut self, mut buffer: D) -> Result<(), (D, Error)> { let rx_channel = self.rx_channel.as_mut().unwrap(); if rx_channel.is_enabled() { return Err((buffer, Error::ScheduledTransfer)); + } else if let Err(error) = self.peripheral.enable_source() { + return Err((buffer, Error::Peripheral(error))); } - self.peripheral.enable_source(); + let dst = buffer.destination(); unsafe { - rx_channel.set_destination_transfer(&dst); + rx_channel.set_destination_transfer(dst); } rx_channel.set_minor_loop_elements::(1); - rx_channel.set_transfer_iterations(buffer.destination_len() as u16); + rx_channel.set_transfer_iterations(dst.len() as u16); buffer.prepare_destination(); compiler_fence(Ordering::Release); - unsafe { - rx_channel.enable(); - } + rx_channel.set_enable(true); if rx_channel.is_error() { - let es = rx_channel.error_status(); + let es = ErrorStatus::new(rx_channel.error_status()); rx_channel.clear_error(); Err((buffer, Error::Setup(es))) } else { @@ -159,7 +250,7 @@ where #[allow(deprecated)] core::sync::atomic::spin_loop_hint(); } - rx_channel.disable(); + rx_channel.set_enable(false); compiler_fence(Ordering::Acquire); self.destination_buffer.take() } @@ -214,12 +305,12 @@ where } fn init_transfer(&mut self, mut channel: Channel) { - channel.set_trigger_from_hardware(Some(self.peripheral.destination_signal())); + channel.set_trigger_from_hardware(Some(P::DESTINATION_REQUEST_SIGNAL)); // Safety: Destination trait is only implemented on peripherals within // this crate. We may study those implementations to show that the pointers // point to valid memory. unsafe { - channel.set_destination_transfer(&Transfer::hardware(self.peripheral.destination())); + channel.set_destination_transfer(Transfer::hardware(self.peripheral.destination())); } channel.set_disable_on_completion(true); self.tx_channel = Some(channel); @@ -228,28 +319,28 @@ where /// Start a DMA transfer that transfers data from the supplied buffer to the peripheral /// /// A complete transfer is signaled by `is_transfer_complete()`, and possibly an interrupt. - pub fn start_transfer(&mut self, mut buffer: S) -> Result<(), (S, Error)> { + pub fn start_transfer(&mut self, mut buffer: S) -> Result<(), (S, Error)> { let tx_channel = self.tx_channel.as_mut().unwrap(); if tx_channel.is_enabled() { return Err((buffer, Error::ScheduledTransfer)); + } else if let Err(error) = self.peripheral.enable_destination() { + return Err((buffer, Error::Peripheral(error))); } - self.peripheral.enable_destination(); + let src = buffer.source(); unsafe { - tx_channel.set_source_transfer(&src); + tx_channel.set_source_transfer(src); } tx_channel.set_minor_loop_elements::(1); - tx_channel.set_transfer_iterations(buffer.source_len() as u16); + tx_channel.set_transfer_iterations(src.len() as u16); buffer.prepare_source(); compiler_fence(Ordering::Release); - unsafe { - tx_channel.enable(); - } + tx_channel.set_enable(true); if tx_channel.is_error() { - let es = tx_channel.error_status(); + let es = ErrorStatus::new(tx_channel.error_status()); tx_channel.clear_error(); Err((buffer, Error::Setup(es))) } else { @@ -299,7 +390,7 @@ where #[allow(deprecated)] core::sync::atomic::spin_loop_hint(); } - tx_channel.disable(); + tx_channel.set_enable(false); compiler_fence(Ordering::Acquire); self.source_buffer.take() } @@ -421,7 +512,7 @@ pub mod helpers { rx: Channel, ) -> Peripheral where - P: Source + Destination, + P: Source>::Error> + Destination, S: buffer::Source, D: buffer::Destination, { @@ -436,7 +527,7 @@ pub mod helpers { rx: Channel, ) -> Peripheral where - P: Source + Destination, + P: Source>::Error> + Destination, S: buffer::Source, D: buffer::Destination, { diff --git a/imxrt-hal/src/gpio.rs b/imxrt-hal/src/gpio.rs index d0f2baef..be77d487 100644 --- a/imxrt-hal/src/gpio.rs +++ b/imxrt-hal/src/gpio.rs @@ -10,9 +10,9 @@ //! # Example //! //! ```no_run -//! use imxrt1060_hal::{self, gpio::GPIO}; +//! use imxrt_hal::{self, gpio::GPIO}; //! -//! let mut peripherals = imxrt1060_hal::Peripherals::take().unwrap(); +//! let mut peripherals = imxrt_hal::Peripherals::take().unwrap(); //! let input = GPIO::new(peripherals.iomuxc.ad_b0.p11); //! //! assert!(!input.is_set()); @@ -60,10 +60,10 @@ //! invokes a user's callback when input pin detects a rising edge. //! //! ```no_run -//! use imxrt1060_hal as hal; +//! use imxrt_hal as hal; //! use hal::{ //! gpio::{GPIO, Input, InterruptConfiguration}, -//! iomuxc::imxrt1060::b0::B0_10, +//! iomuxc::imxrt106x::b0::B0_10, //! }; //! use cortex_m::interrupt::Mutex; //! use core::cell::RefCell; diff --git a/imxrt-hal/src/lib.rs b/imxrt-hal/src/lib.rs index 7445956f..ad8ceed5 100644 --- a/imxrt-hal/src/lib.rs +++ b/imxrt-hal/src/lib.rs @@ -1,7 +1,7 @@ //! NXP iMXRT hardware abstraction layer //! //! An [`embedded-hal`](https://crates.io/crates/embedded-hal) implementation -//! targeting processors in NXP's IMXRT1060 family. +//! targeting processors in NXP's IMXRT106x family. //! //! See the module-level documentation for more information and examples. @@ -15,9 +15,11 @@ pub use imxrt_ral as ral; /// See the `imxrt_iomuxc` crate documentation for more information on this module. /// This module re-exports that crate, along with a chip-specific IOMUXC crate. pub mod iomuxc { - pub use imxrt_iomuxc::imxrt106x::*; pub use imxrt_iomuxc::*; + #[cfg(any(feature = "imxrt1061", feature = "imxrt1062", feature = "imxrt1064",))] + pub use imxrt_iomuxc::imxrt106x::*; + /// Use this function to acquire the IOMUXC pads. It requires that you have an /// instance to the RAL's IOMUXC instance. pub(super) fn pads(_: crate::ral::iomuxc::Instance) -> Pads { @@ -36,6 +38,8 @@ pub mod pit; pub mod pwm; pub mod spi; pub mod srtc; +#[cfg(any(feature = "imxrt1061", feature = "imxrt1062", feature = "imxrt1064"))] +pub mod tempmon; pub mod trng; pub mod uart; @@ -67,6 +71,8 @@ pub struct Peripherals { pub gpt2: gpt::Unclocked, pub dma: dma::Unclocked, pub srtc: srtc::Unclocked, + #[cfg(any(feature = "imxrt1061", feature = "imxrt1062", feature = "imxrt1064"))] + pub tempmon: tempmon::Uninitialized, pub trng: trng::Unclocked, } @@ -122,6 +128,8 @@ impl Peripherals { gpt2: gpt::Unclocked::two(ral::gpt::GPT2::steal()), dma: dma::Unclocked::new(ral::dma0::DMA0::steal(), ral::dmamux::DMAMUX::steal()), srtc: srtc::Unclocked::new(ral::snvs::SNVS::steal()), + #[cfg(any(feature = "imxrt1061", feature = "imxrt1062", feature = "imxrt1064"))] + tempmon: tempmon::Uninitialized::new(ral::tempmon::TEMPMON::steal()), trng: trng::Unclocked::new(ral::trng::TRNG::steal()), } } @@ -174,6 +182,8 @@ impl Peripherals { gpt2: gpt::Unclocked::two(ral::gpt::GPT2::take()?), dma: dma::Unclocked::new(ral::dma0::DMA0::take()?, ral::dmamux::DMAMUX::take()?), srtc: srtc::Unclocked::new(ral::snvs::SNVS::take()?), + #[cfg(any(feature = "imxrt1061", feature = "imxrt1062", feature = "imxrt1064"))] + tempmon: tempmon::Uninitialized::new(ral::tempmon::TEMPMON::take()?), trng: trng::Unclocked::new(ral::trng::TRNG::take()?), }; Some(p) diff --git a/imxrt-hal/src/srtc.rs b/imxrt-hal/src/srtc.rs index cdd6364e..00b4dc93 100644 --- a/imxrt-hal/src/srtc.rs +++ b/imxrt-hal/src/srtc.rs @@ -10,9 +10,9 @@ //! # Example //! //! ```no_run -//! use imxrt1060_hal; +//! use imxrt_hal; //! -//! let mut peripherals = imxrt1060_hal::Peripherals::take().unwrap(); +//! let mut peripherals = imxrt_hal::Peripherals::take().unwrap(); //! //! let mut srtc = peripherals.srtc.enable_and_set(&mut peripherals.ccm.handle, 1600000000, 0); //! // Interpreted as Unix time: Sep 13 2020 12:26:40.000 diff --git a/imxrt-hal/src/tempmon.rs b/imxrt-hal/src/tempmon.rs new file mode 100644 index 00000000..300b5dbb --- /dev/null +++ b/imxrt-hal/src/tempmon.rs @@ -0,0 +1,395 @@ +//! # Temperature Monitor (TEMPMON) +//! +//! ## IMPORTANT NOTE: +//! The temperature sensor uses and assumes that the bandgap +//! reference, 480MHz PLL and 32KHz RTC modules are properly programmed and fully +//! settled for correct operation. +//! +//! +//! ## Example 1 +//! +//! Manually triggered read +//! +//! ```no_run +//! use imxrt_hal; +//! +//! let mut peripherals = imxrt_hal::Peripherals::take().unwrap(); +//! +//! let (_, ipg_hz) = peripherals.ccm.pll1.set_arm_clock( +//! imxrt_hal::ccm::PLL1::ARM_HZ, +//! &mut peripherals.ccm.handle, +//! &mut peripherals.dcdc, +//! ); +//! +//! let mut cfg = peripherals.ccm.perclk.configure( +//! &mut peripherals.ccm.handle, +//! imxrt_hal::ccm::perclk::PODF::DIVIDE_3, +//! imxrt_hal::ccm::perclk::CLKSEL::IPG(ipg_hz), +//! ); +//! +//! // Init temperature monitor +//! let mut temp_mon = peripherals.tempmon.init(); +//! loop { +//! if let Ok(temperature) = nb::block!(temp_mon.measure_temp()) { +//! // Temperature in mC (1°C = 1000°mC) +//! } +//! } +//! ``` +//! +//! ## Example 2 +//! +//! Non-blocking reading +//! +//! ```no_run +//! use imxrt_hal::{self, tempmon::TempMon}; +//! +//! # let mut peripherals = imxrt_hal::Peripherals::take().unwrap(); +//! # let (_, ipg_hz) = peripherals.ccm.pll1.set_arm_clock( +//! # imxrt_hal::ccm::PLL1::ARM_HZ, +//! # &mut peripherals.ccm.handle, +//! # &mut peripherals.dcdc, +//! # ); +//! # let mut cfg = peripherals.ccm.perclk.configure( +//! # &mut peripherals.ccm.handle, +//! # imxrt_hal::ccm::perclk::PODF::DIVIDE_3, +//! # imxrt_hal::ccm::perclk::CLKSEL::IPG(ipg_hz), +//! # ); +//! +//! // Init temperature monitor with 8Hz measure freq +//! // 0xffff = 2 Sec. Read more at `measure_freq()` +//! let mut temp_mon = peripherals.tempmon.init_with_measure_freq(0x1000); +//! temp_mon.start(); +//! +//! let mut last_temp = 0_i32; +//! loop { +//! // Get the last temperature read by the measure_freq +//! if let Ok(temp) = temp_mon.get_temp() { +//! if last_temp != temp { +//! // Temperature changed +//! last_temp = temp; +//! } +//! // Do something else +//! } +//! } +//! ``` +//! +//! ## Example 3 +//! +//! Low and high temperature Interrupt +//! +//! *NOTE*: TEMP_LOW_HIGH is triggered for `TempSensor low` and `TempSensor high` +//! +//! ```no_run +//! use imxrt_hal::{self, tempmon::TempMon}; +//! use imxrt_hal::ral::interrupt; +//! +//! # let mut peripherals = imxrt_hal::Peripherals::take().unwrap(); +//! # let (_, ipg_hz) = peripherals.ccm.pll1.set_arm_clock( +//! # imxrt_hal::ccm::PLL1::ARM_HZ, +//! # &mut peripherals.ccm.handle, +//! # &mut peripherals.dcdc, +//! # ); +//! # let mut cfg = peripherals.ccm.perclk.configure( +//! # &mut peripherals.ccm.handle, +//! # imxrt_hal::ccm::perclk::PODF::DIVIDE_3, +//! # imxrt_hal::ccm::perclk::CLKSEL::IPG(ipg_hz), +//! # ); +//! +//! // Init temperature monitor with 8Hz measure freq +//! // 0xffff = 2 Sec. Read more at `measure_freq()` +//! let mut temp_mon = peripherals.tempmon.init_with_measure_freq(0x1000); +//! +//! // Set low_alarm, high_alarm, and panic_alarm temperature +//! temp_mon.set_alarm_values(-5_000, 65_000, 95_000); +//! +//! // Use values from registers if you like to compare it somewhere +//! let (low_alarm, high_alarm, panic_alarm) = temp_mon.alarm_values(); +//! +//! // Enables interrupts for low_high_alarm +//! unsafe { +//! cortex_m::peripheral::NVIC::unmask(interrupt::TEMP_LOW_HIGH); +//! } +//! +//! // Start could fail if the module is not powered up +//! if temp_mon.start().is_err() { +//! temp_mon.power_up(); +//! temp_mon.start(); +//! } +//! +//! #[cortex_m_rt::interrupt] +//! fn TEMP_LOW_HIGH() { +//! // disable the interrupt to avoid endless triggers +//! cortex_m::peripheral::NVIC::mask(interrupt::TEMP_LOW_HIGH); +//! +//! // don't forget to enable it after the temperature is back to normal +//! } +//! ``` + +use crate::ral; + +/// Indicates that the temperature monitor is powered down. +/// +/// If you receive this error, `power_up()` the temperature monitor first, +/// and try again. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PowerDownError(()); + +/// An Uninitialized temperature monitor module +/// +/// # Important note: +/// +/// The temperature sensor uses and assumes that the bandgap +/// reference, 480MHz PLL and 32KHz RTC modules are properly +/// programmed and fully settled for correct operation. +pub struct Uninitialized(ral::tempmon::Instance); + +impl Uninitialized { + /// assign the tempmon Instance to this temperature monitor wrapper. + pub fn new(base: ral::tempmon::Instance) -> Self { + Self(base) + } + + /// Initialize the temperature monitor. + pub fn init(self) -> TempMon { + // this operation is safe. This value is read-only and set by the manufacturer. + let calibration = unsafe { ral::read_reg!(ral::ocotp, OCOTP, ANA1) }; + + // The ral doesn't provide direct access to the values. + let n1_room_count = (calibration >> 20) as i32; + let t1_room_temp = 25_000_i32; + let n2_hot_count = ((calibration >> 8) & 0xFFF) as i32; + let t2_hot_temp = (calibration & 0xFF) as i32 * 1_000; + + // Tmeas = HOT_TEMP - (Nmeas - HOT_COUNT) * ((HOT_TEMP - 25.0) / (ROOM_COUNT – HOT_COUNT)) + let scaler = (t2_hot_temp - t1_room_temp) / (n1_room_count - n2_hot_count); + // Tmeas = HOT_TEMP - (Nmeas - HOT_COUNT) * scaler + + let mut t = TempMon { + base: self.0, + scaler, + hot_count: n2_hot_count, + hot_temp: t2_hot_temp, + }; + t.power_up(); + t + } + + /// Initialize the temperature monitor. + /// + /// The `measure_freq` determines how many RTC clocks to wait before automatically repeating a temperature + /// measurement. The pause time before remeasuring is the field value multiplied by the RTC period. + /// + /// Find more details `TempMon.set_measure_frequency` + pub fn init_with_measure_freq(self, measure_freq: u16) -> TempMon { + let mut t = self.init(); + t.set_measure_frequency(measure_freq); + t + } +} + +/// A Temperature Monitor (TEMPMON) +/// +/// # Example +/// +/// ```no_run +/// use imxrt_hal; +/// +/// let mut peripherals = imxrt_hal::Peripherals::take().unwrap(); +/// let (_, ipg_hz) = peripherals.ccm.pll1.set_arm_clock( +/// imxrt_hal::ccm::PLL1::ARM_HZ, +/// &mut peripherals.ccm.handle, +/// &mut peripherals.dcdc, +/// ); +/// let mut cfg = peripherals.ccm.perclk.configure( +/// &mut peripherals.ccm.handle, +/// imxrt_hal::ccm::perclk::PODF::DIVIDE_3, +/// imxrt_hal::ccm::perclk::CLKSEL::IPG(ipg_hz), +/// ); +/// +/// // init temperature monitor +/// // consider using init_with_measure_freq +/// let mut temp_mon = peripherals.tempmon.init(); +/// loop { +/// if let Ok(_temperature) = nb::block!(temp_mon.measure_temp()) { +/// // _temperature in mC (1°C = 1000°mC) +/// } +/// } +/// ``` +pub struct TempMon { + base: ral::tempmon::Instance, + /// Scaler + scaler: i32, + /// Hot_count + hot_count: i32, + /// Hot_temp * 1000 + hot_temp: i32, +} + +impl TempMon { + /// Converts the temp_cnt into a human readable temperature [°mC] (1/1000 °C) + /// + /// param **temp_cnt**: measurement value from the tempmon module + /// + /// return: Temperature in °mC (1/1000°C) + fn convert(&self, temp_cnt: i32) -> i32 { + let n_meas = temp_cnt - self.hot_count; + self.hot_temp - n_meas * self.scaler + } + + /// Decode the temp_value into measurable bytes + /// + /// param **temp_value_mc**: temperature value in °mC (1/1000°C) + /// + /// return: decoded temperature, compatible to the module internal measurements + fn decode(&self, temp_value_mc: i32) -> u32 { + let v = (temp_value_mc - self.hot_temp) / self.scaler; + (self.hot_count - v) as u32 + } + + /// Triggers a new measurement + /// + /// If you configured automatically repeating, this will trigger additional measurement. + /// Use get_temp instate to get the last read value + /// + /// The returning temperature in 1/1000 Celsius (°mC) + /// + /// Example: 25500°mC -> 25.5°C + pub fn measure_temp(&mut self) -> nb::Result { + if !self.is_powered_up() { + Err(nb::Error::from(PowerDownError(()))) + } else { + // If no measurement is active, trigger new measurement + let active = ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, MEASURE_TEMP == START); + if !active { + ral::write_reg!(ral::tempmon, self.base, TEMPSENSE0_SET, MEASURE_TEMP: START); + } + + // If the measurement is not finished or not started + // i.MX Docs: This bit should be cleared by the sensor after the start of each measurement + if ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, FINISHED == INVALID) { + // measure_temp could be triggered again without any effect + Err(nb::Error::WouldBlock) + } else { + // Clear MEASURE_TEMP to trigger a new measurement at the next call + ral::write_reg!(ral::tempmon, self.base, TEMPSENSE0_CLR, MEASURE_TEMP: START); + + let temp_cnt = ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, TEMP_CNT) as i32; + Ok(self.convert(temp_cnt)) + } + } + } + + /// Returns the last read value from the temperature sensor + /// + /// The returning temperature in 1/1000 Celsius (°mC) + /// + /// Example: 25500°mC -> 25.5°C + pub fn get_temp(&self) -> nb::Result { + if self.is_powered_up() { + let temp_cnt = ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, TEMP_CNT) as i32; + Ok(self.convert(temp_cnt)) + } else { + Err(nb::Error::from(PowerDownError(()))) + } + } + + /// Starts the measurement process. If the measurement frequency is zero, this + /// results in a single conversion. + pub fn start(&mut self) -> nb::Result<(), PowerDownError> { + if self.is_powered_up() { + ral::write_reg!(ral::tempmon, self.base, TEMPSENSE0_SET, MEASURE_TEMP: START); + Ok(()) + } else { + Err(nb::Error::from(PowerDownError(()))) + } + } + + /// Stops the measurement process. This only has an effect If the measurement + /// frequency is not zero. + pub fn stop(&mut self) { + ral::write_reg!(ral::tempmon, self.base, TEMPSENSE0_CLR, MEASURE_TEMP: START); + } + + /// Returns the true if the tempmon module is powered up. + pub fn is_powered_up(&self) -> bool { + ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, POWER_DOWN == POWER_UP) + } + + /// This powers down the temperature sensor. + pub fn power_down(&mut self) { + ral::write_reg!( + ral::tempmon, + self.base, + TEMPSENSE0_SET, + POWER_DOWN: POWER_DOWN + ); + } + + /// This powers up the temperature sensor. + pub fn power_up(&mut self) { + ral::write_reg!( + ral::tempmon, + self.base, + TEMPSENSE0_CLR, + POWER_DOWN: POWER_DOWN + ); + } + + /// Set the temperature that will generate a low alarm, high alarm, and panic alarm interrupt + /// when the temperature exceeded this values. + /// + /// ## Note: + /// low_alarm_mc, high_alarm_mc, and panic_alarm_mc are in milli Celsius (1/1000 °C) + pub fn set_alarm_values(&mut self, low_alarm_mc: i32, high_alarm_mc: i32, panic_alarm_mc: i32) { + let low_alarm = self.decode(low_alarm_mc); + let high_alarm = self.decode(high_alarm_mc); + let panic_alarm = self.decode(panic_alarm_mc); + ral::modify_reg!(ral::tempmon, self.base, TEMPSENSE0, ALARM_VALUE: high_alarm); + ral::write_reg!( + ral::tempmon, + self.base, + TEMPSENSE2, + LOW_ALARM_VALUE: low_alarm, + PANIC_ALARM_VALUE: panic_alarm + ); + } + + /// Queries the temperature that will generate a low alarm, high alarm, and panic alarm interrupt. + /// + /// Returns (low_alarm_temp, high_alarm_temp, panic_alarm_temp) + pub fn alarm_values(&self) -> (i32, i32, i32) { + let high_alarm = ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, ALARM_VALUE); + let (low_alarm, panic_alarm) = ral::read_reg!( + ral::tempmon, + self.base, + TEMPSENSE2, + LOW_ALARM_VALUE, + PANIC_ALARM_VALUE + ); + ( + self.convert(low_alarm as i32), + self.convert(high_alarm as i32), + self.convert(panic_alarm as i32), + ) + } + + /// This bits determines how many RTC clocks to wait before automatically repeating a temperature + /// measurement. The pause time before remeasuring is the field value multiplied by the RTC period. + /// + /// | value | note | + /// | ------ | ----------------------------------------------------- | + /// | 0x0000 | Defines a single measurement with no repeat. | + /// | 0x0001 | Updates the temperature value at a RTC clock rate. | + /// | 0x0002 | Updates the temperature value at a RTC/2 clock rate. | + /// | ... | ... | + /// | 0xFFFF | Determines a two second sample period with a 32.768KHz RTC clock. Exact timings depend on the accuracy of the RTC clock.| + /// + pub fn set_measure_frequency(&mut self, measure_freq: u16) { + ral::modify_reg!( + ral::tempmon, + self.base, + TEMPSENSE1, + MEASURE_FREQ: measure_freq as u32 + ); + } +} diff --git a/imxrt-hal/src/trng.rs b/imxrt-hal/src/trng.rs index 7cbbe2af..65c44001 100644 --- a/imxrt-hal/src/trng.rs +++ b/imxrt-hal/src/trng.rs @@ -30,19 +30,6 @@ //! [rand_core]: https://crates.io/crates/rand_core //! [rand]: https://crates.io/crates/rand //! [nfr]: https://github.com/rust-lang/cargo/issues/7916 -//! -//! # Example -//! -//! ```no_run -//! use imxrt1060_hal as hal; -//! -//! let mut peripherals = hal::Peripherals::take().unwrap(); -//! peripherals.trng.set_sample_mode(hal::trng::SampleMode::VonNeumannRaw); -//! peripherals.trng.set_retry_count(10).unwrap(); -//! -//! let mut trng = peripherals.trng.clock(&mut peripherals.ccm.handle); -//! let random_data = trng.next_u32().unwrap(); -//! ``` use core::fmt;