2019独角兽企业重金招聘Python工程师标准>>>
最近在维护一个基于STM32F4 Discovery的USB Audio项目,之前在Mac OSX环境下测试正常,但今天在Windows10上测试了下没有声音输出。
使用Keil Debug了下发现在Windows 10 USB连接下有个关于DMA配置的全局变量被莫名其妙的改写成其他值,导致I2S DMA传输出错。
可以发现DMA_InitStructure被改写的面目全非,难怪要出现DMA Tranfer Error了。
添加断点发现只要一进USB中断DMA_InitStructure就会被改写,先怀疑是中断导致的重入问题,因为这里面涉及到I2S DMA和USB 2个中断处理都会对这个全局变量进行写操作,所以屏蔽了所有对DMA_InitStructure的写操作,问题依旧。
后来想想刚开始思路不对,在Mac OSX上是能正常工作的,为什么在Windows10上不行呢?那一定是USB Host驱动不同导致的问题。于是用USB分析仪对比了两者的交互流程:
两者之间明显的区别是Windows每次第一个发起的setup token包中请求的长度都是255(应该是它能处理的最大长度),而Mac OSX则是用8, 2,9这类小的长度进行试探,这无可厚非,或许Windows更喜欢采用一次性到位的策略吧。比较了USB的整个交互过程没发现其他不同。
又想了想,还是看看编译出来的map文件或许能有新的发现。果然:
sampleBuffer 0x20000e48 Data 57600 usbd_audio_out_if.o(.bss)
USBD_StrDesc 0x2000ef48 Data 50 usbd_req.o(.bss)
DMA_InitStructure 0x2000ef7c Data 60 stm32f4_discovery_audio_codec.o(.bss)
AUDIO_MAL_DMA_InitStructure0x2000efb8 Data 60 stm32f4_discovery_audio_codec.o(.bss)
根据经验很有可能USBD_StrDesc越界导致把DMA_InitStructure改写了,看了下USBD_StrDesc被填充的值的末尾数据:
00530046不正是被改写的值吗?看了下大小是66,在代码中check了下发现USBD_StrDesc被定义为50字节的数组,难怪会出现问题,将USBD_StrDesc大小改大问题果然被解决了。
但一开始为什么在Mac OSX上是正常的呢?是因为DMA_InitStructure是放在第一次setup token里面实现的,由于Mac OSX第一次发起的请求的长度是2,没有触发覆写的边界条件,幸运的避开了这个问题。