From 190e7d629e6caff2b05f219f507041a22d3879b5 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 9 Feb 2018 00:22:29 -0800 Subject: [PATCH 01/13] WIP --- ports/atmel-samd/Makefile | 8 +- .../common-hal/microcontroller/Pin.h | 2 - ports/atmel-samd/common-hal/pulseio/PWMOut.c | 171 ++++++++++-------- ports/atmel-samd/common-hal/pulseio/PWMOut.h | 4 - ports/atmel-samd/common-hal/pulseio/PulseIn.c | 139 +++++++------- ports/atmel-samd/common-hal/pulseio/PulseIn.h | 1 - .../atmel-samd/common-hal/pulseio/PulseOut.c | 54 +++--- ports/atmel-samd/mpconfigport.h | 5 +- ports/atmel-samd/samd51_pins.c | 2 + 9 files changed, 189 insertions(+), 197 deletions(-) diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 15d59171ee..bb15311e64 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -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 db43bd4b57..9120d38d0c 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Pin.h +++ b/ports/atmel-samd/common-hal/microcontroller/Pin.h @@ -44,9 +44,7 @@ typedef struct { Tc *const tc; Tcc *const tcc; }; - #ifdef SAMD21 bool is_tc:1; - #endif uint8_t wave_output:4; } pin_timer_t; diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index bf2b0cb331..21fc733ddb 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -38,24 +38,29 @@ # define _TCC_SIZE(n,unused) TPASTE3(TCC,n,_SIZE), # define TCC_SIZES { MREPEAT(TCC_INST_NUM, _TCC_SIZE, 0) } -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]; +static uint32_t tcc_periods[TCC_INST_NUM]; +static uint32_t tc_periods[TC_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}; +uint8_t tcc_cc_num[3] = {4, 2, 2}; +#endif +#ifdef SAMD51 +uint8_t tcc_channels[5] = {0xc0, 0xf0, 0xf8, 0xfc, 0xfc}; +uint8_t tcc_cc_num[5] = {6, 4, 3, 2, 2}; +Tcc* tcc_insts[TCC_INST_NUM] = TCC_INSTS; +#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_timer_frequencies[i] = 0; + timer_refcount[i] = 0; } Tcc *tccs[TCC_INST_NUM] = TCC_INSTS; for (int i = 0; i < TCC_INST_NUM; i++) { @@ -65,32 +70,45 @@ 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) { } } } +static uint8_t tcc_channel(uint8_t timer_index, uint8_t wave_output) { + // 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[index]; +} + bool channel_ok(const pin_timer_t* t, uint8_t index) { - return (!t->is_tc && (tcc_channels[index] & (1 << t->channel)) == 0) || + uint8_t channel_bit = 1 << tcc_channel(index, t->wave_output); + return (!t->is_tc && ((tcc_channels[index] & channel_bit) == 0)) || t->is_tc; } -static uint8_t timer_index(uint32_t base_timer_address) { +static uint8_t timer_index(Tcc* base_timer_address) { + #ifdef SAMD21 return (base_timer_address - ((uint32_t) TCC0)) / 0x400; + #endif + // TCCs are scattered through the memory map of the SAMD51 so use a loop. + #ifdef SAMD51 + for (uint8_t i = 0; i < TCC_INST_NUM; i++) { + if (base_timer_address == tcc_insts[i]) { + return i; + } + } + #endif } void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, @@ -185,32 +203,32 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, } timer_periods[index] = top; if (t->is_tc) { - struct tc_config config_tc; - tc_get_config_defaults(&config_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; - 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); + // 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"); - } - tcc_enable(&self->tcc_instance); + // 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"); + // } + // tcc_enable(&self->tcc_instance); } target_timer_frequencies[index] = frequency; @@ -222,18 +240,18 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, // We're changing frequency so claim all of the channels. tcc_channels[index] = 0xff; } else { - tcc_channels[index] |= (1 << t->channel); + tcc_channels[index] |= (1 << tcc_channel(index, t->channel)); } } self->timer = t; // 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); + //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); common_hal_pulseio_pwmout_set_duty_cycle(self, duty); } @@ -250,20 +268,20 @@ void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { uint8_t index = (((uint32_t) t->tcc) - ((uint32_t) TCC0)) / 0x400; timer_refcount[index]--; if (!t->is_tc) { - tcc_channels[index] &= ~(1 << t->channel); + tcc_channels[index] &= ~(1 << tcc_channel(index, t->wave_output)); } if (timer_refcount[index] == 0) { target_timer_frequencies[index] = 0; if (t->is_tc) { - tc_disable(&self->tc_instance); + //tc_disable(&self->tc_instance); } else { if (t->tcc == TCC0) { tcc_channels[index] = 0xf0; } else { tcc_channels[index] = 0xfc; } - tcc_disable(&self->tcc_instance); - tcc_reset(&self->tcc_instance); + //tcc_disable(&self->tcc_instance); + //tcc_reset(&self->tcc_instance); } } reset_pin(self->pin->pin); @@ -276,31 +294,32 @@ extern void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, 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); + //tc_set_compare_value(&self->tc_instance, t->channel, adjusted_duty); } 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); + //tcc_set_compare_value(&self->tcc_instance, t->channel, adjusted_duty); } } 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; + // while (tc_is_syncing(&self->tc_instance)) { + // /* Wait for sync */ + // } + uint16_t cv = t->tc->COUNT16.CC[t->wave_output].reg; return cv * 0xffff / timer_periods[timer_index((uint32_t) self->timer->tc)]; } else { + uint8_t channel = tcc_channel(timer_index(t->tcc), t->wave_output); uint32_t cv = 0; - if ((t->tcc->STATUS.vec.CCBV & (1 << t->channel)) != 0) { - cv = t->tcc->CCB[t->channel].reg; + if ((t->tcc->STATUS.vec.CCBV & (1 << channel)) != 0) { + cv = t->tcc->CCB[channel].reg; } else { - cv = t->tcc->CC[t->channel].reg; + cv = t->tcc->CC[channel].reg; } - 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 / timer_periods[timer_index(t->tcc)]; return duty_cycle; } @@ -332,31 +351,31 @@ void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, uint8_t old_divisor; uint8_t index; if (t->is_tc) { - index = timer_index((uint32_t) self->timer->tc); + index = timer_index(t->tc); old_divisor = t->tc->COUNT16.CTRLA.bit.PRESCALER; } else { - index = timer_index((uint32_t) self->timer->tcc); + index = timer_index(t->tcc); old_divisor = t->tcc->CTRLA.bit.PRESCALER; } if (new_divisor != old_divisor) { if (t->is_tc) { - tc_disable(&self->tc_instance); + //tc_disable(&self->tc_instance); t->tc->COUNT16.CTRLA.bit.PRESCALER = new_divisor; - tc_enable(&self->tc_instance); + //tc_enable(&self->tc_instance); } else { - tcc_disable(&self->tcc_instance); + //tcc_disable(&self->tcc_instance); t->tcc->CTRLA.bit.PRESCALER = new_divisor; - tcc_enable(&self->tcc_instance); + //tcc_enable(&self->tcc_instance); } } timer_periods[index] = new_top; if (t->is_tc) { - while (tc_is_syncing(&self->tc_instance)) { - /* Wait for sync */ - } + // while (tc_is_syncing(&self->tc_instance)) { + // /* Wait for sync */ + // } t->tc->COUNT16.CC[0].reg = new_top; } else { - tcc_set_top_value(&self->tcc_instance, new_top); + //tcc_set_top_value(&self->tcc_instance, new_top); } common_hal_pulseio_pwmout_set_duty_cycle(self, old_duty); diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.h b/ports/atmel-samd/common-hal/pulseio/PWMOut.h index d6af617a98..eef653bcb2 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 99f747caf8..7e001a1e2d 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -28,10 +28,7 @@ #include -#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 "hal/include/hal_gpio.h" #include "mpconfigport.h" #include "py/gc.h" @@ -49,7 +46,7 @@ static uint16_t last_us[EIC_NUMBER_OF_INTERRUPTS]; 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); + //extint_chan_disable_callback(i, EXTINT_CALLBACK_TYPE_DETECT); } active_pulseins[i] = NULL; last_ms[i] = 0; @@ -58,65 +55,65 @@ void pulsein_reset(void) { } 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; + // 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; if (!first_edge) { - config.detection_criteria = EXTINT_DETECT_BOTH; + //config.detection_criteria = EXTINT_DETECT_BOTH; } else if (self->idle_state) { - config.detection_criteria = EXTINT_DETECT_FALLING; + //config.detection_criteria = EXTINT_DETECT_FALLING; } else { - config.detection_criteria = EXTINT_DETECT_RISING; + //config.detection_criteria = EXTINT_DETECT_RISING; } - extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); - extint_chan_set_config(self->channel, &config); + //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); + //extint_chan_enable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); } -static void pulsein_callback(void) { +//static void pulsein_callback(void) { // Grab the current time first. - uint16_t current_us = tc_get_count_value(&ms_timer); + //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; - if (self->first_edge) { - self->first_edge = false; - pulsein_set_config(self, false); - } else { - uint32_t ms_diff = current_ms - last_ms[self->channel]; - uint16_t us_diff = current_us - last_us[self->channel]; - uint32_t total_diff = us_diff; - if (last_us[self->channel] > current_us) { - total_diff = 1000 + current_us - last_us[self->channel]; - if (ms_diff > 1) { - total_diff += (ms_diff - 1) * 1000; - } - } else { - total_diff += ms_diff * 1000; - } - uint16_t duration = 0xffff; - if (total_diff < duration) { - duration = total_diff; - } - - uint16_t i = (self->start + self->len) % self->maxlen; - self->buffer[i] = duration; - if (self->len < self->maxlen) { - self->len++; - } else { - self->start++; - } - } - last_ms[self->channel] = current_ms; - last_us[self->channel] = current_us; -} + //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; + // if (self->first_edge) { + // self->first_edge = false; + // pulsein_set_config(self, false); + // } else { + // uint32_t ms_diff = current_ms - last_ms[self->channel]; + // uint16_t us_diff = current_us - last_us[self->channel]; + // uint32_t total_diff = us_diff; + // if (last_us[self->channel] > current_us) { + // total_diff = 1000 + current_us - last_us[self->channel]; + // if (ms_diff > 1) { + // total_diff += (ms_diff - 1) * 1000; + // } + // } else { + // total_diff += ms_diff * 1000; + // } + // uint16_t duration = 0xffff; + // if (total_diff < duration) { + // duration = total_diff; + // } + // + // uint16_t i = (self->start + self->len) % self->maxlen; + // self->buffer[i] = duration; + // if (self->len < self->maxlen) { + // self->len++; + // } else { + // self->start++; + // } + // } +// last_ms[self->channel] = current_ms; +// last_us[self->channel] = current_us; +// } void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) { @@ -129,7 +126,7 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, 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 +137,15 @@ 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; 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); + //extint_register_callback( + // pulsein_callback, + // self->channel, + // EXTINT_CALLBACK_TYPE_DETECT); + //extint_chan_enable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); } bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) { @@ -160,38 +156,27 @@ 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); + //extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); active_pulseins[self->channel] = NULL; reset_pin(self->pin); self->pin = NO_PIN; } void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) { - extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); + //extint_chan_disable_callback(self->channel, EXTINT_CALLBACK_TYPE_DETECT); } void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, uint16_t trigger_duration) { // 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(); } diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.h b/ports/atmel-samd/common-hal/pulseio/PulseIn.h index f577a61311..e3af42e0a3 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 b2d594232e..4b84357383 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.c @@ -28,8 +28,7 @@ #include -#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" @@ -37,13 +36,12 @@ #include "samd21_pins.h" #include "shared-bindings/pulseio/PulseOut.h" -#undef ENABLE - // 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 Tc* pulseout_tc_instance = NULL; + static __IO PORT_PINCFG_Type *active_pincfg = NULL; static uint16_t *pulse_buffer = NULL; static volatile uint16_t pulse_index = 0; @@ -70,7 +68,7 @@ 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_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); if (pulse_index % 2 == 0) { turn_on(active_pincfg); } @@ -78,7 +76,7 @@ void pulse_finish(struct tc_module *const module) { void pulseout_reset() { refcount = 0; - MP_STATE_VM(pulseout_tc_instance) = NULL; + pulseout_tc_instance = NULL; active_pincfg = NULL; } @@ -97,28 +95,24 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, if (t == 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); + // 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; - 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; - - 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_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)); } 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. @@ -144,8 +138,8 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { refcount--; if (refcount == 0) { - tc_reset(MP_STATE_VM(pulseout_tc_instance)); - gc_free(MP_STATE_VM(pulseout_tc_instance)); + //tc_reset(MP_STATE_VM(pulseout_tc_instance)); + m_free(MP_STATE_VM(pulseout_tc_instance)); MP_STATE_VM(pulseout_tc_instance) = NULL; } self->pin = NO_PIN; @@ -161,11 +155,11 @@ 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_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); - tc_enable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); + //tc_enable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); turn_on(active_pincfg); - tc_start_counter(MP_STATE_VM(pulseout_tc_instance)); + //tc_start_counter(MP_STATE_VM(pulseout_tc_instance)); while(pulse_index < length) { // Do other things while we wait. The interrupts will handle sending the @@ -175,7 +169,7 @@ 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_stop_counter(MP_STATE_VM(pulseout_tc_instance)); + //tc_disable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); active_pincfg = NULL; } diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h index 2df138359c..2e14f7a8b2 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)µcontroller_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/samd51_pins.c b/ports/atmel-samd/samd51_pins.c index 41114fe111..122dd59796 100644 --- a/ports/atmel-samd/samd51_pins.c +++ b/ports/atmel-samd/samd51_pins.c @@ -45,12 +45,14 @@ #define TCC(p_tcc, p_wave_output) \ { \ .tcc = p_tcc, \ + .is_tc = false, \ .wave_output = p_wave_output \ } #define TC(p_tc, p_wave_output) \ { \ .tc = p_tc, \ + .is_tc = true, \ .wave_output = p_wave_output \ } From 0398f308faee7fd699c670681042f15fcf4a5e97 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 9 Feb 2018 16:37:18 -0800 Subject: [PATCH 02/13] m4 compiles, pwmout implemented --- .../common-hal/microcontroller/Pin.h | 7 +- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 502 +++++++++++------- .../atmel-samd/common-hal/pulseio/PulseOut.c | 7 +- ports/atmel-samd/samd21_pins.c | 152 +++--- ports/atmel-samd/samd51_pins.c | 278 +++++----- 5 files changed, 533 insertions(+), 413 deletions(-) diff --git a/ports/atmel-samd/common-hal/microcontroller/Pin.h b/ports/atmel-samd/common-hal/microcontroller/Pin.h index 9120d38d0c..ca639eb849 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Pin.h +++ b/ports/atmel-samd/common-hal/microcontroller/Pin.h @@ -40,12 +40,9 @@ typedef struct { } pin_sercom_t; typedef struct { - union { - Tc *const tc; - Tcc *const tcc; - }; + uint8_t index; bool is_tc:1; - 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 21fc733ddb..cb1464f3f5 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -30,13 +30,17 @@ #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 "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]; @@ -48,19 +52,42 @@ 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}; -uint8_t tcc_cc_num[3] = {4, 2, 2}; +const uint8_t tcc_cc_num[3] = {4, 2, 2}; +const uint8_t tc_gclk_ids[] = {}; +const uint8_t tc_gclk_ids[5] = {TC3_GCLK_ID, TC4_GCLK_ID, TC5_GCLK_ID, TC6_GCLK_ID, TC7_GCLK_ID}; +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}; -uint8_t tcc_cc_num[5] = {6, 4, 3, 2, 2}; -Tcc* tcc_insts[TCC_INST_NUM] = TCC_INSTS; +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 for (int i = 0; i < TCC_INST_NUM; i++) { - target_timer_frequencies[i] = 0; - timer_refcount[i] = 0; + 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++) { @@ -85,29 +112,105 @@ void pwmout_reset(void) { } } -static uint8_t tcc_channel(uint8_t timer_index, uint8_t wave_output) { +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[index]; + return t->wave_output % tcc_cc_num[t->index]; } -bool channel_ok(const pin_timer_t* t, uint8_t index) { - uint8_t channel_bit = 1 << tcc_channel(index, t->wave_output); - return (!t->is_tc && ((tcc_channels[index] & channel_bit) == 0)) || +static void tc_set_enable(Tc* tc, bool enable) { + tc->COUNT16.CTRLA.bit.ENABLE = enable; + while (tc->COUNT16.SYNCBUSY.bit.ENABLE != 0) { + /* Wait for sync */ + } +} + +static void tcc_set_enable(Tcc* tcc, bool enable) { + tcc->CTRLA.bit.ENABLE = enable; + while (tcc->SYNCBUSY.bit.ENABLE != 0) { + /* Wait for sync */ + } +} + +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; } -static uint8_t timer_index(Tcc* base_timer_address) { - #ifdef SAMD21 - return (base_timer_address - ((uint32_t) TCC0)) / 0x400; - #endif - // TCCs are scattered through the memory map of the SAMD51 so use a loop. +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 - for (uint8_t i = 0; i < TCC_INST_NUM; i++) { - if (base_timer_address == tcc_insts[i]) { - return i; + 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; } } + + 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 } @@ -119,7 +222,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"); } @@ -127,72 +235,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 (uint8_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++) { @@ -201,57 +315,48 @@ 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); + turn_on_clocks(timer); + + 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.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER(divisor); + tc->COUNT16.CTRLBSET.bit.LUPD = true; + tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MPWM; + tc->COUNT16.CCBUF[0].reg = top; + #endif + + tc_set_enable(tc, true); } 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"); - // } - // 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; - } else { - tcc_channels[index] |= (1 << tcc_channel(index, t->channel)); + tcc_periods[timer->index] = top; + Tcc* tcc = tcc_insts[timer->index]; + tcc->CTRLA.bit.PRESCALER = divisor; + tcc->CTRLBSET.bit.LUPD = true; + 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); } @@ -265,23 +370,24 @@ 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 << tcc_channel(index, t->wave_output)); - } - 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; + while (tc->COUNT16.SYNCBUSY.bit.SWRST != 0) { + /* Wait for sync */ + } + } 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); @@ -290,36 +396,50 @@ 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_insts[t->index]->COUNT16.CCBUF[t->wave_output].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_insts[t->index]->CCBUF[channel].reg = adjusted_duty; } } 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->wave_output].reg; - return cv * 0xffff / timer_periods[timer_index((uint32_t) self->timer->tc)]; - } else { - uint8_t channel = tcc_channel(timer_index(t->tcc), t->wave_output); - uint32_t cv = 0; - if ((t->tcc->STATUS.vec.CCBV & (1 << channel)) != 0) { - cv = t->tcc->CCB[channel].reg; - } else { - cv = t->tcc->CC[channel].reg; + Tc* tc = tc_insts[t->index]; + while (tc->COUNT16.SYNCBUSY.reg != 0) { + /* Wait for sync */ } + 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; + #ifdef SAMD21 + if ((tcc->STATUS.vec.CCBV & (1 << channel)) != 0) { + cv = tcc->CCB[channel].reg; + } else { + 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(t->tcc)]; + uint32_t duty_cycle = ((uint64_t) cv) * 0xffff / tcc_periods[t->index]; return duty_cycle; } @@ -338,7 +458,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++) { @@ -348,52 +468,60 @@ 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(t->tc); - old_divisor = t->tc->COUNT16.CTRLA.bit.PRESCALER; - } else { - index = timer_index(t->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->COUNT16.CTRLA.bit.ENABLE = false; + while (tc->COUNT16.SYNCBUSY.bit.ENABLE != 0) { + /* Wait for sync */ + } + tc->COUNT16.CTRLA.bit.PRESCALER = new_divisor; + tc->COUNT16.CTRLA.bit.ENABLE = true; } - } - timer_periods[index] = new_top; - if (t->is_tc) { - // while (tc_is_syncing(&self->tc_instance)) { - // /* Wait for sync */ - // } - t->tc->COUNT16.CC[0].reg = new_top; + tc_periods[t->index] = new_top; + while (tc->COUNT16.SYNCBUSY.reg != 0) { + /* Wait for sync */ + } + #ifdef SAMD21 + tc->COUNT16.CC[0].reg = new_top; + #endif + #ifdef SAMD51 + 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->CTRLA.bit.ENABLE = false; + while (tcc->SYNCBUSY.bit.ENABLE != 0) { + /* Wait for sync */ + } + tcc->CTRLA.bit.PRESCALER = new_divisor; + tcc->CTRLA.bit.ENABLE = true; + } + tcc_periods[t->index] = new_top; + while (tcc->SYNCBUSY.reg != 0) { + /* Wait for sync */ + } + tcc->PERBUF.bit.PERBUF = new_top; } 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/PulseOut.c b/ports/atmel-samd/common-hal/pulseio/PulseOut.c index 4b84357383..7ebc566f59 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.c @@ -112,7 +112,7 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, self->pin = carrier->pin->pin; - PortGroup *const port_base = PORT->GROUP[GPIO_PORT(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. @@ -131,7 +131,7 @@ 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); @@ -139,8 +139,7 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { refcount--; if (refcount == 0) { //tc_reset(MP_STATE_VM(pulseout_tc_instance)); - m_free(MP_STATE_VM(pulseout_tc_instance)); - MP_STATE_VM(pulseout_tc_instance) = NULL; + pulseout_tc_instance = NULL; } self->pin = NO_PIN; } diff --git a/ports/atmel-samd/samd21_pins.c b/ports/atmel-samd/samd21_pins.c index b86f9acbfe..0fa3f57bd0 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,91 +306,87 @@ 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, SERCOM(3, 0), #ifdef SERCOM5 SERCOM(5, 0), - #else - NO_SERCOM, - #endif, - TC(TC4, 0), - TCC(TCC0, 4)); + #els0, 4)); #endif #ifdef PIN_PA23 PIN(PA23, EXTINT_CHANNEL(7), NO_ADC, NO_TOUCH, @@ -400,8 +396,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 +407,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 +418,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 +437,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 +461,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 +501,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 +512,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 +523,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 122dd59796..78bdf0553c 100644 --- a/ports/atmel-samd/samd51_pins.c +++ b/ports/atmel-samd/samd51_pins.c @@ -42,21 +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, \ @@ -102,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 @@ -114,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 @@ -123,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 @@ -254,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 @@ -266,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 @@ -277,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 @@ -285,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 @@ -293,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 @@ -303,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 @@ -316,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 @@ -359,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, @@ -421,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, @@ -442,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, @@ -463,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, @@ -484,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, @@ -509,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 @@ -526,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 @@ -543,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 @@ -560,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 @@ -569,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 @@ -586,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, @@ -603,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, @@ -620,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, @@ -637,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, @@ -654,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, @@ -671,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 @@ -696,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, @@ -763,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 @@ -776,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 @@ -789,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 @@ -798,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 @@ -807,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 @@ -816,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 @@ -825,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 @@ -834,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 @@ -843,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 @@ -855,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, @@ -883,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 @@ -895,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 @@ -907,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 @@ -919,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 @@ -927,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 @@ -987,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 @@ -1001,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 @@ -1013,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 @@ -1049,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 @@ -1057,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 @@ -1065,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 @@ -1125,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 @@ -1141,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 @@ -1156,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, @@ -1168,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, @@ -1200,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 @@ -1217,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 @@ -1229,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 From 0397202288b5e883f4306cb8962019bf0dd473f1 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 9 Feb 2018 17:21:06 -0800 Subject: [PATCH 03/13] m4 compiles, pwmout implemented but TC0 (A1) doesn't run --- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index cb1464f3f5..ef5efaedcc 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -198,6 +198,8 @@ void turn_on_clocks(const pin_timer_t* timer) { } } + // 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 From cc616aea4e8553e1e92fc402dda64ce67a12b519 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 12 Feb 2018 23:41:26 -0800 Subject: [PATCH 04/13] m4 tc output works. Watch out for the PAC! --- main.c | 7 ++++--- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 13 +++++++++++-- ports/atmel-samd/supervisor/port.c | 3 ++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/main.c b/main.c index 21940d795a..fc70e9c3ec 100644 --- a/main.c +++ b/main.c @@ -153,6 +153,10 @@ bool start_mp(safe_mode_t safe_mode) { serial_write(MSG_DOUBLE_FILE_EXTENSION); } } + + reset_port(); + reset_board(); + reset_mp(); reset_status_led(); if (result.return_code & PYEXEC_FORCED_EXIT) { @@ -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/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index ef5efaedcc..1b5cedac21 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -330,10 +330,16 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, tc->COUNT16.CC[0].reg = top; #endif #ifdef SAMD51 + + tc->COUNT16.CTRLA.bit.SWRST = 1; + while (tc->COUNT16.CTRLA.bit.SWRST == 1) { + } + tc_set_enable(tc, false); tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER(divisor); - tc->COUNT16.CTRLBSET.bit.LUPD = true; + //tc->COUNT16.CTRLBSET.bit.LUPD = true; tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MPWM; tc->COUNT16.CCBUF[0].reg = top; + tc->COUNT16.CCBUF[1].reg = top / 2; #endif tc_set_enable(tc, true); @@ -404,7 +410,10 @@ extern void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, tc_insts[t->index]->COUNT16.CC[t->wave_output].reg = adjusted_duty; #endif #ifdef SAMD51 - tc_insts[t->index]->COUNT16.CCBUF[t->wave_output].reg = adjusted_duty; + while (tc_insts[t->index]->COUNT16.SYNCBUSY.bit.CC1 != 0) { + // Wait for a previous value to be written. + } + tc_insts[t->index]->COUNT16.CCBUF[1].reg = adjusted_duty; #endif } else { uint32_t adjusted_duty = ((uint64_t) tcc_periods[t->index]) * duty / 0xffff; diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 5d483b7bf4..7a947010db 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -46,6 +46,7 @@ #include "common-hal/analogio/AnalogIn.h" #include "common-hal/analogio/AnalogOut.h" #include "common-hal/microcontroller/Pin.h" +#include "common-hal/pulseio/PWMOut.h" #include "tick.h" extern volatile bool mp_msc_enabled; @@ -206,8 +207,8 @@ void reset_port(void) { // pdmin_reset(); // pulsein_reset(); // pulseout_reset(); -// pwmout_reset(); // #endif + pwmout_reset(); analogin_reset(); From 6c3075bec679bce29b4746fc3458edbd29160b42 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 13 Feb 2018 14:22:55 -0800 Subject: [PATCH 05/13] m4 tc and tcc works. multi-tcc channels ok too. --- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index 1b5cedac21..360a3e3ce3 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -336,18 +336,17 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, } tc_set_enable(tc, false); tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER(divisor); - //tc->COUNT16.CTRLBSET.bit.LUPD = true; tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MPWM; tc->COUNT16.CCBUF[0].reg = top; - tc->COUNT16.CCBUF[1].reg = top / 2; + tc->COUNT16.CCBUF[1].reg = 0; #endif tc_set_enable(tc, true); } else { tcc_periods[timer->index] = top; Tcc* tcc = tcc_insts[timer->index]; + tcc_set_enable(tcc, false); tcc->CTRLA.bit.PRESCALER = divisor; - tcc->CTRLBSET.bit.LUPD = true; tcc->PER.bit.PER = top; tcc->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val; tcc_set_enable(tcc, true); @@ -410,15 +409,20 @@ extern void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, tc_insts[t->index]->COUNT16.CC[t->wave_output].reg = adjusted_duty; #endif #ifdef SAMD51 - while (tc_insts[t->index]->COUNT16.SYNCBUSY.bit.CC1 != 0) { + Tc* tc = tc_insts[t->index]; + while (tc->COUNT16.SYNCBUSY.bit.CC1 != 0) { // Wait for a previous value to be written. } - tc_insts[t->index]->COUNT16.CCBUF[1].reg = adjusted_duty; + tc->COUNT16.CCBUF[1].reg = adjusted_duty; #endif } else { uint32_t adjusted_duty = ((uint64_t) tcc_periods[t->index]) * duty / 0xffff; uint8_t channel = tcc_channel(t); - tcc_insts[t->index]->CCBUF[channel].reg = adjusted_duty; + Tcc* tcc = tcc_insts[t->index]; + while ((tcc->SYNCBUSY.vec.CC & (1 << channel)) != 0) { + // Wait for a previous value to be written. + } + tcc->CCBUF[channel].reg = adjusted_duty; } } From 8479eef5780f3460f8fa5b26dcb451a9d14c114e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 13 Feb 2018 16:44:04 -0800 Subject: [PATCH 06/13] m0 tc and tcc work --- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 69 +++++++++++++------ ports/atmel-samd/common-hal/pulseio/PulseIn.c | 8 +-- ports/atmel-samd/samd21_pins.c | 6 +- 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index 360a3e3ce3..de45f16e03 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -34,6 +34,9 @@ #include "atmel_start_pins.h" #include "hal/utils/include/utils_repeat_macro.h" +#ifdef SAMD21 +#include "hpl/gclk/hpl_gclk_base.h" +#endif #include "samd21_pins.h" @@ -53,8 +56,16 @@ const uint16_t prescaler[8] = {1, 2, 4, 8, 16, 64, 256, 1024}; #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[] = {}; -const uint8_t tc_gclk_ids[5] = {TC3_GCLK_ID, TC4_GCLK_ID, TC5_GCLK_ID, TC6_GCLK_ID, TC7_GCLK_ID}; +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 @@ -120,9 +131,16 @@ static uint8_t tcc_channel(const pin_timer_t* t) { 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) { @@ -132,6 +150,15 @@ static void tcc_set_enable(Tcc* tcc, bool enable) { } } +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)) || @@ -381,9 +408,7 @@ void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { Tc* tc = tc_insts[t->index]; tc_set_enable(tc, false); tc->COUNT16.CTRLA.bit.SWRST = true; - while (tc->COUNT16.SYNCBUSY.bit.SWRST != 0) { - /* Wait for sync */ - } + tc_wait_for_sync(tc); } else { tcc_refcount[t->index]--; tcc_channels[t->index] &= ~(1 << tcc_channel(t)); @@ -422,7 +447,12 @@ extern void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, while ((tcc->SYNCBUSY.vec.CC & (1 << channel)) != 0) { // Wait for a previous value to be written. } + #ifdef SAMD21 + tcc->CCB[channel].reg = adjusted_duty; + #endif + #ifdef SAMD51 tcc->CCBUF[channel].reg = adjusted_duty; + #endif } } @@ -430,9 +460,7 @@ 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) { Tc* tc = tc_insts[t->index]; - while (tc->COUNT16.SYNCBUSY.reg != 0) { - /* Wait for sync */ - } + tc_wait_for_sync(tc); uint16_t cv = tc->COUNT16.CC[t->wave_output].reg; return cv * 0xffff / tc_periods[t->index]; } else { @@ -487,39 +515,38 @@ void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, Tc* tc = tc_insts[t->index]; uint8_t old_divisor = tc->COUNT16.CTRLA.bit.PRESCALER; if (new_divisor != old_divisor) { - tc->COUNT16.CTRLA.bit.ENABLE = false; - while (tc->COUNT16.SYNCBUSY.bit.ENABLE != 0) { - /* Wait for sync */ - } + tc_set_enable(tc, false); tc->COUNT16.CTRLA.bit.PRESCALER = new_divisor; - tc->COUNT16.CTRLA.bit.ENABLE = true; + tc_set_enable(tc, true); } tc_periods[t->index] = new_top; - while (tc->COUNT16.SYNCBUSY.reg != 0) { - /* Wait for sync */ - } #ifdef SAMD21 tc->COUNT16.CC[0].reg = new_top; #endif #ifdef SAMD51 + while (tc->COUNT16.SYNCBUSY.reg != 0) { + /* Wait for sync */ + } tc->COUNT16.CCBUF[0].reg = new_top; #endif } else { Tcc* tcc = tcc_insts[t->index]; uint8_t old_divisor = tcc->CTRLA.bit.PRESCALER; if (new_divisor != old_divisor) { - tcc->CTRLA.bit.ENABLE = false; - while (tcc->SYNCBUSY.bit.ENABLE != 0) { - /* Wait for sync */ - } + tcc_set_enable(tcc, false); tcc->CTRLA.bit.PRESCALER = new_divisor; - tcc->CTRLA.bit.ENABLE = true; + 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); diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c index 7e001a1e2d..5f7ec7a091 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -39,12 +39,12 @@ #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]; void pulsein_reset(void) { - for (int i = 0; i < EIC_NUMBER_OF_INTERRUPTS; i++) { + for (int i = 0; i < EIC_EXTINT_NUM; i++) { if (active_pulseins[i] != NULL) { //extint_chan_disable_callback(i, EXTINT_CALLBACK_TYPE_DETECT); } diff --git a/ports/atmel-samd/samd21_pins.c b/ports/atmel-samd/samd21_pins.c index 0fa3f57bd0..f1d006de8b 100644 --- a/ports/atmel-samd/samd21_pins.c +++ b/ports/atmel-samd/samd21_pins.c @@ -386,7 +386,11 @@ PIN(PA22, EXTINT_CHANNEL(6), NO_ADC, NO_TOUCH, SERCOM(3, 0), #ifdef SERCOM5 SERCOM(5, 0), - #els0, 4)); + #else + NO_SERCOM, + #endif + TC(4, 0), + TCC(0, 4)); #endif #ifdef PIN_PA23 PIN(PA23, EXTINT_CHANNEL(7), NO_ADC, NO_TOUCH, From 6a7d889dd4df813e2a00d8e741651ff736274e83 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 13 Feb 2018 18:17:20 -0800 Subject: [PATCH 07/13] m0 pulseout works. Factored out shared timer code. --- ports/atmel-samd/Makefile | 2 +- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 149 +--------- .../atmel-samd/common-hal/pulseio/PulseOut.c | 85 ++++-- .../atmel-samd/common-hal/pulseio/PulseOut.h | 1 + ports/atmel-samd/supervisor/port.c | 3 +- ports/atmel-samd/timers.c | 258 ++++++++++++++++++ ports/atmel-samd/timers.h | 67 +++++ 7 files changed, 390 insertions(+), 175 deletions(-) create mode 100644 ports/atmel-samd/timers.c create mode 100644 ports/atmel-samd/timers.h diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index bb15311e64..041f1d1ad7 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -188,7 +188,6 @@ SRC_ASF := \ hpl/rtc/hpl_rtc.c \ hpl/sercom/hpl_sercom.c \ hpl/systick/hpl_systick.c \ - hpl/tc/hpl_tc.c \ hpl/usb/hpl_usb.c \ usb/class/cdc/device/cdcdf_acm.c \ usb/class/msc/device/mscdf.c \ @@ -227,6 +226,7 @@ SRC_C = \ peripherals.c \ $(CHIP_FAMILY)_pins.c \ tick.c \ + timers.c \ usb.c \ usb_mass_storage.c \ boards/$(BOARD)/board.c \ diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index de45f16e03..ba534811e2 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -34,9 +34,7 @@ #include "atmel_start_pins.h" #include "hal/utils/include/utils_repeat_macro.h" -#ifdef SAMD21 -#include "hpl/gclk/hpl_gclk_base.h" -#endif +#include "timers.h" #include "samd21_pins.h" @@ -55,44 +53,10 @@ const uint16_t prescaler[8] = {1, 2, 4, 8, 16, 64, 256, 1024}; // This bitmask keeps track of which channels of a TCC are currently claimed. #ifdef SAMD21 uint8_t tcc_channels[3] = {0xf0, 0xfc, 0xfc}; -const uint8_t tcc_cc_num[3] = {4, 2, 2}; -const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC3_GCLK_ID, - TC4_GCLK_ID, - TC5_GCLK_ID, -#ifdef TC6_GCLK_ID - , TC6_GCLK_ID -#endif -#ifdef TC7_GCLK_ID - , TC7_GCLK_ID -#endif - }; -const uint8_t tcc_gclk_ids[3] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID}; #endif #ifdef SAMD51 uint8_t tcc_channels[5] = {0xc0, 0xf0, 0xf8, 0xfc, 0xfc}; -static const uint8_t tcc_cc_num[5] = {6, 4, 3, 2, 2}; -const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC0_GCLK_ID, - TC1_GCLK_ID, - TC2_GCLK_ID, - TC3_GCLK_ID -#ifdef TC4_GCLK_ID - , TC4_GCLK_ID #endif -#ifdef TC5_GCLK_ID - , TC5_GCLK_ID -#endif -#ifdef TC6_GCLK_ID - , TC6_GCLK_ID -#endif -#ifdef TC7_GCLK_ID - , TC7_GCLK_ID -#endif - }; -const uint8_t tcc_gclk_ids[5] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID, TCC3_GCLK_ID, - TCC4_GCLK_ID}; -#endif -static Tc* const tc_insts[TC_INST_NUM] = TC_INSTS; -static Tcc* const tcc_insts[TCC_INST_NUM] = TCC_INSTS; void pwmout_reset(void) { // Reset all timers @@ -129,120 +93,12 @@ static uint8_t tcc_channel(const pin_timer_t* t) { return t->wave_output % tcc_cc_num[t->index]; } -static void tc_set_enable(Tc* tc, bool enable) { - tc->COUNT16.CTRLA.bit.ENABLE = enable; - #ifdef SAMD21 - while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) { - /* Wait for sync */ - } - #endif - #ifdef SAMD51 - while (tc->COUNT16.SYNCBUSY.bit.ENABLE != 0) { - /* Wait for sync */ - } - #endif -} - -static void tcc_set_enable(Tcc* tcc, bool enable) { - tcc->CTRLA.bit.ENABLE = enable; - while (tcc->SYNCBUSY.bit.ENABLE != 0) { - /* Wait for sync */ - } -} - -static void tc_wait_for_sync(Tc* tc) { - #ifdef SAMD21 - while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) {} - #endif - #ifdef SAMD51 - while (tc->COUNT16.SYNCBUSY.reg != 0) {} - #endif -} - bool channel_ok(const pin_timer_t* t) { uint8_t channel_bit = 1 << tcc_channel(t); return (!t->is_tc && ((tcc_channels[t->index] & channel_bit) == 0)) || t->is_tc; } -void turn_on_clocks(const pin_timer_t* timer) { - uint8_t gclk_id; - if (timer->is_tc) { - gclk_id = tc_gclk_ids[timer->index]; - } else { - gclk_id = tcc_gclk_ids[timer->index]; - } - // Turn on the clocks for the peripherals. - #ifdef SAMD51 - if (timer->is_tc) { - switch (timer->index) { - case 0: - MCLK->APBAMASK.reg |= MCLK_APBAMASK_TC0; - break; - case 1: - MCLK->APBAMASK.reg |= MCLK_APBAMASK_TC1; - break; - case 2: - MCLK->APBBMASK.reg |= MCLK_APBBMASK_TC2; - break; - case 3: - MCLK->APBBMASK.reg |= MCLK_APBBMASK_TC3; - break; - case 4: - MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC4; - break; - case 5: - MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC5; - break; - case 6: - MCLK->APBDMASK.reg |= MCLK_APBDMASK_TC6; - break; - case 7: - MCLK->APBDMASK.reg |= MCLK_APBDMASK_TC7; - break; - default: - break; - } - } else { - switch (timer->index) { - case 0: - MCLK->APBBMASK.reg |= MCLK_APBBMASK_TCC0; - break; - case 1: - MCLK->APBBMASK.reg |= MCLK_APBBMASK_TCC1; - break; - case 2: - MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC2; - break; - case 3: - MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC3; - break; - case 4: - MCLK->APBDMASK.reg |= MCLK_APBDMASK_TCC4; - break; - default: - break; - } - } - - // FIXME(tannewt): TC4-TC7 can only have 100mhz inputs. - - hri_gclk_write_PCHCTRL_reg(GCLK, gclk_id, - GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); - #endif - - #ifdef SAMD21 - // Determine the clock slot on the APBC bus. TCC0 is the first and 8 slots in. - uint8_t clock_slot = 8 + timer->index; - // We index TCs starting at zero but in memory they begin at three so we have to add three. - if (timer->is_tc) { - clock_slot += 3; - } - PM->APBCMASK.reg |= 1 << clock_slot; - _gclk_enable_channel(gclk_id, GCLK_CLKCTRL_GEN_GCLK0_Val); - #endif -} - void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, const mcu_pin_obj_t* pin, uint16_t duty, @@ -345,7 +201,8 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, } } - turn_on_clocks(timer); + // We use the zeroeth clock on either port to go full speed. + turn_on_clocks(timer->is_tc, timer->index, 0); if (timer->is_tc) { tc_periods[timer->index] = top; diff --git a/ports/atmel-samd/common-hal/pulseio/PulseOut.c b/ports/atmel-samd/common-hal/pulseio/PulseOut.c index 7ebc566f59..35224c8e5d 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.c @@ -35,12 +35,13 @@ #include "py/runtime.h" #include "samd21_pins.h" #include "shared-bindings/pulseio/PulseOut.h" +#include "timers.h" // This timer is shared amongst all PulseOut objects under the assumption that // the code is single threaded. static uint8_t refcount = 0; -static Tc* pulseout_tc_instance = NULL; +static uint8_t pulseout_tc_index = 0xff; static __IO PORT_PINCFG_Type *active_pincfg = NULL; static uint16_t *pulse_buffer = NULL; @@ -56,7 +57,7 @@ static void turn_off(__IO PORT_PINCFG_Type * pincfg) { pincfg->reg = PORT_PINCFG_RESETVALUE; } -void pulse_finish(struct tc_module *const module) { +void pulse_finish(void) { pulse_index++; if (active_pincfg == NULL) { @@ -68,15 +69,27 @@ void pulse_finish(struct tc_module *const module) { return; } current_compare = (current_compare + pulse_buffer[pulse_index] * 3 / 4) & 0xffff; - //tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); + Tc* tc = tc_insts[pulseout_tc_index]; + tc->COUNT16.CC[0].reg = current_compare; if (pulse_index % 2 == 0) { turn_on(active_pincfg); } } +void pulseout_interrupt_handler(uint8_t index) { + if (index != pulseout_tc_index) return; + Tc* tc = tc_insts[index]; + if (!tc->COUNT16.INTFLAG.bit.MC0) return; + + pulse_finish(); + + // Clear the interrupt bit. + tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0; +} + void pulseout_reset() { refcount = 0; - pulseout_tc_instance = NULL; + pulseout_tc_index = 0xff; active_pincfg = NULL; } @@ -84,29 +97,44 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, const pulseio_pwmout_obj_t* carrier) { if (refcount == 0) { // Find a spare timer. - Tc *t = NULL; - Tc *tcs[TC_INST_NUM] = TC_INSTS; - for (uint8_t i = TC_INST_NUM; i > 0; i--) { - if (tcs[i - 1]->COUNT16.CTRLA.bit.ENABLE == 0) { - t = tcs[i - 1]; + Tc *tc = NULL; + uint8_t index = TC_INST_NUM - 1; + for (; index >= 0; index--) { + if (tc_insts[index]->COUNT16.CTRLA.bit.ENABLE == 0) { + tc = tc_insts[index]; break; } } - if (t == NULL) { + if (tc == NULL) { mp_raise_RuntimeError("All timers in use"); } - // struct tc_config config_tc; - // tc_get_config_defaults(&config_tc); - // - // config_tc.counter_size = TC_COUNTER_SIZE_16BIT; - // config_tc.clock_prescaler = TC_CTRLA_PRESCALER_DIV64; - // config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_FREQ; + pulseout_tc_index = index; - // tc_init(MP_STATE_VM(pulseout_tc_instance), t, &config_tc); - // tc_register_callback(MP_STATE_VM(pulseout_tc_instance), pulse_finish, TC_CALLBACK_CC_CHANNEL0); - // tc_enable(MP_STATE_VM(pulseout_tc_instance)); - // tc_stop_counter(MP_STATE_VM(pulseout_tc_instance)); + // We use GCLK0 for SAMD21 and GCLK1 for SAMD51 because they both run at 48mhz making our + // math the same across the boards. + #ifdef SAMD21 + turn_on_clocks(true, index, 0); + #endif + #ifdef SAMD51 + turn_on_clocks(true, index, 1); + #endif + + + #ifdef SAMD21 + tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | + TC_CTRLA_PRESCALER_DIV64 | + TC_CTRLA_WAVEGEN_NFRQ; + #endif + #ifdef SAMD51 + tc_reset(tc); + tc_set_enable(tc, false); + tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER_DIV64; + tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_NFRQ; + #endif + + tc_set_enable(tc, true); + tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_STOP; } refcount++; @@ -138,8 +166,8 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { refcount--; if (refcount == 0) { - //tc_reset(MP_STATE_VM(pulseout_tc_instance)); - pulseout_tc_instance = NULL; + tc_reset(tc_insts[pulseout_tc_index]); + pulseout_tc_index = 0xff; } self->pin = NO_PIN; } @@ -154,11 +182,13 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu pulse_length = length; current_compare = pulses[0] * 3 / 4; - //tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); + Tc* tc = tc_insts[pulseout_tc_index]; + tc->COUNT16.CC[0].reg = current_compare; - //tc_enable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); + tc->COUNT16.INTENSET.reg = TC_INTENSET_MC0; + tc_enable_interrupts(pulseout_tc_index); turn_on(active_pincfg); - //tc_start_counter(MP_STATE_VM(pulseout_tc_instance)); + tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER; while(pulse_index < length) { // Do other things while we wait. The interrupts will handle sending the @@ -168,7 +198,8 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu #endif } - //tc_stop_counter(MP_STATE_VM(pulseout_tc_instance)); - //tc_disable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); + tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_STOP; + tc->COUNT16.INTENCLR.reg = TC_INTENCLR_MC0; + tc_disable_interrupts(pulseout_tc_index); active_pincfg = NULL; } diff --git a/ports/atmel-samd/common-hal/pulseio/PulseOut.h b/ports/atmel-samd/common-hal/pulseio/PulseOut.h index 4294d6d68d..634088128f 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.h +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.h @@ -38,5 +38,6 @@ typedef struct { } pulseio_pulseout_obj_t; void pulseout_reset(void); +void pulseout_interrupt_handler(uint8_t index); #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEOUT_H diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 7a947010db..c120b01369 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -46,6 +46,7 @@ #include "common-hal/analogio/AnalogIn.h" #include "common-hal/analogio/AnalogOut.h" #include "common-hal/microcontroller/Pin.h" +#include "common-hal/pulseio/PulseOut.h" #include "common-hal/pulseio/PWMOut.h" #include "tick.h" @@ -206,8 +207,8 @@ void reset_port(void) { // touchin_reset(); // pdmin_reset(); // pulsein_reset(); -// pulseout_reset(); // #endif + pulseout_reset(); pwmout_reset(); analogin_reset(); diff --git a/ports/atmel-samd/timers.c b/ports/atmel-samd/timers.c new file mode 100644 index 0000000000..3a1b21edfd --- /dev/null +++ b/ports/atmel-samd/timers.c @@ -0,0 +1,258 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "timers.h" + +#include "common-hal/pulseio/PulseOut.h" + +#ifdef SAMD21 +#include "hpl/gclk/hpl_gclk_base.h" +#endif + +// This bitmask keeps track of which channels of a TCC are currently claimed. +#ifdef SAMD21 +const uint8_t tcc_cc_num[3] = {4, 2, 2}; +const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC3_GCLK_ID, + TC4_GCLK_ID, + TC5_GCLK_ID, +#ifdef TC6_GCLK_ID + , TC6_GCLK_ID +#endif +#ifdef TC7_GCLK_ID + , TC7_GCLK_ID +#endif + }; +const uint8_t tcc_gclk_ids[3] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID}; +#endif +#ifdef SAMD51 +static const uint8_t tcc_cc_num[5] = {6, 4, 3, 2, 2}; +const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC0_GCLK_ID, + TC1_GCLK_ID, + TC2_GCLK_ID, + TC3_GCLK_ID +#ifdef TC4_GCLK_ID + , TC4_GCLK_ID +#endif +#ifdef TC5_GCLK_ID + , TC5_GCLK_ID +#endif +#ifdef TC6_GCLK_ID + , TC6_GCLK_ID +#endif +#ifdef TC7_GCLK_ID + , TC7_GCLK_ID +#endif + }; +const uint8_t tcc_gclk_ids[5] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID, TCC3_GCLK_ID, + TCC4_GCLK_ID}; +#endif +Tc* const tc_insts[TC_INST_NUM] = TC_INSTS; +Tcc* const tcc_insts[TCC_INST_NUM] = TCC_INSTS; + +IRQn_Type const tc_irq[TC_INST_NUM] = { +#ifdef TC0 + TC0_IRQn, +#endif +#ifdef TC1 + TC1_IRQn, +#endif +#ifdef TC2 + TC2_IRQn, +#endif + TC3_IRQn, + TC4_IRQn, + TC5_IRQn +#ifdef TC6 + , TC6_IRQn +#endif +#ifdef TC7 + , TC7_IRQn +#endif +}; + +void turn_on_clocks(bool is_tc, uint8_t index, uint32_t gclk_index) { + uint8_t gclk_id; + if (is_tc) { + gclk_id = tc_gclk_ids[index]; + } else { + gclk_id = tcc_gclk_ids[index]; + } + // Turn on the clocks for the peripherals. + #ifdef SAMD51 + if (is_tc) { + switch (index) { + case 0: + MCLK->APBAMASK.reg |= MCLK_APBAMASK_TC0; + break; + case 1: + MCLK->APBAMASK.reg |= MCLK_APBAMASK_TC1; + break; + case 2: + MCLK->APBBMASK.reg |= MCLK_APBBMASK_TC2; + break; + case 3: + MCLK->APBBMASK.reg |= MCLK_APBBMASK_TC3; + break; + case 4: + MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC4; + break; + case 5: + MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC5; + break; + case 6: + MCLK->APBDMASK.reg |= MCLK_APBDMASK_TC6; + break; + case 7: + MCLK->APBDMASK.reg |= MCLK_APBDMASK_TC7; + break; + default: + break; + } + } else { + switch (index) { + case 0: + MCLK->APBBMASK.reg |= MCLK_APBBMASK_TCC0; + break; + case 1: + MCLK->APBBMASK.reg |= MCLK_APBBMASK_TCC1; + break; + case 2: + MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC2; + break; + case 3: + MCLK->APBCMASK.reg |= MCLK_APBCMASK_TCC3; + break; + case 4: + MCLK->APBDMASK.reg |= MCLK_APBDMASK_TCC4; + break; + default: + break; + } + } + + // FIXME(tannewt): TC4-TC7 can only have 100mhz inputs. + + hri_gclk_write_PCHCTRL_reg(GCLK, gclk_id, + gclk_index | (1 << GCLK_PCHCTRL_CHEN_Pos)); + #endif + + #ifdef SAMD21 + // Determine the clock slot on the APBC bus. TCC0 is the first and 8 slots in. + uint8_t clock_slot = 8 + index; + // We index TCs starting at zero but in memory they begin at three so we have to add three. + if (is_tc) { + clock_slot += 3; + } + PM->APBCMASK.reg |= 1 << clock_slot; + _gclk_enable_channel(gclk_id, gclk_index); + #endif +} + +void tc_set_enable(Tc* tc, bool enable) { + tc->COUNT16.CTRLA.bit.ENABLE = enable; + #ifdef SAMD21 + while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) { + /* Wait for sync */ + } + #endif + #ifdef SAMD51 + while (tc->COUNT16.SYNCBUSY.bit.ENABLE != 0) { + /* Wait for sync */ + } + #endif +} + +void tc_enable_interrupts(uint8_t tc_index) { + NVIC_DisableIRQ(tc_irq[tc_index]); + NVIC_ClearPendingIRQ(tc_irq[tc_index]); + NVIC_EnableIRQ(tc_irq[tc_index]); +} + +void tc_disable_interrupts(uint8_t tc_index) { + NVIC_DisableIRQ(tc_irq[tc_index]); + NVIC_ClearPendingIRQ(tc_irq[tc_index]); +} + +void tcc_set_enable(Tcc* tcc, bool enable) { + tcc->CTRLA.bit.ENABLE = enable; + while (tcc->SYNCBUSY.bit.ENABLE != 0) { + /* Wait for sync */ + } +} + +void tc_wait_for_sync(Tc* tc) { + #ifdef SAMD21 + while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) {} + #endif + #ifdef SAMD51 + while (tc->COUNT16.SYNCBUSY.reg != 0) {} + #endif +} + +void tc_reset(Tc* tc) { + tc->COUNT16.CTRLA.bit.SWRST = 1; + while (tc->COUNT16.CTRLA.bit.SWRST == 1) { + } +} + +void shared_timer_handler(bool is_tc, uint8_t index) { + // Add calls to interrupt handlers for specific functionality here. + if (is_tc) { + pulseout_interrupt_handler(index); + } +} + +void TCC0_Handler(void) { + shared_timer_handler(false, 0); +} +void TCC1_Handler(void) { + shared_timer_handler(false, 1); +} +void TCC2_Handler(void) { + shared_timer_handler(false, 2); +} +void TC3_Handler(void) { + shared_timer_handler(true, 0); +} +void TC4_Handler(void) { + shared_timer_handler(true, 1); +} +void TC5_Handler(void) { + shared_timer_handler(true, 2); +} +#ifdef TC6 +void TC6_Handler(void) { + shared_timer_handler(true, 3); +} +#endif +#ifdef TC7 +void TC7_Handler(void) { + shared_timer_handler(true, 4); +} +#endif diff --git a/ports/atmel-samd/timers.h b/ports/atmel-samd/timers.h new file mode 100644 index 0000000000..a2ce52f255 --- /dev/null +++ b/ports/atmel-samd/timers.h @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_TIMERS_H +#define MICROPY_INCLUDED_ATMEL_SAMD_TIMERS_H + +#include "include/sam.h" + +#ifdef SAMD21 +const uint8_t tcc_cc_num[3]; +const uint8_t tc_gclk_ids[TC_INST_NUM]; +const uint8_t tcc_gclk_ids[3]; +#endif +#ifdef SAMD51 +static const uint8_t tcc_cc_num[5]; +const uint8_t tc_gclk_ids[TC_INST_NUM]; +const uint8_t tcc_gclk_ids[5]; +#endif +Tc* const tc_insts[TC_INST_NUM]; +Tcc* const tcc_insts[TCC_INST_NUM]; + +void turn_on_clocks(bool is_tc, uint8_t index, uint32_t gclk_index); +void tc_set_enable(Tc* tc, bool enable); +void tcc_set_enable(Tcc* tcc, bool enable); +void tc_wait_for_sync(Tc* tc); +void tc_reset(Tc* tc); + +void tc_enable_interrupts(uint8_t tc_index); +void tc_disable_interrupts(uint8_t tc_index); + +// Handlers +void TCC0_Handler(void); +void TCC1_Handler(void); +void TCC2_Handler(void); +void TC3_Handler(void); +void TC4_Handler(void); +void TC5_Handler(void); +#ifdef TC6 +void TC6_Handler(void); +#endif +#ifdef TC7 +void TC7_Handler(void); +#endif + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_TIMERS_H From c7af17525b077cd474d007b89db3834d27515cfb Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 14 Feb 2018 11:38:52 -0800 Subject: [PATCH 08/13] m4 pulseout works --- main.c | 4 +- ports/atmel-samd/Makefile | 2 +- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 12 +++++- .../atmel-samd/common-hal/pulseio/PulseOut.c | 2 + ports/atmel-samd/timers.c | 39 ++++++++++++++++--- ports/atmel-samd/timers.h | 2 +- 6 files changed, 49 insertions(+), 12 deletions(-) diff --git a/main.c b/main.c index fc70e9c3ec..8c981aee18 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); @@ -156,7 +157,6 @@ bool start_mp(safe_mode_t safe_mode) { reset_port(); reset_board(); - reset_mp(); reset_status_led(); if (result.return_code & PYEXEC_FORCED_EXIT) { @@ -300,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) { @@ -310,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) { diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 041f1d1ad7..29377dc601 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -95,7 +95,7 @@ endif ifeq ($(DEBUG), 1) # Turn on Python modules useful for debugging (e.g. uheap, ustack). CFLAGS += -ggdb - CFLAGS += -flto + #CFLAGS += -flto ifeq ($(CHIP_FAMILY), samd21) CFLAGS += -DENABLE_MICRO_TRACE_BUFFER endif diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index ba534811e2..cbcdeb03c2 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -293,7 +293,11 @@ extern void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, #ifdef SAMD51 Tc* tc = tc_insts[t->index]; while (tc->COUNT16.SYNCBUSY.bit.CC1 != 0) { - // Wait for a previous value to be written. + // 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 @@ -302,7 +306,11 @@ extern void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, 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. + // 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; diff --git a/ports/atmel-samd/common-hal/pulseio/PulseOut.c b/ports/atmel-samd/common-hal/pulseio/PulseOut.c index 35224c8e5d..d0cf8e6661 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.c @@ -185,6 +185,8 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu Tc* tc = tc_insts[pulseout_tc_index]; tc->COUNT16.CC[0].reg = current_compare; + // 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); diff --git a/ports/atmel-samd/timers.c b/ports/atmel-samd/timers.c index 3a1b21edfd..513b1ec95a 100644 --- a/ports/atmel-samd/timers.c +++ b/ports/atmel-samd/timers.c @@ -35,6 +35,10 @@ #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}; @@ -51,7 +55,7 @@ const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC3_GCLK_ID, 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 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, @@ -228,6 +232,13 @@ void shared_timer_handler(bool is_tc, uint8_t index) { } } +#ifdef SAMD51 +#define TC_OFFSET 0 +#endif +#ifdef SAMD21 +#define TC_OFFSET 0 +#endif + void TCC0_Handler(void) { shared_timer_handler(false, 0); } @@ -237,22 +248,38 @@ void TCC1_Handler(void) { void TCC2_Handler(void) { shared_timer_handler(false, 2); } -void TC3_Handler(void) { +// TC0 - TC2 only exist on the SAMD51 +#ifdef TC0 +void TC0_Handler(void) { shared_timer_handler(true, 0); } -void TC4_Handler(void) { +#endif +#ifdef TC1 +void TC1_Handler(void) { shared_timer_handler(true, 1); } -void TC5_Handler(void) { +#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, 3); + shared_timer_handler(true, 6 - TC_OFFSET); } #endif #ifdef TC7 void TC7_Handler(void) { - shared_timer_handler(true, 4); + shared_timer_handler(true, 7 - TC_OFFSET); } #endif diff --git a/ports/atmel-samd/timers.h b/ports/atmel-samd/timers.h index a2ce52f255..a22ec74844 100644 --- a/ports/atmel-samd/timers.h +++ b/ports/atmel-samd/timers.h @@ -34,7 +34,7 @@ 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 tcc_cc_num[5]; const uint8_t tc_gclk_ids[TC_INST_NUM]; const uint8_t tcc_gclk_ids[5]; #endif From 07230f263789df2b7ecaaf8f82415496f9b95de2 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 14 Feb 2018 16:59:04 -0800 Subject: [PATCH 09/13] pulsein compiles but doesn't work --- ports/atmel-samd/common-hal/pulseio/PulseIn.c | 270 +++++++++++++----- ports/atmel-samd/supervisor/port.c | 3 +- 2 files changed, 207 insertions(+), 66 deletions(-) diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c index 5f7ec7a091..d8d3e56c9d 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -28,6 +28,7 @@ #include +#include "atmel_start_pins.h" #include "hal/include/hal_gpio.h" #include "mpconfigport.h" @@ -45,84 +46,94 @@ static uint16_t last_us[EIC_EXTINT_NUM]; void pulsein_reset(void) { for (int i = 0; i < EIC_EXTINT_NUM; i++) { - if (active_pulseins[i] != NULL) { - //extint_chan_disable_callback(i, EXTINT_CALLBACK_TYPE_DETECT); - } 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->CTRLA.bit.SWRST = true; + while (EIC->SYNCBUSY.bit.SWRST != 0) {} + #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->CTRLA.bit.ENABLE = false; + while (EIC->SYNCBUSY.bit.ENABLE != 0) {} + 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->CTRLA.bit.ENABLE = true; + 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. } -//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; - // if (self->first_edge) { - // self->first_edge = false; - // pulsein_set_config(self, false); - // } else { - // uint32_t ms_diff = current_ms - last_ms[self->channel]; - // uint16_t us_diff = current_us - last_us[self->channel]; - // uint32_t total_diff = us_diff; - // if (last_us[self->channel] > current_us) { - // total_diff = 1000 + current_us - last_us[self->channel]; - // if (ms_diff > 1) { - // total_diff += (ms_diff - 1) * 1000; - // } - // } else { - // total_diff += ms_diff * 1000; - // } - // uint16_t duration = 0xffff; - // if (total_diff < duration) { - // duration = total_diff; - // } - // - // uint16_t i = (self->start + self->len) % self->maxlen; - // self->buffer[i] = duration; - // if (self->len < self->maxlen) { - // self->len++; - // } else { - // self->start++; - // } - // } -// last_ms[self->channel] = current_ms; -// last_us[self->channel] = current_us; -// } + uint32_t current_us; + uint64_t current_ms; + current_tick(¤t_ms, ¤t_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); + } else { + uint32_t ms_diff = current_ms - last_ms[self->channel]; + uint16_t us_diff = current_us - last_us[self->channel]; + uint32_t total_diff = us_diff; + if (last_us[self->channel] > current_us) { + total_diff = 1000 + current_us - last_us[self->channel]; + if (ms_diff > 1) { + total_diff += (ms_diff - 1) * 1000; + } + } else { + total_diff += ms_diff * 1000; + } + uint16_t duration = 0xffff; + if (total_diff < duration) { + duration = total_diff; + } + + uint16_t i = (self->start + self->len) % self->maxlen; + self->buffer[i] = duration; + if (self->len < self->maxlen) { + self->len++; + } else { + self->start++; + } + } + last_ms[self->channel] = current_ms; + last_us[self->channel] = current_us; +} void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) { 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->CTRLA.bit.ENABLE == 1 && + ((EIC->INTENSET.bit.EXTINT & mask) != 0 || + (EIC->EVCTRL.bit.EXTINTEO & mask) != 0))) { mp_raise_RuntimeError("EXTINT channel already in use"); } @@ -140,12 +151,39 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, 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->CTRLA.bit.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) { @@ -156,14 +194,44 @@ 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->CTRLA.bit.ENABLE = 0; + #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; + _gclk_disable_channel(EIC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val); + #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, @@ -184,6 +252,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); } @@ -229,3 +303,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.bit.EXTINT & (1 << i)) == 1) { + 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/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index c120b01369..726a48d060 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -46,6 +46,7 @@ #include "common-hal/analogio/AnalogIn.h" #include "common-hal/analogio/AnalogOut.h" #include "common-hal/microcontroller/Pin.h" +#include "common-hal/pulseio/PulseIn.h" #include "common-hal/pulseio/PulseOut.h" #include "common-hal/pulseio/PWMOut.h" #include "tick.h" @@ -206,8 +207,8 @@ void reset_port(void) { // audioout_reset(); // touchin_reset(); // pdmin_reset(); -// pulsein_reset(); // #endif + pulsein_reset(); pulseout_reset(); pwmout_reset(); From fcde138ea358cfdcf8e7c315e9f3b8c33986ae7e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 15 Feb 2018 15:12:58 -0800 Subject: [PATCH 10/13] pulsein works on m4 --- ports/atmel-samd/common-hal/pulseio/PulseIn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c index d8d3e56c9d..72a2a2cef2 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -236,6 +236,9 @@ void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) { 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) { gpio_set_pin_pull_mode(self->pin, GPIO_PULL_OFF); From 538081528de1ae3c052cc114167f05b7ffa9f6de Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 15 Feb 2018 16:04:39 -0800 Subject: [PATCH 11/13] pulsein works on m0 --- ports/atmel-samd/common-hal/pulseio/PulseIn.c | 70 +++++++++++++++---- ports/atmel-samd/timers.c | 2 +- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c index 72a2a2cef2..2dca52913a 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -38,12 +38,51 @@ #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_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_EXTINT_NUM; i++) { active_pulseins[i] = NULL; @@ -54,8 +93,7 @@ void pulsein_reset(void) { NVIC_ClearPendingIRQ(EIC_0_IRQn + i); #endif } - EIC->CTRLA.bit.SWRST = true; - while (EIC->SYNCBUSY.bit.SWRST != 0) {} + eic_reset(); #ifdef SAMD21 NVIC_DisableIRQ(EIC_IRQn); NVIC_ClearPendingIRQ(EIC_IRQn); @@ -71,16 +109,12 @@ static void pulsein_set_config(pulseio_pulsein_obj_t* self, bool first_edge) { } else { sense_setting |= EIC_CONFIG_SENSE0_RISE_Val; } - EIC->CTRLA.bit.ENABLE = false; - while (EIC->SYNCBUSY.bit.ENABLE != 0) {} + 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->CTRLA.bit.ENABLE = true; - 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. + eic_set_enable(true); } static void pulsein_interrupt_handler(uint8_t channel) { @@ -131,9 +165,15 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, } uint32_t mask = 1 << pin->extint_channel; if (active_pulseins[pin->extint_channel] != NULL || - (EIC->CTRLA.bit.ENABLE == 1 && + (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"); } @@ -153,7 +193,7 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* 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->CTRLA.bit.ENABLE == 0) { + if (eic_get_enable() == 0) { #ifdef SAMD51 MCLK->APBAMASK.bit.EIC_ = true; hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, @@ -161,7 +201,7 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, #endif #ifdef SAMD21 - PM->APBAMASK.bit.EIC = true; + PM->APBAMASK.bit.EIC_ = true; _gclk_enable_channel(EIC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val); #endif @@ -216,15 +256,15 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) { #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->CTRLA.bit.ENABLE = 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; - _gclk_disable_channel(EIC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val); + PM->APBAMASK.bit.EIC_ = false; + hri_gclk_write_CLKCTRL_reg(GCLK, GCLK_CLKCTRL_ID(EIC_GCLK_ID)); #endif } } @@ -315,7 +355,7 @@ void external_interrupt_handler(uint8_t channel) { #ifdef SAMD21 void EIC_Handler(void) { for (uint8_t i = 0; i < 16; i++) { - if ((EIC->INTFLAG.bit.EXTINT & (1 << i)) == 1) { + if ((EIC->INTFLAG.vec.EXTINT & (1 << i)) != 0) { external_interrupt_handler(i); } } diff --git a/ports/atmel-samd/timers.c b/ports/atmel-samd/timers.c index 513b1ec95a..7b85c5b261 100644 --- a/ports/atmel-samd/timers.c +++ b/ports/atmel-samd/timers.c @@ -236,7 +236,7 @@ void shared_timer_handler(bool is_tc, uint8_t index) { #define TC_OFFSET 0 #endif #ifdef SAMD21 -#define TC_OFFSET 0 +#define TC_OFFSET 3 #endif void TCC0_Handler(void) { From eb2b41810a8679fffd4a6e149ec84565fea09e95 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 15 Feb 2018 16:12:58 -0800 Subject: [PATCH 12/13] Turn on lto --- ports/atmel-samd/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 29377dc601..041f1d1ad7 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -95,7 +95,7 @@ endif ifeq ($(DEBUG), 1) # Turn on Python modules useful for debugging (e.g. uheap, ustack). CFLAGS += -ggdb - #CFLAGS += -flto + CFLAGS += -flto ifeq ($(CHIP_FAMILY), samd21) CFLAGS += -DENABLE_MICRO_TRACE_BUFFER endif From a2b18b75d4bc68aa93edf67509185cb6e18f596b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 16 Feb 2018 10:05:28 -0800 Subject: [PATCH 13/13] Fix loops and comma style. --- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 2 +- .../atmel-samd/common-hal/pulseio/PulseOut.c | 2 +- ports/atmel-samd/timers.c | 20 +++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index cbcdeb03c2..c68ea69856 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -156,7 +156,7 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, direction = 1; start = 0; } - for (uint8_t i = start; i >= 0 && i < NUM_TIMERS_PER_PIN && timer == NULL; i += direction) { + 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)) { diff --git a/ports/atmel-samd/common-hal/pulseio/PulseOut.c b/ports/atmel-samd/common-hal/pulseio/PulseOut.c index d0cf8e6661..95b0bbee07 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.c @@ -98,7 +98,7 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, if (refcount == 0) { // Find a spare timer. Tc *tc = NULL; - uint8_t index = TC_INST_NUM - 1; + int8_t index = TC_INST_NUM - 1; for (; index >= 0; index--) { if (tc_insts[index]->COUNT16.CTRLA.bit.ENABLE == 0) { tc = tc_insts[index]; diff --git a/ports/atmel-samd/timers.c b/ports/atmel-samd/timers.c index 7b85c5b261..7b5d06cb0c 100644 --- a/ports/atmel-samd/timers.c +++ b/ports/atmel-samd/timers.c @@ -46,10 +46,10 @@ 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 + TC6_GCLK_ID, #endif #ifdef TC7_GCLK_ID - , TC7_GCLK_ID + TC7_GCLK_ID, #endif }; const uint8_t tcc_gclk_ids[3] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID}; @@ -59,18 +59,18 @@ 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 + TC3_GCLK_ID, #ifdef TC4_GCLK_ID - , TC4_GCLK_ID + TC4_GCLK_ID, #endif #ifdef TC5_GCLK_ID - , TC5_GCLK_ID + TC5_GCLK_ID, #endif #ifdef TC6_GCLK_ID - , TC6_GCLK_ID + TC6_GCLK_ID, #endif #ifdef TC7_GCLK_ID - , 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, @@ -91,12 +91,12 @@ IRQn_Type const tc_irq[TC_INST_NUM] = { #endif TC3_IRQn, TC4_IRQn, - TC5_IRQn + TC5_IRQn, #ifdef TC6 - , TC6_IRQn + TC6_IRQn, #endif #ifdef TC7 - , TC7_IRQn + TC7_IRQn, #endif };