Files
edgetx-gx12/radio/src/targets/sky9x/audio_driver.cpp
T

185 lines
5.0 KiB
C++

/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
volatile uint8_t dacStarted = false;
#if !defined(SIMU)
#if !defined(SOFTWARE_VOLUME)
const int8_t volumeScale[VOLUME_LEVEL_MAX+1] =
{
0, 2, 4, 6, 8, 10, 13, 17, 22, 27, 33, 40,
64, 82, 96, 105, 112, 117, 120, 122, 124, 125, 126, 127
} ;
#endif
void setSampleRate(uint32_t frequency)
{
Tc *ptc ;
uint32_t timer ;
timer = Master_frequency / (8 * frequency) ; // MCK/8 and 100 000 Hz
if (timer > 65535)
timer = 65535 ;
if (timer < 2)
timer = 2 ;
ptc = TC0 ; // Tc block 0 (TC0-2)
ptc->TC_CHANNEL[1].TC_CCR = TC_CCR0_CLKDIS ; // Stop clock
ptc->TC_CHANNEL[1].TC_RC = timer ; // 100 000 Hz
ptc->TC_CHANNEL[1].TC_RA = timer >> 1 ;
ptc->TC_CHANNEL[1].TC_CCR = 5 ; // Enable clock and trigger it (may only need trigger)
}
// Start TIMER1 at 100000Hz, used for DACC trigger
void dacTimerStart()
{
Tc *ptc ;
uint32_t timer ;
// Enable peripheral clock TC0 = bit 23 thru TC5 = bit 28
PMC->PMC_PCER0 |= 0x01000000L ; // Enable peripheral clock to TC1
timer = Master_frequency / 800000 ; // MCK/8 and 100 000 Hz
ptc = TC0 ; // Tc block 0 (TC0-2)
ptc->TC_BCR = 0 ; // No sync
ptc->TC_BMR = 0 ;
ptc->TC_CHANNEL[1].TC_CMR = 0x00008000 ; // Waveform mode
ptc->TC_CHANNEL[1].TC_RC = timer ; // 100 000 Hz
ptc->TC_CHANNEL[1].TC_RA = timer >> 1 ;
ptc->TC_CHANNEL[1].TC_CMR = 0x0009C001 ; // 0000 0000 0000 1001 1100 0000 0000 0001
// MCK/8, set @ RA, Clear @ RC waveform
ptc->TC_CHANNEL[1].TC_CCR = 5 ; // Enable clock and trigger it (may only need trigger)
// Sound_g.Frequency = 1000 ;
}
// Configure DAC0
// Not sure why PB14 has not be allocated to the DAC, although it is an EXTRA function
// So maybe it is automatically done
void dacInit()
{
dacTimerStart() ;
PMC->PMC_PCER0 |= 0x40000000L ; // Enable peripheral clock to DAC
Dacc *dacptr = DACC;
dacptr->DACC_MR = 0x0B000215L ; // 0000 1011 0000 0001 0000 0010 0001 0101
dacptr->DACC_CHER = 1 ; // Enable channel 0
dacptr->DACC_CDR = 2048 ; // Half amplitude
dacptr->DACC_PTCR = DACC_PTCR_TXTEN ;
NVIC_EnableIRQ(DACC_IRQn) ;
}
inline void dacStart()
{
PMC->PMC_PCER0 |= 0x40000000L ; // Enable peripheral clock to DAC
DACC->DACC_IER = DACC_IER_ENDTX ;
dacStarted = true;
}
inline void dacStop()
{
DACC->DACC_IDR = DACC_IDR_ENDTX ; // Disable interrupt
dacStarted = false;
}
void audioConsumeCurrentBuffer()
{
if (!dacStarted) {
dacStart();
}
}
extern "C" void DAC_IRQHandler()
{
uint32_t sr = DACC->DACC_ISR;
if (sr & DACC_ISR_ENDTX) {
audioQueue.buffersFifo.freeNextFilledBuffer();
const AudioBuffer * nextBuffer = audioQueue.buffersFifo.getNextFilledBuffer();
if (nextBuffer) {
// Try the first PDC buffer
if ((DACC->DACC_TCR == 0) && (DACC->DACC_TNCR == 0)) {
DACC->DACC_TPR = CONVERT_PTR_UINT(nextBuffer->data);
DACC->DACC_TCR = nextBuffer->size/2;
DACC->DACC_PTCR = DACC_PTCR_TXTEN;
return;
}
// Try the second PDC buffer
if (DACC->DACC_TNCR == 0) {
DACC->DACC_TNPR = CONVERT_PTR_UINT(nextBuffer->data);
DACC->DACC_TNCR = nextBuffer->size/2;
DACC->DACC_PTCR = DACC_PTCR_TXTEN;
return;
}
}
else {
dacStop();
}
}
}
// Sound routines
void audioInit()
{
Pio * pioptr ;
dacInit() ;
pioptr = PIOA ;
pioptr->PIO_CODR = 0x02000000L ; // Set bit A25 OFF
pioptr->PIO_PER = 0x02000000L ; // Enable bit A25 (Stock buzzer)
pioptr->PIO_OER = 0x02000000L ; // Set bit A25 as output
#if defined(REVX)
configure_pins( PIO_PC26, PIN_ENABLE | PIN_LOW | PIN_OUTPUT | PIN_PORTC | PIN_NO_PULLUP ) ;
PIOC->PIO_CODR = PIO_PC26 ;
#endif
}
void audioEnd()
{
DACC->DACC_IDR = DACC_IDR_ENDTX ;
DACC->DACC_IDR = DACC_IDR_TXBUFE ;
NVIC_DisableIRQ(DACC_IRQn) ;
TWI0->TWI_IDR = TWI_IDR_TXCOMP ;
NVIC_DisableIRQ(TWI0_IRQn) ;
PMC->PMC_PCER0 &= ~0x00080000L ; // Disable peripheral clock to TWI0
PMC->PMC_PCER0 &= ~0x40000000L ; // Disable peripheral clock to DAC
}
#if !defined(SOFTWARE_VOLUME)
void setScaledVolume(uint8_t volume)
{
volumeRequired = volumeScale[min<uint8_t>(volume, VOLUME_LEVEL_MAX)];
__disable_irq() ;
i2cCheck() ;
__enable_irq() ;
}
#endif
#endif // #if !defined(SIMU)