完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
最近在使用STM32的USB模块开发个项目,还以为挺简单,结果搞了快两天才把USB的包缓冲区的访问搞定,在此做个小总结吧。
STM32的USB模块包缓冲区有512B,但是在STM32的参考手册中的存储器映像中却表明0x40006000-0x400063ff,整整多了512B,怎么会这样呢,同时在尝试着编程时也遇到了一个问题: 在u***_core.c文件的Setup0_Process(void)这个函数中,有这么一段: uint16_t offset = 1; if (pInformation->ControlState != PAUSE) { pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */ pInformation->USBbRequest = *pBuf.b++; /* bRequest */ pBuf.w += offset; /* word not accessed because of 32 bits addressing */ pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */ pBuf.w += offset; /* word not accessed because of 32 bits addressing */ pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* wIndex */ pBuf.w += offset; /* word not accessed because of 32 bits addressing */ pInformation->USBwLength = *pBuf.w; /* wLength */ } 这其中又不太明白为什么需要pBuf.w += offset;而且后面的解释也不太懂 /* word not accessed because of 32 bits addressing */ ,我于是在这段之前加入调试以显示收到什么数 #ifdef DEBUG UARTSend_String("*** 端点0收到SETUP数据 ***rn"); for(offset=0;offset<16;offset++) { UARTSend_Hex(*pBuf.b++); } #endif 结果串口调试显示如下: *** USB总线复位 *** *** USB总线CTR置位 *** *** 进入端点0 *** *** 端点0收到SETUP包 *** *** 端点0收到SETUP数据 *** 0x80 0x06 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x40 0x00 0x00 0x00 本来应该显示0x80 0x06 0x00 0x01 0x00 0x000x40 0x00才对,不太明白怎么0x80 0x06和0x00 0x01 后面多了两个 0x00 ,难道USB模块还会将收到的数据跳着放吗? 后来反复看参考手册,问了些人,才知道原来STM32的USB缓冲区是一个双端口的RAM,CPU一端需要使用32位方式访问,但USB模块一端使用16位方式访问。 也就是说每个USB模块中的地址*2才能对应到控制器中的实际地址,这样每四个字节地址空间后两个字节地址空间是空的。所以上面串口调试显示的数据每正确两个字节就会多出两个字节的0x00。 这里也对STM32的USB库函数中对缓冲区的操作函数做个说明: 在u***_men.c文件有这么一个函数 void PMAToUserBufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) uint32_t n = (wNBytes + 1) >> 1;/* /2*/ uint32_t i; uint32_t *pdwVal; pdwVal = (uint32_t *)(wPMABufAddr * 2 + PMAAddr); for (i = n; i != 0; i--) { *(uint16_t*)pbUsrBuf++ = *pdwVal++; pbUsrBuf++; } 它的作用是将缓冲区中的数据拷贝到你所定义的uint8_t Receive_Buffer[];数组中。其它地方都好理解,这里说说 pdwVal = (uint32_t *)(wPMABufAddr * 2 + PMAAddr); for (i = n; i != 0; i--) { *(uint16_t*)pbUsrBuf++ = *pdwVal++; pbUsrBuf++; } 首先是pdwVal = (uint32_t *)(wPMABufAddr * 2 + PMAAddr);这里wPMABufAddr * 2 之所以要*2就是前面所述的USB模块中的地址*2才能对应到控制器中的实际地址,在取得对应端点的缓冲区首地址后,将其(uint32_t *)强制指向uint32_t型,这样每次*pdwVal++,pdwVal的地址都增加4个字节,并且每次都会有四个字节的数据读出。 在for循环中,*(uint16_t*)pbUsrBuf++ = *pdwVal++;这句重点说说,++ 与指针*同优先级,结合顺序为至右向左结合,因此相当于*((uint16_t*)pbUsrBuf++),先*(uint16_t*)pbUsrBuf赋值只取*pdwVal++的32位数据的前16位,然后再将pbUsrBuf加上1个字节。到这里,前面定义的uint8_t Receive_Buffer[];数组中就有两个数组变量被赋值了,但这时地址还指增加一个字节,因此还需要pbUsrBuf++;让其指向Receive_Buffer[];的下下个数组变量。一次循环,知道读出所有数据。 |
|
相关推荐
|
|
请问楼主,就是一但接收升级程序完成后,执行升级后的程序,但是由于程序错误或者接收不完全,导致程序无法运行,如何回到API位置,是否只有返厂重新加载API?还是有更合理的方案? |
|
|
|
|
|
1252 浏览 1 评论
AD7686芯片不传输数据给STM32,但是手按住就会有数据。
1184 浏览 3 评论
2263 浏览 0 评论
如何解决MPU-9250与STM32通讯时,出现HAL_ERROR = 0x01U
1351 浏览 1 评论
hal库中i2c卡死在HAL_I2C_Master_Transmit
1774 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-28 16:09 , Processed in 0.566833 second(s), Total 69, Slave 51 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号