m0 pulseout works. Factored out shared timer code.

This commit is contained in:
Scott Shawcroft 2018-02-13 18:17:20 -08:00
parent 8479eef578
commit 6a7d889dd4
7 changed files with 390 additions and 175 deletions

View File

@ -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 \

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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();

258
ports/atmel-samd/timers.c Normal file
View File

@ -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 <stdbool.h>
#include <stdint.h>
#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

67
ports/atmel-samd/timers.h Normal file
View File

@ -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