STM32H5 HAL库LWIP裸机移植指南:含源代码,轻松实现一文搞定
本博客使用的是STM32H563型号MUC。该型号在CubeMX中目前还不支持直接生成LWIP协议(2024.7.20),所以,需要在官网找到LWIP中间件及驱动(LAN8720A)手动移植。
PHY芯片型号: LAN8720A
目录
STM32H563通过CubeMX 移植LWIP
CubeMX ETH配置
下载LWIP移植文件
移植LWIP 源文件
移植头文件
移植完成后的问题:
STM32H563通过CubeMX 移植LWIP
使用CubeMX,配置ETH外设(以太网(Ethernet)接口)
CubeMX创建STM32H563工程步骤省略……
CubeMX ETH配置
首先根据自己的需求配置:调试器接口以及时钟
使能ETH(选择的RMII模式)
配置ETH引脚复用
复位引脚设置(查看原理图 LAN8720ANRST引脚接了MCU哪个引脚):
根据自己需求配置时钟
生成项目
下载LWIP移植文件
打开网站 点击Download(下载)按钮
lwIP – A Lightweight TCP/IP stack – Summary [Savannah] (nongnu.org)
下载文件
将文件解压 移植之前先要了解文件中的内容
打开lwip文件
src源码文件
打开contrib文件
移植LWIP 源文件
现在开始移植
lwip文件
将lwip源码(src文件夹)添加到文件中
工程文件
添加工程分组
创建分组存放lwip源码
每个分组中都添加对应的源文件
对应源码 (src文件夹文件)添加到对应工程分组中
lwip/api文件
lwip/core文件
再点击ipv4文件夹 将文件夹下的所有文件添加
lwip/netif分组 (ppp文件夹内文件不需要添加)
添加工程中所需要的头文件路径
移植头文件
我们的工程基本就添加完成了,但想要lwip跑起来,还需要一些头文件的支持(lwip的配置文件 )
在源文件(src)文件夹中 创建arch文件夹
打开contrib文件夹
将\contrib-2.1.0\examples\example_app路径下的lwipopts.h文件拷贝到.\src\arch文件夹中
再将.\contrib-2.1.0\ports\unix\port\include\arch路径下的cc.h及perf.h文件拷贝到.\src\arch文件夹下
.\src\arch文件夹下文件
再将.\src\arch文件夹下的所有文件添加到组
打开lwipopts.h 并在文件内 根据自己需求配置
下列源代码中没有配置的参数在opt.h中有默认配置 如需改变默认配置参数 在该文件中使用宏定义直接配置即可
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__
/**
* SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
* critical regions during buffer allocation, deallocation and memory
* allocation and deallocation.
*/
#define SYS_LIGHTWEIGHT_PROT 0
/**
* NO_SYS==1: Provides VERY minimal functionality. Otherwise,
* use lwIP facilities.
*/
#define NO_SYS 1
/* ---------- Memory options ---------- */
/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
byte alignment -> define MEM_ALIGNMENT to 2. */
#define MEM_ALIGNMENT 4
/* MEM_SIZE: the size of the heap memory. If the application will send
a lot of data that needs to be copied, this should be set high. */
#define MEM_SIZE (14*1024)
/* Relocate the LwIP RAM heap pointer */
#define LWIP_RAM_HEAP_POINTER (0x20084000)
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
connections. */
#define MEMP_NUM_TCP_PCB 10
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
segments. */
#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN
/* ---------- Pbuf options ---------- */
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool */
#define PBUF_POOL_BUFSIZE 1536
/* LWIP_SUPPORT_CUSTOM_PBUF == 1: to pass directly MAC Rx buffers to the stack
no copy is needed */
#define LWIP_SUPPORT_CUSTOM_PBUF 1
/*
------------------------------------------------
---------- Network Interfaces options ----------
------------------------------------------------
*/
#define LWIP_NETIF_LINK_CALLBACK 1
/* ---------- TCP options ---------- */
#define LWIP_TCP 1
#define TCP_TTL 255
/* TCP Maximum segment size. */
#define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */
/* TCP sender buffer space (bytes). */
#define TCP_SND_BUF (4*TCP_MSS)
/* TCP receive window. */
#define TCP_WND (4*TCP_MSS)
/* ---------- ICMP options ---------- */
#define LWIP_ICMP 1
/* ---------- DHCP options ---------- */
#define LWIP_DHCP 0
/* ---------- UDP options ---------- */
#define LWIP_UDP 1
#define UDP_TTL 255
/* ---------- Statistics options ---------- */
#define LWIP_STATS 0
/*
--------------------------------------
---------- Checksum options ----------
--------------------------------------
*/
/*
The STM32H7xx allows computing and verifying the IP, UDP, TCP and ICMP checksums by hardware:
- To use this feature let the following define uncommented.
- To disable it and process by CPU comment the the checksum.
*/
#define CHECKSUM_BY_HARDWARE
#ifdef CHECKSUM_BY_HARDWARE
/* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/
#define CHECKSUM_GEN_IP 0
/* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP 0
/* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP 0
/* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/
#define CHECKSUM_CHECK_IP 0
/* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP 0
/* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP 0
/* CHECKSUM_GEN_ICMP==1: Check checksums by hardware for outgoing ICMP packets.*/
/* Hardware TCP/UDP checksum insertion not supported when packet is an IPv4 fragment*/
#define CHECKSUM_GEN_ICMP 1
/* CHECKSUM_CHECK_ICMP==0: Check checksums by hardware for incoming ICMP packets.*/
#define CHECKSUM_CHECK_ICMP 0
#else
/* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/
#define CHECKSUM_GEN_IP 1
/* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP 1
/* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP 1
/* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/
#define CHECKSUM_CHECK_IP 1
/* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP 1
/* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP 1
/* CHECKSUM_GEN_ICMP==1: Check checksums by hardware for outgoing ICMP packets.*/
#define CHECKSUM_GEN_ICMP 1
/* CHECKSUM_CHECK_ICMP==1: Check checksums by hardware for incoming ICMP packets.*/
#define CHECKSUM_CHECK_ICMP 1
#endif
/*
----------------------------------------------
---------- Sequential layer options ----------
----------------------------------------------
*/
/**
* LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
*/
#define LWIP_NETCONN 0
/*
------------------------------------
---------- Socket options ----------
------------------------------------
*/
/**
* LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
*/
#define LWIP_SOCKET 0
#endif /* __LWIPOPTS_H__ */
NO_SYS 表示无操作系统模拟层,这个宏非常重要, 因为无操作系统与有操作系统的移植和编写是完全不一样的, 我们现在是无操作系统移植,所以将这个宏定义为1。
MEM_ALIGNMENT 内存对齐,按照4字节对齐。
MEM_SIZE 堆内存的大小。PBUF_POOL_BUFSIZE PBUF_POOL内存池中每个内存块大小。
TCP_MSS TCP协议报文最大长度。
TCP_WND TCP接收窗口大小。
LWIP_SOCKET 因为现在是无操作系统,就不使能NETCONN API和Socket API编程。
LWIP_NETCONN 因为现在是无操作系统,就不使能NETCONN API和Socket API编程。
cc.h文件
cc.h文件定义大小端模式,输出调试的宏等
#ifndef __CC_H__
#define __CC_H__
#include "cpu.h"
#include <stdlib.h>
#include <stdio.h>
typedef int sys_prot_t;
#define LWIP_PROVIDE_ERRNO
#if defined (__GNUC__) & !defined (__CC_ARM)
#define LWIP_TIMEVAL_PRIVATE 0
//#include <sys/time.h>
#endif
/* define compiler specific symbols */
#if defined (__ICCARM__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES
#elif defined (__GNUC__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#elif defined (__CC_ARM)
#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#elif defined (__TASKING__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#endif
#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \
x, __LINE__, __FILE__); } while(0)
/* Define random number generator function */
#define LWIP_RAND() ((u32_t)rand())
#endif /* __CC_H__ */
perf.h文件是与系统统计与测量相关的头文件,我们暂时无需使用任何统计与测量功能,因此该头文件的量宏定义直接为空即可
#ifndef __PERF_H__
#define __PERF_H__
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */
#endif /* __PERF_H__ */
再将以下文件按原步骤添加到lwip/arch中
ethernetif.c文件
底层驱动的函数,LwIP的contrib包中就包含这个文件的模板,我们直接拿过来修改即可。
也可直接复制以下源代码
/* Includes ------------------------------------------------------------------*/
#include "stm32h5xx_hal.h"
#include "lwip/opt.h"
#include "lwip/timeouts.h"
#include "lwip/netif.h"
#include "netif/etharp.h"
#include "ethernetif.h"
#include "lan8742.h"
#include <string.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Network interface name */
#define IFNAME0 's'
#define IFNAME1 't'
#define ETH_DMA_TRANSMIT_TIMEOUT (20U)
#define ETH_RX_BUFFER_SIZE 1524U
#define ETH_RX_BUFFER_CNT 12U
#define ETH_TX_BUFFER_MAX ((ETH_TX_DESC_CNT) * 2U)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/*
@Note: This interface is implemented to operate in zero-copy mode only:
- Rx Buffers will be allocated from LwIP stack memory heap,
then passed to ETH HAL driver.
- Tx Buffers will be allocated from LwIP stack memory heap,
then passed to ETH HAL driver.
@Notes:
1.a. ETH DMA Rx descriptors must be contiguous, the default count is 4,
to customize it please redefine ETH_RX_DESC_CNT in ETH GUI (Rx Descriptor Length)
so that updated value will be generated in stm32xxxx_hal_conf.h
1.b. ETH DMA Tx descriptors must be contiguous, the default count is 4,
to customize it please redefine ETH_TX_DESC_CNT in ETH GUI (Tx Descriptor Length)
so that updated value will be generated in stm32xxxx_hal_conf.h
2.a. Rx Buffers number: ETH_RX_BUFFER_CNT must be greater than ETH_RX_DESC_CNT.
2.b. Rx Buffers must have the same size: ETH_RX_BUFFER_SIZE, this value must
passed to ETH DMA in the init field (heth.Init.RxBuffLen)
*/
typedef enum
{
RX_ALLOC_OK = 0x00,
RX_ALLOC_ERROR = 0x01
} RxAllocStatusTypeDef;
typedef struct
{
struct pbuf_custom pbuf_custom;
uint8_t buff[(ETH_RX_BUFFER_SIZE + 31) & ~31] __ALIGNED(32);
} RxBuff_t;
ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
extern u8_t memp_memory_RX_POOL_base[];
/* Variable Definitions */
LWIP_MEMPOOL_DECLARE(RX_POOL, ETH_RX_BUFFER_CNT, sizeof(RxBuff_t), "Zero-copy RX PBUF pool");
static uint8_t RxAllocStatus;
/* Global Ethernet handle*/
ETH_HandleTypeDef EthHandle;
ETH_TxPacketConfig TxConfig;
/* Private function prototypes -----------------------------------------------*/
u32_t sys_now(void);
int32_t ETH_PHY_IO_Init(void);
int32_t ETH_PHY_IO_DeInit (void);
int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal);
int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal);
int32_t ETH_PHY_IO_GetTick(void);
lan8742_Object_t LAN8742;
lan8742_IOCtx_t LAN8742_IOCtx = {ETH_PHY_IO_Init,
ETH_PHY_IO_DeInit,
ETH_PHY_IO_WriteReg,
ETH_PHY_IO_ReadReg,
ETH_PHY_IO_GetTick};
/* Private functions ---------------------------------------------------------*/
void pbuf_free_custom(struct pbuf *p);
/*******************************************************************************
LL Driver Interface ( LwIP stack --> ETH)
*******************************************************************************/
/**
* @brief In this function, the hardware should be initialized.
* Called from ethernetif_init().
*
* @param netif the already initialized lwip network interface structure
* for this ethernetif
*/
static void low_level_init(struct netif *netif)
{
uint8_t macaddress[6];
macaddress[0] = 0x00;
macaddress[1] = 0x80;
macaddress[2] = 0xE1;
macaddress[3] = 0x00;
macaddress[4] = 0x00;
macaddress[5] = 0x00;
EthHandle.Instance = ETH;
EthHandle.Init.MACAddr = &macaddress[0];
EthHandle.Init.MediaInterface = HAL_ETH_RMII_MODE;
EthHandle.Init.RxDesc = DMARxDscrTab;
EthHandle.Init.TxDesc = DMATxDscrTab;
EthHandle.Init.RxBuffLen = ETH_RX_BUFFER_SIZE;
/* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */
HAL_ETH_Init(&EthHandle);
/* set MAC hardware address length */
netif->hwaddr_len = ETH_HWADDR_LEN;
/* set MAC hardware address */
netif->hwaddr[0] = EthHandle.Init.MACAddr[0];
netif->hwaddr[1] = EthHandle.Init.MACAddr[1];
netif->hwaddr[2] = EthHandle.Init.MACAddr[2];
netif->hwaddr[3] = EthHandle.Init.MACAddr[3];
netif->hwaddr[4] = EthHandle.Init.MACAddr[4];
netif->hwaddr[5] = EthHandle.Init.MACAddr[5];
/* maximum transfer unit */
netif->mtu = ETH_MAX_PAYLOAD;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
/* Initialize the RX POOL */
LWIP_MEMPOOL_INIT(RX_POOL);
/* Set Tx packet config common parameters */
memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig));
TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
/* Set PHY IO functions */
LAN8742_RegisterBusIO(&LAN8742, &LAN8742_IOCtx);
/* Initialize the LAN8742 ETH PHY */
LAN8742_Init(&LAN8742);
ethernet_link_check_state(netif);
}
/**
* @brief This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
* @param netif the lwip network interface structure for this ethernetif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
* an err_t value if the packet couldn't be sent
*
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
* strange results. You might consider waiting for space in the DMA queue
* to become available since the stack doesn't retry to send a packet
* dropped because of memory failure (except for the TCP timers).
*/
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
uint32_t i = 0U;
struct pbuf *q = NULL;
err_t errval = ERR_OK;
ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT] = {0};
memset(Txbuffer, 0 , ETH_TX_DESC_CNT*sizeof(ETH_BufferTypeDef));
for(q = p; q != NULL; q = q->next)
{
if(i >= ETH_TX_DESC_CNT)
return ERR_IF;
Txbuffer[i].buffer = q->payload;
Txbuffer[i].len = q->len;
if(i>0)
{
Txbuffer[i-1].next = &Txbuffer[i];
}
if(q->next == NULL)
{
Txbuffer[i].next = NULL;
}
i++;
}
TxConfig.Length = p->tot_len;
TxConfig.TxBuffer = Txbuffer;
TxConfig.pData = p;
HAL_ETH_Transmit(&EthHandle, &TxConfig, ETH_DMA_TRANSMIT_TIMEOUT);
return errval;
}
/**
* @brief Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
* @param netif the lwip network interface structure for this ethernetif
* @return a pbuf filled with the received packet (including MAC header)
* NULL on memory error
*/
static struct pbuf * low_level_input(struct netif *netif)
{
struct pbuf *p = NULL;
if(RxAllocStatus == RX_ALLOC_OK)
{
HAL_ETH_ReadData(&EthHandle, (void **)&p);
}
return p;
}
/**
* @brief This function is the ethernetif_input task, it is processed when a packet
* is ready to be read from the interface. It uses the function low_level_input()
* that should handle the actual reception of bytes from the network
* interface. Then the type of the received packet is determined and
* the appropriate input function is called.
*
* @param netif the lwip network interface structure for this ethernetif
*/
void ethernetif_input(struct netif *netif)
{
struct pbuf *p = NULL;
do
{
p = low_level_input( netif );
if (p != NULL)
{
if (netif->input( p, netif) != ERR_OK )
{
pbuf_free(p);
}
}
} while(p!=NULL);
}
/**
* @brief Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
* This function should be passed as a parameter to netif_add().
*
* @param netif the lwip network interface structure for this ethernetif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other err_t on error
*/
err_t ethernetif_init(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", (netif != NULL));
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
/* We directly use etharp_output() here to save a function call.
* You can instead declare your own function an call etharp_output()
* from it if you have to do some checks before sending (e.g. if link
* is available...) */
netif->output = etharp_output;
netif->linkoutput = low_level_output;
/* initialize the hardware */
low_level_init(netif);
return ERR_OK;
}
/**
* @brief Custom Rx pbuf free callback
* @param pbuf: pbuf to be freed
* @retval None
*/
void pbuf_free_custom(struct pbuf *p)
{
struct pbuf_custom* custom_pbuf = (struct pbuf_custom*)p;
LWIP_MEMPOOL_FREE(RX_POOL, custom_pbuf);
/* If the Rx Buffer Pool was exhausted, signal the ethernetif_input task to
* call HAL_ETH_GetRxDataBuffer to rebuild the Rx descriptors. */
if (RxAllocStatus == RX_ALLOC_ERROR)
{
RxAllocStatus = RX_ALLOC_OK;
}
}
/**
* @brief Returns the current time in milliseconds
* when LWIP_TIMERS == 1 and NO_SYS == 1
* @param None
* @retval Current Time value
*/
u32_t sys_now(void)
{
return HAL_GetTick();
}
/*******************************************************************************
Ethernet MSP Routines
*******************************************************************************/
/**
* @brief Initializes the ETH MSP.
* @param ethHandle: ETH handle
* @retval None
*/
void HAL_ETH_MspInit(ETH_HandleTypeDef* ethHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(ethHandle->Instance==ETH)
{
/* USER CODE BEGIN ETH_MspInit 0 */
/* USER CODE END ETH_MspInit 0 */
/* ETH clock enable */
__HAL_RCC_ETH_CLK_ENABLE();
__HAL_RCC_ETHTX_CLK_ENABLE();
__HAL_RCC_ETHRX_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**ETH GPIO Configuration
PC1 ------> ETH_MDC
PA1 ------> ETH_REF_CLK
PA2 ------> ETH_MDIO
PA5 ------> ETH_TX_EN
PA7 ------> ETH_CRS_DV
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
PB12 ------> ETH_TXD0
PB15 ------> ETH_TXD1
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_5|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN ETH_MspInit 1 */
/* USER CODE END ETH_MspInit 1 */
}
}
void HAL_ETH_MspDeInit(ETH_HandleTypeDef* ethHandle)
{
if(ethHandle->Instance==ETH)
{
/* USER CODE BEGIN ETH_MspDeInit 0 */
/* USER CODE END ETH_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_ETH_CLK_DISABLE();
__HAL_RCC_ETHTX_CLK_DISABLE();
__HAL_RCC_ETHRX_CLK_DISABLE();
/**ETH GPIO Configuration
PC1 ------> ETH_MDC
PA1 ------> ETH_REF_CLK
PA2 ------> ETH_MDIO
PA5 ------> ETH_TX_EN
PA7 ------> ETH_CRS_DV
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
PB12 ------> ETH_TXD0
PB15 ------> ETH_TXD1
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5);
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_5|GPIO_PIN_7);
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_12|GPIO_PIN_15);
/* USER CODE BEGIN ETH_MspDeInit 1 */
/* USER CODE END ETH_MspDeInit 1 */
}
}
/*******************************************************************************
PHI IO Functions
*******************************************************************************/
/**
* @brief Initializes the MDIO interface GPIO and clocks.
* @param None
* @retval 0 if OK, -1 if ERROR
*/
int32_t ETH_PHY_IO_Init(void)
{
/* We assume that MDIO GPIO configuration is already done
in the ETH_MspInit() else it should be done here
*/
/* Configure the MDIO Clock */
HAL_ETH_SetMDIOClockRange(&EthHandle);
return 0;
}
/**
* @brief De-Initializes the MDIO interface .
* @param None
* @retval 0 if OK, -1 if ERROR
*/
int32_t ETH_PHY_IO_DeInit (void)
{
return 0;
}
/**
* @brief Read a PHY register through the MDIO interface.
* @param DevAddr: PHY port address
* @param RegAddr: PHY register address
* @param pRegVal: pointer to hold the register value
* @retval 0 if OK -1 if Error
*/
int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal)
{
if(HAL_ETH_ReadPHYRegister(&EthHandle, DevAddr, RegAddr, pRegVal) != HAL_OK)
{
return -1;
}
return 0;
}
/**
* @brief Write a value to a PHY register through the MDIO interface.
* @param DevAddr: PHY port address
* @param RegAddr: PHY register address
* @param RegVal: Value to be written
* @retval 0 if OK -1 if Error
*/
int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal)
{
if(HAL_ETH_WritePHYRegister(&EthHandle, DevAddr, RegAddr, RegVal) != HAL_OK)
{
return -1;
}
return 0;
}
/**
* @brief Get the time in millisecons used for internal PHY driver process.
* @retval Time value
*/
int32_t ETH_PHY_IO_GetTick(void)
{
return HAL_GetTick();
}
/**
* @brief
* @retval None
*/
void ethernet_link_check_state(struct netif *netif)
{
ETH_MACConfigTypeDef MACConf = {0};
int32_t PHYLinkState = 0U;
uint32_t linkchanged = 0U, speed = 0U, duplex =0U;
PHYLinkState = LAN8742_GetLinkState(&LAN8742);
if(netif_is_link_up(netif) && (PHYLinkState <= LAN8742_STATUS_LINK_DOWN))
{
HAL_ETH_Stop(&EthHandle);
netif_set_down(netif);
netif_set_link_down(netif);
}
else if(!netif_is_link_up(netif) && (PHYLinkState > LAN8742_STATUS_LINK_DOWN))
{
switch (PHYLinkState)
{
case LAN8742_STATUS_100MBITS_FULLDUPLEX:
duplex = ETH_FULLDUPLEX_MODE;
speed = ETH_SPEED_100M;
linkchanged = 1;
break;
case LAN8742_STATUS_100MBITS_HALFDUPLEX:
duplex = ETH_HALFDUPLEX_MODE;
speed = ETH_SPEED_100M;
linkchanged = 1;
break;
case LAN8742_STATUS_10MBITS_FULLDUPLEX:
duplex = ETH_FULLDUPLEX_MODE;
speed = ETH_SPEED_10M;
linkchanged = 1;
break;
case LAN8742_STATUS_10MBITS_HALFDUPLEX:
duplex = ETH_HALFDUPLEX_MODE;
speed = ETH_SPEED_10M;
linkchanged = 1;
break;
default:
break;
}
if(linkchanged)
{
/* Get MAC Config MAC */
HAL_ETH_GetMACConfig(&EthHandle, &MACConf);
MACConf.DuplexMode = duplex;
MACConf.Speed = speed;
HAL_ETH_SetMACConfig(&EthHandle, &MACConf);
HAL_ETH_Start(&EthHandle);
netif_set_up(netif);
netif_set_link_up(netif);
}
}
}
void HAL_ETH_RxAllocateCallback(uint8_t **buff)
{
struct pbuf_custom *p = LWIP_MEMPOOL_ALLOC(RX_POOL);
if (p)
{
/* Get the buff from the struct pbuf address. */
*buff = (uint8_t *)p + offsetof(RxBuff_t, buff);
p->custom_free_function = pbuf_free_custom;
/* Initialize the struct pbuf.
* This must be performed whenever a buffer's allocated because it may be
* changed by lwIP or the app, e.g., pbuf_free decrements ref. */
pbuf_alloced_custom(PBUF_RAW, 0, PBUF_REF, p, *buff, ETH_RX_BUFFER_SIZE);
}
else
{
RxAllocStatus = RX_ALLOC_ERROR;
*buff = NULL;
}
}
void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length)
{
struct pbuf **ppStart = (struct pbuf **)pStart;
struct pbuf **ppEnd = (struct pbuf **)pEnd;
struct pbuf *p = NULL;
/* Get the struct pbuf from the buff address. */
p = (struct pbuf *)(buff - offsetof(RxBuff_t, buff));
p->next = NULL;
p->tot_len = 0;
p->len = Length;
/* Chain the buffer. */
if (!*ppStart)
{
/* The first buffer of the packet. */
*ppStart = p;
}
else
{
/* Chain the buffer to the end of the packet. */
(*ppEnd)->next = p;
}
*ppEnd = p;
/* Update the total length of all the buffers of the chain. Each pbuf in the chain should have its tot_len
* set to its own length, plus the length of all the following pbufs in the chain. */
for (p = *ppStart; p != NULL; p = p->next)
{
p->tot_len += Length;
}
/* Invalidate data cache because Rx DMA's writing to physical memory makes it stale. */
}
void HAL_ETH_TxFreeCallback(uint32_t * buff)
{
pbuf_free((struct pbuf *)buff);
}
创建文件 并添加到工程分组中
ethernetif.h文件
#ifndef __ETHERNETIF_H__
#define __ETHERNETIF_H__
#include "lwip/err.h"
#include "lwip/netif.h"
#define ETH_RST_GPIO_Port GPIOC
#define ETH_RST_Pin GPIO_PIN_0
/* Exported types ------------------------------------------------------------*/
err_t ethernetif_init(struct netif *netif);
void ethernetif_input(struct netif *netif);
void ethernet_link_check_state(struct netif *netif);
#endif
创建lan8742.c文件
#include "lan8742.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup LAN8742_Private_Defines LAN8742 Private Defines
* @{
*/
#define LAN8742_SW_RESET_TO ((uint32_t)500U)
#define LAN8742_INIT_TO ((uint32_t)2000U)
#define LAN8742_MAX_DEV_ADDR ((uint32_t)31U)
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup LAN8742_Private_Functions LAN8742 Private Functions
* @{
*/
/**
* @brief Register IO functions to component object
* @param pObj: device object of LAN8742_Object_t.
* @param ioctx: holds device IO functions.
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_ERROR if missing mandatory function
*/
int32_t LAN8742_RegisterBusIO(lan8742_Object_t *pObj, lan8742_IOCtx_t *ioctx)
{
if(!pObj || !ioctx->ReadReg || !ioctx->WriteReg || !ioctx->GetTick)
{
return LAN8742_STATUS_ERROR;
}
pObj->IO.Init = ioctx->Init;
pObj->IO.DeInit = ioctx->DeInit;
pObj->IO.ReadReg = ioctx->ReadReg;
pObj->IO.WriteReg = ioctx->WriteReg;
pObj->IO.GetTick = ioctx->GetTick;
return LAN8742_STATUS_OK;
}
/**
* @brief Initialize the lan8742 and configure the needed hardware resources
* @param pObj: device object LAN8742_Object_t.
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_ADDRESS_ERROR if cannot find device address
* LAN8742_STATUS_READ_ERROR if connot read register
* LAN8742_STATUS_WRITE_ERROR if connot write to register
* LAN8742_STATUS_RESET_TIMEOUT if cannot perform a software reset
*/
int32_t LAN8742_Init(lan8742_Object_t *pObj)
{
uint32_t tickstart = 0, regvalue = 0, addr = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->Is_Initialized == 0)
{
if(pObj->IO.Init != 0)
{
/* GPIO and Clocks initialization */
pObj->IO.Init();
}
/* for later check */
pObj->DevAddr = LAN8742_MAX_DEV_ADDR + 1;
/* Get the device address from special mode register */
for(addr = 0; addr <= LAN8742_MAX_DEV_ADDR; addr ++)
{
if(pObj->IO.ReadReg(addr, LAN8742_SMR, ®value) < 0)
{
status = LAN8742_STATUS_READ_ERROR;
/* Can't read from this device address
continue with next address */
continue;
}
if((regvalue & LAN8742_SMR_PHY_ADDR) == addr)
{
pObj->DevAddr = addr;
status = LAN8742_STATUS_OK;
break;
}
}
if(pObj->DevAddr > LAN8742_MAX_DEV_ADDR)
{
status = LAN8742_STATUS_ADDRESS_ERROR;
}
/* if device address is matched */
if(status == LAN8742_STATUS_OK)
{
/* set a software reset */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, LAN8742_BCR_SOFT_RESET) >= 0)
{
/* get software reset status */
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, ®value) >= 0)
{
tickstart = pObj->IO.GetTick();
/* wait until software reset is done or timeout occured */
while(regvalue & LAN8742_BCR_SOFT_RESET)
{
if((pObj->IO.GetTick() - tickstart) <= LAN8742_SW_RESET_TO)
{
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, ®value) < 0)
{
status = LAN8742_STATUS_READ_ERROR;
break;
}
}
else
{
status = LAN8742_STATUS_RESET_TIMEOUT;
break;
}
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
}
else
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
}
if(status == LAN8742_STATUS_OK)
{
tickstart = pObj->IO.GetTick();
/* Wait for 2s to perform initialization */
while((pObj->IO.GetTick() - tickstart) <= LAN8742_INIT_TO)
{
}
pObj->Is_Initialized = 1;
}
return status;
}
/**
* @brief De-Initialize the lan8742 and it's hardware resources
* @param pObj: device object LAN8742_Object_t.
* @retval None
*/
int32_t LAN8742_DeInit(lan8742_Object_t *pObj)
{
if(pObj->Is_Initialized)
{
if(pObj->IO.DeInit != 0)
{
if(pObj->IO.DeInit() < 0)
{
return LAN8742_STATUS_ERROR;
}
}
pObj->Is_Initialized = 0;
}
return LAN8742_STATUS_OK;
}
/**
* @brief Disable the LAN8742 power down mode.
* @param pObj: device object LAN8742_Object_t.
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_READ_ERROR if connot read register
* LAN8742_STATUS_WRITE_ERROR if connot write to register
*/
int32_t LAN8742_DisablePowerDownMode(lan8742_Object_t *pObj)
{
uint32_t readval = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) >= 0)
{
readval &= ~LAN8742_BCR_POWER_DOWN;
/* Apply configuration */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, readval) < 0)
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
return status;
}
/**
* @brief Enable the LAN8742 power down mode.
* @param pObj: device object LAN8742_Object_t.
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_READ_ERROR if connot read register
* LAN8742_STATUS_WRITE_ERROR if connot write to register
*/
int32_t LAN8742_EnablePowerDownMode(lan8742_Object_t *pObj)
{
uint32_t readval = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) >= 0)
{
readval |= LAN8742_BCR_POWER_DOWN;
/* Apply configuration */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, readval) < 0)
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
return status;
}
/**
* @brief Start the auto negotiation process.
* @param pObj: device object LAN8742_Object_t.
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_READ_ERROR if connot read register
* LAN8742_STATUS_WRITE_ERROR if connot write to register
*/
int32_t LAN8742_StartAutoNego(lan8742_Object_t *pObj)
{
uint32_t readval = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) >= 0)
{
readval |= LAN8742_BCR_AUTONEGO_EN;
/* Apply configuration */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, readval) < 0)
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
return status;
}
/**
* @brief Get the link state of LAN8742 device.
* @param pObj: Pointer to device object.
* @param pLinkState: Pointer to link state
* @retval LAN8742_STATUS_LINK_DOWN if link is down
* LAN8742_STATUS_AUTONEGO_NOTDONE if Auto nego not completed
* LAN8742_STATUS_100MBITS_FULLDUPLEX if 100Mb/s FD
* LAN8742_STATUS_100MBITS_HALFDUPLEX if 100Mb/s HD
* LAN8742_STATUS_10MBITS_FULLDUPLEX if 10Mb/s FD
* LAN8742_STATUS_10MBITS_HALFDUPLEX if 10Mb/s HD
* LAN8742_STATUS_READ_ERROR if connot read register
* LAN8742_STATUS_WRITE_ERROR if connot write to register
*/
int32_t LAN8742_GetLinkState(lan8742_Object_t *pObj)
{
uint32_t readval = 0;
/* Read Status register */
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BSR, &readval) < 0)
{
return LAN8742_STATUS_READ_ERROR;
}
/* Read Status register again */
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BSR, &readval) < 0)
{
return LAN8742_STATUS_READ_ERROR;
}
if((readval & LAN8742_BSR_LINK_STATUS) == 0)
{
/* Return Link Down status */
return LAN8742_STATUS_LINK_DOWN;
}
/* Check Auto negotiaition */
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) < 0)
{
return LAN8742_STATUS_READ_ERROR;
}
if((readval & LAN8742_BCR_AUTONEGO_EN) != LAN8742_BCR_AUTONEGO_EN)
{
if(((readval & LAN8742_BCR_SPEED_SELECT) == LAN8742_BCR_SPEED_SELECT) && ((readval & LAN8742_BCR_DUPLEX_MODE) == LAN8742_BCR_DUPLEX_MODE))
{
return LAN8742_STATUS_100MBITS_FULLDUPLEX;
}
else if ((readval & LAN8742_BCR_SPEED_SELECT) == LAN8742_BCR_SPEED_SELECT)
{
return LAN8742_STATUS_100MBITS_HALFDUPLEX;
}
else if ((readval & LAN8742_BCR_DUPLEX_MODE) == LAN8742_BCR_DUPLEX_MODE)
{
return LAN8742_STATUS_10MBITS_FULLDUPLEX;
}
else
{
return LAN8742_STATUS_10MBITS_HALFDUPLEX;
}
}
else /* Auto Nego enabled */
{
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_PHYSCSR, &readval) < 0)
{
return LAN8742_STATUS_READ_ERROR;
}
/* Check if auto nego not done */
if((readval & LAN8742_PHYSCSR_AUTONEGO_DONE) == 0)
{
return LAN8742_STATUS_AUTONEGO_NOTDONE;
}
if((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_FD)
{
return LAN8742_STATUS_100MBITS_FULLDUPLEX;
}
else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_HD)
{
return LAN8742_STATUS_100MBITS_HALFDUPLEX;
}
else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_10BT_FD)
{
return LAN8742_STATUS_10MBITS_FULLDUPLEX;
}
else
{
return LAN8742_STATUS_10MBITS_HALFDUPLEX;
}
}
}
/**
* @brief Set the link state of LAN8742 device.
* @param pObj: Pointer to device object.
* @param pLinkState: link state can be one of the following
* LAN8742_STATUS_100MBITS_FULLDUPLEX if 100Mb/s FD
* LAN8742_STATUS_100MBITS_HALFDUPLEX if 100Mb/s HD
* LAN8742_STATUS_10MBITS_FULLDUPLEX if 10Mb/s FD
* LAN8742_STATUS_10MBITS_HALFDUPLEX if 10Mb/s HD
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_ERROR if parameter error
* LAN8742_STATUS_READ_ERROR if connot read register
* LAN8742_STATUS_WRITE_ERROR if connot write to register
*/
int32_t LAN8742_SetLinkState(lan8742_Object_t *pObj, uint32_t LinkState)
{
uint32_t bcrvalue = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &bcrvalue) >= 0)
{
/* Disable link config (Auto nego, speed and duplex) */
bcrvalue &= ~(LAN8742_BCR_AUTONEGO_EN | LAN8742_BCR_SPEED_SELECT | LAN8742_BCR_DUPLEX_MODE);
if(LinkState == LAN8742_STATUS_100MBITS_FULLDUPLEX)
{
bcrvalue |= (LAN8742_BCR_SPEED_SELECT | LAN8742_BCR_DUPLEX_MODE);
}
else if (LinkState == LAN8742_STATUS_100MBITS_HALFDUPLEX)
{
bcrvalue |= LAN8742_BCR_SPEED_SELECT;
}
else if (LinkState == LAN8742_STATUS_10MBITS_FULLDUPLEX)
{
bcrvalue |= LAN8742_BCR_DUPLEX_MODE;
}
else
{
/* Wrong link status parameter */
status = LAN8742_STATUS_ERROR;
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
if(status == LAN8742_STATUS_OK)
{
/* Apply configuration */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, bcrvalue) < 0)
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
return status;
}
/**
* @brief Enable loopback mode.
* @param pObj: Pointer to device object.
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_READ_ERROR if connot read register
* LAN8742_STATUS_WRITE_ERROR if connot write to register
*/
int32_t LAN8742_EnableLoopbackMode(lan8742_Object_t *pObj)
{
uint32_t readval = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) >= 0)
{
readval |= LAN8742_BCR_LOOPBACK;
/* Apply configuration */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, readval) < 0)
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
return status;
}
/**
* @brief Disable loopback mode.
* @param pObj: Pointer to device object.
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_READ_ERROR if connot read register
* LAN8742_STATUS_WRITE_ERROR if connot write to register
*/
int32_t LAN8742_DisableLoopbackMode(lan8742_Object_t *pObj)
{
uint32_t readval = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) >= 0)
{
readval &= ~LAN8742_BCR_LOOPBACK;
/* Apply configuration */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, readval) < 0)
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
return status;
}
/**
* @brief Enable IT source.
* @param pObj: Pointer to device object.
* @param Interrupt: IT source to be enabled
* should be a value or a combination of the following:
* LAN8742_WOL_IT
* LAN8742_ENERGYON_IT
* LAN8742_AUTONEGO_COMPLETE_IT
* LAN8742_REMOTE_FAULT_IT
* LAN8742_LINK_DOWN_IT
* LAN8742_AUTONEGO_LP_ACK_IT
* LAN8742_PARALLEL_DETECTION_FAULT_IT
* LAN8742_AUTONEGO_PAGE_RECEIVED_IT
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_READ_ERROR if connot read register
* LAN8742_STATUS_WRITE_ERROR if connot write to register
*/
int32_t LAN8742_EnableIT(lan8742_Object_t *pObj, uint32_t Interrupt)
{
uint32_t readval = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_IMR, &readval) >= 0)
{
readval |= Interrupt;
/* Apply configuration */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_IMR, readval) < 0)
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
return status;
}
/**
* @brief Disable IT source.
* @param pObj: Pointer to device object.
* @param Interrupt: IT source to be disabled
* should be a value or a combination of the following:
* LAN8742_WOL_IT
* LAN8742_ENERGYON_IT
* LAN8742_AUTONEGO_COMPLETE_IT
* LAN8742_REMOTE_FAULT_IT
* LAN8742_LINK_DOWN_IT
* LAN8742_AUTONEGO_LP_ACK_IT
* LAN8742_PARALLEL_DETECTION_FAULT_IT
* LAN8742_AUTONEGO_PAGE_RECEIVED_IT
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_READ_ERROR if connot read register
* LAN8742_STATUS_WRITE_ERROR if connot write to register
*/
int32_t LAN8742_DisableIT(lan8742_Object_t *pObj, uint32_t Interrupt)
{
uint32_t readval = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_IMR, &readval) >= 0)
{
readval &= ~Interrupt;
/* Apply configuration */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_IMR, readval) < 0)
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
return status;
}
/**
* @brief Clear IT flag.
* @param pObj: Pointer to device object.
* @param Interrupt: IT flag to be cleared
* should be a value or a combination of the following:
* LAN8742_WOL_IT
* LAN8742_ENERGYON_IT
* LAN8742_AUTONEGO_COMPLETE_IT
* LAN8742_REMOTE_FAULT_IT
* LAN8742_LINK_DOWN_IT
* LAN8742_AUTONEGO_LP_ACK_IT
* LAN8742_PARALLEL_DETECTION_FAULT_IT
* LAN8742_AUTONEGO_PAGE_RECEIVED_IT
* @retval LAN8742_STATUS_OK if OK
* LAN8742_STATUS_READ_ERROR if connot read register
*/
int32_t LAN8742_ClearIT(lan8742_Object_t *pObj, uint32_t Interrupt)
{
uint32_t readval = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_ISFR, &readval) < 0)
{
status = LAN8742_STATUS_READ_ERROR;
}
return status;
}
/**
* @brief Get IT Flag status.
* @param pObj: Pointer to device object.
* @param Interrupt: IT Flag to be checked,
* should be a value or a combination of the following:
* LAN8742_WOL_IT
* LAN8742_ENERGYON_IT
* LAN8742_AUTONEGO_COMPLETE_IT
* LAN8742_REMOTE_FAULT_IT
* LAN8742_LINK_DOWN_IT
* LAN8742_AUTONEGO_LP_ACK_IT
* LAN8742_PARALLEL_DETECTION_FAULT_IT
* LAN8742_AUTONEGO_PAGE_RECEIVED_IT
* @retval 1 IT flag is SET
* 0 IT flag is RESET
* LAN8742_STATUS_READ_ERROR if connot read register
*/
int32_t LAN8742_GetITStatus(lan8742_Object_t *pObj, uint32_t Interrupt)
{
uint32_t readval = 0;
int32_t status = 0;
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_ISFR, &readval) >= 0)
{
status = ((readval & Interrupt) == Interrupt);
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
return status;
}
创建lan8742.h文件
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef LAN8742_H
#define LAN8742_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
/** @addtogroup BSP
* @{
*/
/** @addtogroup Component
* @{
*/
/** @defgroup LAN8742
* @{
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup LAN8742_Exported_Constants LAN8742 Exported Constants
* @{
*/
/** @defgroup LAN8742_Registers_Mapping LAN8742 Registers Mapping
* @{
*/
#define LAN8742_BCR ((uint16_t)0x0000U)
#define LAN8742_BSR ((uint16_t)0x0001U)
#define LAN8742_PHYI1R ((uint16_t)0x0002U)
#define LAN8742_PHYI2R ((uint16_t)0x0003U)
#define LAN8742_ANAR ((uint16_t)0x0004U)
#define LAN8742_ANLPAR ((uint16_t)0x0005U)
#define LAN8742_ANER ((uint16_t)0x0006U)
#define LAN8742_ANNPTR ((uint16_t)0x0007U)
#define LAN8742_ANNPRR ((uint16_t)0x0008U)
#define LAN8742_MMDACR ((uint16_t)0x000DU)
#define LAN8742_MMDAADR ((uint16_t)0x000EU)
#define LAN8742_ENCTR ((uint16_t)0x0010U)
#define LAN8742_MCSR ((uint16_t)0x0011U)
#define LAN8742_SMR ((uint16_t)0x0012U)
#define LAN8742_TPDCR ((uint16_t)0x0018U)
#define LAN8742_TCSR ((uint16_t)0x0019U)
#define LAN8742_SECR ((uint16_t)0x001AU)
#define LAN8742_SCSIR ((uint16_t)0x001BU)
#define LAN8742_CLR ((uint16_t)0x001CU)
#define LAN8742_ISFR ((uint16_t)0x001DU)
#define LAN8742_IMR ((uint16_t)0x001EU)
#define LAN8742_PHYSCSR ((uint16_t)0x001FU)
/**
* @}
*/
/** @defgroup LAN8742_BCR_Bit_Definition LAN8742 BCR Bit Definition
* @{
*/
#define LAN8742_BCR_SOFT_RESET ((uint16_t)0x8000U)
#define LAN8742_BCR_LOOPBACK ((uint16_t)0x4000U)
#define LAN8742_BCR_SPEED_SELECT ((uint16_t)0x2000U)
#define LAN8742_BCR_AUTONEGO_EN ((uint16_t)0x1000U)
#define LAN8742_BCR_POWER_DOWN ((uint16_t)0x0800U)
#define LAN8742_BCR_ISOLATE ((uint16_t)0x0400U)
#define LAN8742_BCR_RESTART_AUTONEGO ((uint16_t)0x0200U)
#define LAN8742_BCR_DUPLEX_MODE ((uint16_t)0x0100U)
/**
* @}
*/
/** @defgroup LAN8742_BSR_Bit_Definition LAN8742 BSR Bit Definition
* @{
*/
#define LAN8742_BSR_100BASE_T4 ((uint16_t)0x8000U)
#define LAN8742_BSR_100BASE_TX_FD ((uint16_t)0x4000U)
#define LAN8742_BSR_100BASE_TX_HD ((uint16_t)0x2000U)
#define LAN8742_BSR_10BASE_T_FD ((uint16_t)0x1000U)
#define LAN8742_BSR_10BASE_T_HD ((uint16_t)0x0800U)
#define LAN8742_BSR_100BASE_T2_FD ((uint16_t)0x0400U)
#define LAN8742_BSR_100BASE_T2_HD ((uint16_t)0x0200U)
#define LAN8742_BSR_EXTENDED_STATUS ((uint16_t)0x0100U)
#define LAN8742_BSR_AUTONEGO_CPLT ((uint16_t)0x0020U)
#define LAN8742_BSR_REMOTE_FAULT ((uint16_t)0x0010U)
#define LAN8742_BSR_AUTONEGO_ABILITY ((uint16_t)0x0008U)
#define LAN8742_BSR_LINK_STATUS ((uint16_t)0x0004U)
#define LAN8742_BSR_JABBER_DETECT ((uint16_t)0x0002U)
#define LAN8742_BSR_EXTENDED_CAP ((uint16_t)0x0001U)
/**
* @}
*/
/** @defgroup LAN8742_PHYI1R_Bit_Definition LAN8742 PHYI1R Bit Definition
* @{
*/
#define LAN8742_PHYI1R_OUI_3_18 ((uint16_t)0xFFFFU)
/**
* @}
*/
/** @defgroup LAN8742_PHYI2R_Bit_Definition LAN8742 PHYI2R Bit Definition
* @{
*/
#define LAN8742_PHYI2R_OUI_19_24 ((uint16_t)0xFC00U)
#define LAN8742_PHYI2R_MODEL_NBR ((uint16_t)0x03F0U)
#define LAN8742_PHYI2R_REVISION_NBR ((uint16_t)0x000FU)
/**
* @}
*/
/** @defgroup LAN8742_ANAR_Bit_Definition LAN8742 ANAR Bit Definition
* @{
*/
#define LAN8742_ANAR_NEXT_PAGE ((uint16_t)0x8000U)
#define LAN8742_ANAR_REMOTE_FAULT ((uint16_t)0x2000U)
#define LAN8742_ANAR_PAUSE_OPERATION ((uint16_t)0x0C00U)
#define LAN8742_ANAR_PO_NOPAUSE ((uint16_t)0x0000U)
#define LAN8742_ANAR_PO_SYMMETRIC_PAUSE ((uint16_t)0x0400U)
#define LAN8742_ANAR_PO_ASYMMETRIC_PAUSE ((uint16_t)0x0800U)
#define LAN8742_ANAR_PO_ADVERTISE_SUPPORT ((uint16_t)0x0C00U)
#define LAN8742_ANAR_100BASE_TX_FD ((uint16_t)0x0100U)
#define LAN8742_ANAR_100BASE_TX ((uint16_t)0x0080U)
#define LAN8742_ANAR_10BASE_T_FD ((uint16_t)0x0040U)
#define LAN8742_ANAR_10BASE_T ((uint16_t)0x0020U)
#define LAN8742_ANAR_SELECTOR_FIELD ((uint16_t)0x000FU)
/**
* @}
*/
/** @defgroup LAN8742_ANLPAR_Bit_Definition LAN8742 ANLPAR Bit Definition
* @{
*/
#define LAN8742_ANLPAR_NEXT_PAGE ((uint16_t)0x8000U)
#define LAN8742_ANLPAR_REMOTE_FAULT ((uint16_t)0x2000U)
#define LAN8742_ANLPAR_PAUSE_OPERATION ((uint16_t)0x0C00U)
#define LAN8742_ANLPAR_PO_NOPAUSE ((uint16_t)0x0000U)
#define LAN8742_ANLPAR_PO_SYMMETRIC_PAUSE ((uint16_t)0x0400U)
#define LAN8742_ANLPAR_PO_ASYMMETRIC_PAUSE ((uint16_t)0x0800U)
#define LAN8742_ANLPAR_PO_ADVERTISE_SUPPORT ((uint16_t)0x0C00U)
#define LAN8742_ANLPAR_100BASE_TX_FD ((uint16_t)0x0100U)
#define LAN8742_ANLPAR_100BASE_TX ((uint16_t)0x0080U)
#define LAN8742_ANLPAR_10BASE_T_FD ((uint16_t)0x0040U)
#define LAN8742_ANLPAR_10BASE_T ((uint16_t)0x0020U)
#define LAN8742_ANLPAR_SELECTOR_FIELD ((uint16_t)0x000FU)
/**
* @}
*/
/** @defgroup LAN8742_ANER_Bit_Definition LAN8742 ANER Bit Definition
* @{
*/
#define LAN8742_ANER_RX_NP_LOCATION_ABLE ((uint16_t)0x0040U)
#define LAN8742_ANER_RX_NP_STORAGE_LOCATION ((uint16_t)0x0020U)
#define LAN8742_ANER_PARALLEL_DETECT_FAULT ((uint16_t)0x0010U)
#define LAN8742_ANER_LP_NP_ABLE ((uint16_t)0x0008U)
#define LAN8742_ANER_NP_ABLE ((uint16_t)0x0004U)
#define LAN8742_ANER_PAGE_RECEIVED ((uint16_t)0x0002U)
#define LAN8742_ANER_LP_AUTONEG_ABLE ((uint16_t)0x0001U)
/**
* @}
*/
/** @defgroup LAN8742_ANNPTR_Bit_Definition LAN8742 ANNPTR Bit Definition
* @{
*/
#define LAN8742_ANNPTR_NEXT_PAGE ((uint16_t)0x8000U)
#define LAN8742_ANNPTR_MESSAGE_PAGE ((uint16_t)0x2000U)
#define LAN8742_ANNPTR_ACK2 ((uint16_t)0x1000U)
#define LAN8742_ANNPTR_TOGGLE ((uint16_t)0x0800U)
#define LAN8742_ANNPTR_MESSAGGE_CODE ((uint16_t)0x07FFU)
/**
* @}
*/
/** @defgroup LAN8742_ANNPRR_Bit_Definition LAN8742 ANNPRR Bit Definition
* @{
*/
#define LAN8742_ANNPTR_NEXT_PAGE ((uint16_t)0x8000U)
#define LAN8742_ANNPRR_ACK ((uint16_t)0x4000U)
#define LAN8742_ANNPRR_MESSAGE_PAGE ((uint16_t)0x2000U)
#define LAN8742_ANNPRR_ACK2 ((uint16_t)0x1000U)
#define LAN8742_ANNPRR_TOGGLE ((uint16_t)0x0800U)
#define LAN8742_ANNPRR_MESSAGGE_CODE ((uint16_t)0x07FFU)
/**
* @}
*/
/** @defgroup LAN8742_MMDACR_Bit_Definition LAN8742 MMDACR Bit Definition
* @{
*/
#define LAN8742_MMDACR_MMD_FUNCTION ((uint16_t)0xC000U)
#define LAN8742_MMDACR_MMD_FUNCTION_ADDR ((uint16_t)0x0000U)
#define LAN8742_MMDACR_MMD_FUNCTION_DATA ((uint16_t)0x4000U)
#define LAN8742_MMDACR_MMD_DEV_ADDR ((uint16_t)0x001FU)
/**
* @}
*/
/** @defgroup LAN8742_ENCTR_Bit_Definition LAN8742 ENCTR Bit Definition
* @{
*/
#define LAN8742_ENCTR_TX_ENABLE ((uint16_t)0x8000U)
#define LAN8742_ENCTR_TX_TIMER ((uint16_t)0x6000U)
#define LAN8742_ENCTR_TX_TIMER_1S ((uint16_t)0x0000U)
#define LAN8742_ENCTR_TX_TIMER_768MS ((uint16_t)0x2000U)
#define LAN8742_ENCTR_TX_TIMER_512MS ((uint16_t)0x4000U)
#define LAN8742_ENCTR_TX_TIMER_265MS ((uint16_t)0x6000U)
#define LAN8742_ENCTR_RX_ENABLE ((uint16_t)0x1000U)
#define LAN8742_ENCTR_RX_MAX_INTERVAL ((uint16_t)0x0C00U)
#define LAN8742_ENCTR_RX_MAX_INTERVAL_64MS ((uint16_t)0x0000U)
#define LAN8742_ENCTR_RX_MAX_INTERVAL_256MS ((uint16_t)0x0400U)
#define LAN8742_ENCTR_RX_MAX_INTERVAL_512MS ((uint16_t)0x0800U)
#define LAN8742_ENCTR_RX_MAX_INTERVAL_1S ((uint16_t)0x0C00U)
#define LAN8742_ENCTR_EX_CROSS_OVER ((uint16_t)0x0002U)
#define LAN8742_ENCTR_EX_MANUAL_CROSS_OVER ((uint16_t)0x0001U)
/**
* @}
*/
/** @defgroup LAN8742_MCSR_Bit_Definition LAN8742 MCSR Bit Definition
* @{
*/
#define LAN8742_MCSR_EDPWRDOWN ((uint16_t)0x2000U)
#define LAN8742_MCSR_FARLOOPBACK ((uint16_t)0x0200U)
#define LAN8742_MCSR_ALTINT ((uint16_t)0x0040U)
#define LAN8742_MCSR_ENERGYON ((uint16_t)0x0002U)
/**
* @}
*/
/** @defgroup LAN8742_SMR_Bit_Definition LAN8742 SMR Bit Definition
* @{
*/
#define LAN8742_SMR_MODE ((uint16_t)0x00E0U)
#define LAN8742_SMR_PHY_ADDR ((uint16_t)0x001FU)
/**
* @}
*/
/** @defgroup LAN8742_TPDCR_Bit_Definition LAN8742 TPDCR Bit Definition
* @{
*/
#define LAN8742_TPDCR_DELAY_IN ((uint16_t)0x8000U)
#define LAN8742_TPDCR_LINE_BREAK_COUNTER ((uint16_t)0x7000U)
#define LAN8742_TPDCR_PATTERN_HIGH ((uint16_t)0x0FC0U)
#define LAN8742_TPDCR_PATTERN_LOW ((uint16_t)0x003FU)
/**
* @}
*/
/** @defgroup LAN8742_TCSR_Bit_Definition LAN8742 TCSR Bit Definition
* @{
*/
#define LAN8742_TCSR_TDR_ENABLE ((uint16_t)0x8000U)
#define LAN8742_TCSR_TDR_AD_FILTER_ENABLE ((uint16_t)0x4000U)
#define LAN8742_TCSR_TDR_CH_CABLE_TYPE ((uint16_t)0x0600U)
#define LAN8742_TCSR_TDR_CH_CABLE_DEFAULT ((uint16_t)0x0000U)
#define LAN8742_TCSR_TDR_CH_CABLE_SHORTED ((uint16_t)0x0200U)
#define LAN8742_TCSR_TDR_CH_CABLE_OPEN ((uint16_t)0x0400U)
#define LAN8742_TCSR_TDR_CH_CABLE_MATCH ((uint16_t)0x0600U)
#define LAN8742_TCSR_TDR_CH_STATUS ((uint16_t)0x0100U)
#define LAN8742_TCSR_TDR_CH_LENGTH ((uint16_t)0x00FFU)
/**
* @}
*/
/** @defgroup LAN8742_SCSIR_Bit_Definition LAN8742 SCSIR Bit Definition
* @{
*/
#define LAN8742_SCSIR_AUTO_MDIX_ENABLE ((uint16_t)0x8000U)
#define LAN8742_SCSIR_CHANNEL_SELECT ((uint16_t)0x2000U)
#define LAN8742_SCSIR_SQE_DISABLE ((uint16_t)0x0800U)
#define LAN8742_SCSIR_XPOLALITY ((uint16_t)0x0010U)
/**
* @}
*/
/** @defgroup LAN8742_CLR_Bit_Definition LAN8742 CLR Bit Definition
* @{
*/
#define LAN8742_CLR_CABLE_LENGTH ((uint16_t)0xF000U)
/**
* @}
*/
/** @defgroup LAN8742_IMR_ISFR_Bit_Definition LAN8742 IMR ISFR Bit Definition
* @{
*/
#define LAN8742_INT_8 ((uint16_t)0x0100U)
#define LAN8742_INT_7 ((uint16_t)0x0080U)
#define LAN8742_INT_6 ((uint16_t)0x0040U)
#define LAN8742_INT_5 ((uint16_t)0x0020U)
#define LAN8742_INT_4 ((uint16_t)0x0010U)
#define LAN8742_INT_3 ((uint16_t)0x0008U)
#define LAN8742_INT_2 ((uint16_t)0x0004U)
#define LAN8742_INT_1 ((uint16_t)0x0002U)
/**
* @}
*/
/** @defgroup LAN8742_PHYSCSR_Bit_Definition LAN8742 PHYSCSR Bit Definition
* @{
*/
#define LAN8742_PHYSCSR_AUTONEGO_DONE ((uint16_t)0x1000U)
#define LAN8742_PHYSCSR_HCDSPEEDMASK ((uint16_t)0x001CU)
#define LAN8742_PHYSCSR_10BT_HD ((uint16_t)0x0004U)
#define LAN8742_PHYSCSR_10BT_FD ((uint16_t)0x0014U)
#define LAN8742_PHYSCSR_100BTX_HD ((uint16_t)0x0008U)
#define LAN8742_PHYSCSR_100BTX_FD ((uint16_t)0x0018U)
/**
* @}
*/
/** @defgroup LAN8742_Status LAN8742 Status
* @{
*/
#define LAN8742_STATUS_READ_ERROR ((int32_t)-5)
#define LAN8742_STATUS_WRITE_ERROR ((int32_t)-4)
#define LAN8742_STATUS_ADDRESS_ERROR ((int32_t)-3)
#define LAN8742_STATUS_RESET_TIMEOUT ((int32_t)-2)
#define LAN8742_STATUS_ERROR ((int32_t)-1)
#define LAN8742_STATUS_OK ((int32_t) 0)
#define LAN8742_STATUS_LINK_DOWN ((int32_t) 1)
#define LAN8742_STATUS_100MBITS_FULLDUPLEX ((int32_t) 2)
#define LAN8742_STATUS_100MBITS_HALFDUPLEX ((int32_t) 3)
#define LAN8742_STATUS_10MBITS_FULLDUPLEX ((int32_t) 4)
#define LAN8742_STATUS_10MBITS_HALFDUPLEX ((int32_t) 5)
#define LAN8742_STATUS_AUTONEGO_NOTDONE ((int32_t) 6)
/**
* @}
*/
/** @defgroup LAN8742_IT_Flags LAN8742 IT Flags
* @{
*/
#define LAN8742_WOL_IT LAN8742_INT_8
#define LAN8742_ENERGYON_IT LAN8742_INT_7
#define LAN8742_AUTONEGO_COMPLETE_IT LAN8742_INT_6
#define LAN8742_REMOTE_FAULT_IT LAN8742_INT_5
#define LAN8742_LINK_DOWN_IT LAN8742_INT_4
#define LAN8742_AUTONEGO_LP_ACK_IT LAN8742_INT_3
#define LAN8742_PARALLEL_DETECTION_FAULT_IT LAN8742_INT_2
#define LAN8742_AUTONEGO_PAGE_RECEIVED_IT LAN8742_INT_1
/**
* @}
*/
/**
* @}
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup LAN8742_Exported_Types LAN8742 Exported Types
* @{
*/
typedef int32_t (*lan8742_Init_Func) (void);
typedef int32_t (*lan8742_DeInit_Func) (void);
typedef int32_t (*lan8742_ReadReg_Func) (uint32_t, uint32_t, uint32_t *);
typedef int32_t (*lan8742_WriteReg_Func) (uint32_t, uint32_t, uint32_t);
typedef int32_t (*lan8742_GetTick_Func) (void);
typedef struct
{
lan8742_Init_Func Init;
lan8742_DeInit_Func DeInit;
lan8742_WriteReg_Func WriteReg;
lan8742_ReadReg_Func ReadReg;
lan8742_GetTick_Func GetTick;
} lan8742_IOCtx_t;
typedef struct
{
uint32_t DevAddr;
uint32_t Is_Initialized;
lan8742_IOCtx_t IO;
void *pData;
}lan8742_Object_t;
/**
* @}
*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup LAN8742_Exported_Functions LAN8742 Exported Functions
* @{
*/
int32_t LAN8742_RegisterBusIO(lan8742_Object_t *pObj, lan8742_IOCtx_t *ioctx);
int32_t LAN8742_Init(lan8742_Object_t *pObj);
int32_t LAN8742_DeInit(lan8742_Object_t *pObj);
int32_t LAN8742_DisablePowerDownMode(lan8742_Object_t *pObj);
int32_t LAN8742_EnablePowerDownMode(lan8742_Object_t *pObj);
int32_t LAN8742_StartAutoNego(lan8742_Object_t *pObj);
int32_t LAN8742_GetLinkState(lan8742_Object_t *pObj);
int32_t LAN8742_SetLinkState(lan8742_Object_t *pObj, uint32_t LinkState);
int32_t LAN8742_EnableLoopbackMode(lan8742_Object_t *pObj);
int32_t LAN8742_DisableLoopbackMode(lan8742_Object_t *pObj);
int32_t LAN8742_EnableIT(lan8742_Object_t *pObj, uint32_t Interrupt);
int32_t LAN8742_DisableIT(lan8742_Object_t *pObj, uint32_t Interrupt);
int32_t LAN8742_ClearIT(lan8742_Object_t *pObj, uint32_t Interrupt);
int32_t LAN8742_GetITStatus(lan8742_Object_t *pObj, uint32_t Interrupt);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* LAN8742_H */
创建app_ethernet.c及app_ethernet.h文件并添加
app_ethernet.c代码
/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "lwip/opt.h"
#include "main.h"
#if LWIP_DHCP
#include "lwip/dhcp.h"
#endif
#include "app_ethernet.h"
#include "ethernetif.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint32_t EthernetLinkTimer;
#if LWIP_DHCP
#define MAX_DHCP_TRIES 4
uint32_t DHCPfineTimer = 0;
uint8_t DHCP_state = DHCP_OFF;
#endif
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief Notify the User about the network interface config status
* @param netif: the network interface
* @retval None
*/
void ethernet_link_status_updated(struct netif *netif)
{
if (netif_is_link_up(netif))
{
#if LWIP_DHCP
/* Update DHCP state machine */
DHCP_state = DHCP_START;
#else
// BSP_LED_On(LED2);
// BSP_LED_Off(LED3);
#endif /* LWIP_DHCP */
netif_set_up(netif);
}
else
{
#if LWIP_DHCP
/* Update DHCP state machine */
DHCP_state = DHCP_LINK_DOWN;
#else
// BSP_LED_Off(LED2);
// BSP_LED_On(LED3);
#endif /* LWIP_DHCP */
netif_set_down(netif);
}
}
#if LWIP_NETIF_LINK_CALLBACK
/**
* @brief Ethernet Link periodic check
* @param netif
* @retval None
*/
void Ethernet_Link_Periodic_Handle(struct netif *netif)
{
/* Ethernet Link every 100ms */
if (HAL_GetTick() - EthernetLinkTimer >= 100)
{
EthernetLinkTimer = HAL_GetTick();
// ethernet_link_check_state(netif);
}
}
#endif
#if LWIP_DHCP
/**
* @brief DHCP_Process_Handle
* @param None
* @retval None
*/
void DHCP_Process(struct netif *netif)
{
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gw;
struct dhcp *dhcp;
switch (DHCP_state)
{
case DHCP_START:
{
ip_addr_set_zero_ip4(&netif->ip_addr);
ip_addr_set_zero_ip4(&netif->netmask);
ip_addr_set_zero_ip4(&netif->gw);
dhcp_start(netif);
DHCP_state = DHCP_WAIT_ADDRESS;
}
break;
case DHCP_WAIT_ADDRESS:
{
if (dhcp_supplied_address(netif))
{
DHCP_state = DHCP_ADDRESS_ASSIGNED;
char ip_str[16];
ip4_addr_set_u32(&ipaddr, netif_ip4_addr(netif)->addr);
ip4addr_ntoa_r(&ipaddr, ip_str, sizeof(ip_str));
printf("IPv4 address: %s\n", ip_str);
}
else
{
dhcp = (struct dhcp *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);
/* DHCP timeout */
if (dhcp->tries > MAX_DHCP_TRIES)
{
DHCP_state = DHCP_TIMEOUT;
/* Static address used */
IP_ADDR4(&ipaddr, IP_ADDR0 ,IP_ADDR1 , IP_ADDR2 , IP_ADDR3 );
IP_ADDR4(&netmask, NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
IP_ADDR4(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
netif_set_addr(netif, &ipaddr, &netmask, &gw);
}
}
}
break;
case DHCP_LINK_DOWN:
{
DHCP_state = DHCP_OFF;
}
break;
default: break;
}
}
/**
* @brief DHCP periodic check
* @param netif
* @retval None
*/
void DHCP_Periodic_Handle(struct netif *netif)
{
/* Fine DHCP periodic process every 500ms */
if (HAL_GetTick() - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)
{
DHCPfineTimer = HAL_GetTick();
/* process DHCP state machine */
DHCP_Process(netif);
}
}
#endif
app_ethernet.h代码
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __APP_ETHERNET_H
#define __APP_ETHERNET_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "lwip/netif.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* DHCP process states */
#define DHCP_OFF (uint8_t) 0
#define DHCP_START (uint8_t) 1
#define DHCP_WAIT_ADDRESS (uint8_t) 2
#define DHCP_ADDRESS_ASSIGNED (uint8_t) 3
#define DHCP_TIMEOUT (uint8_t) 4
#define DHCP_LINK_DOWN (uint8_t) 5
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void ethernet_link_status_updated(struct netif *netif);
void Ethernet_Link_Periodic_Handle(struct netif *netif);
#if LWIP_DHCP
void DHCP_Process(struct netif *netif);
void DHCP_Periodic_Handle(struct netif *netif);
#endif
#ifdef __cplusplus
}
#endif
#endif /* __APP_ETHERNET_H */
这里lwip移植基本完成 最后一步需要完成协议栈初始化、获取数据包。
在工程文件Core\src中创建lwip.c文件及 Core\src文件夹中创建lwip.h文件
添加到工程分组中
lwip.c文件
设置主机的IP地址、子网掩码、网关地址等
#include "lwip.h"
uint8_t flag_netif = 0;
struct netif gnetif;
ip4_addr_t ipaddr;
uint8_t lwip_flag;
ip4_addr_t netmask;
ip4_addr_t gw;
extern ETH_HandleTypeDef EthHandle;
uint32_t pRegValue;
void MX_LWIP_Init(void)
{
/* IP addresses initialization */
//复位ETH
HAL_GPIO_WritePin(ETH_RST_GPIO_Port,ETH_RST_Pin,GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(ETH_RST_GPIO_Port,ETH_RST_Pin,GPIO_PIN_SET);
HAL_Delay(100);
/* Initilialize the LwIP stack without RTOS */
lwip_init();
/* IP addresses initialization without DHCP (IPv4) */
IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3);
IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
/* add the network interface (IPv4/IPv6) without RTOS */
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
/* Registers the default network interface */
netif_set_default(&gnetif);
if (netif_is_link_up(&gnetif))
{
flag_netif = 1;
/* When the netif is fully configured this function must be called */
netif_set_up(&gnetif);
}
else
{
/* When the netif link is down this function must be called */
netif_set_down(&gnetif);
}
/* Set the link callback function, this function is called on change of link status*/
netif_set_link_callback(&gnetif, ethernet_link_status_updated);
}
/*处理接收到的数据包*/
void MX_LWIP_Process(void)
{
lwip_flag = 0;
ethernetif_input(&gnetif);
/* Handle timeouts */
sys_check_timeouts();
}
lwip.h文件 (配置IP地址)
#ifndef __LWIP_H_
#define __LWIP_H_
#include "main.h"
#include "lwip/opt.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/netif.h"
#include "lwip/timeouts.h"
#if LWIP_DHCP
#include "lwip/dhcp.h"
#endif
#include "ethernetif.h"
#include "app_ethernet.h"
#include "tcp.h"
#include "lan8742.h"
#define ETH_RST_GPIO_Port GPIOC
#define ETH_RST_Pin GPIO_PIN_0
/*设置的IP*/
#define IP_ADDR0 ((uint8_t) 192U) /*换为自己需要配置的IP地址*/
#define IP_ADDR1 ((uint8_t) 168U)
#define IP_ADDR2 ((uint8_t) 0U)
#define IP_ADDR3 ((uint8_t) 1U)
/*子网掩码*/
#define NETMASK_ADDR0 ((uint8_t) 255U) /*换为自己需要配置的子网掩码*/
#define NETMASK_ADDR1 ((uint8_t) 255U)
#define NETMASK_ADDR2 ((uint8_t) 0U)
#define NETMASK_ADDR3 ((uint8_t) 0U)
/*网关地址*/
#define GW_ADDR0 ((uint8_t) 192U) /*换为自己需要配置的网关地址*/
#define GW_ADDR1 ((uint8_t) 168U)
#define GW_ADDR2 ((uint8_t) 0U)
#define GW_ADDR3 ((uint8_t) 1U)
void MX_LWIP_Init(void);
void Reset_network(void);
void MX_LWIP_Process(void);
#endif
main.c文件
在main.c文件中 添加#include "lwip.h" 头文件
添加lwip初始化函数和数据包处理函数
移植完成后的问题:
移植完成后 发现还有报错 显示重复定义
检查后发现 在ethernetif.c文件中 已经对eth引脚的定义 我又在CubeMX中定义了一次 所以导致了重复定义 需要把eth.c文件中的源码全部删除
再将main函数中的eth引脚初始化函数删除
在 ethernetif.c文件 需要对比配置引脚 是否于硬件设计电路是否一致
编译成功
可以ping通 这样移植lwip就成功了
通过上面的步骤,我们能使用开发板获取网络的数据包了,但是获取数据包的方式有两种,一种是查询方式,另一种是中断方式。这里选择查询方式,查询方式通过主函数的while循环进行周期性处理,去获取网卡中是否接收到数据包,然后递交给上层协议去处理。
中断方式后续更新。
作者能力有限 有什么问题 欢迎大家指正或讨论
作者:梦途笑匠