Implement audio PCM type I enc./decoding acc. to 2.3.1.5 Audio Streams

Extending capabilities of support FIFOs
Removing copy from to FIFO
Adjusting audio examples
Remove peek/read into other FIFO
This commit is contained in:
Reinhard Panhuber 2021-03-10 19:32:13 +01:00
parent de1f36f2b0
commit d5a5a1cab6
7 changed files with 167 additions and 261 deletions

View File

@ -73,12 +73,12 @@ int main(void)
tusb_init();
// Init values
sampFreq = 48000;
sampFreq = AUDIO_SAMPLE_RATE;
clkValid = 1;
sampleFreqRng.wNumSubRanges = 1;
sampleFreqRng.subrange[0].bMin = 48000;
sampleFreqRng.subrange[0].bMax = 48000;
sampleFreqRng.subrange[0].bMin = AUDIO_SAMPLE_RATE;
sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE;
sampleFreqRng.subrange[0].bRes = 0;
while (1)

View File

@ -91,9 +91,12 @@ extern "C" {
// AUDIO CLASS DRIVER CONFIGURATION
//--------------------------------------------------------------------
#ifndef AUDIO_SAMPLE_RATE
#define AUDIO_SAMPLE_RATE 48000
#endif
// Audio format type
#define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I
#define CFG_TUD_AUDIO_FORMAT_TYPE_RX AUDIO_FORMAT_TYPE_UNDEFINED
// Audio format type I specifications
#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM
@ -101,8 +104,8 @@ extern "C" {
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2
// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
#define CFG_TUD_AUDIO_EPSIZE_IN 48*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX*CFG_TUD_AUDIO_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channels
#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN + 1 // Just for safety one sample more space
#define CFG_TUD_AUDIO_EPSIZE_IN 48 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // ceil(f_s/1000) * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX
#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN + CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // Just for safety one sample more space
// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
#define CFG_TUD_AUDIO_N_AS_INT 1

View File

@ -110,7 +110,6 @@ extern "C" {
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2
#define CFG_TUD_AUDIO_N_CHANNELS_RX 2
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 2
#define CFG_TUD_AUDIO_RX_ITEMSIZE 2
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0
// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)

View File

@ -161,18 +161,18 @@ typedef struct
// Support FIFOs
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
tu_fifo_t tx_supp_ff[CFG_TUD_AUDIO_N_CHANNELS_TX];
CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_TX][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE];
tu_fifo_t tx_supp_ff[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO];
CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_supp_ff_mutex_wr[CFG_TUD_AUDIO_N_CHANNELS_TX]; // No need for read mutex as only USB driver reads from FIFO
osal_mutex_def_t tx_supp_ff_mutex_wr[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
tu_fifo_t rx_supp_ff[CFG_TUD_AUDIO_N_CHANNELS_RX];
CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_RX][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE];
tu_fifo_t rx_supp_ff[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO];
CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX];
#if CFG_FIFO_MUTEX
osal_mutex_def_t rx_supp_ff_mutex_rd[CFG_TUD_AUDIO_N_CHANNELS_RX]; // No need for write mutex as only USB driver writes into FIFO
osal_mutex_def_t rx_supp_ff_mutex_rd[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif
@ -284,19 +284,19 @@ bool tud_audio_n_clear_ep_out_ff(uint8_t itf)
// Delete all content in the support RX FIFOs
bool tud_audio_n_clear_rx_support_ff(uint8_t itf, uint8_t channelId)
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX);
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO);
return tu_fifo_clear(&_audiod_itf[itf].rx_supp_ff[channelId]);
}
uint16_t tud_audio_n_available_support_ff(uint8_t itf, uint8_t channelId)
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX);
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO);
return tu_fifo_count(&_audiod_itf[itf].rx_supp_ff[channelId]);
}
uint16_t tud_audio_n_read_support_ff(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize)
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX);
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO);
return tu_fifo_read_n(&_audiod_itf[itf].rx_supp_ff[channelId], buffer, bufsize);
}
#endif
@ -382,35 +382,55 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_
// The following functions are used in case CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE != 0
#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT
// Decoding according to 2.3.1.5 Audio Streams
static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received)
{
(void) rhport;
// We assume there is always the correct number of samples available for decoding - extra checks make no sense here
// Determine amount of samples
uint16_t const nChannelsPerFF = CFG_TUD_AUDIO_N_CHANNELS_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO;
uint16_t const nBytesToCopy = nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX;
uint16_t const nSamplesPerFFToRead = n_bytes_received / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO;
uint8_t cnt_ff;
uint16_t cnt = CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX;
uint16_t idxSample = 0;
// Decode
void * dst;
uint8_t * src;
uint8_t * dst_end;
uint16_t len;
while (cnt <= n_bytes_received)
for (cnt_ff = 0; cnt_ff < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt_ff++)
{
for (uint8_t cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_RX; cntChannel++)
{
// If 8, 16, or 32 bit values are to be copied
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == CFG_TUD_AUDIO_RX_ITEMSIZE
// If this aborts then the target buffer is full
TU_VERIFY(tu_fifo_write_n(&audio->rx_supp_ff[cntChannel], &audio->lin_buf_out[idxSample], CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX));
#else
uint32_t sample = audio->lin_buf_out[idxSample];
#if CFG_TUD_AUDIO_JUSTIFICATION_RX == CFG_TUD_AUDIO_LEFT_JUSTIFIED
sample = sample << 8;
#endif
src = &audio->lin_buf_out[cnt_ff*nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX];
TU_VERIFY(tu_fifo_write_n(&audio->rx_supp_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX));
#endif
idxSample += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX;
len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nSamplesPerFFToRead);
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len);
dst_end = dst + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX;
while((uint8_t *)dst < dst_end)
{
memcpy(dst, src, nBytesToCopy);
dst = (uint8_t *)dst + nBytesToCopy;
src += nBytesToCopy * CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO;
}
cnt += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX;
// Handle wrapped part of FIFO
if (len < nSamplesPerFFToRead)
{
len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nSamplesPerFFToRead - len);
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len);
dst_end = dst + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX;
while((uint8_t *)dst < dst_end)
{
memcpy(dst, src, nBytesToCopy);
dst = (uint8_t *)dst + nBytesToCopy;
src += nBytesToCopy * CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO;
}
}
}
// Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it
@ -469,13 +489,13 @@ uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force a
bool tud_audio_n_clear_tx_support_ff(uint8_t itf, uint8_t channelId)
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX);
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO);
return tu_fifo_clear(&_audiod_itf[itf].tx_supp_ff[channelId]);
}
uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len)
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX);
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO);
return tu_fifo_write_n(&_audiod_itf[itf].tx_supp_ff[channelId], data, len);
}
#endif
@ -590,60 +610,91 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio)
#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN
// Take samples from the support buffer and encode them into the IN EP software FIFO
// Returns number of bytes written into linear buffer
/* 2.3.1.7.1 PCM Format
The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio
data streams. The audio data is not compressed and uses a signed twos-complement fixed point format. It
is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused
bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the
range [-1, +1)
*/
/*
* This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples
* in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and
* does not change the number of bytes per sample.
* */
static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio)
{
// We encode directly into IN EP's FIFO - abort if previous transfer not complete
// We encode directly into IN EP's linear buffer - abort if previous transfer not complete
TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in));
// Determine amount of samples
uint16_t const nEndpointSampleCapacity = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_supp_ff[0]); // We first look for the minimum number of bytes and afterwards convert it to sample size
uint8_t cntChannel;
uint16_t const nChannelsPerFF = CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO;
uint16_t const nBytesToCopy = nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
uint16_t const capSamplesPerFF = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO;
uint16_t nSamplesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]);
uint8_t cnt_ff;
for (cntChannel = 1; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++)
for (cnt_ff = 1; cnt_ff < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt_ff++)
{
uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cntChannel]);
if (count < nSamplesPerChannelToSend)
uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]);
if (count < nSamplesPerFFToSend)
{
nSamplesPerChannelToSend = count;
nSamplesPerFFToSend = count;
}
}
// Convert to sample size
nSamplesPerChannelToSend = nSamplesPerChannelToSend / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
// Check if there is enough
if (nSamplesPerChannelToSend == 0) return 0;
if (nSamplesPerFFToSend == 0) return 0;
// Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT!
nSamplesPerChannelToSend = tu_min16(nSamplesPerChannelToSend, nEndpointSampleCapacity);
nSamplesPerFFToSend = tu_min16(nSamplesPerFFToSend, capSamplesPerFF);
// Round to full number of samples (flooring)
nSamplesPerFFToSend = (nSamplesPerFFToSend / nChannelsPerFF) * nChannelsPerFF;
// Encode
uint16_t cntSample;
uint16_t idxSample = 0;
void * src;
uint8_t * dst;
uint8_t * src_end;
uint16_t len;
for (cntSample = 0; cntSample < nSamplesPerChannelToSend; cntSample++)
for (cnt_ff = 0; cnt_ff < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt_ff++)
{
for (cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++)
dst = &audio->lin_buf_in[cnt_ff*nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX];
len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nSamplesPerFFToSend);
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len);
src_end = src + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
while((uint8_t *)src < src_end)
{
// If 8, 16, or 32 bit values are to be copied
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == CFG_TUD_AUDIO_TX_ITEMSIZE
tu_fifo_read_n(&audio->tx_supp_ff[cntChannel], &audio->lin_buf_in[idxSample], CFG_TUD_AUDIO_TX_ITEMSIZE);
#else
uint32_t sample = 0;
memcpy(dst, src, nBytesToCopy);
src = (uint8_t *)src + nBytesToCopy;
dst += nBytesToCopy * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO;
}
// Get sample from buffer
tu_fifo_read_n(&audio->tx_supp_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX);
// Handle wrapped part of FIFO
if (len < nSamplesPerFFToSend)
{
len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nSamplesPerFFToSend - len);
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len);
#if CFG_TUD_AUDIO_JUSTIFICATION_TX == CFG_TUD_AUDIO_LEFT_JUSTIFIED
sample = sample << 8;
#endif
audio->lin_buf_in[idxSample] = sample;
#endif
idxSample += CFG_TUD_AUDIO_TX_ITEMSIZE;
src_end = src + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
while((uint8_t *)src < src_end)
{
memcpy(dst, src, nBytesToCopy);
src = (uint8_t *)src + nBytesToCopy;
dst += nBytesToCopy * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO;
}
}
}
return nSamplesPerChannelToSend * CFG_TUD_AUDIO_N_CHANNELS_TX * CFG_TUD_AUDIO_TX_ITEMSIZE;
return nSamplesPerFFToSend * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO;
}
#endif //CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
@ -685,9 +736,9 @@ void audiod_init(void)
// Initialize TX support FIFOs if required
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++)
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt++)
{
tu_fifo_config(&audio->tx_supp_ff[cnt], &audio->tx_supp_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, 1, true);
tu_fifo_config(&audio->tx_supp_ff[cnt], &audio->tx_supp_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&audio->tx_supp_ff[cnt], osal_mutex_create(&audio->tx_supp_ff_mutex_wr[cnt]), NULL);
#endif
@ -696,9 +747,9 @@ void audiod_init(void)
// Initialize RX support FIFOs if required
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++)
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt++)
{
tu_fifo_config(&audio->rx_supp_ff[cnt], &audio->rx_supp_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, 1, true);
tu_fifo_config(&audio->rx_supp_ff[cnt], &audio->rx_supp_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&audio->rx_supp_ff[cnt], NULL, osal_mutex_create(&audio->rx_supp_ff_mutex_rd[cnt]));
#endif
@ -725,14 +776,14 @@ void audiod_reset(uint8_t rhport)
#endif
#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++)
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt++)
{
tu_fifo_clear(&audio->tx_supp_ff[cnt]);
}
#endif
#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++)
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt++)
{
tu_fifo_clear(&audio->rx_supp_ff[cnt]);
}

View File

@ -50,7 +50,7 @@
#error You must define an audio class control request buffer size!
#endif
// End point sizes - Limits: Full Speed <= 1023, High Speed <= 1024
// End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024
#ifndef CFG_TUD_AUDIO_EPSIZE_IN
#define CFG_TUD_AUDIO_EPSIZE_IN 0 // TX
#endif
@ -76,13 +76,13 @@
#define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE 0
#endif
// General information of number of TX and/or RX channels - is used in case support FIFOs (see below) are used and can be used for descriptor definitions
// General information of number of TX and/or RX channels - is used in combination with support FIFOs (see below) and can be used for descriptor definitions
#ifndef CFG_TUD_AUDIO_N_CHANNELS_TX
#define CFG_TUD_AUDIO_N_CHANNELS_TX 0
#define CFG_TUD_AUDIO_N_CHANNELS_TX 1
#endif
#ifndef CFG_TUD_AUDIO_N_CHANNELS_RX
#define CFG_TUD_AUDIO_N_CHANNELS_RX 0
#define CFG_TUD_AUDIO_N_CHANNELS_RX 1
#endif
// Use of TX/RX support FIFOs
@ -104,7 +104,7 @@
// The encoding/decoding starts when the private callback functions
// - audio_tx_done_cb()
// - audio_rx_done_cb()
// are invoked. If support FIFOs are used the corresponding encoding/decoding functions are called from there.
// are invoked. If support FIFOs are used, the corresponding encoding/decoding functions are called from there.
// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions
// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb()
// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb()
@ -120,13 +120,31 @@
// - audio_rx_done_cb()
// functions.
// Size of support FIFOs - if size > 0 there are as many FIFOs set up as TX/RX channels defined
// The number of support FIFOs and number of channels is decoupled. The PCM encoding/decoding works depending on the ratio CFG_TUD_AUDIO_N_CHANNELS_XX / CFG_TUD_AUDIO_N_XX_SUPPORT_SW_FIFO, where currently 1:1 and 2:1 is implemented. The version 2:1 is useful in case of I2S for which usually 2 are channels already interleaved available.
// Size of support FIFOs IN SAMPLES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO and CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO
#ifndef CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
#define CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE 0 // Buffer size per channel - minimum size: ceil(f_s/1000)*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX
#define CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE 0 // FIFO size - minimum size: // ceil(f_s/1000) * CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO
#endif
#ifndef CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
#define CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE 0 // Buffer size per channel - minimum size: ceil(f_s/1000)*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX
#define CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE 0 // FIFO size - minimum size: ceil(f_s/1000) * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO
#endif
#ifndef CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO
#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
#define CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO CFG_TUD_AUDIO_N_CHANNELS_TX // default size is equal to number of channels
#else
#define CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO 0
#endif
#endif
#ifndef CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO
#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
#define CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO CFG_TUD_AUDIO_N_CHANNELS_RX // default size is equal to number of channels
#else
#define CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO 0
#endif
#endif
// Enable/disable feedback EP (required for asynchronous RX applications)
@ -167,20 +185,6 @@
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 1
#endif
#ifndef CFG_TUD_AUDIO_TX_ITEMSIZE
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 1
#define CFG_TUD_AUDIO_TX_ITEMSIZE 1
#elif CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 2
#define CFG_TUD_AUDIO_TX_ITEMSIZE 2
#else
#define CFG_TUD_AUDIO_TX_ITEMSIZE 4
#endif
#endif
#if CFG_TUD_AUDIO_TX_ITEMSIZE < CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX
#error FIFO element size (ITEMSIZE) must not be smaller then sample size
#endif
#endif
#if CFG_TUD_AUDIO_FORMAT_TYPE_RX == AUDIO_FORMAT_TYPE_I
@ -193,26 +197,6 @@
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 1
#endif
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 1
#define CFG_TUD_AUDIO_RX_ITEMSIZE 1
#elif CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 2
#define CFG_TUD_AUDIO_RX_ITEMSIZE 2
#else
#define CFG_TUD_AUDIO_RX_ITEMSIZE 4
#endif
#endif
// In case PCM encoding/decoding of 24 into 32 bits, the adjustment needs to be defined
#define CFG_TUD_AUDIO_LEFT_JUSTIFIED
#define CFG_TUD_AUDIO_RIGHT_JUSTIFIED
#ifndef CFG_TUD_AUDIO_JUSTIFICATION_RX
#define CFG_TUD_AUDIO_JUSTIFICATION_RX CFG_TUD_AUDIO_LEFT_JUSTIFIED
#endif
#ifndef CFG_TUD_AUDIO_JUSTIFICATION_TX
#define CFG_TUD_AUDIO_JUSTIFICATION_TX CFG_TUD_AUDIO_LEFT_JUSTIFIED
#endif
//static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!");
@ -256,7 +240,7 @@ bool tud_audio_n_clear_ep_in_ff (uint8_t itf);
#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN
uint16_t tud_audio_n_flush_tx_support_ff (uint8_t itf); // Force all content in the support TX FIFOs to be written into EP SW FIFO
bool tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId);
bool tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId);
uint16_t tud_audio_n_write_support_ff (uint8_t itf, uint8_t channelId, const void * data, uint16_t len);
#endif

View File

@ -596,42 +596,6 @@ uint16_t tu_fifo_read_n_const_addr(tu_fifo_t* f, void * buffer, uint16_t n)
return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST);
}
/******************************************************************************/
/*!
@brief This function will read n elements from the array index specified by
the read pointer and increment the read index. It copies the elements
into another FIFO and as such takes care of wraps etc.
This function checks for an overflow and corrects read pointer if required.
@param[in] f
Pointer to the FIFO buffer to manipulate
@param[in] f_target
Pointer to target FIFO i.e. to copy into
@param[in] offset
Position to read from in the FIFO buffer with respect to read pointer
@param[in] n
Number of items to peek
@returns number of items read from the FIFO
*/
/******************************************************************************/
uint16_t tu_fifo_read_n_into_other_fifo(tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n)
{
tu_fifo_lock(f->mutex_rd);
tu_fifo_lock(f_target->mutex_wr);
// Conduct copy
n = tu_fifo_peek_n_into_other_fifo(f, f_target, offset, n);
// Advance read pointer
f->rd_idx = advance_pointer(f, f->rd_idx, n);
tu_fifo_unlock(f->mutex_rd);
tu_fifo_unlock(f_target->mutex_wr);
return n;
}
/******************************************************************************/
/*!
@brief Read one item without removing it from the FIFO.
@ -680,92 +644,6 @@ uint16_t tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint1
return ret;
}
/******************************************************************************/
/*!
@brief Read n items without removing it from the FIFO and copy them into another FIFO.
This function checks for an overflow and corrects read pointer if required.
@param[in] f
Pointer to the FIFO buffer to manipulate
@param[in] f_target
Pointer to target FIFO i.e. to copy into
@param[in] offset
Position to read from in the FIFO buffer with respect to read pointer
@param[in] n
Number of items to peek
@returns Number of bytes written to p_buffer
*/
/******************************************************************************/
uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n)
{
// Copy is only possible if both FIFOs have common element size
TU_VERIFY(f->item_size == f_target->item_size);
// Work on local copies on case any pointer changes in between (only necessary if something is written into FIFO f in the meantime)
uint16_t f_wr_idx = f->wr_idx;
uint16_t f_rd_idx = f->rd_idx;
uint16_t cnt = _tu_fifo_count(f, f_wr_idx, f_rd_idx);
// Check overflow and correct if required
if (cnt > f->depth)
{
_tu_fifo_correct_read_pointer(f, f->wr_idx);
f_rd_idx = f->rd_idx;
cnt = f->depth;
}
// Skip beginning of buffer
if (cnt == 0 || offset >= cnt) return 0;
// Check if we can read something at and after offset - if too less is available we read what remains
cnt -= offset;
if (cnt < n) n = cnt;
tu_fifo_lock(f_target->mutex_wr); // Lock both read and write pointers - in case of an overwritable FIFO both may be modified
uint16_t wr_rel_tgt = get_relative_pointer(f_target, f_target->wr_idx, 0);
if (!f_target->overwritable)
{
// Not overwritable limit up to full
n = tu_min16(n, tu_fifo_remaining(f_target));
}
// Advance write pointer - not required for later
f_target->wr_idx = advance_pointer(f_target, f_target->wr_idx, n);
if (n >= f_target->depth)
{
offset += n - f_target->depth;
// We start writing at the read pointer's position since we fill the complete
// buffer and we do not want to modify the read pointer within a write function!
// This would end up in a race condition with read functions!
wr_rel_tgt = get_relative_pointer(f_target, f_target->rd_idx, 0);
n = f_target->depth;
// Update write pointer
f_target->wr_idx = advance_pointer(f_target, f_target->rd_idx, n);
}
// Copy linear size
uint16_t sz = f_target->depth - wr_rel_tgt;
_tu_fifo_peek_at_n(f, offset, &f_target->buffer[wr_rel_tgt], sz, f_wr_idx, f_rd_idx, TU_FIFO_COPY_INC);
if (n > sz)
{
// Copy remaining, now wrapped part, into target buffer
_tu_fifo_peek_at_n(f, offset + sz, f_target->buffer, n-sz, f_wr_idx, f_rd_idx, TU_FIFO_COPY_INC);
}
tu_fifo_unlock(f_target->mutex_wr);
return n;
}
/******************************************************************************/
/*!
@brief Write one element into the buffer.
@ -976,7 +854,7 @@ void tu_fifo_backward_read_pointer(tu_fifo_t *f, uint16_t n)
Returns the length and pointer from which bytes can be read in a linear manner.
This is of major interest for DMA transmissions. If returned length is zero the
corresponding pointer is invalid. The returned length is limited to the number
of BYTES n which the user wants to write into the buffer.
of ITEMS n which the user wants to write into the buffer.
The write pointer does NOT get advanced, use tu_fifo_advance_read_pointer() to
do so! If the length returned is less than n i.e. len<n, then a wrap occurs
and you need to execute this function a second time to get a pointer to the
@ -984,13 +862,13 @@ void tu_fifo_backward_read_pointer(tu_fifo_t *f, uint16_t n)
@param[in] f
Pointer to FIFO
@param[in] offset
Number of BYTES to ignore before start writing
Number of ITEMS to ignore before start writing
@param[out] **ptr
Pointer to start writing to
@param[in] n
Number of BYTES to read from buffer
Number of ITEMS to read from buffer
@return len
Length of linear part IN BYTES, if zero corresponding pointer ptr is invalid
Length of linear part IN ITEMS, if zero corresponding pointer ptr is invalid
*/
/******************************************************************************/
uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n)
@ -1010,9 +888,6 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr,
cnt = f->depth;
}
// Convert to bytes
cnt = cnt * f->item_size;
// Skip beginning of buffer
if (cnt == 0 || offset >= cnt) return 0;
@ -1027,16 +902,14 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr,
// Check if there is a wrap around necessary
uint16_t len;
if (w >= r) {
if (w > r) {
len = w - r;
}
else
{
len = f->depth - r;
len = f->depth - r; // Also the case if FIFO was full
}
len = len * f->item_size;
// Limit to required length
len = tu_min16(n, len);
@ -1060,31 +933,31 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr,
@param[in] f
Pointer to FIFO
@param[in] offset
Number of bytes to ignore before start writing
Number of ITEMS to ignore before start writing
@param[out] **ptr
Pointer to start writing to
@param[in] n
Number of BYTES to write into buffer
Number of ITEMS to write into buffer
@return len
Length of linear part IN BYTES, if zero corresponding pointer ptr is invalid
Length of linear part IN ITEMS, if zero corresponding pointer ptr is invalid
*/
/******************************************************************************/
uint16_t tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n)
{
uint16_t w = f->wr_idx, r = f->rd_idx;
uint16_t free = _tu_fifo_remaining(f, w, r) * f->item_size;
uint16_t free = _tu_fifo_remaining(f, w, r);
if (!f->overwritable)
{
// Not overwritable limit up to full
n = tu_min16(n, free);
}
else if (n >= f->depth * f->item_size)
else if (n >= f->depth)
{
// If overwrite is allowed it must be less than or equal to 2 x buffer length, otherwise the overflow can not be resolved by the read functions
TU_VERIFY(n <= 2*f->depth * f->item_size);
TU_VERIFY(n <= 2*f->depth);
n = f->depth * f->item_size;
n = f->depth;
// We start writing at the read pointer's position since we fill the complete
// buffer and we do not want to modify the read pointer within a write function!
// This would end up in a race condition with read functions!
@ -1108,8 +981,6 @@ uint16_t tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, void **ptr
len = f->depth - w;
}
len = len * f->item_size;
// Limit to required length
len = tu_min16(n, len);

View File

@ -113,11 +113,9 @@ uint16_t tu_fifo_write_n_const_addr (tu_fifo_t* f, const void * dat
bool tu_fifo_read (tu_fifo_t* f, void * p_buffer);
uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n);
uint16_t tu_fifo_read_n_const_addr (tu_fifo_t* f, void * buffer, uint16_t n);
uint16_t tu_fifo_read_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n);
bool tu_fifo_peek_at (tu_fifo_t* f, uint16_t pos, void * p_buffer);
uint16_t tu_fifo_peek_at_n (tu_fifo_t* f, uint16_t pos, void * p_buffer, uint16_t n);
uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n);
uint16_t tu_fifo_count (tu_fifo_t* f);
bool tu_fifo_empty (tu_fifo_t* f);