历史上的今天
今天是:2024年11月05日(星期二)
2020年11月05日 | 使用STM32的USB模块中后对USB缓冲区的认识
2020-11-05 来源:eefocus
最近在使用STM32的USB模块开发个项目,还以为挺简单,结果搞了快两天才把USB的包缓冲区的访问搞定,在此做个小总结吧。
STM32的USB模块包缓冲区有512B,但是在STM32的参考手册中的存储器映像中却表明0x40006000-0x400063ff,整整多了512B,怎么会这样呢,同时在尝试着编程时也遇到了一个问题:
在usb_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库函数中对缓冲区的操作函数做个说明:
在usb_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_tReceive_Buffer[];数组中就有两个数组变量被赋值了,但这时地址还指增加一个字节,因此还需要pbUsrBuf++;让其指向Receive_Buffer[];的下下个数组变量。一次循环,知道读出所有数据。
史海拾趣
|
问题一:RFID是什么?RFID是Radio Frequency Identification的缩写,即射频识别,俗称电子标签。 问题二:什么是RFID技术? RFID射频识别是一种非接触式的自动识别技术,它通过射频信号自动识别目标对象并获取相关数据,识别工作无须人工 ...… 查看全部问答> |
|
编制了利用EXCEL为运算平台,能够自动计算的《经纬仪导线测量计算簿》 测量工作是煤矿生产的眼睛,它为矿山建设的设计和施工提供了必要的基础数据和资料。矿山测量工作分为外业和内业两项,内业计算工作需要进行大量的函数和数据运算,稍不注意就可能出现错误,将给矿山的安全生产工作造成损失。另外,随着地质测量标准化工 ...… 查看全部问答> |
|
大家好,我想学习FPGA,对它很感兴趣。 所以想买一块学习板,请大家推荐一款比较适合初学者的。价格的话在800以内就行。 如果可以的话,推荐几本经典的书就更好了。 小弟在此先谢过了 … 查看全部问答> |
|
在WINCE显示设备里出现连个flash设备:Nandflash,Nandflash2,而两个FLASH文件夹都是指向同一个flash。查了下注册表,里 面就有一个FLASH项。请问这是哪里设置不对造成的?… 查看全部问答> |
|
新建了一个wince下的单文档工程,在CMainFrame里添加了EraseBkgnd的消息响应,设置断点发现程序并没有进入响应。 后来又新建了一个windows下的单文档工程,同样添加消息响应,发现程序有响应EraseBkgnd。 不知道为什么。麻烦高手解答。… 查看全部问答> |
|
大神们 求帮帮忙吧, 把50hz左右交流转成直流,AD给单片机测其电压,交流幅值变换在0到15v左右吧,直流电压最好就是交流有效值,要有比例关系。要精确点的,大家给点意见吧,最好是以前做过的。… 查看全部问答> |
|
助力电子爱好者开发更小型、更友好、更低成本解决方案 信用卡大小的开发板支持便捷硬件扩展、通过单线缆以及 10 秒钟 Linux 启动便可实现快速开发 北京2011年11月2日电 -- 日前,BeagleBoard.org 高兴地宣布推出其深受青睐产品系列中 ...… 查看全部问答> |
|
场效应管共源极放大器实验 一、实验目的1、明确场效应管的性能和特点2、明确场效应管共源极放大器的特点3、进一步熟悉放大器静态工作点和动态参数的调试方法 二、预习要求1、熟悉有关场效应管部分内容,并根据提供的实验电路参数,分别用 ...… 查看全部问答> |
|
摘 要 UCD3028 数字电源功能丰富,可以完成两个独立功率支路的控制;软件配置灵活,可以实现多种功能包括多种故障的检测和处理。本文基于一款1/8 砖模块产品对UCD3028 的软件设计进行了详细说明,内容包括外界模拟信号的采集与转换,副边电流的采 ...… 查看全部问答> |




