chore: audio drivers cleanup

This commit is contained in:
raphaelcoeffic
2025-01-17 13:30:49 +01:00
committed by Raphael Coeffic
parent 11f79746f5
commit 6d6c449c12
20 changed files with 276 additions and 351 deletions
+5 -8
View File
@@ -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;
}
+34 -119
View File
@@ -23,10 +23,13 @@
#include <stddef.h>
#include <string.h>
#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<AUDIO_BUFFER_COUNT; ++n) {
if (audioBuffers[n].state == AUDIO_BUFFER_FILLED) {
if (++count >= 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
+9 -8
View File
@@ -22,21 +22,22 @@
#include <FreeRTOS/include/FreeRTOS.h>
#include <FreeRTOS/include/stream_buffer.h>
#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]);
+2 -1
View File
@@ -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
+3
View File
@@ -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)
+1
View File
@@ -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[] = {
+1
View File
@@ -21,6 +21,7 @@
#include "hal/adc_driver.h"
#include "hal/usb_driver.h"
#include "hal/audio_driver.h"
#define LANGUAGE_PACKS_DEFINITION
@@ -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"
+37
View File
@@ -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 <stdint.h>
// 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);
+3 -1
View File
@@ -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
+1
View File
@@ -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
@@ -32,6 +32,7 @@
#include "hal/switch_driver.h"
#include "hal/adc_driver.h"
#include "hal/audio_driver.h"
//
// WARNING:
@@ -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<uint32_t>(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)
+19 -35
View File
@@ -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
-13
View File
@@ -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
-13
View File
@@ -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
-13
View File
@@ -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
+25 -32
View File
@@ -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 <errno.h>
#include <stdarg.h>
@@ -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<samples; i++) {
int sample = ((int32_t)(uint32_t)(buff[i]) - 0x8000); // conversion from uint16_t
*((uint16_t*)dest) = (int16_t)((sample * simuAudio.currentVolume)/127);
dest += 2;
for (unsigned i = 0; i < samples; i++) {
int16_t sample = buff[i];
*((int16_t*)dest) = (int16_t)((sample * simuAudio.currentVolume) / 127);
dest = (int16_t*)dest + 1;
}
}
@@ -314,29 +306,29 @@ void fillAudioBuffer(void *udata, Uint8 *stream, int len)
if (simuAudio.leftoverLen) return; // buffer fully filled
}
if (audioQueue.buffersFifo.filledAtleast(len/(AUDIO_BUFFER_SIZE*2)+1) ) {
while(true) {
const AudioBuffer * nextBuffer = audioQueue.buffersFifo.getNextFilledBuffer();
if (audioQueue.buffersFifo.filledAtleast(len / (AUDIO_BUFFER_SIZE * 2) + 1)) {
while (true) {
const AudioBuffer* nextBuffer =
audioQueue.buffersFifo.getNextFilledBuffer();
if (nextBuffer) {
if (len >= 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);
+6 -14
View File
@@ -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();
+10 -8
View File
@@ -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