【朝花夕拾】RT600/1170 UAC改变输出端点interval方法

一,文档说明

客户在使用RT600官方SDK的usb复合体例程的时候,发现默认的HS interval 是125us,代码是:mimxrt685audevk_dev_composite_hid_audio_unified_bm。但是在实际的应用中,125us的数据包间隔传输数据,会让CPU有很大的中断负荷,所以客户希望把间隔改大一些,比如1ms,改成1ms之后发现数据包是能够发到RT芯片,但是RT这边播放确实有问题。改成同步模式下的500us也是可以,不过500us,客户的CPU负荷还是达到了80%以上,不便于后续应用代码扩展,所以还是希望做到1ms的方式。
本文将给出UAC不同interval的传输情况,并且给出1ms间隔的解决方案。

二,测试情况

开发板:MIMXRT685-AUD-EVK
SDK:SDK_2_15_000_MIMXRT685-AUD-EVK
USB分析仪:Lecroy USB-TOS2-A01-X

2.1 平台连接情况

首先,给出MIMXRT685-AUD-EVK和USB分析仪以及音源的连接情况,本文主要测试的是RT685 UAC speaker功能,也就是USB传输音源数据到RT685,并且通过播放器(可以是耳机)去播放音源。EVK的J7 USB口连接到Lecroy的A口,Lecroy的B口连接到音源,可以是PC也可以是手机,如果使用PC,需要把speaker选择成为USB AUDIO+HID DEMO,因为板子UAC的枚举成功后的名字就是USB AUDIO+HID DEMO。
Lecroy的另外一端USB连接到PC,用于传输USB总线数据,具体连接图如下:
在这里插入图片描述

图 1 EVK USB分析仪连接图

2.2 不同音频interval抓包情况

本篇给出不同interval下的修改情况,以及USB分析仪抓包的结果。
音频的同步/等时音频端点的时钟系统可以通过SOF来同步,usb 1.0采样率必须锁定到1ms的SOF节拍。USB2.0高速HS端点可以选择锁定到125us的SOF节拍。如果要改变interval,通常是125us的倍数,也就是可以是250us,500us, 1ms等,修改的方法通常是直接修改USB stack的usb_audio_config.h中的:

#define HS_ISO_OUT_ENDP_INTERVAL (0x01)

这个HS_ISO_OUT_ENDP_INTERVAL值和间隔时间的关系是:125us*2^( HS_ISO_OUT_ENDP_INTERVAL -1)
所以:

HS_ISO_OUT_ENDP_INTERVAL=1 : 125us
HS_ISO_OUT_ENDP_INTERVAL=2 : 250us
HS_ISO_OUT_ENDP_INTERVAL=3 : 500us
HS_ISO_OUT_ENDP_INTERVAL=4 : 1000us

下面分别对上述的4种情况通过USB分析仪抓包测试。

2.2.1 125us interval 抓包情况

#define HS_ISO_OUT_ENDP_INTERVAL (0x01)

在这里插入图片描述

图 2 125us interval
可以看到,在interval配置为125us的时候,各个OUT的包前面的SOF节拍间隔就是125us,OUT数据包长度为24Byte,这24Byte一包的数据就是实际的音频数据。
这种情况下,播放正常。

2.2.2 250us interval 抓包情况

  #define HS_ISO_OUT_ENDP_INTERVAL (0x02)

配置为250us的抓包如下图,可以看到,两个OUT包前面的SOF节拍间隔是250us,OUT数据包长度为48Byte,也就是说,随着interval间隔拉大,数据包长也在等比增长,也就是传输时间长了,但是一包包含的数据包也多了,这个时候也需要RT那边给出更多的USB接受buffer去接数据。
在这里插入图片描述

图 3 250us interval
这种情况下播放正常。

2.2.3 500us interval 抓包情况

#define HS_ISO_OUT_ENDP_INTERVAL (0x03)

在这里插入图片描述

图 4 500us间隔 同步模式
这个时候,可以看到数据包变成了96Byte字节,而且看数据内容也是一个正常的音频数据,不过播放已经出问题,听不到声音。
但是,如果同时配置:

#define USB_DEVICE_AUDIO_USE_SYNC_MODE (0U)

也就是处于非同步模式下,是能够正常听到声音的,抓包情况如下:
在这里插入图片描述

图 5 500us间隔 非同步模式
但是,非同步模式也有问题,经过长时间运行之后,可能会出现不同步,播放卡顿的问题。所以还是需要在同步模式下去做1ms的方式。

2.2.4 1ms interval 抓包情况

#define HS_ISO_OUT_ENDP_INTERVAL (0x04)

在这里插入图片描述

图 6 interval 1ms
可以看到数据包长已经变成了192字节,而且OUT包前面的SOF节拍间隔时间也确实变成了1ms,音频数据包的看上去也是正常的音频数据,所以说,这里的音频数据还是成功从USB传给了RT。但是播放异常,无法听到声音。

三,1ms inteval解决方案

下面开始工程debug查找问题,因为通过USB分析仪可以看到USB bus总线的音频数据是实际传输过去的,那么首先要查看USB的在audio_unified.c中的USB_DeviceAudioCompositeCallback中kUSB_DeviceAudioEventStreamRecvResponse事件中是否接到了数据包,数据包长是否正确,数据内容是否看上去音频数据,下面是debug 结果:
在这里插入图片描述

图7 数据包接收情况
所以从这点看,USB的接口数据包是接下来了,而且看着数据也是像真正的音频数据,如果不正常数据,要么就是全0,要么也不是这种会变化的无规律数据,但是测试结果不能播放。
所以去查看I2S播放函数情况,composite.h文件, TxCallback函数:
在这里插入图片描述

图8 I2S播放buffer
可以看到这里真正传给I2S的数据buffer永远是0,而且按道理应该是g_composite.audioUnified.startPlayFlag置位,使用:

s_TxTransfer.dataSize = g_composite.audioUnified.audioPlayTransferSize;
s_TxTransfer.data=audioPlayDataBuff + g_composite.audioUnified.tdReadNumberPlay;

但是看下来,audioPlayDataBuff数据也是0。所以问题应该是USB那边接收到了数据,但是数据在刷给audioPlayDataBuff的过程中出问题。这里还是需要回到audio_unified.c,
在这里插入图片描述

图 9 USB_DeviceAudioCompositeCallback
在这里插入图片描述

图10 USB_AudioSpeakerPutBuffer
测试发现,图9中,audioUnified.tdWriteNumberPlay永远无法超过

g_deviceAudioComposite->audioUnified.audioPlayTransferSize * AUDIO_CLASS_2_0_HS_LOW_LATENCY_TRANSFER_COUNT=192*6


#define AUDIO_CLASS_2_0_HS_LOW_LATENCY_TRANSFER_COUNT \
(0x06U) /* 6 means 6 mico frames (6*125us), make sure the latency is smaller than 1ms for sync mode */

这里的low latency是做一个延迟缓存。所以说,USB的缓存数据最起码要放得下这个延迟的数据包,单位1代表一个间隔的frame。现在改成了间隔1ms,6个延迟单位,意味着这里延迟做的是6ms,这里就需要接收buffer大小变大,和下面定义有关:
在这里插入图片描述

图11

g_composite.audioUnified.audioPlayBufferSize =
AUDIO_PLAY_BUFFER_SIZE_ONE_FRAME * AUDIO_SPEAKER_DATA_WHOLE_BUFFER_COUNT;

#define AUDIO_PLAY_BUFFER_SIZE_ONE_FRAME AUDIO_OUT_TRANSFER_LENGTH_ONE_FRAME

#define AUDIO_OUT_FORMAT_CHANNELS (0x02U)
#define AUDIO_OUT_FORMAT_SIZE     (0x02)
#define AUDIO_OUT_SAMPLING_RATE_KHZ (48)
/* transfer length during 1 ms */
#define AUDIO_OUT_TRANSFER_LENGTH_ONE_FRAME \
    (AUDIO_OUT_SAMPLING_RATE_KHZ * AUDIO_OUT_FORMAT_CHANNELS * AUDIO_OUT_FORMAT_SIZE)

#define AUDIO_SPEAKER_DATA_WHOLE_BUFFER_COUNT \
    (2U) /* 2 units size buffer (1 unit means the size to play during 1ms) */

所以这里考虑把AUDIO_SPEAKER_DATA_WHOLE_BUFFER_COUNT放大,最起码得放得下6ms的,1unit是1ms内播放的单位,那么需要缓存6ms以上,这里直接做成12个unit,所以修改定义:
#define AUDIO_SPEAKER_DATA_WHOLE_BUFFER_COUNT 12
再次编译烧录,抓USB波形:
在这里插入图片描述

图 12 成功播放1ms间隔数据包
这个数据波形是能够正常播放的数据。
下面给出MIMXRT685-AUD-EVK测试的视频情况。
附件提供了RT685和RT1170两个demo,都修改为1ms interval,RT1170的修改方法也完全一致。

四,总结

不论是RT600,还是RT1170,或者更准确的说整个RT系列的UAC代码,如果需要修改interval,主要关注的就是usb_audio_config.h如下几个宏,下面是针对1ms的interval:

#define HS_ISO_OUT_ENDP_INTERVAL (0x04)//(0x01)//(0X04)
#define AUDIO_CLASS_2_0_HS_LOW_LATENCY_TRANSFER_COUNT \
    (0x06U) /* 6 means 16 mico frames (6*125us), make sure the latency is smaller than 1ms for ehci high speed */
#define AUDIO_SPEAKER_DATA_WHOLE_BUFFER_COUNT \
    (12U)//(2U) /* 2 units size buffer (1 unit means the size to play during 1ms) */

代码链接:
https://community.nxp.com/t5/i-MX-RT-Knowledge-Base/RT600-1170-UAC-change-OUT-endpoint-interval-methods/ta-p/1887520

MIMXRT685-AUD-EVK UAC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值