summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2018-02-16 14:08:01 -0500
committerGitHub <noreply@github.com>2018-02-16 14:08:01 -0500
commitcb39bfcad93cece6c0fd645b78363cf4731c6f01 (patch)
tree77e5387f4b208f2156405cb94bbddd16dd78f757
parentfb5f6534420356e4ecee4533ffbcaa4f2028ee6c (diff)
parenta2b18b75d4bc68aa93edf67509185cb6e18f596b (diff)
Merge pull request #625 from tannewt/pulseio3
Re-enable pulseio for SAMD21 and SAMD51
-rw-r--r--main.c9
-rw-r--r--ports/atmel-samd/Makefile10
-rw-r--r--ports/atmel-samd/common-hal/microcontroller/Pin.h9
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PWMOut.c428
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PWMOut.h4
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PulseIn.c288
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PulseIn.h1
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PulseOut.c102
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PulseOut.h1
-rw-r--r--ports/atmel-samd/mpconfigport.h5
-rw-r--r--ports/atmel-samd/samd21_pins.c152
-rw-r--r--ports/atmel-samd/samd51_pins.c280
-rw-r--r--ports/atmel-samd/supervisor/port.c9
-rw-r--r--ports/atmel-samd/timers.c285
-rw-r--r--ports/atmel-samd/timers.h67
15 files changed, 1123 insertions, 527 deletions
diff --git a/main.c b/main.c
index 21940d795..8c981aee1 100644
--- a/main.c
+++ b/main.c
@@ -146,6 +146,7 @@ bool start_mp(safe_mode_t safe_mode) {
const char *supported_filenames[] = STRING_LIST("code.txt", "code.py", "main.py", "main.txt");
const char *double_extension_filenames[] = STRING_LIST("code.txt.py", "code.py.txt", "code.txt.txt","code.py.py",
"main.txt.py", "main.py.txt", "main.txt.txt","main.py.py");
+ reset_mp();
found_main = maybe_run_list(supported_filenames, &result);
if (!found_main){
found_main = maybe_run_list(double_extension_filenames, &result);
@@ -153,6 +154,9 @@ bool start_mp(safe_mode_t safe_mode) {
serial_write(MSG_DOUBLE_FILE_EXTENSION);
}
}
+
+ reset_port();
+ reset_board();
reset_status_led();
if (result.return_code & PYEXEC_FORCED_EXIT) {
@@ -296,6 +300,7 @@ int __attribute__((used)) main(void) {
bool first_run = true;
for (;;) {
if (!skip_repl) {
+ reset_mp();
autoreload_suspend();
new_status_color(REPL_RUNNING);
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
@@ -306,7 +311,6 @@ int __attribute__((used)) main(void) {
autoreload_resume();
reset_port();
reset_board();
- reset_mp();
}
if (exit_code == PYEXEC_FORCED_EXIT) {
if (!first_run) {
@@ -314,9 +318,6 @@ int __attribute__((used)) main(void) {
}
first_run = false;
skip_repl = start_mp(safe_mode);
- reset_port();
- reset_board();
- reset_mp();
} else if (exit_code != 0) {
break;
}
diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile
index 15d59171e..041f1d1ad 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 \
@@ -272,6 +272,10 @@ SRC_COMMON_HAL = \
analogio/__init__.c \
analogio/AnalogIn.c \
analogio/AnalogOut.c \
+ pulseio/__init__.c \
+ pulseio/PulseIn.c \
+ pulseio/PulseOut.c \
+ pulseio/PWMOut.c \
# audiobusio/__init__.c \
audiobusio/PDMIn.c \
audioio/__init__.c \
@@ -279,10 +283,6 @@ SRC_COMMON_HAL = \
busio/UART.c \
nvm/__init__.c \
nvm/ByteArray.c \
- pulseio/__init__.c \
- pulseio/PulseIn.c \
- pulseio/PulseOut.c \
- pulseio/PWMOut.c \
touchio/__init__.c \
touchio/TouchIn.c \
usb_hid/__init__.c \
diff --git a/ports/atmel-samd/common-hal/microcontroller/Pin.h b/ports/atmel-samd/common-hal/microcontroller/Pin.h
index db43bd4b5..ca639eb84 100644
--- a/ports/atmel-samd/common-hal/microcontroller/Pin.h
+++ b/ports/atmel-samd/common-hal/microcontroller/Pin.h
@@ -40,14 +40,9 @@ typedef struct {
} pin_sercom_t;
typedef struct {
- union {
- Tc *const tc;
- Tcc *const tcc;
- };
- #ifdef SAMD21
+ uint8_t index;
bool is_tc:1;
- #endif
- uint8_t wave_output:4;
+ uint8_t wave_output:7;
} pin_timer_t;
#ifdef SAMD21
diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c
index bf2b0cb33..c68ea6985 100644
--- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c
+++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c
@@ -30,32 +30,39 @@
#include "py/runtime.h"
#include "common-hal/pulseio/PWMOut.h"
#include "shared-bindings/pulseio/PWMOut.h"
+#include "shared-bindings/microcontroller/Processor.h"
+
+#include "atmel_start_pins.h"
+#include "hal/utils/include/utils_repeat_macro.h"
+#include "timers.h"
#include "samd21_pins.h"
#undef ENABLE
-# define _TCC_SIZE(n,unused) TPASTE3(TCC,n,_SIZE),
-# define TCC_SIZES { MREPEAT(TCC_INST_NUM, _TCC_SIZE, 0) }
+# define _TCC_SIZE(unused, n) TCC ## n ## _SIZE,
+# define TCC_SIZES { REPEAT_MACRO(_TCC_SIZE, 0, TCC_INST_NUM) }
+
+static uint32_t tcc_periods[TCC_INST_NUM];
+static uint32_t tc_periods[TC_INST_NUM];
-uint32_t target_timer_frequencies[TC_INST_NUM + TCC_INST_NUM];
-static uint32_t timer_periods[TC_INST_NUM + TCC_INST_NUM];
-uint8_t timer_refcount[TC_INST_NUM + TCC_INST_NUM];
+uint32_t target_tcc_frequencies[TCC_INST_NUM];
+uint8_t tcc_refcount[TCC_INST_NUM];
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};
+#endif
+#ifdef SAMD51
+uint8_t tcc_channels[5] = {0xc0, 0xf0, 0xf8, 0xfc, 0xfc};
+#endif
void pwmout_reset(void) {
- // Reset all but TC5
- for (int i = 0; i < TC_INST_NUM + TCC_INST_NUM; i++) {
- if (i == 5) {
- target_timer_frequencies[i] = 1000;
- timer_refcount[i] = 1;
- } else {
- target_timer_frequencies[i] = 0;
- timer_refcount[i] = 0;
- }
+ // Reset all timers
+ for (int i = 0; i < TCC_INST_NUM; i++) {
+ target_tcc_frequencies[i] = 0;
+ tcc_refcount[i] = 0;
}
Tcc *tccs[TCC_INST_NUM] = TCC_INSTS;
for (int i = 0; i < TCC_INST_NUM; i++) {
@@ -65,32 +72,31 @@ void pwmout_reset(void) {
while (tccs[i]->SYNCBUSY.bit.ENABLE == 1) {
}
}
- // TODO(tannewt): Make this depend on the CMSIS.
- if (i == 0) {
- tcc_channels[i] = 0xf0;
- } else {
- tcc_channels[i] = 0xfc;
+ uint8_t mask = 0xff;
+ for (uint8_t j = 0; j < tcc_cc_num[i]; j++) {
+ mask <<= 1;
}
+ tcc_channels[i] = 0xf0;
tccs[i]->CTRLA.bit.SWRST = 1;
}
Tc *tcs[TC_INST_NUM] = TC_INSTS;
for (int i = 0; i < TC_INST_NUM; i++) {
- if (tcs[i] == TC5) {
- continue;
- }
tcs[i]->COUNT16.CTRLA.bit.SWRST = 1;
while (tcs[i]->COUNT16.CTRLA.bit.SWRST == 1) {
}
}
}
-bool channel_ok(const pin_timer_t* t, uint8_t index) {
- return (!t->is_tc && (tcc_channels[index] & (1 << t->channel)) == 0) ||
- t->is_tc;
+static uint8_t tcc_channel(const pin_timer_t* t) {
+ // For the SAMD51 this hardcodes the use of OTMX == 0x0, the output matrix mapping, which uses
+ // SAMD21-style modulo mapping.
+ return t->wave_output % tcc_cc_num[t->index];
}
-static uint8_t timer_index(uint32_t base_timer_address) {
- return (base_timer_address - ((uint32_t) TCC0)) / 0x400;
+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 common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
@@ -101,7 +107,12 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
self->pin = pin;
self->variable_frequency = variable_frequency;
- if (pin->primary_timer.tc == 0 && pin->secondary_timer.tc == 0) {
+ if (pin->timer[0].index >= TC_INST_NUM &&
+ pin->timer[1].index >= TCC_INST_NUM
+#ifdef SAMD51
+ && pin->timer[2].index >= TCC_INST_NUM
+#endif
+ ) {
mp_raise_ValueError("Invalid pin");
}
@@ -109,72 +120,78 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
mp_raise_ValueError("Invalid PWM frequency");
}
- uint16_t primary_timer_index = 0xff;
- uint16_t secondary_timer_index = 0xff;
- if (pin->primary_timer.tc != NULL) {
- primary_timer_index = timer_index((uint32_t) pin->primary_timer.tcc);
- }
- if (pin->secondary_timer.tc != NULL) {
- secondary_timer_index = timer_index((uint32_t) pin->secondary_timer.tcc);
- }
-
// Figure out which timer we are using.
- // First see if a timer is already going with the frequency we want and our
- // channel is unused.
- // NOTE(shawcroft): The enable bit is in the same position for TC and TCC so
- // we treat them all as TCC for checking ENABLE.
- const pin_timer_t* t = NULL;
- uint8_t index = 0;
- if (!variable_frequency &&
- primary_timer_index != 0xff &&
- target_timer_frequencies[primary_timer_index] == frequency &&
- pin->primary_timer.tcc->CTRLA.bit.ENABLE == 1 &&
- channel_ok(&pin->primary_timer, primary_timer_index)) {
- t = &pin->primary_timer;
- index = primary_timer_index;
- self->tcc_instance.hw = t->tcc;
- self->tcc_instance.double_buffering_enabled = true;
- } else if (!variable_frequency &&
- secondary_timer_index != 0xff &&
- target_timer_frequencies[secondary_timer_index] == frequency &&
- pin->secondary_timer.tcc->CTRLA.bit.ENABLE == 1 &&
- channel_ok(&pin->secondary_timer, secondary_timer_index)) {
- t = &pin->secondary_timer;
- index = secondary_timer_index;
- self->tcc_instance.hw = t->tcc;
- self->tcc_instance.double_buffering_enabled = true;
- } else {
- // Pick an unused timer if available.
-
- // Check the secondary timer first since its always a nicer TCC (when it
- // exists)
- if (pin->secondary_timer.tc != 0 &&
- timer_refcount[secondary_timer_index] == 0 &&
- pin->secondary_timer.tcc->CTRLA.bit.ENABLE == 0) {
- t = &pin->secondary_timer;
- index = secondary_timer_index;
- } else if (pin->primary_timer.tc != 0 &&
- (!pin->primary_timer.is_tc || pin->primary_timer.channel == 1) &&
- timer_refcount[primary_timer_index] == 0) {
- t = &pin->primary_timer;
- index = primary_timer_index;
+ // First see if a tcc is already going with the frequency we want and our
+ // channel is unused. tc's don't have neough channels to share.
+ const pin_timer_t* timer = NULL;
+ uint8_t mux_position = 0;
+ if (!variable_frequency) {
+ for (uint8_t i = 0; i < TCC_INST_NUM && timer == NULL; i++) {
+ if (target_tcc_frequencies[i] != frequency) {
+ continue;
+ }
+ for (uint8_t j = 0; j < NUM_TIMERS_PER_PIN && timer == NULL; j++) {
+ const pin_timer_t* t = &pin->timer[j];
+ if (t->index != i || t->is_tc || t->index >= TCC_INST_NUM) {
+ continue;
+ }
+ Tcc* tcc = tcc_insts[t->index];
+ if (tcc->CTRLA.bit.ENABLE == 1 && channel_ok(t)) {
+ timer = t;
+ mux_position = j;
+ }
+ }
}
- if (t == NULL) {
+ }
+
+ // No existing timer has been found, so find a new one to use and set it up.
+ if (timer == NULL) {
+ // By default, with fixed frequency we want to share a TCC because its likely we'll have
+ // other outputs at the same frequency. If the frequency is variable then we'll only have
+ // one output so we start with the TCs to see if they work.
+ int8_t direction = -1;
+ uint8_t start = NUM_TIMERS_PER_PIN - 1;
+ if (variable_frequency) {
+ direction = 1;
+ start = 0;
+ }
+ for (int8_t i = start; i >= 0 && i < NUM_TIMERS_PER_PIN && timer == NULL; i += direction) {
+ const pin_timer_t* t = &pin->timer[i];
+ if ((!t->is_tc && t->index >= TCC_INST_NUM) ||
+ (t->is_tc && t->index >= TC_INST_NUM)) {
+ continue;
+ }
+ if (t->is_tc) {
+ Tc* tc = tc_insts[t->index];
+ if (tc->COUNT16.CTRLA.bit.ENABLE == 0 && t->wave_output == 1) {
+ timer = t;
+ mux_position = i;
+ }
+ } else {
+ Tcc* tcc = tcc_insts[t->index];
+ if (tcc->CTRLA.bit.ENABLE == 0 && channel_ok(t)) {
+ timer = t;
+ mux_position = i;
+ }
+ }
+ }
+
+ if (timer == NULL) {
mp_raise_RuntimeError("All timers in use");
return;
}
uint8_t resolution = 0;
- if (t->is_tc) {
+ if (timer->is_tc) {
resolution = 16;
} else {
// TCC resolution varies so look it up.
const uint8_t _tcc_sizes[TCC_INST_NUM] = TCC_SIZES;
- resolution = _tcc_sizes[index];
+ resolution = _tcc_sizes[timer->index];
}
// First determine the divisor that gets us the highest resolution.
- uint32_t system_clock = system_cpu_clock_get_hz();
+ uint32_t system_clock = common_hal_mcu_processor_get_frequency();
uint32_t top;
uint8_t divisor;
for (divisor = 0; divisor < 8; divisor++) {
@@ -183,57 +200,54 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
break;
}
}
- timer_periods[index] = top;
- if (t->is_tc) {
- 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(divisor);
- config_tc.wave_generation = TC_WAVE_GENERATION_MATCH_PWM;
- config_tc.counter_16_bit.compare_capture_channel[0] = top;
-
- enum status_code status = tc_init(&self->tc_instance, t->tc, &config_tc);
- if (status != STATUS_OK) {
- mp_raise_RuntimeError("Failed to init timer");
- }
- tc_enable(&self->tc_instance);
- } else {
- struct tcc_config config_tcc;
- tcc_get_config_defaults(&config_tcc, t->tcc);
-
- config_tcc.counter.clock_prescaler = divisor;
- config_tcc.counter.period = top;
- config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM;
- enum status_code status = tcc_init(&self->tcc_instance, t->tcc, &config_tcc);
- if (status != STATUS_OK) {
- mp_raise_RuntimeError("Failed to init 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;
+ Tc* tc = tc_insts[timer->index];
+ #ifdef SAMD21
+ tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 |
+ TC_CTRLA_PRESCALER(divisor) |
+ TC_CTRLA_WAVEGEN_MPWM;
+ tc->COUNT16.CC[0].reg = top;
+ #endif
+ #ifdef SAMD51
+
+ tc->COUNT16.CTRLA.bit.SWRST = 1;
+ while (tc->COUNT16.CTRLA.bit.SWRST == 1) {
}
- tcc_enable(&self->tcc_instance);
- }
-
- target_timer_frequencies[index] = frequency;
- timer_refcount[index]++;
- }
-
- if (!t->is_tc) {
- if (variable_frequency) {
- // We're changing frequency so claim all of the channels.
- tcc_channels[index] = 0xff;
+ tc_set_enable(tc, false);
+ tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER(divisor);
+ tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MPWM;
+ tc->COUNT16.CCBUF[0].reg = top;
+ tc->COUNT16.CCBUF[1].reg = 0;
+ #endif
+
+ tc_set_enable(tc, true);
} else {
- tcc_channels[index] |= (1 << t->channel);
+ tcc_periods[timer->index] = top;
+ Tcc* tcc = tcc_insts[timer->index];
+ tcc_set_enable(tcc, false);
+ tcc->CTRLA.bit.PRESCALER = divisor;
+ tcc->PER.bit.PER = top;
+ tcc->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val;
+ tcc_set_enable(tcc, true);
+ target_tcc_frequencies[timer->index] = frequency;
+ tcc_refcount[timer->index]++;
+ if (variable_frequency) {
+ // We're changing frequency so claim all of the channels.
+ tcc_channels[timer->index] = 0xff;
+ } else {
+ tcc_channels[timer->index] |= (1 << tcc_channel(timer));
+ }
}
}
- self->timer = t;
+ self->timer = timer;
- // Connect the wave output to the outside world.
- struct system_pinmux_config pin_config;
- system_pinmux_get_config_defaults(&pin_config);
- pin_config.mux_position = &self->pin->primary_timer == t ? MUX_E : MUX_F;
- pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
- system_pinmux_pin_set_config(pin->pin, &pin_config);
+ gpio_set_pin_function(pin->pin, GPIO_PIN_FUNCTION_E + mux_position);
common_hal_pulseio_pwmout_set_duty_cycle(self, duty);
}
@@ -247,23 +261,22 @@ void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) {
return;
}
const pin_timer_t* t = self->timer;
- uint8_t index = (((uint32_t) t->tcc) - ((uint32_t) TCC0)) / 0x400;
- timer_refcount[index]--;
- if (!t->is_tc) {
- tcc_channels[index] &= ~(1 << t->channel);
- }
- if (timer_refcount[index] == 0) {
- target_timer_frequencies[index] = 0;
- if (t->is_tc) {
- tc_disable(&self->tc_instance);
- } else {
- if (t->tcc == TCC0) {
- tcc_channels[index] = 0xf0;
- } else {
- tcc_channels[index] = 0xfc;
+ if (t->is_tc) {
+ Tc* tc = tc_insts[t->index];
+ tc_set_enable(tc, false);
+ tc->COUNT16.CTRLA.bit.SWRST = true;
+ tc_wait_for_sync(tc);
+ } else {
+ tcc_refcount[t->index]--;
+ tcc_channels[t->index] &= ~(1 << tcc_channel(t));
+ if (tcc_refcount[t->index] == 0) {
+ target_tcc_frequencies[t->index] = 0;
+ Tcc* tcc = tcc_insts[t->index];
+ tcc_set_enable(tcc, false);
+ tcc->CTRLA.bit.SWRST = true;
+ while (tcc->SYNCBUSY.bit.SWRST != 0) {
+ /* Wait for sync */
}
- tcc_disable(&self->tcc_instance);
- tcc_reset(&self->tcc_instance);
}
}
reset_pin(self->pin->pin);
@@ -272,35 +285,69 @@ void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) {
extern void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty) {
const pin_timer_t* t = self->timer;
- uint8_t index;
if (t->is_tc) {
- index = timer_index((uint32_t) self->timer->tc);
- uint16_t adjusted_duty = timer_periods[index] * duty / 0xffff;
- tc_set_compare_value(&self->tc_instance, t->channel, adjusted_duty);
+ uint16_t adjusted_duty = tc_periods[t->index] * duty / 0xffff;
+ #ifdef SAMD21
+ tc_insts[t->index]->COUNT16.CC[t->wave_output].reg = adjusted_duty;
+ #endif
+ #ifdef SAMD51
+ Tc* tc = tc_insts[t->index];
+ while (tc->COUNT16.SYNCBUSY.bit.CC1 != 0) {
+ // Wait for a previous value to be written. This can wait up to one period so we do
+ // other stuff in the meantime.
+ #ifdef MICROPY_VM_HOOK_LOOP
+ MICROPY_VM_HOOK_LOOP
+ #endif
+ }
+ tc->COUNT16.CCBUF[1].reg = adjusted_duty;
+ #endif
} else {
- index = timer_index((uint32_t) self->timer->tcc);
- uint32_t adjusted_duty = ((uint64_t) timer_periods[index]) * duty / 0xffff;
- tcc_set_compare_value(&self->tcc_instance, t->channel, adjusted_duty);
+ uint32_t adjusted_duty = ((uint64_t) tcc_periods[t->index]) * duty / 0xffff;
+ uint8_t channel = tcc_channel(t);
+ Tcc* tcc = tcc_insts[t->index];
+ while ((tcc->SYNCBUSY.vec.CC & (1 << channel)) != 0) {
+ // Wait for a previous value to be written. This can wait up to one period so we do
+ // other stuff in the meantime.
+ #ifdef MICROPY_VM_HOOK_LOOP
+ MICROPY_VM_HOOK_LOOP
+ #endif
+ }
+ #ifdef SAMD21
+ tcc->CCB[channel].reg = adjusted_duty;
+ #endif
+ #ifdef SAMD51
+ tcc->CCBUF[channel].reg = adjusted_duty;
+ #endif
}
}
uint16_t common_hal_pulseio_pwmout_get_duty_cycle(pulseio_pwmout_obj_t* self) {
const pin_timer_t* t = self->timer;
if (t->is_tc) {
- while (tc_is_syncing(&self->tc_instance)) {
- /* Wait for sync */
- }
- uint16_t cv = t->tc->COUNT16.CC[t->channel].reg;
- return cv * 0xffff / timer_periods[timer_index((uint32_t) self->timer->tc)];
+ Tc* tc = tc_insts[t->index];
+ tc_wait_for_sync(tc);
+ uint16_t cv = tc->COUNT16.CC[t->wave_output].reg;
+ return cv * 0xffff / tc_periods[t->index];
} else {
+ Tcc* tcc = tcc_insts[t->index];
+ uint8_t channel = tcc_channel(t);
uint32_t cv = 0;
- if ((t->tcc->STATUS.vec.CCBV & (1 << t->channel)) != 0) {
- cv = t->tcc->CCB[t->channel].reg;
+ #ifdef SAMD21
+ if ((tcc->STATUS.vec.CCBV & (1 << channel)) != 0) {
+ cv = tcc->CCB[channel].reg;
} else {
- cv = t->tcc->CC[t->channel].reg;
+ cv = tcc->CC[channel].reg;
}
+ #endif
+ #ifdef SAMD51
+ if ((tcc->STATUS.vec.CCBUFV & (1 << channel)) != 0) {
+ cv = tcc->CCBUF[channel].reg;
+ } else {
+ cv = tcc->CC[channel].reg;
+ }
+ #endif
- uint32_t duty_cycle = ((uint64_t) cv) * 0xffff / timer_periods[timer_index((uint32_t) self->timer->tcc)];
+ uint32_t duty_cycle = ((uint64_t) cv) * 0xffff / tcc_periods[t->index];
return duty_cycle;
}
@@ -319,7 +366,7 @@ void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self,
} else {
resolution = 24;
}
- uint32_t system_clock = system_cpu_clock_get_hz();
+ uint32_t system_clock = common_hal_mcu_processor_get_frequency();
uint32_t new_top;
uint8_t new_divisor;
for (new_divisor = 0; new_divisor < 8; new_divisor++) {
@@ -329,52 +376,59 @@ void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self,
}
}
uint16_t old_duty = common_hal_pulseio_pwmout_get_duty_cycle(self);
- uint8_t old_divisor;
- uint8_t index;
if (t->is_tc) {
- index = timer_index((uint32_t) self->timer->tc);
- old_divisor = t->tc->COUNT16.CTRLA.bit.PRESCALER;
- } else {
- index = timer_index((uint32_t) self->timer->tcc);
- old_divisor = t->tcc->CTRLA.bit.PRESCALER;
- }
- if (new_divisor != old_divisor) {
- if (t->is_tc) {
- tc_disable(&self->tc_instance);
- t->tc->COUNT16.CTRLA.bit.PRESCALER = new_divisor;
- tc_enable(&self->tc_instance);
- } else {
- tcc_disable(&self->tcc_instance);
- t->tcc->CTRLA.bit.PRESCALER = new_divisor;
- tcc_enable(&self->tcc_instance);
+ Tc* tc = tc_insts[t->index];
+ uint8_t old_divisor = tc->COUNT16.CTRLA.bit.PRESCALER;
+ if (new_divisor != old_divisor) {
+ tc_set_enable(tc, false);
+ tc->COUNT16.CTRLA.bit.PRESCALER = new_divisor;
+ tc_set_enable(tc, true);
}
- }
- timer_periods[index] = new_top;
- if (t->is_tc) {
- while (tc_is_syncing(&self->tc_instance)) {
+ tc_periods[t->index] = new_top;
+ #ifdef SAMD21
+ tc->COUNT16.CC[0].reg = new_top;
+ #endif
+ #ifdef SAMD51
+ while (tc->COUNT16.SYNCBUSY.reg != 0) {
/* Wait for sync */
}
- t->tc->COUNT16.CC[0].reg = new_top;
+ tc->COUNT16.CCBUF[0].reg = new_top;
+ #endif
} else {
- tcc_set_top_value(&self->tcc_instance, new_top);
+ Tcc* tcc = tcc_insts[t->index];
+ uint8_t old_divisor = tcc->CTRLA.bit.PRESCALER;
+ if (new_divisor != old_divisor) {
+ tcc_set_enable(tcc, false);
+ tcc->CTRLA.bit.PRESCALER = new_divisor;
+ tcc_set_enable(tcc, true);
+ }
+ tcc_periods[t->index] = new_top;
+ #ifdef SAMD21
+ tcc->PERB.bit.PERB = new_top;
+ #endif
+ #ifdef SAMD51
+ while (tcc->SYNCBUSY.reg != 0) {
+ /* Wait for sync */
+ }
+ tcc->PERBUF.bit.PERBUF = new_top;
+ #endif
}
common_hal_pulseio_pwmout_set_duty_cycle(self, old_duty);
}
uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self) {
- uint32_t system_clock = system_cpu_clock_get_hz();
+ uint32_t system_clock = common_hal_mcu_processor_get_frequency();
const pin_timer_t* t = self->timer;
- uint8_t index;
uint8_t divisor;
+ uint32_t top;
if (t->is_tc) {
- index = timer_index((uint32_t) self->timer->tc);
- divisor = t->tc->COUNT16.CTRLA.bit.PRESCALER;
+ divisor = tc_insts[t->index]->COUNT16.CTRLA.bit.PRESCALER;
+ top = tc_periods[t->index];
} else {
- index = timer_index((uint32_t) self->timer->tcc);
- divisor = t->tcc->CTRLA.bit.PRESCALER;
+ divisor = tcc_insts[t->index]->CTRLA.bit.PRESCALER;
+ top = tcc_periods[t->index];
}
- uint32_t top = timer_periods[index];
return (system_clock / prescaler[divisor]) / (top + 1);
}
diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.h b/ports/atmel-samd/common-hal/pulseio/PWMOut.h
index d6af617a9..eef653bcb 100644
--- a/ports/atmel-samd/common-hal/pulseio/PWMOut.h
+++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.h
@@ -36,10 +36,6 @@ typedef struct {
const mcu_pin_obj_t *pin;
const pin_timer_t* timer;
bool variable_frequency;
- union {
- struct tc_module tc_instance;
- struct tcc_module tcc_instance;
- };
} pulseio_pwmout_obj_t;
void pwmout_reset(void);
diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c
index 99f747caf..2dca52913 100644
--- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c
+++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c
@@ -28,10 +28,8 @@
#include <stdint.h>
-#include "asf/common2/services/delay/delay.h"
-#include "asf/sam0/drivers/extint/extint.h"
-#include "asf/sam0/drivers/extint/extint_callback.h"
-#include "asf/sam0/drivers/port/port.h"
+#include "atmel_start_pins.h"
+#include "hal/include/hal_gpio.h"
#include "mpconfigport.h"
#include "py/gc.h"
@@ -40,52 +38,94 @@
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/pulseio/PulseIn.h"
+#ifdef SAMD21
+#include "hpl/gclk/hpl_gclk_base.h"
+#endif
+
#include "tick.h"
-static pulseio_pulsein_obj_t *active_pulseins[EIC_NUMBER_OF_INTERRUPTS];
-static uint64_t last_ms[EIC_NUMBER_OF_INTERRUPTS];
-static uint16_t last_us[EIC_NUMBER_OF_INTERRUPTS];
+static pulseio_pulsein_obj_t *active_pulseins[EIC_EXTINT_NUM];
+static uint64_t last_ms[EIC_EXTINT_NUM];
+static uint16_t last_us[EIC_EXTINT_NUM];
+
+bool eic_get_enable(void) {
+ #ifdef SAMD51
+ return EIC->CTRLA.bit.ENABLE;
+ #endif
+ #ifdef SAMD21
+ return EIC->CTRL.bit.ENABLE;
+ #endif
+}
+
+void eic_set_enable(bool value) {
+ #ifdef SAMD51
+ EIC->CTRLA.bit.ENABLE = value;
+ while (EIC->SYNCBUSY.bit.ENABLE != 0) {}
+ // This won't actually block long enough in Rev A of SAMD51 and will miss edges in the first
+ // three cycles of the peripheral clock. See the errata for details. It shouldn't impact us.
+ #endif
+ #ifdef SAMD21
+ EIC->CTRL.bit.ENABLE = value;
+ while (EIC->STATUS.bit.SYNCBUSY != 0) {}
+ #endif
+}
+
+void eic_reset(void) {
+ #ifdef SAMD51
+ EIC->CTRLA.bit.SWRST = true;
+ while (EIC->SYNCBUSY.bit.SWRST != 0) {}
+ // This won't actually block long enough in Rev A of SAMD51 and will miss edges in the first
+ // three cycles of the peripheral clock. See the errata for details. It shouldn't impact us.
+ #endif
+ #ifdef SAMD21
+ EIC->CTRL.bit.SWRST = true;
+ while (EIC->STATUS.bit.SYNCBUSY != 0) {}
+ #endif
+}
void pulsein_reset(void) {
- for (int i = 0; i < EIC_NUMBER_OF_INTERRUPTS; i++) {
- if (active_pulseins[i] != NULL) {
- extint_chan_disable_callback(i, EXTINT_CALLBACK_TYPE_DETECT);
- }
+ for (int i = 0; i < EIC_EXTINT_NUM; i++) {
active_pulseins[i] = NULL;
last_ms[i] = 0;
last_us[i] = 0;
+ #ifdef SAMD51
+ NVIC_DisableIRQ(EIC_0_IRQn + i);
+ NVIC_ClearPendingIRQ(EIC_0_IRQn + i);
+ #endif
}
+ eic_reset();
+ #ifdef SAMD21
+ NVIC_DisableIRQ(EIC_IRQn);
+ NVIC_ClearPendingIRQ(EIC_IRQn);
+ #endif
}
static void pulsein_set_config(pulseio_pulsein_obj_t* self, bool first_edge) {
- struct extint_chan_conf config;
- extint_chan_get_config_defaults(&config);
- config.gpio_pin = self->pin;
- config.gpio_pin_pull = EXTINT_PULL_NONE;
- config.filter_input_signal = true;
-
+ uint8_t sense_setting = EIC_CONFIG_FILTEN0;
if (!first_edge) {
- config.detection_criteria = EXTINT_DETECT_BOTH;
+ sense_setting |= EIC_CONFIG_SENSE0_BOTH_Val;
} else if (self->idle_state) {
- config.detection_criteria = EXTINT_DETECT_FALLING;
+ sense_setting |= EIC_CONFIG_SENSE0_FALL_Val;
} else {
- config.detection_criteria = EXTINT_DETECT_RISING;
+ sense_setting |= EIC_CONFIG_SENSE0_RISE_Val;
}
- extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT);
- extint_chan_set_config(self->channel, &config);
- // Clear any interrupts that may have triggered without notifying the CPU.
- EIC->INTFLAG.reg |= (1UL << self->channel);
- extint_chan_enable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT);
+ eic_set_enable(false);
+ uint8_t config_index = self->channel / 8;
+ uint8_t position = (self->channel % 8) * 4;
+ uint32_t masked_value = EIC->CONFIG[config_index].reg & ~(0xf << position);
+ EIC->CONFIG[config_index].reg = masked_value | (sense_setting << position);
+ eic_set_enable(true);
}
-static void pulsein_callback(void) {
+static void pulsein_interrupt_handler(uint8_t channel) {
// Grab the current time first.
- uint16_t current_us = tc_get_count_value(&ms_timer);
- // Add the overflow flag to account for tick interrupts that are blocked by
- // this interrupt.
- uint64_t current_ms = ticks_ms + TC5->COUNT16.INTFLAG.bit.OVF;
- pulseio_pulsein_obj_t* self = active_pulseins[extint_get_current_channel()];
- current_us = current_us * 1000 / self->ticks_per_ms;
+ uint32_t current_us;
+ uint64_t current_ms;
+ current_tick(&current_ms, &current_us);
+ // current_tick gives us the remaining us until the next tick but we want the number since the
+ // last ms.
+ current_us = 1000 - current_us;
+ pulseio_pulsein_obj_t* self = active_pulseins[channel];
if (self->first_edge) {
self->first_edge = false;
pulsein_set_config(self, false);
@@ -123,13 +163,21 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self,
if (!pin->has_extint) {
mp_raise_RuntimeError("No hardware support on pin");
}
- // TODO(tannewt): Switch to checking actual extint peripheral state when other
- // classes use extints.
- if (active_pulseins[pin->extint_channel] != NULL) {
+ uint32_t mask = 1 << pin->extint_channel;
+ if (active_pulseins[pin->extint_channel] != NULL ||
+ (eic_get_enable() == 1 &&
+#ifdef SAMD51
+ ((EIC->INTENSET.bit.EXTINT & mask) != 0 ||
+ (EIC->EVCTRL.bit.EXTINTEO & mask) != 0))) {
+#endif
+#ifdef SAMD21
+ ((EIC->INTENSET.vec.EXTINT & mask) != 0 ||
+ (EIC->EVCTRL.vec.EXTINTEO & mask) != 0))) {
+#endif
mp_raise_RuntimeError("EXTINT channel already in use");
}
- self->buffer = (uint16_t *) gc_alloc(maxlen * sizeof(uint16_t), false);
+ self->buffer = (uint16_t *) m_malloc(maxlen * sizeof(uint16_t), false);
if (self->buffer == NULL) {
mp_raise_msg_varg(&mp_type_MemoryError, "Failed to allocate RX buffer of %d bytes", maxlen * sizeof(uint16_t));
}
@@ -140,16 +188,42 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self,
self->start = 0;
self->len = 0;
self->first_edge = true;
- self->ticks_per_ms = (system_cpu_clock_get_hz() / 1000 - 1);
active_pulseins[pin->extint_channel] = self;
+ // Check to see if the EIC is enabled and start it up if its not.'
+ // SAMD51 EIC can only be clocked up to 100mhz so we use the 48mhz clock.
+ if (eic_get_enable() == 0) {
+ #ifdef SAMD51
+ MCLK->APBAMASK.bit.EIC_ = true;
+ hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID,
+ GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos));
+ #endif
+
+ #ifdef SAMD21
+ PM->APBAMASK.bit.EIC_ = true;
+ _gclk_enable_channel(EIC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val);
+ #endif
+
+
+ #ifdef SAMD21
+ NVIC_DisableIRQ(EIC_IRQn);
+ NVIC_ClearPendingIRQ(EIC_IRQn);
+ NVIC_EnableIRQ(EIC_IRQn);
+ #endif
+ }
+
+ gpio_set_pin_function(pin->pin, GPIO_PIN_FUNCTION_A);
+
+ #ifdef SAMD51
+ NVIC_DisableIRQ(EIC_0_IRQn + self->channel);
+ NVIC_ClearPendingIRQ(EIC_0_IRQn + self->channel);
+ NVIC_EnableIRQ(EIC_0_IRQn + self->channel);
+ #endif
+
+ // Set config will enable the EIC.
pulsein_set_config(self, true);
- extint_register_callback(
- pulsein_callback,
- self->channel,
- EXTINT_CALLBACK_TYPE_DETECT);
- extint_chan_enable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT);
+ EIC->INTENSET.reg = mask << EIC_INTENSET_EXTINT_Pos;
}
bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) {
@@ -160,38 +234,60 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) {
if (common_hal_pulseio_pulsein_deinited(self)) {
return;
}
- extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT);
+ uint32_t mask = 1 << self->channel;
+ EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos;
+ #ifdef SAMD51
+ NVIC_DisableIRQ(EIC_0_IRQn + self->channel);
+ NVIC_ClearPendingIRQ(EIC_0_IRQn + self->channel);
+ #endif
active_pulseins[self->channel] = NULL;
reset_pin(self->pin);
self->pin = NO_PIN;
+
+ bool all_null = true;
+ for (uint8_t i = 0; all_null && i < 16; i++) {
+ all_null = all_null && active_pulseins[i] == NULL;
+ }
+ #ifdef SAMD21
+ if (all_null && EIC->INTENSET.reg == 0) {
+ NVIC_DisableIRQ(EIC_IRQn);
+ NVIC_ClearPendingIRQ(EIC_IRQn);
+ }
+ #endif
+ // Test if all channels are null and deinit everything if they are.
+ if (all_null && EIC->EVCTRL.reg == 0 && EIC->INTENSET.reg == 0) {
+ eic_set_enable(false);
+ #ifdef SAMD51
+ MCLK->APBAMASK.bit.EIC_ = false;
+ hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, 0);
+ #endif
+
+ #ifdef SAMD21
+ PM->APBAMASK.bit.EIC_ = false;
+ hri_gclk_write_CLKCTRL_reg(GCLK, GCLK_CLKCTRL_ID(EIC_GCLK_ID));
+ #endif
+ }
}
void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) {
- extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT);
+ uint32_t mask = 1 << self->channel;
+ EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos;
}
void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self,
uint16_t trigger_duration) {
+ // Make sure we're paused.
+ common_hal_pulseio_pulsein_pause(self);
+
// Send the trigger pulse.
if (trigger_duration > 0) {
- struct port_config pin_conf;
- port_get_config_defaults(&pin_conf);
-
- pin_conf.direction = PORT_PIN_DIR_OUTPUT;
- pin_conf.input_pull = PORT_PIN_PULL_NONE;
- port_pin_set_config(self->pin, &pin_conf);
-
- // TODO(tannewt): delay_us isn't exactly correct so we adjust the value
- // here before calling it. Find out why its not exact and fix it instead
- // of hacking around it here.
- uint32_t adjusted_duration = trigger_duration;
- adjusted_duration *= 4;
- adjusted_duration /= 5;
+ gpio_set_pin_pull_mode(self->pin, GPIO_PULL_OFF);
+ gpio_set_pin_direction(self->pin, GPIO_DIRECTION_OUT);
common_hal_mcu_disable_interrupts();
- port_pin_set_output_level(self->pin, !self->idle_state);
- common_hal_mcu_delay_us(adjusted_duration);
- port_pin_set_output_level(self->pin, self->idle_state);
+ gpio_set_pin_level(self->pin, !self->idle_state);
+ common_hal_mcu_delay_us(trigger_duration);
+ gpio_set_pin_level(self->pin, self->idle_state);
common_hal_mcu_enable_interrupts();
}
@@ -199,6 +295,12 @@ void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self,
last_ms[self->channel] = 0;
last_us[self->channel] = 0;
self->first_edge = true;
+ gpio_set_pin_function(self->pin, GPIO_PIN_FUNCTION_A);
+ uint32_t mask = 1 << self->channel;
+ // Clear previous interrupt state and re-enable it.
+ EIC->INTFLAG.reg = mask << EIC_INTFLAG_EXTINT_Pos;
+ EIC->INTENSET.reg = mask << EIC_INTENSET_EXTINT_Pos;
+
pulsein_set_config(self, true);
}
@@ -244,3 +346,69 @@ uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self,
common_hal_mcu_enable_interrupts();
return value;
}
+
+void external_interrupt_handler(uint8_t channel) {
+ pulsein_interrupt_handler(channel);
+ EIC->INTFLAG.reg = (1 << channel) << EIC_INTFLAG_EXTINT_Pos;
+}
+
+#ifdef SAMD21
+void EIC_Handler(void) {
+ for (uint8_t i = 0; i < 16; i++) {
+ if ((EIC->INTFLAG.vec.EXTINT & (1 << i)) != 0) {
+ external_interrupt_handler(i);
+ }
+ }
+}
+#endif
+
+#ifdef SAMD51
+void EIC_0_Handler(void) {
+ external_interrupt_handler(0);
+}
+void EIC_1_Handler(void) {
+ external_interrupt_handler(1);
+}
+void EIC_2_Handler(void) {
+ external_interrupt_handler(2);
+}
+void EIC_3_Handler(void) {
+ external_interrupt_handler(3);
+}
+void EIC_4_Handler(void) {
+ external_interrupt_handler(4);
+}
+void EIC_5_Handler(void) {
+ external_interrupt_handler(5);
+}
+void EIC_6_Handler(void) {
+ external_interrupt_handler(6);
+}
+void EIC_7_Handler(void) {
+ external_interrupt_handler(7);
+}
+void EIC_8_Handler(void) {
+ external_interrupt_handler(8);
+}
+void EIC_9_Handler(void) {
+ external_interrupt_handler(9);
+}
+void EIC_10_Handler(void) {
+ external_interrupt_handler(10);
+}
+void EIC_11_Handler(void) {
+ external_interrupt_handler(11);
+}
+void EIC_12_Handler(void) {
+ external_interrupt_handler(12);
+}
+void EIC_13_Handler(void) {
+ external_interrupt_handler(13);
+}
+void EIC_14_Handler(void) {
+ external_interrupt_handler(14);
+}
+void EIC_15_Handler(void) {
+ external_interrupt_handler(15);
+}
+#endif
diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.h b/ports/atmel-samd/common-hal/pulseio/PulseIn.h
index f577a6131..e3af42e0a 100644
--- a/ports/atmel-samd/common-hal/pulseio/PulseIn.h
+++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.h
@@ -41,7 +41,6 @@ typedef struct {
volatile uint16_t start;
volatile uint16_t len;
volatile bool first_edge;
- uint16_t ticks_per_ms;
} pulseio_pulsein_obj_t;
void pulsein_reset(void);
diff --git a/ports/atmel-samd/common-hal/pulseio/PulseOut.c b/ports/atmel-samd/common-hal/pulseio/PulseOut.c
index b2d594232..95b0bbee0 100644
--- a/ports/atmel-samd/common-hal/pulseio/PulseOut.c
+++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.c
@@ -28,22 +28,21 @@
#include <stdint.h>
-#include "asf/sam0/drivers/tc/tc_interrupt.h"
-#include "asf/sam0/drivers/port/port.h"
+#include "hal/include/hal_gpio.h"
#include "mpconfigport.h"
#include "py/gc.h"
#include "py/runtime.h"
#include "samd21_pins.h"
#include "shared-bindings/pulseio/PulseOut.h"
-
-#undef ENABLE
+#include "timers.h"
// This timer is shared amongst all PulseOut objects under the assumption that
-// the code is single threaded. Its stored in MICROPY_PORT_ROOT_POINTERS so it
-// doesn't get garbage collected.
+// the code is single threaded.
static uint8_t refcount = 0;
+static uint8_t pulseout_tc_index = 0xff;
+
static __IO PORT_PINCFG_Type *active_pincfg = NULL;
static uint16_t *pulse_buffer = NULL;
static volatile uint16_t pulse_index = 0;
@@ -58,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) {
@@ -70,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;
- MP_STATE_VM(pulseout_tc_instance) = NULL;
+ pulseout_tc_index = 0xff;
active_pincfg = NULL;
}
@@ -86,39 +97,50 @@ 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;
+ int8_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");
}
- MP_STATE_VM(pulseout_tc_instance) = gc_alloc(sizeof(struct tc_module), false);
- if (t == NULL) {
- mp_raise_msg(&mp_type_MemoryError, "");
- }
- struct tc_config config_tc;
- tc_get_config_defaults(&config_tc);
+ pulseout_tc_index = index;
- 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;
+ // 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_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));
+ tc_set_enable(tc, true);
+ tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_STOP;
}
refcount++;
self->pin = carrier->pin->pin;
- PortGroup *const port_base = port_get_group_from_gpio_pin(self->pin);
+ PortGroup *const port_base = &PORT->Group[GPIO_PORT(self->pin)];
self->pincfg = &port_base->PINCFG[self->pin % 32];
// Set the port to output a zero.
@@ -137,16 +159,15 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) {
if (common_hal_pulseio_pulseout_deinited(self)) {
return;
}
- PortGroup *const port_base = port_get_group_from_gpio_pin(self->pin);
+ PortGroup *const port_base = &PORT->Group[GPIO_PORT(self->pin)];
port_base->DIRCLR.reg = 1 << (self->pin % 32);
turn_on(self->pincfg);
refcount--;
if (refcount == 0) {
- tc_reset(MP_STATE_VM(pulseout_tc_instance));
- gc_free(MP_STATE_VM(pulseout_tc_instance));
- MP_STATE_VM(pulseout_tc_instance) = NULL;
+ tc_reset(tc_insts[pulseout_tc_index]);
+ pulseout_tc_index = 0xff;
}
self->pin = NO_PIN;
}
@@ -161,11 +182,15 @@ 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);
+ // Clear our interrupt in case it was set earlier
+ tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;
+ 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
@@ -175,7 +200,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 4294d6d68..634088128 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/mpconfigport.h b/ports/atmel-samd/mpconfigport.h
index 2df138359..2e14f7a8b 100644
--- a/ports/atmel-samd/mpconfigport.h
+++ b/ports/atmel-samd/mpconfigport.h
@@ -197,7 +197,7 @@ extern const struct _mp_obj_module_t usb_hid_module;
{ MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module }
// { MP_OBJ_NEW_QSTR(MP_QSTR_audioio), (mp_obj_t)&audioio_module },
// { MP_OBJ_NEW_QSTR(MP_QSTR_audiobusio), (mp_obj_t)&audiobusio_module },
-// { MP_OBJ_NEW_QSTR(MP_QSTR_pulseio), (mp_obj_t)&pulseio_module },
+// { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module },
#define EXPRESS_BOARD
#else
#define MICROPY_PY_BUILTINS_REVERSED (0)
@@ -212,7 +212,6 @@ extern const struct _mp_obj_module_t usb_hid_module;
// Disabled for now.
// { MP_OBJ_NEW_QSTR(MP_QSTR_touchio), (mp_obj_t)&touchio_module },
-// { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module },
// { MP_OBJ_NEW_QSTR(MP_QSTR__stage), (mp_obj_t)&stage_module },
// { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module },
@@ -225,6 +224,7 @@ extern const struct _mp_obj_module_t usb_hid_module;
{ MP_OBJ_NEW_QSTR(MP_QSTR_microcontroller), (mp_obj_t)&microcontroller_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pulseio), (mp_obj_t)&pulseio_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_storage), (mp_obj_t)&storage_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&struct_module }, \
@@ -260,7 +260,6 @@ extern const struct _mp_obj_module_t usb_hid_module;
struct dac_module* audioout_dac_instance; \
struct events_resource* audioout_sample_event; \
struct events_resource* audioout_dac_event; \
- struct tc_module* pulseout_tc_instance; \
FLASH_ROOT_POINTERS \
void run_background_tasks(void);
diff --git a/ports/atmel-samd/samd21_pins.c b/ports/atmel-samd/samd21_pins.c
index b86f9acbf..f1d006de8 100644
--- a/ports/atmel-samd/samd21_pins.c
+++ b/ports/atmel-samd/samd21_pins.c
@@ -41,18 +41,18 @@
.index = 0, \
.pad = 0 \
}
-
-#define TCC(p_tcc, p_wave_output) \
+
+#define TCC(p_index, p_wave_output) \
{ \
- .tcc = p_tcc, \
+ .index = p_index, \
.is_tc = false, \
.wave_output = p_wave_output \
}
-#define TC(p_tc, p_wave_output) \
+#define TC(p_index, p_wave_output) \
{ \
- .tc = p_tc, \
+ .index = p_index - 3, \
.is_tc = true, \
.wave_output = p_wave_output \
}
@@ -101,14 +101,14 @@ const mcu_pin_obj_t pin_## p_name = { \
PIN(PA00, EXTINT_CHANNEL(0), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(1, 0),
- TCC(TCC2, 0),
+ TCC(2, 0),
NO_TIMER);
#endif
#ifdef PIN_PA01
PIN(PA01, EXTINT_CHANNEL(1), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(1, 1),
- TCC(TCC2, 1),
+ TCC(2, 1),
NO_TIMER);
#endif
#ifdef PIN_PA02
@@ -163,105 +163,105 @@ PIN(PB07, EXTINT_CHANNEL(7), ADC_INPUT(15), TOUCH(13),
PIN(PB08, EXTINT_CHANNEL(8), ADC_INPUT(2), TOUCH(14),
NO_SERCOM,
SERCOM(4, 0),
- TC(TC4, 0),
+ TC(4, 0),
NO_TIMER);
#endif
#ifdef PIN_PB09
PIN(PB09, EXTINT_CHANNEL(9), ADC_INPUT(3), TOUCH(15),
NO_SERCOM,
SERCOM(4, 1),
- TC(TC4, 1),
+ TC(4, 1),
NO_TIMER);
#endif
#ifdef PIN_PA04
PIN(PA04, EXTINT_CHANNEL(4), ADC_INPUT(4), TOUCH(2),
NO_SERCOM,
SERCOM(0, 0),
- TCC(TCC0, 0),
+ TCC(0, 0),
NO_TIMER);
#endif
#ifdef PIN_PA05
PIN(PA05, EXTINT_CHANNEL(5), ADC_INPUT(5), TOUCH(3),
NO_SERCOM,
SERCOM(0, 1),
- TCC(TCC0, 1),
+ TCC(0, 1),
NO_TIMER);
#endif
#ifdef PIN_PA06
PIN(PA06, EXTINT_CHANNEL(6), ADC_INPUT(6), TOUCH(4),
NO_SERCOM,
SERCOM(0, 2),
- TCC(TCC1, 0),
+ TCC(1, 0),
NO_TIMER);
#endif
#ifdef PIN_PA07
PIN(PA07, EXTINT_CHANNEL(7), ADC_INPUT(7), TOUCH(5),
NO_SERCOM,
SERCOM(0, 3),
- TCC(TCC1, 1),
+ TCC(1, 1),
NO_TIMER);
#endif
#ifdef PIN_PA08
PIN(PA08, NO_EXTINT, ADC_INPUT(16), NO_TOUCH,
SERCOM(0, 0),
SERCOM(2, 0),
- TCC(TCC0, 0),
- TCC(TCC1, 2));
+ TCC(0, 0),
+ TCC(1, 2));
#endif
#ifdef PIN_PA09
PIN(PA09, EXTINT_CHANNEL(9), ADC_INPUT(17), NO_TOUCH,
SERCOM(0, 1),
SERCOM(2, 1),
- TCC(TCC0, 1),
- TCC(TCC1, 3));
+ TCC(0, 1),
+ TCC(1, 3));
#endif
#ifdef PIN_PA10
PIN(PA10, EXTINT_CHANNEL(10), ADC_INPUT(18), NO_TOUCH,
SERCOM(0, 2),
SERCOM(2, 2),
- TCC(TCC1, 0),
- TCC(TCC0, 2));
+ TCC(1, 0),
+ TCC(0, 2));
#endif
#ifdef PIN_PA11
PIN(PA11, EXTINT_CHANNEL(11), ADC_INPUT(19), NO_TOUCH,
SERCOM(0, 3),
SERCOM(2, 3),
- TCC(TCC1, 1),
- TCC(TCC0, 3));
+ TCC(1, 1),
+ TCC(0, 3));
#endif
#ifdef PIN_PB10
PIN(PB10, EXTINT_CHANNEL(10), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(4, 2),
- TC(TC5, 0),
- TCC(TCC0, 4));
+ TC(5, 0),
+ TCC(0, 4));
#endif
#ifdef PIN_PB11
PIN(PB11, EXTINT_CHANNEL(11), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(4, 3),
- TC(TC5, 1),
- TCC(TCC0, 5));
+ TC(5, 1),
+ TCC(0, 5));
#endif
#ifdef PIN_PB12
PIN(PB12, EXTINT_CHANNEL(12), NO_ADC, NO_TOUCH,
SERCOM(4, 0),
NO_SERCOM,
- TC(TC4, 0),
- TCC(TCC0, 6));
+ TC(4, 0),
+ TCC(0, 6));
#endif
#ifdef PIN_PB13
PIN(PB13, EXTINT_CHANNEL(13), NO_ADC, NO_TOUCH,
SERCOM(4, 1),
NO_SERCOM,
- TC(TC4, 1),
- TCC(TCC0, 7));
+ TC(4, 1),
+ TCC(0, 7));
#endif
#ifdef PIN_PB14
PIN(PB14, EXTINT_CHANNEL(14), NO_ADC, NO_TOUCH,
SERCOM(4, 2),
NO_SERCOM,
- TC(TC5, 0),
+ TC(5, 0),
NO_TIMER);
#endif
@@ -270,22 +270,22 @@ PIN(PB14, EXTINT_CHANNEL(14), NO_ADC, NO_TOUCH,
PIN(PB15, EXTINT_CHANNEL(15), NO_ADC, NO_TOUCH,
SERCOM(4, 3),
NO_SERCOM,
- TC(TC5, 1),
+ TC(5, 1),
NO_TIMER);
#endif
#ifdef PIN_PA12
PIN(PA12, EXTINT_CHANNEL(12), NO_ADC, NO_TOUCH,
SERCOM(2, 0),
SERCOM(4, 0),
- TCC(TCC2, 0),
- TCC(TCC0, 6));
+ TCC(2, 0),
+ TCC(0, 6));
#endif
#ifdef PIN_PA13
PIN(PA13, EXTINT_CHANNEL(13), NO_ADC, NO_TOUCH,
SERCOM(2, 1),
SERCOM(4, 1),
- TCC(TCC2, 1),
- TCC(TCC0, 7));
+ TCC(2, 1),
+ TCC(0, 7));
#endif
#ifdef PIN_PA14
PIN(PA14, EXTINT_CHANNEL(14), NO_ADC, NO_TOUCH,
@@ -295,8 +295,8 @@ PIN(PA14, EXTINT_CHANNEL(14), NO_ADC, NO_TOUCH,
#else
NO_SERCOM,
#endif
- TC(TC3, 0),
- TCC(TCC0, 4));
+ TC(3, 0),
+ TCC(0, 4));
#endif
#ifdef PIN_PA15
PIN(PA15, EXTINT_CHANNEL(15), NO_ADC, NO_TOUCH,
@@ -306,80 +306,80 @@ PIN(PA15, EXTINT_CHANNEL(15), NO_ADC, NO_TOUCH,
#else
NO_SERCOM,
#endif
- TC(TC3, 1),
- TCC(TCC0, 5));
+ TC(3, 1),
+ TCC(0, 5));
#endif
#ifdef PIN_PA16
PIN(PA16, EXTINT_CHANNEL(0), NO_ADC, NO_TOUCH,
SERCOM(1, 0),
SERCOM(3, 0),
- TCC(TCC2, 0),
- TCC(TCC0, 6));
+ TCC(2, 0),
+ TCC(0, 6));
#endif
#ifdef PIN_PA17
PIN(PA17, EXTINT_CHANNEL(1), NO_ADC, NO_TOUCH,
SERCOM(1, 1),
SERCOM(3, 1),
- TCC(TCC2, 1),
- TCC(TCC0, 7));
+ TCC(2, 1),
+ TCC(0, 7));
#endif
#ifdef PIN_PA18
PIN(PA18, EXTINT_CHANNEL(2), NO_ADC, NO_TOUCH,
SERCOM(1, 2),
SERCOM(3, 2),
- TC(TC3, 0),
- TCC(TCC0, 2));
+ TC(3, 0),
+ TCC(0, 2));
#endif
#ifdef PIN_PA19
PIN(PA19, EXTINT_CHANNEL(3), NO_ADC, NO_TOUCH,
SERCOM(1, 3),
SERCOM(3, 3),
- TC(TC3, 1),
- TCC(TCC0, 3));
+ TC(3, 1),
+ TCC(0, 3));
#endif
#ifdef PIN_PB16
PIN(PB16, EXTINT_CHANNEL(0), NO_ADC, NO_TOUCH,
SERCOM(5, 0),
NO_SERCOM,
#ifdef TC6
- TC(TC6, 0),
+ TC(6, 0),
#else
NO_TIMER,
#endif
- TCC(TCC0, 4));
+ TCC(0, 4));
#endif
#ifdef PIN_PB17
PIN(PB17, EXTINT_CHANNEL(1), NO_ADC, NO_TOUCH,
SERCOM(5, 1),
NO_SERCOM,
#ifdef TC6
- TC(TC6, 1),
+ TC(6, 1),
#else
NO_TIMER,
#endif
- TCC(TCC0, 5));
+ TCC(0, 5));
#endif
#ifdef PIN_PA20
PIN(PA20, EXTINT_CHANNEL(4), NO_ADC, NO_TOUCH,
SERCOM(5, 2),
SERCOM(3, 2),
#ifdef TC7
- TC(TC7, 0),
+ TC(7, 0),
#else
NO_TIMER,
#endif
- TCC(TCC0, 6));
+ TCC(0, 6));
#endif
#ifdef PIN_PA21
PIN(PA21, EXTINT_CHANNEL(5), NO_ADC, NO_TOUCH,
SERCOM(5, 3),
SERCOM(3, 3),
#ifdef TC7
- TC(TC7, 1),
+ TC(7, 1),
#else
NO_TIMER,
#endif
- TCC(TCC0, 7));
+ TCC(0, 7));
#endif
#ifdef PIN_PA22
PIN(PA22, EXTINT_CHANNEL(6), NO_ADC, NO_TOUCH,
@@ -388,9 +388,9 @@ PIN(PA22, EXTINT_CHANNEL(6), NO_ADC, NO_TOUCH,
SERCOM(5, 0),
#else
NO_SERCOM,
- #endif,
- TC(TC4, 0),
- TCC(TCC0, 4));
+ #endif
+ TC(4, 0),
+ TCC(0, 4));
#endif
#ifdef PIN_PA23
PIN(PA23, EXTINT_CHANNEL(7), NO_ADC, NO_TOUCH,
@@ -400,8 +400,8 @@ PIN(PA23, EXTINT_CHANNEL(7), NO_ADC, NO_TOUCH,
#else
NO_SERCOM,
#endif
- TC(TC4, 1),
- TCC(TCC0, 5));
+ TC(4, 1),
+ TCC(0, 5));
#endif
#ifdef PIN_PA24
PIN(PA24, EXTINT_CHANNEL(12), NO_ADC, NO_TOUCH,
@@ -411,8 +411,8 @@ PIN(PA24, EXTINT_CHANNEL(12), NO_ADC, NO_TOUCH,
#else
NO_SERCOM,
#endif
- TC(TC5, 0),
- TCC(TCC0, 2));
+ TC(5, 0),
+ TCC(0, 2));
#endif
#ifdef PIN_PA25
PIN(PA25, EXTINT_CHANNEL(13), NO_ADC, NO_TOUCH,
@@ -422,15 +422,15 @@ PIN(PA25, EXTINT_CHANNEL(13), NO_ADC, NO_TOUCH,
#else
NO_SERCOM,
#endif
- TC(TC5, 1),
- TCC(TCC1, 3));
+ TC(5, 1),
+ TCC(1, 3));
#endif
#ifdef PIN_PB22
PIN(PB22, EXTINT_CHANNEL(6), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(5, 2),
#ifdef TC7
- TC(TC7, 0, 0),
+ TC(7, 0, 0),
#else
NO_TIMER,
#endif
@@ -441,7 +441,7 @@ PIN(PB23, EXTINT_CHANNEL(7), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(5, 3),
#ifdef TC7
- TC(TC7, 1, 1),
+ TC(7, 1, 1),
#else
NO_TIMER,
#endif
@@ -465,36 +465,36 @@ PIN(PA28, EXTINT_CHANNEL(8), NO_ADC, NO_TOUCH,
PIN(PA30, EXTINT_CHANNEL(10), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(1, 2),
- TCC(TCC1, 0),
+ TCC(1, 0),
NO_TIMER);
#endif
#ifdef PIN_PA31
PIN(PA31, EXTINT_CHANNEL(11), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(1, 3),
- TCC(TCC1, 1),
+ TCC(1, 1),
NO_TIMER);
#endif
#ifdef PIN_PB30
PIN(PB30, EXTINT_CHANNEL(14), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(5, 0),
- TCC(TCC0, 0),
- TCC(TCC1, 2));
+ TCC(0, 0),
+ TCC(1, 2));
#endif
#ifdef PIN_PB31
PIN(PB31, EXTINT_CHANNEL(15), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(5, 1),
- TCC(TCC0, 1),
- TCC(TCC1, 3));
+ TCC(0, 1),
+ TCC(1, 3));
#endif
#ifdef PIN_PB00
PIN(PB00, EXTINT_CHANNEL(0), ADC_INPUT(8), TOUCH(6),
NO_SERCOM,
SERCOM(5, 2),
#ifdef TC7
- TC(TC7, 0, 0),
+ TC(7, 0, 0),
#else
NO_TIMER,
#endif
@@ -505,7 +505,7 @@ PIN(PB01, EXTINT_CHANNEL(1), ADC_INPUT(9), TOUCH(7),
NO_SERCOM,
SERCOM(5, 3)),
#ifdef TC7
- TC(TC7, 1),
+ TC(7, 1),
#else
NO_TIMER,
#endif
@@ -516,7 +516,7 @@ PIN(PB02, EXTINT_CHANNEL(2), ADC_INPUT(10), TOUCH(8),
NO_SERCOM,
SERCOM(5, 0),
#ifdef TC6
- TC(TC6, 0),
+ TC(6, 0),
#else
NO_TIMER,
#endif
@@ -527,7 +527,7 @@ PIN(PB03, EXTINT_CHANNEL(3), ADC_INPUT(11), TOUCH(9),
NO_SERCOM,
SERCOM(5, 1),
#ifdef TC6
- TC(TC6, 1),
+ TC(6, 1),
#else
NO_TIMER,
#endif
diff --git a/ports/atmel-samd/samd51_pins.c b/ports/atmel-samd/samd51_pins.c
index 41114fe11..78bdf0553 100644
--- a/ports/atmel-samd/samd51_pins.c
+++ b/ports/atmel-samd/samd51_pins.c
@@ -42,19 +42,21 @@
.pad = 0 \
}
-#define TCC(p_tcc, p_wave_output) \
+#define TCC(p_index, p_wave_output) \
{ \
- .tcc = p_tcc, \
+ .index = p_index, \
+ .is_tc = false, \
.wave_output = p_wave_output \
}
-#define TC(p_tc, p_wave_output) \
+#define TC(p_index, p_wave_output) \
{ \
- .tc = p_tc, \
+ .index = p_index, \
+ .is_tc = true, \
.wave_output = p_wave_output \
}
-#define NO_TIMER TCC(0, 0)
+#define NO_TIMER TCC(0xff, 0)
#define TOUCH(y_line) \
.has_touch = true, \
@@ -100,7 +102,7 @@ PIN(PB03, EXTINT_CHANNEL(3), ADC_INPUT(15), NO_ADC,
NO_SERCOM,
SERCOM(5, 1),
#ifdef TC6
- TC(TC6, 1),
+ TC(6, 1),
#else
NO_TIMER,
#endif
@@ -112,7 +114,7 @@ PIN(PA00, EXTINT_CHANNEL(0), NO_ADC, NO_ADC,
NO_TOUCH,
NO_SERCOM,
SERCOM(1, 0),
- TC(TC2, 0),
+ TC(2, 0),
NO_TIMER,
NO_TIMER);
#endif
@@ -121,7 +123,7 @@ PIN(PA01, EXTINT_CHANNEL(1), NO_ADC, NO_ADC,
NO_TOUCH,
NO_SERCOM,
SERCOM(1, 1),
- TC(TC2, 0),
+ TC(2, 0),
NO_TIMER,
NO_TIMER);
#endif
@@ -252,7 +254,7 @@ PIN(PB08, EXTINT_CHANNEL(8), ADC_INPUT(2), ADC_INPUT(0), TOUCH(1),
NO_SERCOM,
SERCOM(4, 0),
#ifdef TC4
- TC(TC4, 0),
+ TC(4, 0),
#else
NO_TIMER,
#endif
@@ -264,7 +266,7 @@ PIN(PB09, EXTINT_CHANNEL(9), ADC_INPUT(3), ADC_INPUT(1), TOUCH(2),
NO_SERCOM,
SERCOM(4, 1),
#ifdef TC4
- TC(TC4, 1),
+ TC(4, 1),
#else
NO_TIMER,
#endif
@@ -275,7 +277,7 @@ PIN(PB09, EXTINT_CHANNEL(9), ADC_INPUT(3), ADC_INPUT(1), TOUCH(2),
PIN(PA04, EXTINT_CHANNEL(4), ADC_INPUT(4), NO_ADC, TOUCH(3),
NO_SERCOM,
SERCOM(0, 0),
- TC(TC0, 0),
+ TC(0, 0),
NO_TIMER,
NO_TIMER);
#endif
@@ -283,7 +285,7 @@ PIN(PA04, EXTINT_CHANNEL(4), ADC_INPUT(4), NO_ADC, TOUCH(3),
PIN(PA05, EXTINT_CHANNEL(5), ADC_INPUT(5), NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(0, 1),
- TC(TC0, 1),
+ TC(0, 1),
NO_TIMER,
NO_TIMER);
#endif
@@ -291,7 +293,7 @@ PIN(PA05, EXTINT_CHANNEL(5), ADC_INPUT(5), NO_ADC, NO_TOUCH,
PIN(PA06, EXTINT_CHANNEL(6), ADC_INPUT(6), NO_ADC, TOUCH(4),
NO_SERCOM,
SERCOM(0, 2),
- TC(TC1, 0),
+ TC(1, 0),
NO_TIMER,
NO_TIMER);
#endif
@@ -301,7 +303,7 @@ PIN(PA06, EXTINT_CHANNEL(6), ADC_INPUT(6), NO_ADC, TOUCH(4),
PIN(PA07, EXTINT_CHANNEL(7), ADC_INPUT(7), NO_ADC, TOUCH(5),
NO_SERCOM,
SERCOM(0, 3),
- TC(TC1, 1),
+ TC(1, 1),
NO_TIMER,
NO_TIMER);
#endif
@@ -314,7 +316,7 @@ PIN(PC04, EXTINT_CHANNEL(4), NO_ADC, NO_ADC, NO_TOUCH,
#endif
NO_SERCOM,
NO_TIMER,
- TCC(TCC0, 0),
+ TCC(0, 0),
NO_TIMER);
#endif
#ifdef PIN_PC05
@@ -357,57 +359,57 @@ PIN(PC07, EXTINT_CHANNEL(7), NO_ADC, NO_ADC, NO_TOUCH,
PIN(PA08, NO_EXTINT, ADC_INPUT(8), ADC_INPUT(2), TOUCH(6),
SERCOM(0, 0),
SERCOM(2, 1),
- TC(TC0, 0),
- TCC(TCC0, 0),
- TCC(TCC1, 4));
+ TC(0, 0),
+ TCC(0, 0),
+ TCC(1, 4));
#endif
#ifdef PIN_PA09
PIN(PA09, EXTINT_CHANNEL(9), ADC_INPUT(9), ADC_INPUT(3), TOUCH(7),
SERCOM(0, 1),
SERCOM(2, 0),
- TC(TC0, 1),
- TCC(TCC0, 1),
- TCC(TCC1, 5));
+ TC(0, 1),
+ TCC(0, 1),
+ TCC(1, 5));
#endif
#ifdef PIN_PA10
PIN(PA10, EXTINT_CHANNEL(10), ADC_INPUT(10), NO_ADC, TOUCH(8),
SERCOM(0, 2),
SERCOM(2, 2),
- TC(TC1, 0),
- TCC(TCC0, 2),
- TCC(TCC1, 6));
+ TC(1, 0),
+ TCC(0, 2),
+ TCC(1, 6));
#endif
#ifdef PIN_PA11
PIN(PA11, EXTINT_CHANNEL(11), ADC_INPUT(11), NO_ADC, TOUCH(9),
SERCOM(0, 3),
SERCOM(2, 3),
- TC(TC1, 0),
- TCC(TCC0, 3),
- TCC(TCC1, 7));
+ TC(1, 0),
+ TCC(0, 3),
+ TCC(1, 7));
#endif
#ifdef PIN_PB10
PIN(PB10, EXTINT_CHANNEL(10), NO_ADC, NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(4, 2),
#ifdef TC5
- TC(TC5, 0),
+ TC(5, 0),
#else
NO_TIMER,
#endif
- TCC(TCC0, 4),
- TCC(TCC1, 0));
+ TCC(0, 4),
+ TCC(1, 0));
#endif
#ifdef PIN_PB11
PIN(PB11, EXTINT_CHANNEL(11), NO_ADC, NO_ADC, NO_TOUCH,
NO_SERCOM,
SERCOM(4, 3),
#ifdef TC5
- TC(TC5, 1),
+ TC(5, 1),
#else
NO_TIMER,
#endif
- TCC(TCC0, 5),
- TCC(TCC1, 1));
+ TCC(0, 5),
+ TCC(1, 1));
#endif
#ifdef PIN_PB12
PIN(PB12, EXTINT_CHANNEL(12), NO_ADC, NO_ADC,
@@ -419,16 +421,16 @@ PIN(PB12, EXTINT_CHANNEL(12), NO_ADC, NO_ADC,
SERCOM(4, 0),
NO_SERCOM,
#ifdef TC4
- TC(TC4, 0),
+ TC(4, 0),
#else
NO_TIMER,
#endif
#ifdef TCC3
- TCC(TCC3, 0),
+ TCC(3, 0),
#else
NO_TIMER,
#endif
- TCC(TCC0, 0));
+ TCC(0, 0));
#endif
#ifdef PIN_PB13
PIN(PB13, EXTINT_CHANNEL(13), NO_ADC, NO_ADC,
@@ -440,16 +442,16 @@ PIN(PB13, EXTINT_CHANNEL(13), NO_ADC, NO_ADC,
SERCOM(4, 1),
NO_SERCOM,
#ifdef TC4
- TC(TC4, 1),
+ TC(4, 1),
#else
NO_TIMER,
#endif
#ifdef TCC3
- TCC(TCC3, 1),
+ TCC(3, 1),
#else
NO_TIMER,
#endif
- TCC(TCC0, 1));
+ TCC(0, 1));
#endif
#ifdef PIN_PB14
PIN(PB14, EXTINT_CHANNEL(14), NO_ADC, NO_ADC,
@@ -461,16 +463,16 @@ PIN(PB14, EXTINT_CHANNEL(14), NO_ADC, NO_ADC,
SERCOM(4, 2),
NO_SERCOM,
#ifdef TC5
- TC(TC5, 0),
+ TC(5, 0),
#else
NO_TIMER,
#endif
#ifdef TCC4
- TCC(TCC4, 0),
+ TCC(4, 0),
#else
NO_TIMER,
#endif
- TCC(TCC0, 2));
+ TCC(0, 2));
#endif
#ifdef PIN_PB15
PIN(PB15, EXTINT_CHANNEL(15), NO_ADC, NO_ADC,
@@ -482,16 +484,16 @@ PIN(PB15, EXTINT_CHANNEL(15), NO_ADC, NO_ADC,
SERCOM(4, 3),
NO_SERCOM,
#ifdef TC5
- TC(TC5, 1),
+ TC(5, 1),
#else
NO_TIMER,
#endif
#ifdef TCC4
- TCC(TCC4, 1),
+ TCC(4, 1),
#else
NO_TIMER,
#endif
- TCC(TCC0, 3));
+ TCC(0, 3));
#endif
#ifdef PIN_PD08
PIN(PD08, EXTINT_CHANNEL(3), NO_ADC, NO_ADC,
@@ -507,7 +509,7 @@ PIN(PD08, EXTINT_CHANNEL(3), NO_ADC, NO_ADC,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC0, 1),
+ TCC(0, 1),
NO_TIMER);
#endif
#ifdef PIN_PD09
@@ -524,7 +526,7 @@ PIN(PD09, EXTINT_CHANNEL(4), NO_ADC, NO_ADC,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC0, 2),
+ TCC(0, 2),
NO_TIMER);
#endif
#ifdef PIN_PD10
@@ -541,7 +543,7 @@ PIN(PD10, EXTINT_CHANNEL(5), NO_ADC, NO_ADC,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC0, 3),
+ TCC(0, 3),
NO_TIMER);
#endif
#ifdef PIN_PD11
@@ -558,7 +560,7 @@ PIN(PD11, EXTINT_CHANNEL(6), NO_ADC, NO_ADC,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC0, 4),
+ TCC(0, 4),
NO_TIMER);
#endif
#ifdef PIN_PD12
@@ -567,7 +569,7 @@ PIN(PD12, EXTINT_CHANNEL(7), NO_ADC, NO_ADC,
NO_SERCOM,
NO_SERCOM,
NO_TIMER,
- TCC(TCC0, 5),
+ TCC(0, 5),
NO_TIMER);
#endif
#ifdef PIN_PC10
@@ -584,8 +586,8 @@ PIN(PC10, EXTINT_CHANNEL(10), NO_ADC, NO_ADC,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC0, 0),
- TCC(TCC1, 4));
+ TCC(0, 0),
+ TCC(1, 4));
#endif
#ifdef PIN_PC11
PIN(PC11, EXTINT_CHANNEL(11), NO_ADC, NO_ADC,
@@ -601,8 +603,8 @@ PIN(PC11, EXTINT_CHANNEL(11), NO_ADC, NO_ADC,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC0, 1),
- TCC(TCC1, 5));
+ TCC(0, 1),
+ TCC(1, 5));
#endif
#ifdef PIN_PC12
PIN(PC12, EXTINT_CHANNEL(12), NO_ADC, NO_ADC,
@@ -618,8 +620,8 @@ PIN(PC12, EXTINT_CHANNEL(12), NO_ADC, NO_ADC,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC0, 2),
- TCC(TCC1, 6));
+ TCC(0, 2),
+ TCC(1, 6));
#endif
#ifdef PIN_PC13
PIN(PC13, EXTINT_CHANNEL(13), NO_ADC, NO_ADC,
@@ -635,8 +637,8 @@ PIN(PC13, EXTINT_CHANNEL(13), NO_ADC, NO_ADC,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC0, 3),
- TCC(TCC1, 7));
+ TCC(0, 3),
+ TCC(1, 7));
#endif
#ifdef PIN_PC14
PIN(PC14, EXTINT_CHANNEL(14), NO_ADC, NO_ADC,
@@ -652,8 +654,8 @@ PIN(PC14, EXTINT_CHANNEL(14), NO_ADC, NO_ADC,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC0, 4),
- TCC(TCC1, 0));
+ TCC(0, 4),
+ TCC(1, 0));
#endif
#ifdef PIN_PC15
PIN(PC15, EXTINT_CHANNEL(15), NO_ADC, NO_ADC,
@@ -669,24 +671,24 @@ PIN(PC15, EXTINT_CHANNEL(15), NO_ADC, NO_ADC,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC0, 5),
- TCC(TCC1, 1));
+ TCC(0, 5),
+ TCC(1, 1));
#endif
#ifdef PIN_PA12
PIN(PA12, EXTINT_CHANNEL(12), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(2, 0),
SERCOM(4, 1),
- TC(TC2, 0),
- TCC(TCC0, 6),
- TCC(TCC1, 2));
+ TC(2, 0),
+ TCC(0, 6),
+ TCC(1, 2));
#endif
#ifdef PIN_PA13
PIN(PA13, EXTINT_CHANNEL(13), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(2, 1),
SERCOM(4, 0),
- TC(TC2, 1),
- TCC(TCC0, 7),
- TCC(TCC1, 3));
+ TC(2, 1),
+ TCC(0, 7),
+ TCC(1, 3));
#endif
// Third page
@@ -694,49 +696,49 @@ PIN(PA13, EXTINT_CHANNEL(13), NO_ADC, NO_ADC, NO_TOUCH,
PIN(PA14, EXTINT_CHANNEL(14), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(2, 2),
SERCOM(4, 2),
- TC(TC3, 0),
- TCC(TCC2, 0),
- TCC(TCC1, 2));
+ TC(3, 0),
+ TCC(2, 0),
+ TCC(1, 2));
#endif
#ifdef PIN_PA15
PIN(PA15, EXTINT_CHANNEL(15), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(2, 3),
SERCOM(4, 3),
- TC(TC3, 1),
- TCC(TCC2, 1),
- TCC(TCC1, 3));
+ TC(3, 1),
+ TCC(2, 1),
+ TCC(1, 3));
#endif
#ifdef PIN_PA16
PIN(PA16, EXTINT_CHANNEL(0), NO_ADC, NO_ADC, TOUCH(10),
SERCOM(1, 0),
SERCOM(3, 1),
- TC(TC2, 0),
- TCC(TCC1, 0),
- TCC(TCC0, 4));
+ TC(2, 0),
+ TCC(1, 0),
+ TCC(0, 4));
#endif
#ifdef PIN_PA17
PIN(PA17, EXTINT_CHANNEL(1), NO_ADC, NO_ADC, TOUCH(11),
SERCOM(1, 1),
SERCOM(3, 0),
- TC(TC2, 1),
- TCC(TCC1, 1),
- TCC(TCC0, 5));
+ TC(2, 1),
+ TCC(1, 1),
+ TCC(0, 5));
#endif
#ifdef PIN_PA18
PIN(PA18, EXTINT_CHANNEL(2), NO_ADC, NO_ADC, TOUCH(12),
SERCOM(1, 2),
SERCOM(3, 2),
- TC(TC3, 0),
- TCC(TCC1, 2),
- TCC(TCC0, 6));
+ TC(3, 0),
+ TCC(1, 2),
+ TCC(0, 6));
#endif
#ifdef PIN_PA19
PIN(PA19, EXTINT_CHANNEL(3), NO_ADC, NO_ADC, TOUCH(13),
SERCOM(1, 3),
SERCOM(3, 3),
- TC(TC3, 1),
- TCC(TCC1, 3),
- TCC(TCC0, 7));
+ TC(3, 1),
+ TCC(1, 3),
+ TCC(0, 7));
#endif
#ifdef PIN_PC16
PIN(PC16, EXTINT_CHANNEL(0), NO_ADC, NO_ADC,
@@ -761,7 +763,7 @@ PIN(PC17, EXTINT_CHANNEL(1), NO_ADC, NO_ADC,
#endif
SERCOM(0, 0),
NO_TIMER,
- TCC(TCC0, 1),
+ TCC(0, 1),
NO_TIMER);
#endif
#ifdef PIN_PC18
@@ -774,7 +776,7 @@ PIN(PC18, EXTINT_CHANNEL(2), NO_ADC, NO_ADC,
#endif
SERCOM(0, 2),
NO_TIMER,
- TCC(TCC0, 2),
+ TCC(0, 2),
NO_TIMER);
#endif
#ifdef PIN_PC19
@@ -787,7 +789,7 @@ PIN(PC19, EXTINT_CHANNEL(3), NO_ADC, NO_ADC,
#endif
SERCOM(0, 3),
NO_TIMER,
- TCC(TCC0, 3),
+ TCC(0, 3),
NO_TIMER);
#endif
#ifdef PIN_PC20
@@ -796,7 +798,7 @@ PIN(PC20, EXTINT_CHANNEL(4), NO_ADC, NO_ADC,
NO_SERCOM,
NO_SERCOM,
NO_TIMER,
- TCC(TCC0, 4),
+ TCC(0, 4),
NO_TIMER);
#endif
#ifdef PIN_PC21
@@ -805,7 +807,7 @@ PIN(PC21, EXTINT_CHANNEL(5), NO_ADC, NO_ADC,
NO_SERCOM,
NO_SERCOM,
NO_TIMER,
- TCC(TCC0, 5),
+ TCC(0, 5),
NO_TIMER);
#endif
#ifdef PIN_PC22
@@ -814,7 +816,7 @@ PIN(PC22, EXTINT_CHANNEL(6), NO_ADC, NO_ADC,
SERCOM(1, 0),
SERCOM(3, 1),
NO_TIMER,
- TCC(TCC0, 6),
+ TCC(0, 6),
NO_TIMER);
#endif
#ifdef PIN_PC23
@@ -823,7 +825,7 @@ PIN(PC23, EXTINT_CHANNEL(7), NO_ADC, NO_ADC,
SERCOM(1, 1),
SERCOM(3, 0),
NO_TIMER,
- TCC(TCC0, 7),
+ TCC(0, 7),
NO_TIMER);
#endif
#ifdef PIN_PD20
@@ -832,7 +834,7 @@ PIN(PD20, EXTINT_CHANNEL(10), NO_ADC, NO_ADC,
SERCOM(1, 2),
SERCOM(3, 2),
NO_TIMER,
- TCC(TCC1, 0),
+ TCC(1, 0),
NO_TIMER);
#endif
#ifdef PIN_PD21
@@ -841,7 +843,7 @@ PIN(PD21, EXTINT_CHANNEL(11), NO_ADC, NO_ADC,
SERCOM(1, 3),
SERCOM(3, 3),
NO_TIMER,
- TCC(TCC1, 1),
+ TCC(1, 1),
NO_TIMER);
#endif
@@ -853,24 +855,24 @@ PIN(PB16, EXTINT_CHANNEL(0), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(5, 0),
NO_SERCOM,
#ifdef TC6
- TC(TC6, 0),
+ TC(6, 0),
#else
NO_TIMER,
#endif
- TCC(TCC3, 0),
- TCC(TCC0, 4));
+ TCC(3, 0),
+ TCC(0, 4));
#endif
#ifdef PIN_PB17
PIN(PB17, EXTINT_CHANNEL(1), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(5, 1),
NO_SERCOM,
#ifdef TC6
- TC(TC6, 1),
+ TC(6, 1),
#else
NO_TIMER,
#endif
- TCC(TCC3, 1),
- TCC(TCC0, 5));
+ TCC(3, 1),
+ TCC(0, 5));
#endif
#ifdef PIN_PB18
PIN(PB18, EXTINT_CHANNEL(2), NO_ADC, NO_ADC, NO_TOUCH,
@@ -881,7 +883,7 @@ PIN(PB18, EXTINT_CHANNEL(2), NO_ADC, NO_ADC, NO_TOUCH,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC1, 0),
+ TCC(1, 0),
NO_TIMER);
#endif
#ifdef PIN_PB19
@@ -893,7 +895,7 @@ PIN(PB19, EXTINT_CHANNEL(3), NO_ADC, NO_ADC, NO_TOUCH,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC1, 1),
+ TCC(1, 1),
NO_TIMER);
#endif
#ifdef PIN_PB20
@@ -905,7 +907,7 @@ PIN(PB20, EXTINT_CHANNEL(4), NO_ADC, NO_ADC, NO_TOUCH,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC1, 2),
+ TCC(1, 2),
NO_TIMER);
#endif
#ifdef PIN_PB21
@@ -917,7 +919,7 @@ PIN(PB21, EXTINT_CHANNEL(5), NO_ADC, NO_ADC, NO_TOUCH,
NO_SERCOM,
#endif
NO_TIMER,
- TCC(TCC1, 3),
+ TCC(1, 3),
NO_TIMER);
#endif
#ifdef PIN_PA20
@@ -925,59 +927,59 @@ PIN(PA20, EXTINT_CHANNEL(4), NO_ADC, NO_ADC, TOUCH(14),
SERCOM(5, 2),
SERCOM(3, 2),
#ifdef TC7
- TC(TC7, 0),
+ TC(7, 0),
#else
NO_TIMER,
#endif
- TCC(TCC1, 4),
- TCC(TCC0, 0));
+ TCC(1, 4),
+ TCC(0, 0));
#endif
#ifdef PIN_PA21
PIN(PA21, EXTINT_CHANNEL(5), NO_ADC, NO_ADC, TOUCH(15),
SERCOM(5, 3),
SERCOM(3, 3),
#ifdef TC7
- TC(TC7, 1),
+ TC(7, 1),
#else
NO_TIMER,
#endif
- TCC(TCC1, 5),
- TCC(TCC0, 1));
+ TCC(1, 5),
+ TCC(0, 1));
#endif
#ifdef PIN_PA22
PIN(PA22, EXTINT_CHANNEL(6), NO_ADC, NO_ADC, TOUCH(16),
SERCOM(3, 0),
SERCOM(5, 1),
#ifdef TC4
- TC(TC4, 0),
+ TC(4, 0),
#else
NO_TIMER,
#endif
- TCC(TCC1, 6),
- TCC(TCC0, 2));
+ TCC(1, 6),
+ TCC(0, 2));
#endif
#ifdef PIN_PA23
PIN(PA23, EXTINT_CHANNEL(7), NO_ADC, NO_ADC, TOUCH(17),
SERCOM(3, 1),
SERCOM(5, 0),
#ifdef TC4
- TC(TC4, 1),
+ TC(4, 1),
#else
NO_TIMER,
#endif
- TCC(TCC1, 7),
- TCC(TCC0, 3));
+ TCC(1, 7),
+ TCC(0, 3));
#endif
#ifdef PIN_PA24
PIN(PA24, EXTINT_CHANNEL(8), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(3, 2),
SERCOM(5, 2),
#ifdef TC5
- TC(TC5, 0),
+ TC(5, 0),
#else
NO_TIMER,
#endif
- TCC(TCC2, 2),
+ TCC(2, 2),
NO_TIMER);
#endif
#ifdef PIN_PA25
@@ -985,7 +987,7 @@ PIN(PA25, EXTINT_CHANNEL(9), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(3, 3),
SERCOM(5, 3),
#ifdef TC5
- TC(TC5, 1),
+ TC(5, 1),
#else
NO_TIMER,
#endif
@@ -999,7 +1001,7 @@ PIN(PB22, EXTINT_CHANNEL(6), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(1, 2),
SERCOM(5, 2),
#ifdef TC7
- TC(TC7, 0),
+ TC(7, 0),
#else
NO_TIMER,
#endif
@@ -1011,7 +1013,7 @@ PIN(PB23, EXTINT_CHANNEL(7), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(1, 3),
SERCOM(5, 3),
#ifdef TC7
- TC(TC7, 1),
+ TC(7, 1),
#else
NO_TIMER,
#endif
@@ -1047,7 +1049,7 @@ PIN(PB27, EXTINT_CHANNEL(13), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(2, 1),
SERCOM(4, 0),
NO_TIMER,
- TCC(TCC1, 3),
+ TCC(1, 3),
NO_TIMER);
#endif
#ifdef PIN_PB28
@@ -1055,7 +1057,7 @@ PIN(PB28, EXTINT_CHANNEL(14), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(2, 2),
SERCOM(4, 2),
NO_TIMER,
- TCC(TCC1, 4),
+ TCC(1, 4),
NO_TIMER);
#endif
#ifdef PIN_PB29
@@ -1063,7 +1065,7 @@ PIN(PB29, EXTINT_CHANNEL(15), NO_ADC, NO_ADC, NO_TOUCH,
SERCOM(2, 3),
SERCOM(4, 3),
NO_TIMER,
- TCC(TCC1, 5),
+ TCC(1, 5),
NO_TIMER);
#endif
#ifdef PIN_PC24
@@ -1123,11 +1125,11 @@ PIN(PA30, EXTINT_CHANNEL(14), NO_ADC, NO_ADC, TOUCH(19),
#endif
SERCOM(1, 2),
#ifdef TC6
- TC(TC6, 0),
+ TC(6, 0),
#else
NO_TIMER,
#endif
- TCC(TCC2, 0),
+ TCC(2, 0),
NO_TIMER);
#endif
#ifdef PIN_PA31
@@ -1139,11 +1141,11 @@ PIN(PA31, EXTINT_CHANNEL(15), NO_ADC, NO_ADC, NO_TOUCH,
#endif
SERCOM(1, 23),
#ifdef TC6
- TC(TC6, 1),
+ TC(6, 1),
#else
NO_TIMER,
#endif
- TCC(TCC2, 1),
+ TCC(2, 1),
NO_TIMER);
#endif
#ifdef PIN_PB30
@@ -1154,9 +1156,9 @@ PIN(PB30, EXTINT_CHANNEL(14), NO_ADC, NO_ADC, NO_TOUCH,
NO_SERCOM,
#endif
SERCOM(5, 1),
- TC(TC0, 0),
- TCC(TCC4, 0),
- TCC(TCC0, 6));
+ TC(0, 0),
+ TCC(4, 0),
+ TCC(0, 6));
#endif
#ifdef PIN_PB31
PIN(PB31, EXTINT_CHANNEL(15), NO_ADC, NO_ADC, NO_TOUCH,
@@ -1166,9 +1168,9 @@ PIN(PB31, EXTINT_CHANNEL(15), NO_ADC, NO_ADC, NO_TOUCH,
NO_SERCOM,
#endif
SERCOM(5, 0),
- TC(TC0, 1),
- TCC(TCC4, 1),
- TCC(TCC0, 7));
+ TC(0, 1),
+ TCC(4, 1),
+ TCC(0, 7));
#endif
#ifdef PIN_PC30
PIN(PC30, EXTINT_CHANNEL(14), NO_ADC, ADC_INPUT(12), NO_TOUCH,
@@ -1198,7 +1200,7 @@ PIN(PB00, EXTINT_CHANNEL(0), ADC_INPUT(12), NO_ADC,
NO_SERCOM,
SERCOM(5, 2),
#ifdef TC7
- TC(TC7, 0),
+ TC(7, 0),
#else
NO_TIMER,
#endif
@@ -1215,7 +1217,7 @@ PIN(PB01, EXTINT_CHANNEL(1), ADC_INPUT(13), NO_ADC,
NO_SERCOM,
SERCOM(5, 3),
#ifdef TC7
- TC(TC7, 1),
+ TC(7, 1),
#else
NO_TIMER,
#endif
@@ -1227,10 +1229,10 @@ PIN(PB02, EXTINT_CHANNEL(2), ADC_INPUT(14), NO_ADC, TOUCH(20),
NO_SERCOM,
SERCOM(5, 0),
#ifdef TC6
- TC(TC6, 0),
+ TC(6, 0),
#else
NO_TIMER,
#endif
- TCC(TCC2, 2),
+ TCC(2, 2),
NO_TIMER);
#endif
diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c
index 5d483b7bf..726a48d06 100644
--- a/ports/atmel-samd/supervisor/port.c
+++ b/ports/atmel-samd/supervisor/port.c
@@ -46,6 +46,9 @@
#include "common-hal/analogio/AnalogIn.h"
#include "common-hal/analogio/AnalogOut.h"
#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/pulseio/PulseIn.h"
+#include "common-hal/pulseio/PulseOut.h"
+#include "common-hal/pulseio/PWMOut.h"
#include "tick.h"
extern volatile bool mp_msc_enabled;
@@ -204,10 +207,10 @@ void reset_port(void) {
// audioout_reset();
// touchin_reset();
// pdmin_reset();
-// pulsein_reset();
-// pulseout_reset();
-// pwmout_reset();
// #endif
+ pulsein_reset();
+ 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 000000000..7b5d06cb0
--- /dev/null
+++ b/ports/atmel-samd/timers.c
@@ -0,0 +1,285 @@
+/*
+ * 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
+
+#ifdef SAMD51
+#include "hri/hri_gclk_d51.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
+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);
+ }
+}
+
+#ifdef SAMD51
+#define TC_OFFSET 0
+#endif
+#ifdef SAMD21
+#define TC_OFFSET 3
+#endif
+
+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);
+}
+// TC0 - TC2 only exist on the SAMD51
+#ifdef TC0
+void TC0_Handler(void) {
+ shared_timer_handler(true, 0);
+}
+#endif
+#ifdef TC1
+void TC1_Handler(void) {
+ shared_timer_handler(true, 1);
+}
+#endif
+#ifdef TC2
+void TC2_Handler(void) {
+ shared_timer_handler(true, 2);
+}
+#endif
+void TC3_Handler(void) {
+ shared_timer_handler(true, 3 - TC_OFFSET);
+}
+void TC4_Handler(void) {
+ shared_timer_handler(true, 4 - TC_OFFSET);
+}
+void TC5_Handler(void) {
+ shared_timer_handler(true, 5 - TC_OFFSET);
+}
+#ifdef TC6
+void TC6_Handler(void) {
+ shared_timer_handler(true, 6 - TC_OFFSET);
+}
+#endif
+#ifdef TC7
+void TC7_Handler(void) {
+ shared_timer_handler(true, 7 - TC_OFFSET);
+}
+#endif
diff --git a/ports/atmel-samd/timers.h b/ports/atmel-samd/timers.h
new file mode 100644
index 000000000..a22ec7484
--- /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
+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