Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions ports/atmel-samd/audio_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,23 @@ void audio_dma_stop(audio_dma_t* dma) {
dma->dma_channel = AUDIO_DMA_CHANNEL_COUNT;
}

void audio_dma_pause(audio_dma_t* dma) {
dma_suspend_channel(dma->dma_channel);
}

void audio_dma_resume(audio_dma_t* dma) {
dma_resume_channel(dma->dma_channel);
}

bool audio_dma_get_paused(audio_dma_t* dma) {
if (dma->dma_channel >= AUDIO_DMA_CHANNEL_COUNT) {
return false;
}
uint32_t status = dma_transfer_status(dma->dma_channel);

return (status & DMAC_CHINTFLAG_SUSP) != 0;
}

void audio_dma_init(audio_dma_t* dma) {
dma->dma_channel = AUDIO_DMA_CHANNEL_COUNT;
}
Expand All @@ -341,11 +358,11 @@ bool audio_dma_get_playing(audio_dma_t* dma) {
return false;
}
uint32_t status = dma_transfer_status(dma->dma_channel);
if ((status & DMAC_CHINTFLAG_TCMPL) != 0) {
if ((status & DMAC_CHINTFLAG_TCMPL) != 0 || (status & DMAC_CHINTFLAG_TERR) != 0) {
audio_dma_stop(dma);
}

return status == 0;
return (status & DMAC_CHINTFLAG_TERR) == 0;
}

// WARN(tannewt): DO NOT print from here. Printing calls background tasks such as this and causes a
Expand Down
3 changes: 3 additions & 0 deletions ports/atmel-samd/audio_dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
uint8_t dma_trigger_source);
void audio_dma_stop(audio_dma_t* dma);
bool audio_dma_get_playing(audio_dma_t* dma);
void audio_dma_pause(audio_dma_t* dma);
void audio_dma_resume(audio_dma_t* dma);
bool audio_dma_get_paused(audio_dma_t* dma);

void audio_dma_background(void);

Expand Down
20 changes: 20 additions & 0 deletions ports/atmel-samd/common-hal/audiobusio/I2SOut.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,26 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t* self,
self->playing = true;
}

void common_hal_audiobusio_i2sout_pause(audiobusio_i2sout_obj_t* self) {
audio_dma_pause(&self->dma);
}

void common_hal_audiobusio_i2sout_resume(audiobusio_i2sout_obj_t* self) {
// Clear any overrun/underrun errors
#ifdef SAMD21
I2S->INTFLAG.reg = I2S_INTFLAG_TXUR0 << self->serializer;
#endif
#ifdef SAMD51
I2S->INTFLAG.reg = I2S_INTFLAG_TXUR0 | I2S_INTFLAG_TXUR1;
#endif

audio_dma_resume(&self->dma);
}

bool common_hal_audiobusio_i2sout_get_paused(audiobusio_i2sout_obj_t* self) {
return audio_dma_get_paused(&self->dma);
}

void common_hal_audiobusio_i2sout_stop(audiobusio_i2sout_obj_t* self) {
audio_dma_stop(&self->dma);

Expand Down
26 changes: 26 additions & 0 deletions ports/atmel-samd/common-hal/audioio/AudioOut.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,32 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t* self,
self->playing = true;
}

void common_hal_audioio_audioout_pause(audioio_audioout_obj_t* self) {
audio_dma_pause(&self->left_dma);
#ifdef SAMD51
audio_dma_pause(&self->right_dma);
#endif
}

void common_hal_audioio_audioout_resume(audioio_audioout_obj_t* self) {
// Clear any overrun/underrun errors
#ifdef SAMD21
DAC->INTFLAG.reg = DAC_INTFLAG_UNDERRUN;
#endif
#ifdef SAMD51
DAC->INTFLAG.reg = DAC_INTFLAG_UNDERRUN0 | DAC_INTFLAG_UNDERRUN1;
#endif

audio_dma_resume(&self->left_dma);
#ifdef SAMD51
audio_dma_resume(&self->right_dma);
#endif
}

bool common_hal_audioio_audioout_get_paused(audioio_audioout_obj_t* self) {
return audio_dma_get_paused(&self->left_dma);
}

void common_hal_audioio_audioout_stop(audioio_audioout_obj_t* self) {
Tc* timer = tc_insts[self->tc_index];
timer->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_STOP;
Expand Down
31 changes: 31 additions & 0 deletions ports/atmel-samd/shared_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,37 @@ void dma_disable_channel(uint8_t channel_number) {
#endif
}

void dma_suspend_channel(uint8_t channel_number) {
#ifdef SAMD21
common_hal_mcu_disable_interrupts();
/** Select the DMA channel and clear software trigger */
DMAC->CHID.reg = DMAC_CHID_ID(channel_number);
DMAC->CHCTRLB.bit.CMD = DMAC_CHCTRLB_CMD_SUSPEND_Val;
common_hal_mcu_enable_interrupts();
#endif

#ifdef SAMD51
DmacChannel* channel = &DMAC->Channel[channel_number];
channel->CHCTRLB.reg = DMAC_CHCTRLB_CMD_SUSPEND;
#endif
}

void dma_resume_channel(uint8_t channel_number) {
#ifdef SAMD21
common_hal_mcu_disable_interrupts();
/** Select the DMA channel and clear software trigger */
DMAC->CHID.reg = DMAC_CHID_ID(channel_number);
DMAC->CHCTRLB.bit.CMD = DMAC_CHCTRLB_CMD_RESUME_Val;
DMAC->CHINTFLAG.reg = DMAC_CHINTFLAG_SUSP;
common_hal_mcu_enable_interrupts();
#endif

#ifdef SAMD51
DmacChannel* channel = &DMAC->Channel[channel_number];
channel->CHCTRLB.reg = DMAC_CHCTRLB_CMD_RESUME;
#endif
}

bool dma_channel_enabled(uint8_t channel_number) {
#ifdef SAMD21
common_hal_mcu_disable_interrupts();
Expand Down
2 changes: 2 additions & 0 deletions ports/atmel-samd/shared_dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ int32_t sercom_dma_transfer(Sercom* sercom, const uint8_t* buffer_out, uint8_t*
void dma_configure(uint8_t channel_number, uint8_t trigsrc, bool output_event);
void dma_enable_channel(uint8_t channel_number);
void dma_disable_channel(uint8_t channel_number);
void dma_suspend_channel(uint8_t channel_number);
void dma_resume_channel(uint8_t channel_number);
bool dma_channel_enabled(uint8_t channel_number);
uint8_t dma_transfer_status(uint8_t channel_number);
DmacDescriptor* dma_descriptor(uint8_t channel_number);
Expand Down
53 changes: 53 additions & 0 deletions shared-bindings/audiobusio/I2SOut.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,16 +212,69 @@ const mp_obj_property_t audiobusio_i2sout_playing_obj = {
(mp_obj_t)&mp_const_none_obj},
};

//| .. method:: pause()
//|
//| Stops playback temporarily while remembering the position. Use `resume` to resume playback.
//|
STATIC mp_obj_t audiobusio_i2sout_obj_pause(mp_obj_t self_in) {
audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in);
raise_error_if_deinited(common_hal_audiobusio_i2sout_deinited(self));

if (!common_hal_audiobusio_i2sout_get_playing(self)) {
mp_raise_RuntimeError("Not playing");
}
common_hal_audiobusio_i2sout_pause(self);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_pause_obj, audiobusio_i2sout_obj_pause);

//| .. method:: resume()
//|
//| Resumes sample playback after :py:func:`pause`.
//|
STATIC mp_obj_t audiobusio_i2sout_obj_resume(mp_obj_t self_in) {
audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in);
raise_error_if_deinited(common_hal_audiobusio_i2sout_deinited(self));

if (common_hal_audiobusio_i2sout_get_paused(self)) {
common_hal_audiobusio_i2sout_resume(self);
}

return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_resume_obj, audiobusio_i2sout_obj_resume);

//| .. attribute:: paused
//|
//| True when playback is paused. (read-only)
//|
STATIC mp_obj_t audiobusio_i2sout_obj_get_paused(mp_obj_t self_in) {
audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in);
raise_error_if_deinited(common_hal_audiobusio_i2sout_deinited(self));
return mp_obj_new_bool(common_hal_audiobusio_i2sout_get_paused(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_get_paused_obj, audiobusio_i2sout_obj_get_paused);

const mp_obj_property_t audiobusio_i2sout_paused_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&audiobusio_i2sout_get_paused_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
};

STATIC const mp_rom_map_elem_t audiobusio_i2sout_locals_dict_table[] = {
// Methods
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiobusio_i2sout_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiobusio_i2sout___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiobusio_i2sout_play_obj) },
{ MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiobusio_i2sout_stop_obj) },
{ MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&audiobusio_i2sout_pause_obj) },
{ MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&audiobusio_i2sout_resume_obj) },

// Properties
{ MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiobusio_i2sout_playing_obj) },
{ MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&audiobusio_i2sout_paused_obj) },
};
STATIC MP_DEFINE_CONST_DICT(audiobusio_i2sout_locals_dict, audiobusio_i2sout_locals_dict_table);

Expand Down
3 changes: 3 additions & 0 deletions shared-bindings/audiobusio/I2SOut.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,8 @@ bool common_hal_audiobusio_i2sout_deinited(audiobusio_i2sout_obj_t* self);
void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t* self, mp_obj_t sample, bool loop);
void common_hal_audiobusio_i2sout_stop(audiobusio_i2sout_obj_t* self);
bool common_hal_audiobusio_i2sout_get_playing(audiobusio_i2sout_obj_t* self);
void common_hal_audiobusio_i2sout_pause(audiobusio_i2sout_obj_t* self);
void common_hal_audiobusio_i2sout_resume(audiobusio_i2sout_obj_t* self);
bool common_hal_audiobusio_i2sout_get_paused(audiobusio_i2sout_obj_t* self);

#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO_I2SOUT_H
57 changes: 55 additions & 2 deletions shared-bindings/audioio/AudioOut.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(audioio_audioout_play_obj, 1, audioio_audioout_obj_pl

//| .. method:: stop()
//|
//| Stops playback.
//| Stops playback and resets to the start of the sample.
//|
STATIC mp_obj_t audioio_audioout_obj_stop(mp_obj_t self_in) {
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
Expand All @@ -193,7 +193,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_stop_obj, audioio_audioout_obj_stop);

//| .. attribute:: playing
//|
//| True when an audio sample is being output. (read-only)
//| True when an audio sample is being output even if `paused`. (read-only)
//|
STATIC mp_obj_t audioio_audioout_obj_get_playing(mp_obj_t self_in) {
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
Expand All @@ -209,16 +209,69 @@ const mp_obj_property_t audioio_audioout_playing_obj = {
(mp_obj_t)&mp_const_none_obj},
};

//| .. method:: pause()
//|
//| Stops playback temporarily while remembering the position. Use `resume` to resume playback.
//|
STATIC mp_obj_t audioio_audioout_obj_pause(mp_obj_t self_in) {
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
raise_error_if_deinited(common_hal_audioio_audioout_deinited(self));

if (!common_hal_audioio_audioout_get_playing(self)) {
mp_raise_RuntimeError("Not playing");
}
common_hal_audioio_audioout_pause(self);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_pause_obj, audioio_audioout_obj_pause);

//| .. method:: resume()
//|
//| Resumes sample playback after :py:func:`pause`.
//|
STATIC mp_obj_t audioio_audioout_obj_resume(mp_obj_t self_in) {
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
raise_error_if_deinited(common_hal_audioio_audioout_deinited(self));

if (common_hal_audioio_audioout_get_paused(self)) {
common_hal_audioio_audioout_resume(self);
}

return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_resume_obj, audioio_audioout_obj_resume);

//| .. attribute:: paused
//|
//| True when playback is paused. (read-only)
//|
STATIC mp_obj_t audioio_audioout_obj_get_paused(mp_obj_t self_in) {
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
raise_error_if_deinited(common_hal_audioio_audioout_deinited(self));
return mp_obj_new_bool(common_hal_audioio_audioout_get_paused(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_get_paused_obj, audioio_audioout_obj_get_paused);

const mp_obj_property_t audioio_audioout_paused_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&audioio_audioout_get_paused_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
};

STATIC const mp_rom_map_elem_t audioio_audioout_locals_dict_table[] = {
// Methods
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_audioout_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_audioout___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_audioout_play_obj) },
{ MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audioio_audioout_stop_obj) },
{ MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&audioio_audioout_pause_obj) },
{ MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&audioio_audioout_resume_obj) },

// Properties
{ MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_audioout_playing_obj) },
{ MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&audioio_audioout_paused_obj) },
};
STATIC MP_DEFINE_CONST_DICT(audioio_audioout_locals_dict, audioio_audioout_locals_dict_table);

Expand Down
3 changes: 3 additions & 0 deletions shared-bindings/audioio/AudioOut.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,8 @@ bool common_hal_audioio_audioout_deinited(audioio_audioout_obj_t* self);
void common_hal_audioio_audioout_play(audioio_audioout_obj_t* self, mp_obj_t sample, bool loop);
void common_hal_audioio_audioout_stop(audioio_audioout_obj_t* self);
bool common_hal_audioio_audioout_get_playing(audioio_audioout_obj_t* self);
void common_hal_audioio_audioout_pause(audioio_audioout_obj_t* self);
void common_hal_audioio_audioout_resume(audioio_audioout_obj_t* self);
bool common_hal_audioio_audioout_get_paused(audioio_audioout_obj_t* self);

#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_AUDIOOUT_H