Merge pull request #5100 from tannewt/fix_cp_irremote
Switch SAMD21 ticks to PER event
This commit is contained in:
commit
d294692c4e
@ -149,7 +149,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
|||||||
mp_hal_stdout_tx_strn("\x04", 1);
|
mp_hal_stdout_tx_strn("\x04", 1);
|
||||||
}
|
}
|
||||||
// check for SystemExit
|
// check for SystemExit
|
||||||
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
|
if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
|
||||||
// at the moment, the value of SystemExit is unused
|
// at the moment, the value of SystemExit is unused
|
||||||
ret = pyexec_system_exit;
|
ret = pyexec_system_exit;
|
||||||
#if CIRCUITPY_ALARM
|
#if CIRCUITPY_ALARM
|
||||||
|
@ -273,13 +273,13 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
|
|||||||
|
|
||||||
#ifdef SAM_D5X_E5X
|
#ifdef SAM_D5X_E5X
|
||||||
int irq = dma->event_channel < 4 ? EVSYS_0_IRQn + dma->event_channel : EVSYS_4_IRQn;
|
int irq = dma->event_channel < 4 ? EVSYS_0_IRQn + dma->event_channel : EVSYS_4_IRQn;
|
||||||
|
// Only disable and clear on SAMD51 because the SAMD21 shares EVSYS with ticks.
|
||||||
|
NVIC_DisableIRQ(irq);
|
||||||
|
NVIC_ClearPendingIRQ(irq);
|
||||||
#else
|
#else
|
||||||
int irq = EVSYS_IRQn;
|
int irq = EVSYS_IRQn;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NVIC_DisableIRQ(irq);
|
|
||||||
NVIC_ClearPendingIRQ(irq);
|
|
||||||
|
|
||||||
DmacDescriptor *first_descriptor = dma_descriptor(dma_channel);
|
DmacDescriptor *first_descriptor = dma_descriptor(dma_channel);
|
||||||
setup_audio_descriptor(first_descriptor, dma->beat_size, output_spacing, output_register_address);
|
setup_audio_descriptor(first_descriptor, dma->beat_size, output_spacing, output_register_address);
|
||||||
if (single_buffer) {
|
if (single_buffer) {
|
||||||
@ -374,7 +374,7 @@ STATIC void dma_callback_fun(void *arg) {
|
|||||||
audio_dma_load_next_block(dma);
|
audio_dma_load_next_block(dma);
|
||||||
}
|
}
|
||||||
|
|
||||||
void evsyshandler_common(void) {
|
void audio_evsys_handler(void) {
|
||||||
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
|
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
|
||||||
audio_dma_t *dma = audio_dma_state[i];
|
audio_dma_t *dma = audio_dma_state[i];
|
||||||
if (dma == NULL) {
|
if (dma == NULL) {
|
||||||
@ -388,26 +388,4 @@ void evsyshandler_common(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SAM_D5X_E5X
|
|
||||||
void EVSYS_0_Handler(void) {
|
|
||||||
evsyshandler_common();
|
|
||||||
}
|
|
||||||
void EVSYS_1_Handler(void) {
|
|
||||||
evsyshandler_common();
|
|
||||||
}
|
|
||||||
void EVSYS_2_Handler(void) {
|
|
||||||
evsyshandler_common();
|
|
||||||
}
|
|
||||||
void EVSYS_3_Handler(void) {
|
|
||||||
evsyshandler_common();
|
|
||||||
}
|
|
||||||
void EVSYS_4_Handler(void) {
|
|
||||||
evsyshandler_common();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void EVSYS_Handler(void) {
|
|
||||||
evsyshandler_common();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -99,4 +99,6 @@ void audio_dma_background(void);
|
|||||||
|
|
||||||
uint8_t find_sync_event_channel_raise(void);
|
uint8_t find_sync_event_channel_raise(void);
|
||||||
|
|
||||||
|
void audio_evsys_handler(void);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_ATMEL_SAMD_AUDIO_DMA_H
|
#endif // MICROPY_INCLUDED_ATMEL_SAMD_AUDIO_DMA_H
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define MICROPY_HW_MCU_NAME "samd21e18"
|
#define MICROPY_HW_MCU_NAME "samd21e18"
|
||||||
|
|
||||||
#define MICROPY_HW_NEOPIXEL (&pin_PA15)
|
#define MICROPY_HW_NEOPIXEL (&pin_PA15)
|
||||||
|
#define MICROPY_HW_NEOPIXEL_COUNT (2)
|
||||||
|
|
||||||
#define IGNORE_PIN_PA01 1
|
#define IGNORE_PIN_PA01 1
|
||||||
#define IGNORE_PIN_PA02 1
|
#define IGNORE_PIN_PA02 1
|
||||||
|
@ -14,6 +14,7 @@ CIRCUITPY_FULL_BUILD = 0
|
|||||||
CIRCUITPY_ANALOGIO = 0
|
CIRCUITPY_ANALOGIO = 0
|
||||||
CIRCUITPY_AUDIOCORE = 0
|
CIRCUITPY_AUDIOCORE = 0
|
||||||
CIRCUITPY_BUSIO_SPI = 0
|
CIRCUITPY_BUSIO_SPI = 0
|
||||||
|
CIRCUITPY_BUSIO_UART = 0
|
||||||
CIRCUITPY_PULSEIO = 0
|
CIRCUITPY_PULSEIO = 0
|
||||||
CIRCUITPY_PWMIO = 0
|
CIRCUITPY_PWMIO = 0
|
||||||
CIRCUITPY_ROTARYIO = 0
|
CIRCUITPY_ROTARYIO = 0
|
||||||
|
@ -16,3 +16,16 @@
|
|||||||
// USB is always used internally so skip the pin objects for it.
|
// USB is always used internally so skip the pin objects for it.
|
||||||
#define IGNORE_PIN_PA24 1
|
#define IGNORE_PIN_PA24 1
|
||||||
#define IGNORE_PIN_PA25 1
|
#define IGNORE_PIN_PA25 1
|
||||||
|
// USD ID
|
||||||
|
#define IGNORE_PIN_PA18 1
|
||||||
|
|
||||||
|
// Hooked to the external crystal
|
||||||
|
#define IGNORE_PIN_PA00 1
|
||||||
|
#define IGNORE_PIN_PA01 1
|
||||||
|
|
||||||
|
// SWD only
|
||||||
|
#define IGNORE_PIN_PA30 1
|
||||||
|
#define IGNORE_PIN_PA31 1
|
||||||
|
|
||||||
|
// Not connected
|
||||||
|
#define IGNORE_PIN_PA28 1
|
||||||
|
@ -16,3 +16,11 @@
|
|||||||
// USB is always used internally so skip the pin objects for it.
|
// USB is always used internally so skip the pin objects for it.
|
||||||
#define IGNORE_PIN_PA24 1
|
#define IGNORE_PIN_PA24 1
|
||||||
#define IGNORE_PIN_PA25 1
|
#define IGNORE_PIN_PA25 1
|
||||||
|
|
||||||
|
// Not connected
|
||||||
|
#define IGNORE_PIN_PA00 1
|
||||||
|
#define IGNORE_PIN_PA01 1
|
||||||
|
|
||||||
|
// SWD only
|
||||||
|
#define IGNORE_PIN_PA30 1
|
||||||
|
#define IGNORE_PIN_PA31 1
|
||||||
|
@ -272,6 +272,9 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t *self) {
|
|||||||
void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t *self) {
|
void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t *self) {
|
||||||
uint32_t mask = 1 << self->channel;
|
uint32_t mask = 1 << self->channel;
|
||||||
EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos;
|
EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos;
|
||||||
|
#ifdef SAMD21
|
||||||
|
rtc_end_pulse();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t *self,
|
void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t *self,
|
||||||
@ -299,6 +302,9 @@ void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t *self,
|
|||||||
EIC->INTFLAG.reg = mask << EIC_INTFLAG_EXTINT_Pos;
|
EIC->INTFLAG.reg = mask << EIC_INTFLAG_EXTINT_Pos;
|
||||||
EIC->INTENSET.reg = mask << EIC_INTENSET_EXTINT_Pos;
|
EIC->INTENSET.reg = mask << EIC_INTENSET_EXTINT_Pos;
|
||||||
|
|
||||||
|
#ifdef SAMD21
|
||||||
|
rtc_start_pulse();
|
||||||
|
#endif
|
||||||
pulsein_set_config(self, true);
|
pulsein_set_config(self, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,26 +91,19 @@
|
|||||||
#if CIRCUITPY_PEW
|
#if CIRCUITPY_PEW
|
||||||
#include "common-hal/_pew/PewPew.h"
|
#include "common-hal/_pew/PewPew.h"
|
||||||
#endif
|
#endif
|
||||||
volatile bool hold_interrupt = false;
|
static volatile bool sleep_ok = true;
|
||||||
#ifdef SAMD21
|
#ifdef SAMD21
|
||||||
static void rtc_set_continuous(bool continuous) {
|
static uint8_t _tick_event_channel = 0;
|
||||||
while (RTC->MODE0.STATUS.bit.SYNCBUSY) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
RTC->MODE0.READREQ.reg = (continuous ? RTC_READREQ_RCONT : 0) | 0x0010;
|
|
||||||
while (RTC->MODE0.STATUS.bit.SYNCBUSY) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Sleeping requires a register write that can stall interrupt handling. Turning
|
||||||
|
// off sleeps allows for more accurate interrupt timing. (Python still thinks
|
||||||
|
// it is sleeping though.)
|
||||||
void rtc_start_pulse(void) {
|
void rtc_start_pulse(void) {
|
||||||
rtc_set_continuous(true);
|
sleep_ok = false;
|
||||||
hold_interrupt = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_end_pulse(void) {
|
void rtc_end_pulse(void) {
|
||||||
hold_interrupt = false;
|
sleep_ok = true;
|
||||||
rtc_set_continuous(false);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -161,6 +154,20 @@ static void save_usb_clock_calibration(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void rtc_continuous_mode(void) {
|
||||||
|
#ifdef SAMD21
|
||||||
|
while (RTC->MODE0.STATUS.bit.SYNCBUSY) {
|
||||||
|
}
|
||||||
|
RTC->MODE0.READREQ.reg = RTC_READREQ_RCONT | 0x0010;
|
||||||
|
while (RTC->MODE0.STATUS.bit.SYNCBUSY) {
|
||||||
|
}
|
||||||
|
// Do the first request and wait for it.
|
||||||
|
RTC->MODE0.READREQ.reg = RTC_READREQ_RREQ | RTC_READREQ_RCONT | 0x0010;
|
||||||
|
while (RTC->MODE0.STATUS.bit.SYNCBUSY) {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void rtc_init(void) {
|
static void rtc_init(void) {
|
||||||
#ifdef SAMD21
|
#ifdef SAMD21
|
||||||
_gclk_enable_channel(RTC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK2_Val);
|
_gclk_enable_channel(RTC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK2_Val);
|
||||||
@ -168,9 +175,17 @@ static void rtc_init(void) {
|
|||||||
while (RTC->MODE0.CTRL.bit.SWRST != 0) {
|
while (RTC->MODE0.CTRL.bit.SWRST != 0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Turn on periodic events to use as tick. We control whether it interrupts
|
||||||
|
// us with the EVSYS INTEN register.
|
||||||
|
RTC->MODE0.EVCTRL.reg = RTC_MODE0_EVCTRL_PEREO2;
|
||||||
|
|
||||||
RTC->MODE0.CTRL.reg = RTC_MODE0_CTRL_ENABLE |
|
RTC->MODE0.CTRL.reg = RTC_MODE0_CTRL_ENABLE |
|
||||||
RTC_MODE0_CTRL_MODE_COUNT32 |
|
RTC_MODE0_CTRL_MODE_COUNT32 |
|
||||||
RTC_MODE0_CTRL_PRESCALER_DIV2;
|
RTC_MODE0_CTRL_PRESCALER_DIV2;
|
||||||
|
|
||||||
|
// Turn on continuous sync of the count register. This will speed up all
|
||||||
|
// tick reads.
|
||||||
|
rtc_continuous_mode();
|
||||||
#endif
|
#endif
|
||||||
#ifdef SAM_D5X_E5X
|
#ifdef SAM_D5X_E5X
|
||||||
hri_mclk_set_APBAMASK_RTC_bit(MCLK);
|
hri_mclk_set_APBAMASK_RTC_bit(MCLK);
|
||||||
@ -363,6 +378,9 @@ void reset_port(void) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
reset_event_system();
|
reset_event_system();
|
||||||
|
#ifdef SAMD21
|
||||||
|
_tick_event_channel = EVSYS_SYNCH_NUM;
|
||||||
|
#endif
|
||||||
|
|
||||||
reset_all_pins();
|
reset_all_pins();
|
||||||
|
|
||||||
@ -430,21 +448,14 @@ uint32_t port_get_saved_word(void) {
|
|||||||
// TODO: Move this to an RTC backup register so we can preserve it when only the BACKUP power domain
|
// TODO: Move this to an RTC backup register so we can preserve it when only the BACKUP power domain
|
||||||
// is enabled.
|
// is enabled.
|
||||||
static volatile uint64_t overflowed_ticks = 0;
|
static volatile uint64_t overflowed_ticks = 0;
|
||||||
#ifdef SAMD21
|
|
||||||
static volatile bool _ticks_enabled = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static uint32_t _get_count(uint64_t *overflow_count) {
|
static uint32_t _get_count(uint64_t *overflow_count) {
|
||||||
#ifdef SAM_D5X_E5X
|
#ifdef SAM_D5X_E5X
|
||||||
while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COUNTSYNC | RTC_MODE0_SYNCBUSY_COUNT)) != 0) {
|
while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COUNTSYNC | RTC_MODE0_SYNCBUSY_COUNT)) != 0) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef SAMD21
|
// SAMD21 does continuous sync so we don't need to wait here.
|
||||||
// Request a read so we don't stall the bus later. See section 14.3.1.5 Read Request
|
|
||||||
RTC->MODE0.READREQ.reg = RTC_READREQ_RREQ | 0x0010;
|
|
||||||
while (RTC->MODE0.STATUS.bit.SYNCBUSY != 0) {
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// Disable interrupts so we can grab the count and the overflow.
|
// Disable interrupts so we can grab the count and the overflow.
|
||||||
common_hal_mcu_disable_interrupts();
|
common_hal_mcu_disable_interrupts();
|
||||||
uint32_t count = RTC->MODE0.COUNT.reg;
|
uint32_t count = RTC->MODE0.COUNT.reg;
|
||||||
@ -458,29 +469,6 @@ static uint32_t _get_count(uint64_t *overflow_count) {
|
|||||||
|
|
||||||
volatile bool _woken_up;
|
volatile bool _woken_up;
|
||||||
|
|
||||||
static void _port_interrupt_after_ticks(uint32_t ticks) {
|
|
||||||
uint32_t current_ticks = _get_count(NULL);
|
|
||||||
if (ticks > 1 << 28) {
|
|
||||||
// We'll interrupt sooner with an overflow.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifdef SAMD21
|
|
||||||
if (hold_interrupt) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
uint32_t target = current_ticks + (ticks << 4);
|
|
||||||
RTC->MODE0.COMP[0].reg = target;
|
|
||||||
#ifdef SAM_D5X_E5X
|
|
||||||
while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP0)) != 0) {
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
|
|
||||||
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0;
|
|
||||||
current_ticks = _get_count(NULL);
|
|
||||||
_woken_up = current_ticks >= target;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RTC_Handler(void) {
|
void RTC_Handler(void) {
|
||||||
uint32_t intflag = RTC->MODE0.INTFLAG.reg;
|
uint32_t intflag = RTC->MODE0.INTFLAG.reg;
|
||||||
if (intflag & RTC_MODE0_INTFLAG_OVF) {
|
if (intflag & RTC_MODE0_INTFLAG_OVF) {
|
||||||
@ -497,19 +485,10 @@ void RTC_Handler(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (intflag & RTC_MODE0_INTFLAG_CMP0) {
|
if (intflag & RTC_MODE0_INTFLAG_CMP0) {
|
||||||
// Clear the interrupt because we may have hit a sleep and _ticks_enabled
|
// Clear the interrupt because we may have hit a sleep
|
||||||
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
|
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
|
||||||
_woken_up = true;
|
_woken_up = true;
|
||||||
#ifdef SAMD21
|
// SAMD21 ticks are handled by EVSYS
|
||||||
if (_ticks_enabled) {
|
|
||||||
// Do things common to all ports when the tick occurs.
|
|
||||||
supervisor_tick();
|
|
||||||
// Check _ticks_enabled again because a tick handler may have turned it off.
|
|
||||||
if (_ticks_enabled) {
|
|
||||||
_port_interrupt_after_ticks(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef SAM_D5X_E5X
|
#ifdef SAM_D5X_E5X
|
||||||
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0;
|
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0;
|
||||||
#endif
|
#endif
|
||||||
@ -526,6 +505,39 @@ uint64_t port_get_raw_ticks(uint8_t *subticks) {
|
|||||||
return overflow_count + current_ticks / 16;
|
return overflow_count + current_ticks / 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void evsyshandler_common(void) {
|
||||||
|
#ifdef SAMD21
|
||||||
|
if (_tick_event_channel < EVSYS_SYNCH_NUM && event_interrupt_active(_tick_event_channel)) {
|
||||||
|
supervisor_tick();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
|
||||||
|
audio_evsys_handler();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SAM_D5X_E5X
|
||||||
|
void EVSYS_0_Handler(void) {
|
||||||
|
evsyshandler_common();
|
||||||
|
}
|
||||||
|
void EVSYS_1_Handler(void) {
|
||||||
|
evsyshandler_common();
|
||||||
|
}
|
||||||
|
void EVSYS_2_Handler(void) {
|
||||||
|
evsyshandler_common();
|
||||||
|
}
|
||||||
|
void EVSYS_3_Handler(void) {
|
||||||
|
evsyshandler_common();
|
||||||
|
}
|
||||||
|
void EVSYS_4_Handler(void) {
|
||||||
|
evsyshandler_common();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void EVSYS_Handler(void) {
|
||||||
|
evsyshandler_common();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Enable 1/1024 second tick.
|
// Enable 1/1024 second tick.
|
||||||
void port_enable_tick(void) {
|
void port_enable_tick(void) {
|
||||||
#ifdef SAM_D5X_E5X
|
#ifdef SAM_D5X_E5X
|
||||||
@ -533,9 +545,23 @@ void port_enable_tick(void) {
|
|||||||
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_PER2;
|
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_PER2;
|
||||||
#endif
|
#endif
|
||||||
#ifdef SAMD21
|
#ifdef SAMD21
|
||||||
// TODO: Switch to using the PER *event* from the RTC to generate an interrupt via EVSYS.
|
// SAMD21 ticks won't survive port_reset(). This *should* be ok since it'll
|
||||||
_ticks_enabled = true;
|
// be triggered by ticks and no Python will be running.
|
||||||
_port_interrupt_after_ticks(1);
|
if (_tick_event_channel >= EVSYS_SYNCH_NUM) {
|
||||||
|
turn_on_event_system();
|
||||||
|
_tick_event_channel = find_sync_event_channel();
|
||||||
|
}
|
||||||
|
// This turns on both the event detected interrupt (EVD) and overflow (OVR).
|
||||||
|
init_event_channel_interrupt(_tick_event_channel, CORE_GCLK, EVSYS_ID_GEN_RTC_PER_2);
|
||||||
|
// Disable overflow interrupt because we ignore it.
|
||||||
|
if (_tick_event_channel >= 8) {
|
||||||
|
uint8_t value = 1 << (_tick_event_channel - 8);
|
||||||
|
EVSYS->INTENCLR.reg = EVSYS_INTENSET_OVRp8(value);
|
||||||
|
} else {
|
||||||
|
uint8_t value = 1 << _tick_event_channel;
|
||||||
|
EVSYS->INTENCLR.reg = EVSYS_INTENSET_OVR(value);
|
||||||
|
}
|
||||||
|
NVIC_EnableIRQ(EVSYS_IRQn);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,21 +571,48 @@ void port_disable_tick(void) {
|
|||||||
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_PER2;
|
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_PER2;
|
||||||
#endif
|
#endif
|
||||||
#ifdef SAMD21
|
#ifdef SAMD21
|
||||||
_ticks_enabled = false;
|
if (_tick_event_channel >= 8) {
|
||||||
RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0;
|
uint8_t value = 1 << (_tick_event_channel - 8);
|
||||||
|
EVSYS->INTENCLR.reg = EVSYS_INTENSET_EVDp8(value);
|
||||||
|
} else {
|
||||||
|
uint8_t value = 1 << _tick_event_channel;
|
||||||
|
EVSYS->INTENCLR.reg = EVSYS_INTENSET_EVD(value);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called by sleep, we ignore it when our ticks are enabled because
|
|
||||||
// they'll wake us up earlier. If we don't, we'll mess up ticks by overwriting
|
|
||||||
// the next RTC wake up time.
|
|
||||||
void port_interrupt_after_ticks(uint32_t ticks) {
|
void port_interrupt_after_ticks(uint32_t ticks) {
|
||||||
|
uint32_t current_ticks = _get_count(NULL);
|
||||||
|
if (ticks > 1 << 28) {
|
||||||
|
// We'll interrupt sooner with an overflow.
|
||||||
|
return;
|
||||||
|
}
|
||||||
#ifdef SAMD21
|
#ifdef SAMD21
|
||||||
if (_ticks_enabled) {
|
if (!sleep_ok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
_port_interrupt_after_ticks(ticks);
|
|
||||||
|
uint32_t target = current_ticks + (ticks << 4);
|
||||||
|
#ifdef SAMD21
|
||||||
|
// Try and avoid a bus stall when writing COMP by checking for an obvious
|
||||||
|
// existing sync.
|
||||||
|
while (RTC->MODE0.STATUS.bit.SYNCBUSY == 1) {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// Writing the COMP register can take up to 180us to synchronize. During
|
||||||
|
// this time, the bus will stall and no interrupts will be serviced.
|
||||||
|
RTC->MODE0.COMP[0].reg = target;
|
||||||
|
#ifdef SAM_D5X_E5X
|
||||||
|
while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP0)) != 0) {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
|
||||||
|
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0;
|
||||||
|
// Set continuous mode again because setting COMP may disable it.
|
||||||
|
rtc_continuous_mode();
|
||||||
|
current_ticks = _get_count(NULL);
|
||||||
|
_woken_up = current_ticks >= target;
|
||||||
}
|
}
|
||||||
|
|
||||||
void port_idle_until_interrupt(void) {
|
void port_idle_until_interrupt(void) {
|
||||||
@ -571,7 +624,7 @@ void port_idle_until_interrupt(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
common_hal_mcu_disable_interrupts();
|
common_hal_mcu_disable_interrupts();
|
||||||
if (!tud_task_event_ready() && !hold_interrupt && !_woken_up) {
|
if (!tud_task_event_ready() && sleep_ok && !_woken_up) {
|
||||||
__DSB();
|
__DSB();
|
||||||
__WFI();
|
__WFI();
|
||||||
}
|
}
|
||||||
|
@ -121,9 +121,15 @@ CFLAGS += -DCIRCUITPY_BUILTINS_POW3=$(CIRCUITPY_BUILTINS_POW3)
|
|||||||
CIRCUITPY_BUSIO ?= 1
|
CIRCUITPY_BUSIO ?= 1
|
||||||
CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO)
|
CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO)
|
||||||
|
|
||||||
|
# These two flags pretend to implement their class but raise a ValueError due to
|
||||||
|
# unsupported pins. This should be used sparingly on boards that don't break out
|
||||||
|
# generic IO but need parts of busio.
|
||||||
CIRCUITPY_BUSIO_SPI ?= 1
|
CIRCUITPY_BUSIO_SPI ?= 1
|
||||||
CFLAGS += -DCIRCUITPY_BUSIO_SPI=$(CIRCUITPY_BUSIO_SPI)
|
CFLAGS += -DCIRCUITPY_BUSIO_SPI=$(CIRCUITPY_BUSIO_SPI)
|
||||||
|
|
||||||
|
CIRCUITPY_BUSIO_UART ?= 1
|
||||||
|
CFLAGS += -DCIRCUITPY_BUSIO_UART=$(CIRCUITPY_BUSIO_UART)
|
||||||
|
|
||||||
CIRCUITPY_CAMERA ?= 0
|
CIRCUITPY_CAMERA ?= 0
|
||||||
CFLAGS += -DCIRCUITPY_CAMERA=$(CIRCUITPY_CAMERA)
|
CFLAGS += -DCIRCUITPY_CAMERA=$(CIRCUITPY_CAMERA)
|
||||||
|
|
||||||
@ -184,7 +190,7 @@ CFLAGS += -DCIRCUITPY_FREQUENCYIO=$(CIRCUITPY_FREQUENCYIO)
|
|||||||
CIRCUITPY_GAMEPADSHIFT ?= 0
|
CIRCUITPY_GAMEPADSHIFT ?= 0
|
||||||
CFLAGS += -DCIRCUITPY_GAMEPADSHIFT=$(CIRCUITPY_GAMEPADSHIFT)
|
CFLAGS += -DCIRCUITPY_GAMEPADSHIFT=$(CIRCUITPY_GAMEPADSHIFT)
|
||||||
|
|
||||||
CIRCUITPY_GETPASS ?= 1
|
CIRCUITPY_GETPASS ?= $(CIRCUITPY_FULL_BUILD)
|
||||||
CFLAGS += -DCIRCUITPY_GETPASS=$(CIRCUITPY_GETPASS)
|
CFLAGS += -DCIRCUITPY_GETPASS=$(CIRCUITPY_GETPASS)
|
||||||
|
|
||||||
CIRCUITPY_GNSS ?= 0
|
CIRCUITPY_GNSS ?= 0
|
||||||
@ -330,7 +336,7 @@ CFLAGS += -DCIRCUITPY_TOUCHIO_USE_NATIVE=$(CIRCUITPY_TOUCHIO_USE_NATIVE)
|
|||||||
CIRCUITPY_TOUCHIO ?= 1
|
CIRCUITPY_TOUCHIO ?= 1
|
||||||
CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO)
|
CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO)
|
||||||
|
|
||||||
CIRCUITPY_TRACEBACK ?= 1
|
CIRCUITPY_TRACEBACK ?= $(CIRCUITPY_FULL_BUILD)
|
||||||
CFLAGS += -DCIRCUITPY_TRACEBACK=$(CIRCUITPY_TRACEBACK)
|
CFLAGS += -DCIRCUITPY_TRACEBACK=$(CIRCUITPY_TRACEBACK)
|
||||||
|
|
||||||
# For debugging.
|
# For debugging.
|
||||||
|
@ -104,7 +104,7 @@ STATIC mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, con
|
|||||||
common_hal_busio_spi_construct(self, clock, mosi, miso);
|
common_hal_busio_spi_construct(self, clock, mosi, miso);
|
||||||
return MP_OBJ_FROM_PTR(self);
|
return MP_OBJ_FROM_PTR(self);
|
||||||
#else
|
#else
|
||||||
mp_raise_NotImplementedError(NULL);
|
mp_raise_ValueError(translate("Invalid pins"));
|
||||||
#endif // CIRCUITPY_BUSIO_SPI
|
#endif // CIRCUITPY_BUSIO_SPI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,13 +72,16 @@ typedef struct {
|
|||||||
extern const busio_uart_parity_obj_t busio_uart_parity_even_obj;
|
extern const busio_uart_parity_obj_t busio_uart_parity_even_obj;
|
||||||
extern const busio_uart_parity_obj_t busio_uart_parity_odd_obj;
|
extern const busio_uart_parity_obj_t busio_uart_parity_odd_obj;
|
||||||
|
|
||||||
|
#if CIRCUITPY_BUSIO_UART
|
||||||
STATIC void validate_timeout(mp_float_t timeout) {
|
STATIC void validate_timeout(mp_float_t timeout) {
|
||||||
if (timeout < (mp_float_t)0.0f || timeout > (mp_float_t)100.0f) {
|
if (timeout < (mp_float_t)0.0f || timeout > (mp_float_t)100.0f) {
|
||||||
mp_raise_ValueError(translate("timeout must be 0.0-100.0 seconds"));
|
mp_raise_ValueError(translate("timeout must be 0.0-100.0 seconds"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // CIRCUITPY_BUSIO_UART
|
||||||
|
|
||||||
STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
|
#if CIRCUITPY_BUSIO_UART
|
||||||
// Always initially allocate the UART object within the long-lived heap.
|
// Always initially allocate the UART object within the long-lived heap.
|
||||||
// This is needed to avoid crashes with certain UART implementations which
|
// This is needed to avoid crashes with certain UART implementations which
|
||||||
// cannot accomodate being moved after creation. (See
|
// cannot accomodate being moved after creation. (See
|
||||||
@ -141,8 +144,12 @@ STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, co
|
|||||||
args[ARG_baudrate].u_int, bits, parity, stop, timeout,
|
args[ARG_baudrate].u_int, bits, parity, stop, timeout,
|
||||||
args[ARG_receiver_buffer_size].u_int, NULL, false);
|
args[ARG_receiver_buffer_size].u_int, NULL, false);
|
||||||
return (mp_obj_t)self;
|
return (mp_obj_t)self;
|
||||||
|
#else
|
||||||
|
mp_raise_ValueError(translate("Invalid pins"));
|
||||||
|
#endif // CIRCUITPY_BUSIO_UART
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CIRCUITPY_BUSIO_UART
|
||||||
|
|
||||||
// Helper to ensure we have the native super class instead of a subclass.
|
// Helper to ensure we have the native super class instead of a subclass.
|
||||||
busio_uart_obj_t *native_uart(mp_obj_t uart_obj) {
|
busio_uart_obj_t *native_uart(mp_obj_t uart_obj) {
|
||||||
@ -358,6 +365,7 @@ STATIC mp_obj_t busio_uart_obj_reset_input_buffer(mp_obj_t self_in) {
|
|||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_reset_input_buffer_obj, busio_uart_obj_reset_input_buffer);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_reset_input_buffer_obj, busio_uart_obj_reset_input_buffer);
|
||||||
|
#endif // CIRCUITPY_BUSIO_UART
|
||||||
|
|
||||||
//| class Parity:
|
//| class Parity:
|
||||||
//| """Enum-like class to define the parity used to verify correct data transfer."""
|
//| """Enum-like class to define the parity used to verify correct data transfer."""
|
||||||
@ -400,6 +408,7 @@ const mp_obj_type_t busio_uart_parity_type = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t busio_uart_locals_dict_table[] = {
|
STATIC const mp_rom_map_elem_t busio_uart_locals_dict_table[] = {
|
||||||
|
#if CIRCUITPY_BUSIO_UART
|
||||||
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&busio_uart_deinit_obj) },
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&busio_uart_deinit_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_uart_deinit_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_uart_deinit_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
|
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
|
||||||
@ -417,12 +426,14 @@ STATIC const mp_rom_map_elem_t busio_uart_locals_dict_table[] = {
|
|||||||
{ MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&busio_uart_baudrate_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&busio_uart_baudrate_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&busio_uart_in_waiting_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&busio_uart_in_waiting_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&busio_uart_timeout_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&busio_uart_timeout_obj) },
|
||||||
|
#endif // CIRCUITPY_BUSIO_UART
|
||||||
|
|
||||||
// Nested Enum-like Classes.
|
// Nested Enum-like Classes.
|
||||||
{ MP_ROM_QSTR(MP_QSTR_Parity), MP_ROM_PTR(&busio_uart_parity_type) },
|
{ MP_ROM_QSTR(MP_QSTR_Parity), MP_ROM_PTR(&busio_uart_parity_type) },
|
||||||
};
|
};
|
||||||
STATIC MP_DEFINE_CONST_DICT(busio_uart_locals_dict, busio_uart_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(busio_uart_locals_dict, busio_uart_locals_dict_table);
|
||||||
|
|
||||||
|
#if CIRCUITPY_BUSIO_UART
|
||||||
STATIC const mp_stream_p_t uart_stream_p = {
|
STATIC const mp_stream_p_t uart_stream_p = {
|
||||||
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
|
MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
|
||||||
.read = busio_uart_read,
|
.read = busio_uart_read,
|
||||||
@ -445,3 +456,11 @@ const mp_obj_type_t busio_uart_type = {
|
|||||||
.protocol = &uart_stream_p,
|
.protocol = &uart_stream_p,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
#else
|
||||||
|
const mp_obj_type_t busio_uart_type = {
|
||||||
|
{ &mp_type_type },
|
||||||
|
.name = MP_QSTR_UART,
|
||||||
|
.make_new = busio_uart_make_new,
|
||||||
|
.locals_dict = (mp_obj_dict_t *)&busio_uart_locals_dict,
|
||||||
|
};
|
||||||
|
#endif // CIRCUITPY_BUSIO_UART
|
||||||
|
Loading…
Reference in New Issue
Block a user