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
This commit is contained in:
parent
db3efb21be
commit
be21364b30
|
|
@ -24,9 +24,6 @@
|
||||||
#include <interfaces/gpio.h>
|
#include <interfaces/gpio.h>
|
||||||
#include <kernel/scheduler/scheduler.h>
|
#include <kernel/scheduler/scheduler.h>
|
||||||
|
|
||||||
#include <interfaces/delays.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sine table for PWM-based sinewave generation, containing 256 samples over one
|
* 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.
|
* 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()
|
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();
|
dmaWaiting->IRQwakeup();
|
||||||
if(dmaWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority())
|
if(dmaWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority())
|
||||||
Scheduler::IRQfindNextThread();
|
Scheduler::IRQfindNextThread();
|
||||||
|
|
@ -298,13 +305,24 @@ void toneGen_playAudioStream(const uint16_t* buf, const size_t len,
|
||||||
|
|
||||||
// Start timer for DMA transfer triggering
|
// Start timer for DMA transfer triggering
|
||||||
TIM7->CR1 = TIM_CR1_CEN;
|
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;
|
FastInterruptDisableLock dLock;
|
||||||
dmaWaiting = Thread::IRQgetCurrentThread();
|
Thread *curThread = Thread::IRQgetCurrentThread();
|
||||||
|
if(tonesLocked == false) return false;
|
||||||
|
if((dmaWaiting != 0) && (dmaWaiting != curThread)) return false;
|
||||||
|
dmaWaiting = curThread;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Thread::IRQwait();
|
Thread::IRQwait();
|
||||||
|
|
@ -315,17 +333,8 @@ void toneGen_playAudioStream(const uint16_t* buf, const size_t len,
|
||||||
} while(dmaWaiting);
|
} while(dmaWaiting);
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of transfer, turn off TIM7 and DMA
|
// Outside critical section, here we finished waiting and everything is ok.
|
||||||
TIM7->CR1 = 0;
|
return true;
|
||||||
TIM3->CCER &= ~TIM_CCER_CC3E;
|
|
||||||
|
|
||||||
RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA1EN;
|
|
||||||
RCC->APB1ENR &= ~RCC_APB1ENR_TIM7EN;
|
|
||||||
__DSB();
|
|
||||||
|
|
||||||
// Finally, unlock tones
|
|
||||||
FastInterruptDisableLock dLock;
|
|
||||||
tonesLocked = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void toneGen_stopAudioStream()
|
void toneGen_stopAudioStream()
|
||||||
|
|
@ -346,7 +355,7 @@ void toneGen_stopAudioStream()
|
||||||
if(dmaWaiting) dmaWaiting->IRQwakeup();
|
if(dmaWaiting) dmaWaiting->IRQwakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool toneGen_toneStatus()
|
bool toneGen_toneBusy()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Tone section is busy whenever CC3E bit in TIM3 CCER register is set.
|
* Tone section is busy whenever CC3E bit in TIM3 CCER register is set.
|
||||||
|
|
|
||||||
|
|
@ -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
|
* Reproduce an audio stream, sending audio stream to both the speaker and the
|
||||||
* rtx baseband IC.
|
* rtx baseband IC.
|
||||||
* This function blocks the execution flow until all data has been sent or the
|
* This function returns immediately and the stream is reproduced in background.
|
||||||
* reproduction is interrupted by calling the corresponding function.
|
* 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
|
* 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
|
* 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,
|
void toneGen_playAudioStream(const uint16_t *buf, const size_t len,
|
||||||
const uint32_t sampleRate);
|
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
|
* Interrupt the ongoing reproduction of an audio stream, also making the
|
||||||
* toneGen_playAudioStream return to the caller.
|
* toneGen_playAudioStream return to the caller.
|
||||||
|
|
@ -127,7 +137,7 @@ void toneGen_stopAudioStream();
|
||||||
*
|
*
|
||||||
* @return true if the tone generator is busy.
|
* @return true if the tone generator is busy.
|
||||||
*/
|
*/
|
||||||
bool toneGen_toneStatus();
|
bool toneGen_toneBusy();
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue