diff --git a/platform/drivers/tones/toneGenerator_MDx.cpp b/platform/drivers/tones/toneGenerator_MDx.cpp index 54e612ea..c69e295c 100644 --- a/platform/drivers/tones/toneGenerator_MDx.cpp +++ b/platform/drivers/tones/toneGenerator_MDx.cpp @@ -24,6 +24,8 @@ #include #include +using namespace miosix; + /* * 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. @@ -46,19 +48,14 @@ static const uint8_t sineTable[] = static const uint32_t baseSineFreq = 35; -uint32_t toneTableIndex = 0; // Current sine table index for CTCSS generator -uint32_t toneTableIncr = 0; // CTCSS sine table index increment per tick +static uint32_t toneTableIndex = 0; // Current sine table index for CTCSS generator +static uint32_t toneTableIncr = 0; // CTCSS sine table index increment per tick -uint32_t beepTableIndex = 0; // Current sine table index for "beep" generator -uint32_t beepTableIncr = 0; // "beep" sine table index increment per tick -uint32_t beepTimerCount = 0; // Downcounter for timed "beep" -uint8_t beepVolume = 0; // "beep" volume level -uint8_t beepLockCount = 0; // Counter for management of "beep" generation locking - -bool circularMode = false; // Circular mode enabled - -using namespace miosix; -Thread *dmaWaiting = 0; +static uint32_t beepTableIndex = 0; // Current sine table index for "beep" generator +static uint32_t beepTableIncr = 0; // "beep" sine table index increment per tick +static uint32_t beepTimerCount = 0; // Downcounter for timed "beep" +static uint8_t beepVolume = 0; // "beep" volume level +static uint8_t beepLockCount = 0; // Counter for management of "beep" generation locking /* * TIM14 interrupt handler, used to manage generation of CTCSS and "beep" tones. @@ -94,40 +91,6 @@ void __attribute__((used)) TIM8_TRG_COM_TIM14_IRQHandler() } } -/* - * DMA1 Stream2 interrupt handler, for audio playback and FSK modulation. - */ -void __attribute__((used)) DMA_Handler() -{ - DMA1->LIFCR |= DMA_LIFCR_CTCIF2 // Clear interrupt flags - | DMA_LIFCR_CHTIF2 - | DMA_LIFCR_CTEIF2; - - if(circularMode == false) - { - - TIM7->CR1 = 0; // End of transfer, stop TIM7 - TIM3->CCER &= ~TIM_CCER_CC3E; // Turn off compare channel - RCC->APB1ENR &= ~RCC_APB1ENR_TIM7EN; // Turn off TIM7 - __DSB(); - - toneGen_unlockBeep(); // Finally, unlock tones - } - - if(dmaWaiting == 0) return; // Wake up eventual pending threads - dmaWaiting->IRQwakeup(); - if(dmaWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority()) - Scheduler::IRQfindNextThread(); - dmaWaiting = 0; -} - -void __attribute__((naked)) DMA1_Stream2_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z11DMA_Handlerv"); - restoreContext(); -} - void toneGen_init() { /* @@ -185,8 +148,6 @@ void toneGen_terminate() RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA1EN; __DSB(); - dmaWaiting->wakeup(); - gpio_setMode(CTCSS_OUT, INPUT); gpio_setMode(BEEP_OUT, INPUT); } @@ -276,130 +237,6 @@ bool toneGen_beepLocked() return (beepLockCount > 0) ? true : false; } -void toneGen_playAudioStream(const uint16_t* buf, const size_t len, - const uint32_t sampleRate, const bool circMode) -{ - if((buf == NULL) || (len == 0) || (sampleRate == 0)) return; - - toneGen_lockBeep(); - - RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; - RCC->APB1ENR |= RCC_APB1ENR_TIM7EN; - __DSB(); - - /* - * Timebase for triggering of DMA transfers. - * Bus frequency is 84MHz. - */ - uint32_t ratio = (84000000/sampleRate); - - TIM7->CNT = 0; - TIM7->PSC = 0; - TIM7->ARR = ratio; - TIM7->EGR = TIM_EGR_UG; - TIM7->DIER = TIM_DIER_UDE; - - /* - * DMA stream for sample transfer - */ - DMA1_Stream2->NDTR = len; - DMA1_Stream2->PAR = ((uint32_t) &(TIM3->CCR3)); - DMA1_Stream2->M0AR = ((uint32_t) buf); - DMA1_Stream2->CR = DMA_SxCR_CHSEL_0 // Channel 1 - | DMA_SxCR_PL // Very high priority - | DMA_SxCR_MSIZE_0 // 16 bit source size - | DMA_SxCR_PSIZE_0 // 16 bit destination size - | DMA_SxCR_MINC // Increment source pointer - | DMA_SxCR_DIR_0 // Memory to peripheral - | DMA_SxCR_TCIE // Transfer complete interrupt - | DMA_SxCR_TEIE; // Transfer error interrupt - - if(circMode) - { - DMA1_Stream2->CR |= DMA_SxCR_CIRC // Circular buffer mode - | DMA_SxCR_HTIE; // Half transfer interrupt - circularMode = true; - } - - DMA1_Stream2->CR |= DMA_SxCR_EN; // Enable transfer - - // Enable DMA interrupts - NVIC_ClearPendingIRQ(DMA1_Stream2_IRQn); - NVIC_SetPriority(DMA1_Stream2_IRQn, 10); - NVIC_EnableIRQ(DMA1_Stream2_IRQn); - - // Enable compare channel - TIM3->CCR3 = 0; - TIM3->CCER |= TIM_CCER_CC3E; - TIM3->CR1 |= TIM_CR1_CEN; - - // Start timer for DMA transfer triggering - TIM7->CR1 = TIM_CR1_CEN; -} - -bool toneGen_waitForStreamEnd() -{ - /* - * 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; - Thread *curThread = Thread::IRQgetCurrentThread(); - if(toneGen_beepLocked() == false) return false; - if((dmaWaiting != 0) && (dmaWaiting != curThread)) return false; - dmaWaiting = curThread; - do - { - Thread::IRQwait(); - { - FastInterruptEnableLock eLock(dLock); - Thread::yield(); - } - } while(dmaWaiting); - } - - // Outside critical section, here we finished waiting and everything is ok. - return true; -} - -void toneGen_stopAudioStream() -{ - // Critical section to avoid race conditions - FastInterruptDisableLock dLock; - - // Stop DMA triggering timer and TIM3 compare channel - TIM7->CR1 = 0; - TIM3->CCER &= ~TIM_CCER_CC3E; - - // Stop DMA transfer and clear pending interrupt flags - DMA1_Stream2->CR = 0; - DMA1_Stream2->M0AR = 0; - DMA1->LIFCR |= DMA_LIFCR_CTCIF2 - | DMA_LIFCR_CHTIF2 - | DMA_LIFCR_CTEIF2; - - // Shut down TIM7 clock - RCC->APB1ENR &= ~RCC_APB1ENR_TIM7EN; - __DSB(); - - // Unlock tones and wake up the thread waiting for completion - toneGen_unlockBeep(); - - if(dmaWaiting) - { - dmaWaiting->IRQwakeup(); - dmaWaiting = 0; - } - - // Clear flag for circular double buffered mode - circularMode = false; -} - bool toneGen_toneBusy() { /* diff --git a/platform/drivers/tones/toneGenerator_MDx.h b/platform/drivers/tones/toneGenerator_MDx.h index c48a92cb..820e5ab5 100644 --- a/platform/drivers/tones/toneGenerator_MDx.h +++ b/platform/drivers/tones/toneGenerator_MDx.h @@ -31,8 +31,8 @@ extern "C" { /** * Tone generator for MDx family, used primarily for CTCSS tones and user - * interface "beeps". It also provides a means to encode AFSK/4FSK data and to - * reproduce arbitrary audio samples. + * interface "beeps". It also provides an high-frequency PWM timebase to encode + * AFSK/4FSK data and to reproduce arbitrary audio samples. * * WARNING: this driver implements a priority mechanism between "beeps", FSK * modulation and audio playback. A request for FSK modulation or audio playback @@ -42,7 +42,6 @@ extern "C" { * This driver uses the following peripherals of the STM32F405 MCU: * - TIM3 as high-frequency PWM timebase. * - TIM14 as timebase for CTCSS and "beeps" through a sine table. - * - TIM7 and DMA1_Stream2 for AFSK, 4FSK and playback of audio streams. */ /** @@ -109,42 +108,6 @@ void toneGen_unlockBeep(); */ bool toneGen_beepLocked(); -/** - * Reproduce an audio stream, sending audio stream to both the speaker and the - * rtx baseband IC. - * 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 - * and, when filling it with data, one must remember that the upper 8 bit are - * DISCARDED. - * - * @param buf: pointer to a buffer containing the audio samples. - * @param len: length of the data buffer. - * @param sampleRate: sample rate of the audio stream in samples per second. - * @param circMode: treat buf as a double circular buffer, continuously - * reproducing its content. - */ -void toneGen_playAudioStream(const uint16_t *buf, const size_t len, - const uint32_t sampleRate, const bool circMode); - -/** - * 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_waitForStreamEnd return to the caller. - */ -void toneGen_stopAudioStream(); - /** * Get the current status of the "beep"/AFSK/audio generator stage. *