您的位置:首页 > 其它

使用STM32的USB模块中后对USB缓冲区的认识

2012-03-14 16:07 225 查看
最近在使用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数据 ***\r\n");

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[];的下下个数组变量。一次循环,知道读出所有数据。

转自http://blog.csdn.net/ringstart/article/details/6822377
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: