Skip to content

Commit 7918714

Browse files
dhalberttannewt
authored andcommitted
certain odd-sized PDMIn record buffers would crash or not fill properly
1 parent 2d2735c commit 7918714

File tree

1 file changed

+14
-9
lines changed
  • atmel-samd/common-hal/audiobusio

1 file changed

+14
-9
lines changed

atmel-samd/common-hal/audiobusio/PDMIn.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,15 @@ static void setup_dma(audiobusio_pdmin_obj_t* self, uint32_t length,
213213
}
214214
dma_descriptor_create(audio_dma.descriptor, &descriptor_config);
215215

216+
// Do we need more values than will fit in the first buffer?
217+
// If so, set up a second buffer chained to be filled after the first buffer.
216218
if (length * words_per_sample > words_per_buffer) {
217219
block_transfer_count = words_per_buffer;
218220
descriptor_config.next_descriptor_address = ((uint32_t)audio_dma.descriptor);
219221
if (length * words_per_sample < 2 * words_per_buffer) {
220-
block_transfer_count = 2 * words_per_buffer - length * words_per_sample;
222+
// Length needed is more than one buffer but less than two.
223+
// Subtract off the size of the first buffer, and what remains is the count we need.
224+
block_transfer_count = length * words_per_sample - words_per_buffer;
221225
descriptor_config.next_descriptor_address = 0;
222226
}
223227
descriptor_config.block_transfer_count = block_transfer_count;
@@ -309,18 +313,21 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se
309313
uint32_t remaining_samples_needed = output_buffer_length;
310314
while (values_output < output_buffer_length) {
311315
// Wait for the next buffer to fill
312-
while (tc_get_count_value(MP_STATE_VM(audiodma_block_counter)) == buffers_processed) {
316+
uint32_t block_counter;
317+
while ((block_counter = tc_get_count_value(MP_STATE_VM(audiodma_block_counter))) == buffers_processed) {
313318
#ifdef MICROPY_VM_HOOK_LOOP
314319
MICROPY_VM_HOOK_LOOP
315320
#endif
316321
}
317-
if (tc_get_count_value(MP_STATE_VM(audiodma_block_counter)) != (buffers_processed + 1)) {
322+
if (block_counter != (buffers_processed + 1)) {
323+
// Looks like we aren't keeping up. We shouldn't skip a buffer.
318324
break;
319325
}
320326

321327
// The mic is running all the time, so we don't need to wait the usual 10msec or 100msec
322328
// for it to start up.
323329

330+
// Flip back and forth between processing the first and second buffers.
324331
uint32_t *buffer = first_buffer;
325332
DmacDescriptor* descriptor = audio_dma.descriptor;
326333
if (buffers_processed % 2 == 1) {
@@ -342,15 +349,13 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se
342349
}
343350
values_output++;
344351
}
352+
345353
buffers_processed++;
346354

347-
// See if we need to transfer less than a full buffer for the remaining needed samples.
355+
// We might need fewer than an entire of samples, but we won't try to alter the
356+
// last DMA, which might already be in progress, so we'll just throw away some
357+
// samples at the end.
348358
remaining_samples_needed = output_buffer_length - values_output;
349-
if (remaining_samples_needed > 0 && remaining_samples_needed < samples_per_buffer) {
350-
descriptor->BTCNT.reg = remaining_samples_needed;
351-
descriptor->DSTADDR.reg = ((uint32_t) buffer) + remaining_samples_needed * words_per_sample;
352-
descriptor->DESCADDR.reg = 0;
353-
}
354359
}
355360

356361
stop_dma(self);

0 commit comments

Comments
 (0)