33
33
#include "py/runtime.h"
34
34
#include "common-hal/audioio/AudioOut.h"
35
35
#include "shared-bindings/audioio/AudioOut.h"
36
+ #include "shared-bindings/microcontroller/__init__.h"
36
37
#include "shared-bindings/microcontroller/Pin.h"
37
38
#include "supervisor/shared/translate.h"
38
39
52
53
#include "samd/pins.h"
53
54
#include "samd/timers.h"
54
55
56
+ #ifdef SAMD21
57
+ static void ramp_value (uint16_t start , uint16_t end ) {
58
+ start = DAC -> DATA .reg ;
59
+ int32_t diff = (int32_t ) end - start ;
60
+ int32_t step = 49 ;
61
+ int32_t steps = diff / step ;
62
+ if (diff < 0 ) {
63
+ steps = - steps ;
64
+ step = - step ;
65
+ }
66
+ for (int32_t i = 0 ; i < steps ; i ++ ) {
67
+ uint32_t value = start + step * i ;
68
+ DAC -> DATA .reg = value ;
69
+ DAC -> DATABUF .reg = value ;
70
+ common_hal_mcu_delay_us (50 );
71
+ #ifdef MICROPY_VM_HOOK_LOOP
72
+ MICROPY_VM_HOOK_LOOP
73
+ #endif
74
+ }
75
+ }
76
+ #endif
77
+
78
+ #ifdef SAMD51
79
+ static void ramp_value (uint16_t start , uint16_t end ) {
80
+ int32_t diff = (int32_t ) end - start ;
81
+ int32_t step = 49 ;
82
+ int32_t steps = diff / step ;
83
+ if (diff < 0 ) {
84
+ steps = - steps ;
85
+ step = - step ;
86
+ }
87
+
88
+ for (int32_t i = 0 ; i < steps ; i ++ ) {
89
+ uint16_t value = start + step * i ;
90
+ DAC -> DATA [0 ].reg = value ;
91
+ DAC -> DATABUF [0 ].reg = value ;
92
+ DAC -> DATA [1 ].reg = value ;
93
+ DAC -> DATABUF [1 ].reg = value ;
94
+
95
+ common_hal_mcu_delay_us (50 );
96
+ #ifdef MICROPY_VM_HOOK_LOOP
97
+ MICROPY_VM_HOOK_LOOP
98
+ #endif
99
+ }
100
+ }
101
+ #endif
102
+
55
103
void audioout_reset (void ) {
104
+ #if defined(SAMD21 ) && !defined(PIN_PA02 )
105
+ return ;
106
+ #endif
107
+ #ifdef SAMD21
108
+ while (DAC -> STATUS .reg & DAC_STATUS_SYNCBUSY ) {}
109
+ #endif
110
+ #ifdef SAMD51
111
+ while (DAC -> SYNCBUSY .reg & DAC_SYNCBUSY_SWRST ) {}
112
+ #endif
113
+ if (DAC -> CTRLA .bit .ENABLE ) {
114
+ ramp_value (0x8000 , 0 );
115
+ }
116
+ DAC -> CTRLA .reg |= DAC_CTRLA_SWRST ;
117
+
118
+ // TODO(tannewt): Turn off the DAC clocks to save power.
56
119
}
57
120
58
121
void common_hal_audioio_audioout_construct (audioio_audioout_obj_t * self ,
59
- const mcu_pin_obj_t * left_channel , const mcu_pin_obj_t * right_channel ) {
122
+ const mcu_pin_obj_t * left_channel , const mcu_pin_obj_t * right_channel , uint16_t quiescent_value ) {
60
123
#ifdef SAMD51
61
124
bool dac_clock_enabled = hri_mclk_get_APBDMASK_DAC_bit (MCLK );
62
125
#endif
@@ -94,12 +157,10 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t* self,
94
157
if (right_channel != NULL ) {
95
158
claim_pin (right_channel );
96
159
self -> right_channel = right_channel ;
97
- gpio_set_pin_function (self -> right_channel -> number , GPIO_PIN_FUNCTION_B );
98
160
audio_dma_init (& self -> right_dma );
99
161
}
100
162
#endif
101
163
self -> left_channel = left_channel ;
102
- gpio_set_pin_function (self -> left_channel -> number , GPIO_PIN_FUNCTION_B );
103
164
audio_dma_init (& self -> left_dma );
104
165
105
166
#ifdef SAMD51
@@ -118,6 +179,10 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t* self,
118
179
119
180
DAC -> CTRLA .bit .SWRST = 1 ;
120
181
while (DAC -> CTRLA .bit .SWRST == 1 ) {}
182
+ // Make sure there are no outstanding access errors. (Reading DATA can cause this.)
183
+ #ifdef SAMD51
184
+ PAC -> INTFLAGD .reg = PAC_INTFLAGD_DAC ;
185
+ #endif
121
186
122
187
bool channel0_enabled = true;
123
188
#ifdef SAMD51
@@ -159,6 +224,8 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t* self,
159
224
#endif
160
225
#ifdef SAMD51
161
226
while (DAC -> SYNCBUSY .bit .ENABLE == 1 ) {}
227
+ while (channel0_enabled && DAC -> STATUS .bit .READY0 == 0 ) {}
228
+ while (channel1_enabled && DAC -> STATUS .bit .READY1 == 0 ) {}
162
229
#endif
163
230
164
231
// Use a timer to coordinate when DAC conversions occur.
@@ -220,13 +287,21 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t* self,
220
287
221
288
#ifdef SAMD51
222
289
connect_event_user_to_channel (EVSYS_ID_USER_DAC_START_1 , channel );
290
+ if (right_channel != NULL ) {
291
+ gpio_set_pin_function (self -> right_channel -> number , GPIO_PIN_FUNCTION_B );
292
+ }
223
293
#define EVSYS_ID_USER_DAC_START EVSYS_ID_USER_DAC_START_0
224
294
#endif
225
295
connect_event_user_to_channel (EVSYS_ID_USER_DAC_START , channel );
296
+ gpio_set_pin_function (self -> left_channel -> number , GPIO_PIN_FUNCTION_B );
226
297
init_async_event_channel (channel , tc_gen_id );
227
298
228
299
self -> tc_to_dac_event_channel = channel ;
229
300
301
+ // Ramp the DAC up.
302
+ self -> quiescent_value = quiescent_value ;
303
+ ramp_value (0 , quiescent_value );
304
+
230
305
// Leave the DMA setup to playback.
231
306
}
232
307
@@ -239,6 +314,9 @@ void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t* self) {
239
314
return ;
240
315
}
241
316
317
+ // Ramp the DAC down.
318
+ ramp_value (self -> quiescent_value , 0 );
319
+
242
320
DAC -> CTRLA .bit .ENABLE = 0 ;
243
321
#ifdef SAMD21
244
322
while (DAC -> STATUS .bit .SYNCBUSY == 1 ) {}
@@ -381,6 +459,9 @@ void common_hal_audioio_audioout_stop(audioio_audioout_obj_t* self) {
381
459
#ifdef SAMD51
382
460
audio_dma_stop (& self -> right_dma );
383
461
#endif
462
+ // Ramp the DAC to default. The start is ignored when the current value can be readback.
463
+ // Otherwise, we just set it immediately.
464
+ ramp_value (self -> quiescent_value , self -> quiescent_value );
384
465
}
385
466
386
467
bool common_hal_audioio_audioout_get_playing (audioio_audioout_obj_t * self ) {
0 commit comments