summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2022-05-27 12:27:31 +0700
committerhathach <[email protected]>2022-05-27 12:27:31 +0700
commit15aa593790311d6e279f01ba764a1a96d282a78b (patch)
tree106f39a4004dd952612e2a8ce15808265902306e /src
parente5113a1cfc25c0e5e7e75c2644ed91d252391c28 (diff)
wrap feedback and compute to its own struct/union
Diffstat (limited to 'src')
-rw-r--r--src/class/audio/audio_device.c132
-rw-r--r--src/class/audio/audio_device.h28
2 files changed, 78 insertions, 82 deletions
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index 1dce6a664..e967e8c3f 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -306,21 +306,29 @@ typedef struct
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format).
- uint8_t fb_n_frames; // Number of (micro)frames used to estimate feedback value
- uint8_t fb_n_frames_shift;
- uint8_t fb_compute_method;
+ struct {
+ uint32_t value; // Feedback value for asynchronous mode (in 16.16 format).
+ uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1.
+ uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1.
- uint32_t fb_val_min; // Maximum allowed feedback value according to UAC2 FMT-2.0 section 2.3.1.1.
- uint32_t fb_val_max; // Maximum allowed feedback value according to UAC2 FMT-2.0 section 2.3.1.1.
+ uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS)
+ uint8_t compute_method;
- // should be union
- uint8_t fb_power_of_two_val;
+ union {
+ uint8_t power_of_2; // pre-computed power of 2 shift
+ float float_const; // pre-computed float constant
- float fb_float_val;
+ struct {
+ uint32_t sample_freq;
+ uint32_t mclk_freq;
+ }fixed;
- uint32_t fb_sample_freq;
- uint32_t fb_mclk_freq;
+// struct {
+//
+// }fifo_count;
+ }compute;
+
+ } feedback;
#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -437,10 +445,6 @@ static inline uint8_t tu_desc_subtype(void const* desc)
}
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback);
-#endif
-
bool tud_audio_n_mounted(uint8_t func_id)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO);
@@ -1059,7 +1063,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio)
{
- return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->fb_val, 4);
+ return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4);
}
#endif
@@ -1564,8 +1568,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
usbd_edpt_close(rhport, audio->ep_fb);
audio->ep_fb = 0;
- audio->fb_n_frames = 0;
-
+ tu_memclr(&audio->feedback, sizeof(audio->feedback));
#endif
}
#endif
@@ -1679,8 +1682,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback
{
audio->ep_fb = ep_addr;
- audio->fb_n_frames = 1U << (desc_ep->bInterval -1); // TODO correctly set USB frame interval for SOF (not micro-frame)
- audio->fb_n_frames_shift = desc_ep->bInterval -1;
+ audio->feedback.frame_shift = desc_ep->bInterval -1;
// Enable SOF interrupt if callback is implemented
if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, true);
@@ -1708,18 +1710,26 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
// Prepare feedback computation if callback is available
if (tud_audio_feedback_params_cb)
{
- uint32_t sample_freq = 0;
- uint32_t mclk_freq = 0;
- uint8_t fixed_point = 0;
- tud_audio_feedback_params_cb(func_id, alt, &sample_freq, &mclk_freq, &fixed_point);
+ audio_feedback_params_t fb_param;
- if ( sample_freq == 0 || mclk_freq == 0 )
- {
- audio->fb_compute_method = AUDIO_FEEDBACK_METHOD_DISABLED;
- }else
+ tud_audio_feedback_params_cb(func_id, alt, &fb_param);
+ audio->feedback.compute_method = fb_param.method;
+
+ switch(fb_param.method)
{
- audio->fb_compute_method = fixed_point ? AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED : AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT;
- set_fb_params(audio, sample_freq, mclk_freq);
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
+ set_fb_params_freq(audio, fb_param.frequency.sample_freq, fb_param.frequency.mclk_freq);
+ break;
+
+ case AUDIO_FEEDBACK_METHOD_FIFO_COUNT_FIXED:
+ case AUDIO_FEEDBACK_METHOD_FIFO_COUNT_FLOAT:
+ // TODO feedback by fifo count
+ break;
+
+ // nothing to do
+ default: break;
}
}
#endif
@@ -2035,23 +2045,18 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
}
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-uint8_t tud_audio_n_get_fb_n_frames(uint8_t func_id)
-{
- return _audiod_fct[func_id].fb_n_frames;
-}
-#endif
-
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-static bool set_fb_params(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq)
+static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq)
{
// Check if frame interval is within sane limits
- // The interval value audio->fb_n_frames was taken from the descriptors within audiod_set_interface()
+ // The interval value n_frames was taken from the descriptors within audiod_set_interface()
// n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s / f_m) for high speed
// this lower limit ensures the measures feedback value has sufficient precision
uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13;
- if ( (((1UL << k) * sample_freq / mclk_freq) + 1) > audio->fb_n_frames )
+ uint32_t const n_frame = (1UL << audio->feedback.frame_shift);
+
+ if ( (((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame )
{
TU_LOG1(" UAC2 feedback interval too small\r\n"); TU_BREAKPOINT(); return false;
}
@@ -2059,21 +2064,23 @@ static bool set_fb_params(audiod_function_t* audio, uint32_t sample_freq, uint32
// Check if parameters really allow for a power of two division
if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq))
{
- audio->fb_compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2;
- audio->fb_power_of_two_val = 16 - audio->fb_n_frames_shift - tu_log2(mclk_freq / sample_freq);
- }else if ( audio->fb_compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT)
+ audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2;
+ audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq);
+ }
+ else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT)
{
- audio->fb_float_val = (float)sample_freq / mclk_freq * (1UL << (16 - audio->fb_n_frames_shift));
- }else
+ audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift));
+ }
+ else
{
- audio->fb_sample_freq = sample_freq;
- audio->fb_mclk_freq = mclk_freq;
+ audio->feedback.compute.fixed.sample_freq = sample_freq;
+ audio->feedback.compute.fixed.mclk_freq = mclk_freq;
}
// Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame)
- uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000;
- audio->fb_val_min = (sample_freq/frame_div - 1) << 16;
- audio->fb_val_max = (sample_freq/frame_div + 1) << 16;
+ uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000;
+ audio->feedback.min_value = (sample_freq/frame_div - 1) << 16;
+ audio->feedback.max_value = (sample_freq/frame_div + 1) << 16;
return true;
}
@@ -2083,20 +2090,20 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
audiod_function_t* audio = &_audiod_fct[func_id];
uint32_t feedback;
- switch (audio->fb_compute_method)
+ switch (audio->feedback.compute_method)
{
case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
- feedback = (cycles << audio->fb_power_of_two_val);
+ feedback = (cycles << audio->feedback.compute.power_of_2);
break;
case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
- feedback = (uint32_t) ((float) cylces * audio->fb_float_val);
+ feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const);
break;
case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
{
- uint64_t fb64 = (((uint64_t) cycles) * audio->fb_sample_freq) << (16 - audio->fb_n_frames_shift);
- feedback = (uint32_t) (fb64 / audio->fb_mclk_freq);
+ uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift);
+ feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq);
}
break;
@@ -2107,8 +2114,8 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
// The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1.
// This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot
// (audio slot = channel count samples).
- if ( feedback > audio->fb_val_max ) feedback = audio->fb_val_max;
- if ( feedback < audio->fb_val_min ) feedback = audio->fb_val_min;
+ if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value;
+ if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value;
tud_audio_n_fb_set(func_id, feedback);
@@ -2135,11 +2142,12 @@ void audiod_sof_isr (uint8_t rhport, uint32_t frame_count)
if (audio->ep_fb != 0)
{
- // TODO hs need to be adjusted to frame (SOF event is not generated for micro-frame)
- uint32_t const interval = (1UL << audio->fb_n_frames_shift);
+ // HS shift need to be adjusted since SOF event is generated for frame only
+ uint8_t const hs_adjust = (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0;
+ uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust);
if ( 0 == (frame_count & (interval-1)) )
{
- if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->fb_n_frames_shift);
+ if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift);
}
}
}
@@ -2431,7 +2439,7 @@ bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION
if ( TUSB_SPEED_FULL == tud_speed_get() )
{
- uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
+ uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value;
// For FS format is 10.14
*(fb++) = (feedback >> 2) & 0xFF;
@@ -2443,7 +2451,7 @@ bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
#else
{
// Send value as-is, caller will choose the appropriate format
- _audiod_fct[func_id].fb_val = feedback;
+ _audiod_fct[func_id].feedback.value = feedback;
}
#endif
diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h
index da4a45eee..09de8e9a8 100644
--- a/src/class/audio/audio_device.h
+++ b/src/class/audio/audio_device.h
@@ -487,11 +487,6 @@ TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id);
bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback);
static inline bool tud_audio_fb_set(uint32_t feedback);
-uint8_t tud_audio_n_get_fb_n_frames(uint8_t func_id);
-static inline uint8_t tud_audio_get_fb_n_frames();
-
-#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-
// Update feedback value with passed cycles since last time this update function is called.
// Typically called within tud_audio_sof_isr(). Required tud_audio_feedback_params_cb() is implemented
// This function will also call tud_audio_feedback_set()
@@ -511,8 +506,8 @@ typedef struct {
uint8_t method;
union {
struct {
- uint32_t sample_freq;
- uint32_t mclk_freq;
+ uint32_t sample_freq; // sample frequency in Hz
+ uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to which sample clock is based on
}frequency;
struct {
@@ -523,18 +518,16 @@ typedef struct {
};
}audio_feedback_params_t;
-
-// TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param);
-
-// mclk_freq : Main clock frequency in Hz i.e. master clock to which sample clock is locked
-// sample_freq : sample frequency in Hz
-// fixed_point : 0 float (default), 1 fixed point (for mcu without FPU)
-TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, uint32_t* sample_freq, uint32_t* mclk_freq, uint8_t* fixed_point);
+// Invoked when needed to set feedback parameters
+TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param);
// Callback in ISR context, invoked periodically according to feedback endpoint bInterval.
// Could be used to compute and update feedback value
-TU_ATTR_WEAK void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_log2);
+// frame_number : current SOF count
+// interval_shift: number of bit shift i.e log2(interval) from Feedback endpoint descriptor
+TU_ATTR_WEAK void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift);
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied);
@@ -682,11 +675,6 @@ static inline bool tud_audio_fb_set(uint32_t feedback)
return tud_audio_n_fb_set(0, feedback);
}
-static inline uint8_t tud_audio_get_fb_n_frames()
-{
- return tud_audio_n_get_fb_n_frames(0);
-}
-
#endif
//--------------------------------------------------------------------+