0 工具準備
1.野火 stm32f407霸天虎開發(fā)板
2.LAN8720數(shù)據(jù)手冊
3.STM32F4xx中文參考手冊
1 MAC及DMA配置
1.1 使能ETH時鐘
stm32的ETH外設(shè)掛載在AHB1總線上,位于RCC_AHB1ENR的bit25-bit27:
相關(guān)語句如下:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |
RCC_AHB1Periph_ETH_MAC_Rx,
ENABLE);
1.2 復位MAC寄存器
直接調(diào)用ETH_DeInit函數(shù)來復位ETH外設(shè)
void ETH_DeInit(void)
{
RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_ETH_MAC, ENABLE);
RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_ETH_MAC, DISABLE);
}
上述語句操作的寄存器如下:
首先設(shè)置位25為1復位以太網(wǎng)MAC(復位MAC寄存器到默認值),然后設(shè)置為0取消復位。
1.3 復位MAC DMA控制器
首先調(diào)用ETH_SoftwareReset函數(shù)復位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函數(shù)定義如下:
FlagStatus ETH_GetSoftwareResetStatus(void)
{
FlagStatus bitstatus = RESET;
if((ETH->DMABMR & ETH_DMABMR_SR) != (uint32_t)RESET)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
return bitstatus;
}
這里輪詢位0的狀態(tài),當為0值為0時表示復位完成,方可以進行接下來的操作。
1.4 配置ETH
由于需要配置的ETH參數(shù)非常多,大部分參數(shù)保持默認即可,為了省事首先調(diào)用ETH_StructInit函數(shù)將ETH參數(shù)設(shè)置為默認值。語句如下:
ETH_StructInit(Ð_InitStructure);
ETH_StructInit這個函數(shù)實際上就是將ETH_InitStructure這個變量的成員的值全部設(shè)置為默認值。
然后我們根據(jù)需要修改其中一些參數(shù),比較常見的就是開啟混雜模式,也就是將ETH_InitStructure.ETH_ReceiveAll設(shè)置為ETH_ReceiveAll_Enable。
本文使用的配置如下:
/* 開啟網(wǎng)絡(luò)自適應(yīng)功能 */
ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;
/* 關(guān)閉反饋 */
ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
/* 關(guān)閉重傳功能 */
ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
/* 關(guān)閉自動去除PDA/CRC功能 */
ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
/* 關(guān)閉接收所有的幀 */
ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;
/* 允許接收所有廣播幀 */
ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;
/* 關(guān)閉混合模式的地址過濾 */
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;
/* 開啟接收數(shù)據(jù)的存儲轉(zhuǎn)發(fā)模式 */
ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;
/* 開啟發(fā)送數(shù)據(jù)的存儲轉(zhuǎn)發(fā)模式 */
ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;
/* 禁止轉(zhuǎn)發(fā)錯誤幀 */
ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;
/* 不轉(zhuǎn)發(fā)過小的好幀 */
ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;
/* 打開處理第二幀功能 */
ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;
/* 開啟DMA傳輸?shù)牡刂穼R功能 */
ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;
/* 開啟固定突發(fā)功能 */
ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;
/* DMA發(fā)送的最大突發(fā)長度為32個節(jié)拍 */
ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;
/*DMA接收的最大突發(fā)長度為32個節(jié)拍 */
ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;
ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;
最后調(diào)用ETH_Init函數(shù)初始化ETH即可:
EthStatus = ETH_Init(Ð_InitStructure, ETHERNET_PHY_ADDRESS);
注意,參數(shù)2是PHY的地址,我們使用的PHY地址為0x00。
ETH_Init主要工作就是根據(jù)我們設(shè)置的ETH參數(shù)去配置相應(yīng)的寄存器。
1.5 配置MAC地址
直接使用ETH_MACAddressConfig函數(shù)設(shè)置MAC地址即可:
uint8_t macAddr[6] = {0x00, 0x00, 0x00, 0x14, 0x99, 0x30};
ETH_MACAddressConfig(ETH_MAC_Address0, macAddr);
這里要注意,參數(shù)1的值為0,會操作如下寄存器:
1.6 配置DMA
1.6.1 DMA描述符介紹
在介紹DMA配置之前,需要了解一下STM32的ETH DMA結(jié)構(gòu):
一般來說我們都選擇鏈接結(jié)構(gòu),操作起來更方便一些。提到了ETH DMA就繞不開DMA描述符,DMA描述符分為Tx DMA描述符和Rx DMA描述符,DMA描述符是純軟件的概念,STM32的ETH DMA通過DMA描述符來管理接收、發(fā)送的以太網(wǎng)數(shù)據(jù)。STM32默認使用的是增強型的DMA描述符。
增強型Tx DMA描述符如下:
可以看到描述符的大小為48bit,這和STM32定義的DMA結(jié)構(gòu)體是一模一樣的:
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_DESCRIPTORS
uint32_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描述符在組成上是一致的,唯一的區(qū)別是bit的含義不同。
有人會好奇,既然DMA描述符是純軟件的概念,那么硬件DMA又是如何找到DMA描述符并使用它完成數(shù)據(jù)接收、發(fā)送操作的呢?這里就要提到DMATDLAR、DMARDLAR這兩個寄存器,這兩個寄存器會保存DMA描述符首地址到寄存器,這便是聯(lián)系硬件DMA和軟件DMA描述符的橋梁:
1.6.2 DMA配置過程
(1)定義發(fā)送、接收DMA描述符及buffer等變量
__align(4)
ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB];/* Ethernet Rx DMA Descriptor 以太網(wǎng)接收DMA描述符 */
__align(4)
ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB];/* Ethernet Tx DMA Descriptor 以太網(wǎng)發(fā)送DMA描述符 */
__align(4)
uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; /* Ethernet Receive Buffer 以太網(wǎng)接收Buffer */
__align(4)
uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; /* Ethernet Transmit Buffer 以太網(wǎng)發(fā)送Buffer */
以上是STM32默認配置的DMA描述符和buffer,DMA描述符的數(shù)量為4,buffer的大小為1524Byte。需要4字節(jié)對齊,方便DMA的搬運。
之所以定義buffer大小為1524Byte,是因為以太網(wǎng)報文最大幀大小為1524Byte,計算方法如下:
ETH_HEADER + ETH_EXTRA + VLAN_TAG + MAX_ETH_PAYLOAD + ETH_CRC
其中,
ETH_HEADER表示以太網(wǎng)幀頭,大小為14字節(jié),包括6字節(jié)目的地址、6字節(jié)源地址、2字節(jié)幀類型
ETH_EXTRA表示某些情況下的額外字節(jié),大小為2字節(jié)
VLAN_TAG表示VLAN字段,大小為4字節(jié)
MAX_ETH_PAYLOA表示以太網(wǎng)幀有效載荷,大小為1500字節(jié)(范圍為46-1500字節(jié))
ETH_CRC表示CRC校驗,大小為4字節(jié)
我們還需要定義2個DMA描述符指針,這個DMA描述符指針主要是給CPU使用的,用來指示當前操作到了哪個DMA描述符,有點類似于環(huán)形buffer的頭指針,而ETH DMA則是尾指針。定義內(nèi)容如下:
__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這兩個函數(shù)實際上就是初始化Tx和RxDMA描述符,具體工作如下:
①設(shè)置每個DMA描述符的狀態(tài)
②設(shè)置每個DMA描述符的buffer地址
③設(shè)置每個DMA描述符的下一個DMA描述符地址(構(gòu)成鏈形)
④設(shè)置DMA描述符列表地址寄存器的值為首個DMA描述符地址
這里我們開啟硬件發(fā)送報文校驗和功能,當我們發(fā)送TCP/UDP/ICMP報文時無需使用CPU計算校驗和,直接讓DMA完成即可。語句如下:
for(i = 0; i < ETH_TXBUFNB; i++)
{
ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
}
(3)使能ETH
到此為止,MAC和DMA的配置基本完成,接下來只需要使能所有相關(guān)的外設(shè)即可。直接調(diào)用ETH_Start函數(shù)即可:
ETH_Start();
這個函數(shù)的主要工作就是將相關(guān)的寄存器位使能:
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);
}
這里有個非常有用的函數(shù)ETH_FlushTransmitFIFO,可以用來清空FIFO。當我們的網(wǎng)口之前殘余了一些無用的報文,在我們初始化之前將FIFO清空可以避免這些無用報文的干擾。文章來源:http://www.zghlxwxcb.cn/news/detail-777624.html
2 總結(jié)
(1)DMA描述符是個純軟件的概念,通過設(shè)置DMA描述符地址寄存器來建立DMA和DMA描述符的聯(lián)系。DMA描述符使用起來和環(huán)形buffer類似,且一個報文可能存在多個DMA描述符內(nèi),但一個DMA描述符最多只有一個報文。
(2)最好將接收、發(fā)送buffer大小設(shè)置到1524字節(jié),這樣可以避免拆包,便于我們對數(shù)據(jù)的處理。
(3)可以使能ETH_InitStructure.ETH_ReceiveAll開啟混雜模式,這在開發(fā)Ethernet層的協(xié)議時非常有用。文章來源地址http://www.zghlxwxcb.cn/news/detail-777624.html
到了這里,關(guān)于STM32的以太網(wǎng)外設(shè)+PHY(LAN8720)使用詳解(5):MAC及DMA配置的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!