@@ -49,11 +49,9 @@ extern uint8_t timer_refcount[TC_INST_NUM + TCC_INST_NUM];
49
49
extern const uint16_t prescaler [8 ];
50
50
51
51
// This timer is shared amongst all AudioOut objects under the assumption that
52
- // the code is single threaded.
53
- static struct tc_module * tc_instance ;
54
- static struct dac_module * dac_instance ;
55
- static struct events_resource * tc_event ;
56
- static struct events_resource * dac_event ;
52
+ // the code is single threaded. The audioout_tc_instance, audioout_dac_instance,
53
+ // audioout_tc_event, and audioout_dac_event pointers live in
54
+ // MICROPY_PORT_ROOT_POINTERS so they don't get garbage collected.
57
55
58
56
// The AudioOut object is being currently played. Only it can pause the timer
59
57
// and change its frequency.
@@ -62,25 +60,22 @@ static audioio_audioout_obj_t* active_audioout;
62
60
static uint8_t refcount = 0 ;
63
61
64
62
void audioout_reset (void ) {
65
- // Only reset DMA. PWMOut will reset the timer.
63
+ // Only reset DMA. PWMOut will reset the timer. Other code will reset the DAC.
66
64
refcount = 0 ;
67
- tc_instance = NULL ;
68
- if (dac_instance != NULL ) {
69
- dac_reset (dac_instance );
70
- }
71
- dac_instance = NULL ;
65
+ MP_STATE_VM (audioout_tc_instance ) = NULL ;
66
+ MP_STATE_VM (audioout_dac_instance ) = NULL ;
72
67
73
- if (tc_event != NULL ) {
74
- events_detach_user (tc_event , EVSYS_ID_USER_DAC_START );
75
- events_release (tc_event );
68
+ if (MP_STATE_VM ( audioout_tc_event ) != NULL ) {
69
+ events_detach_user (MP_STATE_VM ( audioout_tc_event ) , EVSYS_ID_USER_DAC_START );
70
+ events_release (MP_STATE_VM ( audioout_tc_event ) );
76
71
}
77
- tc_event = NULL ;
72
+ MP_STATE_VM ( audioout_tc_event ) = NULL ;
78
73
79
- if (dac_event != NULL ) {
80
- events_detach_user (dac_event , EVSYS_ID_USER_DMAC_CH_0 );
81
- events_release (dac_event );
74
+ if (MP_STATE_VM ( audioout_dac_event ) != NULL ) {
75
+ events_detach_user (MP_STATE_VM ( audioout_dac_event ) , EVSYS_ID_USER_DMAC_CH_0 );
76
+ events_release (MP_STATE_VM ( audioout_dac_event ) );
82
77
}
83
- dac_event = NULL ;
78
+ MP_STATE_VM ( audioout_dac_event ) = NULL ;
84
79
85
80
dma_abort_job (& audio_dma );
86
81
}
@@ -90,16 +85,16 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t*
90
85
91
86
// Configure the DAC to output on input event and to output an empty event
92
87
// that triggers the DMA to load the next sample.
93
- dac_instance = gc_alloc (sizeof (struct dac_module ), false);
94
- if (dac_instance == NULL ) {
88
+ MP_STATE_VM ( audioout_dac_instance ) = gc_alloc (sizeof (struct dac_module ), false);
89
+ if (MP_STATE_VM ( audioout_dac_instance ) == NULL ) {
95
90
mp_raise_msg (& mp_type_MemoryError , "" );
96
91
}
97
92
struct dac_config config_dac ;
98
93
dac_get_config_defaults (& config_dac );
99
94
config_dac .left_adjust = true;
100
95
config_dac .reference = DAC_REFERENCE_AVCC ;
101
96
config_dac .clock_source = GCLK_GENERATOR_0 ;
102
- enum status_code status = dac_init (dac_instance , DAC , & config_dac );
97
+ enum status_code status = dac_init (MP_STATE_VM ( audioout_dac_instance ) , DAC , & config_dac );
103
98
if (status != STATUS_OK ) {
104
99
common_hal_audioio_audioout_deinit (self );
105
100
mp_raise_OSError (MP_EIO );
@@ -108,14 +103,12 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t*
108
103
109
104
struct dac_chan_config channel_config ;
110
105
dac_chan_get_config_defaults (& channel_config );
111
- dac_chan_set_config (dac_instance , DAC_CHANNEL_0 , & channel_config );
112
- dac_chan_enable (dac_instance , DAC_CHANNEL_0 );
106
+ dac_chan_set_config (MP_STATE_VM ( audioout_dac_instance ) , DAC_CHANNEL_0 , & channel_config );
107
+ dac_chan_enable (MP_STATE_VM ( audioout_dac_instance ) , DAC_CHANNEL_0 );
113
108
114
109
struct dac_events events_dac = { .generate_event_on_buffer_empty = true,
115
110
.on_event_start_conversion = true };
116
- dac_enable_events (dac_instance , & events_dac );
117
-
118
- dac_enable (dac_instance );
111
+ dac_enable_events (MP_STATE_VM (audioout_dac_instance ), & events_dac );
119
112
120
113
// Figure out which timer we are using.
121
114
Tc * t = NULL ;
@@ -131,37 +124,37 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t*
131
124
mp_raise_RuntimeError ("All timers in use" );
132
125
return ;
133
126
}
134
- tc_instance = gc_alloc (sizeof (struct tc_module ), false);
135
- if (tc_instance == NULL ) {
127
+ MP_STATE_VM ( audioout_tc_instance ) = gc_alloc (sizeof (struct tc_module ), false);
128
+ if (MP_STATE_VM ( audioout_tc_instance ) == NULL ) {
136
129
common_hal_audioio_audioout_deinit (self );
137
130
mp_raise_msg (& mp_type_MemoryError , "" );
138
131
}
139
132
140
133
// Don't bother setting the period. We set it before you playback anything.
141
134
struct tc_config config_tc ;
142
135
tc_get_config_defaults (& config_tc );
143
-
144
136
config_tc .counter_size = TC_COUNTER_SIZE_16BIT ;
145
137
config_tc .clock_prescaler = TC_CLOCK_PRESCALER_DIV1 ;
146
138
config_tc .wave_generation = TC_WAVE_GENERATION_MATCH_FREQ ;
147
- if (tc_init (tc_instance , t , & config_tc ) != STATUS_OK ) {
139
+ if (tc_init (MP_STATE_VM ( audioout_tc_instance ) , t , & config_tc ) != STATUS_OK ) {
148
140
common_hal_audioio_audioout_deinit (self );
149
- mp_printf (& mp_plat_print , "tc \n" );
150
141
mp_raise_OSError (MP_EIO );
151
142
return ;
152
143
};
153
144
154
145
struct tc_events events_tc ;
155
146
events_tc .generate_event_on_overflow = true;
156
- tc_enable_events (tc_instance , & events_tc );
147
+ events_tc .on_event_perform_action = false;
148
+ events_tc .event_action = TC_EVENT_ACTION_OFF ;
149
+ tc_enable_events (MP_STATE_VM (audioout_tc_instance ), & events_tc );
157
150
158
- tc_enable (tc_instance );
159
- tc_stop_counter (tc_instance );
151
+ tc_enable (MP_STATE_VM ( audioout_tc_instance ) );
152
+ tc_stop_counter (MP_STATE_VM ( audioout_tc_instance ) );
160
153
161
154
// Connect the timer overflow event, which happens at the target frequency,
162
155
// to the DAC conversion trigger.
163
- tc_event = gc_alloc (sizeof (struct events_resource ), false);
164
- if (tc_event == NULL ) {
156
+ MP_STATE_VM ( audioout_tc_event ) = gc_alloc (sizeof (struct events_resource ), false);
157
+ if (MP_STATE_VM ( audioout_tc_event ) == NULL ) {
165
158
common_hal_audioio_audioout_deinit (self );
166
159
mp_raise_msg (& mp_type_MemoryError , "" );
167
160
}
@@ -185,24 +178,24 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t*
185
178
186
179
config .generator = generator ;
187
180
config .path = EVENTS_PATH_ASYNCHRONOUS ;
188
- if (events_allocate (tc_event , & config ) != STATUS_OK ||
189
- events_attach_user (tc_event , EVSYS_ID_USER_DAC_START ) != STATUS_OK ) {
181
+ if (events_allocate (MP_STATE_VM ( audioout_tc_event ) , & config ) != STATUS_OK ||
182
+ events_attach_user (MP_STATE_VM ( audioout_tc_event ) , EVSYS_ID_USER_DAC_START ) != STATUS_OK ) {
190
183
common_hal_audioio_audioout_deinit (self );
191
184
mp_raise_OSError (MP_EIO );
192
185
return ;
193
186
}
194
187
195
188
// Connect the DAC to DMA
196
- dac_event = gc_alloc (sizeof (struct events_resource ), false);
197
- if (dac_event == NULL ) {
189
+ MP_STATE_VM ( audioout_dac_event ) = gc_alloc (sizeof (struct events_resource ), false);
190
+ if (MP_STATE_VM ( audioout_dac_event ) == NULL ) {
198
191
common_hal_audioio_audioout_deinit (self );
199
192
mp_raise_msg (& mp_type_MemoryError , "" );
200
193
}
201
194
events_get_config_defaults (& config );
202
195
config .generator = EVSYS_ID_GEN_DAC_EMPTY ;
203
196
config .path = EVENTS_PATH_ASYNCHRONOUS ;
204
- if (events_allocate (dac_event , & config ) != STATUS_OK ||
205
- events_attach_user (dac_event , EVSYS_ID_USER_DMAC_CH_0 ) != STATUS_OK ) {
197
+ if (events_allocate (MP_STATE_VM ( audioout_dac_event ) , & config ) != STATUS_OK ||
198
+ events_attach_user (MP_STATE_VM ( audioout_dac_event ) , EVSYS_ID_USER_DMAC_CH_0 ) != STATUS_OK ) {
206
199
common_hal_audioio_audioout_deinit (self );
207
200
mp_raise_OSError (MP_EIO );
208
201
return ;
@@ -239,26 +232,26 @@ void common_hal_audioio_audioout_construct_from_file(audioio_audioout_obj_t* sel
239
232
void common_hal_audioio_audioout_deinit (audioio_audioout_obj_t * self ) {
240
233
refcount -- ;
241
234
if (refcount == 0 ) {
242
- if (tc_instance != NULL ) {
243
- tc_reset (tc_instance );
244
- gc_free (tc_instance );
245
- tc_instance = NULL ;
235
+ if (MP_STATE_VM ( audioout_tc_instance ) != NULL ) {
236
+ tc_reset (MP_STATE_VM ( audioout_tc_instance ) );
237
+ gc_free (MP_STATE_VM ( audioout_tc_instance ) );
238
+ MP_STATE_VM ( audioout_tc_instance ) = NULL ;
246
239
}
247
- if (dac_instance != NULL ) {
248
- dac_reset (dac_instance );
249
- gc_free (dac_instance );
250
- dac_instance = NULL ;
240
+ if (MP_STATE_VM ( audioout_dac_instance ) != NULL ) {
241
+ dac_reset (MP_STATE_VM ( audioout_dac_instance ) );
242
+ gc_free (MP_STATE_VM ( audioout_dac_instance ) );
243
+ MP_STATE_VM ( audioout_dac_instance ) = NULL ;
251
244
}
252
- if (tc_event != NULL ) {
253
- events_detach_user (tc_event , EVSYS_ID_USER_DAC_START );
254
- events_release (tc_event );
255
- gc_free (tc_event );
256
- tc_event = NULL ;
245
+ if (MP_STATE_VM ( audioout_tc_event ) != NULL ) {
246
+ events_detach_user (MP_STATE_VM ( audioout_tc_event ) , EVSYS_ID_USER_DAC_START );
247
+ events_release (MP_STATE_VM ( audioout_tc_event ) );
248
+ gc_free (MP_STATE_VM ( audioout_tc_event ) );
249
+ MP_STATE_VM ( audioout_tc_event ) = NULL ;
257
250
}
258
- if (dac_event != NULL ) {
259
- events_release (dac_event );
260
- gc_free (dac_event );
261
- dac_event = NULL ;
251
+ if (MP_STATE_VM ( audioout_dac_event ) != NULL ) {
252
+ events_release (MP_STATE_VM ( audioout_dac_event ) );
253
+ gc_free (MP_STATE_VM ( audioout_dac_event ) );
254
+ MP_STATE_VM ( audioout_dac_event ) = NULL ;
262
255
}
263
256
reset_pin (self -> pin -> pin );
264
257
}
@@ -274,17 +267,17 @@ static void set_timer_frequency(uint32_t frequency) {
274
267
break ;
275
268
}
276
269
}
277
- uint8_t old_divisor = tc_instance -> hw -> COUNT16 .CTRLA .bit .PRESCALER ;
270
+ uint8_t old_divisor = MP_STATE_VM ( audioout_tc_instance ) -> hw -> COUNT16 .CTRLA .bit .PRESCALER ;
278
271
if (new_divisor != old_divisor ) {
279
- tc_disable (tc_instance );
280
- tc_instance -> hw -> COUNT16 .CTRLA .bit .PRESCALER = new_divisor ;
281
- tc_enable (tc_instance );
272
+ tc_disable (MP_STATE_VM ( audioout_tc_instance ) );
273
+ MP_STATE_VM ( audioout_tc_instance ) -> hw -> COUNT16 .CTRLA .bit .PRESCALER = new_divisor ;
274
+ tc_enable (MP_STATE_VM ( audioout_tc_instance ) );
282
275
}
283
- while (tc_is_syncing (tc_instance )) {
276
+ while (tc_is_syncing (MP_STATE_VM ( audioout_tc_instance ) )) {
284
277
/* Wait for sync */
285
278
}
286
- tc_instance -> hw -> COUNT16 .CC [0 ].reg = new_top ;
287
- while (tc_is_syncing (tc_instance )) {
279
+ MP_STATE_VM ( audioout_tc_instance ) -> hw -> COUNT16 .CC [0 ].reg = new_top ;
280
+ while (tc_is_syncing (MP_STATE_VM ( audioout_tc_instance ) )) {
288
281
/* Wait for sync */
289
282
}
290
283
}
@@ -293,8 +286,10 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t* self, bool loop) {
293
286
common_hal_audioio_audioout_get_playing (self );
294
287
// Shut down any active playback.
295
288
if (active_audioout != NULL ) {
296
- tc_stop_counter (tc_instance );
289
+ tc_stop_counter (MP_STATE_VM ( audioout_tc_instance ) );
297
290
dma_abort_job (& audio_dma );
291
+ } else {
292
+ dac_enable (MP_STATE_VM (audioout_dac_instance ));
298
293
}
299
294
struct dma_descriptor_config descriptor_config ;
300
295
dma_descriptor_get_config_defaults (& descriptor_config );
@@ -314,15 +309,15 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t* self, bool loop) {
314
309
dma_start_transfer_job (& audio_dma );
315
310
316
311
set_timer_frequency (self -> frequency );
317
- tc_start_counter (tc_instance );
312
+ tc_start_counter (MP_STATE_VM ( audioout_tc_instance ) );
318
313
}
319
314
320
315
void common_hal_audioio_audioout_stop (audioio_audioout_obj_t * self ) {
321
316
if (common_hal_audioio_audioout_get_playing (self )) {
322
- tc_stop_counter (tc_instance );
317
+ tc_stop_counter (MP_STATE_VM ( audioout_tc_instance ) );
323
318
dma_abort_job (& audio_dma );
324
319
active_audioout = NULL ;
325
- // TODO(tannewt): Disable the DAC to save power.
320
+ dac_disable ( MP_STATE_VM ( audioout_dac_instance ));
326
321
}
327
322
}
328
323
0 commit comments