3333#include "py/runtime.h"
3434#include "common-hal/audioio/AudioOut.h"
3535#include "shared-bindings/audioio/AudioOut.h"
36+ #include "shared-bindings/microcontroller/__init__.h"
3637#include "shared-bindings/microcontroller/Pin.h"
3738#include "supervisor/shared/translate.h"
3839
5253#include "samd/pins.h"
5354#include "samd/timers.h"
5455
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+
55103void 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.
56119}
57120
58121void 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 ) {
60123 #ifdef SAMD51
61124 bool dac_clock_enabled = hri_mclk_get_APBDMASK_DAC_bit (MCLK );
62125 #endif
@@ -94,12 +157,10 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t* self,
94157 if (right_channel != NULL ) {
95158 claim_pin (right_channel );
96159 self -> right_channel = right_channel ;
97- gpio_set_pin_function (self -> right_channel -> number , GPIO_PIN_FUNCTION_B );
98160 audio_dma_init (& self -> right_dma );
99161 }
100162 #endif
101163 self -> left_channel = left_channel ;
102- gpio_set_pin_function (self -> left_channel -> number , GPIO_PIN_FUNCTION_B );
103164 audio_dma_init (& self -> left_dma );
104165
105166 #ifdef SAMD51
@@ -118,6 +179,10 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t* self,
118179
119180 DAC -> CTRLA .bit .SWRST = 1 ;
120181 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
121186
122187 bool channel0_enabled = true;
123188 #ifdef SAMD51
@@ -159,6 +224,8 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t* self,
159224 #endif
160225 #ifdef SAMD51
161226 while (DAC -> SYNCBUSY .bit .ENABLE == 1 ) {}
227+ while (channel0_enabled && DAC -> STATUS .bit .READY0 == 0 ) {}
228+ while (channel1_enabled && DAC -> STATUS .bit .READY1 == 0 ) {}
162229 #endif
163230
164231 // Use a timer to coordinate when DAC conversions occur.
@@ -220,13 +287,21 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t* self,
220287
221288 #ifdef SAMD51
222289 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+ }
223293 #define EVSYS_ID_USER_DAC_START EVSYS_ID_USER_DAC_START_0
224294 #endif
225295 connect_event_user_to_channel (EVSYS_ID_USER_DAC_START , channel );
296+ gpio_set_pin_function (self -> left_channel -> number , GPIO_PIN_FUNCTION_B );
226297 init_async_event_channel (channel , tc_gen_id );
227298
228299 self -> tc_to_dac_event_channel = channel ;
229300
301+ // Ramp the DAC up.
302+ self -> quiescent_value = quiescent_value ;
303+ ramp_value (0 , quiescent_value );
304+
230305 // Leave the DMA setup to playback.
231306}
232307
@@ -239,6 +314,9 @@ void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t* self) {
239314 return ;
240315 }
241316
317+ // Ramp the DAC down.
318+ ramp_value (self -> quiescent_value , 0 );
319+
242320 DAC -> CTRLA .bit .ENABLE = 0 ;
243321 #ifdef SAMD21
244322 while (DAC -> STATUS .bit .SYNCBUSY == 1 ) {}
@@ -381,6 +459,9 @@ void common_hal_audioio_audioout_stop(audioio_audioout_obj_t* self) {
381459 #ifdef SAMD51
382460 audio_dma_stop (& self -> right_dma );
383461 #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 );
384465}
385466
386467bool common_hal_audioio_audioout_get_playing (audioio_audioout_obj_t * self ) {
0 commit comments