esp_hal/
system.rs

1//! # System Control
2
3use core::cell::RefCell;
4
5use critical_section::{CriticalSection, Mutex};
6
7use crate::peripherals::SYSTEM;
8
9/// Peripherals which can be enabled via `PeripheralClockControl`.
10///
11/// This enum represents various hardware peripherals that can be enabled
12/// by the system's clock control. Depending on the target device, different
13/// peripherals will be available for enabling.
14// FIXME: This enum needs to be public because it's exposed via a bunch of traits, but it's not
15// useful to users.
16#[doc(hidden)]
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[repr(u8)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum Peripheral {
21    /// SPI2 peripheral.
22    #[cfg(soc_has_spi2)]
23    Spi2,
24    /// SPI3 peripheral.
25    #[cfg(soc_has_spi3)]
26    Spi3,
27    /// External I2C0 peripheral.
28    #[cfg(soc_has_i2c0)]
29    I2cExt0,
30    /// External I2C1 peripheral.
31    #[cfg(soc_has_i2c1)]
32    I2cExt1,
33    /// RMT peripheral (Remote Control).
34    #[cfg(soc_has_rmt)]
35    Rmt,
36    /// LEDC peripheral (LED PWM Controller).
37    #[cfg(soc_has_ledc)]
38    Ledc,
39    /// MCPWM0 peripheral (Motor Control PWM 0).
40    #[cfg(soc_has_mcpwm0)]
41    Mcpwm0,
42    /// MCPWM1 peripheral (Motor Control PWM 1).
43    #[cfg(soc_has_mcpwm1)]
44    Mcpwm1,
45    /// PCNT peripheral (Pulse Counter).
46    #[cfg(soc_has_pcnt)]
47    Pcnt,
48    /// APB SAR ADC peripheral.
49    #[cfg(soc_has_apb_saradc)]
50    ApbSarAdc,
51    /// General DMA (GDMA) peripheral.
52    #[cfg(gdma)]
53    Gdma,
54    /// Peripheral DMA (PDMA) peripheral.
55    #[cfg(pdma)]
56    Dma,
57    /// I2S0 peripheral (Inter-IC Sound).
58    #[cfg(soc_has_i2s0)]
59    I2s0,
60    /// I2S1 peripheral (Inter-IC Sound).
61    #[cfg(soc_has_i2s1)]
62    I2s1,
63    /// USB0 peripheral.
64    #[cfg(soc_has_usb0)]
65    Usb,
66    /// AES peripheral (Advanced Encryption Standard).
67    #[cfg(soc_has_aes)]
68    Aes,
69    /// TWAI0 peripheral.
70    #[cfg(soc_has_twai0)]
71    Twai0,
72    /// TWAI1 peripheral.
73    #[cfg(soc_has_twai1)]
74    Twai1,
75    /// Timer Group 0 peripheral.
76    #[cfg(soc_has_timg0)]
77    Timg0,
78    /// Timer Group 1 peripheral.
79    #[cfg(soc_has_timg1)]
80    Timg1,
81    /// SHA peripheral (Secure Hash Algorithm).
82    #[cfg(soc_has_sha)]
83    Sha,
84    /// USB Device peripheral.
85    #[cfg(soc_has_usb_device)]
86    UsbDevice,
87    /// UART0 peripheral.
88    #[cfg(soc_has_uart0)]
89    Uart0,
90    /// UART1 peripheral.
91    #[cfg(soc_has_uart1)]
92    Uart1,
93    /// UART2 peripheral.
94    #[cfg(soc_has_uart2)]
95    Uart2,
96    /// RSA peripheral (Rivest-Shamir-Adleman encryption).
97    #[cfg(soc_has_rsa)]
98    Rsa,
99    /// Parallel IO peripheral.
100    #[cfg(soc_has_parl_io)]
101    ParlIo,
102    /// HMAC peripheral (Hash-based Message Authentication Code).
103    #[cfg(soc_has_hmac)]
104    Hmac,
105    /// ECC peripheral (Elliptic Curve Cryptography).
106    #[cfg(soc_has_ecc)]
107    Ecc,
108    /// SOC ETM peripheral (Event Task Manager).
109    #[cfg(soc_has_etm)]
110    Etm,
111    /// TRACE0 peripheral (Debug trace).
112    #[cfg(soc_has_trace0)]
113    Trace0,
114    /// LCD Camera peripheral.
115    #[cfg(soc_has_lcd_cam)]
116    LcdCam,
117    /// Systimer peripheral.
118    #[cfg(soc_has_systimer)]
119    Systimer,
120    /// Temperature sensor peripheral.
121    #[cfg(soc_has_tsens)]
122    Tsens,
123}
124
125impl Peripheral {
126    const KEEP_ENABLED: &[Peripheral] = &[
127        Peripheral::Uart0,
128        #[cfg(soc_has_usb_device)]
129        Peripheral::UsbDevice,
130        #[cfg(soc_has_systimer)]
131        Peripheral::Systimer,
132        #[cfg(soc_has_timg0)]
133        Peripheral::Timg0,
134        #[cfg(esp32c6)] // used by some wifi calibration steps.
135        // TODO: We should probably automatically enable this when needed.
136        Peripheral::ApbSarAdc,
137    ];
138
139    const COUNT: usize = Self::ALL.len();
140
141    const ALL: &[Self] = &[
142        #[cfg(soc_has_spi2)]
143        Self::Spi2,
144        #[cfg(soc_has_spi3)]
145        Self::Spi3,
146        #[cfg(soc_has_i2c0)]
147        Self::I2cExt0,
148        #[cfg(soc_has_i2c1)]
149        Self::I2cExt1,
150        #[cfg(soc_has_rmt)]
151        Self::Rmt,
152        #[cfg(soc_has_ledc)]
153        Self::Ledc,
154        #[cfg(soc_has_mcpwm0)]
155        Self::Mcpwm0,
156        #[cfg(soc_has_mcpwm1)]
157        Self::Mcpwm1,
158        #[cfg(soc_has_pcnt)]
159        Self::Pcnt,
160        #[cfg(soc_has_apb_saradc)]
161        Self::ApbSarAdc,
162        #[cfg(gdma)]
163        Self::Gdma,
164        #[cfg(pdma)]
165        Self::Dma,
166        #[cfg(soc_has_i2s0)]
167        Self::I2s0,
168        #[cfg(soc_has_i2s1)]
169        Self::I2s1,
170        #[cfg(soc_has_usb0)]
171        Self::Usb,
172        #[cfg(soc_has_aes)]
173        Self::Aes,
174        #[cfg(soc_has_twai0)]
175        Self::Twai0,
176        #[cfg(soc_has_twai1)]
177        Self::Twai1,
178        #[cfg(soc_has_timg0)]
179        Self::Timg0,
180        #[cfg(soc_has_timg1)]
181        Self::Timg1,
182        #[cfg(soc_has_sha)]
183        Self::Sha,
184        #[cfg(soc_has_usb_device)]
185        Self::UsbDevice,
186        #[cfg(soc_has_uart0)]
187        Self::Uart0,
188        #[cfg(soc_has_uart1)]
189        Self::Uart1,
190        #[cfg(soc_has_uart2)]
191        Self::Uart2,
192        #[cfg(soc_has_rsa)]
193        Self::Rsa,
194        #[cfg(soc_has_parl_io)]
195        Self::ParlIo,
196        #[cfg(soc_has_hmac)]
197        Self::Hmac,
198        #[cfg(soc_has_ecc)]
199        Self::Ecc,
200        #[cfg(soc_has_etm)]
201        Self::Etm,
202        #[cfg(soc_has_trace0)]
203        Self::Trace0,
204        #[cfg(soc_has_lcd_cam)]
205        Self::LcdCam,
206        #[cfg(soc_has_systimer)]
207        Self::Systimer,
208        #[cfg(soc_has_tsens)]
209        Self::Tsens,
210    ];
211}
212
213impl Peripheral {
214    pub fn try_from(value: u8) -> Option<Peripheral> {
215        if value >= Peripheral::COUNT as u8 {
216            return None;
217        }
218
219        Some(unsafe { core::mem::transmute::<u8, Peripheral>(value) })
220    }
221}
222
223static PERIPHERAL_REF_COUNT: Mutex<RefCell<[usize; Peripheral::COUNT]>> =
224    Mutex::new(RefCell::new([0; Peripheral::COUNT]));
225
226/// Disable all peripherals.
227///
228/// Peripherals listed in [KEEP_ENABLED] are NOT disabled.
229#[cfg_attr(not(feature = "rt"), expect(dead_code))]
230pub(crate) fn disable_peripherals() {
231    // Take the critical section up front to avoid taking it multiple times.
232    critical_section::with(|cs| {
233        for p in Peripheral::ALL {
234            if Peripheral::KEEP_ENABLED.contains(p) {
235                continue;
236            }
237            PeripheralClockControl::enable_forced_with_cs(*p, false, true, cs);
238        }
239    })
240}
241
242#[derive(Debug, PartialEq, Eq)]
243#[cfg_attr(feature = "defmt", derive(defmt::Format))]
244pub(crate) struct PeripheralGuard {
245    peripheral: Peripheral,
246}
247
248impl PeripheralGuard {
249    pub(crate) fn new_with(p: Peripheral, init: fn()) -> Self {
250        if !Peripheral::KEEP_ENABLED.contains(&p) && PeripheralClockControl::enable(p) {
251            PeripheralClockControl::reset(p);
252            init();
253        }
254
255        Self { peripheral: p }
256    }
257
258    pub(crate) fn new(p: Peripheral) -> Self {
259        Self::new_with(p, || {})
260    }
261}
262
263impl Drop for PeripheralGuard {
264    fn drop(&mut self) {
265        if !Peripheral::KEEP_ENABLED.contains(&self.peripheral) {
266            PeripheralClockControl::disable(self.peripheral);
267        }
268    }
269}
270
271#[derive(Debug)]
272#[cfg_attr(feature = "defmt", derive(defmt::Format))]
273pub(crate) struct GenericPeripheralGuard<const P: u8> {}
274
275impl<const P: u8> GenericPeripheralGuard<P> {
276    pub(crate) fn new_with(init: fn(CriticalSection<'_>)) -> Self {
277        let peripheral = unwrap!(Peripheral::try_from(P));
278        critical_section::with(|cs| {
279            if !Peripheral::KEEP_ENABLED.contains(&peripheral)
280                && PeripheralClockControl::enable_with_cs(peripheral, cs)
281            {
282                PeripheralClockControl::reset(peripheral);
283                init(cs);
284            }
285        });
286
287        Self {}
288    }
289
290    pub(crate) fn new() -> Self {
291        Self::new_with(|_| {})
292    }
293}
294
295impl<const P: u8> Clone for GenericPeripheralGuard<P> {
296    fn clone(&self) -> Self {
297        Self::new()
298    }
299
300    fn clone_from(&mut self, _source: &Self) {
301        // This is a no-op since the ref count for P remains the same.
302    }
303}
304
305impl<const P: u8> Drop for GenericPeripheralGuard<P> {
306    fn drop(&mut self) {
307        let peripheral = unwrap!(Peripheral::try_from(P));
308        if !Peripheral::KEEP_ENABLED.contains(&peripheral) {
309            PeripheralClockControl::disable(peripheral);
310        }
311    }
312}
313
314/// Controls the enablement of peripheral clocks.
315pub(crate) struct PeripheralClockControl;
316
317#[cfg(not(any(esp32c6, esp32h2)))]
318impl PeripheralClockControl {
319    fn enable_internal(peripheral: Peripheral, enable: bool, _cs: CriticalSection<'_>) {
320        debug!("Enable {:?} {}", peripheral, enable);
321
322        let system = SYSTEM::regs();
323
324        #[cfg(esp32)]
325        let (perip_clk_en0, perip_clk_en1) = { (&system.perip_clk_en(), &system.peri_clk_en()) };
326        #[cfg(not(esp32))]
327        let perip_clk_en0 = &system.perip_clk_en0();
328
329        #[cfg(any(esp32c2, esp32c3, esp32s2, esp32s3))]
330        let perip_clk_en1 = &system.perip_clk_en1();
331
332        match peripheral {
333            #[cfg(soc_has_spi2)]
334            Peripheral::Spi2 => {
335                perip_clk_en0.modify(|_, w| w.spi2_clk_en().bit(enable));
336            }
337            #[cfg(soc_has_spi3)]
338            Peripheral::Spi3 => {
339                perip_clk_en0.modify(|_, w| w.spi3_clk_en().bit(enable));
340            }
341            #[cfg(soc_has_i2c0)]
342            Peripheral::I2cExt0 => {
343                perip_clk_en0.modify(|_, w| w.i2c_ext0_clk_en().bit(enable));
344            }
345            #[cfg(soc_has_i2c1)]
346            Peripheral::I2cExt1 => {
347                perip_clk_en0.modify(|_, w| w.i2c_ext1_clk_en().bit(enable));
348            }
349            #[cfg(soc_has_rmt)]
350            Peripheral::Rmt => {
351                perip_clk_en0.modify(|_, w| w.rmt_clk_en().bit(enable));
352            }
353            #[cfg(soc_has_ledc)]
354            Peripheral::Ledc => {
355                perip_clk_en0.modify(|_, w| w.ledc_clk_en().bit(enable));
356            }
357            #[cfg(soc_has_mcpwm0)]
358            Peripheral::Mcpwm0 => {
359                perip_clk_en0.modify(|_, w| w.pwm0_clk_en().bit(enable));
360            }
361            #[cfg(soc_has_mcpwm1)]
362            Peripheral::Mcpwm1 => {
363                perip_clk_en0.modify(|_, w| w.pwm1_clk_en().bit(enable));
364            }
365            #[cfg(soc_has_pcnt)]
366            Peripheral::Pcnt => {
367                perip_clk_en0.modify(|_, w| w.pcnt_clk_en().bit(enable));
368            }
369            #[cfg(soc_has_apb_saradc)]
370            Peripheral::ApbSarAdc => {
371                perip_clk_en0.modify(|_, w| w.apb_saradc_clk_en().bit(enable));
372            }
373            #[cfg(gdma)]
374            Peripheral::Gdma => {
375                perip_clk_en1.modify(|_, w| w.dma_clk_en().bit(enable));
376            }
377            #[cfg(esp32)]
378            Peripheral::Dma => {
379                perip_clk_en0.modify(|_, w| w.spi_dma_clk_en().bit(enable));
380            }
381            #[cfg(esp32s2)]
382            Peripheral::Dma => {
383                perip_clk_en0.modify(|_, w| w.spi2_dma_clk_en().bit(enable));
384                perip_clk_en0.modify(|_, w| w.spi3_dma_clk_en().bit(enable));
385                perip_clk_en1.modify(|_, w| w.crypto_dma_clk_en().bit(enable));
386            }
387            #[cfg(soc_has_i2s0)]
388            Peripheral::I2s0 => {
389                perip_clk_en0.modify(|_, w| w.i2s0_clk_en().bit(enable));
390            }
391            #[cfg(soc_has_i2s1)]
392            Peripheral::I2s1 => {
393                perip_clk_en0.modify(|_, w| w.i2s1_clk_en().bit(enable));
394            }
395            #[cfg(soc_has_usb0)]
396            Peripheral::Usb => {
397                perip_clk_en0.modify(|_, w| w.usb_clk_en().bit(enable));
398            }
399            #[cfg(soc_has_twai0)]
400            Peripheral::Twai0 => {
401                perip_clk_en0.modify(|_, w| w.twai_clk_en().bit(enable));
402            }
403            #[cfg(soc_has_aes)]
404            Peripheral::Aes => {
405                perip_clk_en1.modify(|_, w| w.crypto_aes_clk_en().bit(enable));
406            }
407            #[cfg(soc_has_timg0)]
408            Peripheral::Timg0 => {
409                #[cfg(any(esp32c3, esp32s2, esp32s3))]
410                perip_clk_en0.modify(|_, w| w.timers_clk_en().bit(enable));
411                perip_clk_en0.modify(|_, w| w.timergroup_clk_en().bit(enable));
412            }
413            #[cfg(soc_has_timg1)]
414            Peripheral::Timg1 => {
415                #[cfg(any(esp32c3, esp32s2, esp32s3))]
416                perip_clk_en0.modify(|_, w| w.timers_clk_en().bit(enable));
417                perip_clk_en0.modify(|_, w| w.timergroup1_clk_en().bit(enable));
418            }
419            #[cfg(soc_has_sha)]
420            Peripheral::Sha => {
421                perip_clk_en1.modify(|_, w| w.crypto_sha_clk_en().bit(enable));
422            }
423            #[cfg(esp32c3)]
424            Peripheral::UsbDevice => {
425                perip_clk_en0.modify(|_, w| w.usb_device_clk_en().bit(enable));
426            }
427            #[cfg(esp32s3)]
428            Peripheral::UsbDevice => {
429                perip_clk_en1.modify(|_, w| w.usb_device_clk_en().bit(enable));
430            }
431            #[cfg(soc_has_uart0)]
432            Peripheral::Uart0 => {
433                perip_clk_en0.modify(|_, w| w.uart_clk_en().bit(enable));
434            }
435            #[cfg(soc_has_uart1)]
436            Peripheral::Uart1 => {
437                perip_clk_en0.modify(|_, w| w.uart1_clk_en().bit(enable));
438            }
439            #[cfg(all(soc_has_uart2, esp32s3))]
440            Peripheral::Uart2 => {
441                perip_clk_en1.modify(|_, w| w.uart2_clk_en().set_bit());
442            }
443            #[cfg(all(soc_has_uart2, esp32))]
444            Peripheral::Uart2 => {
445                perip_clk_en0.modify(|_, w| w.uart2_clk_en().bit(enable));
446            }
447            #[cfg(all(rsa, esp32))]
448            Peripheral::Rsa => {
449                perip_clk_en1.modify(|_, w| w.crypto_rsa_clk_en().bit(enable));
450            }
451            #[cfg(all(rsa, any(esp32c3, esp32s2, esp32s3)))]
452            Peripheral::Rsa => {
453                perip_clk_en1.modify(|_, w| w.crypto_rsa_clk_en().bit(enable));
454                system
455                    .rsa_pd_ctrl()
456                    .modify(|_, w| w.rsa_mem_pd().bit(!enable));
457            }
458            #[cfg(soc_has_hmac)]
459            Peripheral::Hmac => {
460                perip_clk_en1.modify(|_, w| w.crypto_hmac_clk_en().bit(enable));
461            }
462            #[cfg(soc_has_ecc)]
463            Peripheral::Ecc => {
464                perip_clk_en1.modify(|_, w| w.crypto_ecc_clk_en().bit(enable));
465            }
466            #[cfg(soc_has_lcd_cam)]
467            Peripheral::LcdCam => {
468                perip_clk_en1.modify(|_, w| w.lcd_cam_clk_en().bit(enable));
469            }
470            #[cfg(soc_has_systimer)]
471            Peripheral::Systimer => {
472                perip_clk_en0.modify(|_, w| w.systimer_clk_en().bit(enable));
473            }
474            #[cfg(soc_has_tsens)]
475            Peripheral::Tsens => {
476                perip_clk_en1.modify(|_, w| w.tsens_clk_en().bit(enable));
477            }
478        }
479    }
480
481    /// Resets the given peripheral
482    pub(crate) fn reset(peripheral: Peripheral) {
483        debug!("Reset {:?}", peripheral);
484
485        assert_peri_reset(peripheral, true);
486        assert_peri_reset(peripheral, false);
487    }
488}
489
490#[cfg(any(esp32c6, esp32h2))]
491impl PeripheralClockControl {
492    fn enable_internal(peripheral: Peripheral, enable: bool, _cs: CriticalSection<'_>) {
493        debug!("Enable {:?} {}", peripheral, enable);
494        let system = SYSTEM::regs();
495
496        match peripheral {
497            #[cfg(soc_has_spi2)]
498            Peripheral::Spi2 => {
499                system
500                    .spi2_conf()
501                    .modify(|_, w| w.spi2_clk_en().bit(enable));
502            }
503            #[cfg(soc_has_i2c0)]
504            Peripheral::I2cExt0 => {
505                system
506                    .i2c0_conf()
507                    .modify(|_, w| w.i2c0_clk_en().bit(enable));
508            }
509            #[cfg(soc_has_i2c1)]
510            Peripheral::I2cExt1 => {
511                system
512                    .i2c1_conf()
513                    .modify(|_, w| w.i2c1_clk_en().bit(enable));
514            }
515            #[cfg(soc_has_rmt)]
516            Peripheral::Rmt => {
517                system.rmt_conf().modify(|_, w| w.rmt_clk_en().bit(enable));
518            }
519            #[cfg(soc_has_ledc)]
520            Peripheral::Ledc => {
521                system
522                    .ledc_conf()
523                    .modify(|_, w| w.ledc_clk_en().bit(enable));
524            }
525            #[cfg(soc_has_mcpwm0)]
526            Peripheral::Mcpwm0 => {
527                system.pwm_conf().modify(|_, w| w.pwm_clk_en().bit(enable));
528            }
529            #[cfg(soc_has_mcpwm1)]
530            Peripheral::Mcpwm1 => {
531                system.pwm_conf.modify(|_, w| w.pwm_clk_en().bit(enable));
532            }
533            #[cfg(soc_has_apb_saradc)]
534            Peripheral::ApbSarAdc => {
535                system
536                    .saradc_conf()
537                    .modify(|_, w| w.saradc_reg_clk_en().bit(enable));
538            }
539            #[cfg(gdma)]
540            Peripheral::Gdma => {
541                system
542                    .gdma_conf()
543                    .modify(|_, w| w.gdma_clk_en().bit(enable));
544            }
545            #[cfg(soc_has_i2s0)]
546            Peripheral::I2s0 => {
547                system.i2s_conf().modify(|_, w| w.i2s_clk_en().bit(enable));
548            }
549            #[cfg(soc_has_twai0)]
550            Peripheral::Twai0 => {
551                system
552                    .twai0_conf()
553                    .modify(|_, w| w.twai0_clk_en().bit(enable));
554
555                if enable {
556                    // use Xtal clk-src
557                    system.twai0_func_clk_conf().modify(|_, w| {
558                        w.twai0_func_clk_en().set_bit();
559                        w.twai0_func_clk_sel().variant(false)
560                    });
561                }
562            }
563            #[cfg(soc_has_twai1)]
564            Peripheral::Twai1 => {
565                system
566                    .twai1_conf()
567                    .modify(|_, w| w.twai1_clk_en().bit(enable));
568            }
569            #[cfg(soc_has_aes)]
570            Peripheral::Aes => {
571                system.aes_conf().modify(|_, w| w.aes_clk_en().bit(enable));
572            }
573            #[cfg(soc_has_pcnt)]
574            Peripheral::Pcnt => {
575                system
576                    .pcnt_conf()
577                    .modify(|_, w| w.pcnt_clk_en().bit(enable));
578            }
579            #[cfg(soc_has_timg0)]
580            Peripheral::Timg0 => {
581                system
582                    .timergroup0_timer_clk_conf()
583                    .modify(|_, w| w.tg0_timer_clk_en().bit(enable));
584            }
585            #[cfg(soc_has_timg1)]
586            Peripheral::Timg1 => {
587                system
588                    .timergroup1_timer_clk_conf()
589                    .modify(|_, w| w.tg1_timer_clk_en().bit(enable));
590            }
591            #[cfg(soc_has_sha)]
592            Peripheral::Sha => {
593                system.sha_conf().modify(|_, w| w.sha_clk_en().bit(enable));
594            }
595            #[cfg(soc_has_usb_device)]
596            Peripheral::UsbDevice => {
597                system
598                    .usb_device_conf()
599                    .modify(|_, w| w.usb_device_clk_en().bit(enable));
600            }
601            #[cfg(soc_has_uart0)]
602            Peripheral::Uart0 => {
603                system.uart(0).conf().modify(|_, w| w.clk_en().bit(enable));
604            }
605            #[cfg(soc_has_uart1)]
606            Peripheral::Uart1 => {
607                system.uart(1).conf().modify(|_, w| w.clk_en().bit(enable));
608            }
609            #[cfg(soc_has_rsa)]
610            Peripheral::Rsa => {
611                system.rsa_conf().modify(|_, w| w.rsa_clk_en().bit(enable));
612                system
613                    .rsa_pd_ctrl()
614                    .modify(|_, w| w.rsa_mem_pd().clear_bit());
615            }
616            #[cfg(soc_has_parl_io)]
617            Peripheral::ParlIo => {
618                system
619                    .parl_io_conf()
620                    .modify(|_, w| w.parl_clk_en().bit(enable));
621            }
622            #[cfg(soc_has_hmac)]
623            Peripheral::Hmac => {
624                system
625                    .hmac_conf()
626                    .modify(|_, w| w.hmac_clk_en().bit(enable));
627            }
628            #[cfg(soc_has_ecc)]
629            Peripheral::Ecc => {
630                system.ecc_conf().modify(|_, w| w.ecc_clk_en().bit(enable));
631            }
632            #[cfg(soc_has_etm)]
633            Peripheral::Etm => {
634                system.etm_conf().modify(|_, w| w.etm_clk_en().bit(enable));
635            }
636            #[cfg(soc_has_trace0)]
637            Peripheral::Trace0 => {
638                system
639                    .trace_conf()
640                    .modify(|_, w| w.trace_clk_en().bit(enable));
641            }
642            #[cfg(soc_has_systimer)]
643            Peripheral::Systimer => {
644                system
645                    .systimer_conf()
646                    .modify(|_, w| w.systimer_clk_en().bit(enable));
647            }
648            #[cfg(soc_has_tsens)]
649            Peripheral::Tsens => {
650                system.tsens_clk_conf().modify(|_, w| {
651                    w.tsens_clk_en().bit(enable);
652                    w.tsens_clk_sel().bit(enable)
653                });
654            }
655        }
656    }
657
658    /// Resets the given peripheral
659    pub(crate) fn reset(peripheral: Peripheral) {
660        debug!("Reset {:?}", peripheral);
661
662        assert_peri_reset(peripheral, true);
663        assert_peri_reset(peripheral, false);
664    }
665}
666
667#[cfg(not(any(esp32c6, esp32h2)))]
668/// Resets the given peripheral
669pub(crate) fn assert_peri_reset(peripheral: Peripheral, reset: bool) {
670    let system = SYSTEM::regs();
671
672    #[cfg(esp32)]
673    let (perip_rst_en0, perip_rst_en1) = (system.perip_rst_en(), system.peri_rst_en());
674    #[cfg(not(esp32))]
675    let perip_rst_en0 = system.perip_rst_en0();
676
677    #[cfg(any(esp32c2, esp32c3, esp32s2, esp32s3))]
678    let perip_rst_en1 = system.perip_rst_en1();
679
680    critical_section::with(|_cs| match peripheral {
681        #[cfg(soc_has_spi2)]
682        Peripheral::Spi2 => {
683            perip_rst_en0.modify(|_, w| w.spi2_rst().bit(reset));
684        }
685        #[cfg(soc_has_spi3)]
686        Peripheral::Spi3 => {
687            perip_rst_en0.modify(|_, w| w.spi3_rst().bit(reset));
688        }
689        #[cfg(soc_has_i2c0)]
690        Peripheral::I2cExt0 => {
691            perip_rst_en0.modify(|_, w| w.i2c_ext0_rst().bit(reset));
692        }
693        #[cfg(soc_has_i2c1)]
694        Peripheral::I2cExt1 => {
695            perip_rst_en0.modify(|_, w| w.i2c_ext1_rst().bit(reset));
696        }
697        #[cfg(soc_has_rmt)]
698        Peripheral::Rmt => {
699            perip_rst_en0.modify(|_, w| w.rmt_rst().bit(reset));
700        }
701        #[cfg(soc_has_ledc)]
702        Peripheral::Ledc => {
703            perip_rst_en0.modify(|_, w| w.ledc_rst().bit(reset));
704        }
705        #[cfg(soc_has_mcpwm0)]
706        Peripheral::Mcpwm0 => {
707            perip_rst_en0.modify(|_, w| w.pwm0_rst().bit(reset));
708        }
709        #[cfg(soc_has_mcpwm1)]
710        Peripheral::Mcpwm1 => {
711            perip_rst_en0.modify(|_, w| w.pwm1_rst().bit(reset));
712        }
713        #[cfg(soc_has_pcnt)]
714        Peripheral::Pcnt => {
715            perip_rst_en0.modify(|_, w| w.pcnt_rst().bit(reset));
716        }
717        #[cfg(soc_has_apb_saradc)]
718        Peripheral::ApbSarAdc => {
719            perip_rst_en0.modify(|_, w| w.apb_saradc_rst().bit(reset));
720        }
721        #[cfg(gdma)]
722        Peripheral::Gdma => {
723            perip_rst_en1.modify(|_, w| w.dma_rst().bit(reset));
724        }
725        #[cfg(esp32)]
726        Peripheral::Dma => {
727            perip_rst_en0.modify(|_, w| w.spi_dma_rst().bit(reset));
728        }
729        #[cfg(esp32s2)]
730        Peripheral::Dma => {
731            perip_rst_en0.modify(|_, w| w.spi2_dma_rst().bit(reset));
732            perip_rst_en0.modify(|_, w| w.spi3_dma_rst().bit(reset));
733            perip_rst_en1.modify(|_, w| w.crypto_dma_rst().bit(reset));
734        }
735        #[cfg(soc_has_i2s0)]
736        Peripheral::I2s0 => {
737            perip_rst_en0.modify(|_, w| w.i2s0_rst().bit(reset));
738        }
739        #[cfg(soc_has_i2s1)]
740        Peripheral::I2s1 => {
741            perip_rst_en0.modify(|_, w| w.i2s1_rst().bit(reset));
742        }
743        #[cfg(soc_has_usb0)]
744        Peripheral::Usb => {
745            perip_rst_en0.modify(|_, w| w.usb_rst().bit(reset));
746        }
747        #[cfg(soc_has_twai0)]
748        Peripheral::Twai0 => {
749            perip_rst_en0.modify(|_, w| w.twai_rst().bit(reset));
750        }
751        #[cfg(soc_has_aes)]
752        Peripheral::Aes => {
753            perip_rst_en1.modify(|_, w| w.crypto_aes_rst().bit(reset));
754        }
755        #[cfg(soc_has_timg0)]
756        Peripheral::Timg0 => {
757            #[cfg(any(esp32c3, esp32s2, esp32s3))]
758            perip_rst_en0.modify(|_, w| w.timers_rst().bit(reset));
759            perip_rst_en0.modify(|_, w| w.timergroup_rst().bit(reset));
760        }
761        #[cfg(soc_has_timg1)]
762        Peripheral::Timg1 => {
763            #[cfg(any(esp32c3, esp32s2, esp32s3))]
764            perip_rst_en0.modify(|_, w| w.timers_rst().bit(reset));
765            perip_rst_en0.modify(|_, w| w.timergroup1_rst().bit(reset));
766        }
767        #[cfg(soc_has_sha)]
768        Peripheral::Sha => {
769            perip_rst_en1.modify(|_, w| w.crypto_sha_rst().bit(reset));
770        }
771        #[cfg(soc_has_usb_device)]
772        Peripheral::UsbDevice => {
773            cfg_if::cfg_if! {
774                if #[cfg(esp32c3)] {
775                    perip_rst_en0.modify(|_, w| w.usb_device_rst().bit(reset));
776                } else {
777                    perip_rst_en1.modify(|_, w| w.usb_device_rst().bit(reset));
778                }
779            }
780        }
781        #[cfg(soc_has_uart0)]
782        Peripheral::Uart0 => {
783            perip_rst_en0.modify(|_, w| w.uart_rst().bit(reset));
784        }
785        #[cfg(soc_has_uart1)]
786        Peripheral::Uart1 => {
787            perip_rst_en0.modify(|_, w| w.uart1_rst().bit(reset));
788        }
789        #[cfg(soc_has_uart2)]
790        Peripheral::Uart2 => {
791            cfg_if::cfg_if! {
792                if #[cfg(esp32)] {
793                    perip_rst_en0.modify(|_, w| w.uart2_rst().bit(reset));
794                } else {
795                    perip_rst_en1.modify(|_, w| w.uart2_rst().bit(reset));
796                }
797            }
798        }
799        #[cfg(soc_has_rsa)]
800        Peripheral::Rsa => {
801            perip_rst_en1.modify(|_, w| w.crypto_rsa_rst().bit(reset));
802        }
803        #[cfg(soc_has_hmac)]
804        Peripheral::Hmac => {
805            perip_rst_en1.modify(|_, w| w.crypto_hmac_rst().bit(reset));
806        }
807        #[cfg(soc_has_ecc)]
808        Peripheral::Ecc => {
809            perip_rst_en1.modify(|_, w| w.crypto_ecc_rst().bit(reset));
810        }
811        #[cfg(soc_has_lcd_cam)]
812        Peripheral::LcdCam => {
813            perip_rst_en1.modify(|_, w| w.lcd_cam_rst().bit(reset));
814        }
815        #[cfg(soc_has_systimer)]
816        Peripheral::Systimer => {
817            perip_rst_en0.modify(|_, w| w.systimer_rst().bit(reset));
818        }
819        #[cfg(soc_has_tsens)]
820        Peripheral::Tsens => {
821            cfg_if::cfg_if! {
822                if #[cfg(esp32c3)] {
823                    perip_rst_en1.modify(|_, w| w.tsens_rst().bit(reset));
824                } else {
825                    perip_rst_en0.modify(|_, w| w.tsens_rst().bit(reset));
826                }
827            }
828        }
829    });
830}
831
832#[cfg(any(esp32c6, esp32h2))]
833fn assert_peri_reset(peripheral: Peripheral, reset: bool) {
834    let system = SYSTEM::regs();
835
836    match peripheral {
837        #[cfg(soc_has_spi2)]
838        Peripheral::Spi2 => {
839            system.spi2_conf().modify(|_, w| w.spi2_rst_en().bit(reset));
840        }
841        #[cfg(soc_has_i2c0)]
842        Peripheral::I2cExt0 => {
843            system.i2c0_conf().modify(|_, w| w.i2c0_rst_en().bit(reset));
844        }
845        #[cfg(soc_has_i2c1)]
846        Peripheral::I2cExt1 => {
847            system.i2c1_conf().modify(|_, w| w.i2c1_rst_en().bit(reset));
848        }
849        #[cfg(soc_has_rmt)]
850        Peripheral::Rmt => {
851            system.rmt_conf().modify(|_, w| w.rmt_rst_en().bit(reset));
852        }
853        #[cfg(soc_has_ledc)]
854        Peripheral::Ledc => {
855            system.ledc_conf().modify(|_, w| w.ledc_rst_en().bit(reset));
856        }
857        #[cfg(soc_has_mcpwm0)]
858        Peripheral::Mcpwm0 => {
859            system.pwm_conf().modify(|_, w| w.pwm_rst_en().bit(reset));
860        }
861        #[cfg(soc_has_apb_saradc)]
862        Peripheral::ApbSarAdc => {
863            system
864                .saradc_conf()
865                .modify(|_, w| w.saradc_reg_rst_en().bit(reset));
866        }
867        #[cfg(gdma)]
868        Peripheral::Gdma => {
869            system.gdma_conf().modify(|_, w| w.gdma_rst_en().bit(reset));
870        }
871        #[cfg(soc_has_i2s0)]
872        Peripheral::I2s0 => {
873            system.i2s_conf().modify(|_, w| w.i2s_rst_en().bit(reset));
874        }
875        #[cfg(soc_has_twai0)]
876        Peripheral::Twai0 => {
877            system
878                .twai0_conf()
879                .modify(|_, w| w.twai0_rst_en().bit(reset));
880        }
881        #[cfg(soc_has_twai1)]
882        Peripheral::Twai1 => {
883            system
884                .twai1_conf()
885                .modify(|_, w| w.twai1_rst_en().bit(reset));
886        }
887        #[cfg(soc_has_aes)]
888        Peripheral::Aes => {
889            system.aes_conf().modify(|_, w| w.aes_rst_en().bit(reset));
890        }
891        #[cfg(soc_has_pcnt)]
892        Peripheral::Pcnt => {
893            system.pcnt_conf().modify(|_, w| w.pcnt_rst_en().bit(reset));
894        }
895        #[cfg(soc_has_timg0)]
896        Peripheral::Timg0 => {
897            // no reset?
898        }
899        #[cfg(soc_has_timg1)]
900        Peripheral::Timg1 => {
901            // no reset?
902        }
903        #[cfg(soc_has_sha)]
904        Peripheral::Sha => {
905            system.sha_conf().modify(|_, w| w.sha_rst_en().bit(reset));
906        }
907        #[cfg(soc_has_usb_device)]
908        Peripheral::UsbDevice => {
909            system
910                .usb_device_conf()
911                .modify(|_, w| w.usb_device_rst_en().bit(reset));
912        }
913        #[cfg(soc_has_uart0)]
914        Peripheral::Uart0 => {
915            system.uart(0).conf().modify(|_, w| w.rst_en().bit(reset));
916        }
917        #[cfg(soc_has_uart1)]
918        Peripheral::Uart1 => {
919            system.uart(1).conf().modify(|_, w| w.rst_en().bit(reset));
920        }
921        #[cfg(soc_has_rsa)]
922        Peripheral::Rsa => {
923            system.rsa_conf().modify(|_, w| w.rsa_rst_en().bit(reset));
924        }
925        #[cfg(soc_has_parl_io)]
926        Peripheral::ParlIo => {
927            system
928                .parl_io_conf()
929                .modify(|_, w| w.parl_rst_en().bit(reset));
930        }
931        #[cfg(soc_has_hmac)]
932        Peripheral::Hmac => {
933            system.hmac_conf().modify(|_, w| w.hmac_rst_en().bit(reset));
934        }
935        #[cfg(soc_has_ecc)]
936        Peripheral::Ecc => {
937            system.ecc_conf().modify(|_, w| w.ecc_rst_en().bit(reset));
938        }
939        #[cfg(soc_has_etm)]
940        Peripheral::Etm => {
941            system.etm_conf().modify(|_, w| w.etm_rst_en().bit(reset));
942        }
943        #[cfg(soc_has_trace0)]
944        Peripheral::Trace0 => {
945            system
946                .trace_conf()
947                .modify(|_, w| w.trace_rst_en().bit(reset));
948        }
949        #[cfg(soc_has_systimer)]
950        Peripheral::Systimer => {
951            system
952                .systimer_conf()
953                .modify(|_, w| w.systimer_rst_en().bit(reset));
954        }
955        #[cfg(soc_has_tsens)]
956        Peripheral::Tsens => {
957            system
958                .tsens_clk_conf()
959                .modify(|_, w| w.tsens_rst_en().bit(reset));
960        }
961    }
962}
963
964impl PeripheralClockControl {
965    /// Enables the given peripheral.
966    ///
967    /// This keeps track of enabling a peripheral - i.e. a peripheral
968    /// is only enabled with the first call attempt to enable it.
969    ///
970    /// Returns `true` if it actually enabled the peripheral.
971    pub(crate) fn enable(peripheral: Peripheral) -> bool {
972        Self::enable_forced(peripheral, true, false)
973    }
974
975    /// Enables the given peripheral.
976    ///
977    /// This keeps track of enabling a peripheral - i.e. a peripheral
978    /// is only enabled with the first call attempt to enable it.
979    ///
980    /// Returns `true` if it actually enabled the peripheral.
981    pub(crate) fn enable_with_cs(peripheral: Peripheral, cs: CriticalSection<'_>) -> bool {
982        Self::enable_forced_with_cs(peripheral, true, false, cs)
983    }
984
985    /// Disables the given peripheral.
986    ///
987    /// This keeps track of disabling a peripheral - i.e. it only
988    /// gets disabled when the number of enable/disable attempts is balanced.
989    ///
990    /// Returns `true` if it actually disabled the peripheral.
991    ///
992    /// Before disabling a peripheral it will also get reset
993    pub(crate) fn disable(peripheral: Peripheral) -> bool {
994        Self::enable_forced(peripheral, false, false)
995    }
996
997    pub(crate) fn enable_forced(peripheral: Peripheral, enable: bool, force: bool) -> bool {
998        critical_section::with(|cs| Self::enable_forced_with_cs(peripheral, enable, force, cs))
999    }
1000
1001    pub(crate) fn enable_forced_with_cs(
1002        peripheral: Peripheral,
1003        enable: bool,
1004        force: bool,
1005        cs: CriticalSection<'_>,
1006    ) -> bool {
1007        let mut ref_counts = PERIPHERAL_REF_COUNT.borrow_ref_mut(cs);
1008        let ref_count = &mut ref_counts[peripheral as usize];
1009        if !force {
1010            let prev = *ref_count;
1011            if enable {
1012                *ref_count += 1;
1013                trace!("Enable {:?} {} -> {}", peripheral, prev, *ref_count);
1014                if prev > 0 {
1015                    return false;
1016                }
1017            } else {
1018                assert!(prev != 0);
1019                *ref_count -= 1;
1020                trace!("Disable {:?} {} -> {}", peripheral, prev, *ref_count);
1021                if prev > 1 {
1022                    return false;
1023                }
1024            };
1025        } else if !enable {
1026            assert!(*ref_count == 0);
1027        }
1028
1029        if !enable {
1030            Self::reset(peripheral);
1031        }
1032
1033        Self::enable_internal(peripheral, enable, cs);
1034
1035        true
1036    }
1037}
1038
1039#[cfg(any(esp32, esp32s3))]
1040#[allow(unused_imports)]
1041pub use crate::soc::cpu_control::*;
1042
1043/// Available CPU cores
1044///
1045/// The actual number of available cores depends on the target.
1046#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::FromRepr)]
1047#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1048#[repr(C)]
1049pub enum Cpu {
1050    /// The first core
1051    ProCpu = 0,
1052    /// The second core
1053    #[cfg(multi_core)]
1054    AppCpu = 1,
1055}
1056
1057impl Cpu {
1058    /// The number of available cores.
1059    pub const COUNT: usize = 1 + cfg!(multi_core) as usize;
1060
1061    #[procmacros::doc_replace]
1062    /// Returns the core the application is currently executing on
1063    ///
1064    /// ```rust, no_run
1065    /// # {before_snippet}
1066    /// #
1067    /// use esp_hal::system::Cpu;
1068    /// let current_cpu = Cpu::current();
1069    /// #
1070    /// # {after_snippet}
1071    /// ```
1072    #[inline(always)]
1073    pub fn current() -> Self {
1074        // This works for both RISCV and Xtensa because both
1075        // get_raw_core functions return zero, _or_ something
1076        // greater than zero; 1 in the case of RISCV and 0x2000
1077        // in the case of Xtensa.
1078        match raw_core() {
1079            0 => Cpu::ProCpu,
1080            #[cfg(all(multi_core, riscv))]
1081            1 => Cpu::AppCpu,
1082            #[cfg(all(multi_core, xtensa))]
1083            0x2000 => Cpu::AppCpu,
1084            _ => unreachable!(),
1085        }
1086    }
1087
1088    /// Returns an iterator over the "other" cores.
1089    #[inline(always)]
1090    pub(crate) fn other() -> impl Iterator<Item = Self> {
1091        cfg_if::cfg_if! {
1092            if #[cfg(multi_core)] {
1093                match Self::current() {
1094                    Cpu::ProCpu => [Cpu::AppCpu].into_iter(),
1095                    Cpu::AppCpu => [Cpu::ProCpu].into_iter(),
1096                }
1097            } else {
1098                [].into_iter()
1099            }
1100        }
1101    }
1102
1103    /// Returns an iterator over all cores.
1104    #[inline(always)]
1105    pub(crate) fn all() -> impl Iterator<Item = Self> {
1106        cfg_if::cfg_if! {
1107            if #[cfg(multi_core)] {
1108                [Cpu::ProCpu, Cpu::AppCpu].into_iter()
1109            } else {
1110                [Cpu::ProCpu].into_iter()
1111            }
1112        }
1113    }
1114}
1115
1116/// Returns the raw value of the mhartid register.
1117///
1118/// On RISC-V, this is the hardware thread ID.
1119///
1120/// On Xtensa, this returns the result of reading the PRID register logically
1121/// ANDed with 0x2000, the 13th bit in the register. Espressif Xtensa chips use
1122/// this bit to determine the core id.
1123#[inline(always)]
1124pub(crate) fn raw_core() -> usize {
1125    // This method must never return UNUSED_THREAD_ID_VALUE
1126    cfg_if::cfg_if! {
1127        if #[cfg(all(multi_core, riscv))] {
1128            riscv::register::mhartid::read()
1129        } else if #[cfg(all(multi_core, xtensa))] {
1130            (xtensa_lx::get_processor_id() & 0x2000) as usize
1131        } else {
1132            0
1133        }
1134    }
1135}
1136
1137use crate::rtc_cntl::SocResetReason;
1138
1139/// Source of the wakeup event
1140#[derive(Debug, Copy, Clone)]
1141#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1142#[instability::unstable]
1143pub enum SleepSource {
1144    /// In case of deep sleep, reset was not caused by exit from deep sleep
1145    Undefined = 0,
1146    /// Not a wakeup cause, used to disable all wakeup sources with
1147    /// esp_sleep_disable_wakeup_source
1148    All,
1149    /// Wakeup caused by external signal using RTC_IO
1150    Ext0,
1151    /// Wakeup caused by external signal using RTC_CNTL
1152    Ext1,
1153    /// Wakeup caused by timer
1154    Timer,
1155    /// Wakeup caused by touchpad
1156    TouchPad,
1157    /// Wakeup caused by ULP program
1158    Ulp,
1159    /// Wakeup caused by GPIO (light sleep only on ESP32, S2 and S3)
1160    Gpio,
1161    /// Wakeup caused by UART (light sleep only)
1162    Uart,
1163    /// Wakeup caused by WIFI (light sleep only)
1164    Wifi,
1165    /// Wakeup caused by COCPU int
1166    Cocpu,
1167    /// Wakeup caused by COCPU crash
1168    CocpuTrapTrig,
1169    /// Wakeup caused by BT (light sleep only)
1170    BT,
1171}
1172
1173#[procmacros::doc_replace]
1174/// Performs a software reset on the chip.
1175///
1176/// # Example
1177///
1178/// ```rust, no_run
1179/// # {before_snippet}
1180/// use esp_hal::system::software_reset;
1181/// software_reset();
1182/// # {after_snippet}
1183/// ```
1184#[inline]
1185pub fn software_reset() -> ! {
1186    crate::rom::software_reset()
1187}
1188
1189/// Resets the given CPU, leaving peripherals unchanged.
1190#[instability::unstable]
1191#[inline]
1192pub fn software_reset_cpu(cpu: Cpu) {
1193    crate::rom::software_reset_cpu(cpu as u32)
1194}
1195
1196/// Retrieves the reason for the last reset as a SocResetReason enum value.
1197/// Returns `None` if the reset reason cannot be determined.
1198#[instability::unstable]
1199#[inline]
1200pub fn reset_reason() -> Option<SocResetReason> {
1201    crate::rtc_cntl::reset_reason(Cpu::current())
1202}
1203
1204/// Retrieves the cause of the last wakeup event as a SleepSource enum value.
1205#[instability::unstable]
1206#[inline]
1207pub fn wakeup_cause() -> SleepSource {
1208    crate::rtc_cntl::wakeup_cause()
1209}