parent
d3a5d40374
commit
50fc90bc5f
@ -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;
|
||||
}
|
||||
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -212,6 +212,56 @@ 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("No sample playing cannot pause");
|
||||
}
|
||||
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)) {
|
||||
mp_raise_RuntimeError("No paused sample");
|
||||
}
|
||||
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) },
|
||||
@ -219,9 +269,12 @@ STATIC const mp_rom_map_elem_t audiobusio_i2sout_locals_dict_table[] = {
|
||||
{ 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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
@ -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);
|
||||
@ -209,6 +209,56 @@ 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("No sample playing cannot pause");
|
||||
}
|
||||
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)) {
|
||||
mp_raise_RuntimeError("No paused sample");
|
||||
}
|
||||
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) },
|
||||
@ -216,9 +266,12 @@ STATIC const mp_rom_map_elem_t audioio_audioout_locals_dict_table[] = {
|
||||
{ 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);
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user