网站响应式和非响应式,网站做支付接口吗,沧州市,wordpress媒体文件位置0 工具准备
1.野火 stm32f407霸天虎开发板
2.LAN8720数据手册
3.STM32F4xx中文参考手册1 MAC及DMA配置
1.1 使能ETH时钟
stm32的ETH外设挂载在AHB1总线上#xff0c;位于RCC_AHB1ENR的bit25-bit27#xff1a; 相关语句如下#xff1a;
RCC_AHB1PeriphClockCmd(RCC_AHB1…0 工具准备
1.野火 stm32f407霸天虎开发板
2.LAN8720数据手册
3.STM32F4xx中文参考手册1 MAC及DMA配置
1.1 使能ETH时钟
stm32的ETH外设挂载在AHB1总线上位于RCC_AHB1ENR的bit25-bit27 相关语句如下
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |RCC_AHB1Periph_ETH_MAC_Rx,ENABLE);1.2 复位MAC寄存器
直接调用ETH_DeInit函数来复位ETH外设
void ETH_DeInit(void)
{RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_ETH_MAC, ENABLE);RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_ETH_MAC, DISABLE);
}上述语句操作的寄存器如下 首先设置位25为1复位以太网MAC复位MAC寄存器到默认值然后设置为0取消复位。
1.3 复位MAC DMA控制器
首先调用ETH_SoftwareReset函数复位MAC的DMA
void ETH_SoftwareReset(void)
{/* Set the SWR bit: resets all MAC subsystem internal registers and logic *//* After reset all the registers holds their respective reset values */ETH-DMABMR | ETH_DMABMR_SR;
}上述语句操作的寄存器如下 等待MAC DMA控制器软件复位完成
while (ETH_GetSoftwareResetStatus() SET);ETH_GetSoftwareResetStatus函数定义如下
FlagStatus ETH_GetSoftwareResetStatus(void)
{FlagStatus bitstatus RESET;if((ETH-DMABMR ETH_DMABMR_SR) ! (uint32_t)RESET){bitstatus SET;}else{bitstatus RESET;}return bitstatus;
}这里轮询位0的状态当为0值为0时表示复位完成方可以进行接下来的操作。
1.4 配置ETH
由于需要配置的ETH参数非常多大部分参数保持默认即可为了省事首先调用ETH_StructInit函数将ETH参数设置为默认值。语句如下
ETH_StructInit(ETH_InitStructure);ETH_StructInit这个函数实际上就是将ETH_InitStructure这个变量的成员的值全部设置为默认值。 然后我们根据需要修改其中一些参数比较常见的就是开启混杂模式也就是将ETH_InitStructure.ETH_ReceiveAll设置为ETH_ReceiveAll_Enable。 本文使用的配置如下
/* 开启网络自适应功能 */
ETH_InitStructure.ETH_AutoNegotiation ETH_AutoNegotiation_Enable;
/* 关闭反馈 */
ETH_InitStructure.ETH_LoopbackMode ETH_LoopbackMode_Disable;
/* 关闭重传功能 */
ETH_InitStructure.ETH_RetryTransmission ETH_RetryTransmission_Disable;
/* 关闭自动去除PDA/CRC功能 */
ETH_InitStructure.ETH_AutomaticPadCRCStrip ETH_AutomaticPadCRCStrip_Disable;
/* 关闭接收所有的帧 */
ETH_InitStructure.ETH_ReceiveAll ETH_ReceiveAll_Disable;
/* 允许接收所有广播帧 */
ETH_InitStructure.ETH_BroadcastFramesReception ETH_BroadcastFramesReception_Enable;
/* 关闭混合模式的地址过滤 */
ETH_InitStructure.ETH_PromiscuousMode ETH_PromiscuousMode_Disable;
/* 对于组播地址使用完美地址过滤 */
ETH_InitStructure.ETH_MulticastFramesFilter ETH_MulticastFramesFilter_Perfect;
/* 对单播地址使用完美地址过滤 */
ETH_InitStructure.ETH_UnicastFramesFilter ETH_UnicastFramesFilter_Perfect;
/* 开启ipv4和TCP/UDP/ICMP的帧校验和卸载 */
ETH_InitStructure.ETH_ChecksumOffload ETH_ChecksumOffload_Enable;
/* 开启丢弃TCP/IP错误帧 */
ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame ETH_DropTCPIPChecksumErrorFrame_Enable;
/* 开启接收数据的存储转发模式 */
ETH_InitStructure.ETH_ReceiveStoreForward ETH_ReceiveStoreForward_Enable;
/* 开启发送数据的存储转发模式 */
ETH_InitStructure.ETH_TransmitStoreForward ETH_TransmitStoreForward_Enable;
/* 禁止转发错误帧 */
ETH_InitStructure.ETH_ForwardErrorFrames ETH_ForwardErrorFrames_Disable;
/* 不转发过小的好帧 */
ETH_InitStructure.ETH_ForwardUndersizedGoodFrames ETH_ForwardUndersizedGoodFrames_Disable;
/* 打开处理第二帧功能 */
ETH_InitStructure.ETH_SecondFrameOperate ETH_SecondFrameOperate_Enable;
/* 开启DMA传输的地址对齐功能 */
ETH_InitStructure.ETH_AddressAlignedBeats ETH_AddressAlignedBeats_Enable;
/* 开启固定突发功能 */
ETH_InitStructure.ETH_FixedBurst ETH_FixedBurst_Enable;
/* DMA发送的最大突发长度为32个节拍 */
ETH_InitStructure.ETH_RxDMABurstLength ETH_RxDMABurstLength_32Beat;
/*DMA接收的最大突发长度为32个节拍 */
ETH_InitStructure.ETH_TxDMABurstLength ETH_TxDMABurstLength_32Beat;
ETH_InitStructure.ETH_DMAArbitration ETH_DMAArbitration_RoundRobin_RxTx_2_1;最后调用ETH_Init函数初始化ETH即可
EthStatus ETH_Init(ETH_InitStructure, ETHERNET_PHY_ADDRESS);注意参数2是PHY的地址我们使用的PHY地址为0x00。 ETH_Init主要工作就是根据我们设置的ETH参数去配置相应的寄存器。
1.5 配置MAC地址
直接使用ETH_MACAddressConfig函数设置MAC地址即可
uint8_t macAddr[6] {0x00, 0x00, 0x00, 0x14, 0x99, 0x30};
ETH_MACAddressConfig(ETH_MAC_Address0, macAddr);这里要注意参数1的值为0会操作如下寄存器
1.6 配置DMA
1.6.1 DMA描述符介绍
在介绍DMA配置之前需要了解一下STM32的ETH DMA结构 一般来说我们都选择链接结构操作起来更方便一些。提到了ETH DMA就绕不开DMA描述符DMA描述符分为Tx DMA描述符和Rx DMA描述符DMA描述符是纯软件的概念STM32的ETH DMA通过DMA描述符来管理接收、发送的以太网数据。STM32默认使用的是增强型的DMA描述符。 增强型Tx DMA描述符如下 可以看到描述符的大小为48bit这和STM32定义的DMA结构体是一模一样的
typedef struct {__IO uint32_t Status; /*! Status */uint32_t ControlBufferSize; /*! Control and Buffer1, Buffer2 lengths */uint32_t Buffer1Addr; /*! Buffer1 address pointer */uint32_t Buffer2NextDescAddr; /*! Buffer2 or next descriptor address pointer */
/* Enhanced ETHERNET DMA PTP Descriptors */
#ifdef USE_ENHANCED_DMA_DESCRIPTORSuint32_t ExtendedStatus; /* Extended status for PTP receive descriptor */uint32_t Reserved1; /* Reserved */uint32_t TimeStampLow; /* Time Stamp Low value for transmit and receive */uint32_t TimeStampHigh; /* Time Stamp High value for transmit and receive */
#endif /* USE_ENHANCED_DMA_DESCRIPTORS */
} ETH_DMADESCTypeDef;增强型Rx DMA描述符如下 增强型Rx DMA描述符和增强型Tx DMA描述符在组成上是一致的唯一的区别是bit的含义不同。 有人会好奇既然DMA描述符是纯软件的概念那么硬件DMA又是如何找到DMA描述符并使用它完成数据接收、发送操作的呢这里就要提到DMATDLAR、DMARDLAR这两个寄存器这两个寄存器会保存DMA描述符首地址到寄存器这便是联系硬件DMA和软件DMA描述符的桥梁
1.6.2 DMA配置过程
1定义发送、接收DMA描述符及buffer等变量
__align(4)
ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB];/* Ethernet Rx DMA Descriptor 以太网接收DMA描述符 */
__align(4)
ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB];/* Ethernet Tx DMA Descriptor 以太网发送DMA描述符 */
__align(4)
uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; /* Ethernet Receive Buffer 以太网接收Buffer */
__align(4)
uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; /* Ethernet Transmit Buffer 以太网发送Buffer */以上是STM32默认配置的DMA描述符和bufferDMA描述符的数量为4buffer的大小为1524Byte。需要4字节对齐方便DMA的搬运。 之所以定义buffer大小为1524Byte是因为以太网报文最大帧大小为1524Byte计算方法如下
ETH_HEADER ETH_EXTRA VLAN_TAG MAX_ETH_PAYLOAD ETH_CRC其中 ETH_HEADER表示以太网帧头大小为14字节包括6字节目的地址、6字节源地址、2字节帧类型 ETH_EXTRA表示某些情况下的额外字节大小为2字节 VLAN_TAG表示VLAN字段大小为4字节 MAX_ETH_PAYLOA表示以太网帧有效载荷大小为1500字节范围为46-1500字节 ETH_CRC表示CRC校验大小为4字节 我们还需要定义2个DMA描述符指针这个DMA描述符指针主要是给CPU使用的用来指示当前操作到了哪个DMA描述符有点类似于环形buffer的头指针而ETH DMA则是尾指针。定义内容如下
__IO ETH_DMADESCTypeDef *DMATxDescToSet;
__IO ETH_DMADESCTypeDef *DMARxDescToGet;2初始化Tx DMA和Rx DMA描述符
/* Initialize Tx Descriptors list: Chain Mode */ETH_DMATxDescChainInit(DMATxDscrTab, Tx_Buff[0][0], ETH_TXBUFNB);/* Initialize Rx Descriptors list: Chain Mode */ETH_DMARxDescChainInit(DMARxDscrTab, Rx_Buff[0][0], ETH_RXBUFNB);ETH_DMATxDescChainInit和ETH_DMARxDescChainInit这两个函数实际上就是初始化Tx和RxDMA描述符具体工作如下 ①设置每个DMA描述符的状态 ②设置每个DMA描述符的buffer地址 ③设置每个DMA描述符的下一个DMA描述符地址构成链形 ④设置DMA描述符列表地址寄存器的值为首个DMA描述符地址 这里我们开启硬件发送报文校验和功能当我们发送TCP/UDP/ICMP报文时无需使用CPU计算校验和直接让DMA完成即可。语句如下 for(i 0; i ETH_TXBUFNB; i){ETH_DMATxDescChecksumInsertionConfig(DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);}3使能ETH 到此为止MAC和DMA的配置基本完成接下来只需要使能所有相关的外设即可。直接调用ETH_Start函数即可
ETH_Start();这个函数的主要工作就是将相关的寄存器位使能
void ETH_Start(void)
{/* Enable transmit state machine of the MAC for transmission on the MII */ETH_MACTransmissionCmd(ENABLE);/* Enable receive state machine of the MAC for reception from the MII */ETH_MACReceptionCmd(ENABLE);/* Flush Transmit FIFO */ETH_FlushTransmitFIFO();/* Start DMA transmission */ETH_DMATransmissionCmd(ENABLE);/* Start DMA reception */ETH_DMAReceptionCmd(ENABLE);
}这里有个非常有用的函数ETH_FlushTransmitFIFO可以用来清空FIFO。当我们的网口之前残余了一些无用的报文在我们初始化之前将FIFO清空可以避免这些无用报文的干扰。
2 总结
1DMA描述符是个纯软件的概念通过设置DMA描述符地址寄存器来建立DMA和DMA描述符的联系。DMA描述符使用起来和环形buffer类似且一个报文可能存在多个DMA描述符内但一个DMA描述符最多只有一个报文。 2最好将接收、发送buffer大小设置到1524字节这样可以避免拆包便于我们对数据的处理。 3可以使能ETH_InitStructure.ETH_ReceiveAll开启混杂模式这在开发Ethernet层的协议时非常有用。