samd/clock_config: Extend the SAMD51 us-counter to 60 bit.
This removes the difference in the time.ticks_us() range between SAMD21 and SAMD51. The function mp_hal_ticks_us_64() is added and used for: - SAMD51's mp_hal_ticks_us and mp_hal_delay_us(). For SAMD21, keep the previous methods, which are faster. - mp_hal_ticks_ms() and mp_hal_tick_ms_64(), which saves some bytes and removes a potential race condition every 50 days. Also set the us-counter for SAMD51 to 16 MHz for a faster reading of the microsecond value. Note: With SAMD51, mp_hal_ticks_us_64() has a 60 bit range only, which is still a long time (~36000 years).
This commit is contained in:
parent
fc9d66fac6
commit
e33db80a59
|
@ -190,7 +190,7 @@ void init_clocks(uint32_t cpu_freq) {
|
|||
// GCLK0: 48MHz from DFLL48M or 48 - 200 MHz from DPLL0 (SAMD51)
|
||||
// GCLK1: 32768 Hz from 32KULP or DFLL48M
|
||||
// GCLK2: 8-48MHz from DFLL48M for Peripheral devices
|
||||
// GCLK3: 8Mhz for the us-counter (TC0/TC1)
|
||||
// GCLK3: 16Mhz for the us-counter (TC0/TC1)
|
||||
// GCLK4: 32kHz from crystal, if present
|
||||
// GCLK5: 48MHz from DFLL48M for USB
|
||||
// DPLL0: 48 - 200 MHz
|
||||
|
@ -204,7 +204,7 @@ void init_clocks(uint32_t cpu_freq) {
|
|||
// Setup DPLL0 to 120MHz
|
||||
// Setup GCLK0 to 120MHz
|
||||
// Setup GCLK2 to 48MHz for Peripherals
|
||||
// Setup GCLK3 to 8MHz for TC0/TC1
|
||||
// Setup GCLK3 to 16MHz for TC0/TC1
|
||||
// Setup GCLK4 to 32kHz crystal, if present
|
||||
// Setup GCLK5 to 48 MHz
|
||||
|
||||
|
@ -320,8 +320,8 @@ void init_clocks(uint32_t cpu_freq) {
|
|||
while (GCLK->SYNCBUSY.bit.GENCTRL2) {
|
||||
}
|
||||
|
||||
// Setup GCLK3 for 8MHz, Used for TC0/1 counter
|
||||
GCLK->GENCTRL[3].reg = GCLK_GENCTRL_DIV(6) | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL;
|
||||
// Setup GCLK3 for 16MHz, Used for TC0/1 counter
|
||||
GCLK->GENCTRL[3].reg = GCLK_GENCTRL_DIV(3) | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL;
|
||||
while (GCLK->SYNCBUSY.bit.GENCTRL3) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,6 @@ unsigned long trng_random_u32(void);
|
|||
#endif
|
||||
#endif
|
||||
|
||||
// Due to a limitation in the TC counter for us, the ticks period is 2**29
|
||||
#define MICROPY_PY_UTIME_TICKS_PERIOD (0x20000000)
|
||||
|
||||
// fatfs configuration used in ffconf.h
|
||||
#define MICROPY_FATFS_ENABLE_LFN (1)
|
||||
#define MICROPY_FATFS_RPATH (2)
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#define MICROPY_HW_STDIN_BUFFER_LEN 128
|
||||
#endif
|
||||
|
||||
extern volatile uint32_t ticks_us64_upper;
|
||||
|
||||
STATIC uint8_t stdin_ringbuf_array[MICROPY_HW_STDIN_BUFFER_LEN];
|
||||
ringbuf_t stdin_ringbuf = { stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0 };
|
||||
|
||||
|
@ -111,19 +113,47 @@ void mp_hal_delay_ms(mp_uint_t ms) {
|
|||
|
||||
void mp_hal_delay_us(mp_uint_t us) {
|
||||
if (us > 0) {
|
||||
uint32_t start = mp_hal_ticks_us();
|
||||
#if defined(MCU_SAMD21)
|
||||
// SAMD21 counter has effective 32 bit width
|
||||
uint32_t start = mp_hal_ticks_us();
|
||||
while ((mp_hal_ticks_us() - start) < us) {
|
||||
}
|
||||
#elif defined(MCU_SAMD51)
|
||||
// SAMD51 counter has effective 29 bit width
|
||||
while (((mp_hal_ticks_us() - start) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)) < us) {
|
||||
#else
|
||||
uint64_t stop = mp_hal_ticks_us_64() + us;
|
||||
while (mp_hal_ticks_us_64() < stop) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t mp_hal_ticks_us_64(void) {
|
||||
uint32_t us64_upper = ticks_us64_upper;
|
||||
uint32_t us64_lower;
|
||||
uint8_t intflag;
|
||||
__disable_irq();
|
||||
#if defined(MCU_SAMD21)
|
||||
us64_lower = REG_TC4_COUNT32_COUNT;
|
||||
intflag = TC4->COUNT32.INTFLAG.reg;
|
||||
#elif defined(MCU_SAMD51)
|
||||
TC0->COUNT32.CTRLBSET.reg = TC_CTRLBSET_CMD_READSYNC;
|
||||
while (TC0->COUNT32.CTRLBSET.reg != 0) {
|
||||
}
|
||||
us64_lower = REG_TC0_COUNT32_COUNT;
|
||||
intflag = TC0->COUNT32.INTFLAG.reg;
|
||||
#endif
|
||||
__enable_irq();
|
||||
if ((intflag & TC_INTFLAG_OVF) && us64_lower < 0x10000000) {
|
||||
// The timer counter overflowed before reading it but the IRQ handler
|
||||
// has not yet been called, so perform the IRQ arithmetic now.
|
||||
us64_upper++;
|
||||
}
|
||||
#if defined(MCU_SAMD21)
|
||||
return ((uint64_t)us64_upper << 32) | us64_lower;
|
||||
#elif defined(MCU_SAMD51)
|
||||
return ((uint64_t)us64_upper << 28) | (us64_lower >> 4);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
|
||||
uintptr_t ret = 0;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
extern int mp_interrupt_char;
|
||||
extern volatile uint32_t systick_ms;
|
||||
extern volatile uint32_t systick_ms_upper;
|
||||
uint64_t mp_hal_ticks_us_64(void);
|
||||
|
||||
void mp_hal_set_interrupt_char(int c);
|
||||
|
||||
|
@ -47,28 +47,19 @@ void mp_hal_set_interrupt_char(int c);
|
|||
|
||||
#define mp_hal_delay_us_fast mp_hal_delay_us
|
||||
|
||||
static inline mp_uint_t mp_hal_ticks_ms(void) {
|
||||
return systick_ms;
|
||||
static inline uint64_t mp_hal_ticks_ms_64(void) {
|
||||
return mp_hal_ticks_us_64() / 1000;
|
||||
}
|
||||
|
||||
static inline uint64_t mp_hal_ticks_ms_64(void) {
|
||||
return ((uint64_t)systick_ms_upper << 32) + systick_ms;
|
||||
static inline mp_uint_t mp_hal_ticks_ms(void) {
|
||||
return (mp_uint_t)mp_hal_ticks_ms_64();
|
||||
}
|
||||
|
||||
static inline mp_uint_t mp_hal_ticks_us(void) {
|
||||
#if defined(MCU_SAMD21)
|
||||
|
||||
return REG_TC4_COUNT32_COUNT;
|
||||
|
||||
#elif defined(MCU_SAMD51)
|
||||
|
||||
TC0->COUNT32.CTRLBSET.reg = TC_CTRLBSET_CMD_READSYNC;
|
||||
while (TC0->COUNT32.CTRLBSET.reg != 0) {
|
||||
}
|
||||
return REG_TC0_COUNT32_COUNT >> 3;
|
||||
|
||||
#else
|
||||
return systick_ms * 1000;
|
||||
return (mp_uint_t)mp_hal_ticks_us_64();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -89,7 +80,7 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) {
|
|||
#endif
|
||||
|
||||
static inline uint64_t mp_hal_time_ns(void) {
|
||||
return mp_hal_ticks_ms_64() * 1000000;
|
||||
return mp_hal_ticks_us_64() * 1000;
|
||||
}
|
||||
|
||||
// C-level pin HAL
|
||||
|
|
|
@ -41,7 +41,7 @@ extern void EIC_Handler(void);
|
|||
|
||||
const ISR isr_vector[];
|
||||
volatile uint32_t systick_ms;
|
||||
volatile uint32_t systick_ms_upper;
|
||||
volatile uint32_t ticks_us64_upper;
|
||||
|
||||
void Reset_Handler(void) __attribute__((naked));
|
||||
void Reset_Handler(void) {
|
||||
|
@ -93,15 +93,27 @@ void Default_Handler(void) {
|
|||
void SysTick_Handler(void) {
|
||||
uint32_t next_tick = systick_ms + 1;
|
||||
systick_ms = next_tick;
|
||||
if (systick_ms == 0) {
|
||||
systick_ms_upper += 1;
|
||||
}
|
||||
|
||||
if (soft_timer_next == next_tick) {
|
||||
pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler);
|
||||
}
|
||||
}
|
||||
|
||||
void us_timer_IRQ(void) {
|
||||
#if defined(MCU_SAMD21)
|
||||
if (TC4->COUNT32.INTFLAG.reg & TC_INTFLAG_OVF) {
|
||||
ticks_us64_upper++;
|
||||
}
|
||||
TC4->COUNT32.INTFLAG.reg = TC_INTFLAG_OVF;
|
||||
#elif defined(MCU_SAMD51)
|
||||
if (TC0->COUNT32.INTFLAG.reg & TC_INTFLAG_OVF) {
|
||||
ticks_us64_upper++;
|
||||
}
|
||||
TC0->COUNT32.INTFLAG.reg = TC_INTFLAG_OVF;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Sercom IRQ handler support
|
||||
void (*sercom_irq_handler_table[SERCOM_INST_NUM])(int num) = {};
|
||||
|
||||
void sercom_register_irq(int sercom_id, void (*sercom_irq_handler)) {
|
||||
|
@ -180,7 +192,7 @@ const ISR isr_vector[] __attribute__((section(".isr_vector"))) = {
|
|||
0, // 16 Timer Counter Control 1 (TCC1)
|
||||
0, // 17 Timer Counter Control 2 (TCC2)
|
||||
0, // 18 Basic Timer Counter 3 (TC3)
|
||||
0, // 19 Basic Timer Counter 4 (TC4)
|
||||
&us_timer_IRQ, // 19 Basic Timer Counter 4 (TC4)
|
||||
0, // 20 Basic Timer Counter 5 (TC5)
|
||||
0, // 21 Basic Timer Counter 6 (TC6)
|
||||
0, // 22 Basic Timer Counter 7 (TC7)
|
||||
|
@ -316,7 +328,7 @@ const ISR isr_vector[] __attribute__((section(".isr_vector"))) = {
|
|||
0, // 104 Timer Counter Control 4 (TCC4): TCC4_CNT_A ...
|
||||
0, // 105 Timer Counter Control 4 (TCC4): TCC4_MC_0
|
||||
0, // 106 Timer Counter Control 4 (TCC4): TCC4_MC_1
|
||||
0, // 107 Basic Timer Counter 0 (TC0)
|
||||
&us_timer_IRQ, // 107 Basic Timer Counter 0 (TC0)
|
||||
0, // 108 Basic Timer Counter 1 (TC1)
|
||||
0, // 109 Basic Timer Counter 2 (TC2)
|
||||
0, // 110 Basic Timer Counter 3 (TC3)
|
||||
|
|
|
@ -68,7 +68,7 @@ static void usb_init(void) {
|
|||
tusb_init();
|
||||
}
|
||||
|
||||
// Initialize the microsecond counter on TC 0/1
|
||||
// Initialize the µs counter on TC 0/1 or TC4/5
|
||||
void init_us_counter(void) {
|
||||
#if defined(MCU_SAMD21)
|
||||
|
||||
|
@ -89,6 +89,9 @@ void init_us_counter(void) {
|
|||
TC4->COUNT32.READREQ.reg = TC_READREQ_RREQ | TC_READREQ_RCONT | 0x10;
|
||||
while (TC4->COUNT32.STATUS.bit.SYNCBUSY) {
|
||||
}
|
||||
// Enable the IRQ
|
||||
TC4->COUNT32.INTENSET.reg = TC_INTENSET_OVF;
|
||||
NVIC_EnableIRQ(TC4_IRQn);
|
||||
|
||||
#elif defined(MCU_SAMD51)
|
||||
|
||||
|
@ -107,6 +110,9 @@ void init_us_counter(void) {
|
|||
while (TC0->COUNT32.SYNCBUSY.bit.ENABLE) {
|
||||
}
|
||||
|
||||
// Enable the IRQ
|
||||
TC0->COUNT32.INTENSET.reg = TC_INTENSET_OVF;
|
||||
NVIC_EnableIRQ(TC0_IRQn);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue