diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index bb15311e64..041f1d1ad7 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -188,7 +188,6 @@ SRC_ASF := \ hpl/rtc/hpl_rtc.c \ hpl/sercom/hpl_sercom.c \ hpl/systick/hpl_systick.c \ - hpl/tc/hpl_tc.c \ hpl/usb/hpl_usb.c \ usb/class/cdc/device/cdcdf_acm.c \ usb/class/msc/device/mscdf.c \ @@ -227,6 +226,7 @@ SRC_C = \ peripherals.c \ $(CHIP_FAMILY)_pins.c \ tick.c \ + timers.c \ usb.c \ usb_mass_storage.c \ boards/$(BOARD)/board.c \ diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index de45f16e03..ba534811e2 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -34,9 +34,7 @@ #include "atmel_start_pins.h" #include "hal/utils/include/utils_repeat_macro.h" -#ifdef SAMD21 -#include "hpl/gclk/hpl_gclk_base.h" -#endif +#include "timers.h" #include "samd21_pins.h" @@ -55,44 +53,10 @@ const uint16_t prescaler[8] = {1, 2, 4, 8, 16, 64, 256, 1024}; // This bitmask keeps track of which channels of a TCC are currently claimed. #ifdef SAMD21 uint8_t tcc_channels[3] = {0xf0, 0xfc, 0xfc}; -const uint8_t tcc_cc_num[3] = {4, 2, 2}; -const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC3_GCLK_ID, - TC4_GCLK_ID, - TC5_GCLK_ID, -#ifdef TC6_GCLK_ID - , TC6_GCLK_ID -#endif -#ifdef TC7_GCLK_ID - , TC7_GCLK_ID -#endif - }; -const uint8_t tcc_gclk_ids[3] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID}; #endif #ifdef SAMD51 uint8_t tcc_channels[5] = {0xc0, 0xf0, 0xf8, 0xfc, 0xfc}; -static const uint8_t tcc_cc_num[5] = {6, 4, 3, 2, 2}; -const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC0_GCLK_ID, - TC1_GCLK_ID, - TC2_GCLK_ID, - TC3_GCLK_ID -#ifdef TC4_GCLK_ID - , TC4_GCLK_ID #endif -#ifdef TC5_GCLK_ID - , TC5_GCLK_ID -#endif -#ifdef TC6_GCLK_ID - , TC6_GCLK_ID -#endif -#ifdef TC7_GCLK_ID - , TC7_GCLK_ID -#endif - }; -const uint8_t tcc_gclk_ids[5] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID, TCC3_GCLK_ID, - TCC4_GCLK_ID}; -#endif -static Tc* const tc_insts[TC_INST_NUM] = TC_INSTS; -static Tcc* const tcc_insts[TCC_INST_NUM] = TCC_INSTS; void pwmout_reset(void) { // Reset all timers @@ -129,120 +93,12 @@ static uint8_t tcc_channel(const pin_timer_t* t) { return t->wave_output % tcc_cc_num[t->index]; } -static void tc_set_enable(Tc* tc, bool enable) { - tc->COUNT16.CTRLA.bit.ENABLE = enable; - #ifdef SAMD21 - while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) { - /* Wait for sync */ - } - #endif - #ifdef SAMD51 - while (tc->COUNT16.SYNCBUSY.bit.ENABLE != 0) { - /* Wait for sync */ - } - #endif -} - -static void tcc_set_enable(Tcc* tcc, bool enable) { - tcc->CTRLA.bit.ENABLE = enable; - while (tcc->SYNCBUSY.bit.ENABLE != 0) { - /* Wait for sync */ - } -} - -static void tc_wait_for_sync(Tc* tc) { - #ifdef SAMD21 - while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) {} - #endif - #ifdef SAMD51 - while (tc->COUNT16.SYNCBUSY.reg != 0) {} - #endif -} - bool channel_ok(const pin_timer_t* t) { uint8_t channel_bit = 1 << tcc_channel(t); return (!t->is_tc && ((tcc_channels[t->index] & channel_bit) == 0)) || t->is_tc; } -void turn_on_clocks(const pin_timer_t* timer) { - uint8_t gclk_id; - if (timer->is_tc) { - gclk_id = tc_gclk_ids[timer->index]; - } else { - gclk_id = tcc_gclk_ids[timer->index]; - } - // Turn on the clocks for the peripherals. - #ifdef SAMD51 - if (timer->is_tc) { - switch (timer->index) { - case 0: - MCLK->APBAMASK.reg |= MCLK_APBAMASK_TC0; - break; - case 1: - MCLK->APBAMASK.reg |= MCLK_APBAMASK_TC1; - break; - case 2: - MCLK->APBBMASK.reg |= MCLK_APBBMASK_TC2; - break; - case 3: - MCLK->APBBMASK.reg |= MCLK_APBBMASK_TC3; - break; - case 4: - MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC4; - break; - case 5: - MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC5; - break; - case 6: - MCLK->APBDMASK.reg |= MCLK_APBDMASK_TC6; - break; - case 7: - MCLK->APBDMASK.reg |= MCLK_APBDMASK_TC7; - break; - default: - break; - } - } else { - switch (timer->index) { - case 0: - MCLK->APBBMASK.reg |= MCLK_APBBMASK_TCC0; - break; - case 1: - MCLK->APBBMASK.reg |= MCLK_APBBMASK_TCC1; - break; - case 2: - MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC2; - break; - case 3: - MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC3; - break; - case 4: - MCLK->APBDMASK.reg |= MCLK_APBDMASK_TCC4; - break; - default: - break; - } - } - - // FIXME(tannewt): TC4-TC7 can only have 100mhz inputs. - - hri_gclk_write_PCHCTRL_reg(GCLK, gclk_id, - GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); - #endif - - #ifdef SAMD21 - // Determine the clock slot on the APBC bus. TCC0 is the first and 8 slots in. - uint8_t clock_slot = 8 + timer->index; - // We index TCs starting at zero but in memory they begin at three so we have to add three. - if (timer->is_tc) { - clock_slot += 3; - } - PM->APBCMASK.reg |= 1 << clock_slot; - _gclk_enable_channel(gclk_id, GCLK_CLKCTRL_GEN_GCLK0_Val); - #endif -} - void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, const mcu_pin_obj_t* pin, uint16_t duty, @@ -345,7 +201,8 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, } } - turn_on_clocks(timer); + // We use the zeroeth clock on either port to go full speed. + turn_on_clocks(timer->is_tc, timer->index, 0); if (timer->is_tc) { tc_periods[timer->index] = top; diff --git a/ports/atmel-samd/common-hal/pulseio/PulseOut.c b/ports/atmel-samd/common-hal/pulseio/PulseOut.c index 7ebc566f59..35224c8e5d 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.c @@ -35,12 +35,13 @@ #include "py/runtime.h" #include "samd21_pins.h" #include "shared-bindings/pulseio/PulseOut.h" +#include "timers.h" // This timer is shared amongst all PulseOut objects under the assumption that // the code is single threaded. static uint8_t refcount = 0; -static Tc* pulseout_tc_instance = NULL; +static uint8_t pulseout_tc_index = 0xff; static __IO PORT_PINCFG_Type *active_pincfg = NULL; static uint16_t *pulse_buffer = NULL; @@ -56,7 +57,7 @@ static void turn_off(__IO PORT_PINCFG_Type * pincfg) { pincfg->reg = PORT_PINCFG_RESETVALUE; } -void pulse_finish(struct tc_module *const module) { +void pulse_finish(void) { pulse_index++; if (active_pincfg == NULL) { @@ -68,15 +69,27 @@ void pulse_finish(struct tc_module *const module) { return; } current_compare = (current_compare + pulse_buffer[pulse_index] * 3 / 4) & 0xffff; - //tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); + Tc* tc = tc_insts[pulseout_tc_index]; + tc->COUNT16.CC[0].reg = current_compare; if (pulse_index % 2 == 0) { turn_on(active_pincfg); } } +void pulseout_interrupt_handler(uint8_t index) { + if (index != pulseout_tc_index) return; + Tc* tc = tc_insts[index]; + if (!tc->COUNT16.INTFLAG.bit.MC0) return; + + pulse_finish(); + + // Clear the interrupt bit. + tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0; +} + void pulseout_reset() { refcount = 0; - pulseout_tc_instance = NULL; + pulseout_tc_index = 0xff; active_pincfg = NULL; } @@ -84,29 +97,44 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, const pulseio_pwmout_obj_t* carrier) { if (refcount == 0) { // Find a spare timer. - Tc *t = NULL; - Tc *tcs[TC_INST_NUM] = TC_INSTS; - for (uint8_t i = TC_INST_NUM; i > 0; i--) { - if (tcs[i - 1]->COUNT16.CTRLA.bit.ENABLE == 0) { - t = tcs[i - 1]; + Tc *tc = NULL; + uint8_t index = TC_INST_NUM - 1; + for (; index >= 0; index--) { + if (tc_insts[index]->COUNT16.CTRLA.bit.ENABLE == 0) { + tc = tc_insts[index]; break; } } - if (t == NULL) { + if (tc == NULL) { mp_raise_RuntimeError("All timers in use"); } - // struct tc_config config_tc; - // tc_get_config_defaults(&config_tc); - // - // config_tc.counter_size = TC_COUNTER_SIZE_16BIT; - // config_tc.clock_prescaler = TC_CTRLA_PRESCALER_DIV64; - // config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_FREQ; + pulseout_tc_index = index; - // tc_init(MP_STATE_VM(pulseout_tc_instance), t, &config_tc); - // tc_register_callback(MP_STATE_VM(pulseout_tc_instance), pulse_finish, TC_CALLBACK_CC_CHANNEL0); - // tc_enable(MP_STATE_VM(pulseout_tc_instance)); - // tc_stop_counter(MP_STATE_VM(pulseout_tc_instance)); + // We use GCLK0 for SAMD21 and GCLK1 for SAMD51 because they both run at 48mhz making our + // math the same across the boards. + #ifdef SAMD21 + turn_on_clocks(true, index, 0); + #endif + #ifdef SAMD51 + turn_on_clocks(true, index, 1); + #endif + + + #ifdef SAMD21 + tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | + TC_CTRLA_PRESCALER_DIV64 | + TC_CTRLA_WAVEGEN_NFRQ; + #endif + #ifdef SAMD51 + tc_reset(tc); + tc_set_enable(tc, false); + tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER_DIV64; + tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_NFRQ; + #endif + + tc_set_enable(tc, true); + tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_STOP; } refcount++; @@ -138,8 +166,8 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { refcount--; if (refcount == 0) { - //tc_reset(MP_STATE_VM(pulseout_tc_instance)); - pulseout_tc_instance = NULL; + tc_reset(tc_insts[pulseout_tc_index]); + pulseout_tc_index = 0xff; } self->pin = NO_PIN; } @@ -154,11 +182,13 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu pulse_length = length; current_compare = pulses[0] * 3 / 4; - //tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); + Tc* tc = tc_insts[pulseout_tc_index]; + tc->COUNT16.CC[0].reg = current_compare; - //tc_enable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); + tc->COUNT16.INTENSET.reg = TC_INTENSET_MC0; + tc_enable_interrupts(pulseout_tc_index); turn_on(active_pincfg); - //tc_start_counter(MP_STATE_VM(pulseout_tc_instance)); + tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER; while(pulse_index < length) { // Do other things while we wait. The interrupts will handle sending the @@ -168,7 +198,8 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu #endif } - //tc_stop_counter(MP_STATE_VM(pulseout_tc_instance)); - //tc_disable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); + tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_STOP; + tc->COUNT16.INTENCLR.reg = TC_INTENCLR_MC0; + tc_disable_interrupts(pulseout_tc_index); active_pincfg = NULL; } diff --git a/ports/atmel-samd/common-hal/pulseio/PulseOut.h b/ports/atmel-samd/common-hal/pulseio/PulseOut.h index 4294d6d68d..634088128f 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.h +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.h @@ -38,5 +38,6 @@ typedef struct { } pulseio_pulseout_obj_t; void pulseout_reset(void); +void pulseout_interrupt_handler(uint8_t index); #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEOUT_H diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 7a947010db..c120b01369 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -46,6 +46,7 @@ #include "common-hal/analogio/AnalogIn.h" #include "common-hal/analogio/AnalogOut.h" #include "common-hal/microcontroller/Pin.h" +#include "common-hal/pulseio/PulseOut.h" #include "common-hal/pulseio/PWMOut.h" #include "tick.h" @@ -206,8 +207,8 @@ void reset_port(void) { // touchin_reset(); // pdmin_reset(); // pulsein_reset(); -// pulseout_reset(); // #endif + pulseout_reset(); pwmout_reset(); analogin_reset(); diff --git a/ports/atmel-samd/timers.c b/ports/atmel-samd/timers.c new file mode 100644 index 0000000000..3a1b21edfd --- /dev/null +++ b/ports/atmel-samd/timers.c @@ -0,0 +1,258 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#include +#include + +#include "timers.h" + +#include "common-hal/pulseio/PulseOut.h" + +#ifdef SAMD21 +#include "hpl/gclk/hpl_gclk_base.h" +#endif + +// This bitmask keeps track of which channels of a TCC are currently claimed. +#ifdef SAMD21 +const uint8_t tcc_cc_num[3] = {4, 2, 2}; +const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC3_GCLK_ID, + TC4_GCLK_ID, + TC5_GCLK_ID, +#ifdef TC6_GCLK_ID + , TC6_GCLK_ID +#endif +#ifdef TC7_GCLK_ID + , TC7_GCLK_ID +#endif + }; +const uint8_t tcc_gclk_ids[3] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID}; +#endif +#ifdef SAMD51 +static const uint8_t tcc_cc_num[5] = {6, 4, 3, 2, 2}; +const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC0_GCLK_ID, + TC1_GCLK_ID, + TC2_GCLK_ID, + TC3_GCLK_ID +#ifdef TC4_GCLK_ID + , TC4_GCLK_ID +#endif +#ifdef TC5_GCLK_ID + , TC5_GCLK_ID +#endif +#ifdef TC6_GCLK_ID + , TC6_GCLK_ID +#endif +#ifdef TC7_GCLK_ID + , TC7_GCLK_ID +#endif + }; +const uint8_t tcc_gclk_ids[5] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID, TCC3_GCLK_ID, + TCC4_GCLK_ID}; +#endif +Tc* const tc_insts[TC_INST_NUM] = TC_INSTS; +Tcc* const tcc_insts[TCC_INST_NUM] = TCC_INSTS; + +IRQn_Type const tc_irq[TC_INST_NUM] = { +#ifdef TC0 + TC0_IRQn, +#endif +#ifdef TC1 + TC1_IRQn, +#endif +#ifdef TC2 + TC2_IRQn, +#endif + TC3_IRQn, + TC4_IRQn, + TC5_IRQn +#ifdef TC6 + , TC6_IRQn +#endif +#ifdef TC7 + , TC7_IRQn +#endif +}; + +void turn_on_clocks(bool is_tc, uint8_t index, uint32_t gclk_index) { + uint8_t gclk_id; + if (is_tc) { + gclk_id = tc_gclk_ids[index]; + } else { + gclk_id = tcc_gclk_ids[index]; + } + // Turn on the clocks for the peripherals. + #ifdef SAMD51 + if (is_tc) { + switch (index) { + case 0: + MCLK->APBAMASK.reg |= MCLK_APBAMASK_TC0; + break; + case 1: + MCLK->APBAMASK.reg |= MCLK_APBAMASK_TC1; + break; + case 2: + MCLK->APBBMASK.reg |= MCLK_APBBMASK_TC2; + break; + case 3: + MCLK->APBBMASK.reg |= MCLK_APBBMASK_TC3; + break; + case 4: + MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC4; + break; + case 5: + MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC5; + break; + case 6: + MCLK->APBDMASK.reg |= MCLK_APBDMASK_TC6; + break; + case 7: + MCLK->APBDMASK.reg |= MCLK_APBDMASK_TC7; + break; + default: + break; + } + } else { + switch (index) { + case 0: + MCLK->APBBMASK.reg |= MCLK_APBBMASK_TCC0; + break; + case 1: + MCLK->APBBMASK.reg |= MCLK_APBBMASK_TCC1; + break; + case 2: + MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC2; + break; + case 3: + MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC3; + break; + case 4: + MCLK->APBDMASK.reg |= MCLK_APBDMASK_TCC4; + break; + default: + break; + } + } + + // FIXME(tannewt): TC4-TC7 can only have 100mhz inputs. + + hri_gclk_write_PCHCTRL_reg(GCLK, gclk_id, + gclk_index | (1 << GCLK_PCHCTRL_CHEN_Pos)); + #endif + + #ifdef SAMD21 + // Determine the clock slot on the APBC bus. TCC0 is the first and 8 slots in. + uint8_t clock_slot = 8 + index; + // We index TCs starting at zero but in memory they begin at three so we have to add three. + if (is_tc) { + clock_slot += 3; + } + PM->APBCMASK.reg |= 1 << clock_slot; + _gclk_enable_channel(gclk_id, gclk_index); + #endif +} + +void tc_set_enable(Tc* tc, bool enable) { + tc->COUNT16.CTRLA.bit.ENABLE = enable; + #ifdef SAMD21 + while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) { + /* Wait for sync */ + } + #endif + #ifdef SAMD51 + while (tc->COUNT16.SYNCBUSY.bit.ENABLE != 0) { + /* Wait for sync */ + } + #endif +} + +void tc_enable_interrupts(uint8_t tc_index) { + NVIC_DisableIRQ(tc_irq[tc_index]); + NVIC_ClearPendingIRQ(tc_irq[tc_index]); + NVIC_EnableIRQ(tc_irq[tc_index]); +} + +void tc_disable_interrupts(uint8_t tc_index) { + NVIC_DisableIRQ(tc_irq[tc_index]); + NVIC_ClearPendingIRQ(tc_irq[tc_index]); +} + +void tcc_set_enable(Tcc* tcc, bool enable) { + tcc->CTRLA.bit.ENABLE = enable; + while (tcc->SYNCBUSY.bit.ENABLE != 0) { + /* Wait for sync */ + } +} + +void tc_wait_for_sync(Tc* tc) { + #ifdef SAMD21 + while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) {} + #endif + #ifdef SAMD51 + while (tc->COUNT16.SYNCBUSY.reg != 0) {} + #endif +} + +void tc_reset(Tc* tc) { + tc->COUNT16.CTRLA.bit.SWRST = 1; + while (tc->COUNT16.CTRLA.bit.SWRST == 1) { + } +} + +void shared_timer_handler(bool is_tc, uint8_t index) { + // Add calls to interrupt handlers for specific functionality here. + if (is_tc) { + pulseout_interrupt_handler(index); + } +} + +void TCC0_Handler(void) { + shared_timer_handler(false, 0); +} +void TCC1_Handler(void) { + shared_timer_handler(false, 1); +} +void TCC2_Handler(void) { + shared_timer_handler(false, 2); +} +void TC3_Handler(void) { + shared_timer_handler(true, 0); +} +void TC4_Handler(void) { + shared_timer_handler(true, 1); +} +void TC5_Handler(void) { + shared_timer_handler(true, 2); +} +#ifdef TC6 +void TC6_Handler(void) { + shared_timer_handler(true, 3); +} +#endif +#ifdef TC7 +void TC7_Handler(void) { + shared_timer_handler(true, 4); +} +#endif diff --git a/ports/atmel-samd/timers.h b/ports/atmel-samd/timers.h new file mode 100644 index 0000000000..a2ce52f255 --- /dev/null +++ b/ports/atmel-samd/timers.h @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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_TIMERS_H +#define MICROPY_INCLUDED_ATMEL_SAMD_TIMERS_H + +#include "include/sam.h" + +#ifdef SAMD21 +const uint8_t tcc_cc_num[3]; +const uint8_t tc_gclk_ids[TC_INST_NUM]; +const uint8_t tcc_gclk_ids[3]; +#endif +#ifdef SAMD51 +static const uint8_t tcc_cc_num[5]; +const uint8_t tc_gclk_ids[TC_INST_NUM]; +const uint8_t tcc_gclk_ids[5]; +#endif +Tc* const tc_insts[TC_INST_NUM]; +Tcc* const tcc_insts[TCC_INST_NUM]; + +void turn_on_clocks(bool is_tc, uint8_t index, uint32_t gclk_index); +void tc_set_enable(Tc* tc, bool enable); +void tcc_set_enable(Tcc* tcc, bool enable); +void tc_wait_for_sync(Tc* tc); +void tc_reset(Tc* tc); + +void tc_enable_interrupts(uint8_t tc_index); +void tc_disable_interrupts(uint8_t tc_index); + +// Handlers +void TCC0_Handler(void); +void TCC1_Handler(void); +void TCC2_Handler(void); +void TC3_Handler(void); +void TC4_Handler(void); +void TC5_Handler(void); +#ifdef TC6 +void TC6_Handler(void); +#endif +#ifdef TC7 +void TC7_Handler(void); +#endif + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_TIMERS_H