summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott.shawcroft@gmail.com>2018-06-05 12:38:31 -0700
committerScott Shawcroft <scott.shawcroft@gmail.com>2018-06-08 12:56:32 -0700
commit2fbab8067afcb008bc92d9c155dfef360fbc10f9 (patch)
tree137d0ec0459ae562fa411fbccbfea3ec05bd3256
parentc01ce175bb63aab3f44a3efb31bcfd57a58b22bd (diff)
Prevent freezing USB during high frequency PulseIn.
We now track the last time the background task ran and bail on the PulseIn if it starves the background work. In practice, this happens after the numbers from pulsein are no longer accurate. This also adjusts interrupt priorities so most are the lowest level except for the tick and USB interrupts. Fixes #516 and #876
-rw-r--r--ports/atmel-samd/background.c8
-rw-r--r--ports/atmel-samd/background.h3
-rw-r--r--ports/atmel-samd/common-hal/microcontroller/__init__.c14
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PulseIn.c16
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PulseIn.h1
-rw-r--r--ports/atmel-samd/tick.c7
-rw-r--r--shared-bindings/pulseio/PulseIn.c23
-rw-r--r--shared-bindings/pulseio/PulseIn.h1
8 files changed, 62 insertions, 11 deletions
diff --git a/ports/atmel-samd/background.c b/ports/atmel-samd/background.c
index 92648f42e..4cba7a110 100644
--- a/ports/atmel-samd/background.c
+++ b/ports/atmel-samd/background.c
@@ -26,11 +26,19 @@
#include "background.h"
#include "audio_dma.h"
+#include "tick.h"
#include "usb.h"
#include "usb_mass_storage.h"
+volatile uint64_t last_finished_tick = 0;
+
void run_background_tasks(void) {
audio_dma_background();
usb_msc_background();
usb_cdc_background();
+ last_finished_tick = ticks_ms;
+}
+
+bool background_tasks_ok(void) {
+ return ticks_ms - last_finished_tick < 1000;
}
diff --git a/ports/atmel-samd/background.h b/ports/atmel-samd/background.h
index f7fb10a1f..e841049a4 100644
--- a/ports/atmel-samd/background.h
+++ b/ports/atmel-samd/background.h
@@ -27,6 +27,9 @@
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H
#define MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H
+#include <stdbool.h>
+
void run_background_tasks(void);
+bool background_tasks_ok(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H
diff --git a/ports/atmel-samd/common-hal/microcontroller/__init__.c b/ports/atmel-samd/common-hal/microcontroller/__init__.c
index c57b6939c..ad4d81ddd 100644
--- a/ports/atmel-samd/common-hal/microcontroller/__init__.c
+++ b/ports/atmel-samd/common-hal/microcontroller/__init__.c
@@ -40,18 +40,10 @@ void common_hal_mcu_delay_us(uint32_t delay) {
mp_hal_delay_us(delay);
}
-// Interrupt flags that will be saved and restored during disable/Enable
-// interrupt functions below.
-
-// ASF4's interrupt disable doesn't handle duplicate calls
-volatile uint32_t interrupt_flags;
volatile uint32_t nesting_count = 0;
void common_hal_mcu_disable_interrupts(void) {
- if (nesting_count == 0) {
- interrupt_flags = __get_PRIMASK();
- __disable_irq();
- __DMB();
- }
+ __disable_irq();
+ __DMB();
nesting_count++;
}
@@ -66,7 +58,7 @@ void common_hal_mcu_enable_interrupts(void) {
return;
}
__DMB();
- __set_PRIMASK(interrupt_flags);
+ __enable_irq();
}
extern uint32_t _ezero;
diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c
index 99a60a829..dee32bbec 100644
--- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c
+++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c
@@ -31,6 +31,7 @@
#include "atmel_start_pins.h"
#include "hal/include/hal_gpio.h"
+#include "background.h"
#include "mpconfigport.h"
#include "py/gc.h"
#include "py/runtime.h"
@@ -60,10 +61,16 @@ void pulsein_interrupt_handler(uint8_t channel) {
uint32_t current_us;
uint64_t current_ms;
current_tick(&current_ms, &current_us);
+
// current_tick gives us the remaining us until the next tick but we want the number since the
// last ms.
current_us = 1000 - current_us;
pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
+ if (!background_tasks_ok() || self->errored_too_fast) {
+ self->errored_too_fast = true;
+ common_hal_pulseio_pulsein_pause(self);
+ return;
+ }
if (self->first_edge) {
self->first_edge = false;
pulsein_set_config(self, false);
@@ -118,6 +125,7 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self,
self->first_edge = true;
self->last_us = 0;
self->last_ms = 0;
+ self->errored_too_fast = 0;
set_eic_channel_data(pin->extint_channel, (void*) self);
@@ -157,6 +165,9 @@ void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self,
// Make sure we're paused.
common_hal_pulseio_pulsein_pause(self);
+ // Reset erroring
+ self->errored_too_fast = false;
+
// Send the trigger pulse.
if (trigger_duration > 0) {
gpio_set_pin_pull_mode(self->pin, GPIO_PULL_OFF);
@@ -207,6 +218,11 @@ uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) {
return self->len;
}
+bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t* self) {
+ uint32_t mask = 1 << self->channel;
+ return (EIC->INTENSET.reg & (mask << EIC_INTENSET_EXTINT_Pos)) == 0;
+}
+
uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self,
int16_t index) {
common_hal_mcu_disable_interrupts();
diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.h b/ports/atmel-samd/common-hal/pulseio/PulseIn.h
index 3d79b50c3..f5326d9e5 100644
--- a/ports/atmel-samd/common-hal/pulseio/PulseIn.h
+++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.h
@@ -43,6 +43,7 @@ typedef struct {
volatile bool first_edge;
volatile uint64_t last_ms;
volatile uint16_t last_us;
+ volatile bool errored_too_fast;
} pulseio_pulsein_obj_t;
void pulsein_reset(void);
diff --git a/ports/atmel-samd/tick.c b/ports/atmel-samd/tick.c
index 6cd7c7833..81841c4af 100644
--- a/ports/atmel-samd/tick.c
+++ b/ports/atmel-samd/tick.c
@@ -60,6 +60,13 @@ void tick_init() {
uint32_t ticks_per_ms = common_hal_mcu_processor_get_frequency() / 1000;
SysTick_Config(ticks_per_ms-1);
NVIC_EnableIRQ(SysTick_IRQn);
+ // Set all peripheral interrupt priorities to the lowest priority by default.
+ for (uint16_t i = 0; i < PERIPH_COUNT_IRQn; i++) {
+ NVIC_SetPriority(i, (1UL << __NVIC_PRIO_BITS) - 1UL);
+ }
+ // Bump up the systick interrupt.
+ NVIC_SetPriority(SysTick_IRQn, 1);
+ NVIC_SetPriority(USB_IRQn, 1);
}
void tick_delay(uint32_t us) {
diff --git a/shared-bindings/pulseio/PulseIn.c b/shared-bindings/pulseio/PulseIn.c
index 736441c74..862dbd99d 100644
--- a/shared-bindings/pulseio/PulseIn.c
+++ b/shared-bindings/pulseio/PulseIn.c
@@ -219,6 +219,26 @@ const mp_obj_property_t pulseio_pulsein_maxlen_obj = {
(mp_obj_t)&mp_const_none_obj},
};
+//| .. attribute:: paused
+//|
+//| True when pulse capture is paused as a result of :py:func:`pause` or an error during capture
+//| such as a signal that is too fast.
+//|
+STATIC mp_obj_t pulseio_pulsein_obj_get_paused(mp_obj_t self_in) {
+ pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ raise_error_if_deinited(common_hal_pulseio_pulsein_deinited(self));
+
+ return mp_obj_new_bool(common_hal_pulseio_pulsein_get_paused(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_get_paused_obj, pulseio_pulsein_obj_get_paused);
+
+const mp_obj_property_t pulseio_pulsein_paused_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&pulseio_pulsein_get_paused_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
//| .. method:: __len__()
//|
//| Returns the current pulse length
@@ -285,7 +305,10 @@ STATIC const mp_rom_map_elem_t pulseio_pulsein_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&pulseio_pulsein_resume_obj) },
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&pulseio_pulsein_clear_obj) },
{ MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&pulseio_pulsein_popleft_obj) },
+
+ // Properties
{ MP_ROM_QSTR(MP_QSTR_maxlen), MP_ROM_PTR(&pulseio_pulsein_maxlen_obj) },
+ { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&pulseio_pulsein_paused_obj) },
};
STATIC MP_DEFINE_CONST_DICT(pulseio_pulsein_locals_dict, pulseio_pulsein_locals_dict_table);
diff --git a/shared-bindings/pulseio/PulseIn.h b/shared-bindings/pulseio/PulseIn.h
index 88b6f356e..e28a3c2df 100644
--- a/shared-bindings/pulseio/PulseIn.h
+++ b/shared-bindings/pulseio/PulseIn.h
@@ -41,6 +41,7 @@ extern void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, uint1
extern void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t* self);
extern uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t* self);
extern uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t* self);
+extern bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t* self);
extern uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self);
extern uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self, int16_t index);