24
24
* THE SOFTWARE.
25
25
*/
26
26
27
+ #include <string.h>
28
+
27
29
#include "audio_dma.h"
28
30
#include "samd/clocks.h"
29
31
#include "samd/events.h"
30
32
#include "samd/dma.h"
31
33
32
34
#include "shared-bindings/audiocore/RawSample.h"
33
35
#include "shared-bindings/audiocore/WaveFile.h"
36
+ #include "shared-bindings/microcontroller/__init__.h"
34
37
#include "supervisor/background_callback.h"
35
38
36
39
#include "py/mpstate.h"
37
40
#include "py/runtime.h"
38
41
39
42
#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
40
43
44
+ // Flag value for dma->buffer_to_load, indicating there is nothing to do.
45
+ // Otherwise dma->buffer_to_load is 0 or 1.
46
+ #define NO_BUFFER_TO_LOAD 0xff
47
+
41
48
static audio_dma_t * audio_dma_state [AUDIO_DMA_CHANNEL_COUNT ];
42
49
43
50
// This cannot be in audio_dma_state because it's volatile.
@@ -85,70 +92,79 @@ void audio_dma_enable_channel(uint8_t channel) {
85
92
dma_enable_channel (channel );
86
93
}
87
94
88
- void audio_dma_convert_signed (audio_dma_t * dma , uint8_t * buffer , uint32_t buffer_length ,
89
- uint8_t * * output_buffer , uint32_t * output_buffer_length ,
95
+ static void audio_dma_convert_samples (
96
+ audio_dma_t * dma ,
97
+ uint8_t * input , uint32_t input_length ,
98
+ uint8_t * available_output_buffer , uint32_t available_output_buffer_length ,
99
+ uint8_t * * output , uint32_t * output_length ,
90
100
uint8_t * output_spacing ) {
91
- if (dma -> first_buffer_free ) {
92
- * output_buffer = dma -> first_buffer ;
93
- } else {
94
- * output_buffer = dma -> second_buffer ;
95
- }
96
101
#pragma GCC diagnostic push
97
102
#pragma GCC diagnostic ignored "-Wcast-align"
98
103
if (dma -> signed_to_unsigned || dma -> unsigned_to_signed ) {
99
- * output_buffer_length = buffer_length / dma -> spacing ;
104
+
105
+ // Must convert.
106
+ // Write the conversion into the passed-in output buffer
107
+ * output = available_output_buffer ;
108
+ * output_length = input_length / dma -> spacing ;
100
109
* output_spacing = 1 ;
110
+
111
+ if (* output_length > available_output_buffer_length ) {
112
+ mp_raise_RuntimeError (translate ("Internal audio buffer too small" ));
113
+ }
114
+
101
115
uint32_t out_i = 0 ;
102
116
if (dma -> bytes_per_sample == 1 ) {
103
- for (uint32_t i = 0 ; i < buffer_length ; i += dma -> spacing ) {
117
+ for (uint32_t i = 0 ; i < input_length ; i += dma -> spacing ) {
104
118
if (dma -> signed_to_unsigned ) {
105
- ((uint8_t * )* output_buffer )[out_i ] = ((int8_t * )buffer )[i ] + 0x80 ;
119
+ ((uint8_t * )* output )[out_i ] = ((int8_t * )input )[i ] + 0x80 ;
106
120
} else {
107
- ((int8_t * )* output_buffer )[out_i ] = ((uint8_t * )buffer )[i ] - 0x80 ;
121
+ ((int8_t * )* output )[out_i ] = ((uint8_t * )input )[i ] - 0x80 ;
108
122
}
109
123
out_i += 1 ;
110
124
}
111
125
} else if (dma -> bytes_per_sample == 2 ) {
112
- for (uint32_t i = 0 ; i < buffer_length / 2 ; i += dma -> spacing ) {
126
+ for (uint32_t i = 0 ; i < input_length / 2 ; i += dma -> spacing ) {
113
127
if (dma -> signed_to_unsigned ) {
114
- ((uint16_t * )* output_buffer )[out_i ] = ((int16_t * )buffer )[i ] + 0x8000 ;
128
+ ((uint16_t * )* output )[out_i ] = ((int16_t * )input )[i ] + 0x8000 ;
115
129
} else {
116
- ((int16_t * )* output_buffer )[out_i ] = ((uint16_t * )buffer )[i ] - 0x8000 ;
130
+ ((int16_t * )* output )[out_i ] = ((uint16_t * )input )[i ] - 0x8000 ;
117
131
}
118
132
out_i += 1 ;
119
133
}
120
134
}
121
135
} else {
122
- * output_buffer = buffer ;
123
- * output_buffer_length = buffer_length ;
136
+ * output = input ;
137
+ * output_length = input_length ;
124
138
* output_spacing = dma -> spacing ;
125
139
}
126
140
#pragma GCC diagnostic pop
127
- dma -> first_buffer_free = !dma -> first_buffer_free ;
128
141
}
129
142
130
- void audio_dma_load_next_block (audio_dma_t * dma ) {
131
- uint8_t * buffer ;
132
- uint32_t buffer_length ;
143
+ static void audio_dma_load_next_block (audio_dma_t * dma , size_t buffer_idx ) {
144
+ uint8_t * sample_buffer ;
145
+ uint32_t sample_buffer_length ;
133
146
audioio_get_buffer_result_t get_buffer_result =
134
147
audiosample_get_buffer (dma -> sample , dma -> single_channel_output , dma -> audio_channel ,
135
- & buffer , & buffer_length );
148
+ & sample_buffer , & sample_buffer_length );
136
149
137
- DmacDescriptor * descriptor = dma -> second_descriptor ;
138
- if (dma -> first_descriptor_free ) {
139
- descriptor = dma_descriptor (dma -> dma_channel );
140
- }
141
- dma -> first_descriptor_free = !dma -> first_descriptor_free ;
150
+ DmacDescriptor * descriptor = dma -> descriptor [buffer_idx ];
142
151
143
152
if (get_buffer_result == GET_BUFFER_ERROR ) {
144
153
audio_dma_stop (dma );
145
154
return ;
146
155
}
147
156
157
+ // Use one of the allocated buffers for conversion. But if there's no conversion,
158
+ // this will be set to buffer in audio_dma_convert_samples() to avoid any copying.
148
159
uint8_t * output_buffer ;
149
160
uint32_t output_buffer_length ;
150
161
uint8_t output_spacing ;
151
- audio_dma_convert_signed (dma , buffer , buffer_length , & output_buffer , & output_buffer_length ,
162
+
163
+ audio_dma_convert_samples (dma , sample_buffer , sample_buffer_length ,
164
+ // Available output buffer: may be used or not.
165
+ dma -> buffer [buffer_idx ], dma -> buffer_length [buffer_idx ],
166
+ // Buffer where output was placed.
167
+ & output_buffer , & output_buffer_length ,
152
168
& output_spacing );
153
169
154
170
descriptor -> BTCNT .reg = output_buffer_length / dma -> beat_size / output_spacing ;
@@ -157,9 +173,10 @@ void audio_dma_load_next_block(audio_dma_t *dma) {
157
173
if (dma -> loop ) {
158
174
audiosample_reset_buffer (dma -> sample , dma -> single_channel_output , dma -> audio_channel );
159
175
} else {
160
- if (( output_buffer_length == 0 ) && dma_transfer_status ( SHARED_RX_CHANNEL ) & 0x3 ) {
176
+ if (output_buffer_length == 0 ) {
161
177
// Nothing further to read and previous buffer is finished.
162
178
audio_dma_stop (dma );
179
+ return ;
163
180
} else {
164
181
// Break descriptor chain.
165
182
descriptor -> DESCADDR .reg = 0 ;
@@ -206,30 +223,33 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
206
223
dma -> dma_channel = dma_channel ;
207
224
dma -> signed_to_unsigned = false;
208
225
dma -> unsigned_to_signed = false;
209
- dma -> second_descriptor = NULL ;
210
226
dma -> spacing = 1 ;
211
- dma -> first_descriptor_free = true;
212
227
audiosample_reset_buffer (sample , single_channel_output , audio_channel );
228
+ dma -> buffer_to_load = NO_BUFFER_TO_LOAD ;
229
+ dma -> descriptor [0 ] = dma_descriptor (dma_channel );
230
+ dma -> descriptor [1 ] = & dma -> second_descriptor ;
213
231
214
- bool single_buffer ;
215
232
bool samples_signed ;
216
233
uint32_t max_buffer_length ;
217
- audiosample_get_buffer_structure (sample , single_channel_output , & single_buffer , & samples_signed ,
234
+ audiosample_get_buffer_structure (sample , single_channel_output , & dma -> single_buffer , & samples_signed ,
218
235
& max_buffer_length , & dma -> spacing );
219
236
uint8_t output_spacing = dma -> spacing ;
220
237
if (output_signed != samples_signed ) {
221
238
output_spacing = 1 ;
222
239
max_buffer_length /= dma -> spacing ;
223
240
}
224
241
225
- dma -> first_buffer = (uint8_t * )m_realloc (dma -> first_buffer , max_buffer_length );
226
- if (dma -> first_buffer == NULL ) {
242
+
243
+ dma -> buffer [0 ] = (uint8_t * )m_realloc (dma -> buffer [0 ], max_buffer_length );
244
+ dma -> buffer_length [0 ] = max_buffer_length ;
245
+ if (dma -> buffer [0 ] == NULL ) {
227
246
return AUDIO_DMA_MEMORY_ERROR ;
228
247
}
229
- dma -> first_buffer_free = true;
230
- if (!single_buffer ) {
231
- dma -> second_buffer = (uint8_t * )m_realloc (dma -> second_buffer , max_buffer_length );
232
- if (dma -> second_buffer == NULL ) {
248
+
249
+ if (!dma -> single_buffer ) {
250
+ dma -> buffer [1 ] = (uint8_t * )m_realloc (dma -> buffer [1 ], max_buffer_length );
251
+ dma -> buffer_length [1 ] = max_buffer_length ;
252
+ if (dma -> buffer [1 ] == NULL ) {
233
253
return AUDIO_DMA_MEMORY_ERROR ;
234
254
}
235
255
}
@@ -238,12 +258,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
238
258
dma -> unsigned_to_signed = output_signed && !samples_signed ;
239
259
240
260
dma -> event_channel = 0xff ;
241
- if (!single_buffer ) {
242
- dma -> second_descriptor = (DmacDescriptor * )m_malloc (sizeof (DmacDescriptor ), false);
243
- if (dma -> second_descriptor == NULL ) {
244
- return AUDIO_DMA_MEMORY_ERROR ;
245
- }
246
-
261
+ if (!dma -> single_buffer ) {
247
262
// We're likely double buffering so set up the block interrupts.
248
263
turn_on_event_system ();
249
264
dma -> event_channel = find_sync_event_channel_raise ();
@@ -280,25 +295,27 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
280
295
int irq = EVSYS_IRQn ;
281
296
#endif
282
297
283
- DmacDescriptor * first_descriptor = dma_descriptor (dma_channel );
284
- setup_audio_descriptor (first_descriptor , dma -> beat_size , output_spacing , output_register_address );
285
- if (single_buffer ) {
286
- first_descriptor -> DESCADDR .reg = 0 ;
298
+ setup_audio_descriptor (dma -> descriptor [0 ], dma -> beat_size , output_spacing , output_register_address );
299
+ if (dma -> single_buffer ) {
300
+ dma -> descriptor [0 ]-> DESCADDR .reg = 0 ;
287
301
if (dma -> loop ) {
288
- first_descriptor -> DESCADDR .reg = (uint32_t )first_descriptor ;
302
+ // The descriptor chains to itself.
303
+ dma -> descriptor [0 ]-> DESCADDR .reg = (uint32_t )dma -> descriptor [0 ];
289
304
}
290
305
} else {
291
- first_descriptor -> DESCADDR .reg = (uint32_t )dma -> second_descriptor ;
292
- setup_audio_descriptor (dma -> second_descriptor , dma -> beat_size , output_spacing , output_register_address );
293
- dma -> second_descriptor -> DESCADDR .reg = (uint32_t )first_descriptor ;
306
+ // Set up the two descriptors to chain to each other.
307
+ dma -> descriptor [0 ]-> DESCADDR .reg = (uint32_t )dma -> descriptor [1 ];
308
+ setup_audio_descriptor (dma -> descriptor [1 ], dma -> beat_size , output_spacing , output_register_address );
309
+ dma -> descriptor [1 ]-> DESCADDR .reg = (uint32_t )dma -> descriptor [0 ];
294
310
}
295
311
296
312
// Load the first two blocks up front.
297
- audio_dma_load_next_block (dma );
298
- if (!single_buffer ) {
299
- audio_dma_load_next_block (dma );
313
+ audio_dma_load_next_block (dma , 0 );
314
+ if (!dma -> single_buffer ) {
315
+ audio_dma_load_next_block (dma , 1 );
300
316
}
301
317
318
+ dma -> playing_in_progress = true;
302
319
dma_configure (dma_channel , dma_trigger_source , true);
303
320
audio_dma_enable_channel (dma_channel );
304
321
@@ -317,6 +334,7 @@ void audio_dma_stop(audio_dma_t *dma) {
317
334
dma_free_channel (dma -> dma_channel );
318
335
}
319
336
dma -> dma_channel = AUDIO_DMA_CHANNEL_COUNT ;
337
+ dma -> playing_in_progress = false;
320
338
}
321
339
322
340
void audio_dma_pause (audio_dma_t * dma ) {
@@ -355,12 +373,7 @@ bool audio_dma_get_playing(audio_dma_t *dma) {
355
373
if (dma -> dma_channel >= AUDIO_DMA_CHANNEL_COUNT ) {
356
374
return false;
357
375
}
358
- uint32_t status = dma_transfer_status (dma -> dma_channel );
359
- if ((status & DMAC_CHINTFLAG_TCMPL ) != 0 || (status & DMAC_CHINTFLAG_TERR ) != 0 ) {
360
- audio_dma_stop (dma );
361
- }
362
-
363
- return (status & DMAC_CHINTFLAG_TERR ) == 0 ;
376
+ return dma -> playing_in_progress ;
364
377
}
365
378
366
379
// WARN(tannewt): DO NOT print from here, or anything it calls. Printing calls
@@ -371,7 +384,16 @@ STATIC void dma_callback_fun(void *arg) {
371
384
return ;
372
385
}
373
386
374
- audio_dma_load_next_block (dma );
387
+ common_hal_mcu_disable_interrupts ();
388
+ uint8_t buffer_to_load = dma -> buffer_to_load ;
389
+ dma -> buffer_to_load = NO_BUFFER_TO_LOAD ;
390
+ common_hal_mcu_enable_interrupts ();
391
+
392
+ if (buffer_to_load == NO_BUFFER_TO_LOAD ) {
393
+ audio_dma_stop (dma );
394
+ } else {
395
+ audio_dma_load_next_block (dma , buffer_to_load );
396
+ }
375
397
}
376
398
377
399
void audio_evsys_handler (void ) {
@@ -384,6 +406,28 @@ void audio_evsys_handler(void) {
384
406
if (!block_done ) {
385
407
continue ;
386
408
}
409
+
410
+ // By the time we get here, the write-back descriptor has been set to the
411
+ // current running descriptor. Fill the buffer that the next chained descriptor
412
+ // will play.
413
+ //
414
+ // The state of the write-back descriptor was determined empirically,
415
+ // The datasheet appears to imply that the descriptor that just finished would
416
+ // be in the write-back descriptor. But the VALID bit is set in the write-back descriptor,
417
+ // and reversing which buffer to fill produces crackly output. So the choice
418
+ // of which buffer to fill here appears correct.
419
+ DmacDescriptor * next_descriptor =
420
+ (DmacDescriptor * )dma_write_back_descriptor (dma -> dma_channel )-> DESCADDR .reg ;
421
+ if (next_descriptor == dma -> descriptor [0 ]) {
422
+ dma -> buffer_to_load = 0 ;
423
+ } else if (next_descriptor == dma -> descriptor [1 ]) {
424
+ dma -> buffer_to_load = 1 ;
425
+ } else if (next_descriptor == NULL ) {
426
+ dma -> buffer_to_load = NO_BUFFER_TO_LOAD ;
427
+ } else {
428
+ continue ;
429
+ }
430
+
387
431
background_callback_add (& dma -> callback , dma_callback_fun , (void * )dma );
388
432
}
389
433
}
0 commit comments