Fix SAMD51 pulsein
This commit is contained in:
parent
7100d5e485
commit
76ca13b6ed
@ -34,14 +34,32 @@
|
||||
#include "background.h"
|
||||
#include "eic_handler.h"
|
||||
#include "mpconfigport.h"
|
||||
#include "timer_handler.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/runtime.h"
|
||||
#include "samd/external_interrupts.h"
|
||||
#include "samd/pins.h"
|
||||
#include "samd/timers.h"
|
||||
#include "shared-bindings/microcontroller/__init__.h"
|
||||
#include "shared-bindings/pulseio/PulseIn.h"
|
||||
#include "supervisor/shared/translate.h"
|
||||
|
||||
// This timer is shared amongst all PulseIn objects as a higher resolution clock.
|
||||
static uint8_t refcount = 0;
|
||||
static uint8_t pulsein_tc_index = 0xff;
|
||||
|
||||
static uint32_t overflow_count = 0;
|
||||
|
||||
void pulsein_timer_interrupt_handler(uint8_t index) {
|
||||
if (index != pulsein_tc_index) return;
|
||||
overflow_count++;
|
||||
Tc* tc = tc_insts[index];
|
||||
if (!tc->COUNT16.INTFLAG.bit.OVF) return;
|
||||
|
||||
// Clear the interrupt bit.
|
||||
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF;
|
||||
}
|
||||
|
||||
static void pulsein_set_config(pulseio_pulsein_obj_t* self, bool first_edge) {
|
||||
uint32_t sense_setting;
|
||||
if (!first_edge) {
|
||||
@ -59,13 +77,10 @@ static void pulsein_set_config(pulseio_pulsein_obj_t* self, bool first_edge) {
|
||||
|
||||
void pulsein_interrupt_handler(uint8_t channel) {
|
||||
// Grab the current time first.
|
||||
uint32_t current_us = 0;
|
||||
uint64_t current_ms = 0;
|
||||
// current_tick(¤t_ms, ¤t_us);
|
||||
uint32_t current_overflow = overflow_count;
|
||||
Tc* tc = tc_insts[pulsein_tc_index];
|
||||
uint32_t current_count = tc->COUNT16.COUNT.reg;
|
||||
|
||||
// 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 = get_eic_channel_data(channel);
|
||||
if (!background_tasks_ok() || self->errored_too_fast) {
|
||||
self->errored_too_fast = true;
|
||||
@ -76,17 +91,11 @@ void pulsein_interrupt_handler(uint8_t channel) {
|
||||
self->first_edge = false;
|
||||
pulsein_set_config(self, false);
|
||||
} else {
|
||||
uint32_t ms_diff = current_ms - self->last_ms;
|
||||
uint16_t us_diff = current_us - self->last_us;
|
||||
uint32_t total_diff = us_diff;
|
||||
if (self->last_us > current_us) {
|
||||
total_diff = 1000 + current_us - self->last_us;
|
||||
if (ms_diff > 1) {
|
||||
total_diff += (ms_diff - 1) * 1000;
|
||||
}
|
||||
} else {
|
||||
total_diff += ms_diff * 1000;
|
||||
}
|
||||
uint32_t total_diff = current_count + 0xffff * (current_overflow - self->last_overflow) - self->last_count;
|
||||
#ifdef SAMD21
|
||||
total_diff /= 3;
|
||||
#endif
|
||||
// Cap duration at 16 bits.
|
||||
uint16_t duration = 0xffff;
|
||||
if (total_diff < duration) {
|
||||
duration = total_diff;
|
||||
@ -100,8 +109,8 @@ void pulsein_interrupt_handler(uint8_t channel) {
|
||||
self->start++;
|
||||
}
|
||||
}
|
||||
self->last_ms = current_ms;
|
||||
self->last_us = current_us;
|
||||
self->last_overflow = current_overflow;
|
||||
self->last_count = current_count;
|
||||
}
|
||||
|
||||
void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self,
|
||||
@ -124,10 +133,57 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self,
|
||||
self->start = 0;
|
||||
self->len = 0;
|
||||
self->first_edge = true;
|
||||
self->last_us = 0;
|
||||
self->last_ms = 0;
|
||||
self->last_overflow = 0;
|
||||
self->last_count = 0;
|
||||
self->errored_too_fast = false;
|
||||
|
||||
if (refcount == 0) {
|
||||
// Find a spare timer.
|
||||
Tc *tc = NULL;
|
||||
int8_t index = TC_INST_NUM - 1;
|
||||
for (; index >= 0; index--) {
|
||||
if (tc_insts[index]->COUNT16.CTRLA.bit.ENABLE == 0) {
|
||||
tc = tc_insts[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tc == NULL) {
|
||||
mp_raise_RuntimeError(translate("All timers in use"));
|
||||
}
|
||||
|
||||
pulsein_tc_index = index;
|
||||
|
||||
set_timer_handler(true, index, TC_HANDLER_PULSEIN);
|
||||
#ifdef SAMD21
|
||||
// We use GCLK0 for SAMD21 which is 48mhz. We prescale it to 3mhz.
|
||||
turn_on_clocks(true, index, 0);
|
||||
#endif
|
||||
#ifdef SAMD51
|
||||
// We use GCLK5 for SAMD51 because it runs at 2mhz and we can use it for a 1mhz clock,
|
||||
// 1us per tick.
|
||||
turn_on_clocks(true, index, 5);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SAMD21
|
||||
tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 |
|
||||
TC_CTRLA_PRESCALER_DIV16 |
|
||||
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_DIV2;
|
||||
tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_NFRQ;
|
||||
#endif
|
||||
|
||||
tc_set_enable(tc, true);
|
||||
tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER;
|
||||
|
||||
overflow_count = 0;
|
||||
}
|
||||
refcount++;
|
||||
|
||||
set_eic_channel_data(pin->extint_channel, (void*) self);
|
||||
|
||||
// Check to see if the EIC is enabled and start it up if its not.'
|
||||
@ -156,6 +212,12 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) {
|
||||
set_eic_handler(self->channel, EIC_HANDLER_NO_INTERRUPT);
|
||||
turn_off_eic_channel(self->channel);
|
||||
reset_pin_number(self->pin);
|
||||
|
||||
refcount--;
|
||||
if (refcount == 0) {
|
||||
tc_reset(tc_insts[pulsein_tc_index]);
|
||||
pulsein_tc_index = 0xff;
|
||||
}
|
||||
self->pin = NO_PIN;
|
||||
}
|
||||
|
||||
@ -183,8 +245,8 @@ void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self,
|
||||
|
||||
// Reconfigure the pin and make sure its set to detect the first edge.
|
||||
self->first_edge = true;
|
||||
self->last_ms = 0;
|
||||
self->last_us = 0;
|
||||
self->last_overflow = 0;
|
||||
self->last_count = 0;
|
||||
gpio_set_pin_function(self->pin, GPIO_PIN_FUNCTION_A);
|
||||
uint32_t mask = 1 << self->channel;
|
||||
// Clear previous interrupt state and re-enable it.
|
||||
|
@ -41,13 +41,14 @@ typedef struct {
|
||||
volatile uint16_t start;
|
||||
volatile uint16_t len;
|
||||
volatile bool first_edge;
|
||||
volatile uint64_t last_ms;
|
||||
volatile uint16_t last_us;
|
||||
volatile uint32_t last_overflow;
|
||||
volatile uint16_t last_count;
|
||||
volatile bool errored_too_fast;
|
||||
} pulseio_pulsein_obj_t;
|
||||
|
||||
void pulsein_reset(void);
|
||||
|
||||
void pulsein_interrupt_handler(uint8_t channel);
|
||||
void pulsein_timer_interrupt_handler(uint8_t index);
|
||||
|
||||
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEIN_H
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "timer_handler.h"
|
||||
|
||||
#include "common-hal/pulseio/PulseIn.h"
|
||||
#include "common-hal/pulseio/PulseOut.h"
|
||||
#include "shared-module/_pew/PewPew.h"
|
||||
#include "common-hal/frequencyio/FrequencyIn.h"
|
||||
@ -47,6 +48,11 @@ void shared_timer_handler(bool is_tc, uint8_t index) {
|
||||
if (is_tc) {
|
||||
uint8_t handler = tc_handler[index];
|
||||
switch(handler) {
|
||||
case TC_HANDLER_PULSEIN:
|
||||
#if CIRCUITPY_PULSEIO
|
||||
pulsein_timer_interrupt_handler(index);
|
||||
#endif
|
||||
break;
|
||||
case TC_HANDLER_PULSEOUT:
|
||||
#if CIRCUITPY_PULSEIO
|
||||
pulseout_interrupt_handler(index);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#define TC_HANDLER_PULSEOUT 0x1
|
||||
#define TC_HANDLER_PEW 0x2
|
||||
#define TC_HANDLER_FREQUENCYIN 0x3
|
||||
#define TC_HANDLER_PULSEIN 0x4
|
||||
|
||||
void set_timer_handler(bool is_tc, uint8_t index, uint8_t timer_handler);
|
||||
void shared_timer_handler(bool is_tc, uint8_t index);
|
||||
|
@ -88,14 +88,7 @@ static void _pulsein_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action
|
||||
self->first_edge = false;
|
||||
}
|
||||
}else {
|
||||
// Wrapped around a number of times.
|
||||
uint32_t total_diff = 0xffff;
|
||||
// Wrapped around once so
|
||||
if (self->last_overflow == current_overflow - 1) {
|
||||
total_diff = current_count + (0xffffffff - self->last_count);
|
||||
} else if (self->last_overflow == current_overflow) {
|
||||
total_diff = current_count - self->last_count;
|
||||
}
|
||||
uint32_t total_diff = current_count + 0xffff * (current_overflow - self->last_overflow) - self->last_count;
|
||||
|
||||
// Cap duration at 16 bits.
|
||||
uint16_t duration = 0xffff;
|
||||
|
Loading…
x
Reference in New Issue
Block a user