你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F103 上 USB 的端点资源灵活使用

[复制链接]
STMCU小助手 发布时间:2022-2-11 22:31
前言
理解 STM32F103 上 USB 模块的端点资源,灵活在应用中的配置。

问题
某客户使用 STM32F103 的 USB 模块做设备时和上位机 PC 连接时碰到一个问题:PC 端驱动已经固
定好,是对下位机 USB 设备上的地址编号为 0x0A 和 0x0B 的两个端点通信,从 0x0A 端点读取数据,
向 0x0B 端点写数据。而 STM32F103 的 USB 模块只有 8 个双向端点,能否支持这样的寻址。

1. 问题调研
   我们先来看看 STM32F103 上的 USB 端点资源。从 STM32F103 参考手册(RM0008)可知,一共有8 个双向端点,对应 8 个寄存器来控制其属性和表征其状态。如下图,可知每一对端点必须配置成相同的端点地址,这个地址位域是 4 位,取值从 0x0 到 0x0F 范围。

~{FA[HY@EV72{SAB@39H){2.png

   和以下摘录的 USB 规范符合:

4Q4IJ]Y_LY]IH~MN6TUMTKP.png

   客户使用的是 STSW-STM32121(STM32F10x, STM32L1xx and STM32F3xx 全速 USB 设备库),那么应该修改哪些代码呢?
2. 问题分析
   首先,USB 设备通过端点描述符向主机 PC 报告它所使用的端点有哪些:每个端点的地址(即 USB 规范里,以及参考手册的寄存器中规定的那 4 位地址域)、传输方向、传输类型、最大包长等。以STSW-STM32121 库中的 Mass_Storage 例程为例,需要把中的端点描述符做如下修改:0x0A 地址的端点作为 IN 端点(PC 从它读取数据),0x0B 地址的端点作为 OUT 端点(PC 向它写据)。
  1. const uint8_t MASS_ConfigDescriptor[MASS_SIZ_CONFIG_DESC] =
  2. {
  3. 。。。。。。
  4. /* 18 */
  5. 0x07, /*Endpoint descriptor length = 7*/
  6. 0x05, /*Endpoint descriptor type */
  7. 0x8A, //0x81, /*Endpoint address (IN, address 1) */
  8. 0x02, /*Bulk endpoint type */
  9. 0x40, /*Maximum packet size (64 bytes) */
  10. 0x00,
  11. 0x00, /*Polling interval in milliseconds */
  12. /* 25 */
  13. 0x07, /*Endpoint descriptor length = 7 */
  14. 0x05, /*Endpoint descriptor type */
  15. 0x0B, //0x02, /*Endpoint address (OUT, address 2) */
  16. 0x02, /*Bulk endpoint type */
  17. 0x40, /*Maximum packet size (64 bytes) */
  18. 0x00,
  19. 0x00 /*Polling interval in milliseconds*/
  20. /*32*/
  21. };
复制代码

接下来就是考虑使用 STM32F103 USB 模块提供的 8 个双向端点的哪个端点了。我们刚才从参考手册
关于寄存器描述的截图中看到,每一对端点具有相同的地址。在库函数里,对端点寄存器的地址位域
的操作在这里:
  1. void SetDeviceAddress(uint8_t Val)
  2. {
  3. uint32_t i;
  4. uint32_t nEP = Device_Table.Total_Endpoint;
  5. /* set address in every used endpoint */
  6. for (i = 0; i < nEP; i++)
  7. {
  8. _SetEPAddress((uint8_t)i, (uint8_t)i);
  9. } /* for */
  10. _SetDADDR(Val | DADDR_EF); /* set device address and enable function */
  11. }
复制代码
这个函数的名称是“设置(USB)设备地址”,但是其中除了最后一句是在设置 USB 设备的地址,前面
的 for 循环是在设置该设备内的端点地址。

   从以上绿色标注的代码段可以看到,库代码固定给 1 号端点”0x01”这个地址,2 号端点”0x02”这个地址,以此类推。这里的”1 号”、”2 号”指的是端点的编号,对应的就是之前提到的 8 个寄存器的编号,即下图中的 n=0~7。n 在这里就是端点的编号。

VHN6%WI7UEW4X5`{5LMJYDM.png

   那么在这个应用中,需要用到地址为 0x0A 和 0x0B 的两个端点,但是端点编号最多只能到 7,因此需要修改库代码中关于端点地址设置的地方如下:这里,我们使用编号为 1 和 2 的两个端点。
   为啥不用编号 0?因为编号 0 默认给双向 0 端点,即用于控制传输的 0 端点。
   为啥用 2 个编号?因为这里需要 2 个不同的端点地址,必须用 2 个编号。一个编号对应的 2 个端点必须共享同样的端点地址。
  1. void SetDeviceAddress(uint8_t Val)
  2. {
  3. /* set address in every used endpoint */
  4. _SetEPAddress((uint8_t)0, (uint8_t)0);
  5. _SetEPAddress((uint8_t)1, (uint8_t)0x0A); // 1 号端点是 0x8A,即地址为 A 的 IN 端点
  6. _SetEPAddress((uint8_t)2, (uint8_t)0x0B); // 2 号端点是 0x0B,即地址位 B 的 OUT 端点
  7. _SetDADDR(Val | DADDR_EF); /* set device address and enable function */
  8. }
复制代码
  既然这里指定了使用编号 1 和编号 2 的端点,那么需要在中设置这两个端点的硬件收发缓冲区地址
  1. /* EP0 */
  2. /* rx/tx buffer base address */
  3. #define ENDP0_RXADDR (0x18)
  4. #define ENDP0_TXADDR (0x58)
  5. /* 1 号端点,IN 端点,发送缓冲区如下 */
  6. #define ENDP1_TXADDR (0x98)
  7. /* 2 号端点,OUT 端点,接收缓冲区如下 */
复制代码

   当然如果你很任性,一定要使用编号为 6 和 7 的端点,也可以,那么代码就如下修改:
  1.    void SetDeviceAddress(uint8_t Val)
  2.    {
  3.    /* set address in every used endpoint */
  4.    _SetEPAddress((uint8_t)0, (uint8_t)0);
  5.    _SetEPAddress((uint8_t)6, (uint8_t)0x0A);
  6.    _SetEPAddress((uint8_t)7, (uint8_t)0x0B);
  7.    _SetDADDR(Val | DADDR_EF); /* set device address and enable function */
  8.    }
复制代码

   相应地,需要在中指明编号为 6 和 7 的这两个端点的硬件收发缓冲区地址。那么如法炮
   制做如下修改,就可以了吗?就可以了吗?就可以了吗?
  1.    /* EP0 */
  2.    /* rx/tx buffer base address */
  3.    #define ENDP0_RXADDR (0x18)
  4.    #define ENDP0_TXADDR (0x58)
  5.    /* 6 号端点,IN 端点,发送缓冲区如下 */
  6.    #define ENDP6_TXADDR (0x98)
  7.    /* 7 号端点,OUT 端点,接收缓冲区如下 */
  8.    #define ENDP7_RXADDR (0xD8)
复制代码

   答案是否定的!以下的代码才 OK。欲知详情,请参考下一条应用技巧《STM32F103 上 USB 模块的
   包缓冲区详解》
  1.    /* EP0 */
  2.    /* rx/tx buffer base address */
  3.    #define ENDP0_RXADDR (0x40)
  4.    #define ENDP0_TXADDR (0x80)
  5.    /* 6 号端点,IN 端点,发送缓冲区如下 */
  6.    #define ENDP6_TXADDR (0xC0)
  7.    /* 7 号端点,OUT 端点,接收缓冲区如下 */
复制代码


收藏 评论0 发布时间:2022-2-11 22:31

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版