diff --git a/radio/src/audio.cpp b/radio/src/audio.cpp index d62e34767..c58c5db4c 100644 --- a/radio/src/audio.cpp +++ b/radio/src/audio.cpp @@ -30,6 +30,7 @@ #endif #include "model_audio.h" +#include "hal/audio_driver.h" extern RTOS_MUTEX_HANDLE audioMutex; @@ -366,8 +367,6 @@ void audioTask(void * pdata) RTOS_WAIT_TICKS(1); } - setSampleRate(AUDIO_SAMPLE_RATE); - #if defined(PCBX12S) || defined(RADIO_TX16S) || defined(RADIO_F16) || defined(RADIO_V16) // The audio amp needs ~2s to start RTOS_WAIT_MS(1000); // 1s @@ -378,14 +377,14 @@ void audioTask(void * pdata) DEBUG_TIMER_START(debugTimerAudioDuration); audioQueue.wakeup(); DEBUG_TIMER_STOP(debugTimerAudioDuration); - RTOS_WAIT_MS(4); + RTOS_WAIT_MS(4); // ??? } } #endif inline void mixSample(audio_data_t * result, int sample, unsigned int fade) { - *result = limit(AUDIO_DATA_MIN, *result + ((sample >> fade) >> (16-AUDIO_BITS_PER_SAMPLE)), AUDIO_DATA_MAX); + *result += (sample >> fade); } #define RIFF_CHUNK_SIZE 12 @@ -646,15 +645,13 @@ void AudioQueue::wakeup() buffer->data[i] = (int16_t) (((tmpSample * currentSpeakerVolume) / VOLUME_LEVEL_MAX) + AUDIO_DATA_SILENCE); } buffersFifo.audioPushBuffer(); - } - else { + } else { break; } #else buffersFifo.audioPushBuffer(); #endif - } - else { + } else { // break the endless loop break; } diff --git a/radio/src/audio.h b/radio/src/audio.h index b9b6fd751..fecf15598 100644 --- a/radio/src/audio.h +++ b/radio/src/audio.h @@ -23,10 +23,13 @@ #include #include + #include "ff.h" #include "edgetx_types.h" #include "dataconstants.h" +#include "hal/audio_driver.h" + /* Implements a bit field, number of bits is set by the template, each bit can be modified and read by the provided methods. @@ -74,10 +77,17 @@ constexpr uint8_t AUDIO_FILENAME_MAXLEN = (AUDIO_LUA_FILENAME_MAXLEN > AUDIO_MOD #define AUDIO_QUEUE_LENGTH (16) // must be a power of 2! -#define AUDIO_SAMPLE_RATE (32000) #define AUDIO_BUFFER_DURATION (10) #define AUDIO_BUFFER_SIZE (AUDIO_SAMPLE_RATE*AUDIO_BUFFER_DURATION/1000) +#if !defined(AUDIO_SAMPLE_FMT) + #if defined(SIMU) || defined(AUDIO_SPI) + #define AUDIO_SAMPLE_FMT AUDIO_SAMPLE_FMT_S16 + #else + #define AUDIO_SAMPLE_FMT AUDIO_SAMPLE_FMT_U12 + #endif +#endif + #if defined(SIMU) && defined(SIMU_AUDIO) #define AUDIO_BUFFER_COUNT (10) // simulator needs more buffers for smooth audio #elif defined(PCBX12S) @@ -94,41 +104,19 @@ constexpr uint8_t AUDIO_FILENAME_MAXLEN = (AUDIO_LUA_FILENAME_MAXLEN > AUDIO_MOD #define USE_SETTINGS_VOLUME (127) -#if defined(AUDIO_DUAL_BUFFER) -enum AudioBufferState -{ - AUDIO_BUFFER_FREE, - AUDIO_BUFFER_FILLED, - AUDIO_BUFFER_PLAYING -}; -#endif - -#if defined(SIMU) - typedef uint16_t audio_data_t; - #define AUDIO_DATA_SILENCE 0x8000 - #define AUDIO_DATA_MIN 0 - #define AUDIO_DATA_MAX 0xffff - #define AUDIO_BITS_PER_SAMPLE 16 -#elif defined(PCBX12S) || defined(PCBNV14) +#if AUDIO_SAMPLE_FMT == AUDIO_SAMPLE_FMT_S16 typedef int16_t audio_data_t; - #define AUDIO_DATA_SILENCE 0 - #define AUDIO_DATA_MIN INT16_MIN - #define AUDIO_DATA_MAX INT16_MAX - #define AUDIO_BITS_PER_SAMPLE 16 -#else + #define AUDIO_DATA_SILENCE 0 +#elif AUDIO_SAMPLE_FMT == AUDIO_SAMPLE_FMT_U12 typedef uint16_t audio_data_t; - #define AUDIO_DATA_SILENCE (0x8000 >> 4) - #define AUDIO_DATA_MIN 0 - #define AUDIO_DATA_MAX 0x0fff - #define AUDIO_BITS_PER_SAMPLE 12 + #define AUDIO_DATA_SILENCE 0x8000 +#else + #error "Unknown audio sample format" #endif struct AudioBuffer { audio_data_t data[AUDIO_BUFFER_SIZE]; uint16_t size; -#if defined(AUDIO_DUAL_BUFFER) - uint8_t state; -#endif }; extern AudioBuffer audioBuffers[AUDIO_BUFFER_COUNT]; @@ -314,115 +302,42 @@ class AudioBufferFifo { private: volatile uint8_t readIdx; volatile uint8_t writeIdx; - volatile bool bufferFull; - - // readIdx == writeIdx -> buffer empty - // readIdx == writeIdx + 1 -> buffer full inline uint8_t nextBufferIdx(uint8_t idx) const { - return (idx >= AUDIO_BUFFER_COUNT-1 ? 0 : idx+1); + return (idx >= AUDIO_BUFFER_COUNT - 1 ? 0 : idx + 1); } - bool full() const - { - return bufferFull; - } + bool full() const { return readIdx == nextBufferIdx(writeIdx); } + bool empty() const { return readIdx == writeIdx; } + uint8_t used() const { return (writeIdx - readIdx) % AUDIO_BUFFER_COUNT; } - bool empty() const - { - return (readIdx == writeIdx) && !bufferFull; - } - - uint8_t used() const - { - return bufferFull ? AUDIO_BUFFER_COUNT : writeIdx - readIdx; - } - - public: - AudioBufferFifo() : readIdx(0), writeIdx(0), bufferFull(false) + public: + AudioBufferFifo() : readIdx(0), writeIdx(0) { memset(audioBuffers, 0, sizeof(audioBuffers)); } - // returns an empty buffer to be filled wit data and put back into FIFO with audioPushBuffer() - AudioBuffer * getEmptyBuffer() const + // returns an empty buffer to be filled with data and put back into FIFO + // with audioPushBuffer() + AudioBuffer *getEmptyBuffer() const { -#if defined(AUDIO_DUAL_BUFFER) - AudioBuffer * buffer = &audioBuffers[writeIdx]; - return buffer->state == AUDIO_BUFFER_FREE ? buffer : NULL; -#else - return full() ? NULL : &audioBuffers[writeIdx]; -#endif + return full() ? nullptr : &audioBuffers[writeIdx]; } // puts filled buffer into FIFO - void audioPushBuffer() - { - audioDisableIrq(); -#if defined(AUDIO_DUAL_BUFFER) - AudioBuffer * buffer = &audioBuffers[writeIdx]; - buffer->state = AUDIO_BUFFER_FILLED; -#endif - writeIdx = nextBufferIdx(writeIdx); - bufferFull = (writeIdx == readIdx); - audioEnableIrq(); - } - - // returns a pointer to the audio buffer to be played - const AudioBuffer * getNextFilledBuffer() - { -#if defined(AUDIO_DUAL_BUFFER) - uint8_t idx = readIdx; - do { - AudioBuffer * buffer = &audioBuffers[idx]; - if (buffer->state == AUDIO_BUFFER_FILLED) { - buffer->state = AUDIO_BUFFER_PLAYING; - readIdx = idx; - return buffer; - } - idx = nextBufferIdx(idx); - } while (idx != writeIdx); // this fixes a bug if all buffers are filled - return NULL; -#else - return empty() ? NULL : &audioBuffers[readIdx]; -#endif - } + void audioPushBuffer() { writeIdx = nextBufferIdx(writeIdx); } // frees the last played buffer - void freeNextFilledBuffer() + void freeNextFilledBuffer() { readIdx = nextBufferIdx(readIdx); } + + // returns a pointer to the audio buffer to be played + const AudioBuffer *getNextFilledBuffer() { - audioDisableIrq(); -#if defined(AUDIO_DUAL_BUFFER) - if (audioBuffers[readIdx].state == AUDIO_BUFFER_PLAYING) { - audioBuffers[readIdx].state = AUDIO_BUFFER_FREE; - readIdx = nextBufferIdx(readIdx); - bufferFull = false; - } -#else - readIdx = nextBufferIdx(readIdx); - bufferFull = false; -#endif - audioEnableIrq(); - } - - bool filledAtleast(int noBuffers) const - { -#if defined(AUDIO_DUAL_BUFFER) - int count = 0; - for(int n= 0; n= noBuffers) { - return true; - } - } - } - return false; -#else - return used() >= noBuffers; -#endif + return empty() ? nullptr : &audioBuffers[readIdx]; } + bool filledAtleast(int noBuffers) const { return used() >= noBuffers; } }; class AudioFragmentFifo diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp index 0a78cb7b7..7e9c07e40 100644 --- a/radio/src/cli.cpp +++ b/radio/src/cli.cpp @@ -22,21 +22,22 @@ #include #include +#include "hal/adc_driver.h" +#include "hal/audio_driver.h" +#include "hal/fatfs_diskio.h" +#include "hal/module_port.h" #include "hal/serial_driver.h" +#include "hal/storage.h" +#include "hal/usb_driver.h" +#include "hal/watchdog_driver.h" + #include "edgetx.h" #include "timers_driver.h" -#include "hal/watchdog_driver.h" #if defined(BLUETOOTH) #include "bluetooth_driver.h" #endif -#include "hal/adc_driver.h" -#include "hal/module_port.h" -#include "hal/fatfs_diskio.h" -#include "hal/storage.h" -#include "hal/usb_driver.h" - #include "tasks.h" #include "tasks/mixer_task.h" @@ -975,7 +976,7 @@ int cliSet(const char **argv) else if (!strcmp(argv[1], "volume")) { int level = 0; if (toInt(argv, 2, &level) > 0) { - setVolume(level); + audioSetVolume(level); } else { cliSerialPrint("%s: Invalid argument \"%s\" \"%s\"", argv[0], argv[1], argv[2]); diff --git a/radio/src/edgetx.cpp b/radio/src/edgetx.cpp index 2385f4217..86252be40 100644 --- a/radio/src/edgetx.cpp +++ b/radio/src/edgetx.cpp @@ -34,6 +34,7 @@ #include "hal/watchdog_driver.h" #include "hal/abnormal_reboot.h" #include "hal/usb_driver.h" +#include "hal/audio_driver.h" #include "timers_driver.h" @@ -1461,7 +1462,7 @@ void edgeTxInit() currentSpeakerVolume = requiredSpeakerVolume = g_eeGeneral.speakerVolume + VOLUME_LEVEL_DEF; #if !defined(SOFTWARE_VOLUME) - setScaledVolume(currentSpeakerVolume); + audioSetVolume(currentSpeakerVolume); #endif #endif diff --git a/radio/src/functions.cpp b/radio/src/functions.cpp index f72134589..20f0c317e 100644 --- a/radio/src/functions.cpp +++ b/radio/src/functions.cpp @@ -21,6 +21,9 @@ #include "edgetx.h" #include "switches.h" + +#include "hal/audio_driver.h" + #include "boards/generic_stm32/rgb_leds.h" #if defined(COLORLCD) diff --git a/radio/src/gui/128x64/radio_setup.cpp b/radio/src/gui/128x64/radio_setup.cpp index fb5e04448..da7fea236 100644 --- a/radio/src/gui/128x64/radio_setup.cpp +++ b/radio/src/gui/128x64/radio_setup.cpp @@ -25,6 +25,7 @@ #include "tasks/mixer_task.h" #include "hal/adc_driver.h" #include "hal/usb_driver.h" +#include "hal/audio_driver.h" #include "input_mapping.h" const unsigned char sticks[] = { diff --git a/radio/src/gui/212x64/radio_setup.cpp b/radio/src/gui/212x64/radio_setup.cpp index f6478df0c..c5a4f3c25 100644 --- a/radio/src/gui/212x64/radio_setup.cpp +++ b/radio/src/gui/212x64/radio_setup.cpp @@ -21,6 +21,7 @@ #include "hal/adc_driver.h" #include "hal/usb_driver.h" +#include "hal/audio_driver.h" #define LANGUAGE_PACKS_DEFINITION diff --git a/radio/src/gui/colorlcd/radio/radio_setup.cpp b/radio/src/gui/colorlcd/radio/radio_setup.cpp index 819934483..3d819d42a 100644 --- a/radio/src/gui/colorlcd/radio/radio_setup.cpp +++ b/radio/src/gui/colorlcd/radio/radio_setup.cpp @@ -25,6 +25,8 @@ #include "hal/adc_driver.h" #include "hal/usb_driver.h" +#include "hal/audio_driver.h" + #include "input_mapping.h" #include "libopenui.h" #include "edgetx.h" diff --git a/radio/src/hal/audio_driver.h b/radio/src/hal/audio_driver.h new file mode 100644 index 000000000..70c5c482b --- /dev/null +++ b/radio/src/hal/audio_driver.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#pragma once + +#include + +// Audio volume is defined between 0 and VOLUME_LEVEL_MAX. +#define VOLUME_LEVEL_MAX 23 +#define VOLUME_LEVEL_DEF 12 + +#define AUDIO_SAMPLE_RATE 32000 + +#define AUDIO_SAMPLE_FMT_S16 0 +#define AUDIO_SAMPLE_FMT_U12 1 + + +void audioSetVolume(uint8_t volume); + diff --git a/radio/src/main.cpp b/radio/src/main.cpp index 80195a47d..b6ff7ddbc 100644 --- a/radio/src/main.cpp +++ b/radio/src/main.cpp @@ -23,6 +23,8 @@ #include "hal/storage.h" #include "hal/abnormal_reboot.h" #include "hal/usb_driver.h" +#include "hal/audio_driver.h" + #include "edgetx.h" #include "lua/lua_states.h" @@ -251,7 +253,7 @@ void checkSpeakerVolume() if (currentSpeakerVolume != requiredSpeakerVolume) { currentSpeakerVolume = requiredSpeakerVolume; #if !defined(SOFTWARE_VOLUME) - setScaledVolume(currentSpeakerVolume); + audioSetVolume(currentSpeakerVolume); #endif } #endif diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index ab0a110c4..730eb7b45 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -29,6 +29,7 @@ #include "hal/adc_driver.h" #include "hal/trainer_driver.h" #include "hal/switch_driver.h" +#include "hal/audio_driver.h" #define DELAY_POS_MARGIN 3 diff --git a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp index 37e704e7b..751a8317e 100644 --- a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp @@ -32,6 +32,7 @@ #include "hal/switch_driver.h" #include "hal/adc_driver.h" +#include "hal/audio_driver.h" // // WARNING: diff --git a/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp b/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp index e582b5f72..48f8d174a 100644 --- a/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp +++ b/radio/src/targets/common/arm/stm32/audio_dac_driver.cpp @@ -20,37 +20,48 @@ */ #include "hal/gpio.h" +#include "hal/audio_driver.h" + #include "stm32_gpio.h" #include "stm32_timer.h" #include "stm32_dma.h" #include "edgetx.h" -#if !defined(SIMU) const AudioBuffer * nextBuffer = nullptr; -void setSampleRate(uint32_t frequency) -{ - uint32_t timer = (PERI1_FREQUENCY * TIMER_MULT_APB1) / frequency - 1 ; // MCK/8 and 100 000 Hz - AUDIO_TIMER->CR1 &= ~TIM_CR1_CEN ; - AUDIO_TIMER->CNT = 0 ; - AUDIO_TIMER->ARR = limit(2, timer, 65535) ; - AUDIO_TIMER->CR1 |= TIM_CR1_CEN ; -} -// Start TIMER6 at 100000Hz, used for DAC trigger -void dacTimerInit() +// Init timer that triggers the DAC conversion +// at sampling frequency +static void dac_trigger_init() { stm32_timer_enable_clock(AUDIO_TIMER); - AUDIO_TIMER->PSC = 0 ; // Max speed - AUDIO_TIMER->ARR = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 100000 - 1 ; // 10 uS, 100 kHz - AUDIO_TIMER->CR2 = 0 ; - AUDIO_TIMER->CR2 = 0x20 ; - AUDIO_TIMER->CR1 = TIM_CR1_CEN ; + + // set timer to: 10 uS, 100 kHz + AUDIO_TIMER->PSC = 0; + AUDIO_TIMER->ARR = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 100000 - 1; + + // reset counter + AUDIO_TIMER->CNT = 0; + + // set expiry to sample period (1 / sample_rate) + AUDIO_TIMER->ARR = + (PERI1_FREQUENCY * TIMER_MULT_APB1) / AUDIO_SAMPLE_RATE - 1; + + // Master mode selection + // + // 000: Reset + AUDIO_TIMER->CR2 = 0; + // 010: The update event is selected as trigger output (TRGO) + // (used to trigger DAC conversion) + AUDIO_TIMER->CR2 = TIM_CR2_MMS_1; + + // enable timer + AUDIO_TIMER->CR1 |= TIM_CR1_CEN; } #if defined(AUDIO_MUTE_GPIO) -static inline void setMutePin(bool enabled) +static inline void set_mute_pin(bool enabled) { #if defined(INVERTED_MUTE_PIN) enabled = !enabled; @@ -58,7 +69,7 @@ static inline void setMutePin(bool enabled) gpio_write(AUDIO_MUTE_GPIO, enabled); } -static inline bool getMutePin(void) +static inline bool get_mute_pin(void) { bool enabled = gpio_read(AUDIO_MUTE_GPIO) ? 1 : 0; #if defined(INVERTED_MUTE_PIN) @@ -76,30 +87,45 @@ void dacInit() #if defined(AUDIO_MUTE_GPIO) // Mute before init anything gpio_init(AUDIO_MUTE_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); - setMutePin(true); + set_mute_pin(true); #endif - dacTimerInit(); + dac_trigger_init(); gpio_init_analog(AUDIO_OUTPUT_GPIO); stm32_dma_enable_clock(AUDIO_DMA); + // Disable DMA stream + AUDIO_DMA_Stream->CR &= ~DMA_SxCR_EN; + + // clear DMA stream flags + AUDIO_DMA->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | + DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; + // Chan 7, 16-bit wide, Medium priority, memory increments - AUDIO_DMA_Stream->CR &= ~DMA_SxCR_EN ; // Disable DMA - AUDIO_DMA->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5 ; // Write ones to clear bits - AUDIO_DMA_Stream->CR = DMA_SxCR_CHSEL_0 | DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_2 | DMA_SxCR_PL_0 | - DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_CIRC ; - AUDIO_DMA_Stream->PAR = CONVERT_PTR_UINT(&DAC->DHR12R1); - // AUDIO_DMA_Stream->M0AR = CONVERT_PTR_UINT(Sine_values); - AUDIO_DMA_Stream->FCR = 0x05 ; //DMA_SxFCR_DMDIS | DMA_SxFCR_FTH_0 ; - // AUDIO_DMA_Stream->NDTR = 100 ; + AUDIO_DMA_Stream->CR = DMA_SxCR_CHSEL_0 | DMA_SxCR_CHSEL_1 | + DMA_SxCR_CHSEL_2 | DMA_SxCR_PL_0 | DMA_SxCR_MSIZE_0 | + DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC | DMA_SxCR_DIR_0 | + DMA_SxCR_CIRC; + + // write to DAC channel 1 (12 bits, left-aligned) + AUDIO_DMA_Stream->PAR = CONVERT_PTR_UINT(&DAC->DHR12L1); + + // disable direct mode and set FIFO threshold to half + AUDIO_DMA_Stream->FCR = DMA_SxFCR_DMDIS | DMA_SxFCR_FTH_0; LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_DAC1); - DAC->DHR12R1 = 2010 ; - DAC->SR = DAC_SR_DMAUDR1 ; // Write 1 to clear flag - DAC->CR = DAC_CR_TEN1 | DAC_CR_EN1 ; // Enable DAC - NVIC_EnableIRQ(AUDIO_TIM_IRQn); // TODO needed? - NVIC_SetPriority(AUDIO_TIM_IRQn, 7); + + // set data registre to silence + DAC->DHR12L1 = AUDIO_DATA_SILENCE; + + // clear underrun flag + DAC->SR = DAC_SR_DMAUDR1; + + // use TIM6 TRGO as trigger (TSEL1 = TSEL2 = 000) + // enable DAC & channel 1 trigger + DAC->CR = DAC_CR_TEN1 | DAC_CR_EN1; + NVIC_EnableIRQ(AUDIO_DMA_Stream_IRQn); NVIC_SetPriority(AUDIO_DMA_Stream_IRQn, 7); } @@ -116,32 +142,32 @@ void audioMute() } else if (now - audioQueue.lastAudioPlayTime > AUDIO_MUTE_DELAY / 10) { // delay expired, we may mute - setMutePin(true); + set_mute_pin(true); } #else // mute - setMutePin(true); + set_mute_pin(true); #endif } void audioUnmute() { -if(isFunctionActive(FUNCTION_DISABLE_AUDIO_AMP)) { - setMutePin(true); - return; -} + if (isFunctionActive(FUNCTION_DISABLE_AUDIO_AMP)) { + set_mute_pin(true); + return; + } #if defined(AUDIO_UNMUTE_DELAY) // if muted - if (getMutePin()) { + if (get_mute_pin()) { // ..un-mute - setMutePin(false); + set_mute_pin(false); RTOS_WAIT_MS(AUDIO_UNMUTE_DELAY); } // reset the mute delay audioQueue.lastAudioPlayTime = 0; #else - setMutePin(false); + set_mute_pin(false); #endif } #endif @@ -151,39 +177,40 @@ void audioConsumeCurrentBuffer() if (!nextBuffer) { nextBuffer = audioQueue.buffersFifo.getNextFilledBuffer(); if (nextBuffer) { + #if defined(AUDIO_MUTE_GPIO) audioUnmute(); #endif - AUDIO_DMA_Stream->CR &= ~DMA_SxCR_EN; // Disable DMA channel - AUDIO_DMA->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; // Write ones to clear bits + + // Disable DMA stream + AUDIO_DMA_Stream->CR &= ~DMA_SxCR_EN; + + // reset DMA flags + AUDIO_DMA->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | + DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | + DMA_HIFCR_CFEIF5; + + // set DMA buffer AUDIO_DMA_Stream->M0AR = CONVERT_PTR_UINT(nextBuffer->data); AUDIO_DMA_Stream->NDTR = nextBuffer->size; - AUDIO_DMA_Stream->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA channel and interrupt - DAC->SR = DAC_SR_DMAUDR1; // Write 1 to clear flag - DAC->CR |= DAC_CR_EN1 | DAC_CR_DMAEN1; // Enable DAC - } + + // enable DMA stream and transfer complete interrupt + AUDIO_DMA_Stream->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; + + // clear underrun flag + DAC->SR = DAC_SR_DMAUDR1; + + // enable DAC + DAC->CR |= DAC_CR_EN1 | DAC_CR_DMAEN1; + + } else { #if defined(AUDIO_MUTE_GPIO) - else { audioMute(); - } #endif + } } } -void dacStart() -{ - AUDIO_DMA->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5 ; // Write ones to clear bits - AUDIO_DMA_Stream->CR |= DMA_SxCR_CIRC | DMA_SxCR_EN ; // Enable DMA channel - DAC->SR = DAC_SR_DMAUDR1 ; // Write 1 to clear flag - DAC->CR |= DAC_CR_EN1 | DAC_CR_DMAEN1 ; // Enable DAC -} - -void dacStop() -{ - AUDIO_DMA_Stream->CR &= ~DMA_SxCR_CIRC ; -} - - // Sound routines void audioInit() { @@ -192,38 +219,42 @@ void audioInit() void audioEnd() { - DAC->CR = 0 ; - AUDIO_TIMER->CR1 = 0 ; - // Also need to turn off any possible interrupts - NVIC_DisableIRQ(AUDIO_TIM_IRQn) ; - NVIC_DisableIRQ(AUDIO_DMA_Stream_IRQn) ; -} + DAC->CR = 0; + AUDIO_TIMER->CR1 = 0; -extern "C" void AUDIO_TIM_IRQHandler() -{ - DEBUG_INTERRUPT(INT_AUDIO); - DAC->CR &= ~DAC_CR_DMAEN1 ; // Stop DMA requests -#if defined(STM32F2) - DAC->CR &= ~DAC_CR_DMAUDRIE1 ; // Stop underrun interrupt -#endif - DAC->SR = DAC_SR_DMAUDR1 ; // Write 1 to clear flag + // Also need to turn off any possible interrupts + NVIC_DisableIRQ(AUDIO_TIM_IRQn); + NVIC_DisableIRQ(AUDIO_DMA_Stream_IRQn); } extern "C" void AUDIO_DMA_Stream_IRQHandler() { - AUDIO_DMA_Stream->CR &= ~DMA_SxCR_TCIE ; // Stop interrupt - AUDIO_DMA->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5 ; // Write ones to clear flags - AUDIO_DMA_Stream->CR &= ~DMA_SxCR_EN ; // Disable DMA channel + // disable transfer complete interrupt + AUDIO_DMA_Stream->CR &= ~DMA_SxCR_TCIE; + // reset DMA flags + AUDIO_DMA->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | + DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; + + // Disable DMA stream + AUDIO_DMA_Stream->CR &= ~DMA_SxCR_EN; + + // get next buffer if any if (nextBuffer) audioQueue.buffersFifo.freeNextFilledBuffer(); - nextBuffer = audioQueue.buffersFifo.getNextFilledBuffer(); + if (nextBuffer) { AUDIO_DMA_Stream->M0AR = CONVERT_PTR_UINT(nextBuffer->data); AUDIO_DMA_Stream->NDTR = nextBuffer->size; - AUDIO_DMA->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5 ; // Write ones to clear bits - AUDIO_DMA_Stream->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE ; // Enable DMA channel - DAC->SR = DAC_SR_DMAUDR1; // Write 1 to clear flag + + // reset DMA flags (again?) + AUDIO_DMA->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | + DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; + + // enable DMA stream and transfer complete interrupt + AUDIO_DMA_Stream->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; + + // clear underrun flag + DAC->SR = DAC_SR_DMAUDR1; } } -#endif // #if !defined(SIMU) diff --git a/radio/src/targets/common/arm/stm32/vs1053b.cpp b/radio/src/targets/common/arm/stm32/vs1053b.cpp index 3a59ac143..b4784f965 100644 --- a/radio/src/targets/common/arm/stm32/vs1053b.cpp +++ b/radio/src/targets/common/arm/stm32/vs1053b.cpp @@ -25,7 +25,9 @@ #include "stm32_spi.h" #include "hal/gpio.h" +#include "hal/audio_driver.h" +#include "board.h" #include "edgetx.h" #if !defined(SIMU) @@ -187,25 +189,7 @@ uint16_t audioSpiReadReg(uint8_t address) return result; } -uint16_t audioSpiReadCmd(uint8_t address) -{ - if (!audioWaitDreq(100)) - return 0; - - audioSpiSetSpeed(SPI_SPEED_64); - XDCS_HIGH(); - CS_LOW(); - audioSpiReadWriteByte(VS_READ_COMMAND); - audioSpiReadWriteByte(address); - uint16_t result = audioSpiReadWriteByte(0) << 8; - result |= audioSpiReadWriteByte(0); - delay_01us(50); // 5us - CS_HIGH(); - audioSpiSetSpeed(SPI_SPEED_8); - return result; -} - -uint8_t audioSpiWriteCmd(uint8_t address, uint16_t data) +static uint8_t audioSpiWriteCmd(uint8_t address, uint16_t data) { if (!audioWaitDreq(100)) return 0; @@ -400,9 +384,19 @@ void audioInit() audioSendRiffHeader(); } -uint8_t * currentBuffer = nullptr; -uint32_t currentSize = 0; -int16_t newVolume = -1; +static uint8_t * currentBuffer = nullptr; +static uint32_t currentSize = 0; +static int16_t newVolume = -1; + +static void set_volume(uint8_t volume) +{ + newVolume = volume; +} + +static int32_t get_volume() +{ + return -1; // TODO +} void audioSetCurrentBuffer(const AudioBuffer * buffer) { @@ -454,29 +448,19 @@ void audioConsumeCurrentBuffer() // max value is 126 #define VOLUME_MIN_DB 40 -void setScaledVolume(uint8_t volume) +void audioSetVolume(uint8_t volume) { if (volume > VOLUME_LEVEL_MAX) { volume = VOLUME_LEVEL_MAX; } // maximum volume is 0x00 and total silence is 0xFE if (volume == 0) { - setVolume(0xFE); // silence + set_volume(0xFE); // silence } else { uint32_t vol = (VOLUME_MIN_DB * 2) - ((uint32_t)volume * (VOLUME_MIN_DB * 2)) / VOLUME_LEVEL_MAX; - setVolume(vol); + set_volume(vol); } } -void setVolume(uint8_t volume) -{ - newVolume = volume; -} - -int32_t getVolume() -{ - return -1; // TODO -} - #endif diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 897188366..08a8b7257 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -261,19 +261,6 @@ bool isBacklightEnabled(); // Audio driver void audioInit(); void audioConsumeCurrentBuffer(); -#define audioDisableIrq() // interrupts must stay enabled on Horus -#define audioEnableIrq() // interrupts must stay enabled on Horus -#if defined(PCBX12S) -#define setSampleRate(freq) -#else -void setSampleRate(uint32_t frequency); -#define audioWaitReady() -#endif -void setScaledVolume(uint8_t volume); -void setVolume(uint8_t volume); -int32_t getVolume(); -#define VOLUME_LEVEL_MAX 23 -#define VOLUME_LEVEL_DEF 12 // Telemetry driver #define INTMODULE_FIFO_SIZE 512 diff --git a/radio/src/targets/nv14/board.h b/radio/src/targets/nv14/board.h index e19af17ef..3b4da3cb5 100644 --- a/radio/src/targets/nv14/board.h +++ b/radio/src/targets/nv14/board.h @@ -208,19 +208,6 @@ bool audioChipReset(); #define SPI_SPEED_128 6 #define SPI_SPEED_256 7 -#define audioDisableIrq() // interrupts must stay enabled on Horus -#define audioEnableIrq() // interrupts must stay enabled on Horus -#if defined(PCBNV14) -#define setSampleRate(freq) -#else -void setSampleRate(uint32_t frequency); -#endif -void setScaledVolume(uint8_t volume); -void setVolume(uint8_t volume); -int32_t getVolume(); -#define VOLUME_LEVEL_MAX 23 -#define VOLUME_LEVEL_DEF 12 - // Telemetry driver #define INTMODULE_FIFO_SIZE 512 #define TELEMETRY_FIFO_SIZE 512 diff --git a/radio/src/targets/pl18/board.h b/radio/src/targets/pl18/board.h index d05b45a7b..f9829865f 100644 --- a/radio/src/targets/pl18/board.h +++ b/radio/src/targets/pl18/board.h @@ -195,19 +195,6 @@ bool audioChipReset(); #define SPI_SPEED_128 6 #define SPI_SPEED_256 7 -#define audioDisableIrq() // interrupts must stay enabled on Horus -#define audioEnableIrq() // interrupts must stay enabled on Horus -#if defined(PCBNV14) -#define setSampleRate(freq) -#else -void setSampleRate(uint32_t frequency); -#endif -void setScaledVolume(uint8_t volume); -void setVolume(uint8_t volume); -int32_t getVolume(); -#define VOLUME_LEVEL_MAX 23 -#define VOLUME_LEVEL_DEF 12 - // Telemetry driver #define INTMODULE_FIFO_SIZE 512 #define TELEMETRY_FIFO_SIZE 512 diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 2229cc04a..88d1b264e 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -32,6 +32,7 @@ #include "hal/adc_driver.h" #include "hal/rotary_encoder.h" #include "hal/usb_driver.h" +#include "hal/audio_driver.h" #include #include @@ -250,7 +251,7 @@ void simuStop() struct SimulatorAudio { int volumeGain; int currentVolume; - uint16_t leftoverData[AUDIO_BUFFER_SIZE]; + int16_t leftoverData[AUDIO_BUFFER_SIZE]; int leftoverLen; bool threadRunning; pthread_t threadPid; @@ -275,28 +276,19 @@ void audioConsumeCurrentBuffer() { } -void setScaledVolume(uint8_t volume) +void audioSetVolume(uint8_t volume) { simuAudio.currentVolume = 127 * volume * simuAudio.volumeGain / VOLUME_LEVEL_MAX / 10; // TRACE_SIMPGMSPACE("setVolume(): in: %u, out: %u", volume, simuAudio.currentVolume); } -void setVolume(uint8_t volume) -{ -} - -int32_t getVolume() -{ - return 0; -} - #if defined(SIMU_AUDIO) -void copyBuffer(uint8_t * dest, const uint16_t * buff, unsigned int samples) +void copyBuffer(void* dest, const int16_t* buff, unsigned samples) { - for(unsigned int i=0; i= nextBuffer->size*2) { + if (len >= nextBuffer->size * 2) { copyBuffer(stream, nextBuffer->data, nextBuffer->size); - stream += nextBuffer->size*2; - len -= nextBuffer->size*2; + stream += nextBuffer->size * 2; + len -= nextBuffer->size * 2; // putchar('+'); audioQueue.buffersFifo.freeNextFilledBuffer(); - } - else { - //partial - copyBuffer(stream, nextBuffer->data, len/2); - simuAudio.leftoverLen = (nextBuffer->size-len/2); - memcpy(simuAudio.leftoverData, &nextBuffer->data[len/2], simuAudio.leftoverLen*2); + } else { + // partial + copyBuffer(stream, nextBuffer->data, len / 2); + simuAudio.leftoverLen = (nextBuffer->size - len / 2); + memcpy(simuAudio.leftoverData, &nextBuffer->data[len / 2], + simuAudio.leftoverLen * 2); len = 0; // putchar('p'); audioQueue.buffersFifo.freeNextFilledBuffer(); break; } - } - else { + } else { break; } } @@ -367,7 +359,8 @@ void * audioThread(void *) wanted.freq = AUDIO_SAMPLE_RATE; wanted.format = AUDIO_S16SYS; wanted.channels = 1; /* 1 = mono, 2 = stereo */ - wanted.samples = AUDIO_BUFFER_SIZE*2; /* Good low-latency value for callback */ + wanted.samples = + AUDIO_BUFFER_SIZE * 2; /* Good low-latency value for callback */ wanted.callback = fillAudioBuffer; wanted.userdata = nullptr; @@ -395,7 +388,7 @@ void startAudioThread(int volumeGain) simuAudio.threadRunning = true; simuAudio.volumeGain = volumeGain; TRACE_SIMPGMSPACE("startAudioThread(%d)", volumeGain); - setScaledVolume(VOLUME_LEVEL_DEF); + audioSetVolume(VOLUME_LEVEL_DEF); pthread_attr_t attr; pthread_attr_init(&attr); diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 5ad4ed5b0..4ce90c7eb 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -246,18 +246,9 @@ uint8_t isBacklightEnabled(); void debugPutc(const char c); // Audio driver -void audioInit() ; -void audioEnd() ; -void dacStart(); -void dacStop(); -void setSampleRate(uint32_t frequency); -#define VOLUME_LEVEL_MAX 23 -#define VOLUME_LEVEL_DEF 12 -#if !defined(SOFTWARE_VOLUME) -void setScaledVolume(uint8_t volume); -void setVolume(uint8_t volume); -int32_t getVolume(); -#endif +void audioInit(); +void audioEnd(); + #if defined(AUDIO_SPEAKER_ENABLE_GPIO) void initSpeakerEnable(); void enableSpeaker(); @@ -267,6 +258,7 @@ static inline void initSpeakerEnable() { } static inline void enableSpeaker() { } static inline void disableSpeaker() { } #endif + #if defined(HEADPHONE_TRAINER_SWITCH_GPIO) void initHeadphoneTrainerSwitch(); void enableHeadphone(); @@ -276,13 +268,13 @@ static inline void initHeadphoneTrainerSwitch() { } static inline void enableHeadphone() { } static inline void enableTrainer() { } #endif + #if defined(JACK_DETECT_GPIO) void initJackDetect(); bool isJackPlugged(); #endif + void audioConsumeCurrentBuffer(); -#define audioDisableIrq() __disable_irq() -#define audioEnableIrq() __enable_irq() // Haptic driver void hapticInit(); diff --git a/radio/src/targets/taranis/volume_i2c.cpp b/radio/src/targets/taranis/volume_i2c.cpp index b4ce4f316..d1ed2365c 100644 --- a/radio/src/targets/taranis/volume_i2c.cpp +++ b/radio/src/targets/taranis/volume_i2c.cpp @@ -21,17 +21,19 @@ #if !defined(SOFTWARE_VOLUME) -#include "hal/i2c_driver.h" #include "stm32_i2c_driver.h" +#include "hal/i2c_driver.h" +#include "hal/audio_driver.h" + #include "board.h" -static const uint8_t volumeScale[VOLUME_LEVEL_MAX+1] = { - 0, 1, 2, 3, 5, 9, 13, 17, 22, 27, 33, 40, - 64, 82, 96, 105, 112, 117, 120, 122, 124, 125, 126, 127 +static const uint8_t volumeScale[VOLUME_LEVEL_MAX + 1] = { + 0, 1, 2, 3, 5, 9, 13, 17, 22, 27, 33, 40, + 64, 82, 96, 105, 112, 117, 120, 122, 124, 125, 126, 127, }; -int32_t getVolume() +static int32_t read_i2c_volume() { uint8_t value = 0; if (i2c_read(VOLUME_I2C_BUS, VOLUME_I2C_ADDRESS, 0, 1, &value, 1) < 0) @@ -40,19 +42,19 @@ int32_t getVolume() return value; } -void setVolume(uint8_t volume) +static void write_i2c_volume(uint8_t volume) { i2c_init(VOLUME_I2C_BUS); i2c_write(VOLUME_I2C_BUS, VOLUME_I2C_ADDRESS, 0, 1, &volume, 1); } -void setScaledVolume(uint8_t volume) +void audioSetVolume(uint8_t volume) { if (volume > VOLUME_LEVEL_MAX) { volume = VOLUME_LEVEL_MAX; } - setVolume(volumeScale[volume]); + write_i2c_volume(volumeScale[volume]); } #endif