diff options
Diffstat (limited to 'embassy-mcxa')
| -rw-r--r-- | embassy-mcxa/src/adc.rs | 784 | ||||
| -rw-r--r-- | embassy-mcxa/src/clocks/mod.rs | 3 | ||||
| -rw-r--r-- | embassy-mcxa/src/clocks/periph_helpers.rs | 1 | ||||
| -rw-r--r-- | embassy-mcxa/src/i2c/controller.rs | 2 | ||||
| -rw-r--r-- | embassy-mcxa/src/interrupt.rs | 41 | ||||
| -rw-r--r-- | embassy-mcxa/src/lib.rs | 10 | ||||
| -rw-r--r-- | embassy-mcxa/src/lpuart/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-mcxa/src/pins.rs | 33 | ||||
| -rw-r--r-- | embassy-mcxa/src/reset_reason.rs | 106 | ||||
| -rw-r--r-- | embassy-mcxa/src/rtc.rs | 78 |
10 files changed, 766 insertions, 296 deletions
diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 7475299ba..f88bb6b37 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs | |||
| @@ -1,42 +1,23 @@ | |||
| 1 | //! ADC driver | 1 | //! ADC driver |
| 2 | use core::sync::atomic::{AtomicBool, Ordering}; | 2 | use core::future::Future; |
| 3 | use core::marker::PhantomData; | ||
| 3 | 4 | ||
| 4 | use embassy_hal_internal::{Peri, PeripheralType}; | 5 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 6 | use maitake_sync::WaitCell; | ||
| 7 | use paste::paste; | ||
| 5 | 8 | ||
| 6 | use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; | 9 | use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; |
| 7 | use crate::clocks::{Gate, PoweredClock, enable_and_reset}; | 10 | use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset}; |
| 11 | use crate::gpio::{GpioPin, SealedPin}; | ||
| 12 | use crate::interrupt::typelevel::{Handler, Interrupt}; | ||
| 8 | use crate::pac; | 13 | use crate::pac; |
| 9 | use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; | 14 | use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; |
| 10 | use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; | 15 | use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; |
| 11 | use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; | 16 | use crate::pac::adc1::cmdl1::Mode; |
| 12 | use crate::pac::adc1::ctrl::CalAvgs; | 17 | use crate::pac::adc1::ctrl::CalAvgs; |
| 13 | use crate::pac::adc1::tctrl::{Tcmd, Tpri}; | 18 | use crate::pac::adc1::tctrl::{Tcmd, Tpri}; |
| 14 | 19 | ||
| 15 | type Regs = pac::adc1::RegisterBlock; | 20 | /// Trigger priority policy for ADC conversions. |
| 16 | |||
| 17 | static INTERRUPT_TRIGGERED: AtomicBool = AtomicBool::new(false); | ||
| 18 | // Token-based instance pattern like embassy-imxrt | ||
| 19 | pub trait Instance: Gate<MrccPeriphConfig = AdcConfig> + PeripheralType { | ||
| 20 | fn ptr() -> *const Regs; | ||
| 21 | } | ||
| 22 | |||
| 23 | /// Token for ADC1 | ||
| 24 | pub type Adc1 = crate::peripherals::ADC1; | ||
| 25 | impl Instance for crate::peripherals::ADC1 { | ||
| 26 | #[inline(always)] | ||
| 27 | fn ptr() -> *const Regs { | ||
| 28 | pac::Adc1::ptr() | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | // Also implement Instance for the Peri wrapper type | ||
| 33 | // impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::ADC1> { | ||
| 34 | // #[inline(always)] | ||
| 35 | // fn ptr() -> *const Regs { | ||
| 36 | // pac::Adc1::ptr() | ||
| 37 | // } | ||
| 38 | // } | ||
| 39 | |||
| 40 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 21 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 41 | #[repr(u8)] | 22 | #[repr(u8)] |
| 42 | pub enum TriggerPriorityPolicy { | 23 | pub enum TriggerPriorityPolicy { |
| @@ -52,20 +33,36 @@ pub enum TriggerPriorityPolicy { | |||
| 52 | TriggerPriorityExceptionDisabled = 16, | 33 | TriggerPriorityExceptionDisabled = 16, |
| 53 | } | 34 | } |
| 54 | 35 | ||
| 36 | /// Configuration for the LPADC peripheral. | ||
| 55 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 37 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 56 | pub struct LpadcConfig { | 38 | pub struct LpadcConfig { |
| 39 | /// Control system transition to Stop and Wait power modes while ADC is converting. | ||
| 40 | /// When enabled in Doze mode, immediate entries to Wait or Stop are allowed. | ||
| 41 | /// When disabled, the ADC will wait for the current averaging iteration/FIFO storage to complete before acknowledging stop or wait mode entry. | ||
| 57 | pub enable_in_doze_mode: bool, | 42 | pub enable_in_doze_mode: bool, |
| 43 | /// Auto-Calibration Averages. | ||
| 58 | pub conversion_average_mode: CalAvgs, | 44 | pub conversion_average_mode: CalAvgs, |
| 45 | /// ADC analog circuits are pre-enabled and ready to execute conversions without startup delays(at the cost of higher DC current consumption). | ||
| 59 | pub enable_analog_preliminary: bool, | 46 | pub enable_analog_preliminary: bool, |
| 47 | /// Power-up delay value (in ADC clock cycles) | ||
| 60 | pub power_up_delay: u8, | 48 | pub power_up_delay: u8, |
| 49 | /// Reference voltage source selection | ||
| 61 | pub reference_voltage_source: Refsel, | 50 | pub reference_voltage_source: Refsel, |
| 51 | /// Power configuration selection. | ||
| 62 | pub power_level_mode: Pwrsel, | 52 | pub power_level_mode: Pwrsel, |
| 53 | /// Trigger priority policy for handling multiple triggers | ||
| 63 | pub trigger_priority_policy: TriggerPriorityPolicy, | 54 | pub trigger_priority_policy: TriggerPriorityPolicy, |
| 55 | /// Enables the ADC pausing function. When enabled, a programmable delay is inserted during command execution sequencing between LOOP iterations, | ||
| 56 | /// between commands in a sequence, and between conversions when command is executing in "Compare Until True" configuration. | ||
| 64 | pub enable_conv_pause: bool, | 57 | pub enable_conv_pause: bool, |
| 58 | /// Controls the duration of pausing during command execution sequencing. The pause delay is a count of (convPauseDelay*4) ADCK cycles. | ||
| 59 | /// Only available when ADC pausing function is enabled. The available value range is in 9-bit. | ||
| 65 | pub conv_pause_delay: u16, | 60 | pub conv_pause_delay: u16, |
| 66 | pub fifo_watermark: u8, | 61 | /// Power configuration (normal/deep sleep behavior) |
| 67 | pub power: PoweredClock, | 62 | pub power: PoweredClock, |
| 63 | /// ADC clock source selection | ||
| 68 | pub source: AdcClockSel, | 64 | pub source: AdcClockSel, |
| 65 | /// Clock divider for ADC clock | ||
| 69 | pub div: Div4, | 66 | pub div: Div4, |
| 70 | } | 67 | } |
| 71 | 68 | ||
| @@ -81,7 +78,6 @@ impl Default for LpadcConfig { | |||
| 81 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, | 78 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, |
| 82 | enable_conv_pause: false, | 79 | enable_conv_pause: false, |
| 83 | conv_pause_delay: 0, | 80 | conv_pause_delay: 0, |
| 84 | fifo_watermark: 0, | ||
| 85 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | 81 | power: PoweredClock::NormalEnabledDeepSleepDisabled, |
| 86 | source: AdcClockSel::FroLfDiv, | 82 | source: AdcClockSel::FroLfDiv, |
| 87 | div: Div4::no_div(), | 83 | div: Div4::no_div(), |
| @@ -89,10 +85,11 @@ impl Default for LpadcConfig { | |||
| 89 | } | 85 | } |
| 90 | } | 86 | } |
| 91 | 87 | ||
| 88 | /// Configuration for a conversion command. | ||
| 89 | /// | ||
| 90 | /// Defines the parameters for a single ADC conversion operation. | ||
| 92 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 91 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 93 | pub struct ConvCommandConfig { | 92 | pub struct ConvCommandConfig { |
| 94 | pub sample_channel_mode: Ctype, | ||
| 95 | pub channel_number: Adch, | ||
| 96 | pub chained_next_command_number: Next, | 93 | pub chained_next_command_number: Next, |
| 97 | pub enable_auto_channel_increment: bool, | 94 | pub enable_auto_channel_increment: bool, |
| 98 | pub loop_count: u8, | 95 | pub loop_count: u8, |
| @@ -105,6 +102,26 @@ pub struct ConvCommandConfig { | |||
| 105 | pub enable_wait_trigger: bool, | 102 | pub enable_wait_trigger: bool, |
| 106 | } | 103 | } |
| 107 | 104 | ||
| 105 | impl Default for ConvCommandConfig { | ||
| 106 | fn default() -> Self { | ||
| 107 | ConvCommandConfig { | ||
| 108 | chained_next_command_number: Next::NoNextCmdTerminateOnFinish, | ||
| 109 | enable_auto_channel_increment: false, | ||
| 110 | loop_count: 0, | ||
| 111 | hardware_average_mode: Avgs::NoAverage, | ||
| 112 | sample_time_mode: Sts::Sample3p5, | ||
| 113 | hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult, | ||
| 114 | hardware_compare_value_high: 0, | ||
| 115 | hardware_compare_value_low: 0, | ||
| 116 | conversion_resolution_mode: Mode::Data12Bits, | ||
| 117 | enable_wait_trigger: false, | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | /// Configuration for a conversion trigger. | ||
| 123 | /// | ||
| 124 | /// Defines how a trigger initiates ADC conversions. | ||
| 108 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 125 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 109 | pub struct ConvTriggerConfig { | 126 | pub struct ConvTriggerConfig { |
| 110 | pub target_command_id: Tcmd, | 127 | pub target_command_id: Tcmd, |
| @@ -113,32 +130,298 @@ pub struct ConvTriggerConfig { | |||
| 113 | pub enable_hardware_trigger: bool, | 130 | pub enable_hardware_trigger: bool, |
| 114 | } | 131 | } |
| 115 | 132 | ||
| 133 | impl Default for ConvTriggerConfig { | ||
| 134 | fn default() -> Self { | ||
| 135 | ConvTriggerConfig { | ||
| 136 | target_command_id: Tcmd::NotValid, | ||
| 137 | delay_power: 0, | ||
| 138 | priority: Tpri::HighestPriority, | ||
| 139 | enable_hardware_trigger: false, | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | /// Shorthand for `Result<T>`. | ||
| 145 | pub type Result<T> = core::result::Result<T, Error>; | ||
| 146 | |||
| 147 | /// ADC Error types | ||
| 148 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 149 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 150 | pub enum Error { | ||
| 151 | /// FIFO is empty, no conversion result available | ||
| 152 | FifoEmpty, | ||
| 153 | /// Invalid configuration | ||
| 154 | InvalidConfig, | ||
| 155 | /// Clock configuration error. | ||
| 156 | ClockSetup(ClockError), | ||
| 157 | } | ||
| 158 | |||
| 159 | /// Result of an ADC conversion. | ||
| 160 | /// | ||
| 161 | /// Contains the conversion value and metadata about the conversion. | ||
| 116 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 162 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 117 | pub struct ConvResult { | 163 | pub struct ConvResult { |
| 118 | pub command_id_source: u32, | 164 | pub command_id_source: u8, |
| 119 | pub loop_count_index: u32, | 165 | pub loop_count_index: u8, |
| 120 | pub trigger_id_source: u32, | 166 | pub trigger_id_source: u8, |
| 121 | pub conv_value: u16, | 167 | pub conv_value: u16, |
| 122 | } | 168 | } |
| 123 | 169 | ||
| 124 | pub struct Adc<'a, I: Instance> { | 170 | /// ADC interrupt handler. |
| 125 | _inst: core::marker::PhantomData<&'a mut I>, | 171 | pub struct InterruptHandler<I: Instance> { |
| 172 | _phantom: PhantomData<I>, | ||
| 173 | } | ||
| 174 | |||
| 175 | /// ADC driver instance. | ||
| 176 | pub struct Adc<'a, M: ModeAdc> { | ||
| 177 | _inst: PhantomData<&'a mut ()>, | ||
| 178 | mode: M, | ||
| 179 | |||
| 180 | // The channel index of the pin used to create our ADC instance | ||
| 181 | channel_idx: u8, | ||
| 182 | |||
| 183 | // The register block of the ADC instance | ||
| 184 | info: &'static pac::adc0::RegisterBlock, | ||
| 185 | } | ||
| 186 | |||
| 187 | impl<'a> Adc<'a, Blocking> { | ||
| 188 | /// Create a new blocking instance of the ADC driver. | ||
| 189 | /// # Arguments | ||
| 190 | /// * `_inst` - ADC peripheral instance | ||
| 191 | /// * `pin` - GPIO pin to use for ADC | ||
| 192 | /// * `config` - ADC configuration | ||
| 193 | pub fn new_blocking<I: Instance>( | ||
| 194 | _inst: Peri<'a, I>, | ||
| 195 | pin: Peri<'a, impl AdcPin<I>>, | ||
| 196 | config: LpadcConfig, | ||
| 197 | ) -> Result<Self> { | ||
| 198 | Self::new_inner(_inst, pin, config, Blocking) | ||
| 199 | } | ||
| 200 | |||
| 201 | /// Enable ADC interrupts. | ||
| 202 | /// | ||
| 203 | /// Enables the interrupt sources specified in the bitmask. | ||
| 204 | /// | ||
| 205 | /// # Arguments | ||
| 206 | /// * `mask` - Bitmask of interrupt sources to enable | ||
| 207 | pub fn enable_interrupt(&mut self, mask: u32) { | ||
| 208 | self.info.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); | ||
| 209 | } | ||
| 210 | |||
| 211 | /// Disable ADC interrupts. | ||
| 212 | /// | ||
| 213 | /// Disables the interrupt sources specified in the bitmask. | ||
| 214 | /// | ||
| 215 | /// # Arguments | ||
| 216 | /// * `mask` - Bitmask of interrupt sources to disable | ||
| 217 | pub fn disable_interrupt(&mut self, mask: u32) { | ||
| 218 | self.info.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); | ||
| 219 | } | ||
| 220 | |||
| 221 | pub fn set_fifo_watermark(&mut self, watermark: u8) -> Result<()> { | ||
| 222 | if watermark > 0b111 { | ||
| 223 | return Err(Error::InvalidConfig); | ||
| 224 | } | ||
| 225 | self.info.fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(watermark) }); | ||
| 226 | Ok(()) | ||
| 227 | } | ||
| 228 | |||
| 229 | /// Trigger ADC conversion(s) via software. | ||
| 230 | /// | ||
| 231 | /// Initiates conversion(s) for the trigger(s) specified in the bitmask. | ||
| 232 | /// Each bit in the mask corresponds to a trigger ID (bit 0 = trigger 0, etc.). | ||
| 233 | /// | ||
| 234 | /// # Arguments | ||
| 235 | /// * `trigger_id_mask` - Bitmask of trigger IDs to activate (bit N = trigger N) | ||
| 236 | /// | ||
| 237 | /// # Returns | ||
| 238 | /// * `Ok(())` if the triger mask was valid | ||
| 239 | /// * `Err(Error::InvalidConfig)` if the mask was greater than `0b1111` | ||
| 240 | pub fn do_software_trigger(&self, trigger_id_mask: u8) -> Result<()> { | ||
| 241 | if trigger_id_mask > 0b1111 { | ||
| 242 | return Err(Error::InvalidConfig); | ||
| 243 | } | ||
| 244 | self.info.swtrig().write(|w| unsafe { w.bits(trigger_id_mask as u32) }); | ||
| 245 | Ok(()) | ||
| 246 | } | ||
| 247 | |||
| 248 | /// Set conversion command configuration. | ||
| 249 | /// | ||
| 250 | /// Configures a conversion command slot with the specified parameters. | ||
| 251 | /// Commands define how conversions are performed (channel, resolution, etc.). | ||
| 252 | /// | ||
| 253 | /// # Arguments | ||
| 254 | /// * `index` - Command index (Must be in range 1..=7) | ||
| 255 | /// * `config` - Command configuration | ||
| 256 | /// | ||
| 257 | /// # Returns | ||
| 258 | /// * `Ok(())` if the command was configured successfully | ||
| 259 | /// * `Err(Error::InvalidConfig)` if the index is out of range | ||
| 260 | pub fn set_conv_command_config(&self, index: usize, config: &ConvCommandConfig) -> Result<()> { | ||
| 261 | self.set_conv_command_config_inner(index, config) | ||
| 262 | } | ||
| 263 | |||
| 264 | /// Set conversion trigger configuration. | ||
| 265 | /// | ||
| 266 | /// Configures a trigger to initiate conversions. Triggers can be | ||
| 267 | /// activated by software or hardware signals. | ||
| 268 | /// | ||
| 269 | /// # Arguments | ||
| 270 | /// * `trigger_id` - Trigger index (0..=3) | ||
| 271 | /// * `config` - Trigger configuration | ||
| 272 | pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> { | ||
| 273 | self.set_conv_trigger_config_inner(trigger_id, config) | ||
| 274 | } | ||
| 275 | |||
| 276 | /// Reset the FIFO buffer. | ||
| 277 | /// | ||
| 278 | /// Clears all pending conversion results from the FIFO. | ||
| 279 | pub fn do_reset_fifo(&self) { | ||
| 280 | self.info.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); | ||
| 281 | } | ||
| 282 | |||
| 283 | /// Get conversion result from FIFO. | ||
| 284 | /// | ||
| 285 | /// Reads and returns the next conversion result from the FIFO. | ||
| 286 | /// Returns `None` if the FIFO is empty. | ||
| 287 | /// | ||
| 288 | /// # Returns | ||
| 289 | /// - `Some(ConvResult)` if a result is available | ||
| 290 | /// - `Err(Error::FifoEmpty)` if the FIFO is empty | ||
| 291 | pub fn get_conv_result(&self) -> Result<ConvResult> { | ||
| 292 | self.get_conv_result_inner() | ||
| 293 | } | ||
| 126 | } | 294 | } |
| 127 | 295 | ||
| 128 | impl<'a, I: Instance> Adc<'a, I> { | 296 | impl<'a> Adc<'a, Async> { |
| 129 | /// initialize ADC | 297 | /// Initialize ADC with interrupt support. |
| 130 | pub fn new(_inst: Peri<'a, I>, config: LpadcConfig) -> Self { | 298 | /// |
| 131 | let adc = unsafe { &*I::ptr() }; | 299 | /// # Arguments |
| 300 | /// * `_inst` - ADC peripheral instance | ||
| 301 | /// * `pin` - GPIO pin to use for ADC | ||
| 302 | /// * `_irq` - Interrupt binding for this ADC instance | ||
| 303 | /// * `config` - ADC configuration | ||
| 304 | pub fn new_async<I: Instance>( | ||
| 305 | _inst: Peri<'a, I>, | ||
| 306 | pin: Peri<'a, impl AdcPin<I>>, | ||
| 307 | _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a, | ||
| 308 | config: LpadcConfig, | ||
| 309 | ) -> Result<Self> { | ||
| 310 | let adc = Self::new_inner(_inst, pin, config, Async { waiter: I::wait_cell() })?; | ||
| 311 | |||
| 312 | I::Interrupt::unpend(); | ||
| 313 | unsafe { I::Interrupt::enable() }; | ||
| 314 | |||
| 315 | let cfg = ConvCommandConfig { | ||
| 316 | chained_next_command_number: Next::NoNextCmdTerminateOnFinish, | ||
| 317 | enable_auto_channel_increment: false, | ||
| 318 | loop_count: 0, | ||
| 319 | hardware_average_mode: Avgs::NoAverage, | ||
| 320 | sample_time_mode: Sts::Sample3p5, | ||
| 321 | hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult, | ||
| 322 | hardware_compare_value_high: 0, | ||
| 323 | hardware_compare_value_low: 0, | ||
| 324 | conversion_resolution_mode: Mode::Data16Bits, | ||
| 325 | enable_wait_trigger: false, | ||
| 326 | }; | ||
| 327 | |||
| 328 | // We always use command 1, so this cannot fail | ||
| 329 | _ = adc.set_conv_command_config_inner(1, &cfg); | ||
| 330 | |||
| 331 | let cfg = ConvTriggerConfig { | ||
| 332 | target_command_id: Tcmd::ExecuteCmd1, | ||
| 333 | delay_power: 0, | ||
| 334 | priority: Tpri::HighestPriority, | ||
| 335 | enable_hardware_trigger: false, | ||
| 336 | }; | ||
| 337 | |||
| 338 | // We always use trigger 0, so this cannot fail | ||
| 339 | _ = adc.set_conv_trigger_config_inner(0, &cfg); | ||
| 340 | |||
| 341 | // We always set the watermark to 0 (trigger when 1 is available) | ||
| 342 | I::ptr().fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(0) }); | ||
| 343 | |||
| 344 | Ok(adc) | ||
| 345 | } | ||
| 346 | |||
| 347 | /// Set the number of averages | ||
| 348 | pub fn set_averages(&mut self, avgs: Avgs) { | ||
| 349 | // TODO: we should probably return a result or wait for idle? | ||
| 350 | // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." | ||
| 351 | self.info.cmdh1().modify(|_r, w| w.avgs().variant(avgs)); | ||
| 352 | } | ||
| 132 | 353 | ||
| 133 | let _clock_freq = unsafe { | 354 | /// Set the sample time |
| 355 | pub fn set_sample_time(&mut self, st: Sts) { | ||
| 356 | // TODO: we should probably return a result or wait for idle? | ||
| 357 | // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." | ||
| 358 | self.info.cmdh1().modify(|_r, w| w.sts().variant(st)); | ||
| 359 | } | ||
| 360 | |||
| 361 | pub fn set_resolution(&mut self, mode: Mode) { | ||
| 362 | // TODO: we should probably return a result or wait for idle? | ||
| 363 | // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." | ||
| 364 | self.info.cmdl1().modify(|_r, w| w.mode().variant(mode)); | ||
| 365 | } | ||
| 366 | |||
| 367 | fn wait_idle(&mut self) -> impl Future<Output = core::result::Result<(), maitake_sync::Closed>> + use<'_> { | ||
| 368 | self.mode | ||
| 369 | .waiter | ||
| 370 | .wait_for(|| self.info.ie().read().fwmie0().bit_is_clear()) | ||
| 371 | } | ||
| 372 | |||
| 373 | /// Read ADC value asynchronously. | ||
| 374 | /// | ||
| 375 | /// Performs a single ADC conversion and returns the result when the ADC interrupt is triggered. | ||
| 376 | /// | ||
| 377 | /// The function: | ||
| 378 | /// 1. Enables the FIFO watermark interrupt | ||
| 379 | /// 2. Triggers a software conversion on trigger 0 | ||
| 380 | /// 3. Waits for the conversion to complete | ||
| 381 | /// 4. Returns the conversion result | ||
| 382 | /// | ||
| 383 | /// # Returns | ||
| 384 | /// 16-bit ADC conversion value | ||
| 385 | pub async fn read(&mut self) -> Result<u16> { | ||
| 386 | // If we cancelled a previous read, we might still be busy, wait | ||
| 387 | // until the interrupt is cleared (done by the interrupt) | ||
| 388 | _ = self.wait_idle().await; | ||
| 389 | |||
| 390 | // Clear the fifo | ||
| 391 | self.info.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); | ||
| 392 | |||
| 393 | // Trigger a new conversion | ||
| 394 | self.info.ie().modify(|_r, w| w.fwmie0().set_bit()); | ||
| 395 | self.info.swtrig().write(|w| w.swt0().set_bit()); | ||
| 396 | |||
| 397 | // Wait for completion | ||
| 398 | _ = self.wait_idle().await; | ||
| 399 | |||
| 400 | self.get_conv_result_inner().map(|r| r.conv_value) | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | impl<'a, M: ModeAdc> Adc<'a, M> { | ||
| 405 | /// Internal initialization function shared by `new_async` and `new_blocking`. | ||
| 406 | fn new_inner<I: Instance, P: AdcPin<I>>( | ||
| 407 | _inst: Peri<'a, I>, | ||
| 408 | pin: Peri<'a, P>, | ||
| 409 | config: LpadcConfig, | ||
| 410 | mode: M, | ||
| 411 | ) -> Result<Self> { | ||
| 412 | let adc = I::ptr(); | ||
| 413 | |||
| 414 | _ = unsafe { | ||
| 134 | enable_and_reset::<I>(&AdcConfig { | 415 | enable_and_reset::<I>(&AdcConfig { |
| 135 | power: config.power, | 416 | power: config.power, |
| 136 | source: config.source, | 417 | source: config.source, |
| 137 | div: config.div, | 418 | div: config.div, |
| 138 | }) | 419 | }) |
| 139 | .expect("Adc Init should not fail") | 420 | .map_err(Error::ClockSetup)? |
| 140 | }; | 421 | }; |
| 141 | 422 | ||
| 423 | pin.mux(); | ||
| 424 | |||
| 142 | /* Reset the module. */ | 425 | /* Reset the module. */ |
| 143 | adc.ctrl().modify(|_, w| w.rst().held_in_reset()); | 426 | adc.ctrl().modify(|_, w| w.rst().held_in_reset()); |
| 144 | adc.ctrl().modify(|_, w| w.rst().released_from_reset()); | 427 | adc.ctrl().modify(|_, w| w.rst().released_from_reset()); |
| @@ -149,22 +432,14 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 149 | adc.ctrl().modify(|_, w| w.adcen().disabled()); | 432 | adc.ctrl().modify(|_, w| w.adcen().disabled()); |
| 150 | 433 | ||
| 151 | /* Configure the module generally. */ | 434 | /* Configure the module generally. */ |
| 152 | if config.enable_in_doze_mode { | 435 | adc.ctrl().modify(|_, w| w.dozen().bit(config.enable_in_doze_mode)); |
| 153 | adc.ctrl().modify(|_, w| w.dozen().enabled()); | ||
| 154 | } else { | ||
| 155 | adc.ctrl().modify(|_, w| w.dozen().disabled()); | ||
| 156 | } | ||
| 157 | 436 | ||
| 158 | /* Set calibration average mode. */ | 437 | /* Set calibration average mode. */ |
| 159 | adc.ctrl() | 438 | adc.ctrl() |
| 160 | .modify(|_, w| w.cal_avgs().variant(config.conversion_average_mode)); | 439 | .modify(|_, w| w.cal_avgs().variant(config.conversion_average_mode)); |
| 161 | 440 | ||
| 162 | adc.cfg().write(|w| unsafe { | 441 | adc.cfg().write(|w| unsafe { |
| 163 | let w = if config.enable_analog_preliminary { | 442 | w.pwren().bit(config.enable_analog_preliminary); |
| 164 | w.pwren().pre_enabled() | ||
| 165 | } else { | ||
| 166 | w | ||
| 167 | }; | ||
| 168 | 443 | ||
| 169 | w.pudly() | 444 | w.pudly() |
| 170 | .bits(config.power_up_delay) | 445 | .bits(config.power_up_delay) |
| @@ -214,32 +489,38 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 214 | adc.pause().write(|w| unsafe { w.bits(0) }); | 489 | adc.pause().write(|w| unsafe { w.bits(0) }); |
| 215 | } | 490 | } |
| 216 | 491 | ||
| 217 | adc.fctrl0() | 492 | adc.fctrl0().write(|w| unsafe { w.fwmark().bits(0) }); |
| 218 | .write(|w| unsafe { w.fwmark().bits(config.fifo_watermark) }); | ||
| 219 | 493 | ||
| 220 | // Enable ADC | 494 | // Enable ADC |
| 221 | adc.ctrl().modify(|_, w| w.adcen().enabled()); | 495 | adc.ctrl().modify(|_, w| w.adcen().enabled()); |
| 222 | 496 | ||
| 223 | Self { | 497 | Ok(Self { |
| 224 | _inst: core::marker::PhantomData, | 498 | _inst: PhantomData, |
| 225 | } | 499 | mode, |
| 226 | } | 500 | channel_idx: P::CHANNEL, |
| 227 | 501 | info: adc, | |
| 228 | pub fn deinit(&self) { | 502 | }) |
| 229 | let adc = unsafe { &*I::ptr() }; | ||
| 230 | adc.ctrl().modify(|_, w| w.adcen().disabled()); | ||
| 231 | } | 503 | } |
| 232 | 504 | ||
| 505 | /// Perform offset calibration. | ||
| 506 | /// Waits for calibration to complete before returning. | ||
| 233 | pub fn do_offset_calibration(&self) { | 507 | pub fn do_offset_calibration(&self) { |
| 234 | let adc = unsafe { &*I::ptr() }; | ||
| 235 | // Enable calibration mode | 508 | // Enable calibration mode |
| 236 | adc.ctrl() | 509 | self.info |
| 510 | .ctrl() | ||
| 237 | .modify(|_, w| w.calofs().offset_calibration_request_pending()); | 511 | .modify(|_, w| w.calofs().offset_calibration_request_pending()); |
| 238 | 512 | ||
| 239 | // Wait for calibration to complete (polling status register) | 513 | // Wait for calibration to complete (polling status register) |
| 240 | while adc.stat().read().cal_rdy().is_not_set() {} | 514 | while self.info.stat().read().cal_rdy().is_not_set() {} |
| 241 | } | 515 | } |
| 242 | 516 | ||
| 517 | /// Calculate gain conversion result from gain adjustment factor. | ||
| 518 | /// | ||
| 519 | /// # Arguments | ||
| 520 | /// * `gain_adjustment` - Gain adjustment factor | ||
| 521 | /// | ||
| 522 | /// # Returns | ||
| 523 | /// Gain calibration register value | ||
| 243 | pub fn get_gain_conv_result(&self, mut gain_adjustment: f32) -> u32 { | 524 | pub fn get_gain_conv_result(&self, mut gain_adjustment: f32) -> u32 { |
| 244 | let mut gcra_array = [0u32; 17]; | 525 | let mut gcra_array = [0u32; 17]; |
| 245 | let mut gcalr: u32 = 0; | 526 | let mut gcalr: u32 = 0; |
| @@ -258,102 +539,80 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 258 | gcalr | 539 | gcalr |
| 259 | } | 540 | } |
| 260 | 541 | ||
| 542 | /// Perform automatic gain calibration. | ||
| 261 | pub fn do_auto_calibration(&self) { | 543 | pub fn do_auto_calibration(&self) { |
| 262 | let adc = unsafe { &*I::ptr() }; | 544 | self.info |
| 263 | adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); | 545 | .ctrl() |
| 546 | .modify(|_, w| w.cal_req().calibration_request_pending()); | ||
| 264 | 547 | ||
| 265 | while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} | 548 | while self.info.gcc0().read().rdy().is_gain_cal_not_valid() {} |
| 266 | 549 | ||
| 267 | let mut gcca = adc.gcc0().read().gain_cal().bits() as u32; | 550 | let mut gcca = self.info.gcc0().read().gain_cal().bits() as u32; |
| 268 | if gcca & ((0xFFFF + 1) >> 1) != 0 { | 551 | if gcca & 0x8000 != 0 { |
| 269 | gcca |= !0xFFFF; | 552 | gcca |= !0xFFFF; |
| 270 | } | 553 | } |
| 271 | 554 | ||
| 272 | let gcra = 131072.0 / (131072.0 - gcca as f32); | 555 | let gcra = 131072.0 / (131072.0 - gcca as f32); |
| 273 | 556 | ||
| 274 | // Write to GCR0 | 557 | // Write to GCR0 |
| 275 | adc.gcr0().write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) }); | 558 | self.info |
| 559 | .gcr0() | ||
| 560 | .write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) }); | ||
| 276 | 561 | ||
| 277 | adc.gcr0().modify(|_, w| w.rdy().set_bit()); | 562 | self.info.gcr0().modify(|_, w| w.rdy().set_bit()); |
| 278 | 563 | ||
| 279 | // Wait for calibration to complete (polling status register) | 564 | // Wait for calibration to complete (polling status register) |
| 280 | while adc.stat().read().cal_rdy().is_not_set() {} | 565 | while self.info.stat().read().cal_rdy().is_not_set() {} |
| 281 | } | 566 | } |
| 282 | 567 | ||
| 283 | pub fn do_software_trigger(&self, trigger_id_mask: u32) { | 568 | fn set_conv_command_config_inner(&self, index: usize, config: &ConvCommandConfig) -> Result<()> { |
| 284 | let adc = unsafe { &*I::ptr() }; | 569 | let (cmdl, cmdh) = match index { |
| 285 | adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask) }); | 570 | 1 => (self.info.cmdl1(), self.info.cmdh1()), |
| 286 | } | 571 | 2 => (self.info.cmdl2(), self.info.cmdh2()), |
| 572 | 3 => (self.info.cmdl3(), self.info.cmdh3()), | ||
| 573 | 4 => (self.info.cmdl4(), self.info.cmdh4()), | ||
| 574 | 5 => (self.info.cmdl5(), self.info.cmdh5()), | ||
| 575 | 6 => (self.info.cmdl6(), self.info.cmdh6()), | ||
| 576 | 7 => (self.info.cmdl7(), self.info.cmdh7()), | ||
| 577 | _ => return Err(Error::InvalidConfig), | ||
| 578 | }; | ||
| 287 | 579 | ||
| 288 | pub fn get_default_conv_command_config(&self) -> ConvCommandConfig { | 580 | cmdl.write(|w| { |
| 289 | ConvCommandConfig { | 581 | unsafe { |
| 290 | sample_channel_mode: Ctype::SingleEndedASideChannel, | 582 | w.adch().bits(self.channel_idx); |
| 291 | channel_number: Adch::SelectCh0, | 583 | } |
| 292 | chained_next_command_number: Next::NoNextCmdTerminateOnFinish, | 584 | w.mode().variant(config.conversion_resolution_mode) |
| 293 | enable_auto_channel_increment: false, | 585 | }); |
| 294 | loop_count: 0, | ||
| 295 | hardware_average_mode: Avgs::NoAverage, | ||
| 296 | sample_time_mode: Sts::Sample3p5, | ||
| 297 | hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult, | ||
| 298 | hardware_compare_value_high: 0, | ||
| 299 | hardware_compare_value_low: 0, | ||
| 300 | conversion_resolution_mode: Mode::Data12Bits, | ||
| 301 | enable_wait_trigger: false, | ||
| 302 | } | ||
| 303 | } | ||
| 304 | 586 | ||
| 305 | //TBD Need to add cmdlx and cmdhx with x {2..7} | 587 | cmdh.write(|w| { |
| 306 | pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) { | 588 | w.next().variant(config.chained_next_command_number); |
| 307 | let adc = unsafe { &*I::ptr() }; | 589 | unsafe { |
| 308 | 590 | w.loop_().bits(config.loop_count); | |
| 309 | match index { | ||
| 310 | 1 => { | ||
| 311 | adc.cmdl1().write(|w| { | ||
| 312 | w.adch() | ||
| 313 | .variant(config.channel_number) | ||
| 314 | .mode() | ||
| 315 | .variant(config.conversion_resolution_mode) | ||
| 316 | }); | ||
| 317 | adc.cmdh1().write(|w| unsafe { | ||
| 318 | w.next() | ||
| 319 | .variant(config.chained_next_command_number) | ||
| 320 | .loop_() | ||
| 321 | .bits(config.loop_count) | ||
| 322 | .avgs() | ||
| 323 | .variant(config.hardware_average_mode) | ||
| 324 | .sts() | ||
| 325 | .variant(config.sample_time_mode) | ||
| 326 | .cmpen() | ||
| 327 | .variant(config.hardware_compare_mode); | ||
| 328 | if config.enable_wait_trigger { | ||
| 329 | w.wait_trig().enabled(); | ||
| 330 | } | ||
| 331 | if config.enable_auto_channel_increment { | ||
| 332 | w.lwi().enabled(); | ||
| 333 | } | ||
| 334 | w | ||
| 335 | }); | ||
| 336 | } | 591 | } |
| 337 | _ => panic!("Invalid command index: must be between 1 and 7"), | 592 | w.avgs().variant(config.hardware_average_mode); |
| 338 | } | 593 | w.sts().variant(config.sample_time_mode); |
| 594 | w.cmpen().variant(config.hardware_compare_mode); | ||
| 595 | w.wait_trig().bit(config.enable_wait_trigger); | ||
| 596 | w.lwi().bit(config.enable_auto_channel_increment); | ||
| 597 | w | ||
| 598 | }); | ||
| 599 | |||
| 600 | Ok(()) | ||
| 339 | } | 601 | } |
| 340 | 602 | ||
| 341 | pub fn get_default_conv_trigger_config(&self) -> ConvTriggerConfig { | 603 | fn set_conv_trigger_config_inner(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> { |
| 342 | ConvTriggerConfig { | 604 | // 0..4 are valid |
| 343 | target_command_id: Tcmd::NotValid, | 605 | if trigger_id >= 4 { |
| 344 | delay_power: 0, | 606 | return Err(Error::InvalidConfig); |
| 345 | priority: Tpri::HighestPriority, | ||
| 346 | enable_hardware_trigger: false, | ||
| 347 | } | 607 | } |
| 348 | } | ||
| 349 | 608 | ||
| 350 | pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) { | 609 | let tctrl = &self.info.tctrl(trigger_id); |
| 351 | let adc = unsafe { &*I::ptr() }; | ||
| 352 | let tctrl = &adc.tctrl(trigger_id); | ||
| 353 | 610 | ||
| 354 | tctrl.write(|w| unsafe { | 611 | tctrl.write(|w| { |
| 355 | let w = w.tcmd().variant(config.target_command_id); | 612 | w.tcmd().variant(config.target_command_id); |
| 356 | let w = w.tdly().bits(config.delay_power); | 613 | unsafe { |
| 614 | w.tdly().bits(config.delay_power); | ||
| 615 | } | ||
| 357 | w.tpri().variant(config.priority); | 616 | w.tpri().variant(config.priority); |
| 358 | if config.enable_hardware_trigger { | 617 | if config.enable_hardware_trigger { |
| 359 | w.hten().enabled() | 618 | w.hten().enabled() |
| @@ -361,49 +620,230 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 361 | w | 620 | w |
| 362 | } | 621 | } |
| 363 | }); | 622 | }); |
| 364 | } | ||
| 365 | 623 | ||
| 366 | pub fn do_reset_fifo(&self) { | 624 | Ok(()) |
| 367 | let adc = unsafe { &*I::ptr() }; | ||
| 368 | adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); | ||
| 369 | } | 625 | } |
| 370 | 626 | ||
| 371 | pub fn enable_interrupt(&self, mask: u32) { | 627 | /// Get conversion result from FIFO. |
| 372 | let adc = unsafe { &*I::ptr() }; | 628 | /// |
| 373 | adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); | 629 | /// Reads and returns the next conversion result from the FIFO. |
| 374 | INTERRUPT_TRIGGERED.store(false, Ordering::SeqCst); | 630 | /// Returns `None` if the FIFO is empty. |
| 375 | } | 631 | /// |
| 632 | /// # Returns | ||
| 633 | /// - `Some(ConvResult)` if a result is available | ||
| 634 | /// - `Err(Error::FifoEmpty)` if the FIFO is empty | ||
| 635 | fn get_conv_result_inner(&self) -> Result<ConvResult> { | ||
| 636 | let fifo = self.info.resfifo0().read(); | ||
| 637 | if !fifo.valid().is_valid() { | ||
| 638 | return Err(Error::FifoEmpty); | ||
| 639 | } | ||
| 376 | 640 | ||
| 377 | pub fn is_interrupt_triggered(&self) -> bool { | 641 | Ok(ConvResult { |
| 378 | INTERRUPT_TRIGGERED.load(Ordering::Relaxed) | 642 | command_id_source: fifo.cmdsrc().bits(), |
| 643 | loop_count_index: fifo.loopcnt().bits(), | ||
| 644 | trigger_id_source: fifo.tsrc().bits(), | ||
| 645 | conv_value: fifo.d().bits(), | ||
| 646 | }) | ||
| 379 | } | 647 | } |
| 380 | } | 648 | } |
| 381 | 649 | ||
| 382 | pub fn get_conv_result() -> Option<ConvResult> { | 650 | impl<T: Instance> Handler<T::Interrupt> for InterruptHandler<T> { |
| 383 | let adc = unsafe { &*pac::Adc1::ptr() }; | 651 | unsafe fn on_interrupt() { |
| 384 | let fifo = adc.resfifo0().read().bits(); | 652 | T::ptr().ie().modify(|_r, w| w.fwmie0().clear_bit()); |
| 385 | const VALID_MASK: u32 = 1 << 31; | 653 | T::wait_cell().wake(); |
| 386 | if fifo & VALID_MASK == 0 { | ||
| 387 | return None; | ||
| 388 | } | 654 | } |
| 655 | } | ||
| 389 | 656 | ||
| 390 | Some(ConvResult { | 657 | mod sealed { |
| 391 | command_id_source: (fifo >> 24) & 0x0F, | 658 | /// Seal a trait |
| 392 | loop_count_index: (fifo >> 20) & 0x0F, | 659 | pub trait Sealed {} |
| 393 | trigger_id_source: (fifo >> 16) & 0x0F, | ||
| 394 | conv_value: (fifo & 0xFFFF) as u16, | ||
| 395 | }) | ||
| 396 | } | 660 | } |
| 397 | 661 | ||
| 398 | pub fn on_interrupt() { | 662 | impl<I: GpioPin> sealed::Sealed for I {} |
| 399 | if get_conv_result().is_some() { | 663 | |
| 400 | INTERRUPT_TRIGGERED.store(true, Ordering::SeqCst); | 664 | trait SealedInstance { |
| 401 | } | 665 | fn ptr() -> &'static pac::adc0::RegisterBlock; |
| 666 | fn wait_cell() -> &'static WaitCell; | ||
| 402 | } | 667 | } |
| 403 | 668 | ||
| 404 | pub struct AdcHandler; | 669 | /// ADC Instance |
| 405 | impl crate::interrupt::typelevel::Handler<crate::interrupt::typelevel::ADC1> for AdcHandler { | 670 | #[allow(private_bounds)] |
| 406 | unsafe fn on_interrupt() { | 671 | pub trait Instance: SealedInstance + PeripheralType + Gate<MrccPeriphConfig = AdcConfig> { |
| 407 | on_interrupt(); | 672 | /// Interrupt for this ADC instance. |
| 408 | } | 673 | type Interrupt: Interrupt; |
| 409 | } | 674 | } |
| 675 | |||
| 676 | macro_rules! impl_instance { | ||
| 677 | ($($n:expr),*) => { | ||
| 678 | $( | ||
| 679 | paste!{ | ||
| 680 | impl SealedInstance for crate::peripherals::[<ADC $n>] { | ||
| 681 | fn ptr() -> &'static pac::adc0::RegisterBlock { | ||
| 682 | unsafe { &*pac::[<Adc $n>]::ptr() } | ||
| 683 | } | ||
| 684 | |||
| 685 | fn wait_cell() -> &'static WaitCell { | ||
| 686 | static WAIT_CELL: WaitCell = WaitCell::new(); | ||
| 687 | &WAIT_CELL | ||
| 688 | } | ||
| 689 | |||
| 690 | } | ||
| 691 | |||
| 692 | impl Instance for crate::peripherals::[<ADC $n>] { | ||
| 693 | type Interrupt = crate::interrupt::typelevel::[<ADC $n>]; | ||
| 694 | } | ||
| 695 | } | ||
| 696 | )* | ||
| 697 | }; | ||
| 698 | } | ||
| 699 | |||
| 700 | impl_instance!(0, 1, 2, 3); | ||
| 701 | |||
| 702 | pub trait AdcPin<Instance>: GpioPin + sealed::Sealed + PeripheralType { | ||
| 703 | const CHANNEL: u8; | ||
| 704 | |||
| 705 | /// Set the given pin to the correct muxing state | ||
| 706 | fn mux(&self); | ||
| 707 | } | ||
| 708 | |||
| 709 | /// Driver mode. | ||
| 710 | #[allow(private_bounds)] | ||
| 711 | pub trait ModeAdc: sealed::Sealed {} | ||
| 712 | |||
| 713 | /// Blocking mode. | ||
| 714 | pub struct Blocking; | ||
| 715 | impl sealed::Sealed for Blocking {} | ||
| 716 | impl ModeAdc for Blocking {} | ||
| 717 | |||
| 718 | /// Async mode. | ||
| 719 | pub struct Async { | ||
| 720 | waiter: &'static WaitCell, | ||
| 721 | } | ||
| 722 | impl sealed::Sealed for Async {} | ||
| 723 | impl ModeAdc for Async {} | ||
| 724 | |||
| 725 | macro_rules! impl_pin { | ||
| 726 | ($pin:ident, $peri:ident, $func:ident, $channel:literal) => { | ||
| 727 | impl AdcPin<crate::peripherals::$peri> for crate::peripherals::$pin { | ||
| 728 | const CHANNEL: u8 = $channel; | ||
| 729 | |||
| 730 | fn mux(&self) { | ||
| 731 | self.set_pull(crate::gpio::Pull::Disabled); | ||
| 732 | self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); | ||
| 733 | self.set_drive_strength(crate::gpio::DriveStrength::Normal.into()); | ||
| 734 | self.set_function(crate::pac::port0::pcr0::Mux::$func); | ||
| 735 | } | ||
| 736 | } | ||
| 737 | }; | ||
| 738 | } | ||
| 739 | |||
| 740 | impl_pin!(P2_0, ADC0, Mux0, 0); | ||
| 741 | impl_pin!(P2_4, ADC0, Mux0, 1); | ||
| 742 | impl_pin!(P2_15, ADC0, Mux0, 2); | ||
| 743 | impl_pin!(P2_3, ADC0, Mux0, 3); | ||
| 744 | impl_pin!(P2_2, ADC0, Mux0, 4); | ||
| 745 | impl_pin!(P2_12, ADC0, Mux0, 5); | ||
| 746 | impl_pin!(P2_16, ADC0, Mux0, 6); | ||
| 747 | impl_pin!(P2_7, ADC0, Mux0, 7); | ||
| 748 | impl_pin!(P0_18, ADC0, Mux0, 8); | ||
| 749 | impl_pin!(P0_19, ADC0, Mux0, 9); | ||
| 750 | impl_pin!(P0_20, ADC0, Mux0, 10); | ||
| 751 | impl_pin!(P0_21, ADC0, Mux0, 11); | ||
| 752 | impl_pin!(P0_22, ADC0, Mux0, 12); | ||
| 753 | impl_pin!(P0_23, ADC0, Mux0, 13); | ||
| 754 | impl_pin!(P0_3, ADC0, Mux0, 14); | ||
| 755 | impl_pin!(P0_6, ADC0, Mux0, 15); | ||
| 756 | impl_pin!(P1_0, ADC0, Mux0, 16); | ||
| 757 | impl_pin!(P1_1, ADC0, Mux0, 17); | ||
| 758 | impl_pin!(P1_2, ADC0, Mux0, 18); | ||
| 759 | impl_pin!(P1_3, ADC0, Mux0, 19); | ||
| 760 | impl_pin!(P1_4, ADC0, Mux0, 20); | ||
| 761 | impl_pin!(P1_5, ADC0, Mux0, 21); | ||
| 762 | impl_pin!(P1_6, ADC0, Mux0, 22); | ||
| 763 | impl_pin!(P1_7, ADC0, Mux0, 23); | ||
| 764 | |||
| 765 | // ??? | ||
| 766 | // impl_pin!(P1_10, ADC0, Mux0, 255); | ||
| 767 | |||
| 768 | impl_pin!(P2_1, ADC1, Mux0, 0); | ||
| 769 | impl_pin!(P2_5, ADC1, Mux0, 1); | ||
| 770 | impl_pin!(P2_19, ADC1, Mux0, 2); | ||
| 771 | impl_pin!(P2_6, ADC1, Mux0, 3); | ||
| 772 | impl_pin!(P2_3, ADC1, Mux0, 4); | ||
| 773 | impl_pin!(P2_13, ADC1, Mux0, 5); | ||
| 774 | impl_pin!(P2_17, ADC1, Mux0, 6); | ||
| 775 | impl_pin!(P2_7, ADC1, Mux0, 7); | ||
| 776 | impl_pin!(P1_10, ADC1, Mux0, 8); | ||
| 777 | impl_pin!(P1_11, ADC1, Mux0, 9); | ||
| 778 | impl_pin!(P1_12, ADC1, Mux0, 10); | ||
| 779 | impl_pin!(P1_13, ADC1, Mux0, 11); | ||
| 780 | impl_pin!(P1_14, ADC1, Mux0, 12); | ||
| 781 | impl_pin!(P1_15, ADC1, Mux0, 13); | ||
| 782 | // ??? | ||
| 783 | // impl_pin!(P1_16, ADC1, Mux0, 255); | ||
| 784 | // impl_pin!(P1_17, ADC1, Mux0, 255); | ||
| 785 | // impl_pin!(P1_18, ADC1, Mux0, 255); | ||
| 786 | // impl_pin!(P1_19, ADC1, Mux0, 255); | ||
| 787 | // ??? | ||
| 788 | impl_pin!(P3_31, ADC1, Mux0, 20); | ||
| 789 | impl_pin!(P3_30, ADC1, Mux0, 21); | ||
| 790 | impl_pin!(P3_29, ADC1, Mux0, 22); | ||
| 791 | |||
| 792 | impl_pin!(P2_4, ADC2, Mux0, 0); | ||
| 793 | impl_pin!(P2_10, ADC2, Mux0, 1); | ||
| 794 | impl_pin!(P4_4, ADC2, Mux0, 2); | ||
| 795 | // impl_pin!(P2_24, ADC2, Mux0, 255); ??? | ||
| 796 | impl_pin!(P2_16, ADC2, Mux0, 4); | ||
| 797 | impl_pin!(P2_12, ADC2, Mux0, 5); | ||
| 798 | impl_pin!(P2_20, ADC2, Mux0, 6); | ||
| 799 | impl_pin!(P2_7, ADC2, Mux0, 7); | ||
| 800 | impl_pin!(P0_2, ADC2, Mux0, 8); | ||
| 801 | // ??? | ||
| 802 | // impl_pin!(P0_4, ADC2, Mux0, 255); | ||
| 803 | // impl_pin!(P0_5, ADC2, Mux0, 255); | ||
| 804 | // impl_pin!(P0_6, ADC2, Mux0, 255); | ||
| 805 | // impl_pin!(P0_7, ADC2, Mux0, 255); | ||
| 806 | // impl_pin!(P0_12, ADC2, Mux0, 255); | ||
| 807 | // impl_pin!(P0_13, ADC2, Mux0, 255); | ||
| 808 | // ??? | ||
| 809 | impl_pin!(P0_14, ADC2, Mux0, 14); | ||
| 810 | impl_pin!(P0_15, ADC2, Mux0, 15); | ||
| 811 | // ??? | ||
| 812 | // impl_pin!(P4_0, ADC2, Mux0, 255); | ||
| 813 | // impl_pin!(P4_1, ADC2, Mux0, 255); | ||
| 814 | // ??? | ||
| 815 | impl_pin!(P4_2, ADC2, Mux0, 18); | ||
| 816 | impl_pin!(P4_3, ADC2, Mux0, 19); | ||
| 817 | //impl_pin!(P4_4, ADC2, Mux0, 20); // Conflit with ADC2_A3 and ADC2_A20 using the same pin | ||
| 818 | impl_pin!(P4_5, ADC2, Mux0, 21); | ||
| 819 | impl_pin!(P4_6, ADC2, Mux0, 22); | ||
| 820 | impl_pin!(P4_7, ADC2, Mux0, 23); | ||
| 821 | |||
| 822 | impl_pin!(P2_5, ADC3, Mux0, 0); | ||
| 823 | impl_pin!(P2_11, ADC3, Mux0, 1); | ||
| 824 | impl_pin!(P2_23, ADC3, Mux0, 2); | ||
| 825 | // impl_pin!(P2_25, ADC3, Mux0, 255); // ??? | ||
| 826 | impl_pin!(P2_17, ADC3, Mux0, 4); | ||
| 827 | impl_pin!(P2_13, ADC3, Mux0, 5); | ||
| 828 | impl_pin!(P2_21, ADC3, Mux0, 6); | ||
| 829 | impl_pin!(P2_7, ADC3, Mux0, 7); | ||
| 830 | // ??? | ||
| 831 | // impl_pin!(P3_2, ADC3, Mux0, 255); | ||
| 832 | // impl_pin!(P3_3, ADC3, Mux0, 255); | ||
| 833 | // impl_pin!(P3_4, ADC3, Mux0, 255); | ||
| 834 | // impl_pin!(P3_5, ADC3, Mux0, 255); | ||
| 835 | // ??? | ||
| 836 | impl_pin!(P3_6, ADC3, Mux0, 12); | ||
| 837 | impl_pin!(P3_7, ADC3, Mux0, 13); | ||
| 838 | impl_pin!(P3_12, ADC3, Mux0, 14); | ||
| 839 | impl_pin!(P3_13, ADC3, Mux0, 15); | ||
| 840 | impl_pin!(P3_14, ADC3, Mux0, 16); | ||
| 841 | impl_pin!(P3_15, ADC3, Mux0, 17); | ||
| 842 | impl_pin!(P3_20, ADC3, Mux0, 18); | ||
| 843 | impl_pin!(P3_21, ADC3, Mux0, 19); | ||
| 844 | impl_pin!(P3_22, ADC3, Mux0, 20); | ||
| 845 | // ??? | ||
| 846 | // impl_pin!(P3_23, ADC3, Mux0, 255); | ||
| 847 | // impl_pin!(P3_24, ADC3, Mux0, 255); | ||
| 848 | // impl_pin!(P3_25, ADC3, Mux0, 255); | ||
| 849 | // ??? | ||
diff --git a/embassy-mcxa/src/clocks/mod.rs b/embassy-mcxa/src/clocks/mod.rs index 9288f5dc1..b96d9612a 100644 --- a/embassy-mcxa/src/clocks/mod.rs +++ b/embassy-mcxa/src/clocks/mod.rs | |||
| @@ -945,7 +945,10 @@ pub(crate) mod gate { | |||
| 945 | impl_cc_gate!(LPUART3, mrcc_glb_cc0, mrcc_glb_rst0, lpuart3, LpuartConfig); | 945 | impl_cc_gate!(LPUART3, mrcc_glb_cc0, mrcc_glb_rst0, lpuart3, LpuartConfig); |
| 946 | impl_cc_gate!(LPUART4, mrcc_glb_cc0, mrcc_glb_rst0, lpuart4, LpuartConfig); | 946 | impl_cc_gate!(LPUART4, mrcc_glb_cc0, mrcc_glb_rst0, lpuart4, LpuartConfig); |
| 947 | impl_cc_gate!(LPUART5, mrcc_glb_cc1, mrcc_glb_rst1, lpuart5, LpuartConfig); | 947 | impl_cc_gate!(LPUART5, mrcc_glb_cc1, mrcc_glb_rst1, lpuart5, LpuartConfig); |
| 948 | impl_cc_gate!(ADC0, mrcc_glb_cc1, mrcc_glb_rst1, adc0, AdcConfig); | ||
| 948 | impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig); | 949 | impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig); |
| 950 | impl_cc_gate!(ADC2, mrcc_glb_cc1, mrcc_glb_rst1, adc2, AdcConfig); | ||
| 951 | impl_cc_gate!(ADC3, mrcc_glb_cc1, mrcc_glb_rst1, adc3, AdcConfig); | ||
| 949 | 952 | ||
| 950 | // DMA0 peripheral - uses NoConfig since it has no selectable clock source | 953 | // DMA0 peripheral - uses NoConfig since it has no selectable clock source |
| 951 | impl_cc_gate!(DMA0, mrcc_glb_cc0, mrcc_glb_rst0, dma0, NoConfig); | 954 | impl_cc_gate!(DMA0, mrcc_glb_cc0, mrcc_glb_rst0, dma0, NoConfig); |
diff --git a/embassy-mcxa/src/clocks/periph_helpers.rs b/embassy-mcxa/src/clocks/periph_helpers.rs index fed5e558e..f2f51c60c 100644 --- a/embassy-mcxa/src/clocks/periph_helpers.rs +++ b/embassy-mcxa/src/clocks/periph_helpers.rs | |||
| @@ -427,6 +427,7 @@ impl SPConfHelper for OsTimerConfig { | |||
| 427 | 427 | ||
| 428 | /// Selectable clocks for the ADC peripheral | 428 | /// Selectable clocks for the ADC peripheral |
| 429 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 429 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
| 430 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 430 | pub enum AdcClockSel { | 431 | pub enum AdcClockSel { |
| 431 | /// Divided `fro_lf`/`clk_12m`/FRO12M source | 432 | /// Divided `fro_lf`/`clk_12m`/FRO12M source |
| 432 | FroLfDiv, | 433 | FroLfDiv, |
diff --git a/embassy-mcxa/src/i2c/controller.rs b/embassy-mcxa/src/i2c/controller.rs index c27d508b0..62789f85f 100644 --- a/embassy-mcxa/src/i2c/controller.rs +++ b/embassy-mcxa/src/i2c/controller.rs | |||
| @@ -8,9 +8,9 @@ use embassy_hal_internal::drop::OnDrop; | |||
| 8 | use mcxa_pac::lpi2c0::mtdr::Cmd; | 8 | use mcxa_pac::lpi2c0::mtdr::Cmd; |
| 9 | 9 | ||
| 10 | use super::{Async, Blocking, Error, Instance, InterruptHandler, Mode, Result, SclPin, SdaPin}; | 10 | use super::{Async, Blocking, Error, Instance, InterruptHandler, Mode, Result, SclPin, SdaPin}; |
| 11 | use crate::AnyPin; | ||
| 12 | use crate::clocks::periph_helpers::{Div4, Lpi2cClockSel, Lpi2cConfig}; | 11 | use crate::clocks::periph_helpers::{Div4, Lpi2cClockSel, Lpi2cConfig}; |
| 13 | use crate::clocks::{PoweredClock, enable_and_reset}; | 12 | use crate::clocks::{PoweredClock, enable_and_reset}; |
| 13 | use crate::gpio::AnyPin; | ||
| 14 | use crate::interrupt::typelevel::Interrupt; | 14 | use crate::interrupt::typelevel::Interrupt; |
| 15 | 15 | ||
| 16 | /// Bus speed (nominal SCL, no clock stretching) | 16 | /// Bus speed (nominal SCL, no clock stretching) |
diff --git a/embassy-mcxa/src/interrupt.rs b/embassy-mcxa/src/interrupt.rs index be2704454..b662f7ee0 100644 --- a/embassy-mcxa/src/interrupt.rs +++ b/embassy-mcxa/src/interrupt.rs | |||
| @@ -9,7 +9,10 @@ | |||
| 9 | mod generated { | 9 | mod generated { |
| 10 | #[rustfmt::skip] | 10 | #[rustfmt::skip] |
| 11 | embassy_hal_internal::interrupt_mod!( | 11 | embassy_hal_internal::interrupt_mod!( |
| 12 | ADC0, | ||
| 12 | ADC1, | 13 | ADC1, |
| 14 | ADC2, | ||
| 15 | ADC3, | ||
| 13 | DMA_CH0, | 16 | DMA_CH0, |
| 14 | DMA_CH1, | 17 | DMA_CH1, |
| 15 | DMA_CH2, | 18 | DMA_CH2, |
| @@ -281,44 +284,6 @@ impl InterruptExt for Rtc { | |||
| 281 | } | 284 | } |
| 282 | } | 285 | } |
| 283 | 286 | ||
| 284 | pub struct Adc; | ||
| 285 | pub const ADC1: Adc = Adc; | ||
| 286 | |||
| 287 | impl InterruptExt for Adc { | ||
| 288 | /// Clear any pending ADC1 in NVIC. | ||
| 289 | #[inline] | ||
| 290 | fn unpend(&self) { | ||
| 291 | cortex_m::peripheral::NVIC::unpend(Interrupt::ADC1); | ||
| 292 | } | ||
| 293 | |||
| 294 | /// Set NVIC priority for ADC1. | ||
| 295 | #[inline] | ||
| 296 | fn set_priority(&self, priority: Priority) { | ||
| 297 | unsafe { | ||
| 298 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 299 | nvic.set_priority(Interrupt::ADC1, u8::from(priority)); | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | /// Enable ADC1 in NVIC. | ||
| 304 | #[inline] | ||
| 305 | unsafe fn enable(&self) { | ||
| 306 | cortex_m::peripheral::NVIC::unmask(Interrupt::ADC1); | ||
| 307 | } | ||
| 308 | |||
| 309 | /// Disable ADC1 in NVIC. | ||
| 310 | #[inline] | ||
| 311 | unsafe fn disable(&self) { | ||
| 312 | cortex_m::peripheral::NVIC::mask(Interrupt::ADC1); | ||
| 313 | } | ||
| 314 | |||
| 315 | /// Check if ADC1 is pending in NVIC. | ||
| 316 | #[inline] | ||
| 317 | fn is_pending(&self) -> bool { | ||
| 318 | cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC1) | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | pub struct Gpio0; | 287 | pub struct Gpio0; |
| 323 | pub const GPIO0: Gpio0 = Gpio0; | 288 | pub const GPIO0: Gpio0 = Gpio0; |
| 324 | 289 | ||
diff --git a/embassy-mcxa/src/lib.rs b/embassy-mcxa/src/lib.rs index 12c2708de..6383353db 100644 --- a/embassy-mcxa/src/lib.rs +++ b/embassy-mcxa/src/lib.rs | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | pub mod clocks; // still provide clock helpers | 8 | pub mod clocks; // still provide clock helpers |
| 9 | pub mod dma; | 9 | pub mod dma; |
| 10 | pub mod gpio; | 10 | pub mod gpio; |
| 11 | pub mod pins; // pin mux helpers | ||
| 12 | 11 | ||
| 13 | pub mod adc; | 12 | pub mod adc; |
| 14 | pub mod clkout; | 13 | pub mod clkout; |
| @@ -18,15 +17,19 @@ pub mod i2c; | |||
| 18 | pub mod interrupt; | 17 | pub mod interrupt; |
| 19 | pub mod lpuart; | 18 | pub mod lpuart; |
| 20 | pub mod ostimer; | 19 | pub mod ostimer; |
| 20 | pub mod reset_reason; | ||
| 21 | pub mod rtc; | 21 | pub mod rtc; |
| 22 | pub mod trng; | 22 | pub mod trng; |
| 23 | 23 | ||
| 24 | use crate::interrupt::InterruptExt; | ||
| 24 | pub use crate::pac::NVIC_PRIO_BITS; | 25 | pub use crate::pac::NVIC_PRIO_BITS; |
| 25 | 26 | ||
| 26 | #[rustfmt::skip] | 27 | #[rustfmt::skip] |
| 27 | embassy_hal_internal::peripherals!( | 28 | embassy_hal_internal::peripherals!( |
| 28 | ADC0, | 29 | ADC0, |
| 29 | ADC1, | 30 | ADC1, |
| 31 | ADC2, | ||
| 32 | ADC3, | ||
| 30 | 33 | ||
| 31 | AOI0, | 34 | AOI0, |
| 32 | AOI1, | 35 | AOI1, |
| @@ -337,9 +340,6 @@ embassy_hal_internal::peripherals!( | |||
| 337 | // Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it. | 340 | // Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it. |
| 338 | 341 | ||
| 339 | // Re-export interrupt traits and types | 342 | // Re-export interrupt traits and types |
| 340 | pub use adc::Adc1 as Adc1Token; | ||
| 341 | pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output}; | ||
| 342 | pub use interrupt::InterruptExt; | ||
| 343 | #[cfg(feature = "unstable-pac")] | 343 | #[cfg(feature = "unstable-pac")] |
| 344 | pub use mcxa_pac as pac; | 344 | pub use mcxa_pac as pac; |
| 345 | #[cfg(not(feature = "unstable-pac"))] | 345 | #[cfg(not(feature = "unstable-pac"))] |
| @@ -355,8 +355,6 @@ pub fn init(cfg: crate::config::Config) -> Peripherals { | |||
| 355 | // Apply user-configured priority early; enabling is left to examples/apps | 355 | // Apply user-configured priority early; enabling is left to examples/apps |
| 356 | crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); | 356 | crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); |
| 357 | // Apply user-configured priority early; enabling is left to examples/apps | 357 | // Apply user-configured priority early; enabling is left to examples/apps |
| 358 | crate::interrupt::ADC1.set_priority(cfg.adc_interrupt_priority); | ||
| 359 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 360 | crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority); | 358 | crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority); |
| 361 | // Apply user-configured priority early; enabling is left to examples/apps | 359 | // Apply user-configured priority early; enabling is left to examples/apps |
| 362 | crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority); | 360 | crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority); |
diff --git a/embassy-mcxa/src/lpuart/mod.rs b/embassy-mcxa/src/lpuart/mod.rs index e59ce8140..bce3986b5 100644 --- a/embassy-mcxa/src/lpuart/mod.rs +++ b/embassy-mcxa/src/lpuart/mod.rs | |||
| @@ -6,12 +6,12 @@ use paste::paste; | |||
| 6 | 6 | ||
| 7 | use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig}; | 7 | use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig}; |
| 8 | use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset}; | 8 | use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset}; |
| 9 | use crate::gpio::SealedPin; | 9 | use crate::gpio::{AnyPin, SealedPin}; |
| 10 | use crate::pac::lpuart0::baud::Sbns as StopBits; | 10 | use crate::pac::lpuart0::baud::Sbns as StopBits; |
| 11 | use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, M as DataBits, Pt as Parity}; | 11 | use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, M as DataBits, Pt as Parity}; |
| 12 | use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; | 12 | use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; |
| 13 | use crate::pac::lpuart0::stat::Msbf as MsbFirst; | 13 | use crate::pac::lpuart0::stat::Msbf as MsbFirst; |
| 14 | use crate::{AnyPin, interrupt, pac}; | 14 | use crate::{interrupt, pac}; |
| 15 | 15 | ||
| 16 | pub mod buffered; | 16 | pub mod buffered; |
| 17 | 17 | ||
diff --git a/embassy-mcxa/src/pins.rs b/embassy-mcxa/src/pins.rs deleted file mode 100644 index 9adbe64c8..000000000 --- a/embassy-mcxa/src/pins.rs +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | //! Pin configuration helpers (separate from peripheral drivers). | ||
| 2 | use crate::pac; | ||
| 3 | |||
| 4 | /// Configure pins for ADC usage. | ||
| 5 | /// | ||
| 6 | /// # Safety | ||
| 7 | /// | ||
| 8 | /// Must be called after PORT clocks are enabled. | ||
| 9 | pub unsafe fn configure_adc_pins() { | ||
| 10 | // P1_10 = ADC1_A8 | ||
| 11 | let port1 = &*pac::Port1::ptr(); | ||
| 12 | port1.pcr10().write(|w| { | ||
| 13 | w.ps() | ||
| 14 | .ps0() | ||
| 15 | .pe() | ||
| 16 | .pe0() | ||
| 17 | .sre() | ||
| 18 | .sre0() | ||
| 19 | .ode() | ||
| 20 | .ode0() | ||
| 21 | .dse() | ||
| 22 | .dse0() | ||
| 23 | .mux() | ||
| 24 | .mux0() | ||
| 25 | .ibe() | ||
| 26 | .ibe0() | ||
| 27 | .inv() | ||
| 28 | .inv0() | ||
| 29 | .lk() | ||
| 30 | .lk0() | ||
| 31 | }); | ||
| 32 | core::arch::asm!("dsb sy; isb sy"); | ||
| 33 | } | ||
diff --git a/embassy-mcxa/src/reset_reason.rs b/embassy-mcxa/src/reset_reason.rs new file mode 100644 index 000000000..f9a9ce096 --- /dev/null +++ b/embassy-mcxa/src/reset_reason.rs | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | //! Reset reason | ||
| 2 | //! | ||
| 3 | //! MCXA families keep the most recent reset reason in the SRS | ||
| 4 | //! register of the CMC block. This lets users understand why the MCU | ||
| 5 | //! has reset and take appropriate corrective actions if required. | ||
| 6 | |||
| 7 | /// Reads the most recent reset reason from the Core Mode Controller | ||
| 8 | /// (CMC). | ||
| 9 | pub fn reset_reason() -> ResetReason { | ||
| 10 | let regs = unsafe { &*crate::pac::Cmc::steal() }; | ||
| 11 | |||
| 12 | let srs = regs.srs().read(); | ||
| 13 | |||
| 14 | if srs.wakeup().is_enabled() { | ||
| 15 | ResetReason::WakeUp | ||
| 16 | } else if srs.por().bit_is_set() { | ||
| 17 | ResetReason::Por | ||
| 18 | } else if srs.vd().bit_is_set() { | ||
| 19 | ResetReason::VoltageDetect | ||
| 20 | } else if srs.warm().bit_is_set() { | ||
| 21 | ResetReason::Warm | ||
| 22 | } else if srs.fatal().bit_is_set() { | ||
| 23 | ResetReason::Fatal | ||
| 24 | } else if srs.pin().bit_is_set() { | ||
| 25 | ResetReason::Pin | ||
| 26 | } else if srs.dap().bit_is_set() { | ||
| 27 | ResetReason::Dap | ||
| 28 | } else if srs.rstack().bit_is_set() { | ||
| 29 | ResetReason::ResetAckTimeout | ||
| 30 | } else if srs.lpack().bit_is_set() { | ||
| 31 | ResetReason::LowPowerAckTimeout | ||
| 32 | } else if srs.scg().bit_is_set() { | ||
| 33 | ResetReason::SystemClockGeneration | ||
| 34 | } else if srs.wwdt0().bit_is_set() { | ||
| 35 | ResetReason::Wwdt0 | ||
| 36 | } else if srs.sw().bit_is_set() { | ||
| 37 | ResetReason::Software | ||
| 38 | } else if srs.lockup().bit_is_set() { | ||
| 39 | ResetReason::Lockup | ||
| 40 | } else if srs.cdog0().bit_is_set() { | ||
| 41 | ResetReason::Cdog0 | ||
| 42 | } else if srs.cdog1().bit_is_set() { | ||
| 43 | ResetReason::Cdog1 | ||
| 44 | } else if srs.jtag().bit_is_set() { | ||
| 45 | ResetReason::Jtag | ||
| 46 | } else { | ||
| 47 | ResetReason::Tamper | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | /// Indicates the type and source of the most recent reset. | ||
| 52 | #[derive(Clone, Copy, Debug)] | ||
| 53 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 54 | #[non_exhaustive] | ||
| 55 | pub enum ResetReason { | ||
| 56 | /// Tamper reset. | ||
| 57 | Tamper, | ||
| 58 | |||
| 59 | /// JTAG System Reset request. | ||
| 60 | Jtag, | ||
| 61 | |||
| 62 | /// Code Watchdog 0 reset. | ||
| 63 | Cdog0, | ||
| 64 | |||
| 65 | /// Code Watchdog 1 reset. | ||
| 66 | Cdog1, | ||
| 67 | |||
| 68 | /// Lockup reset. | ||
| 69 | Lockup, | ||
| 70 | |||
| 71 | /// Software reset. | ||
| 72 | Software, | ||
| 73 | |||
| 74 | /// Windowed Watchdog 0 reset. | ||
| 75 | Wwdt0, | ||
| 76 | |||
| 77 | /// System clock generation reset. | ||
| 78 | SystemClockGeneration, | ||
| 79 | |||
| 80 | /// Low Power Acknowledge Timeout reset. | ||
| 81 | LowPowerAckTimeout, | ||
| 82 | |||
| 83 | /// Reset Timeout. | ||
| 84 | ResetAckTimeout, | ||
| 85 | |||
| 86 | /// Debug Access Port reset. | ||
| 87 | Dap, | ||
| 88 | |||
| 89 | /// External assertion of RESET_b pin. | ||
| 90 | Pin, | ||
| 91 | |||
| 92 | /// Fatal reset. | ||
| 93 | Fatal, | ||
| 94 | |||
| 95 | /// Warm reset. | ||
| 96 | Warm, | ||
| 97 | |||
| 98 | /// Voltage detect reset. | ||
| 99 | VoltageDetect, | ||
| 100 | |||
| 101 | /// Power-on reset. | ||
| 102 | Por, | ||
| 103 | |||
| 104 | /// Wake-up reset. | ||
| 105 | WakeUp, | ||
| 106 | } | ||
diff --git a/embassy-mcxa/src/rtc.rs b/embassy-mcxa/src/rtc.rs index f975d9c9f..c5474d34a 100644 --- a/embassy-mcxa/src/rtc.rs +++ b/embassy-mcxa/src/rtc.rs | |||
| @@ -9,8 +9,6 @@ use crate::interrupt::typelevel::{Handler, Interrupt}; | |||
| 9 | use crate::pac; | 9 | use crate::pac; |
| 10 | use crate::pac::rtc0::cr::Um; | 10 | use crate::pac::rtc0::cr::Um; |
| 11 | 11 | ||
| 12 | type Regs = pac::rtc0::RegisterBlock; | ||
| 13 | |||
| 14 | /// Global wait cell for alarm notifications | 12 | /// Global wait cell for alarm notifications |
| 15 | static WAKER: WaitCell = WaitCell::new(); | 13 | static WAKER: WaitCell = WaitCell::new(); |
| 16 | 14 | ||
| @@ -22,7 +20,7 @@ pub struct InterruptHandler<I: Instance> { | |||
| 22 | /// Trait for RTC peripheral instances | 20 | /// Trait for RTC peripheral instances |
| 23 | pub trait Instance: PeripheralType { | 21 | pub trait Instance: PeripheralType { |
| 24 | type Interrupt: Interrupt; | 22 | type Interrupt: Interrupt; |
| 25 | fn ptr() -> *const Regs; | 23 | fn ptr() -> &'static pac::rtc0::RegisterBlock; |
| 26 | } | 24 | } |
| 27 | 25 | ||
| 28 | /// Token for RTC0 | 26 | /// Token for RTC0 |
| @@ -30,8 +28,8 @@ pub type Rtc0 = crate::peripherals::RTC0; | |||
| 30 | impl Instance for crate::peripherals::RTC0 { | 28 | impl Instance for crate::peripherals::RTC0 { |
| 31 | type Interrupt = crate::interrupt::typelevel::RTC; | 29 | type Interrupt = crate::interrupt::typelevel::RTC; |
| 32 | #[inline(always)] | 30 | #[inline(always)] |
| 33 | fn ptr() -> *const Regs { | 31 | fn ptr() -> &'static pac::rtc0::RegisterBlock { |
| 34 | pac::Rtc0::ptr() | 32 | unsafe { &*pac::Rtc0::ptr() } |
| 35 | } | 33 | } |
| 36 | } | 34 | } |
| 37 | 35 | ||
| @@ -204,18 +202,19 @@ pub fn get_default_config() -> RtcConfig { | |||
| 204 | } | 202 | } |
| 205 | } | 203 | } |
| 206 | /// Minimal RTC handle for a specific instance I (store the zero-sized token like embassy) | 204 | /// Minimal RTC handle for a specific instance I (store the zero-sized token like embassy) |
| 207 | pub struct Rtc<'a, I: Instance> { | 205 | pub struct Rtc<'a> { |
| 208 | _inst: core::marker::PhantomData<&'a mut I>, | 206 | _inst: core::marker::PhantomData<&'a mut ()>, |
| 207 | info: &'static pac::rtc0::RegisterBlock, | ||
| 209 | } | 208 | } |
| 210 | 209 | ||
| 211 | impl<'a, I: Instance> Rtc<'a, I> { | 210 | impl<'a> Rtc<'a> { |
| 212 | /// Create a new instance of the real time clock. | 211 | /// Create a new instance of the real time clock. |
| 213 | pub fn new( | 212 | pub fn new<I: Instance>( |
| 214 | _inst: Peri<'a, I>, | 213 | _inst: Peri<'a, I>, |
| 215 | _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a, | 214 | _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a, |
| 216 | config: RtcConfig, | 215 | config: RtcConfig, |
| 217 | ) -> Self { | 216 | ) -> Self { |
| 218 | let rtc = unsafe { &*I::ptr() }; | 217 | let info = I::ptr(); |
| 219 | 218 | ||
| 220 | // The RTC is NOT gated by the MRCC, but we DO need to make sure the 16k clock | 219 | // The RTC is NOT gated by the MRCC, but we DO need to make sure the 16k clock |
| 221 | // on the vsys domain is active | 220 | // on the vsys domain is active |
| @@ -227,13 +226,13 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 227 | } | 226 | } |
| 228 | 227 | ||
| 229 | // RTC reset | 228 | // RTC reset |
| 230 | rtc.cr().modify(|_, w| w.swr().set_bit()); | 229 | info.cr().modify(|_, w| w.swr().set_bit()); |
| 231 | rtc.cr().modify(|_, w| w.swr().clear_bit()); | 230 | info.cr().modify(|_, w| w.swr().clear_bit()); |
| 232 | rtc.tsr().write(|w| unsafe { w.bits(1) }); | 231 | info.tsr().write(|w| unsafe { w.bits(1) }); |
| 233 | 232 | ||
| 234 | rtc.cr().modify(|_, w| w.um().variant(config.update_mode)); | 233 | info.cr().modify(|_, w| w.um().variant(config.update_mode)); |
| 235 | 234 | ||
| 236 | rtc.tcr().modify(|_, w| unsafe { | 235 | info.tcr().modify(|_, w| unsafe { |
| 237 | w.cir() | 236 | w.cir() |
| 238 | .bits(config.compensation_interval) | 237 | .bits(config.compensation_interval) |
| 239 | .tcr() | 238 | .tcr() |
| @@ -246,6 +245,7 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 246 | 245 | ||
| 247 | Self { | 246 | Self { |
| 248 | _inst: core::marker::PhantomData, | 247 | _inst: core::marker::PhantomData, |
| 248 | info, | ||
| 249 | } | 249 | } |
| 250 | } | 250 | } |
| 251 | 251 | ||
| @@ -259,9 +259,8 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 259 | /// | 259 | /// |
| 260 | /// The datetime is converted to Unix timestamp and written to the time seconds register. | 260 | /// The datetime is converted to Unix timestamp and written to the time seconds register. |
| 261 | pub fn set_datetime(&self, datetime: RtcDateTime) { | 261 | pub fn set_datetime(&self, datetime: RtcDateTime) { |
| 262 | let rtc = unsafe { &*I::ptr() }; | ||
| 263 | let seconds = convert_datetime_to_seconds(&datetime); | 262 | let seconds = convert_datetime_to_seconds(&datetime); |
| 264 | rtc.tsr().write(|w| unsafe { w.bits(seconds) }); | 263 | self.info.tsr().write(|w| unsafe { w.bits(seconds) }); |
| 265 | } | 264 | } |
| 266 | 265 | ||
| 267 | /// Get the current date and time | 266 | /// Get the current date and time |
| @@ -274,8 +273,7 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 274 | /// | 273 | /// |
| 275 | /// Reads the current Unix timestamp from the time seconds register and converts it. | 274 | /// Reads the current Unix timestamp from the time seconds register and converts it. |
| 276 | pub fn get_datetime(&self) -> RtcDateTime { | 275 | pub fn get_datetime(&self) -> RtcDateTime { |
| 277 | let rtc = unsafe { &*I::ptr() }; | 276 | let seconds = self.info.tsr().read().bits(); |
| 278 | let seconds = rtc.tsr().read().bits(); | ||
| 279 | convert_seconds_to_datetime(seconds) | 277 | convert_seconds_to_datetime(seconds) |
| 280 | } | 278 | } |
| 281 | 279 | ||
| @@ -295,19 +293,18 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 295 | /// - Uses timeouts to prevent infinite loops | 293 | /// - Uses timeouts to prevent infinite loops |
| 296 | /// - Enables the alarm interrupt after setting | 294 | /// - Enables the alarm interrupt after setting |
| 297 | pub fn set_alarm(&self, alarm: RtcDateTime) { | 295 | pub fn set_alarm(&self, alarm: RtcDateTime) { |
| 298 | let rtc = unsafe { &*I::ptr() }; | ||
| 299 | let seconds = convert_datetime_to_seconds(&alarm); | 296 | let seconds = convert_datetime_to_seconds(&alarm); |
| 300 | 297 | ||
| 301 | rtc.tar().write(|w| unsafe { w.bits(0) }); | 298 | self.info.tar().write(|w| unsafe { w.bits(0) }); |
| 302 | let mut timeout = 10000; | 299 | let mut timeout = 10000; |
| 303 | while rtc.tar().read().bits() != 0 && timeout > 0 { | 300 | while self.info.tar().read().bits() != 0 && timeout > 0 { |
| 304 | timeout -= 1; | 301 | timeout -= 1; |
| 305 | } | 302 | } |
| 306 | 303 | ||
| 307 | rtc.tar().write(|w| unsafe { w.bits(seconds) }); | 304 | self.info.tar().write(|w| unsafe { w.bits(seconds) }); |
| 308 | 305 | ||
| 309 | let mut timeout = 10000; | 306 | let mut timeout = 10000; |
| 310 | while rtc.tar().read().bits() != seconds && timeout > 0 { | 307 | while self.info.tar().read().bits() != seconds && timeout > 0 { |
| 311 | timeout -= 1; | 308 | timeout -= 1; |
| 312 | } | 309 | } |
| 313 | 310 | ||
| @@ -324,8 +321,7 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 324 | /// | 321 | /// |
| 325 | /// Reads the alarm timestamp from the time alarm register and converts it. | 322 | /// Reads the alarm timestamp from the time alarm register and converts it. |
| 326 | pub fn get_alarm(&self) -> RtcDateTime { | 323 | pub fn get_alarm(&self) -> RtcDateTime { |
| 327 | let rtc = unsafe { &*I::ptr() }; | 324 | let alarm_seconds = self.info.tar().read().bits(); |
| 328 | let alarm_seconds = rtc.tar().read().bits(); | ||
| 329 | convert_seconds_to_datetime(alarm_seconds) | 325 | convert_seconds_to_datetime(alarm_seconds) |
| 330 | } | 326 | } |
| 331 | 327 | ||
| @@ -335,8 +331,7 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 335 | /// | 331 | /// |
| 336 | /// Sets the Time Counter Enable (TCE) bit in the status register. | 332 | /// Sets the Time Counter Enable (TCE) bit in the status register. |
| 337 | pub fn start(&self) { | 333 | pub fn start(&self) { |
| 338 | let rtc = unsafe { &*I::ptr() }; | 334 | self.info.sr().modify(|_, w| w.tce().set_bit()); |
| 339 | rtc.sr().modify(|_, w| w.tce().set_bit()); | ||
| 340 | } | 335 | } |
| 341 | 336 | ||
| 342 | /// Stop the RTC time counter | 337 | /// Stop the RTC time counter |
| @@ -345,8 +340,7 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 345 | /// | 340 | /// |
| 346 | /// Clears the Time Counter Enable (TCE) bit in the status register. | 341 | /// Clears the Time Counter Enable (TCE) bit in the status register. |
| 347 | pub fn stop(&self) { | 342 | pub fn stop(&self) { |
| 348 | let rtc = unsafe { &*I::ptr() }; | 343 | self.info.sr().modify(|_, w| w.tce().clear_bit()); |
| 349 | rtc.sr().modify(|_, w| w.tce().clear_bit()); | ||
| 350 | } | 344 | } |
| 351 | 345 | ||
| 352 | /// Enable specific RTC interrupts | 346 | /// Enable specific RTC interrupts |
| @@ -364,19 +358,17 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 364 | /// - Alarm Interrupt | 358 | /// - Alarm Interrupt |
| 365 | /// - Seconds Interrupt | 359 | /// - Seconds Interrupt |
| 366 | pub fn set_interrupt(&self, mask: u32) { | 360 | pub fn set_interrupt(&self, mask: u32) { |
| 367 | let rtc = unsafe { &*I::ptr() }; | ||
| 368 | |||
| 369 | if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 { | 361 | if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 { |
| 370 | rtc.ier().modify(|_, w| w.tiie().tiie_1()); | 362 | self.info.ier().modify(|_, w| w.tiie().tiie_1()); |
| 371 | } | 363 | } |
| 372 | if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 { | 364 | if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 { |
| 373 | rtc.ier().modify(|_, w| w.toie().toie_1()); | 365 | self.info.ier().modify(|_, w| w.toie().toie_1()); |
| 374 | } | 366 | } |
| 375 | if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 { | 367 | if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 { |
| 376 | rtc.ier().modify(|_, w| w.taie().taie_1()); | 368 | self.info.ier().modify(|_, w| w.taie().taie_1()); |
| 377 | } | 369 | } |
| 378 | if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 { | 370 | if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 { |
| 379 | rtc.ier().modify(|_, w| w.tsie().tsie_1()); | 371 | self.info.ier().modify(|_, w| w.tsie().tsie_1()); |
| 380 | } | 372 | } |
| 381 | } | 373 | } |
| 382 | 374 | ||
| @@ -390,19 +382,17 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 390 | /// | 382 | /// |
| 391 | /// This function disables the specified interrupt types. | 383 | /// This function disables the specified interrupt types. |
| 392 | pub fn disable_interrupt(&self, mask: u32) { | 384 | pub fn disable_interrupt(&self, mask: u32) { |
| 393 | let rtc = unsafe { &*I::ptr() }; | ||
| 394 | |||
| 395 | if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 { | 385 | if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 { |
| 396 | rtc.ier().modify(|_, w| w.tiie().tiie_0()); | 386 | self.info.ier().modify(|_, w| w.tiie().tiie_0()); |
| 397 | } | 387 | } |
| 398 | if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 { | 388 | if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 { |
| 399 | rtc.ier().modify(|_, w| w.toie().toie_0()); | 389 | self.info.ier().modify(|_, w| w.toie().toie_0()); |
| 400 | } | 390 | } |
| 401 | if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 { | 391 | if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 { |
| 402 | rtc.ier().modify(|_, w| w.taie().taie_0()); | 392 | self.info.ier().modify(|_, w| w.taie().taie_0()); |
| 403 | } | 393 | } |
| 404 | if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 { | 394 | if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 { |
| 405 | rtc.ier().modify(|_, w| w.tsie().tsie_0()); | 395 | self.info.ier().modify(|_, w| w.tsie().tsie_0()); |
| 406 | } | 396 | } |
| 407 | } | 397 | } |
| 408 | 398 | ||
| @@ -412,8 +402,7 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 412 | /// | 402 | /// |
| 413 | /// This function clears the Time Alarm Interrupt Enable bit. | 403 | /// This function clears the Time Alarm Interrupt Enable bit. |
| 414 | pub fn clear_alarm_flag(&self) { | 404 | pub fn clear_alarm_flag(&self) { |
| 415 | let rtc = unsafe { &*I::ptr() }; | 405 | self.info.ier().modify(|_, w| w.taie().clear_bit()); |
| 416 | rtc.ier().modify(|_, w| w.taie().clear_bit()); | ||
| 417 | } | 406 | } |
| 418 | 407 | ||
| 419 | /// Wait for an RTC alarm to trigger. | 408 | /// Wait for an RTC alarm to trigger. |
| @@ -421,6 +410,7 @@ impl<'a, I: Instance> Rtc<'a, I> { | |||
| 421 | /// # Arguments | 410 | /// # Arguments |
| 422 | /// | 411 | /// |
| 423 | /// * `alarm` - The date and time when the alarm should trigger | 412 | /// * `alarm` - The date and time when the alarm should trigger |
| 413 | /// | ||
| 424 | /// This function will wait until the RTC alarm is triggered. | 414 | /// This function will wait until the RTC alarm is triggered. |
| 425 | /// If no alarm is scheduled, it will wait indefinitely until one is scheduled and triggered. | 415 | /// If no alarm is scheduled, it will wait indefinitely until one is scheduled and triggered. |
| 426 | pub async fn wait_for_alarm(&mut self, alarm: RtcDateTime) { | 416 | pub async fn wait_for_alarm(&mut self, alarm: RtcDateTime) { |
