From 79ee78e6904286d6b1ba84f2869f15c07902c195 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 15 Oct 2021 09:39:13 -0400 Subject: [PATCH 1/2] fix SAMD21 PDMIn DMA event use --- ports/atmel-samd/audio_dma.c | 2 +- ports/atmel-samd/audio_dma.h | 2 +- .../atmel-samd/common-hal/audiobusio/PDMIn.c | 43 +++++++++++-------- .../atmel-samd/common-hal/audiobusio/PDMIn.h | 2 + ports/atmel-samd/supervisor/port.c | 31 ++++++++++++- 5 files changed, 58 insertions(+), 22 deletions(-) diff --git a/ports/atmel-samd/audio_dma.c b/ports/atmel-samd/audio_dma.c index d7ec9dcd075cf..4dbb0a0006d7b 100644 --- a/ports/atmel-samd/audio_dma.c +++ b/ports/atmel-samd/audio_dma.c @@ -396,7 +396,7 @@ STATIC void dma_callback_fun(void *arg) { } } -void audio_evsys_handler(void) { +void audio_dma_evsys_handler(void) { for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) { audio_dma_t *dma = audio_dma_state[i]; if (dma == NULL) { diff --git a/ports/atmel-samd/audio_dma.h b/ports/atmel-samd/audio_dma.h index 0b5f35c71be17..cc41b0ae78d97 100644 --- a/ports/atmel-samd/audio_dma.h +++ b/ports/atmel-samd/audio_dma.h @@ -101,6 +101,6 @@ void audio_dma_background(void); uint8_t find_sync_event_channel_raise(void); -void audio_evsys_handler(void); +void audio_dma_evsys_handler(void); #endif // MICROPY_INCLUDED_ATMEL_SAMD_AUDIO_DMA_H diff --git a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c index 6ea70e39dcb05..e00d69c8483fe 100644 --- a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c +++ b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c @@ -35,6 +35,7 @@ #include "common-hal/audiobusio/PDMIn.h" #include "shared-bindings/analogio/AnalogOut.h" #include "shared-bindings/audiobusio/PDMIn.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "supervisor/shared/translate.h" @@ -64,7 +65,20 @@ #define SERCTRL(name) I2S_RXCTRL_ ## name #endif +// Set by interrupt handler when DMA block has finished transferring. +static bool pdmin_dma_block_done; +// Event channel used to trigger interrupt. Set to invalid value EVSYS_SYNCH_NUM when not in use. +static uint8_t pdmin_event_channel; + +void pdmin_evsys_handler(void) { + if (pdmin_event_channel < EVSYS_SYNCH_NUM && event_interrupt_active(pdmin_event_channel)) { + pdmin_dma_block_done = true; + } +} + void pdmin_reset(void) { + pdmin_event_channel = EVSYS_SYNCH_NUM; + while (I2S->SYNCBUSY.reg & I2S_SYNCBUSY_ENABLE) {} I2S->INTENCLR.reg = I2S_INTENCLR_MASK; I2S->INTFLAG.reg = I2S_INTFLAG_MASK; @@ -368,7 +382,8 @@ static uint16_t filter_sample(uint32_t pdm_samples[4]) { uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* self, uint16_t* output_buffer, uint32_t output_buffer_length) { uint8_t dma_channel = dma_allocate_channel(); - uint8_t event_channel = find_sync_event_channel_raise(); + pdmin_event_channel = find_sync_event_channel_raise(); + pdmin_dma_block_done = false; // We allocate two buffers on the stack to use for double buffering. const uint8_t samples_per_buffer = SAMPLES_PER_BUFFER; @@ -391,7 +406,7 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se #endif dma_configure(dma_channel, trigger_source, true); - init_event_channel_interrupt(event_channel, CORE_GCLK, EVSYS_ID_GEN_DMAC_CH_0 + dma_channel); + init_event_channel_interrupt(pdmin_event_channel, CORE_GCLK, EVSYS_ID_GEN_DMAC_CH_0 + dma_channel); // Turn on serializer now to get it in sync with DMA. i2s_set_serializer_enable(self->serializer, true); audio_dma_enable_channel(dma_channel); @@ -402,23 +417,12 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se uint32_t remaining_samples_needed = output_buffer_length; while (values_output < output_buffer_length) { - if (event_interrupt_overflow(event_channel)) { - // Looks like we aren't keeping up. We shouldn't skip a buffer so stop early. - break; - } - // Wait for the next buffer to fill - uint32_t wait_counts = 0; - #ifdef SAMD21 - #define MAX_WAIT_COUNTS 1000 - #endif - #ifdef SAM_D5X_E5X - #define MAX_WAIT_COUNTS 6000 - #endif - // If wait_counts exceeds the max count, buffer has probably stopped filling; - // DMA may have missed an I2S trigger event. - while (!event_interrupt_active(event_channel) && ++wait_counts < MAX_WAIT_COUNTS) { + while (!pdmin_dma_block_done) { RUN_BACKGROUND_TASKS; } + common_hal_mcu_disable_interrupts(); + pdmin_dma_block_done = false; + common_hal_mcu_enable_interrupts(); // The mic is running all the time, so we don't need to wait the usual 10msec or 100msec // for it to start up. @@ -430,6 +434,7 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se buffer = second_buffer; descriptor = &second_descriptor; } + // Decimate and filter the buffer that was just filled. uint32_t samples_gathered = descriptor->BTCNT.reg / words_per_sample; // Don't run off the end of output buffer. Process only as many as needed. @@ -472,7 +477,8 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se } } - disable_event_channel(event_channel); + disable_event_channel(pdmin_event_channel); + pdmin_event_channel = EVSYS_SYNCH_NUM; // Invalid event_channel. dma_free_channel(dma_channel); // Turn off serializer, but leave clock on, to avoid mic startup delay. i2s_set_serializer_enable(self->serializer, false); @@ -481,5 +487,4 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se } void common_hal_audiobusio_pdmin_record_to_file(audiobusio_pdmin_obj_t* self, uint8_t* buffer, uint32_t length) { - } diff --git a/ports/atmel-samd/common-hal/audiobusio/PDMIn.h b/ports/atmel-samd/common-hal/audiobusio/PDMIn.h index 5c4d4feea0651..7f00886d29690 100644 --- a/ports/atmel-samd/common-hal/audiobusio/PDMIn.h +++ b/ports/atmel-samd/common-hal/audiobusio/PDMIn.h @@ -46,6 +46,8 @@ typedef struct { void pdmin_reset(void); +void pdmin_evsys_handler(void); + void pdmin_background(void); #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_AUDIOBUSIO_AUDIOOUT_H diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 4b0775ea91574..fec5d8e63dd87 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -53,18 +53,42 @@ #error Unknown chip family #endif +#if CIRCUITPY_ANALOGIO #include "common-hal/analogio/AnalogIn.h" #include "common-hal/analogio/AnalogOut.h" +#endif + +#if CIRCUITPY_AUDIOBUSIO #include "common-hal/audiobusio/PDMIn.h" #include "common-hal/audiobusio/I2SOut.h" +#endif + +#if CIRCUITPY_AUDIOIO #include "common-hal/audioio/AudioOut.h" +#endif + +#if CIRCUITPY_BUSIO_SPI #include "common-hal/busio/SPI.h" +#endif + #include "common-hal/microcontroller/Pin.h" + +#if CIRCUITPY_PULSEIO #include "common-hal/pulseio/PulseIn.h" #include "common-hal/pulseio/PulseOut.h" +#endif + +#if CIRCUITPY_PWMIO #include "common-hal/pwmio/PWMOut.h" +#endif + +#if CIRCUITPY_PS2IO #include "common-hal/ps2io/Ps2.h" +#endif + +#if CIRCUITPY_RTC #include "common-hal/rtc/RTC.h" +#endif #if CIRCUITPY_TOUCHIO_USE_NATIVE #include "common-hal/touchio/TouchIn.h" @@ -516,8 +540,13 @@ void evsyshandler_common(void) { supervisor_tick(); } #endif + #if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO - audio_evsys_handler(); + audio_dma_evsys_handler(); + #endif + + #if CIRCUITPY_AUDIOBUSIO + pdmin_evsys_handler(); #endif } From fc440e7609590a24df2f8013c377e6871cf27ea5 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 19 Oct 2021 15:18:32 -0400 Subject: [PATCH 2/2] move sercom_reset() etc. out of busio/SPI.c to busio/__init__.c --- ports/atmel-samd/common-hal/busio/I2C.c | 2 +- ports/atmel-samd/common-hal/busio/SPI.c | 39 +----------- ports/atmel-samd/common-hal/busio/SPI.h | 4 -- ports/atmel-samd/common-hal/busio/UART.c | 2 +- ports/atmel-samd/common-hal/busio/__init__.c | 64 +++++++++++++++++++- ports/atmel-samd/common-hal/busio/__init__.h | 35 +++++++++++ ports/atmel-samd/supervisor/port.c | 4 +- 7 files changed, 104 insertions(+), 46 deletions(-) create mode 100644 ports/atmel-samd/common-hal/busio/__init__.h diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index 39aa6c9e97d3b..7d77c0d43a27b 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -36,7 +36,7 @@ #include "shared-bindings/microcontroller/__init__.h" #include "supervisor/shared/translate.h" -#include "common-hal/busio/SPI.h" // for never_reset_sercom +#include "common-hal/busio/__init__.h" // Number of times to try to send packet if failed. #define ATTEMPTS 2 diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index 884c3e0414c6a..3b60c1d2b4f0a 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -32,7 +32,9 @@ #include "peripheral_clk_config.h" #include "supervisor/board.h" +#include "common-hal/busio/__init__.h" #include "common-hal/microcontroller/Pin.h" + #include "hal/include/hal_gpio.h" #include "hal/include/hal_spi_m_sync.h" #include "hal/include/hpl_spi_m_sync.h" @@ -40,43 +42,6 @@ #include "samd/dma.h" #include "samd/sercom.h" -bool never_reset_sercoms[SERCOM_INST_NUM]; - -void never_reset_sercom(Sercom *sercom) { - // Reset all SERCOMs except the ones being used by on-board devices. - Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; - for (int i = 0; i < SERCOM_INST_NUM; i++) { - if (sercom_instances[i] == sercom) { - never_reset_sercoms[i] = true; - break; - } - } -} - -void allow_reset_sercom(Sercom *sercom) { - // Reset all SERCOMs except the ones being used by on-board devices. - Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; - for (int i = 0; i < SERCOM_INST_NUM; i++) { - if (sercom_instances[i] == sercom) { - never_reset_sercoms[i] = false; - break; - } - } -} - -void reset_sercoms(void) { - // Reset all SERCOMs except the ones being used by on-board devices. - Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; - for (int i = 0; i < SERCOM_INST_NUM; i++) { - if (never_reset_sercoms[i]) { - continue; - } - // SWRST is same for all modes of SERCOMs. - sercom_instances[i]->SPI.CTRLA.bit.SWRST = 1; - } -} - - void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso) { diff --git a/ports/atmel-samd/common-hal/busio/SPI.h b/ports/atmel-samd/common-hal/busio/SPI.h index 27bbfdeb3a04c..2fced6d642eea 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.h +++ b/ports/atmel-samd/common-hal/busio/SPI.h @@ -42,8 +42,4 @@ typedef struct { uint8_t MISO_pin; } busio_spi_obj_t; -void reset_sercoms(void); -void never_reset_sercom(Sercom *sercom); - - #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/atmel-samd/common-hal/busio/UART.c b/ports/atmel-samd/common-hal/busio/UART.c index c33bf6f440464..2625283c839c2 100644 --- a/ports/atmel-samd/common-hal/busio/UART.c +++ b/ports/atmel-samd/common-hal/busio/UART.c @@ -45,7 +45,7 @@ #include "samd/sercom.h" -#include "common-hal/busio/SPI.h" // for never_reset_sercom +#include "common-hal/busio/__init__.h" #define UART_DEBUG(...) (void)0 // #define UART_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) diff --git a/ports/atmel-samd/common-hal/busio/__init__.c b/ports/atmel-samd/common-hal/busio/__init__.c index 41761b6743aea..8ec549e931947 100644 --- a/ports/atmel-samd/common-hal/busio/__init__.c +++ b/ports/atmel-samd/common-hal/busio/__init__.c @@ -1 +1,63 @@ -// No busio module functions. +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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 "samd/sercom.h" + +static bool never_reset_sercoms[SERCOM_INST_NUM]; + +void never_reset_sercom(Sercom *sercom) { + // Reset all SERCOMs except the ones being used by on-board devices. + Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; + for (int i = 0; i < SERCOM_INST_NUM; i++) { + if (sercom_instances[i] == sercom) { + never_reset_sercoms[i] = true; + break; + } + } +} + +void allow_reset_sercom(Sercom *sercom) { + // Reset all SERCOMs except the ones being used by on-board devices. + Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; + for (int i = 0; i < SERCOM_INST_NUM; i++) { + if (sercom_instances[i] == sercom) { + never_reset_sercoms[i] = false; + break; + } + } +} + +void reset_sercoms(void) { + // Reset all SERCOMs except the ones being used by on-board devices. + Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; + for (int i = 0; i < SERCOM_INST_NUM; i++) { + if (never_reset_sercoms[i]) { + continue; + } + // SWRST is same for all modes of SERCOMs. + sercom_instances[i]->SPI.CTRLA.bit.SWRST = 1; + } +} diff --git a/ports/atmel-samd/common-hal/busio/__init__.h b/ports/atmel-samd/common-hal/busio/__init__.h new file mode 100644 index 0000000000000..ded88f113da4f --- /dev/null +++ b/ports/atmel-samd/common-hal/busio/__init__.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_COMMON_HAL_BUSIO_INIT_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_INIT_H + +void reset_sercoms(void); +void allow_reset_sercom(Sercom *sercom); +void never_reset_sercom(Sercom *sercom); + + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_INIT_H diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index fec5d8e63dd87..932252a0d762a 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -67,8 +67,8 @@ #include "common-hal/audioio/AudioOut.h" #endif -#if CIRCUITPY_BUSIO_SPI -#include "common-hal/busio/SPI.h" +#if CIRCUITPY_BUSIO +#include "common-hal/busio/__init__.h" #endif #include "common-hal/microcontroller/Pin.h"