2424 * THE SOFTWARE.
2525 */
2626
27+ #include <string.h>
28+
2729#include "audio_dma.h"
2830#include "samd/clocks.h"
2931#include "samd/events.h"
3032#include "samd/dma.h"
3133
3234#include "shared-bindings/audiocore/RawSample.h"
3335#include "shared-bindings/audiocore/WaveFile.h"
36+ #include "shared-bindings/microcontroller/__init__.h"
3437#include "supervisor/background_callback.h"
3538
3639#include "py/mpstate.h"
3740#include "py/runtime.h"
3841
3942#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
4043
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+
4148static audio_dma_t * audio_dma_state [AUDIO_DMA_CHANNEL_COUNT ];
4249
4350// This cannot be in audio_dma_state because it's volatile.
@@ -85,70 +92,79 @@ void audio_dma_enable_channel(uint8_t channel) {
8592 dma_enable_channel (channel );
8693}
8794
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 ,
90100 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- }
96101 #pragma GCC diagnostic push
97102 #pragma GCC diagnostic ignored "-Wcast-align"
98103 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 ;
100109 * output_spacing = 1 ;
110+
111+ if (* output_length > available_output_buffer_length ) {
112+ mp_raise_RuntimeError (translate ("Internal audio buffer too small" ));
113+ }
114+
101115 uint32_t out_i = 0 ;
102116 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 ) {
104118 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 ;
106120 } else {
107- ((int8_t * )* output_buffer )[out_i ] = ((uint8_t * )buffer )[i ] - 0x80 ;
121+ ((int8_t * )* output )[out_i ] = ((uint8_t * )input )[i ] - 0x80 ;
108122 }
109123 out_i += 1 ;
110124 }
111125 } 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 ) {
113127 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 ;
115129 } else {
116- ((int16_t * )* output_buffer )[out_i ] = ((uint16_t * )buffer )[i ] - 0x8000 ;
130+ ((int16_t * )* output )[out_i ] = ((uint16_t * )input )[i ] - 0x8000 ;
117131 }
118132 out_i += 1 ;
119133 }
120134 }
121135 } else {
122- * output_buffer = buffer ;
123- * output_buffer_length = buffer_length ;
136+ * output = input ;
137+ * output_length = input_length ;
124138 * output_spacing = dma -> spacing ;
125139 }
126140 #pragma GCC diagnostic pop
127- dma -> first_buffer_free = !dma -> first_buffer_free ;
128141}
129142
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 ;
133146 audioio_get_buffer_result_t get_buffer_result =
134147 audiosample_get_buffer (dma -> sample , dma -> single_channel_output , dma -> audio_channel ,
135- & buffer , & buffer_length );
148+ & sample_buffer , & sample_buffer_length );
136149
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 ];
142151
143152 if (get_buffer_result == GET_BUFFER_ERROR ) {
144153 audio_dma_stop (dma );
145154 return ;
146155 }
147156
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.
148159 uint8_t * output_buffer ;
149160 uint32_t output_buffer_length ;
150161 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 ,
152168 & output_spacing );
153169
154170 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) {
157173 if (dma -> loop ) {
158174 audiosample_reset_buffer (dma -> sample , dma -> single_channel_output , dma -> audio_channel );
159175 } else {
160- if (( output_buffer_length == 0 ) && dma_transfer_status ( SHARED_RX_CHANNEL ) & 0x3 ) {
176+ if (output_buffer_length == 0 ) {
161177 // Nothing further to read and previous buffer is finished.
162178 audio_dma_stop (dma );
179+ return ;
163180 } else {
164181 // Break descriptor chain.
165182 descriptor -> DESCADDR .reg = 0 ;
@@ -206,30 +223,33 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
206223 dma -> dma_channel = dma_channel ;
207224 dma -> signed_to_unsigned = false;
208225 dma -> unsigned_to_signed = false;
209- dma -> second_descriptor = NULL ;
210226 dma -> spacing = 1 ;
211- dma -> first_descriptor_free = true;
212227 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 ;
213231
214- bool single_buffer ;
215232 bool samples_signed ;
216233 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 ,
218235 & max_buffer_length , & dma -> spacing );
219236 uint8_t output_spacing = dma -> spacing ;
220237 if (output_signed != samples_signed ) {
221238 output_spacing = 1 ;
222239 max_buffer_length /= dma -> spacing ;
223240 }
224241
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 ) {
227246 return AUDIO_DMA_MEMORY_ERROR ;
228247 }
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 ) {
233253 return AUDIO_DMA_MEMORY_ERROR ;
234254 }
235255 }
@@ -238,12 +258,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
238258 dma -> unsigned_to_signed = output_signed && !samples_signed ;
239259
240260 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 ) {
247262 // We're likely double buffering so set up the block interrupts.
248263 turn_on_event_system ();
249264 dma -> event_channel = find_sync_event_channel_raise ();
@@ -280,25 +295,27 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
280295 int irq = EVSYS_IRQn ;
281296 #endif
282297
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 ;
287301 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 ];
289304 }
290305 } 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 ];
294310 }
295311
296312 // 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 );
300316 }
301317
318+ dma -> playing_in_progress = true;
302319 dma_configure (dma_channel , dma_trigger_source , true);
303320 audio_dma_enable_channel (dma_channel );
304321
@@ -317,6 +334,7 @@ void audio_dma_stop(audio_dma_t *dma) {
317334 dma_free_channel (dma -> dma_channel );
318335 }
319336 dma -> dma_channel = AUDIO_DMA_CHANNEL_COUNT ;
337+ dma -> playing_in_progress = false;
320338}
321339
322340void audio_dma_pause (audio_dma_t * dma ) {
@@ -355,12 +373,7 @@ bool audio_dma_get_playing(audio_dma_t *dma) {
355373 if (dma -> dma_channel >= AUDIO_DMA_CHANNEL_COUNT ) {
356374 return false;
357375 }
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 ;
364377}
365378
366379// WARN(tannewt): DO NOT print from here, or anything it calls. Printing calls
@@ -371,7 +384,16 @@ STATIC void dma_callback_fun(void *arg) {
371384 return ;
372385 }
373386
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+ }
375397}
376398
377399void audio_evsys_handler (void ) {
@@ -384,6 +406,28 @@ void audio_evsys_handler(void) {
384406 if (!block_done ) {
385407 continue ;
386408 }
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+
387431 background_callback_add (& dma -> callback , dma_callback_fun , (void * )dma );
388432 }
389433}
0 commit comments