3232
3333// ASF 4
3434#include "atmel_start_pins.h"
35+ #include "peripheral_clk_config.h"
3536#include "hal/include/hal_delay.h"
3637#include "hal/include/hal_flash.h"
3738#include "hal/include/hal_gpio.h"
@@ -134,19 +135,25 @@ static void save_usb_clock_calibration(void) {
134135
135136static void rtc_init (void ) {
136137#ifdef SAMD21
137- _gclk_enable_channel (RTC_GCLK_ID , CONF_GCLK_RTC_SRC );
138+ _gclk_enable_channel (RTC_GCLK_ID , GCLK_CLKCTRL_GEN_GCLK2_Val );
139+ RTC -> MODE0 .CTRL .bit .SWRST = true;
140+ while (RTC -> MODE0 .CTRL .bit .SWRST != 0 ) {}
141+
142+ RTC -> MODE0 .CTRL .reg = RTC_MODE0_CTRL_ENABLE |
143+ RTC_MODE0_CTRL_MODE_COUNT32 |
144+ RTC_MODE0_CTRL_PRESCALER_DIV2 ;
138145#endif
139146#ifdef SAMD51
140147 hri_mclk_set_APBAMASK_RTC_bit (MCLK );
141- #endif
142-
143148 RTC -> MODE0 .CTRLA .bit .SWRST = true;
144149 while (RTC -> MODE0 .SYNCBUSY .bit .SWRST != 0 ) {}
145150
146151 RTC -> MODE0 .CTRLA .reg = RTC_MODE0_CTRLA_ENABLE |
147152 RTC_MODE0_CTRLA_MODE_COUNT32 |
148153 RTC_MODE0_CTRLA_PRESCALER_DIV2 |
149154 RTC_MODE0_CTRLA_COUNTSYNC ;
155+ #endif
156+
150157 RTC -> MODE0 .INTENSET .reg = RTC_MODE0_INTENSET_OVF ;
151158
152159 // Set all peripheral interrupt priorities to the lowest priority by default.
@@ -384,6 +391,7 @@ uint32_t port_get_saved_word(void) {
384391// TODO: Move this to an RTC backup register so we can preserve it when only the BACKUP power domain
385392// is enabled.
386393static volatile uint64_t overflowed_ticks = 0 ;
394+ static volatile bool _ticks_enabled = false;
387395
388396void RTC_Handler (void ) {
389397 uint32_t intflag = RTC -> MODE0 .INTFLAG .reg ;
@@ -392,20 +400,44 @@ void RTC_Handler(void) {
392400 // Our RTC is 32 bits and we're clocking it at 16.384khz which is 16 (2 ** 4) subticks per
393401 // tick.
394402 overflowed_ticks += (1L << (32 - 4 ));
395-
403+ #ifdef SAMD51
396404 } else if (intflag & RTC_MODE0_INTFLAG_PER2 ) {
397405 RTC -> MODE0 .INTFLAG .reg = RTC_MODE0_INTFLAG_PER2 ;
398406 // Do things common to all ports when the tick occurs
399407 supervisor_tick ();
408+ #endif
400409 } else if (intflag & RTC_MODE0_INTFLAG_CMP0 ) {
401- RTC -> MODE0 . INTENCLR . reg = RTC_MODE0_INTENCLR_CMP0 ;
410+ // Clear the interrupt because we may have hit a sleep and _ticks_enabled
402411 RTC -> MODE0 .INTFLAG .reg = RTC_MODE0_INTFLAG_CMP0 ;
412+ #ifdef SAMD21
413+ if (_ticks_enabled ) {
414+ // Do things common to all ports when the tick occurs.
415+ supervisor_tick ();
416+ // Check _ticks_enabled again because a tick handler may have turned it off.
417+ if (_ticks_enabled ) {
418+ port_interrupt_after_ticks (1 );
419+ }
420+ }
421+ #endif
422+ #ifdef SAMD51
423+ RTC -> MODE0 .INTENCLR .reg = RTC_MODE0_INTENCLR_CMP0 ;
424+ #endif
403425 }
404426}
405427
406- uint64_t port_get_raw_ticks (uint8_t * subticks ) {
428+ static uint32_t _get_count (void ) {
429+ #ifdef SAMD51
407430 while ((RTC -> MODE0 .SYNCBUSY .reg & (RTC_MODE0_SYNCBUSY_COUNTSYNC | RTC_MODE0_SYNCBUSY_COUNT )) != 0 ) {}
408- uint32_t current_ticks = RTC -> MODE0 .COUNT .reg ;
431+ #endif
432+ #ifdef SAMD21
433+ while (RTC -> MODE0 .STATUS .bit .SYNCBUSY != 0 ) {}
434+ #endif
435+
436+ return RTC -> MODE0 .COUNT .reg ;
437+ }
438+
439+ uint64_t port_get_raw_ticks (uint8_t * subticks ) {
440+ uint32_t current_ticks = _get_count ();
409441 if (subticks != NULL ) {
410442 * subticks = (current_ticks % 16 ) * 2 ;
411443 }
@@ -415,18 +447,29 @@ uint64_t port_get_raw_ticks(uint8_t* subticks) {
415447
416448// Enable 1/1024 second tick.
417449void port_enable_tick (void ) {
450+ #ifdef SAMD51
418451 // PER2 will generate an interrupt every 32 ticks of the source 32.768 clock.
419452 RTC -> MODE0 .INTENSET .reg = RTC_MODE0_INTENSET_PER2 ;
453+ #endif
454+ #ifdef SAMD21
455+ _ticks_enabled = true;
456+ port_interrupt_after_ticks (1 );
457+ #endif
420458}
421459
422460// Disable 1/1024 second tick.
423461void port_disable_tick (void ) {
462+ #ifdef SAMD51
424463 RTC -> MODE0 .INTENCLR .reg = RTC_MODE0_INTENCLR_PER2 ;
464+ #endif
465+ #ifdef SAMD21
466+ _ticks_enabled = false;
467+ RTC -> MODE0 .INTENCLR .reg = RTC_MODE0_INTENCLR_CMP0 ;
468+ #endif
425469}
426470
427471void port_interrupt_after_ticks (uint32_t ticks ) {
428- while ((RTC -> MODE0 .SYNCBUSY .reg & (RTC_MODE0_SYNCBUSY_COUNTSYNC | RTC_MODE0_SYNCBUSY_COUNT )) != 0 ) {}
429- uint32_t current_ticks = RTC -> MODE0 .COUNT .reg ;
472+ uint32_t current_ticks = _get_count ();
430473 if (ticks > 1 << 28 ) {
431474 // We'll interrupt sooner with an overflow.
432475 return ;
@@ -437,11 +480,13 @@ void port_interrupt_after_ticks(uint32_t ticks) {
437480}
438481
439482void port_sleep_until_interrupt (void ) {
483+ #ifdef SAMD51
440484 // Clear the FPU interrupt because it can prevent us from sleeping.
441485 if (__get_FPSCR () & ~(0x9f )) {
442486 __set_FPSCR (__get_FPSCR () & ~(0x9f ));
443487 (void ) __get_FPSCR ();
444488 }
489+ #endif
445490 // Call wait for interrupt ourselves if the SD isn't enabled.
446491 __WFI ();
447492}
0 commit comments