flexPTP 1.0
An IEEE 1588 PTP implementation designed for microcontrollers
Loading...
Searching...
No Matches
STM32H743 low level lwIP driver modifications to support timestamp communication

lwIP low level driver modifications

In the following you will find a modified version of the vendor-provided STM32H743 low level lwIP Ethernet driver. Both RX and TX functions have been modified so that timestamp capture upon reception and transmission are also supported.

The complete file is accessible is included at the end of this page.

Reception timestamps

Into the function pbuf_low_level_input() we have inserted a small portion of code that copies the reception timestamp into the pbuf.

Inserted lines:

/* Store timestamp */
p->time_s = RxBuff->ts_sec;
p->time_ns = RxBuff->ts_nsec;

Complete function:

static struct pbuf * low_level_input(struct netif *netif)
{
struct pbuf *p = NULL;
ETH_BufferTypeDef RxBuff[ETH_RX_DESC_CNT];
uint32_t framelength = 0, i = 0;;
struct pbuf_custom* custom_pbuf;
memset(RxBuff, 0 , ETH_RX_DESC_CNT*sizeof(ETH_BufferTypeDef));
for(i = 0; i < ETH_RX_DESC_CNT -1; i++)
{
RxBuff[i].next=&RxBuff[i+1];
}
if(HAL_ETH_GetRxDataBuffer(&EthHandle, RxBuff) == HAL_OK)
{
HAL_ETH_GetRxDataLength(&EthHandle, &framelength);
/* Build Rx descriptor to be ready for next data reception */
HAL_ETH_BuildRxDescriptors(&EthHandle);
/* Invalidate data cache for ETH Rx Buffers */
SCB_InvalidateDCache_by_Addr((uint32_t *)RxBuff->buffer, framelength);
custom_pbuf = (struct pbuf_custom*)LWIP_MEMPOOL_ALLOC(RX_POOL);
if(custom_pbuf != NULL)
{
custom_pbuf->custom_free_function = pbuf_free_custom;
p = pbuf_alloced_custom(PBUF_RAW, framelength, PBUF_REF, custom_pbuf, RxBuff->buffer, framelength);
/* Store timestamp */
p->time_s = RxBuff->ts_sec;
p->time_ns = RxBuff->ts_nsec;
}
}
return p;
}
ETH_HandleTypeDef EthHandle

Transmission timestamps

Several functions were modified and variables were declared in order to pass transmission timestamp back to the application through invoking callbacks.

Array for timestamp write back addresses

An array was declared to temporarily hold the addresses where the transmit timestamps will be saved right after the packet transmission has completed.

struct pbuf *ppWriteBackPBufs[ETH_TX_DESC_CNT]; /* pBuf array for timestamp writeback */

Procedure to save transmit timestamps

A procedure was added that writes the transmit timestamp to their designated place. The routine is invoked whenever a frame transmission is done.

void ethernetif_write_back_tx_timestamps() {
/* store timestamps for transmitted frames */
for (size_t j = 0; j < ETH_TX_DESC_CNT; j++) {
ETH_DMADescTypeDef * pDesc = &DMATxDscrTab[j];
struct pbuf * pPBuf = ppWriteBackPBufs[j];
if ((pPBuf != NULL) && (!(pDesc->DESC3 & ETH_DMATXNDESCWBF_OWN)) && (pDesc->DESC3 & ETH_DMATXNDESCWBF_LD) && (pDesc->DESC3 & ETH_DMATXNDESCWBF_TTSS)) {
//MSG("* ");
pPBuf->time_s = pDesc->DESC1;
pPBuf->time_ns = pDesc->DESC0;
ppWriteBackPBufs[j] = NULL;
pDesc->DESC3 &= ~ETH_DMATXNDESCWBF_TTSS;
if (pPBuf->ts_writeback_addr[0] != NULL) {
*pPBuf->ts_writeback_addr[0] = pPBuf->time_s;
}
if (pPBuf->ts_writeback_addr[1] != NULL) {
*pPBuf->ts_writeback_addr[1] = pPBuf->time_ns;
}
if (pPBuf->tx_cb) {
pPBuf->tx_cb(pPBuf);
}
pPBuf->tx_cb = NULL;
pPBuf->ts_writeback_addr[0] = NULL;
pPBuf->ts_writeback_addr[1] = NULL;
}
}
}
void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef * heth) {
ethernetif_write_back_tx_timestamps();
}

If driver operates in polled mode, calling the writeback routine can be placed instead into the following function:

void ethernetif_input( void const * argument )
{
struct pbuf *p;
struct netif *netif = (struct netif *) argument;
for( ;; )
{
if (osSemaphoreWait( RxPktSemaphore, TIME_WAITING_FOR_INPUT)==osOK)
{
do
{
p = low_level_input( netif );
if (p != NULL)
{
if (netif->input( p, netif) != ERR_OK )
{
pbuf_free(p);
}
}
}while(p!=NULL);
ethernetif_write_back_tx_timestamps();
}
}
}

Complete file

/* Includes ------------------------------------------------------------------*/
#include "stm32h7xx_hal.h"
#include "lwip/timeouts.h"
#include "netif/ethernet.h"
#include "netif/etharp.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/tcpip.h"
#include "ethernetif.h"
#include "../Components/lan8742/lan8742.h"
#include <string.h>
#include "utils.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* The time to block waiting for input. */
#define TIME_WAITING_FOR_INPUT ( osWaitForever )
/* Stack size of the interface thread */
#define INTERFACE_THREAD_STACK_SIZE ( 350 )
/* Define those to better describe your network interface. */
#define IFNAME0 's'
#define IFNAME1 't'
#define ETH_RX_BUFFER_SIZE (1536UL)
#define ETH_DMA_TRANSMIT_TIMEOUT (20U)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/*
@Note: This interface is implemented to operate in zero-copy mode only:
- Rx buffers are allocated statically and passed directly to the LwIP stack,
they will return back to ETH DMA after been processed by the stack.
- 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 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 stm32xxxx_hal_conf.h
2.a. Rx Buffers number must be between ETH_RX_DESC_CNT and 2*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 (EthHandle.Init.RxBuffLen)
2.c The RX Ruffers addresses and sizes must be properly defined to be aligned
to L1-CACHE line size (32 bytes).
*/
#if defined ( __ICCARM__ )
#pragma location=0x30040000
ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
#pragma location=0x30040060
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
#pragma location=0x30040200
uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE]; /* Ethernet Receive Buffers */
#elif defined ( __CC_ARM ) /* MDK ARM Compiler */
__attribute__((section(".RxDecripSection"))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
__attribute__((section(".TxDecripSection"))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
__attribute__((section(".RxArraySection"))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE]; /* Ethernet Receive Buffer */
#elif defined ( __GNUC__ ) /* GNU Compiler */
ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection"))); /* Ethernet Tx DMA Descriptors */
uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE] __attribute__((section(".RxArraySection"))); /* Ethernet Receive Buffers */
uint8_t LwIP_HEAP[20*1024] __attribute__((section(".LwIPHEAP"))); /* LwIP heap */
struct pbuf *ppWriteBackPBufs[ETH_TX_DESC_CNT]; /* pBuf array for timestamp writeback */
#endif
ETH_HandleTypeDef EthHandle;
ETH_TxPacketConfig TxConfig;
lan8742_Object_t LAN8742;
osSemaphoreId RxPktSemaphore = NULL; /* Semaphore to signal incoming packets */
/* Private function prototypes -----------------------------------------------*/
static void ethernetif_input( void const * argument );
u32_t sys_now(void);
void pbuf_free_custom(struct pbuf *p);
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_IOCtx_t LAN8742_IOCtx = {ETH_PHY_IO_Init,
ETH_PHY_IO_DeInit,
ETH_PHY_IO_WriteReg,
ETH_PHY_IO_ReadReg,
ETH_PHY_IO_GetTick};
LWIP_MEMPOOL_DECLARE(RX_POOL, 10, sizeof(struct pbuf_custom), "Zero-copy RX PBUF pool");
void ethernetif_write_back_tx_timestamps() {
/* store timestamps for transmitted frames */
for (size_t j = 0; j < ETH_TX_DESC_CNT; j++) {
ETH_DMADescTypeDef * pDesc = &DMATxDscrTab[j];
struct pbuf * pPBuf = ppWriteBackPBufs[j];
if ((pPBuf != NULL) && (!(pDesc->DESC3 & ETH_DMATXNDESCWBF_OWN)) && (pDesc->DESC3 & ETH_DMATXNDESCWBF_LD) && (pDesc->DESC3 & ETH_DMATXNDESCWBF_TTSS)) {
//MSG("* ");
pPBuf->time_s = pDesc->DESC1;
pPBuf->time_ns = pDesc->DESC0;
ppWriteBackPBufs[j] = NULL;
pDesc->DESC3 &= ~ETH_DMATXNDESCWBF_TTSS;
if (pPBuf->ts_writeback_addr[0] != NULL) {
*pPBuf->ts_writeback_addr[0] = pPBuf->time_s;
}
if (pPBuf->ts_writeback_addr[1] != NULL) {
*pPBuf->ts_writeback_addr[1] = pPBuf->time_ns;
}
if (pPBuf->tx_cb) {
pPBuf->tx_cb(pPBuf);
}
pPBuf->tx_cb = NULL;
pPBuf->ts_writeback_addr[0] = NULL;
pPBuf->ts_writeback_addr[1] = NULL;
}
}
}
void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef * heth) {
ethernetif_write_back_tx_timestamps();
}
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
LL Driver Interface ( LwIP stack --> ETH)
*******************************************************************************/
static void low_level_init(struct netif *netif)
{
uint32_t idx, duplex, speed = 0;
int32_t PHYLinkState;
ETH_MACConfigTypeDef MACConf;
uint8_t macaddress[6]= {ETH_MAC_ADDR0, ETH_MAC_ADDR1, ETH_MAC_ADDR2, ETH_MAC_ADDR3, ETH_MAC_ADDR4, ETH_MAC_ADDR5};
EthHandle.Instance = ETH;
EthHandle.Init.MACAddr = macaddress;
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] = ETH_MAC_ADDR0;
netif->hwaddr[1] = ETH_MAC_ADDR1;
netif->hwaddr[2] = ETH_MAC_ADDR2;
netif->hwaddr[3] = ETH_MAC_ADDR3;
netif->hwaddr[4] = ETH_MAC_ADDR4;
netif->hwaddr[5] = ETH_MAC_ADDR5;
/* 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 | NETIF_FLAG_IGMP;
for(idx = 0; idx < ETH_RX_DESC_CNT; idx ++)
{
HAL_ETH_DescAssignMemory(&EthHandle, idx, Rx_Buff[idx], NULL);
}
/* Initialize the RX POOL */
LWIP_MEMPOOL_INIT(RX_POOL);
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;
/* create a binary semaphore used for informing ethernetif of frame reception */
RxPktSemaphore = xSemaphoreCreateBinary();
/* create the task that handles the ETH_MAC */
osThreadDef(EthIf, ethernetif_input, osPriorityRealtime, 0, INTERFACE_THREAD_STACK_SIZE);
osThreadCreate (osThread(EthIf), netif);
/* Set PHY IO functions */
LAN8742_RegisterBusIO(&LAN8742, &LAN8742_IOCtx);
/* Initialize the LAN8742 ETH PHY */
LAN8742_Init(&LAN8742);
PHYLinkState = LAN8742_GetLinkState(&LAN8742);
/* Get link state */
if(PHYLinkState <= LAN8742_STATUS_LINK_DOWN)
{
netif_set_link_down(netif);
netif_set_down(netif);
}
else
{
switch (PHYLinkState)
{
case LAN8742_STATUS_100MBITS_FULLDUPLEX:
duplex = ETH_FULLDUPLEX_MODE;
speed = ETH_SPEED_100M;
break;
case LAN8742_STATUS_100MBITS_HALFDUPLEX:
duplex = ETH_HALFDUPLEX_MODE;
speed = ETH_SPEED_100M;
break;
case LAN8742_STATUS_10MBITS_FULLDUPLEX:
duplex = ETH_FULLDUPLEX_MODE;
speed = ETH_SPEED_10M;
break;
case LAN8742_STATUS_10MBITS_HALFDUPLEX:
duplex = ETH_HALFDUPLEX_MODE;
speed = ETH_SPEED_10M;
break;
default:
duplex = ETH_FULLDUPLEX_MODE;
speed = ETH_SPEED_100M;
break;
}
/* Get MAC Config MAC */
HAL_ETH_GetMACConfig(&EthHandle, &MACConf);
MACConf.DuplexMode = duplex;
MACConf.Speed = speed;
HAL_ETH_SetMACConfig(&EthHandle, &MACConf);
HAL_ETH_Start_IT(&EthHandle);
netif_set_up(netif);
netif_set_link_up(netif);
}
}
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
uint32_t i=0;
struct pbuf *q;
err_t errval = ERR_OK;
ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];
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;
ppWriteBackPBufs[EthHandle.TxDescList.CurTxDesc] = p;
HAL_ETH_Transmit(&EthHandle, &TxConfig, ETH_DMA_TRANSMIT_TIMEOUT);
//HAL_ETH_Transmit_IT(&EthHandle, &TxConfig);
return errval;
}
static struct pbuf * low_level_input(struct netif *netif)
{
struct pbuf *p = NULL;
ETH_BufferTypeDef RxBuff[ETH_RX_DESC_CNT];
uint32_t framelength = 0, i = 0;;
struct pbuf_custom* custom_pbuf;
memset(RxBuff, 0 , ETH_RX_DESC_CNT*sizeof(ETH_BufferTypeDef));
for(i = 0; i < ETH_RX_DESC_CNT -1; i++)
{
RxBuff[i].next=&RxBuff[i+1];
}
if(HAL_ETH_GetRxDataBuffer(&EthHandle, RxBuff) == HAL_OK)
{
HAL_ETH_GetRxDataLength(&EthHandle, &framelength);
/* Build Rx descriptor to be ready for next data reception */
HAL_ETH_BuildRxDescriptors(&EthHandle);
/* Invalidate data cache for ETH Rx Buffers */
SCB_InvalidateDCache_by_Addr((uint32_t *)RxBuff->buffer, framelength);
custom_pbuf = (struct pbuf_custom*)LWIP_MEMPOOL_ALLOC(RX_POOL);
if(custom_pbuf != NULL)
{
custom_pbuf->custom_free_function = pbuf_free_custom;
p = pbuf_alloced_custom(PBUF_RAW, framelength, PBUF_REF, custom_pbuf, RxBuff->buffer, framelength);
/* Store timestamp */
p->time_s = RxBuff->ts_sec;
p->time_ns = RxBuff->ts_nsec;
}
}
return p;
}
void ethernetif_input( void const * argument )
{
struct pbuf *p;
struct netif *netif = (struct netif *) argument;
for( ;; )
{
if (osSemaphoreWait( RxPktSemaphore, TIME_WAITING_FOR_INPUT)==osOK)
{
do
{
p = low_level_input( netif );
if (p != NULL)
{
if (netif->input( p, netif) != ERR_OK )
{
pbuf_free(p);
}
}
}while(p!=NULL);
ethernetif_write_back_tx_timestamps();
}
}
}
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 */
/*
Initialize the snmp variables and counters inside the struct netif.
The last argument should be replaced with your link speed, in units
of bits per second.
*/
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
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;
}
void pbuf_free_custom(struct pbuf *p)
{
struct pbuf_custom* custom_pbuf = (struct pbuf_custom*)p;
LWIP_MEMPOOL_FREE(RX_POOL, custom_pbuf);
}
u32_t sys_now(void)
{
return HAL_GetTick();
}
/*******************************************************************************
Ethernet MSP Routines
*******************************************************************************/
void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Ethernett MSP init: RMII Mode */
/* Enable GPIOs clocks */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
/* Ethernet pins configuration ************************************************/
/*
RMII_REF_CLK ----------------------> PA1
RMII_MDIO -------------------------> PA2
RMII_MDC --------------------------> PC1
RMII_MII_CRS_DV -------------------> PA7
RMII_MII_RXD0 ---------------------> PC4
RMII_MII_RXD1 ---------------------> PC5
RMII_MII_RXER ---------------------> PG2
RMII_MII_TX_EN --------------------> PG11
RMII_MII_TXD0 ---------------------> PG13
RMII_MII_TXD1 ---------------------> PB13
*/
/* Configure PA1, PA2 and PA7 */
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure PB13 */
GPIO_InitStructure.Pin = GPIO_PIN_13;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure PC1, PC4 and PC5 */
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Configure PG2, PG11, PG13 and PG14 */
GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_11 | GPIO_PIN_13;
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
/* Enable the Ethernet global Interrupt */
HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0);
HAL_NVIC_EnableIRQ(ETH_IRQn);
/* Enable Ethernet clocks */
__HAL_RCC_ETH1MAC_CLK_ENABLE();
__HAL_RCC_ETH1TX_CLK_ENABLE();
__HAL_RCC_ETH1RX_CLK_ENABLE();
}
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
osSemaphoreRelease(RxPktSemaphore);
}
/*******************************************************************************
PHI IO Functions
*******************************************************************************/
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;
}
int32_t ETH_PHY_IO_DeInit (void)
{
return 0;
}
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;
}
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;
}
int32_t ETH_PHY_IO_GetTick(void)
{
return HAL_GetTick();
}
void ethernet_link_thread( void const * argument )
{
ETH_MACConfigTypeDef MACConf;
int32_t PHYLinkState;
uint32_t linkchanged = 0, speed = 0, duplex =0;
struct netif *netif = (struct netif *) argument;
for(;;)
{
PHYLinkState = LAN8742_GetLinkState(&LAN8742);
if(netif_is_link_up(netif) && (PHYLinkState <= LAN8742_STATUS_LINK_DOWN))
{
HAL_ETH_Stop_IT(&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_IT(&EthHandle);
netif_set_up(netif);
netif_set_link_up(netif);
}
}
osDelay(100);
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
struct __attribute__((packed))