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

发现STM32F2/F4 ETH标准库函数ETH_Get_Received_Frame_interrupt的重大....

[复制链接]
zlk1214 提问时间:2017-12-20 11:27 /
FrameTypeDef ETH_Get_Received_Frame_interrupt(void)这个函数,注释中说的是在接收中断(ETH_GetDMAFlagStatus(ETH_DMA_FLAG_R) == SET)发生的时候调用。因此在lwip的ethernetif.c中的数据包接收函数中调用:
  1. static struct pbuf *low_level_input(struct netif *netif)
  2. {
  3.   /* 数据包接收函数 */
  4.   //struct ethernetif *ethernetif = netif->state;
  5.   struct pbuf *p/*, *q*/;
  6.   u16_t len;
  7.   FrameTypeDef frame = ETH_Get_Received_Frame_interrupt(); // 获取数据包信息 (代码1)
  8.   
  9.   /*
  10.   // 代码(2)
  11.   FrameTypeDef frame;
  12.   frame.buffer = DMARxDescToGet->Buffer1Addr;
  13.   frame.descriptor = DMARxDescToGet;
  14.   frame.length = (DMARxDescToGet->Status >> 16) & 0x3fff;
  15.   DMARxDescToGet = (ETH_DMADESCTypeDef *)DMARxDescToGet->Buffer2NextDescAddr;
  16.   */
  17.   
  18.   ...
  19. }
复制代码
运行时会发现,返回的frame.buffer始终指向第一个接收缓冲区的地址0x20000244,且DMA_RX_FRAME_infos->Seg_Count的值在不断增加。
将代码1注释掉,换成自己写的代码2,程序就能正常运行。
STM32F207VE Ethernet
SYSCLK=120.0MHz HCLK=120.0MHz PCLK1=30.0MHz PCLK2=60.0MHz
MAC Addr: 30:7C:04:11:90:03
[Send] len=350
buffer=0x20000244 descriptor=0 length=60
FS_Rx_Desc=0 LS_Rx_Desc=0 Seg_Count=1
[Recv] len=60
buffer=0x20000244 descriptor=1 length=60
FS_Rx_Desc=0 LS_Rx_Desc=1 Seg_Count=2
[Recv] len=60
buffer=0x20000244 descriptor=2 length=60
FS_Rx_Desc=0 LS_Rx_Desc=2 Seg_Count=3
[Recv] len=60
[Send] len=350
buffer=0x20000244 descriptor=3 length=344
FS_Rx_Desc=0 LS_Rx_Desc=3 Seg_Count=4
[Recv] len=344
buffer=0x20000244 descriptor=4 length=60
FS_Rx_Desc=0 LS_Rx_Desc=4 Seg_Count=5
[Recv] len=60
buffer=0x20000244 descriptor=0 length=60
FS_Rx_Desc=0 LS_Rx_Desc=0 Seg_Count=6
[Recv] len=60
buffer=0x20000244 descriptor=1 length=60
FS_Rx_Desc=0 LS_Rx_Desc=1 Seg_Count=7
[Recv] len=60
[Send] len=350
buffer=0x20000244 descriptor=2 length=344
FS_Rx_Desc=0 LS_Rx_Desc=2 Seg_Count=8
[Recv] len=344

翻阅stm32f2x7_eth.c整个代码,会发现当且仅当FS(First segment)=1且LS(Last segment)=0时,Seg_Count才会被设回1。
而ETH标准库默认的缓冲区大小是1524,这就注定了接收描述符中基本上都是FS和LS同时为1,不可能有FS=1, LS=0的情况,因此Seg_Count的值永远只增不减,返回的frame.buffer值始终指向第一个接收缓冲区,而frame.length则等于当前缓冲区接收到的数据帧大小。
  1. if (DMA_RX_FRAME_infos->Seg_Count >1)
  2.       {
  3.         frame.buffer =(DMA_RX_FRAME_infos->FS_Rx_Desc)->Buffer1Addr;
  4.       }
复制代码


还有,以下两个函数的实现也有问题:
  1. uint32_t ETH_GetTransmitProcessState(void)
  2. {
  3.   return ((uint32_t)(ETH->DMASR & ETH_DMASR_TS));
  4. }

  5. uint32_t ETH_GetReceiveProcessState(void)
  6. {
  7.   return ((uint32_t)(ETH->DMASR & ETH_DMASR_RS));
  8. }
复制代码
返回的应该分别是ETH_DMASR_TPS和ETH_DMASR_RPS才对!否则根本不可能得到他注释里标称的结果!

所以,慎用ETH的标准库函数!必要情况下自己写寄存器来实现

收藏 1 评论4 发布时间:2017-12-20 11:27

举报

4个回答
zlk1214 回答时间:2017-12-20 11:35:35
之前一直以为是ETH_Init()或者是数据包发送函数的问题
一一排除之后,才知道是接收函数有问题
MrJiu 回答时间:2017-12-20 14:35:58
赶紧移植到hal库,官方主推的啦!!!
zlk1214 回答时间:2020-4-19 23:59:59
HAL库的HAL_ETH_GetReceivedFrame仍然有这个问题,所以STM32CubeMX生成的代码中有这样一句话:heth.RxFrameInfos.SegCount = 0
zlk1214 回答时间:2020-4-20 00:04:05
HAL库里面的下面两个宏的实现也有问题:
  1. #define __HAL_ETH_DMATXDESC_GET_FLAG(__HANDLE__, __FLAG__)             ((__HANDLE__)->TxDesc->Status & (__FLAG__) == (__FLAG__))
  2. #define __HAL_ETH_DMARXDESC_GET_FLAG(__HANDLE__, __FLAG__)             ((__HANDLE__)->RxDesc->Status & (__FLAG__) == (__FLAG__))
复制代码

==运算符的优先级比&更高
应该是(A & B) == C才对
而不是A & B == C,因为这相当于A & (B == C),显然是不能正常工作的
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版