aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-05-09 12:39:11 +0200
committerGitHub <[email protected]>2025-05-09 12:39:11 +0200
commit4dbaa018703f0362d1d20de30817f80d1dbdea35 (patch)
tree30bcd47701931dea52a27ac47414817da494303a
parent8b80195843b6f67eed8dcf6ecb21873ed3aaa6d4 (diff)
parent42c62ba8999df08ad34d566f30f0a7199dbae083 (diff)
Merge pull request #4175 from felipebalbi/imxrt-rtos-timer
iMXRT OS timer
-rw-r--r--embassy-imxrt/Cargo.toml9
-rw-r--r--embassy-imxrt/src/clocks.rs72
-rw-r--r--embassy-imxrt/src/lib.rs8
-rw-r--r--embassy-imxrt/src/time_driver.rs (renamed from embassy-imxrt/src/rtc.rs)196
-rw-r--r--examples/mimxrt6/Cargo.toml4
5 files changed, 209 insertions, 80 deletions
diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml
index d58de6353..f16002a8d 100644
--- a/embassy-imxrt/Cargo.toml
+++ b/embassy-imxrt/Cargo.toml
@@ -12,7 +12,7 @@ documentation = "https://docs.embassy.dev/embassy-imxrt"
12[package.metadata.embassy_docs] 12[package.metadata.embassy_docs]
13src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/" 13src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/"
14src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/" 14src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/"
15features = ["defmt", "unstable-pac", "time", "time-driver"] 15features = ["defmt", "unstable-pac", "time", "time-driver-os-timer"]
16flavors = [ 16flavors = [
17 { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" } 17 { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" }
18] 18]
@@ -37,9 +37,12 @@ defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "mimxr
37time = ["dep:embassy-time", "embassy-embedded-hal/time"] 37time = ["dep:embassy-time", "embassy-embedded-hal/time"]
38 38
39## Enable custom embassy time-driver implementation, using 32KHz RTC 39## Enable custom embassy time-driver implementation, using 32KHz RTC
40time-driver-rtc = ["_time-driver"] 40time-driver-rtc = ["_time-driver", "embassy-time-driver?/tick-hz-1_000"]
41 41
42_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] 42## Enable custom embassy time-driver implementation, using 1MHz OS Timer
43time-driver-os-timer = ["_time-driver", "embassy-time-driver?/tick-hz-1_000_000"]
44
45_time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"]
43 46
44## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable) 47## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable)
45unstable-pac = [] 48unstable-pac = []
diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs
index 1d36fb142..39c3e6238 100644
--- a/embassy-imxrt/src/clocks.rs
+++ b/embassy-imxrt/src/clocks.rs
@@ -1,8 +1,6 @@
1//! Clock configuration for the `RT6xx` 1//! Clock configuration for the `RT6xx`
2use core::sync::atomic::{AtomicU32, AtomicU8, Ordering}; 2use core::sync::atomic::{AtomicU32, AtomicU8, Ordering};
3 3
4#[cfg(feature = "defmt")]
5use defmt;
6use paste::paste; 4use paste::paste;
7 5
8use crate::pac; 6use crate::pac;
@@ -503,7 +501,6 @@ impl ConfigurableClock for LposcConfig {
503 } 501 }
504 } 502 }
505 } else { 503 } else {
506 error!("failed to convert desired clock rate, {:#}, to LPOSC Freq", freq);
507 Err(ClockError::InvalidFrequency) 504 Err(ClockError::InvalidFrequency)
508 } 505 }
509 } 506 }
@@ -549,7 +546,6 @@ impl ConfigurableClock for FfroConfig {
549 Ok(()) 546 Ok(())
550 } 547 }
551 fn get_clock_rate(&self) -> Result<u32, ClockError> { 548 fn get_clock_rate(&self) -> Result<u32, ClockError> {
552 trace!("getting ffro clock rate");
553 Ok(self.freq.load(Ordering::Relaxed)) 549 Ok(self.freq.load(Ordering::Relaxed))
554 } 550 }
555 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { 551 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
@@ -616,7 +612,6 @@ impl ConfigurableClock for SfroConfig {
616 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { 612 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
617 if self.state == State::Enabled { 613 if self.state == State::Enabled {
618 if freq == SFRO_FREQ { 614 if freq == SFRO_FREQ {
619 trace!("Sfro frequency is already set at 16MHz");
620 Ok(()) 615 Ok(())
621 } else { 616 } else {
622 Err(ClockError::InvalidFrequency) 617 Err(ClockError::InvalidFrequency)
@@ -677,7 +672,6 @@ impl MultiSourceClock for MainPllClkConfig {
677 } 672 }
678 MainPllClkSrc::SFRO => { 673 MainPllClkSrc::SFRO => {
679 if !clock_src_config.is_enabled() { 674 if !clock_src_config.is_enabled() {
680 error!("Can't set SFRO as source for MainPll as it's not enabled");
681 return Err(ClockError::ClockNotEnabled); 675 return Err(ClockError::ClockNotEnabled);
682 } 676 }
683 // check if desired frequency is a valid multiple of 16m SFRO clock 677 // check if desired frequency is a valid multiple of 16m SFRO clock
@@ -703,7 +697,6 @@ impl ConfigurableClock for MainPllClkConfig {
703 } 697 }
704 fn disable(&self) -> Result<(), ClockError> { 698 fn disable(&self) -> Result<(), ClockError> {
705 if self.is_enabled() { 699 if self.is_enabled() {
706 error!("Attempting to reset the Main Pll Clock, should be resetting its source");
707 Err(ClockError::ClockNotSupported) 700 Err(ClockError::ClockNotSupported)
708 } else { 701 } else {
709 Err(ClockError::ClockNotEnabled) 702 Err(ClockError::ClockNotEnabled)
@@ -719,7 +712,6 @@ impl ConfigurableClock for MainPllClkConfig {
719 } 712 }
720 fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError> { 713 fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError> {
721 if self.is_enabled() { 714 if self.is_enabled() {
722 trace!("attempting to set main pll clock rate");
723 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0 715 // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0
724 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; 716 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() };
725 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; 717 let sysctl0 = unsafe { crate::pac::Sysctl0::steal() };
@@ -741,15 +733,12 @@ impl ConfigurableClock for MainPllClkConfig {
741 base_rate = r; 733 base_rate = r;
742 } 734 }
743 MainPllClkSrc::FFRO => { 735 MainPllClkSrc::FFRO => {
744 trace!("found FFRO as source, wait a bit");
745 delay_loop_clocks(1000, desired_freq); 736 delay_loop_clocks(1000, desired_freq);
746 match clkctl0.ffroctl0().read().trim_range().is_ffro_48mhz() { 737 match clkctl0.ffroctl0().read().trim_range().is_ffro_48mhz() {
747 true => base_rate = Into::into(FfroFreq::Ffro48m), 738 true => base_rate = Into::into(FfroFreq::Ffro48m),
748 false => base_rate = Into::into(FfroFreq::Ffro60m), 739 false => base_rate = Into::into(FfroFreq::Ffro60m),
749 } 740 }
750 trace!("found ffro rate to be: {:#}", base_rate);
751 if div == 2 { 741 if div == 2 {
752 trace!("dividing FFRO rate by 2");
753 clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2()); 742 clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2());
754 delay_loop_clocks(150, desired_freq); 743 delay_loop_clocks(150, desired_freq);
755 base_rate /= 2; 744 base_rate /= 2;
@@ -763,10 +752,8 @@ impl ConfigurableClock for MainPllClkConfig {
763 } 752 }
764 }; 753 };
765 base_rate *= u32::from(mult); 754 base_rate *= u32::from(mult);
766 trace!("calculated base rate at: {:#}", base_rate);
767 if base_rate != freq { 755 if base_rate != freq {
768 // make sure to power syspll back up before returning the error 756 // make sure to power syspll back up before returning the error
769 error!("invalid frequency found, powering syspll back up before returning error. Check div and mult");
770 // Clear System PLL reset 757 // Clear System PLL reset
771 clkctl0.syspll0ctl0().write(|w| w.reset().normal()); 758 clkctl0.syspll0ctl0().write(|w| w.reset().normal());
772 // Power up SYSPLL 759 // Power up SYSPLL
@@ -775,13 +762,11 @@ impl ConfigurableClock for MainPllClkConfig {
775 .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0()); 762 .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0());
776 return Err(ClockError::InvalidFrequency); 763 return Err(ClockError::InvalidFrequency);
777 } 764 }
778 trace!("setting default num and denom");
779 // SAFETY: unsafe needed to write the bits for the num and demon fields 765 // SAFETY: unsafe needed to write the bits for the num and demon fields
780 clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0b0) }); 766 clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0b0) });
781 clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0b1) }); 767 clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0b1) });
782 delay_loop_clocks(30, desired_freq); 768 delay_loop_clocks(30, desired_freq);
783 self.mult.store(mult, Ordering::Relaxed); 769 self.mult.store(mult, Ordering::Relaxed);
784 trace!("setting self.mult as: {:#}", mult);
785 match mult { 770 match mult {
786 16 => { 771 16 => {
787 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_16()); 772 clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_16());
@@ -803,7 +788,6 @@ impl ConfigurableClock for MainPllClkConfig {
803 } 788 }
804 _ => return Err(ClockError::InvalidMult), 789 _ => return Err(ClockError::InvalidMult),
805 } 790 }
806 trace!("clear syspll reset");
807 // Clear System PLL reset 791 // Clear System PLL reset
808 clkctl0.syspll0ctl0().modify(|_r, w| w.reset().normal()); 792 clkctl0.syspll0ctl0().modify(|_r, w| w.reset().normal());
809 // Power up SYSPLL 793 // Power up SYSPLL
@@ -819,7 +803,6 @@ impl ConfigurableClock for MainPllClkConfig {
819 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable()); 803 clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable());
820 delay_loop_clocks(15, desired_freq); 804 delay_loop_clocks(15, desired_freq);
821 805
822 trace!("setting new PFD0 bits");
823 // gate the output and clear bits. 806 // gate the output and clear bits.
824 // SAFETY: unsafe needed to write the bits for pfd0 807 // SAFETY: unsafe needed to write the bits for pfd0
825 clkctl0 808 clkctl0
@@ -833,7 +816,6 @@ impl ConfigurableClock for MainPllClkConfig {
833 .modify(|_r, w| unsafe { w.pfd0_clkgate().not_gated().pfd0().bits(0x12) }); 816 .modify(|_r, w| unsafe { w.pfd0_clkgate().not_gated().pfd0().bits(0x12) });
834 // wait for ready bit to be set 817 // wait for ready bit to be set
835 delay_loop_clocks(50, desired_freq); 818 delay_loop_clocks(50, desired_freq);
836 trace!("waiting for mainpll clock to be ready");
837 while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {} 819 while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {}
838 // clear by writing a 1 820 // clear by writing a 1
839 clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().set_bit()); 821 clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().set_bit());
@@ -854,11 +836,9 @@ impl ConfigurableClock for MainPllClkConfig {
854impl MainPllClkConfig { 836impl MainPllClkConfig {
855 /// Calculate the mult value of a desired frequency, return error if invalid 837 /// Calculate the mult value of a desired frequency, return error if invalid
856 pub(self) fn calc_mult(rate: u32, base_freq: u32) -> Result<u8, ClockError> { 838 pub(self) fn calc_mult(rate: u32, base_freq: u32) -> Result<u8, ClockError> {
857 trace!("calculating mult for {:#} / {:#}", rate, base_freq);
858 const VALIDMULTS: [u8; 6] = [16, 17, 20, 22, 27, 33]; 839 const VALIDMULTS: [u8; 6] = [16, 17, 20, 22, 27, 33];
859 if rate > base_freq && rate % base_freq == 0 { 840 if rate > base_freq && rate % base_freq == 0 {
860 let mult = (rate / base_freq) as u8; 841 let mult = (rate / base_freq) as u8;
861 trace!("verifying that calculated mult {:#} is a valid one", mult);
862 if VALIDMULTS.into_iter().any(|i| i == mult) { 842 if VALIDMULTS.into_iter().any(|i| i == mult) {
863 Ok(mult) 843 Ok(mult)
864 } else { 844 } else {
@@ -1112,7 +1092,6 @@ impl ConfigurableClock for MainClkConfig {
1112 Ok(()) 1092 Ok(())
1113 } 1093 }
1114 fn disable(&self) -> Result<(), ClockError> { 1094 fn disable(&self) -> Result<(), ClockError> {
1115 error!("Attempting to reset the main clock, should NOT happen during runtime");
1116 Err(ClockError::ClockNotSupported) 1095 Err(ClockError::ClockNotSupported)
1117 } 1096 }
1118 fn get_clock_rate(&self) -> Result<u32, ClockError> { 1097 fn get_clock_rate(&self) -> Result<u32, ClockError> {
@@ -1120,7 +1099,6 @@ impl ConfigurableClock for MainClkConfig {
1120 Ok(rate) 1099 Ok(rate)
1121 } 1100 }
1122 fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> { 1101 fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> {
1123 error!("The multi-source set_clock_rate_and_source method should be used instead of set_clock_rate");
1124 Err(ClockError::ClockNotSupported) 1102 Err(ClockError::ClockNotSupported)
1125 } 1103 }
1126 fn is_enabled(&self) -> bool { 1104 fn is_enabled(&self) -> bool {
@@ -1145,7 +1123,6 @@ impl ConfigurableClock for ClkInConfig {
1145 } 1123 }
1146 } 1124 }
1147 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { 1125 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
1148 trace!("Setting value of clk in config, this won't change the clock itself");
1149 self.freq.as_ref().unwrap().store(freq, Ordering::Relaxed); 1126 self.freq.as_ref().unwrap().store(freq, Ordering::Relaxed);
1150 Ok(()) 1127 Ok(())
1151 } 1128 }
@@ -1188,7 +1165,6 @@ impl ConfigurableClock for RtcClkConfig {
1188 Ok(()) 1165 Ok(())
1189 } 1166 }
1190 fn disable(&self) -> Result<(), ClockError> { 1167 fn disable(&self) -> Result<(), ClockError> {
1191 error!("Resetting the RTC clock, this should NOT happen during runtime");
1192 Err(ClockError::ClockNotSupported) 1168 Err(ClockError::ClockNotSupported)
1193 } 1169 }
1194 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { 1170 fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> {
@@ -1199,7 +1175,6 @@ impl ConfigurableClock for RtcClkConfig {
1199 match r { 1175 match r {
1200 RtcFreq::Default1Hz => { 1176 RtcFreq::Default1Hz => {
1201 if rtc.ctrl().read().rtc_en().is_enable() { 1177 if rtc.ctrl().read().rtc_en().is_enable() {
1202 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1203 } else { 1178 } else {
1204 rtc.ctrl().modify(|_r, w| w.rtc_en().enable()); 1179 rtc.ctrl().modify(|_r, w| w.rtc_en().enable());
1205 } 1180 }
@@ -1207,7 +1182,6 @@ impl ConfigurableClock for RtcClkConfig {
1207 } 1182 }
1208 RtcFreq::HighResolution1khz => { 1183 RtcFreq::HighResolution1khz => {
1209 if rtc.ctrl().read().rtc1khz_en().is_enable() { 1184 if rtc.ctrl().read().rtc1khz_en().is_enable() {
1210 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1211 } else { 1185 } else {
1212 rtc.ctrl().modify(|_r, w| w.rtc1khz_en().enable()); 1186 rtc.ctrl().modify(|_r, w| w.rtc1khz_en().enable());
1213 } 1187 }
@@ -1215,7 +1189,6 @@ impl ConfigurableClock for RtcClkConfig {
1215 } 1189 }
1216 RtcFreq::SubSecond32kHz => { 1190 RtcFreq::SubSecond32kHz => {
1217 if rtc.ctrl().read().rtc_subsec_ena().is_enable() { 1191 if rtc.ctrl().read().rtc_subsec_ena().is_enable() {
1218 trace!("Attempting to enable an already enabled clock, RTC 1Hz");
1219 } else { 1192 } else {
1220 rtc.ctrl().modify(|_r, w| w.rtc_subsec_ena().enable()); 1193 rtc.ctrl().modify(|_r, w| w.rtc_subsec_ena().enable());
1221 } 1194 }
@@ -1245,18 +1218,12 @@ impl ConfigurableClock for RtcClkConfig {
1245 1218
1246impl SysClkConfig { 1219impl SysClkConfig {
1247 /// Updates the system core clock frequency, SW concept used for systick 1220 /// Updates the system core clock frequency, SW concept used for systick
1248 fn update_sys_core_clock(&self) { 1221 fn update_sys_core_clock(&self) {}
1249 trace!(
1250 "System core clock has been updated to {:?}, this involves no HW reg writes",
1251 self.sysclkfreq.load(Ordering::Relaxed)
1252 );
1253 }
1254} 1222}
1255 1223
1256impl ConfigurableClock for SysOscConfig { 1224impl ConfigurableClock for SysOscConfig {
1257 fn enable_and_reset(&self) -> Result<(), ClockError> { 1225 fn enable_and_reset(&self) -> Result<(), ClockError> {
1258 if self.state == State::Enabled { 1226 if self.state == State::Enabled {
1259 trace!("SysOsc was already enabled");
1260 return Ok(()); 1227 return Ok(());
1261 } 1228 }
1262 1229
@@ -1498,32 +1465,26 @@ impl ClockOutConfig {
1498/// Using the config, enables all desired clocks to desired clock rates 1465/// Using the config, enables all desired clocks to desired clock rates
1499fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> { 1466fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> {
1500 if let Err(e) = config.rtc.enable_and_reset() { 1467 if let Err(e) = config.rtc.enable_and_reset() {
1501 error!("couldn't Power on OSC for RTC, result: {:?}", e);
1502 return Err(e); 1468 return Err(e);
1503 } 1469 }
1504 1470
1505 if let Err(e) = config.lposc.enable_and_reset() { 1471 if let Err(e) = config.lposc.enable_and_reset() {
1506 error!("couldn't Power on LPOSC, result: {:?}", e);
1507 return Err(e); 1472 return Err(e);
1508 } 1473 }
1509 1474
1510 if let Err(e) = config.ffro.enable_and_reset() { 1475 if let Err(e) = config.ffro.enable_and_reset() {
1511 error!("couldn't Power on FFRO, result: {:?}", e);
1512 return Err(e); 1476 return Err(e);
1513 } 1477 }
1514 1478
1515 if let Err(e) = config.sfro.enable_and_reset() { 1479 if let Err(e) = config.sfro.enable_and_reset() {
1516 error!("couldn't Power on SFRO, result: {:?}", e);
1517 return Err(e); 1480 return Err(e);
1518 } 1481 }
1519 1482
1520 if let Err(e) = config.sys_osc.enable_and_reset() { 1483 if let Err(e) = config.sys_osc.enable_and_reset() {
1521 error!("Couldn't enable sys oscillator {:?}", e);
1522 return Err(e); 1484 return Err(e);
1523 } 1485 }
1524 1486
1525 if let Err(e) = config.main_pll_clk.enable_and_reset() { 1487 if let Err(e) = config.main_pll_clk.enable_and_reset() {
1526 error!("Couldn't enable main pll clock {:?}", e);
1527 return Err(e); 1488 return Err(e);
1528 } 1489 }
1529 1490
@@ -1542,7 +1503,6 @@ fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> {
1542 init_syscpuahb_clk(); 1503 init_syscpuahb_clk();
1543 1504
1544 if let Err(e) = config.main_clk.enable_and_reset() { 1505 if let Err(e) = config.main_clk.enable_and_reset() {
1545 error!("Couldn't enable main clock {:?}", e);
1546 return Err(e); 1506 return Err(e);
1547 } 1507 }
1548 1508
@@ -1561,7 +1521,8 @@ pub(crate) unsafe fn init(config: ClockConfig) -> Result<(), ClockError> {
1561 1521
1562///Trait to expose perph clocks 1522///Trait to expose perph clocks
1563trait SealedSysconPeripheral { 1523trait SealedSysconPeripheral {
1564 fn enable_and_reset_perph_clock(); 1524 fn enable_perph_clock();
1525 fn reset_perph();
1565 fn disable_perph_clock(); 1526 fn disable_perph_clock();
1566} 1527}
1567 1528
@@ -1574,7 +1535,18 @@ pub trait SysconPeripheral: SealedSysconPeripheral + 'static {}
1574/// 1535///
1575/// Peripheral must not be in use. 1536/// Peripheral must not be in use.
1576pub fn enable_and_reset<T: SysconPeripheral>() { 1537pub fn enable_and_reset<T: SysconPeripheral>() {
1577 T::enable_and_reset_perph_clock(); 1538 T::enable_perph_clock();
1539 T::reset_perph();
1540}
1541
1542/// Enables peripheral `T`.
1543pub fn enable<T: SysconPeripheral>() {
1544 T::enable_perph_clock();
1545}
1546
1547/// Reset peripheral `T`.
1548pub fn reset<T: SysconPeripheral>() {
1549 T::reset_perph();
1578} 1550}
1579 1551
1580/// Disables peripheral `T`. 1552/// Disables peripheral `T`.
@@ -1588,15 +1560,21 @@ pub fn disable<T: SysconPeripheral>() {
1588macro_rules! impl_perph_clk { 1560macro_rules! impl_perph_clk {
1589 ($peripheral:ident, $clkctl:ident, $clkreg:ident, $rstctl:ident, $rstreg:ident, $bit:expr) => { 1561 ($peripheral:ident, $clkctl:ident, $clkreg:ident, $rstctl:ident, $rstreg:ident, $bit:expr) => {
1590 impl SealedSysconPeripheral for crate::peripherals::$peripheral { 1562 impl SealedSysconPeripheral for crate::peripherals::$peripheral {
1591 fn enable_and_reset_perph_clock() { 1563 fn enable_perph_clock() {
1592 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 1564 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
1593 let cc1 = unsafe { pac::$clkctl::steal() }; 1565 let cc1 = unsafe { pac::$clkctl::steal() };
1594 let rc1 = unsafe { pac::$rstctl::steal() };
1595 1566
1596 paste! { 1567 paste! {
1597 // SAFETY: unsafe due to the use of bits() 1568 // SAFETY: unsafe due to the use of bits()
1598 cc1.[<$clkreg _set>]().write(|w| unsafe { w.bits(1 << $bit) }); 1569 cc1.[<$clkreg _set>]().write(|w| unsafe { w.bits(1 << $bit) });
1570 }
1571 }
1599 1572
1573 fn reset_perph() {
1574 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
1575 let rc1 = unsafe { pac::$rstctl::steal() };
1576
1577 paste! {
1600 // SAFETY: unsafe due to the use of bits() 1578 // SAFETY: unsafe due to the use of bits()
1601 rc1.[<$rstreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) }); 1579 rc1.[<$rstreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) });
1602 } 1580 }
@@ -1605,13 +1583,9 @@ macro_rules! impl_perph_clk {
1605 fn disable_perph_clock() { 1583 fn disable_perph_clock() {
1606 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 1584 // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1
1607 let cc1 = unsafe { pac::$clkctl::steal() }; 1585 let cc1 = unsafe { pac::$clkctl::steal() };
1608 let rc1 = unsafe { pac::$rstctl::steal() };
1609 1586
1610 paste! { 1587 paste! {
1611 // SAFETY: unsafe due to the use of bits() 1588 // SAFETY: unsafe due to the use of bits()
1612 rc1.[<$rstreg _set>]().write(|w| unsafe { w.bits(1 << $bit) });
1613
1614 // SAFETY: unsafe due to the use of bits()
1615 cc1.[<$clkreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) }); 1589 cc1.[<$clkreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) });
1616 } 1590 }
1617 } 1591 }
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs
index 5fbf3244b..ad9f81e88 100644
--- a/embassy-imxrt/src/lib.rs
+++ b/embassy-imxrt/src/lib.rs
@@ -22,7 +22,7 @@ pub mod gpio;
22pub mod iopctl; 22pub mod iopctl;
23 23
24#[cfg(feature = "_time-driver")] 24#[cfg(feature = "_time-driver")]
25pub mod rtc; 25pub mod time_driver;
26 26
27// This mod MUST go last, so that it sees all the `impl_foo!' macros 27// This mod MUST go last, so that it sees all the `impl_foo!' macros
28#[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")] 28#[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")]
@@ -132,12 +132,10 @@ pub fn init(config: config::Config) -> Peripherals {
132 error!("unable to initialize Clocks for reason: {:?}", e); 132 error!("unable to initialize Clocks for reason: {:?}", e);
133 // Panic here? 133 // Panic here?
134 } 134 }
135 gpio::init();
136 } 135 }
137
138 // init RTC time driver
139 #[cfg(feature = "_time-driver")] 136 #[cfg(feature = "_time-driver")]
140 rtc::init(config.time_interrupt_priority); 137 time_driver::init(config.time_interrupt_priority);
138 gpio::init();
141 139
142 peripherals 140 peripherals
143} 141}
diff --git a/embassy-imxrt/src/rtc.rs b/embassy-imxrt/src/time_driver.rs
index 56a8f7397..c68679d3e 100644
--- a/embassy-imxrt/src/rtc.rs
+++ b/embassy-imxrt/src/time_driver.rs
@@ -1,5 +1,6 @@
1//! RTC Time Driver. 1//! Time Driver.
2use core::cell::{Cell, RefCell}; 2use core::cell::{Cell, RefCell};
3#[cfg(feature = "time-driver-rtc")]
3use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
4 5
5use critical_section::CriticalSection; 6use critical_section::CriticalSection;
@@ -8,9 +9,26 @@ use embassy_sync::blocking_mutex::Mutex;
8use embassy_time_driver::Driver; 9use embassy_time_driver::Driver;
9use embassy_time_queue_utils::Queue; 10use embassy_time_queue_utils::Queue;
10 11
12#[cfg(feature = "time-driver-os-timer")]
13use crate::clocks::enable;
11use crate::interrupt::InterruptExt; 14use crate::interrupt::InterruptExt;
12use crate::{interrupt, pac}; 15use crate::{interrupt, pac};
13 16
17struct AlarmState {
18 timestamp: Cell<u64>,
19}
20
21unsafe impl Send for AlarmState {}
22
23impl AlarmState {
24 const fn new() -> Self {
25 Self {
26 timestamp: Cell::new(u64::MAX),
27 }
28 }
29}
30
31#[cfg(feature = "time-driver-rtc")]
14fn rtc() -> &'static pac::rtc::RegisterBlock { 32fn rtc() -> &'static pac::rtc::RegisterBlock {
15 unsafe { &*pac::Rtc::ptr() } 33 unsafe { &*pac::Rtc::ptr() }
16} 34}
@@ -25,24 +43,19 @@ fn rtc() -> &'static pac::rtc::RegisterBlock {
25/// the 1kHz RTC counter is 16 bits and RTC doesn't have separate compare channels, 43/// the 1kHz RTC counter is 16 bits and RTC doesn't have separate compare channels,
26/// so using a 32 bit GPREG0-2 as counter, compare, and int_en 44/// so using a 32 bit GPREG0-2 as counter, compare, and int_en
27/// `period` is a 32bit integer, gpreg 'counter' is 31 bits plus the parity bit for overflow detection 45/// `period` is a 32bit integer, gpreg 'counter' is 31 bits plus the parity bit for overflow detection
46#[cfg(feature = "time-driver-rtc")]
28fn calc_now(period: u32, counter: u32) -> u64 { 47fn calc_now(period: u32, counter: u32) -> u64 {
29 ((period as u64) << 31) + ((counter ^ ((period & 1) << 31)) as u64) 48 ((period as u64) << 31) + ((counter ^ ((period & 1) << 31)) as u64)
30} 49}
31 50
32struct AlarmState { 51#[cfg(feature = "time-driver-rtc")]
33 timestamp: Cell<u64>, 52embassy_time_driver::time_driver_impl!(static DRIVER: Rtc = Rtc {
34} 53 period: AtomicU32::new(0),
35 54 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
36unsafe impl Send for AlarmState {} 55 queue: Mutex::new(RefCell::new(Queue::new())),
37 56});
38impl AlarmState {
39 const fn new() -> Self {
40 Self {
41 timestamp: Cell::new(u64::MAX),
42 }
43 }
44}
45 57
58#[cfg(feature = "time-driver-rtc")]
46struct Rtc { 59struct Rtc {
47 /// Number of 2^31 periods elapsed since boot. 60 /// Number of 2^31 periods elapsed since boot.
48 period: AtomicU32, 61 period: AtomicU32,
@@ -51,12 +64,7 @@ struct Rtc {
51 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>, 64 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
52} 65}
53 66
54embassy_time_driver::time_driver_impl!(static DRIVER: Rtc = Rtc { 67#[cfg(feature = "time-driver-rtc")]
55 period: AtomicU32::new(0),
56 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
57 queue: Mutex::new(RefCell::new(Queue::new())),
58});
59
60impl Rtc { 68impl Rtc {
61 /// Access the GPREG0 register to use it as a 31-bit counter. 69 /// Access the GPREG0 register to use it as a 31-bit counter.
62 #[inline] 70 #[inline]
@@ -219,6 +227,7 @@ impl Rtc {
219 } 227 }
220} 228}
221 229
230#[cfg(feature = "time-driver-rtc")]
222impl Driver for Rtc { 231impl Driver for Rtc {
223 fn now(&self) -> u64 { 232 fn now(&self) -> u64 {
224 // `period` MUST be read before `counter`, see comment at the top for details. 233 // `period` MUST be read before `counter`, see comment at the top for details.
@@ -242,13 +251,158 @@ impl Driver for Rtc {
242 } 251 }
243} 252}
244 253
245#[cfg(feature = "rt")] 254#[cfg(all(feature = "rt", feature = "time-driver-rtc"))]
246#[allow(non_snake_case)] 255#[allow(non_snake_case)]
247#[interrupt] 256#[interrupt]
248fn RTC() { 257fn RTC() {
249 DRIVER.on_interrupt() 258 DRIVER.on_interrupt()
250} 259}
251 260
261#[cfg(feature = "time-driver-os-timer")]
262fn os() -> &'static pac::ostimer0::RegisterBlock {
263 unsafe { &*pac::Ostimer0::ptr() }
264}
265
266/// Convert gray to decimal
267///
268/// Os Event provides a 64-bit timestamp gray-encoded. All we have to
269/// do here is read both 32-bit halves of the register and convert
270/// from gray to regular binary.
271#[cfg(feature = "time-driver-os-timer")]
272fn gray_to_dec(gray: u64) -> u64 {
273 let mut dec = gray;
274
275 dec ^= dec >> 1;
276 dec ^= dec >> 2;
277 dec ^= dec >> 4;
278 dec ^= dec >> 8;
279 dec ^= dec >> 16;
280 dec ^= dec >> 32;
281
282 dec
283}
284
285/// Convert decimal to gray
286///
287/// Before writing match value to the target register, we must convert
288/// it back into gray code.
289#[cfg(feature = "time-driver-os-timer")]
290fn dec_to_gray(dec: u64) -> u64 {
291 let gray = dec;
292 gray ^ (gray >> 1)
293}
294
295#[cfg(feature = "time-driver-os-timer")]
296embassy_time_driver::time_driver_impl!(static DRIVER: OsTimer = OsTimer {
297 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
298 queue: Mutex::new(RefCell::new(Queue::new())),
299});
300
301#[cfg(feature = "time-driver-os-timer")]
302struct OsTimer {
303 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
304 alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
305 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
306}
307
308#[cfg(feature = "time-driver-os-timer")]
309impl OsTimer {
310 fn init(&'static self, irq_prio: crate::interrupt::Priority) {
311 // init alarms
312 critical_section::with(|cs| {
313 let alarm = DRIVER.alarms.borrow(cs);
314 alarm.timestamp.set(u64::MAX);
315 });
316
317 // Enable clocks. Documentation advises AGAINST resetting this
318 // peripheral.
319 enable::<crate::peripherals::OS_EVENT>();
320
321 interrupt::OS_EVENT.disable();
322
323 // Make sure interrupt is masked
324 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
325
326 // Default to the end of time
327 os().match_l().write(|w| unsafe { w.bits(0xffff_ffff) });
328 os().match_h().write(|w| unsafe { w.bits(0xffff_ffff) });
329
330 interrupt::OS_EVENT.unpend();
331 interrupt::OS_EVENT.set_priority(irq_prio);
332 unsafe { interrupt::OS_EVENT.enable() };
333 }
334
335 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
336 let alarm = self.alarms.borrow(cs);
337 alarm.timestamp.set(timestamp);
338
339 let t = self.now();
340 if timestamp <= t {
341 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
342 alarm.timestamp.set(u64::MAX);
343 return false;
344 }
345
346 let gray_timestamp = dec_to_gray(timestamp);
347
348 os().match_l()
349 .write(|w| unsafe { w.bits(gray_timestamp as u32 & 0xffff_ffff) });
350 os().match_h()
351 .write(|w| unsafe { w.bits((gray_timestamp >> 32) as u32) });
352 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().set_bit());
353
354 true
355 }
356
357 #[cfg(feature = "rt")]
358 fn trigger_alarm(&self, cs: CriticalSection) {
359 let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
360 while !self.set_alarm(cs, next) {
361 next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
362 }
363 }
364
365 #[cfg(feature = "rt")]
366 fn on_interrupt(&self) {
367 critical_section::with(|cs| {
368 if os().osevent_ctrl().read().ostimer_intrflag().bit_is_set() {
369 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
370 self.trigger_alarm(cs);
371 }
372 });
373 }
374}
375
376#[cfg(feature = "time-driver-os-timer")]
377impl Driver for OsTimer {
378 fn now(&self) -> u64 {
379 let mut t = os().evtimerh().read().bits() as u64;
380 t <<= 32;
381 t |= os().evtimerl().read().bits() as u64;
382 gray_to_dec(t)
383 }
384
385 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
386 critical_section::with(|cs| {
387 let mut queue = self.queue.borrow(cs).borrow_mut();
388
389 if queue.schedule_wake(at, waker) {
390 let mut next = queue.next_expiration(self.now());
391 while !self.set_alarm(cs, next) {
392 next = queue.next_expiration(self.now());
393 }
394 }
395 })
396 }
397}
398
399#[cfg(all(feature = "rt", feature = "time-driver-os-timer"))]
400#[allow(non_snake_case)]
401#[interrupt]
402fn OS_EVENT() {
403 DRIVER.on_interrupt()
404}
405
252pub(crate) fn init(irq_prio: crate::interrupt::Priority) { 406pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
253 DRIVER.init(irq_prio) 407 DRIVER.init(irq_prio)
254} 408}
diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml
index 8fc510c47..b0c56f003 100644
--- a/examples/mimxrt6/Cargo.toml
+++ b/examples/mimxrt6/Cargo.toml
@@ -12,8 +12,8 @@ defmt-rtt = "1.0"
12 12
13embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 13embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
14embassy-futures = { version = "0.1.1", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.1", path = "../../embassy-futures" }
15embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-rtc"] } 15embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-os-timer"] }
16embassy-time = { version = "0.4", path = "../../embassy-time" } 16embassy-time = { version = "0.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
17embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } 17embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
18embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 18embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
19embedded-hal-async = "1.0.0" 19embedded-hal-async = "1.0.0"