zoukankan      html  css  js  c++  java
  • 使用STM32的USB模块中后对USB缓冲区的认识

    最近在使用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


  • 相关阅读:
    Windows下建立FTP服务器站点
    Markdown语法指南
    Win7系统修改hosts无法保存怎么办?
    PHP 7 错误处理 Error
    strtotime 的 BUG
    三角箭头 css实现
    关于 layer.open 动态赋值不了的问题
    layui layer.open弹出框获取不了 input框的值
    webhook 自动部署代码
    lnmp 命令 及其 TP5 部署遇到的一些问题
  • 原文地址:https://www.cnblogs.com/findstr/p/2803693.html
Copyright © 2011-2022 走看看