35
35
#include "common-hal/audiobusio/PDMIn.h"
36
36
#include "shared-bindings/analogio/AnalogOut.h"
37
37
#include "shared-bindings/audiobusio/PDMIn.h"
38
+ #include "shared-bindings/microcontroller/__init__.h"
38
39
#include "shared-bindings/microcontroller/Pin.h"
39
40
#include "supervisor/shared/translate.h"
40
41
64
65
#define SERCTRL (name ) I2S_RXCTRL_ ## name
65
66
#endif
66
67
68
+ // Set by interrupt handler when DMA block has finished transferring.
69
+ static bool pdmin_dma_block_done ;
70
+ // Event channel used to trigger interrupt. Set to invalid value EVSYS_SYNCH_NUM when not in use.
71
+ static uint8_t pdmin_event_channel ;
72
+
73
+ void pdmin_evsys_handler (void ) {
74
+ if (pdmin_event_channel < EVSYS_SYNCH_NUM && event_interrupt_active (pdmin_event_channel )) {
75
+ pdmin_dma_block_done = true;
76
+ }
77
+ }
78
+
67
79
void pdmin_reset (void ) {
80
+ pdmin_event_channel = EVSYS_SYNCH_NUM ;
81
+
68
82
while (I2S -> SYNCBUSY .reg & I2S_SYNCBUSY_ENABLE ) {}
69
83
I2S -> INTENCLR .reg = I2S_INTENCLR_MASK ;
70
84
I2S -> INTFLAG .reg = I2S_INTFLAG_MASK ;
@@ -368,7 +382,8 @@ static uint16_t filter_sample(uint32_t pdm_samples[4]) {
368
382
uint32_t common_hal_audiobusio_pdmin_record_to_buffer (audiobusio_pdmin_obj_t * self ,
369
383
uint16_t * output_buffer , uint32_t output_buffer_length ) {
370
384
uint8_t dma_channel = dma_allocate_channel ();
371
- uint8_t event_channel = find_sync_event_channel_raise ();
385
+ pdmin_event_channel = find_sync_event_channel_raise ();
386
+ pdmin_dma_block_done = false;
372
387
373
388
// We allocate two buffers on the stack to use for double buffering.
374
389
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
391
406
#endif
392
407
393
408
dma_configure (dma_channel , trigger_source , true);
394
- init_event_channel_interrupt (event_channel , CORE_GCLK , EVSYS_ID_GEN_DMAC_CH_0 + dma_channel );
409
+ init_event_channel_interrupt (pdmin_event_channel , CORE_GCLK , EVSYS_ID_GEN_DMAC_CH_0 + dma_channel );
395
410
// Turn on serializer now to get it in sync with DMA.
396
411
i2s_set_serializer_enable (self -> serializer , true);
397
412
audio_dma_enable_channel (dma_channel );
@@ -402,23 +417,12 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se
402
417
403
418
uint32_t remaining_samples_needed = output_buffer_length ;
404
419
while (values_output < output_buffer_length ) {
405
- if (event_interrupt_overflow (event_channel )) {
406
- // Looks like we aren't keeping up. We shouldn't skip a buffer so stop early.
407
- break ;
408
- }
409
- // Wait for the next buffer to fill
410
- uint32_t wait_counts = 0 ;
411
- #ifdef SAMD21
412
- #define MAX_WAIT_COUNTS 1000
413
- #endif
414
- #ifdef SAM_D5X_E5X
415
- #define MAX_WAIT_COUNTS 6000
416
- #endif
417
- // If wait_counts exceeds the max count, buffer has probably stopped filling;
418
- // DMA may have missed an I2S trigger event.
419
- while (!event_interrupt_active (event_channel ) && ++ wait_counts < MAX_WAIT_COUNTS ) {
420
+ while (!pdmin_dma_block_done ) {
420
421
RUN_BACKGROUND_TASKS ;
421
422
}
423
+ common_hal_mcu_disable_interrupts ();
424
+ pdmin_dma_block_done = false;
425
+ common_hal_mcu_enable_interrupts ();
422
426
423
427
// The mic is running all the time, so we don't need to wait the usual 10msec or 100msec
424
428
// for it to start up.
@@ -430,6 +434,7 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se
430
434
buffer = second_buffer ;
431
435
descriptor = & second_descriptor ;
432
436
}
437
+
433
438
// Decimate and filter the buffer that was just filled.
434
439
uint32_t samples_gathered = descriptor -> BTCNT .reg / words_per_sample ;
435
440
// 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
472
477
}
473
478
}
474
479
475
- disable_event_channel (event_channel );
480
+ disable_event_channel (pdmin_event_channel );
481
+ pdmin_event_channel = EVSYS_SYNCH_NUM ; // Invalid event_channel.
476
482
dma_free_channel (dma_channel );
477
483
// Turn off serializer, but leave clock on, to avoid mic startup delay.
478
484
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
481
487
}
482
488
483
489
void common_hal_audiobusio_pdmin_record_to_file (audiobusio_pdmin_obj_t * self , uint8_t * buffer , uint32_t length ) {
484
-
485
490
}
0 commit comments