m0 pulseout works. Factored out shared timer code.
This commit is contained in:
parent
8479eef578
commit
6a7d889dd4
@ -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 \
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
258
ports/atmel-samd/timers.c
Normal 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
67
ports/atmel-samd/timers.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user