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:
parent
9008b93962
commit
5b3a143ffe
@ -161,6 +161,7 @@ SRC_C = \
|
||||
mphalport.c \
|
||||
pin_named_pins.c \
|
||||
samdneopixel.c \
|
||||
tick.c \
|
||||
$(FLASH_IMPL) \
|
||||
asf/common/services/sleepmgr/samd/sleepmgr.c \
|
||||
asf/common/services/storage/ctrl_access/ctrl_access.c \
|
||||
|
@ -27,46 +27,28 @@
|
||||
#include "autoreset.h"
|
||||
|
||||
#include "asf/sam0/drivers/tc/tc_interrupt.h"
|
||||
#include "lib/mp-readline/readline.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 autoreset_callback(struct tc_module *const module_inst) {
|
||||
if (autoreset_enabled) {
|
||||
mp_keyboard_interrupt();
|
||||
inject_character(CHAR_CTRL_D);
|
||||
volatile uint32_t autoreset_delay_ms = 0;
|
||||
bool autoreset_enabled = false;
|
||||
volatile bool reset_next_character = false;
|
||||
|
||||
inline void autoreset_tick() {
|
||||
if (autoreset_delay_ms == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
tc_stop_counter(&autoreset_timer);
|
||||
}
|
||||
|
||||
void autoreset_init() {
|
||||
#ifdef AUTORESET_TIMER
|
||||
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_DIV256;
|
||||
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
|
||||
if (autoreset_delay_ms == 1 && autoreset_enabled && !reset_next_character) {
|
||||
mp_keyboard_interrupt();
|
||||
reset_next_character = true;
|
||||
}
|
||||
autoreset_delay_ms--;
|
||||
}
|
||||
|
||||
void autoreset_enable() {
|
||||
autoreset_enabled = true;
|
||||
reset_next_character = false;
|
||||
}
|
||||
|
||||
void autoreset_disable() {
|
||||
@ -74,14 +56,9 @@ void autoreset_disable() {
|
||||
}
|
||||
|
||||
void autoreset_start() {
|
||||
if (!autoreset_initialized) return;
|
||||
|
||||
tc_stop_counter(&autoreset_timer);
|
||||
tc_start_counter(&autoreset_timer);
|
||||
autoreset_delay_ms = AUTORESET_DELAY_MS;
|
||||
}
|
||||
|
||||
void autoreset_stop() {
|
||||
if (!autoreset_initialized) return;
|
||||
|
||||
tc_stop_counter(&autoreset_timer);
|
||||
autoreset_delay_ms = 0;
|
||||
}
|
||||
|
@ -27,10 +27,12 @@
|
||||
#ifndef __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_stop();
|
||||
void autoreset_enable();
|
||||
|
@ -7,4 +7,6 @@
|
||||
#define MICROPY_HW_LED_TX PIN_PA27
|
||||
#define MICROPY_HW_LED_RX PIN_PB03
|
||||
|
||||
#define AUTORESET_TIMER TC5
|
||||
#define MICROPY_HW_NEOPIXEL PIN_PB22
|
||||
|
||||
#define AUTORESET_DELAY_MS 10
|
||||
|
@ -6,4 +6,4 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Adalogger"
|
||||
#define MICROPY_HW_MCU_NAME "samd21g18"
|
||||
|
||||
#define AUTORESET_TIMER TC5
|
||||
#define AUTORESET_DELAY_MS 10
|
||||
|
@ -6,4 +6,4 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Basic"
|
||||
#define MICROPY_HW_MCU_NAME "samd21g18"
|
||||
|
||||
#define AUTORESET_TIMER TC5
|
||||
#define AUTORESET_DELAY_MS 10
|
||||
|
@ -8,6 +8,8 @@
|
||||
#define MICROPY_HW_LED_TX PIN_PA27
|
||||
#define MICROPY_HW_LED_RX PIN_PB03
|
||||
|
||||
#define MICROPY_HW_NEOPIXEL PIN_PA30
|
||||
|
||||
#define SPI_FLASH_BAUDRATE (1000000)
|
||||
|
||||
// Off-board flash
|
||||
@ -30,4 +32,4 @@
|
||||
#define SPI_FLASH_CS PIN_PA13
|
||||
#define SPI_FLASH_SERCOM SERCOM4
|
||||
|
||||
#define AUTORESET_TIMER TC5
|
||||
#define AUTORESET_DELAY_MS 500
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "internal_flash.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@ -36,7 +37,7 @@
|
||||
#include "asf/sam0/drivers/nvm/nvm.h"
|
||||
#include "asf/sam0/drivers/port/port.h"
|
||||
|
||||
#include "internal_flash.h"
|
||||
#include "samdneopixel.h"
|
||||
|
||||
#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
|
||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
|
||||
#endif
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
temp_status_color(0x8f, 0x00, 0x00);
|
||||
#endif
|
||||
// non-MBR block, copy to cache
|
||||
volatile uint32_t dest = convert_block_to_flash_addr(block);
|
||||
if (dest == -1) {
|
||||
@ -210,6 +214,9 @@ bool internal_flash_write_block(const uint8_t *src, uint32_t block) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
clear_temp_status();
|
||||
#endif
|
||||
#ifdef MICROPY_HW_LED_MSC
|
||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
|
||||
#endif
|
||||
|
@ -26,6 +26,8 @@
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H__
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "mpconfigport.h"
|
||||
|
||||
#define INTERNAL_FLASH_BLOCK_SIZE (512)
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "autoreset.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "modmachine_pin.h"
|
||||
#include "samdneopixel.h"
|
||||
#include "tick.h"
|
||||
|
||||
fs_user_mount_t fs_user_mount_flash;
|
||||
|
||||
@ -173,6 +175,7 @@ static char *stack_top;
|
||||
static char heap[16384];
|
||||
|
||||
void reset_mp() {
|
||||
new_status_color(0x8f, 0x00, 0x8f);
|
||||
autoreset_stop();
|
||||
autoreset_enable();
|
||||
|
||||
@ -198,14 +201,20 @@ void reset_mp() {
|
||||
}
|
||||
|
||||
void start_mp() {
|
||||
#ifdef AUTORESET_TIMER
|
||||
#ifdef AUTORESET_DELAY_MS
|
||||
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("Type anything into the REPL to disable and manually reset (CTRL-D) to re-enable.\r\n");
|
||||
#endif
|
||||
|
||||
new_status_color(0x00, 0x00, 0x8f);
|
||||
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");
|
||||
pyexec_file("main.py");
|
||||
}
|
||||
@ -230,10 +239,6 @@ int main(int argc, char **argv) {
|
||||
// as current dir.
|
||||
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.
|
||||
#ifdef USB_REPL
|
||||
udc_start();
|
||||
@ -246,6 +251,7 @@ int main(int argc, char **argv) {
|
||||
// The REPL mode can change, or it can request a soft reset.
|
||||
int exit_code = 0;
|
||||
for (;;) {
|
||||
new_status_color(0x3f, 0x3f, 0x3f);
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
||||
exit_code = pyexec_raw_repl();
|
||||
} 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
|
||||
|
||||
#ifdef UART_REPL
|
||||
struct usart_module usart_instance;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MICRO_TRACE_BUFFER
|
||||
// Stores 2 ^ TRACE_BUFFER_MAGNITUDE_PACKETS packets.
|
||||
@ -364,8 +372,8 @@ void samd21_init(void) {
|
||||
|
||||
board_init();
|
||||
|
||||
// SysTick millisecond timer initialization.
|
||||
SysTick_Config(system_cpu_clock_get_hz() / 1000);
|
||||
// Configure millisecond timer initialization.
|
||||
tick_init();
|
||||
|
||||
// Uncomment to init PIN_PA17 for debugging.
|
||||
// struct port_config pin_conf;
|
||||
@ -374,6 +382,16 @@ void samd21_init(void) {
|
||||
// pin_conf.direction = PORT_PIN_DIR_OUTPUT;
|
||||
// port_pin_set_config(MICROPY_HW_LED1, &pin_conf);
|
||||
// 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
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "asf/common2/services/delay/delay.h"
|
||||
#include "asf/sam0/drivers/port/port.h"
|
||||
#include "asf/sam0/drivers/sercom/usart/usart.h"
|
||||
#include "lib/mp-readline/readline.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/smallint.h"
|
||||
@ -68,40 +69,6 @@ void usb_rts_notify(uint8_t port, bool set) {
|
||||
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)
|
||||
{
|
||||
irqflags_t flags;
|
||||
@ -191,6 +158,9 @@ int mp_hal_stdin_rx_chr(void) {
|
||||
udi_msc_process_trans();
|
||||
}
|
||||
#ifdef USB_REPL
|
||||
if (reset_next_character) {
|
||||
return CHAR_CTRL_D;
|
||||
}
|
||||
if (usb_rx_count > 0) {
|
||||
#ifdef 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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
@ -297,14 +255,10 @@ 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);
|
||||
}
|
||||
|
@ -32,10 +32,10 @@
|
||||
#define USB_RX_BUF_SIZE 128
|
||||
|
||||
// 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) {
|
||||
return systick_ticks_ms;
|
||||
return ticks_ms;
|
||||
}
|
||||
|
||||
void mp_hal_set_interrupt_char(int c);
|
||||
|
@ -5,6 +5,30 @@
|
||||
|
||||
#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) {
|
||||
// This is adapted directly from the Adafruit NeoPixel library SAMD21G18A code:
|
||||
// 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.
|
||||
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,
|
||||
// like in the Arduino library.
|
||||
delay_ms(50);
|
||||
delay_us(50);
|
||||
}
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include <stdint.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);
|
||||
|
||||
#endif
|
||||
|
@ -23,6 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "spi_flash.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@ -35,7 +36,7 @@
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
|
||||
#include "spi_flash.h"
|
||||
#include "samdneopixel.h"
|
||||
|
||||
#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
|
||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
|
||||
#endif
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
temp_status_color(0x8f, 0x00, 0x00);
|
||||
#endif
|
||||
// If we've cached to the flash itself flush from there.
|
||||
if (ram_cache == NULL) {
|
||||
flush_scratch_flash();
|
||||
@ -390,6 +394,9 @@ static void spi_flash_flush_keep_cache(bool keep_cache) {
|
||||
flush_ram_cache(keep_cache);
|
||||
}
|
||||
current_sector = NO_SECTOR_LOADED;
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
clear_temp_status();
|
||||
#endif
|
||||
#ifdef MICROPY_HW_LED_MSC
|
||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
|
||||
#endif
|
||||
|
@ -26,6 +26,8 @@
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_SPI_FLASH_H__
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_SPI_FLASH_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "mpconfigport.h"
|
||||
|
||||
// Erase sector size.
|
||||
|
36
atmel-samd/tick.c
Normal file
36
atmel-samd/tick.c
Normal 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
35
atmel-samd/tick.h
Normal 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__
|
Loading…
Reference in New Issue
Block a user