格式化/tp 发表于 2017-12-20 11:27:44

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

FrameTypeDef ETH_Get_Received_Frame_interrupt(void)这个函数,注释中说的是在接收中断(ETH_GetDMAFlagStatus(ETH_DMA_FLAG_R) == SET)发生的时候调用。因此在lwip的ethernetif.c中的数据包接收函数中调用:
static struct pbuf *low_level_input(struct netif *netif)
{
/* 数据包接收函数 */
//struct ethernetif *ethernetif = netif->state;
struct pbuf *p/*, *q*/;
u16_t len;
FrameTypeDef frame = ETH_Get_Received_Frame_interrupt(); // 获取数据包信息 (代码1)

/*
// 代码(2)
FrameTypeDef frame;
frame.buffer = DMARxDescToGet->Buffer1Addr;
frame.descriptor = DMARxDescToGet;
frame.length = (DMARxDescToGet->Status >> 16) & 0x3fff;
DMARxDescToGet = (ETH_DMADESCTypeDef *)DMARxDescToGet->Buffer2NextDescAddr;
*/

...
}运行时会发现,返回的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
len=350
buffer=0x20000244 descriptor=0 length=60
FS_Rx_Desc=0 LS_Rx_Desc=0 Seg_Count=1
len=60
buffer=0x20000244 descriptor=1 length=60
FS_Rx_Desc=0 LS_Rx_Desc=1 Seg_Count=2
len=60
buffer=0x20000244 descriptor=2 length=60
FS_Rx_Desc=0 LS_Rx_Desc=2 Seg_Count=3
len=60
len=350
buffer=0x20000244 descriptor=3 length=344
FS_Rx_Desc=0 LS_Rx_Desc=3 Seg_Count=4
len=344
buffer=0x20000244 descriptor=4 length=60
FS_Rx_Desc=0 LS_Rx_Desc=4 Seg_Count=5
len=60
buffer=0x20000244 descriptor=0 length=60
FS_Rx_Desc=0 LS_Rx_Desc=0 Seg_Count=6
len=60
buffer=0x20000244 descriptor=1 length=60
FS_Rx_Desc=0 LS_Rx_Desc=1 Seg_Count=7
len=60
len=350
buffer=0x20000244 descriptor=2 length=344
FS_Rx_Desc=0 LS_Rx_Desc=2 Seg_Count=8
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则等于当前缓冲区接收到的数据帧大小。
if (DMA_RX_FRAME_infos->Seg_Count >1)
      {
      frame.buffer =(DMA_RX_FRAME_infos->FS_Rx_Desc)->Buffer1Addr;
      }

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

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

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

格式化/tp 发表于 2017-12-20 11:35:35

之前一直以为是ETH_Init()或者是数据包发送函数的问题
一一排除之后,才知道是接收函数有问题

MrJiu 发表于 2017-12-20 14:35:58

赶紧移植到hal库,官方主推的啦!!!

格式化/tp 发表于 2020-4-19 23:59:59

HAL库的HAL_ETH_GetReceivedFrame仍然有这个问题,所以STM32CubeMX生成的代码中有这样一句话:heth.RxFrameInfos.SegCount = 0

格式化/tp 发表于 2020-4-20 00:04:05

HAL库里面的下面两个宏的实现也有问题:
#define __HAL_ETH_DMATXDESC_GET_FLAG(__HANDLE__, __FLAG__)             ((__HANDLE__)->TxDesc->Status & (__FLAG__) == (__FLAG__))
#define __HAL_ETH_DMARXDESC_GET_FLAG(__HANDLE__, __FLAG__)             ((__HANDLE__)->RxDesc->Status & (__FLAG__) == (__FLAG__))
==运算符的优先级比&更高
应该是(A & B) == C才对
而不是A & B == C,因为这相当于A & (B == C),显然是不能正常工作的
页: [1]
查看完整版本: 发现STM32F2/F4 ETH标准库函数ETH_Get_Received_Frame_interrupt的重大....