UAC Feedback端点
下面转一段对USB feedback的理解:
这段时间一直在做USB Audio Device(UAC)设备的开发工作。由于UAC采用的是isochronous endpoint来传输数据,对时钟的要求较高。但无奈我们的嵌入式平台的时钟并不准,数据同步就成了问题。经过研究,发现只能使用异步模式来解决这个问题。
所谓异步模式,就是建立一个feedback endpoint在一个固定的时间间隔反馈本地时钟给host, 从而使得host端能够实时的了解client端的时钟变化,调节数据包的长度,从而避免接收或者发送缓冲溢出。
USB 2.0 spec在5.12.4.2中明确的定义了如何提供feedback给host, 个人觉得写得有点复杂,特总结如下:
- Feedback endpoint数据长度为3字节,发送间隔由bRefresh决定。
- Fm = Fs * 2^P, Fm是本地的时钟频率,Fs是采样频率。
- Tmeas=2^K/2^P=2^(K-P), Tmeas是测量时间, 对于full speed, K= 10, 对于high speed, K=13
- 在每Tmeasframe/subframe时间间隔,把本地的clock数写入feedback endpoint。
上面的一大段看起来很复杂,其实基本的思想很简单。不就是时钟不同步嘛,要想让大家同步,怎么办呢?比如说采样率是48000,如果时钟同步,那么1s的时间内,就应该有48000个sample。如果不同步,那么就测量1s, 把1s内的实际sample数返回给host端就可以了。上面的公式实际要表达的就是这个意思。至于要注意的是返回的格式,spec上面说是对于full speed, 数据格式是10.14,对于high speed, 数据格式是16.16。如果你的UAC设备是1.0 version,那么就算是你把它定义成一个high speed的设备,返回数据格式还是10.14的。
例如:
48000 采样率 –> feedback (48 * 2^14) = 0xc0000 = 1024*16*48
47000 采样率 –> feedback (47 * 2^14) = 0xbc000
计算10.14格式采样率代码(audio 1.0)- 全速
这里反馈端点反馈的数据是3个字节的。
/*该设备为:44.1K采样率,10.14格式*/
uint8_t audioFeedBackBuffer[4] = {0x40,0x06,0x0b};
void SetFeedBackSampleRate(uint32_t Rata)
{
Rata = ((Rata / 1000) << 14) | ((Rata % 1000) << 4);
audioFeedBackBuffer[0] = Rata;
audioFeedBackBuffer[1] = Rata>>8;
audioFeedBackBuffer[2] = Rata>>16;
}
计算16.16格式采样率代码(audio 2.0)- 高速/超高速
这部分代码是 通过USB声卡反推出来的,实测可以用。感觉跟USB2.0规范描述不一样。
这里反馈端点反馈的数据是4个字节的。
uint8_t audioFeedBackBuffer[4];
void SetFeedBackSampleRate(uint32_t Rata)
{
Rata = ((Rata / 1000) << 13) | ((Rata % 1000) << 3);
audioFeedBackBuffer[0] = Rata;
audioFeedBackBuffer[1] = Rata>>8;
audioFeedBackBuffer[2] = Rata>>16;
audioFeedBackBuffer[4] = Rata>>24;
}
相关链接:
https://blog.csdn.net/huangkangying/article/details/53152956
https://zhuanlan.zhihu.com/p/166661061
反馈端点描述符
反馈端点描述符一般位于AS接口描述符的Audio Data Endpoint Descriptor描述符之后,也就是说该AS接口描述符的最后面。
4字节的反馈端点描述符示例如下:
- UAC1:使用中断端点反馈
- UAC2:使用同步端点反馈
#define USB_ENDPOINT_SYNCTYPE 0x0c
#define USB_ENDPOINT_SYNC_NONE (0 << 2)
#define USB_ENDPOINT_SYNC_ASYNC (1 << 2)
#define USB_ENDPOINT_SYNC_ADAPTIVE (2 << 2)
#define USB_ENDPOINT_SYNC_SYNC (3 << 2)
#define USB_ENDPOINT_USAGE_MASK 0x30
#define USB_ENDPOINT_USAGE_DATA 0x00
#define USB_ENDPOINT_USAGE_FEEDBACK 0x10
#define USB_ENDPOINT_USAGE_IMPLICIT_FB 0x20
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x15, // bmAttributes (Isochronous, Async, Feedback EP)
0x04, 0x00, // wMaxPacketSize 4
0x03, // bInterval 3 (unit depends on device speed)
什么时候FeedBack
由于主机与设备之间的频率不一致,而使用异步传输模式,设备和主机有各自的时钟,时钟频率差异会导致缓冲区上溢或下溢(爆音/断音)。所以设备通过 USB 反馈端点告诉主机实际时钟频率,主机据此调整发送/接收速率。
Linux USB Gadget UAC系统中:
- 允许的最大频率负偏差(设备时钟比主机慢)250‰(百万分之250)= 0.25% 2500ppm(百万分之2500)
- 允许的最大频率正偏差(设备时钟比主机快)5‰(百万分之5)= 0.005% = 50ppm
但注意:在音频时钟精度中,通常指 2500ppm(百万分之2500)
更直观的例子:
- 48kHz 采样率下,250‰ 偏差 = 48kHz × 0.0025 = 120Hz
- 设备时钟在 47,880Hz 到 48,120Hz 范围内(对于慢速偏差)
/* sound/usb/endpoint.c 中的定义 */
#define MAX_FB_SLOW_DEVIATION 250 /* 250‰ */
#define MAX_FB_FAST_DEVIATION 5 /* 5‰ */
// 设备检测到时钟偏差时的处理
if (deviation > FBACK_FAST_MAX) {
// 时钟太快,需要报告给主机
send_feedback(actual_freq);
} else if (deviation < -FBACK_SLOW_MAX) {
// 时钟太慢,需要报告
send_feedback(actual_freq);
} else {
// 在允许范围内,正常工作
}
本文链接为:http://www.usbzh.com/article/detail-274.html ,欢迎转载,转载请附上本文链接。
UAC规范(USB音频)





