Skip to content

Commit 5ad4261

Browse files
committed
atmel-samd: Move heap objects into MICROPY_PORT_ROOT_POINTERS so they don't get garbage collected while we are using them.
1 parent 6512ccf commit 5ad4261

File tree

4 files changed

+89
-89
lines changed

4 files changed

+89
-89
lines changed

atmel-samd/boards/circuitplayground_express/pins.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ STATIC const mp_map_elem_t board_global_dict_table[] = {
9292
{ MP_OBJ_NEW_QSTR(MP_QSTR_ACCELEROMETER_SDA), (mp_obj_t)&pin_PA00 },
9393
{ MP_OBJ_NEW_QSTR(MP_QSTR_ACCELEROMETER_SCL), (mp_obj_t)&pin_PA01 },
9494

95-
{ MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER_SHUTDOWN), (mp_obj_t)&pin_PA30 },
95+
{ MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER_ENABLE), (mp_obj_t)&pin_PA30 },
9696

9797
{ MP_OBJ_NEW_QSTR(MP_QSTR_SCK), (mp_obj_t)&pin_PA21 },
9898
{ MP_OBJ_NEW_QSTR(MP_QSTR_MOSI), (mp_obj_t)&pin_PA20 },

atmel-samd/common-hal/audioio/AudioOut.c

Lines changed: 66 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,9 @@ extern uint8_t timer_refcount[TC_INST_NUM + TCC_INST_NUM];
4949
extern const uint16_t prescaler[8];
5050

5151
// 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.
5755

5856
// The AudioOut object is being currently played. Only it can pause the timer
5957
// and change its frequency.
@@ -62,25 +60,22 @@ static audioio_audioout_obj_t* active_audioout;
6260
static uint8_t refcount = 0;
6361

6462
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.
6664
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;
7267

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));
7671
}
77-
tc_event = NULL;
72+
MP_STATE_VM(audioout_tc_event) = NULL;
7873

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));
8277
}
83-
dac_event = NULL;
78+
MP_STATE_VM(audioout_dac_event) = NULL;
8479

8580
dma_abort_job(&audio_dma);
8681
}
@@ -90,16 +85,16 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t*
9085

9186
// Configure the DAC to output on input event and to output an empty event
9287
// 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) {
9590
mp_raise_msg(&mp_type_MemoryError, "");
9691
}
9792
struct dac_config config_dac;
9893
dac_get_config_defaults(&config_dac);
9994
config_dac.left_adjust = true;
10095
config_dac.reference = DAC_REFERENCE_AVCC;
10196
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);
10398
if (status != STATUS_OK) {
10499
common_hal_audioio_audioout_deinit(self);
105100
mp_raise_OSError(MP_EIO);
@@ -108,14 +103,12 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t*
108103

109104
struct dac_chan_config channel_config;
110105
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);
113108

114109
struct dac_events events_dac = { .generate_event_on_buffer_empty = true,
115110
.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);
119112

120113
// Figure out which timer we are using.
121114
Tc *t = NULL;
@@ -131,37 +124,37 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t*
131124
mp_raise_RuntimeError("All timers in use");
132125
return;
133126
}
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) {
136129
common_hal_audioio_audioout_deinit(self);
137130
mp_raise_msg(&mp_type_MemoryError, "");
138131
}
139132

140133
// Don't bother setting the period. We set it before you playback anything.
141134
struct tc_config config_tc;
142135
tc_get_config_defaults(&config_tc);
143-
144136
config_tc.counter_size = TC_COUNTER_SIZE_16BIT;
145137
config_tc.clock_prescaler = TC_CLOCK_PRESCALER_DIV1;
146138
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) {
148140
common_hal_audioio_audioout_deinit(self);
149-
mp_printf(&mp_plat_print, "tc \n");
150141
mp_raise_OSError(MP_EIO);
151142
return;
152143
};
153144

154145
struct tc_events events_tc;
155146
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);
157150

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));
160153

161154
// Connect the timer overflow event, which happens at the target frequency,
162155
// 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) {
165158
common_hal_audioio_audioout_deinit(self);
166159
mp_raise_msg(&mp_type_MemoryError, "");
167160
}
@@ -185,24 +178,24 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t*
185178

186179
config.generator = generator;
187180
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) {
190183
common_hal_audioio_audioout_deinit(self);
191184
mp_raise_OSError(MP_EIO);
192185
return;
193186
}
194187

195188
// 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) {
198191
common_hal_audioio_audioout_deinit(self);
199192
mp_raise_msg(&mp_type_MemoryError, "");
200193
}
201194
events_get_config_defaults(&config);
202195
config.generator = EVSYS_ID_GEN_DAC_EMPTY;
203196
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) {
206199
common_hal_audioio_audioout_deinit(self);
207200
mp_raise_OSError(MP_EIO);
208201
return;
@@ -239,26 +232,26 @@ void common_hal_audioio_audioout_construct_from_file(audioio_audioout_obj_t* sel
239232
void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t* self) {
240233
refcount--;
241234
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;
246239
}
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;
251244
}
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;
257250
}
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;
262255
}
263256
reset_pin(self->pin->pin);
264257
}
@@ -274,17 +267,17 @@ static void set_timer_frequency(uint32_t frequency) {
274267
break;
275268
}
276269
}
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;
278271
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));
282275
}
283-
while (tc_is_syncing(tc_instance)) {
276+
while (tc_is_syncing(MP_STATE_VM(audioout_tc_instance))) {
284277
/* Wait for sync */
285278
}
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))) {
288281
/* Wait for sync */
289282
}
290283
}
@@ -293,8 +286,10 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t* self, bool loop) {
293286
common_hal_audioio_audioout_get_playing(self);
294287
// Shut down any active playback.
295288
if (active_audioout != NULL) {
296-
tc_stop_counter(tc_instance);
289+
tc_stop_counter(MP_STATE_VM(audioout_tc_instance));
297290
dma_abort_job(&audio_dma);
291+
} else {
292+
dac_enable(MP_STATE_VM(audioout_dac_instance));
298293
}
299294
struct dma_descriptor_config descriptor_config;
300295
dma_descriptor_get_config_defaults(&descriptor_config);
@@ -314,15 +309,15 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t* self, bool loop) {
314309
dma_start_transfer_job(&audio_dma);
315310

316311
set_timer_frequency(self->frequency);
317-
tc_start_counter(tc_instance);
312+
tc_start_counter(MP_STATE_VM(audioout_tc_instance));
318313
}
319314

320315
void common_hal_audioio_audioout_stop(audioio_audioout_obj_t* self) {
321316
if (common_hal_audioio_audioout_get_playing(self)) {
322-
tc_stop_counter(tc_instance);
317+
tc_stop_counter(MP_STATE_VM(audioout_tc_instance));
323318
dma_abort_job(&audio_dma);
324319
active_audioout = NULL;
325-
// TODO(tannewt): Disable the DAC to save power.
320+
dac_disable(MP_STATE_VM(audioout_dac_instance));
326321
}
327322
}
328323

atmel-samd/common-hal/pulseio/PulseOut.c

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
#undef ENABLE
4040

4141
// This timer is shared amongst all PulseOut objects under the assumption that
42-
// the code is single threaded.
43-
static struct tc_module* tc_instance;
42+
// the code is single threaded. Its stored in MICROPY_PORT_ROOT_POINTERS so it
43+
// doesn't get garbage collected.
4444
static uint8_t refcount = 0;
4545

4646
static __IO PORT_PINCFG_Type *active_pincfg = NULL;
@@ -69,15 +69,15 @@ void pulse_finish(struct tc_module *const module) {
6969
return;
7070
}
7171
current_compare = (current_compare + pulse_buffer[pulse_index] * 3 / 4) & 0xffff;
72-
tc_set_compare_value(tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, current_compare);
72+
tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare);
7373
if (pulse_index % 2 == 0) {
7474
turn_on(active_pincfg);
7575
}
7676
}
7777

7878
void pulseout_reset() {
7979
refcount = 0;
80-
tc_instance = 0;
80+
MP_STATE_VM(pulseout_tc_instance) = NULL;
8181
active_pincfg = NULL;
8282
}
8383

@@ -96,7 +96,7 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self,
9696
if (t == NULL) {
9797
mp_raise_RuntimeError("All timers in use");
9898
}
99-
tc_instance = gc_alloc(sizeof(struct tc_module), false);
99+
MP_STATE_VM(pulseout_tc_instance) = gc_alloc(sizeof(struct tc_module), false);
100100
if (t == NULL) {
101101
mp_raise_msg(&mp_type_MemoryError, "");
102102
}
@@ -108,10 +108,10 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self,
108108
config_tc.clock_prescaler = TC_CTRLA_PRESCALER_DIV64;
109109
config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_FREQ;
110110

111-
tc_init(tc_instance, t, &config_tc);
112-
tc_register_callback(tc_instance, pulse_finish, TC_CALLBACK_CC_CHANNEL0);
113-
tc_enable(tc_instance);
114-
tc_stop_counter(tc_instance);
111+
tc_init(MP_STATE_VM(pulseout_tc_instance), t, &config_tc);
112+
tc_register_callback(MP_STATE_VM(pulseout_tc_instance), pulse_finish, TC_CALLBACK_CC_CHANNEL0);
113+
tc_enable(MP_STATE_VM(pulseout_tc_instance));
114+
tc_stop_counter(MP_STATE_VM(pulseout_tc_instance));
115115
}
116116
refcount++;
117117

@@ -136,9 +136,9 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) {
136136

137137
refcount--;
138138
if (refcount == 0) {
139-
tc_reset(tc_instance);
140-
gc_free(tc_instance);
141-
tc_instance = NULL;
139+
tc_reset(MP_STATE_VM(pulseout_tc_instance));
140+
gc_free(MP_STATE_VM(pulseout_tc_instance));
141+
MP_STATE_VM(pulseout_tc_instance) = NULL;
142142
}
143143
}
144144

@@ -152,11 +152,11 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu
152152
pulse_length = length;
153153

154154
current_compare = pulses[0] * 3 / 4;
155-
tc_set_compare_value(tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, current_compare);
155+
tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare);
156156

157-
tc_enable_callback(tc_instance, TC_CALLBACK_CC_CHANNEL0);
157+
tc_enable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0);
158158
turn_on(active_pincfg);
159-
tc_start_counter(tc_instance);
159+
tc_start_counter(MP_STATE_VM(pulseout_tc_instance));
160160

161161
while(pulse_index < length) {
162162
// Do other things while we wait. The interrupts will handle sending the
@@ -166,7 +166,7 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu
166166
#endif
167167
}
168168

169-
tc_stop_counter(tc_instance);
170-
tc_disable_callback(tc_instance, TC_CALLBACK_CC_CHANNEL0);
169+
tc_stop_counter(MP_STATE_VM(pulseout_tc_instance));
170+
tc_disable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0);
171171
active_pincfg = NULL;
172172
}

atmel-samd/mpconfigport.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ extern const struct _mp_obj_module_t usb_hid_module;
192192
#define MICROPY_PORT_ROOT_POINTERS \
193193
const char *readline_hist[8]; \
194194
vstr_t *repl_line; \
195+
struct tc_module* audioout_tc_instance; \
196+
struct dac_module* audioout_dac_instance; \
197+
struct events_resource* audioout_tc_event; \
198+
struct events_resource* audioout_dac_event; \
199+
struct tc_module* pulseout_tc_instance; \
195200
FLASH_ROOT_POINTERS \
196201

197202
bool udi_msc_process_trans(void);

0 commit comments

Comments
 (0)