STM32 USB endpoint 地址设置说明

2 篇文章 0 订阅
1 篇文章 0 订阅

STM32 USB endpoint 地址设置说明

前言

  移植STM32 usb功能时发现usb_prop.c文件中usb初始化需要设置usb的endpoint地址,之前使用的时候都是直接使用demo程序,没有细致研究,本次使用STM32的usb是想把与virtual com与Mass storage融合在一起,而这两个应用的endpoint地址不一样,所以了解下具体的设置方法,这里做一个记录。

  文件主要记录问题提出、问题简答的分析方法以及最终的结论。如果只是想知道结果直接看结论就好了。

疑问

  查看Mass storage应用中usb_conf.h的内容大致如下:

#define EP_NUM              (3)

#define BTABLE_ADDRESS      (0x00)
/* EP0  */
/* rx/tx buffer base address */
#define ENDP0_RXADDR        (0x18)
#define ENDP0_TXADDR        (0x58)
/* EP1  */*
*/* tx buffer base address */
#define ENDP1_TXADDR        (0x98)
/* EP2  */
/* Rx buffer base address */
#define ENDP2_RXADDR        (0xD8)
/* EP1  */
/* tx buffer base address */
#define ENDP3_TXADDR        (0x118)
/* EP2  */
/* Rx buffer base address */
#define ENDP4_RXADDR        (0x158)

​ 查看Virtual COM应用中usb_conf.h的内容大致如下:

#define EP_NUM              (4)

/* buffer table base address */
#define BTABLE_ADDRESS      (0x00)

/* EP0  */
/* rx/tx buffer base address */
#define ENDP0_RXADDR        (0x40)
#define ENDP0_TXADDR        (0x80)

/* EP1  */
/* tx buffer base address */
#define ENDP1_TXADDR        (0xC0)
#define ENDP2_TXADDR        (0x100)
#define ENDP3_RXADDR        (0x110)

  两个应用中都定义了BTABLE_ADDRESS的地址为0x00,而ENDP0_RXADDR的地址,一个定义为0x18,另一个定义为0x40,那是为何?对应的地址改如何设置,设置的地址在代码中又有什么影响?

分析

  首先来看看BTABLE_ADDRESS,这个BTABLE_ADDRESS到底是存放什么的?

  直接在代码中检索SetBTABLE(BTABLE_ADDRESS);可以发现在usb_prop.c中使用到了BTABLE_ADDRESS:

SetBTABLE(BTABLE_ADDRESS);

  一路跳转下去查找下去最后的实现语句为:

#define _SetBTABLE(wRegValue)(*BTABLE = (uint16_t)(wRegValue & 0xFFF8))

  其中wRegValue的值就是BTABLE_ADDRESS,所以最终就是

*BTABLE =0;

  下面在追踪一下指针 *BTABLE,可以看到BTABLE的定义

#define RegBase  (0x40005C00L)
#define BTABLE  ((__IO unsigned *)(RegBase + 0x50))

  所以其实SetBTABLE就是设置0x40005C50L地址寄存器的数值为0。那0x40005C50L地址寄存器是什么呢?

  由于本次使用的是STM32F103的单片机,所有参看对应的技术文档《RM0008》的643页,可以查看到对应的寄存器以及寄存器的说明。具体如下:

  These bits contain the start address of the buffer allocation table inside the dedicated packet memory. This table describes each endpoint buffer location and size and it must be aligned to an 8 byte boundary (the 3 least significant bits are always ‘0). At the beginning of every transaction addressed to this device, the USB peripheral reads the element of this table related to the addressed endpoint, to get its buffer start location and the buffer size (Refer to Structure and usage of packet buffers on page 626).

  主要是看黑体字部分描述,大概意思是说,每次开始传输时,USB外设读取本表中的端点地址以及端点缓存的大小,由此可见这个BTABLE_ADDRESS地址主要存储两个参数,一个是端点地址,另一个是端点的缓存大小。

  这里又出现了一个新的问题,那BTABLE_ADDRESS地址存储的端点地址以及端点缓存大小需要多少空间呢?

  在回头来看看代码,代码中*BTABLE指针里面的值是怎被使用的,看看数据是怎么被存进去的,存进去的数据有多少呢?另外看看实际存放的是不是端点地址以及缓存大小。

  通过代码查找BTABLE关键字不难看出,_SetBTABLE有与之对应的_GetBTABLE。同时_SetBTABLE被使用到的代码如下:

#define _pEPTxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8  )*2 + PMAAddr))
#define _pEPTxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr))
#define _pEPRxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr))
#define _pEPRxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr))

#define _GetEPTxAddr(bEpNum) ((uint16_t)*_pEPTxAddr(bEpNum))
#define _GetEPRxAddr(bEpNum) ((uint16_t)*_pEPRxAddr(bEpNum))
#define _SetEPTxCount(bEpNum,wCount) (*_pEPTxCount(bEpNum) = wCount)
#define _SetEPRxCount(bEpNum,wCount) {\
    uint32_t *pdwReg = _pEPRxCount(bEpNum); \
    _SetEPCountRxReg(pdwReg, wCount);\
  }

void SetEPTxAddr(uint8_t bEpNum, uint16_t wAddr)
{
  _SetEPTxAddr(bEpNum, wAddr);
}
void SetEPRxAddr(uint8_t bEpNum, uint16_t wAddr)
{
  _SetEPRxAddr(bEpNum, wAddr);
}

void SetEPTxCount(uint8_t bEpNum, uint16_t wCount)
{
  _SetEPTxCount(bEpNum, wCount);
}

void SetEPRxCount(uint8_t bEpNum, uint16_t wCount)
{
  _SetEPRxCount(bEpNum, wCount);
}

  从这里可以看出,wAddr就是端点地址,wCount就是端点缓存大小了,都是2个字节的长度,而这里的bEpNum定义其实就是具体设置哪个端点了,具体如下:

#define ENDP0       ((uint8_t)0)
#define ENDP1       ((uint8_t)1)
#define ENDP2       ((uint8_t)2)
#define ENDP3       ((uint8_t)3)
#define ENDP4       ((uint8_t)4)
#define ENDP5       ((uint8_t)5)
#define ENDP6       ((uint8_t)6)
#define ENDP7       ((uint8_t)7)

  那BTABLE_ADDRESS地址存储的端点地址以及端点缓存大小需要多少空间就可以简单计算出来了,STM32F103单片机有8个端点,每个端点需要存储TxAddr,RxAddr,TxCount,RxCount四个变量,每个变量都是2个字节,那就是一个节点需要8个字节。8个节点最大需要64个字节。

结论

  根据以上的分析,我们来看看前面提及的问题,两个应用中都定义了BTABLE_ADDRESS的地址为0x00,而ENDP0_RXADDR的地址,一个定义为0x18,另一个定义为0x40,那是为何?对应的地址改如何设置,设置的地址在代码中又有什么影响?

  其实ENDP0_RXADDR定义的地址就是为了BTABLE_ADDRESS的偏移量,确保BTABLE_ADDRESS有足够的控件存储前面提及的端点的TxAddr,RxAddr,TxCount,RxCount。

  Mass storage应用中EP_NUM =3,所以BTABLE_ADDRESS只需要24个字节就足够存储每个端点的参数了,故ENDP0_RXADDR从0x18地址开始。

  而在Virtual COM应用中EP_NUM=4,那应该是32个字节就足够,ENDP0_RXADDR地址从0x20开始足以,为何设置成0x40。这里个人猜测编写Demo代码的程序员是想设置一个BTABLE_ADDRESS地址的最大偏移量,方便后续端点的随意使用不需要在考虑BTABLE_ADDRESS的大小问题所以设置了64个字节的便宜,足够存放8个端点的所有参数

拓展

  既然谈到了端点地址的设置,那随便记录一下后面的各个端点的地址如何设置呢?

  其实后面就简单了,设置的方法就是当前的地址加上对应的地址的缓存大小。

  比如ENDP0_RXADDR=0x40ENDP0_RxCount=64,所以ENDP0_TXADDR=ENDP0_RXADDR+ENDP0_RxCount=0x58

  而每个端点的具体的缓存长度有是多上呢?这个通过上面提及SetEPRxCountSetEPTxCount查看一下代码设置的缓存长度是多上就知道了。

  以上所有都是个人的学习笔记,若有错误的地方欢迎大家指点。

  知识就是财富,每次积累一点点,终究会有质的飞跃。

​                           幽灵

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值