From 5ad426124bf15a50edd6aeda50a228933dee8507 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 4 May 2017 11:57:51 -0700 Subject: [PATCH] atmel-samd: Move heap objects into MICROPY_PORT_ROOT_POINTERS so they don't get garbage collected while we are using them. --- .../boards/circuitplayground_express/pins.c | 2 +- atmel-samd/common-hal/audioio/AudioOut.c | 137 +++++++++--------- atmel-samd/common-hal/pulseio/PulseOut.c | 34 ++--- atmel-samd/mpconfigport.h | 5 + 4 files changed, 89 insertions(+), 89 deletions(-) diff --git a/atmel-samd/boards/circuitplayground_express/pins.c b/atmel-samd/boards/circuitplayground_express/pins.c index d7ef47de78..abaea03786 100644 --- a/atmel-samd/boards/circuitplayground_express/pins.c +++ b/atmel-samd/boards/circuitplayground_express/pins.c @@ -92,7 +92,7 @@ STATIC const mp_map_elem_t board_global_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_ACCELEROMETER_SDA), (mp_obj_t)&pin_PA00 }, { MP_OBJ_NEW_QSTR(MP_QSTR_ACCELEROMETER_SCL), (mp_obj_t)&pin_PA01 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER_SHUTDOWN), (mp_obj_t)&pin_PA30 }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER_ENABLE), (mp_obj_t)&pin_PA30 }, { MP_OBJ_NEW_QSTR(MP_QSTR_SCK), (mp_obj_t)&pin_PA21 }, { MP_OBJ_NEW_QSTR(MP_QSTR_MOSI), (mp_obj_t)&pin_PA20 }, diff --git a/atmel-samd/common-hal/audioio/AudioOut.c b/atmel-samd/common-hal/audioio/AudioOut.c index b548d11644..9d7b922f1c 100644 --- a/atmel-samd/common-hal/audioio/AudioOut.c +++ b/atmel-samd/common-hal/audioio/AudioOut.c @@ -49,11 +49,9 @@ extern uint8_t timer_refcount[TC_INST_NUM + TCC_INST_NUM]; extern const uint16_t prescaler[8]; // This timer is shared amongst all AudioOut objects under the assumption that -// the code is single threaded. -static struct tc_module* tc_instance; -static struct dac_module* dac_instance; -static struct events_resource* tc_event; -static struct events_resource* dac_event; +// the code is single threaded. The audioout_tc_instance, audioout_dac_instance, +// audioout_tc_event, and audioout_dac_event pointers live in +// MICROPY_PORT_ROOT_POINTERS so they don't get garbage collected. // The AudioOut object is being currently played. Only it can pause the timer // and change its frequency. @@ -62,25 +60,22 @@ static audioio_audioout_obj_t* active_audioout; static uint8_t refcount = 0; void audioout_reset(void) { - // Only reset DMA. PWMOut will reset the timer. + // Only reset DMA. PWMOut will reset the timer. Other code will reset the DAC. refcount = 0; - tc_instance = NULL; - if (dac_instance != NULL) { - dac_reset(dac_instance); - } - dac_instance = NULL; + MP_STATE_VM(audioout_tc_instance) = NULL; + MP_STATE_VM(audioout_dac_instance) = NULL; - if (tc_event != NULL) { - events_detach_user(tc_event, EVSYS_ID_USER_DAC_START); - events_release(tc_event); + if (MP_STATE_VM(audioout_tc_event) != NULL) { + events_detach_user(MP_STATE_VM(audioout_tc_event), EVSYS_ID_USER_DAC_START); + events_release(MP_STATE_VM(audioout_tc_event)); } - tc_event = NULL; + MP_STATE_VM(audioout_tc_event) = NULL; - if (dac_event != NULL) { - events_detach_user(dac_event, EVSYS_ID_USER_DMAC_CH_0); - events_release(dac_event); + if (MP_STATE_VM(audioout_dac_event) != NULL) { + events_detach_user(MP_STATE_VM(audioout_dac_event), EVSYS_ID_USER_DMAC_CH_0); + events_release(MP_STATE_VM(audioout_dac_event)); } - dac_event = NULL; + MP_STATE_VM(audioout_dac_event) = NULL; dma_abort_job(&audio_dma); } @@ -90,8 +85,8 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t* // Configure the DAC to output on input event and to output an empty event // that triggers the DMA to load the next sample. - dac_instance = gc_alloc(sizeof(struct dac_module), false); - if (dac_instance == NULL) { + MP_STATE_VM(audioout_dac_instance) = gc_alloc(sizeof(struct dac_module), false); + if (MP_STATE_VM(audioout_dac_instance) == NULL) { mp_raise_msg(&mp_type_MemoryError, ""); } struct dac_config config_dac; @@ -99,7 +94,7 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t* config_dac.left_adjust = true; config_dac.reference = DAC_REFERENCE_AVCC; config_dac.clock_source = GCLK_GENERATOR_0; - enum status_code status = dac_init(dac_instance, DAC, &config_dac); + enum status_code status = dac_init(MP_STATE_VM(audioout_dac_instance), DAC, &config_dac); if (status != STATUS_OK) { common_hal_audioio_audioout_deinit(self); mp_raise_OSError(MP_EIO); @@ -108,14 +103,12 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t* struct dac_chan_config channel_config; dac_chan_get_config_defaults(&channel_config); - dac_chan_set_config(dac_instance, DAC_CHANNEL_0, &channel_config); - dac_chan_enable(dac_instance, DAC_CHANNEL_0); + dac_chan_set_config(MP_STATE_VM(audioout_dac_instance), DAC_CHANNEL_0, &channel_config); + dac_chan_enable(MP_STATE_VM(audioout_dac_instance), DAC_CHANNEL_0); struct dac_events events_dac = { .generate_event_on_buffer_empty = true, .on_event_start_conversion = true }; - dac_enable_events(dac_instance, &events_dac); - - dac_enable(dac_instance); + dac_enable_events(MP_STATE_VM(audioout_dac_instance), &events_dac); // Figure out which timer we are using. Tc *t = NULL; @@ -131,8 +124,8 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t* mp_raise_RuntimeError("All timers in use"); return; } - tc_instance = gc_alloc(sizeof(struct tc_module), false); - if (tc_instance == NULL) { + MP_STATE_VM(audioout_tc_instance) = gc_alloc(sizeof(struct tc_module), false); + if (MP_STATE_VM(audioout_tc_instance) == NULL) { common_hal_audioio_audioout_deinit(self); mp_raise_msg(&mp_type_MemoryError, ""); } @@ -140,28 +133,28 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t* // Don't bother setting the period. We set it before you playback anything. struct tc_config config_tc; tc_get_config_defaults(&config_tc); - config_tc.counter_size = TC_COUNTER_SIZE_16BIT; config_tc.clock_prescaler = TC_CLOCK_PRESCALER_DIV1; config_tc.wave_generation = TC_WAVE_GENERATION_MATCH_FREQ; - if (tc_init(tc_instance, t, &config_tc) != STATUS_OK) { + if (tc_init(MP_STATE_VM(audioout_tc_instance), t, &config_tc) != STATUS_OK) { common_hal_audioio_audioout_deinit(self); - mp_printf(&mp_plat_print, "tc \n"); mp_raise_OSError(MP_EIO); return; }; struct tc_events events_tc; events_tc.generate_event_on_overflow = true; - tc_enable_events(tc_instance, &events_tc); + events_tc.on_event_perform_action = false; + events_tc.event_action = TC_EVENT_ACTION_OFF; + tc_enable_events(MP_STATE_VM(audioout_tc_instance), &events_tc); - tc_enable(tc_instance); - tc_stop_counter(tc_instance); + tc_enable(MP_STATE_VM(audioout_tc_instance)); + tc_stop_counter(MP_STATE_VM(audioout_tc_instance)); // Connect the timer overflow event, which happens at the target frequency, // to the DAC conversion trigger. - tc_event = gc_alloc(sizeof(struct events_resource), false); - if (tc_event == NULL) { + MP_STATE_VM(audioout_tc_event) = gc_alloc(sizeof(struct events_resource), false); + if (MP_STATE_VM(audioout_tc_event) == NULL) { common_hal_audioio_audioout_deinit(self); mp_raise_msg(&mp_type_MemoryError, ""); } @@ -185,24 +178,24 @@ static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t* config.generator = generator; config.path = EVENTS_PATH_ASYNCHRONOUS; - if (events_allocate(tc_event, &config) != STATUS_OK || - events_attach_user(tc_event, EVSYS_ID_USER_DAC_START) != STATUS_OK) { + if (events_allocate(MP_STATE_VM(audioout_tc_event), &config) != STATUS_OK || + events_attach_user(MP_STATE_VM(audioout_tc_event), EVSYS_ID_USER_DAC_START) != STATUS_OK) { common_hal_audioio_audioout_deinit(self); mp_raise_OSError(MP_EIO); return; } // Connect the DAC to DMA - dac_event = gc_alloc(sizeof(struct events_resource), false); - if (dac_event == NULL) { + MP_STATE_VM(audioout_dac_event) = gc_alloc(sizeof(struct events_resource), false); + if (MP_STATE_VM(audioout_dac_event) == NULL) { common_hal_audioio_audioout_deinit(self); mp_raise_msg(&mp_type_MemoryError, ""); } events_get_config_defaults(&config); config.generator = EVSYS_ID_GEN_DAC_EMPTY; config.path = EVENTS_PATH_ASYNCHRONOUS; - if (events_allocate(dac_event, &config) != STATUS_OK || - events_attach_user(dac_event, EVSYS_ID_USER_DMAC_CH_0) != STATUS_OK) { + if (events_allocate(MP_STATE_VM(audioout_dac_event), &config) != STATUS_OK || + events_attach_user(MP_STATE_VM(audioout_dac_event), EVSYS_ID_USER_DMAC_CH_0) != STATUS_OK) { common_hal_audioio_audioout_deinit(self); mp_raise_OSError(MP_EIO); return; @@ -239,26 +232,26 @@ void common_hal_audioio_audioout_construct_from_file(audioio_audioout_obj_t* sel void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t* self) { refcount--; if (refcount == 0) { - if (tc_instance != NULL) { - tc_reset(tc_instance); - gc_free(tc_instance); - tc_instance = NULL; + if (MP_STATE_VM(audioout_tc_instance) != NULL) { + tc_reset(MP_STATE_VM(audioout_tc_instance)); + gc_free(MP_STATE_VM(audioout_tc_instance)); + MP_STATE_VM(audioout_tc_instance) = NULL; } - if (dac_instance != NULL) { - dac_reset(dac_instance); - gc_free(dac_instance); - dac_instance = NULL; + if (MP_STATE_VM(audioout_dac_instance) != NULL) { + dac_reset(MP_STATE_VM(audioout_dac_instance)); + gc_free(MP_STATE_VM(audioout_dac_instance)); + MP_STATE_VM(audioout_dac_instance) = NULL; } - if (tc_event != NULL) { - events_detach_user(tc_event, EVSYS_ID_USER_DAC_START); - events_release(tc_event); - gc_free(tc_event); - tc_event = NULL; + if (MP_STATE_VM(audioout_tc_event) != NULL) { + events_detach_user(MP_STATE_VM(audioout_tc_event), EVSYS_ID_USER_DAC_START); + events_release(MP_STATE_VM(audioout_tc_event)); + gc_free(MP_STATE_VM(audioout_tc_event)); + MP_STATE_VM(audioout_tc_event) = NULL; } - if (dac_event != NULL) { - events_release(dac_event); - gc_free(dac_event); - dac_event = NULL; + if (MP_STATE_VM(audioout_dac_event) != NULL) { + events_release(MP_STATE_VM(audioout_dac_event)); + gc_free(MP_STATE_VM(audioout_dac_event)); + MP_STATE_VM(audioout_dac_event) = NULL; } reset_pin(self->pin->pin); } @@ -274,17 +267,17 @@ static void set_timer_frequency(uint32_t frequency) { break; } } - uint8_t old_divisor = tc_instance->hw->COUNT16.CTRLA.bit.PRESCALER; + uint8_t old_divisor = MP_STATE_VM(audioout_tc_instance)->hw->COUNT16.CTRLA.bit.PRESCALER; if (new_divisor != old_divisor) { - tc_disable(tc_instance); - tc_instance->hw->COUNT16.CTRLA.bit.PRESCALER = new_divisor; - tc_enable(tc_instance); + tc_disable(MP_STATE_VM(audioout_tc_instance)); + MP_STATE_VM(audioout_tc_instance)->hw->COUNT16.CTRLA.bit.PRESCALER = new_divisor; + tc_enable(MP_STATE_VM(audioout_tc_instance)); } - while (tc_is_syncing(tc_instance)) { + while (tc_is_syncing(MP_STATE_VM(audioout_tc_instance))) { /* Wait for sync */ } - tc_instance->hw->COUNT16.CC[0].reg = new_top; - while (tc_is_syncing(tc_instance)) { + MP_STATE_VM(audioout_tc_instance)->hw->COUNT16.CC[0].reg = new_top; + while (tc_is_syncing(MP_STATE_VM(audioout_tc_instance))) { /* Wait for sync */ } } @@ -293,8 +286,10 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t* self, bool loop) { common_hal_audioio_audioout_get_playing(self); // Shut down any active playback. if (active_audioout != NULL) { - tc_stop_counter(tc_instance); + tc_stop_counter(MP_STATE_VM(audioout_tc_instance)); dma_abort_job(&audio_dma); + } else { + dac_enable(MP_STATE_VM(audioout_dac_instance)); } struct dma_descriptor_config descriptor_config; dma_descriptor_get_config_defaults(&descriptor_config); @@ -314,15 +309,15 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t* self, bool loop) { dma_start_transfer_job(&audio_dma); set_timer_frequency(self->frequency); - tc_start_counter(tc_instance); + tc_start_counter(MP_STATE_VM(audioout_tc_instance)); } void common_hal_audioio_audioout_stop(audioio_audioout_obj_t* self) { if (common_hal_audioio_audioout_get_playing(self)) { - tc_stop_counter(tc_instance); + tc_stop_counter(MP_STATE_VM(audioout_tc_instance)); dma_abort_job(&audio_dma); active_audioout = NULL; - // TODO(tannewt): Disable the DAC to save power. + dac_disable(MP_STATE_VM(audioout_dac_instance)); } } diff --git a/atmel-samd/common-hal/pulseio/PulseOut.c b/atmel-samd/common-hal/pulseio/PulseOut.c index be95a1418e..32edd08566 100644 --- a/atmel-samd/common-hal/pulseio/PulseOut.c +++ b/atmel-samd/common-hal/pulseio/PulseOut.c @@ -39,8 +39,8 @@ #undef ENABLE // This timer is shared amongst all PulseOut objects under the assumption that -// the code is single threaded. -static struct tc_module* tc_instance; +// the code is single threaded. Its stored in MICROPY_PORT_ROOT_POINTERS so it +// doesn't get garbage collected. static uint8_t refcount = 0; static __IO PORT_PINCFG_Type *active_pincfg = NULL; @@ -69,7 +69,7 @@ void pulse_finish(struct tc_module *const module) { return; } current_compare = (current_compare + pulse_buffer[pulse_index] * 3 / 4) & 0xffff; - tc_set_compare_value(tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); + tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); if (pulse_index % 2 == 0) { turn_on(active_pincfg); } @@ -77,7 +77,7 @@ void pulse_finish(struct tc_module *const module) { void pulseout_reset() { refcount = 0; - tc_instance = 0; + MP_STATE_VM(pulseout_tc_instance) = NULL; active_pincfg = NULL; } @@ -96,7 +96,7 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, if (t == NULL) { mp_raise_RuntimeError("All timers in use"); } - tc_instance = gc_alloc(sizeof(struct tc_module), false); + MP_STATE_VM(pulseout_tc_instance) = gc_alloc(sizeof(struct tc_module), false); if (t == NULL) { mp_raise_msg(&mp_type_MemoryError, ""); } @@ -108,10 +108,10 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, config_tc.clock_prescaler = TC_CTRLA_PRESCALER_DIV64; config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_FREQ; - tc_init(tc_instance, t, &config_tc); - tc_register_callback(tc_instance, pulse_finish, TC_CALLBACK_CC_CHANNEL0); - tc_enable(tc_instance); - tc_stop_counter(tc_instance); + tc_init(MP_STATE_VM(pulseout_tc_instance), t, &config_tc); + tc_register_callback(MP_STATE_VM(pulseout_tc_instance), pulse_finish, TC_CALLBACK_CC_CHANNEL0); + tc_enable(MP_STATE_VM(pulseout_tc_instance)); + tc_stop_counter(MP_STATE_VM(pulseout_tc_instance)); } refcount++; @@ -136,9 +136,9 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { refcount--; if (refcount == 0) { - tc_reset(tc_instance); - gc_free(tc_instance); - tc_instance = NULL; + tc_reset(MP_STATE_VM(pulseout_tc_instance)); + gc_free(MP_STATE_VM(pulseout_tc_instance)); + MP_STATE_VM(pulseout_tc_instance) = NULL; } } @@ -152,11 +152,11 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu pulse_length = length; current_compare = pulses[0] * 3 / 4; - tc_set_compare_value(tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); + tc_set_compare_value(MP_STATE_VM(pulseout_tc_instance), TC_COMPARE_CAPTURE_CHANNEL_0, current_compare); - tc_enable_callback(tc_instance, TC_CALLBACK_CC_CHANNEL0); + tc_enable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); turn_on(active_pincfg); - tc_start_counter(tc_instance); + tc_start_counter(MP_STATE_VM(pulseout_tc_instance)); while(pulse_index < length) { // 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 #endif } - tc_stop_counter(tc_instance); - tc_disable_callback(tc_instance, TC_CALLBACK_CC_CHANNEL0); + tc_stop_counter(MP_STATE_VM(pulseout_tc_instance)); + tc_disable_callback(MP_STATE_VM(pulseout_tc_instance), TC_CALLBACK_CC_CHANNEL0); active_pincfg = NULL; } diff --git a/atmel-samd/mpconfigport.h b/atmel-samd/mpconfigport.h index 16d9cb075f..f66feb4ce4 100644 --- a/atmel-samd/mpconfigport.h +++ b/atmel-samd/mpconfigport.h @@ -192,6 +192,11 @@ extern const struct _mp_obj_module_t usb_hid_module; #define MICROPY_PORT_ROOT_POINTERS \ const char *readline_hist[8]; \ vstr_t *repl_line; \ + struct tc_module* audioout_tc_instance; \ + struct dac_module* audioout_dac_instance; \ + struct events_resource* audioout_tc_event; \ + struct events_resource* audioout_dac_event; \ + struct tc_module* pulseout_tc_instance; \ FLASH_ROOT_POINTERS \ bool udi_msc_process_trans(void);