diff --git a/atmel-samd/main.c b/atmel-samd/main.c index d04983afea..77a0f53fd8 100644 --- a/atmel-samd/main.c +++ b/atmel-samd/main.c @@ -316,6 +316,9 @@ void samd21_init(void) { board_init(); + // SysTick millisecond timer initialization. + SysTick_Config(system_cpu_clock_get_hz() / 1000); + // Uncomment to init PIN_PA17 for debugging. // struct port_config pin_conf; // port_get_config_defaults(&pin_conf); diff --git a/atmel-samd/modutime.c b/atmel-samd/modutime.c index 32e6ea2298..575066be41 100644 --- a/atmel-samd/modutime.c +++ b/atmel-samd/modutime.c @@ -64,12 +64,27 @@ STATIC mp_obj_t time_sleep_us(mp_obj_t arg) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_us_obj, time_sleep_us); +STATIC mp_obj_t time_ticks_ms(void) { + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_ms_obj, time_ticks_ms); + +STATIC mp_obj_t time_ticks_diff(mp_obj_t start_in, mp_obj_t end_in) { + // we assume that the arguments come from ticks_xx so are small ints + uint32_t start = MP_OBJ_SMALL_INT_VALUE(start_in); + uint32_t end = MP_OBJ_SMALL_INT_VALUE(end_in); + return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(time_ticks_diff_obj, time_ticks_diff); + STATIC const mp_map_elem_t time_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utime) }, { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&time_sleep_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&time_sleep_ms_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&time_sleep_us_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&time_ticks_ms_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&time_ticks_diff_obj }, }; STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); diff --git a/atmel-samd/mphalport.c b/atmel-samd/mphalport.c index a46af47cd8..3b70b3d052 100644 --- a/atmel-samd/mphalport.c +++ b/atmel-samd/mphalport.c @@ -210,3 +210,35 @@ void mp_hal_delay_us(mp_uint_t delay) { } delay_us(delay); } + +// Global millisecond tick count (driven by SysTick interrupt handler). +volatile uint32_t systick_ticks_ms = 0; + +void SysTick_Handler(void) { + // SysTick interrupt handler called when the SysTick timer reaches zero + // (every millisecond). + systick_ticks_ms += 1; + // Keep the counter within the range of 31 bit uint values since that's the + // max value for micropython 'small' ints. + systick_ticks_ms = systick_ticks_ms > (0xFFFFFFFF >> 1) ? 0 : systick_ticks_ms; +} + +// Interrupt flags that will be saved and restored during disable/Enable +// interrupt functions below. +static irqflags_t irq_flags; + +void mp_hal_disable_all_interrupts(void) { + // Disable all interrupt sources for timing critical sections. + // Disable ASF-based interrupts. + irq_flags = cpu_irq_save(); + // Disable SysTick interrupt. + SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; +} + +void mp_hal_enable_all_interrupts(void) { + // Enable all interrupt sources after timing critical sections. + // Restore SysTick interrupt. + SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; + // Restore ASF-based interrupts. + cpu_irq_restore(irq_flags); +} diff --git a/atmel-samd/mphalport.h b/atmel-samd/mphalport.h index 982960646f..0e8635f648 100644 --- a/atmel-samd/mphalport.h +++ b/atmel-samd/mphalport.h @@ -27,9 +27,21 @@ #ifndef __MICROPY_INCLUDED_ATMEL_SAMD_MPHALPORT_H__ #define __MICROPY_INCLUDED_ATMEL_SAMD_MPHALPORT_H__ +#include "py/obj.h" + #define USB_RX_BUF_SIZE 128 -static inline mp_uint_t mp_hal_ticks_ms(void) { return 0; } +// Global millisecond tick count (driven by SysTick interrupt). +extern volatile uint32_t systick_ticks_ms; + +static inline mp_uint_t mp_hal_ticks_ms(void) { + return systick_ticks_ms; +} + void mp_hal_set_interrupt_char(int c); +void mp_hal_disable_all_interrupts(void); + +void mp_hal_enable_all_interrupts(void); + #endif // __MICROPY_INCLUDED_ATMEL_SAMD_MPHALPORT_H__ diff --git a/atmel-samd/samdneopixel.c b/atmel-samd/samdneopixel.c index 70b27aee71..e271de0467 100644 --- a/atmel-samd/samdneopixel.c +++ b/atmel-samd/samdneopixel.c @@ -1,6 +1,8 @@ #include "asf/common2/services/delay/delay.h" #include "asf/sam0/drivers/port/port.h" +#include "mphalport.h" + #include "samdneopixel.h" void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) { @@ -11,7 +13,7 @@ void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool PortGroup* port; // Turn off interrupts of any kind during timing-sensitive code. - irqflags_t flags = cpu_irq_save(); + mp_hal_disable_all_interrupts(); port = port_get_group_from_gpio_pin(pin); pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code. @@ -78,7 +80,7 @@ void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool } // Turn on interrupts after timing-sensitive code. - cpu_irq_restore(flags); + mp_hal_enable_all_interrupts(); // 50ms delay to let pixels latch to the data that was just sent. // This could be optimized to only occur before pixel writes when necessary,