mirror of
https://github.com/hathach/tinyusb.git
synced 2025-12-01 12:24:17 +00:00
Use one control buffer as EP0 has no concurrency
Signed-off-by: HiFiPhile <admin@hifiphile.com>
This commit is contained in:
@ -105,8 +105,6 @@ extern "C" {
|
||||
// Have a look into audio_device.h for all configurations
|
||||
#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000
|
||||
|
||||
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
|
||||
|
||||
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
|
||||
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
|
||||
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
|
||||
|
||||
@ -111,8 +111,6 @@ extern "C" {
|
||||
// Have a look into audio_device.h for all configurations
|
||||
#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000
|
||||
|
||||
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
|
||||
|
||||
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
|
||||
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
|
||||
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
|
||||
|
||||
@ -108,8 +108,6 @@ extern "C" {
|
||||
// Have a look into audio_device.h for all configurations
|
||||
#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000
|
||||
|
||||
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
|
||||
|
||||
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
|
||||
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below
|
||||
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor!
|
||||
|
||||
@ -114,8 +114,6 @@ extern "C" {
|
||||
// Have a look into audio_device.h for all configurations
|
||||
#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000
|
||||
|
||||
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
|
||||
|
||||
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
|
||||
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below
|
||||
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor!
|
||||
|
||||
@ -122,8 +122,6 @@ extern "C" {
|
||||
|
||||
// Have a look into audio_device.h for all configurations
|
||||
|
||||
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
|
||||
|
||||
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
|
||||
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor!
|
||||
|
||||
|
||||
@ -155,9 +155,6 @@ extern "C" {
|
||||
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT) // Maximum EP IN size for all AS alternate settings used
|
||||
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device
|
||||
|
||||
// Size of control request buffer
|
||||
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
|
||||
|
||||
// CDC FIFO size of TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
@ -164,9 +164,6 @@ extern "C" {
|
||||
// Example read FIFO every 1ms (8 HS frames), so buffer size should be 8 times larger for HS device
|
||||
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ TU_MAX(4 * CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_OUT, TU_MAX(32 * CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_OUT, 32 * CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_OUT))
|
||||
|
||||
// Size of control request buffer
|
||||
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -145,9 +145,6 @@ extern "C" {
|
||||
// Enable feedback EP
|
||||
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 1
|
||||
|
||||
// Size of control request buffer
|
||||
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -181,15 +181,9 @@ tu_static CFG_TUD_MEM_SECTION struct {
|
||||
} lin_buf_out;
|
||||
#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && USE_LINEAR_BUFFER
|
||||
|
||||
// Control buffers
|
||||
// Control buffer
|
||||
tu_static CFG_TUD_MEM_SECTION struct {
|
||||
TUD_EPBUF_DEF(buf1, CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ);
|
||||
#if CFG_TUD_AUDIO > 1
|
||||
TUD_EPBUF_DEF(buf2, CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ);
|
||||
#endif
|
||||
#if CFG_TUD_AUDIO > 2
|
||||
TUD_EPBUF_DEF(buf3, CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ);
|
||||
#endif
|
||||
TUD_EPBUF_DEF(buf, CFG_TUD_AUDIO_CTRL_BUF_SZ);
|
||||
} ctrl_buf;
|
||||
|
||||
// Aligned buffer for feedback EP
|
||||
@ -219,6 +213,7 @@ typedef struct
|
||||
uint8_t rhport;
|
||||
uint8_t const *p_desc;// Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function
|
||||
uint8_t const *p_desc_as;// Pointer pointing to 1st Standard AS Interface Descriptor(4.9.1) - Audio Streaming descriptor defining audio function
|
||||
uint16_t desc_length;// Length of audio function descriptor
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN
|
||||
uint8_t ep_in; // TX audio data EP.
|
||||
@ -244,8 +239,6 @@ typedef struct
|
||||
|
||||
bool mounted;// Device opened
|
||||
|
||||
uint16_t desc_length;// Length of audio function descriptor
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
||||
struct {
|
||||
uint32_t value; // Feedback value for asynchronous mode (in 16.16 format).
|
||||
@ -290,10 +283,6 @@ typedef struct
|
||||
|
||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||
|
||||
// Buffer for control requests
|
||||
uint8_t *ctrl_buf;
|
||||
uint8_t ctrl_buf_sz;
|
||||
|
||||
// EP Transfer buffers and FIFOs
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
|
||||
tu_fifo_t ep_out_ff;
|
||||
@ -327,7 +316,11 @@ typedef struct
|
||||
#define USE_LINEAR_BUFFER_RX 0
|
||||
#endif
|
||||
|
||||
#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf)
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
|
||||
#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ep_out_ff)
|
||||
#else
|
||||
#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ep_in_ff)
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// WEAK FUNCTION STUBS
|
||||
@ -722,26 +715,6 @@ void audiod_init(void) {
|
||||
for (uint8_t i = 0; i < CFG_TUD_AUDIO; i++) {
|
||||
audiod_function_t *audio = &_audiod_fct[i];
|
||||
|
||||
// Initialize control buffers
|
||||
switch (i) {
|
||||
case 0:
|
||||
audio->ctrl_buf = ctrl_buf.buf1;
|
||||
audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ;
|
||||
break;
|
||||
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0
|
||||
case 1:
|
||||
audio->ctrl_buf = ctrl_buf.buf2;
|
||||
audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ;
|
||||
break;
|
||||
#endif
|
||||
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0
|
||||
case 2:
|
||||
audio->ctrl_buf = ctrl_buf.buf3;
|
||||
audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Initialize IN EP FIFO if required
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN
|
||||
|
||||
@ -1341,20 +1314,20 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
|
||||
if (tud_audio_n_version(func_id) == 2) {
|
||||
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
|
||||
if (_audiod_fct[func_id].bclock_id_tx == entityID && ctrlSel == AUDIO20_CS_CTRL_SAM_FREQ && p_request->bRequest == AUDIO20_CS_REQ_CUR) {
|
||||
_audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf);
|
||||
_audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(ctrl_buf.buf);
|
||||
audiod_calc_tx_packet_sz(&_audiod_fct[func_id]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Invoke callback
|
||||
return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
|
||||
return tud_audio_set_req_entity_cb(rhport, p_request, ctrl_buf.buf);
|
||||
} else {
|
||||
// Find index of audio driver structure and verify interface really exists
|
||||
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
|
||||
|
||||
// Invoke callback
|
||||
return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
|
||||
return tud_audio_set_req_itf_cb(rhport, p_request, ctrl_buf.buf);
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -1369,7 +1342,7 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
|
||||
if (_audiod_fct[func_id].ep_in == ep) {
|
||||
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
|
||||
if (ctrlSel == AUDIO10_EP_CTRL_SAMPLING_FREQ && p_request->bRequest == AUDIO10_CS_REQ_SET_CUR) {
|
||||
_audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf) & 0x00FFFFFF;
|
||||
_audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(ctrl_buf.buf) & 0x00FFFFFF;
|
||||
audiod_calc_tx_packet_sz(&_audiod_fct[func_id]);
|
||||
}
|
||||
}
|
||||
@ -1377,7 +1350,7 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
|
||||
#endif
|
||||
|
||||
// Invoke callback
|
||||
bool ret = tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
|
||||
bool ret = tud_audio_set_req_ep_cb(rhport, p_request, ctrl_buf.buf);
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
||||
if (ret && tud_audio_n_version(func_id) == 1) {
|
||||
@ -1474,7 +1447,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const
|
||||
}
|
||||
|
||||
// If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished
|
||||
TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz));
|
||||
TU_VERIFY(tud_control_xfer(rhport, p_request, ctrl_buf.buf, sizeof(ctrl_buf.buf)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1735,10 +1708,10 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
|
||||
}
|
||||
|
||||
// Crop length
|
||||
if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz;
|
||||
if (len > sizeof(ctrl_buf.buf)) len = sizeof(ctrl_buf.buf);
|
||||
|
||||
// Copy into buffer
|
||||
TU_VERIFY(0 == tu_memcpy_s(_audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz, data, (size_t) len));
|
||||
TU_VERIFY(0 == tu_memcpy_s(ctrl_buf.buf, sizeof(ctrl_buf.buf), data, (size_t) len));
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
|
||||
if (tud_audio_n_version(func_id) == 2) {
|
||||
@ -1747,7 +1720,7 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
|
||||
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
|
||||
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
|
||||
if (_audiod_fct[func_id].bclock_id_tx == entityID && ctrlSel == AUDIO20_CS_CTRL_SAM_FREQ && p_request->bRequest == AUDIO20_CS_REQ_CUR) {
|
||||
_audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf);
|
||||
_audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(ctrl_buf.buf);
|
||||
audiod_calc_tx_packet_sz(&_audiod_fct[func_id]);
|
||||
}
|
||||
}
|
||||
@ -1755,7 +1728,7 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
|
||||
#endif
|
||||
|
||||
// Schedule transmit
|
||||
return tud_control_xfer(rhport, p_request, (void *) _audiod_fct[func_id].ctrl_buf, len);
|
||||
return tud_control_xfer(rhport, p_request, ctrl_buf.buf, len);
|
||||
}
|
||||
|
||||
// Verify an entity with the given ID exists and returns also the corresponding driver index
|
||||
|
||||
@ -37,21 +37,10 @@
|
||||
|
||||
// All sizes are in bytes!
|
||||
|
||||
// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors
|
||||
#ifndef CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ
|
||||
#error You must define an audio class control request buffer size!
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 1
|
||||
#ifndef CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ
|
||||
#error You must define an audio class control request buffer size!
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO > 2
|
||||
#ifndef CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ
|
||||
#error You must define an audio class control request buffer size!
|
||||
#endif
|
||||
// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your
|
||||
// biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors
|
||||
#ifndef CFG_TUD_AUDIO_CTRL_BUF_SZ
|
||||
#define CFG_TUD_AUDIO_CTRL_BUF_SZ 64
|
||||
#endif
|
||||
|
||||
// End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024
|
||||
@ -153,7 +142,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// (For TYPE-I format only) Flow control is necessary to allow IN ep send correct amount of data, unless it's a virtual device where data is perfectly synchronized to USB clock.
|
||||
// (For TYPE-I format only) Flow control is necessary to allow IN ep send correct amount of data, unless it's a
|
||||
// virtual device where data is perfectly synchronized to USB clock.
|
||||
#ifndef CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
|
||||
#define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1
|
||||
#endif
|
||||
@ -230,12 +220,15 @@ static inline bool tud_audio_int_write (const audio_interru
|
||||
#endif
|
||||
|
||||
// Buffer control EP data and schedule a transmit
|
||||
// This function is intended to be used if you do not have a persistent buffer or memory location available (e.g. non-local variables) and need to answer onto a
|
||||
// get request. This function buffers your answer request frame into the control buffer of the corresponding audio driver and schedules a transmit for sending it.
|
||||
// Since transmission is triggered via interrupts, a persistent memory location is required onto which the buffer pointer in pointing. If you already have such
|
||||
// available you may directly use 'tud_control_xfer(...)'. In this case data does not need to be copied into an additional buffer and you save some time.
|
||||
// This function is intended to be used if you do not have a persistent buffer or memory location available
|
||||
// (e.g. non-local variables) and need to answer onto a get request. This function buffers your answer request
|
||||
// frame into the control buffer of the corresponding audio driver and schedules a transmit for sending it.
|
||||
// Since transmission is triggered via interrupts, a persistent memory location is required onto which the buffer
|
||||
// pointer in pointing. If you already have such available you may directly use 'tud_control_xfer(...)'. In this
|
||||
// case data does not need to be copied into an additional buffer and you save some time.
|
||||
// If the request's wLength is zero, a status packet is sent instead.
|
||||
bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len);
|
||||
bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request,
|
||||
void* data, uint16_t len);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callback API
|
||||
@ -243,14 +236,18 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN
|
||||
// Invoked in ISR context once an audio packet was sent successfully.
|
||||
// Normally this function is not needed, since the data transfer should be driven by audio clock (i.e. I2S clock), call tud_audio_write() in I2S receive callback.
|
||||
bool tud_audio_tx_done_isr(uint8_t rhport, uint16_t n_bytes_sent, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting);
|
||||
// Normally this function is not needed, since the data transfer should be driven by audio clock (i.e. I2S clock),
|
||||
// call tud_audio_write() in I2S receive callback.
|
||||
bool tud_audio_tx_done_isr(uint8_t rhport, uint16_t n_bytes_sent, uint8_t func_id, uint8_t ep_in,
|
||||
uint8_t cur_alt_setting);
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
|
||||
// Invoked in ISR context once an audio packet was received successfully.
|
||||
// Normally this function is not needed, since the data transfer should be driven by audio clock (i.e. I2S clock), call tud_audio_read() in I2S transmit callback.
|
||||
bool tud_audio_rx_done_isr(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting);
|
||||
// Normally this function is not needed, since the data transfer should be driven by audio clock (i.e. I2S clock),
|
||||
// call tud_audio_read() in I2S transmit callback.
|
||||
bool tud_audio_rx_done_isr(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out,
|
||||
uint8_t cur_alt_setting);
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
||||
@ -259,41 +256,55 @@ bool tud_audio_rx_done_isr(uint8_t rhport, uint16_t n_bytes_received, uint8_t fu
|
||||
//
|
||||
// Option 1 - AUDIO_FEEDBACK_METHOD_FIFO_COUNT
|
||||
// Feedback value is calculated within the audio driver by regulating the FIFO level to half fill.
|
||||
// Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, well tested
|
||||
// (Windows, Linux, OSX) with a reliable result so far.
|
||||
// Disadvantage: A FIFO of minimal 4 frames is needed to compensate for jitter, an average delay of 2 frames is introduced.
|
||||
// Advantage: No SOF interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus
|
||||
// less CPU load, well tested (Windows, Linux, OSX) with a reliable result so far.
|
||||
// Disadvantage: A FIFO of minimal 4 frames is needed to compensate for jitter, an average delay of 2 frames is
|
||||
// introduced.
|
||||
//
|
||||
// Option 2 - AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED / AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT
|
||||
// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from
|
||||
// which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter).
|
||||
// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information
|
||||
// about the master clock f_m from which the audio sample frequency f_s is derived, f_s itself, and the cycle
|
||||
// count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter).
|
||||
// See tud_audio_set_fb_params() and tud_audio_feedback_update()
|
||||
// Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller and thus a smaller delay is possible.
|
||||
// Disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. (The most critical point is the reading of the cycle counter value of f_m.
|
||||
// It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced).
|
||||
// Long-term drift could occur since error is accumulated.
|
||||
// Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller and thus a
|
||||
// smaller delay is possible.
|
||||
// Disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. (The most critical point
|
||||
// is the reading of the cycle counter value of f_m. It is read from within the SOF ISR - see: audiod_sof() -,
|
||||
// hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is
|
||||
// introduced). Long-term drift will cause the FIFO under/overflow, you still needs to correct it somehow.
|
||||
//
|
||||
// Option 3 - manual
|
||||
// Determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer.
|
||||
// Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load.
|
||||
// Disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 6 frames), i.e. a larger delay is introduced.
|
||||
// Determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined
|
||||
// e.g. from some fill status of some FIFO buffer.
|
||||
// Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus
|
||||
// less CPU load.
|
||||
// Disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 6 frames), i.e. a larger delay
|
||||
// is introduced.
|
||||
|
||||
|
||||
// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed.
|
||||
// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at
|
||||
// FB endpoint interval till it's changed.
|
||||
//
|
||||
// The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus Specification Revision 2.0 5.12.4.2).
|
||||
// For simplicity, this function always uses 16.16 format. For FS devices, the driver will automatically convert the value to 10.14 format.
|
||||
// The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus
|
||||
// Specification Revision 2.0 5.12.4.2). For simplicity, this function always uses 16.16 format. For FS devices,
|
||||
// the driver will automatically convert the value to 10.14 format.
|
||||
//
|
||||
// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and it seems the
|
||||
// driver can work with either format.
|
||||
// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0
|
||||
// devices. On Linux and it seems the driver can work with either format.
|
||||
//
|
||||
// Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value.
|
||||
// Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the
|
||||
// feature is used, the user can not set the feedback value.
|
||||
//
|
||||
// Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec
|
||||
// Boiled down, the feedback value Ff = n_samples / (micro)frame.
|
||||
// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13
|
||||
// for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s)
|
||||
// The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K)
|
||||
// feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames
|
||||
// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames
|
||||
// need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency
|
||||
// e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is
|
||||
// available and locked to f_s)
|
||||
// The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where
|
||||
// P = min( ceil(log2(f_m / f_s)), K)
|
||||
// feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles
|
||||
// within fb_n_frames
|
||||
bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback);
|
||||
|
||||
// Update feedback value with passed MCLK cycles since last time this update function is called.
|
||||
|
||||
Reference in New Issue
Block a user