From be21364b301dc4f5186331725d3452f4f893d690 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Mon, 23 Aug 2021 16:52:04 +0200 Subject: [PATCH] Made 'toneGen_playAudioStream' a non-blocking function, added 'toneGen_waitForStreamEnd' API function to allow blocking execution flow until a currently playing audio stream terminates or is stopped --- platform/drivers/tones/toneGenerator_MDx.cpp | 47 ++++++++++++-------- platform/drivers/tones/toneGenerator_MDx.h | 16 +++++-- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/platform/drivers/tones/toneGenerator_MDx.cpp b/platform/drivers/tones/toneGenerator_MDx.cpp index 3839a2f2..c3a75b2c 100644 --- a/platform/drivers/tones/toneGenerator_MDx.cpp +++ b/platform/drivers/tones/toneGenerator_MDx.cpp @@ -24,9 +24,6 @@ #include #include -#include -#include - /* * Sine table for PWM-based sinewave generation, containing 256 samples over one * period of a 35Hz sinewave. This gives a PWM base frequency of 8.96kHz. @@ -101,9 +98,19 @@ void __attribute__((used)) TIM8_TRG_COM_TIM14_IRQHandler() */ void __attribute__((used)) DMA_Handler() { - DMA1->LIFCR |= DMA_LIFCR_CTCIF2 | DMA_LIFCR_CTEIF2; + DMA1->LIFCR |= DMA_LIFCR_CTCIF2 // Clear interrupt flags + | DMA_LIFCR_CTEIF2; - if(dmaWaiting == 0) return; + TIM7->CR1 = 0; // End of transfer, stop TIM7 + TIM3->CCER &= ~TIM_CCER_CC3E; // Turn off compare channel + + RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA1EN; // Turn off DMA + RCC->APB1ENR &= ~RCC_APB1ENR_TIM7EN; // Turn off TIM7 + __DSB(); + + tonesLocked = false; // Finally, unlock tones + + if(dmaWaiting == 0) return; // Wake up eventual pending threads dmaWaiting->IRQwakeup(); if(dmaWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority()) Scheduler::IRQfindNextThread(); @@ -298,13 +305,24 @@ void toneGen_playAudioStream(const uint16_t* buf, const size_t len, // Start timer for DMA transfer triggering TIM7->CR1 = TIM_CR1_CEN; +} +bool toneGen_waitForStreamEnd() +{ /* - * Put the calling thread in waiting status until transfer completes + * Critical section. Check if: + * - there is no transfer in progress, in which case waiting is useless. + * - there is another thread pending on transfer completion. + * + * If both these conditions are false, put the calling thread in waiting + * status until transfer completes. */ { FastInterruptDisableLock dLock; - dmaWaiting = Thread::IRQgetCurrentThread(); + Thread *curThread = Thread::IRQgetCurrentThread(); + if(tonesLocked == false) return false; + if((dmaWaiting != 0) && (dmaWaiting != curThread)) return false; + dmaWaiting = curThread; do { Thread::IRQwait(); @@ -315,17 +333,8 @@ void toneGen_playAudioStream(const uint16_t* buf, const size_t len, } while(dmaWaiting); } - // End of transfer, turn off TIM7 and DMA - TIM7->CR1 = 0; - TIM3->CCER &= ~TIM_CCER_CC3E; - - RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA1EN; - RCC->APB1ENR &= ~RCC_APB1ENR_TIM7EN; - __DSB(); - - // Finally, unlock tones - FastInterruptDisableLock dLock; - tonesLocked = false; + // Outside critical section, here we finished waiting and everything is ok. + return true; } void toneGen_stopAudioStream() @@ -346,7 +355,7 @@ void toneGen_stopAudioStream() if(dmaWaiting) dmaWaiting->IRQwakeup(); } -bool toneGen_toneStatus() +bool toneGen_toneBusy() { /* * Tone section is busy whenever CC3E bit in TIM3 CCER register is set. diff --git a/platform/drivers/tones/toneGenerator_MDx.h b/platform/drivers/tones/toneGenerator_MDx.h index d234d300..70670847 100644 --- a/platform/drivers/tones/toneGenerator_MDx.h +++ b/platform/drivers/tones/toneGenerator_MDx.h @@ -101,8 +101,9 @@ void toneGen_encodeAFSK1200(const uint8_t *buf, const size_t len); /** * Reproduce an audio stream, sending audio stream to both the speaker and the * rtx baseband IC. - * This function blocks the execution flow until all data has been sent or the - * reproduction is interrupted by calling the corresponding function. + * This function returns immediately and the stream is reproduced in background. + * The calling thread can be made waiting for transfer completion by calling the + * corresponding API function. * * WARNING: the underlying peripheral accepts ONLY 16 bit transfers, while the * PWM resolution is 8 bit. Thus, the sample buffer MUST be of uint16_t elements @@ -116,6 +117,15 @@ void toneGen_encodeAFSK1200(const uint8_t *buf, const size_t len); void toneGen_playAudioStream(const uint16_t *buf, const size_t len, const uint32_t sampleRate); +/** + * When called, this function blocks the execution flow until the reproduction + * of a previously started audio stream or AFSK modulation terminates. + * + * @return false if there is no ongoing stream or if another thread is already + * pending, true otherwise. + */ +bool toneGen_waitForStreamEnd(); + /** * Interrupt the ongoing reproduction of an audio stream, also making the * toneGen_playAudioStream return to the caller. @@ -127,7 +137,7 @@ void toneGen_stopAudioStream(); * * @return true if the tone generator is busy. */ -bool toneGen_toneStatus(); +bool toneGen_toneBusy(); #ifdef __cplusplus