atmel-samd: Rework tick timer to use TC5 and support neopixel status LED.

The tick timer needed to be reworked because the ASF delay functions also
use the SysTick timer. Now, it uses TC5 and calls out to the autoreset
logic every tick. Fixes #43.

Added neopixel status colors and corrected the latch time from ms to us.
Fixes #42.
This commit is contained in:
Scott Shawcroft 2016-10-28 20:16:39 -07:00
parent 9008b93962
commit 5b3a143ffe
18 changed files with 182 additions and 109 deletions

View File

@ -161,6 +161,7 @@ SRC_C = \
mphalport.c \ mphalport.c \
pin_named_pins.c \ pin_named_pins.c \
samdneopixel.c \ samdneopixel.c \
tick.c \
$(FLASH_IMPL) \ $(FLASH_IMPL) \
asf/common/services/sleepmgr/samd/sleepmgr.c \ asf/common/services/sleepmgr/samd/sleepmgr.c \
asf/common/services/storage/ctrl_access/ctrl_access.c \ asf/common/services/storage/ctrl_access/ctrl_access.c \

View File

@ -27,46 +27,28 @@
#include "autoreset.h" #include "autoreset.h"
#include "asf/sam0/drivers/tc/tc_interrupt.h" #include "asf/sam0/drivers/tc/tc_interrupt.h"
#include "lib/mp-readline/readline.h"
#include "py/mphal.h" #include "py/mphal.h"
struct tc_module autoreset_timer;
static bool autoreset_initialized = false;
static bool autoreset_enabled = false;
extern void inject_character(char);
void mp_keyboard_interrupt(void); void mp_keyboard_interrupt(void);
void autoreset_callback(struct tc_module *const module_inst) { volatile uint32_t autoreset_delay_ms = 0;
if (autoreset_enabled) { bool autoreset_enabled = false;
mp_keyboard_interrupt(); volatile bool reset_next_character = false;
inject_character(CHAR_CTRL_D);
}
tc_stop_counter(&autoreset_timer); inline void autoreset_tick() {
} if (autoreset_delay_ms == 0) {
return;
void autoreset_init() { }
#ifdef AUTORESET_TIMER if (autoreset_delay_ms == 1 && autoreset_enabled && !reset_next_character) {
struct tc_config config_tc; mp_keyboard_interrupt();
tc_get_config_defaults(&config_tc); reset_next_character = true;
config_tc.counter_size = TC_COUNTER_SIZE_16BIT; }
config_tc.clock_prescaler = TC_CLOCK_PRESCALER_DIV256; autoreset_delay_ms--;
config_tc.counter_16_bit.compare_capture_channel[0] = 0xFFFF;
tc_init(&autoreset_timer, AUTORESET_TIMER, &config_tc);
tc_enable(&autoreset_timer);
tc_register_callback(&autoreset_timer, autoreset_callback, TC_CALLBACK_CC_CHANNEL0);
tc_enable_callback(&autoreset_timer, TC_CALLBACK_CC_CHANNEL0);
tc_stop_counter(&autoreset_timer);
autoreset_initialized = true;
#endif
} }
void autoreset_enable() { void autoreset_enable() {
autoreset_enabled = true; autoreset_enabled = true;
reset_next_character = false;
} }
void autoreset_disable() { void autoreset_disable() {
@ -74,14 +56,9 @@ void autoreset_disable() {
} }
void autoreset_start() { void autoreset_start() {
if (!autoreset_initialized) return; autoreset_delay_ms = AUTORESET_DELAY_MS;
tc_stop_counter(&autoreset_timer);
tc_start_counter(&autoreset_timer);
} }
void autoreset_stop() { void autoreset_stop() {
if (!autoreset_initialized) return; autoreset_delay_ms = 0;
tc_stop_counter(&autoreset_timer);
} }

View File

@ -27,10 +27,12 @@
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_AUTORESET_H__ #ifndef __MICROPY_INCLUDED_ATMEL_SAMD_AUTORESET_H__
#define __MICROPY_INCLUDED_ATMEL_SAMD_AUTORESET_H__ #define __MICROPY_INCLUDED_ATMEL_SAMD_AUTORESET_H__
#include "asf/sam0/drivers/tc/tc.h" #include <stdbool.h>
extern volatile bool reset_next_character;
void autoreset_tick();
void autoreset_callback(struct tc_module *const module_inst);
void autoreset_init();
void autoreset_start(); void autoreset_start();
void autoreset_stop(); void autoreset_stop();
void autoreset_enable(); void autoreset_enable();

View File

@ -7,4 +7,6 @@
#define MICROPY_HW_LED_TX PIN_PA27 #define MICROPY_HW_LED_TX PIN_PA27
#define MICROPY_HW_LED_RX PIN_PB03 #define MICROPY_HW_LED_RX PIN_PB03
#define AUTORESET_TIMER TC5 #define MICROPY_HW_NEOPIXEL PIN_PB22
#define AUTORESET_DELAY_MS 10

View File

@ -6,4 +6,4 @@
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Adalogger" #define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Adalogger"
#define MICROPY_HW_MCU_NAME "samd21g18" #define MICROPY_HW_MCU_NAME "samd21g18"
#define AUTORESET_TIMER TC5 #define AUTORESET_DELAY_MS 10

View File

@ -6,4 +6,4 @@
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Basic" #define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Basic"
#define MICROPY_HW_MCU_NAME "samd21g18" #define MICROPY_HW_MCU_NAME "samd21g18"
#define AUTORESET_TIMER TC5 #define AUTORESET_DELAY_MS 10

View File

@ -8,6 +8,8 @@
#define MICROPY_HW_LED_TX PIN_PA27 #define MICROPY_HW_LED_TX PIN_PA27
#define MICROPY_HW_LED_RX PIN_PB03 #define MICROPY_HW_LED_RX PIN_PB03
#define MICROPY_HW_NEOPIXEL PIN_PA30
#define SPI_FLASH_BAUDRATE (1000000) #define SPI_FLASH_BAUDRATE (1000000)
// Off-board flash // Off-board flash
@ -30,4 +32,4 @@
#define SPI_FLASH_CS PIN_PA13 #define SPI_FLASH_CS PIN_PA13
#define SPI_FLASH_SERCOM SERCOM4 #define SPI_FLASH_SERCOM SERCOM4
#define AUTORESET_TIMER TC5 #define AUTORESET_DELAY_MS 500

View File

@ -23,6 +23,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "internal_flash.h"
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -36,7 +37,7 @@
#include "asf/sam0/drivers/nvm/nvm.h" #include "asf/sam0/drivers/nvm/nvm.h"
#include "asf/sam0/drivers/port/port.h" #include "asf/sam0/drivers/port/port.h"
#include "internal_flash.h" #include "samdneopixel.h"
#define TOTAL_INTERNAL_FLASH_SIZE 0x010000 #define TOTAL_INTERNAL_FLASH_SIZE 0x010000
@ -173,6 +174,9 @@ bool internal_flash_write_block(const uint8_t *src, uint32_t block) {
#ifdef MICROPY_HW_LED_MSC #ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, true); port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
#endif #endif
#ifdef MICROPY_HW_NEOPIXEL
temp_status_color(0x8f, 0x00, 0x00);
#endif
// non-MBR block, copy to cache // non-MBR block, copy to cache
volatile uint32_t dest = convert_block_to_flash_addr(block); volatile uint32_t dest = convert_block_to_flash_addr(block);
if (dest == -1) { if (dest == -1) {
@ -210,6 +214,9 @@ bool internal_flash_write_block(const uint8_t *src, uint32_t block) {
return false; return false;
} }
} }
#ifdef MICROPY_HW_NEOPIXEL
clear_temp_status();
#endif
#ifdef MICROPY_HW_LED_MSC #ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, false); port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
#endif #endif

View File

@ -26,6 +26,8 @@
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H__ #ifndef __MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H__
#define __MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H__ #define __MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H__
#include <stdbool.h>
#include "mpconfigport.h" #include "mpconfigport.h"
#define INTERNAL_FLASH_BLOCK_SIZE (512) #define INTERNAL_FLASH_BLOCK_SIZE (512)

View File

@ -25,6 +25,8 @@
#include "autoreset.h" #include "autoreset.h"
#include "mpconfigboard.h" #include "mpconfigboard.h"
#include "modmachine_pin.h" #include "modmachine_pin.h"
#include "samdneopixel.h"
#include "tick.h"
fs_user_mount_t fs_user_mount_flash; fs_user_mount_t fs_user_mount_flash;
@ -173,6 +175,7 @@ static char *stack_top;
static char heap[16384]; static char heap[16384];
void reset_mp() { void reset_mp() {
new_status_color(0x8f, 0x00, 0x8f);
autoreset_stop(); autoreset_stop();
autoreset_enable(); autoreset_enable();
@ -198,14 +201,20 @@ void reset_mp() {
} }
void start_mp() { void start_mp() {
#ifdef AUTORESET_TIMER #ifdef AUTORESET_DELAY_MS
mp_hal_stdout_tx_str("\r\n"); mp_hal_stdout_tx_str("\r\n");
mp_hal_stdout_tx_str("Auto-soft reset is on. Simply save files over USB to run them.\r\n"); mp_hal_stdout_tx_str("Auto-soft reset is on. Simply save files over USB to run them.\r\n");
mp_hal_stdout_tx_str("Type anything into the REPL to disable and manually reset (CTRL-D) to re-enable.\r\n"); mp_hal_stdout_tx_str("Type anything into the REPL to disable and manually reset (CTRL-D) to re-enable.\r\n");
#endif #endif
new_status_color(0x00, 0x00, 0x8f);
mp_hal_stdout_tx_str("boot.py output:\r\n"); mp_hal_stdout_tx_str("boot.py output:\r\n");
pyexec_file("boot.py"); int ret = pyexec_file("boot.py");
if (ret & PYEXEC_FORCED_EXIT) {
return;
}
new_status_color(0x00, 0x8f, 0x00);
mp_hal_stdout_tx_str("\r\nmain.py output:\r\n"); mp_hal_stdout_tx_str("\r\nmain.py output:\r\n");
pyexec_file("main.py"); pyexec_file("main.py");
} }
@ -230,10 +239,6 @@ int main(int argc, char **argv) {
// as current dir. // as current dir.
init_flash_fs(); init_flash_fs();
// Initialize the autoreset timer. It will automatically reset the repl
// after a burst of writes to the FS.
autoreset_init();
// Start USB after getting everything going. // Start USB after getting everything going.
#ifdef USB_REPL #ifdef USB_REPL
udc_start(); udc_start();
@ -246,6 +251,7 @@ int main(int argc, char **argv) {
// The REPL mode can change, or it can request a soft reset. // The REPL mode can change, or it can request a soft reset.
int exit_code = 0; int exit_code = 0;
for (;;) { for (;;) {
new_status_color(0x3f, 0x3f, 0x3f);
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
exit_code = pyexec_raw_repl(); exit_code = pyexec_raw_repl();
} else { } else {
@ -315,7 +321,9 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c
#if MICROPY_MIN_USE_SAMD21_MCU #if MICROPY_MIN_USE_SAMD21_MCU
#ifdef UART_REPL
struct usart_module usart_instance; struct usart_module usart_instance;
#endif
#ifdef ENABLE_MICRO_TRACE_BUFFER #ifdef ENABLE_MICRO_TRACE_BUFFER
// Stores 2 ^ TRACE_BUFFER_MAGNITUDE_PACKETS packets. // Stores 2 ^ TRACE_BUFFER_MAGNITUDE_PACKETS packets.
@ -364,8 +372,8 @@ void samd21_init(void) {
board_init(); board_init();
// SysTick millisecond timer initialization. // Configure millisecond timer initialization.
SysTick_Config(system_cpu_clock_get_hz() / 1000); tick_init();
// Uncomment to init PIN_PA17 for debugging. // Uncomment to init PIN_PA17 for debugging.
// struct port_config pin_conf; // struct port_config pin_conf;
@ -374,6 +382,16 @@ void samd21_init(void) {
// pin_conf.direction = PORT_PIN_DIR_OUTPUT; // pin_conf.direction = PORT_PIN_DIR_OUTPUT;
// port_pin_set_config(MICROPY_HW_LED1, &pin_conf); // port_pin_set_config(MICROPY_HW_LED1, &pin_conf);
// port_pin_set_output_level(MICROPY_HW_LED1, false); // port_pin_set_output_level(MICROPY_HW_LED1, false);
#ifdef MICROPY_HW_NEOPIXEL
struct port_config pin_conf;
port_get_config_defaults(&pin_conf);
pin_conf.direction = PORT_PIN_DIR_OUTPUT;
port_pin_set_config(MICROPY_HW_NEOPIXEL, &pin_conf);
port_pin_set_output_level(MICROPY_HW_NEOPIXEL, false);
#endif
} }
#endif #endif

View File

@ -7,6 +7,7 @@
#include "asf/common2/services/delay/delay.h" #include "asf/common2/services/delay/delay.h"
#include "asf/sam0/drivers/port/port.h" #include "asf/sam0/drivers/port/port.h"
#include "asf/sam0/drivers/sercom/usart/usart.h" #include "asf/sam0/drivers/sercom/usart/usart.h"
#include "lib/mp-readline/readline.h"
#include "py/mphal.h" #include "py/mphal.h"
#include "py/mpstate.h" #include "py/mpstate.h"
#include "py/smallint.h" #include "py/smallint.h"
@ -68,40 +69,6 @@ void usb_rts_notify(uint8_t port, bool set) {
return; return;
} }
void inject_character(char c) {
// Introduce a critical section to avoid buffer corruption. We use
// cpu_irq_save instead of cpu_irq_disable because we don't know the
// current state of IRQs. They may have been turned off already and
// we don't want to accidentally turn them back on.
irqflags_t flags = cpu_irq_save();
// If our buffer is full, then don't get another character otherwise
// we'll lose a previous character.
if (usb_rx_count >= USB_RX_BUF_SIZE) {
cpu_irq_restore(flags);
return;
}
uint8_t current_tail = usb_rx_buf_tail;
// Pretend we've received a character so that any nested calls to
// this function have to consider the spot we've reserved.
if ((USB_RX_BUF_SIZE - 1) == usb_rx_buf_tail) {
// Reached the end of buffer, revert back to beginning of
// buffer.
usb_rx_buf_tail = 0x00;
} else {
usb_rx_buf_tail++;
}
// The count of characters present in receive buffer is
// incremented.
usb_rx_count++;
// We put the next character where we expected regardless of whether
// the next character was already loaded in the buffer.
usb_rx_buf[current_tail] = c;
cpu_irq_restore(flags);
}
void usb_rx_notify(void) void usb_rx_notify(void)
{ {
irqflags_t flags; irqflags_t flags;
@ -191,6 +158,9 @@ int mp_hal_stdin_rx_chr(void) {
udi_msc_process_trans(); udi_msc_process_trans();
} }
#ifdef USB_REPL #ifdef USB_REPL
if (reset_next_character) {
return CHAR_CTRL_D;
}
if (usb_rx_count > 0) { if (usb_rx_count > 0) {
#ifdef MICROPY_HW_LED_RX #ifdef MICROPY_HW_LED_RX
port_pin_toggle_output_level(MICROPY_HW_LED_RX); port_pin_toggle_output_level(MICROPY_HW_LED_RX);
@ -277,18 +247,6 @@ void mp_hal_delay_us(mp_uint_t delay) {
delay_us(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 flags that will be saved and restored during disable/Enable
// interrupt functions below. // interrupt functions below.
static irqflags_t irq_flags; static irqflags_t irq_flags;
@ -297,14 +255,10 @@ void mp_hal_disable_all_interrupts(void) {
// Disable all interrupt sources for timing critical sections. // Disable all interrupt sources for timing critical sections.
// Disable ASF-based interrupts. // Disable ASF-based interrupts.
irq_flags = cpu_irq_save(); irq_flags = cpu_irq_save();
// Disable SysTick interrupt.
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
} }
void mp_hal_enable_all_interrupts(void) { void mp_hal_enable_all_interrupts(void) {
// Enable all interrupt sources after timing critical sections. // Enable all interrupt sources after timing critical sections.
// Restore SysTick interrupt.
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
// Restore ASF-based interrupts. // Restore ASF-based interrupts.
cpu_irq_restore(irq_flags); cpu_irq_restore(irq_flags);
} }

View File

@ -32,10 +32,10 @@
#define USB_RX_BUF_SIZE 128 #define USB_RX_BUF_SIZE 128
// Global millisecond tick count (driven by SysTick interrupt). // Global millisecond tick count (driven by SysTick interrupt).
extern volatile uint32_t systick_ticks_ms; extern volatile uint32_t ticks_ms;
static inline mp_uint_t mp_hal_ticks_ms(void) { static inline mp_uint_t mp_hal_ticks_ms(void) {
return systick_ticks_ms; return ticks_ms;
} }
void mp_hal_set_interrupt_char(int c); void mp_hal_set_interrupt_char(int c);

View File

@ -5,6 +5,30 @@
#include "samdneopixel.h" #include "samdneopixel.h"
#ifdef MICROPY_HW_NEOPIXEL
static uint8_t status_neopixel_color[3];
#endif
extern void new_status_color(uint8_t r, uint8_t g, uint8_t b) {
#ifdef MICROPY_HW_NEOPIXEL
status_neopixel_color[0] = g;
status_neopixel_color[1] = r;
status_neopixel_color[2] = b;
samd_neopixel_write(MICROPY_HW_NEOPIXEL, status_neopixel_color, 3, true);
#endif
}
extern void temp_status_color(uint8_t r, uint8_t g, uint8_t b) {
#ifdef MICROPY_HW_NEOPIXEL
uint8_t colors[3] = {g, r, b};
samd_neopixel_write(MICROPY_HW_NEOPIXEL, colors, 3, true);
#endif
}
extern void clear_temp_status() {
#ifdef MICROPY_HW_NEOPIXEL
samd_neopixel_write(MICROPY_HW_NEOPIXEL, status_neopixel_color, 3, true);
#endif
}
void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) { void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) {
// This is adapted directly from the Adafruit NeoPixel library SAMD21G18A code: // This is adapted directly from the Adafruit NeoPixel library SAMD21G18A code:
// https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp // https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp
@ -82,8 +106,8 @@ void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool
// Turn on interrupts after timing-sensitive code. // Turn on interrupts after timing-sensitive code.
mp_hal_enable_all_interrupts(); mp_hal_enable_all_interrupts();
// 50ms delay to let pixels latch to the data that was just sent. // 50us delay to let pixels latch to the data that was just sent.
// This could be optimized to only occur before pixel writes when necessary, // This could be optimized to only occur before pixel writes when necessary,
// like in the Arduino library. // like in the Arduino library.
delay_ms(50); delay_us(50);
} }

View File

@ -4,6 +4,10 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
extern void new_status_color(uint8_t r, uint8_t g, uint8_t b);
extern void temp_status_color(uint8_t r, uint8_t g, uint8_t b);
extern void clear_temp_status();
void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz); void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz);
#endif #endif

View File

@ -23,6 +23,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "spi_flash.h"
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -35,7 +36,7 @@
#include "lib/fatfs/ff.h" #include "lib/fatfs/ff.h"
#include "extmod/fsusermount.h" #include "extmod/fsusermount.h"
#include "spi_flash.h" #include "samdneopixel.h"
#define SPI_FLASH_PART1_START_BLOCK (0x1) #define SPI_FLASH_PART1_START_BLOCK (0x1)
@ -383,6 +384,9 @@ static void spi_flash_flush_keep_cache(bool keep_cache) {
#ifdef MICROPY_HW_LED_MSC #ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, true); port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
#endif #endif
#ifdef MICROPY_HW_NEOPIXEL
temp_status_color(0x8f, 0x00, 0x00);
#endif
// If we've cached to the flash itself flush from there. // If we've cached to the flash itself flush from there.
if (ram_cache == NULL) { if (ram_cache == NULL) {
flush_scratch_flash(); flush_scratch_flash();
@ -390,6 +394,9 @@ static void spi_flash_flush_keep_cache(bool keep_cache) {
flush_ram_cache(keep_cache); flush_ram_cache(keep_cache);
} }
current_sector = NO_SECTOR_LOADED; current_sector = NO_SECTOR_LOADED;
#ifdef MICROPY_HW_NEOPIXEL
clear_temp_status();
#endif
#ifdef MICROPY_HW_LED_MSC #ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, false); port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
#endif #endif

View File

@ -26,6 +26,8 @@
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_SPI_FLASH_H__ #ifndef __MICROPY_INCLUDED_ATMEL_SAMD_SPI_FLASH_H__
#define __MICROPY_INCLUDED_ATMEL_SAMD_SPI_FLASH_H__ #define __MICROPY_INCLUDED_ATMEL_SAMD_SPI_FLASH_H__
#include <stdbool.h>
#include "mpconfigport.h" #include "mpconfigport.h"
// Erase sector size. // Erase sector size.

36
atmel-samd/tick.c Normal file
View File

@ -0,0 +1,36 @@
#include "autoreset.h"
#include "tick.h"
#include "asf/sam0/drivers/tc/tc_interrupt.h"
// Global millisecond tick count
volatile uint32_t ticks_ms = 0;
static struct tc_module ms_timer;
static void ms_tick(struct tc_module *const module_inst) {
// SysTick interrupt handler called when the SysTick timer reaches zero
// (every millisecond).
ticks_ms += 1;
// Keep the counter within the range of 31 bit uint values since that's the
// max value for micropython 'small' ints.
ticks_ms = ticks_ms > (0xFFFFFFFF >> 1) ? 0 : ticks_ms;
#ifdef AUTORESET_DELAY_MS
autoreset_tick();
#endif
}
void tick_init() {
struct tc_config config_tc;
tc_get_config_defaults(&config_tc);
config_tc.counter_size = TC_COUNTER_SIZE_16BIT;
config_tc.clock_prescaler = TC_CLOCK_PRESCALER_DIV1;
tc_set_top_value(&ms_timer, system_cpu_clock_get_hz() / 1000);
tc_init(&ms_timer, TC5, &config_tc);
tc_enable(&ms_timer);
tc_register_callback(&ms_timer, ms_tick, TC_CALLBACK_OVERFLOW);
tc_enable_callback(&ms_timer, TC_CALLBACK_OVERFLOW);
tc_start_counter(&ms_timer);
}

35
atmel-samd/tick.h Normal file
View File

@ -0,0 +1,35 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_TICK_H__
#define __MICROPY_INCLUDED_ATMEL_SAMD_TICK_H__
#include "mpconfigport.h"
extern volatile uint32_t ticks_ms;
void tick_init();
#endif // __MICROPY_INCLUDED_ATMEL_SAMD_TICK_H__