Files
ETH_TCP_Demo/lwip/port/drv_eth.c
2026-02-09 10:27:21 +08:00

333 lines
9.5 KiB
C

#include "drv_eth.h"
#include "lwip/opt.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/timeouts.h"
#include "netif/etharp.h"
#include "lwip/ethip6.h"
#include "osal.h"
#include <string.h>
/* Ethernet Handle */
ETH_HandleTypeDef heth;
static uint32_t g_phy_address = 0; /* Stored PHY Address */
/* DMA Descriptors and Buffers */
__attribute__((section(".RxDecripSection"))) __attribute__((aligned(4))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB];
__attribute__((section(".TxDecripSection"))) __attribute__((aligned(4))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB];
__attribute__((section(".RxArraySection"))) __attribute__((aligned(4))) uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE];
__attribute__((section(".TxArraySection"))) __attribute__((aligned(4))) uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE];
/* Semaphore for Ethernet */
static osal_sem_t s_xSemaphore = NULL;
/* MSP Init */
void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
{
(void)heth;
GPIO_InitTypeDef GPIO_InitStructure;
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_ETH_CLK_ENABLE();
/* PA1, PA2, PA7 */
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
/* PC1, PC4, PC5 */
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
/* PB11, PB12, PB13 */
GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
HAL_NVIC_SetPriority(ETH_IRQn, 0x07, 0);
HAL_NVIC_EnableIRQ(ETH_IRQn);
}
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
(void)heth;
if (s_xSemaphore != NULL)
{
osal_sem_release(s_xSemaphore);
}
}
void HAL_ETH_RxAllocateCallback(uint8_t **buff)
{
static int rx_idx = 0;
*buff = Rx_Buff[rx_idx];
rx_idx = (rx_idx + 1) % ETH_RXBUFNB;
}
void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length)
{
(void)Length;
*pStart = (void *)buff;
*pEnd = (void *)buff;
}
void ETH_IRQHandler(void)
{
osal_enter_critical();
HAL_ETH_IRQHandler(&heth);
osal_exit_critical();
}
static void low_level_init(struct netif *netif)
{
/* Use a fixed MAC address to avoid conflicts/filtering */
uint8_t macaddress[6] = { 0x00, 0x80, 0xE1, 0x00, 0x00, 0x55 };
ETH_MACConfigTypeDef macConf;
HAL_StatusTypeDef hal_eth_init_status;
uint32_t phy_id1 = 0, phy_id2 = 0;
uint8_t detected_phy_addr = 0;
uint32_t regvalue;
/* Generate MAC address from UID */
/*
uint32_t uid0 = HAL_GetUIDw0();
uint32_t uid1 = HAL_GetUIDw1();
uint32_t uid2 = HAL_GetUIDw2();
macaddress[0] = 0x02;
macaddress[1] = 0x80;
macaddress[2] = 0xE1;
macaddress[3] = (uid0 >> 16) & 0xFF;
macaddress[4] = (uid1 >> 8) & 0xFF;
macaddress[5] = uid2 & 0xFF;
*/
osal_log_i("MAC: %02x:%02x:%02x:%02x:%02x:%02x",
macaddress[0], macaddress[1], macaddress[2],
macaddress[3], macaddress[4], macaddress[5]);
heth.Instance = ETH;
heth.Init.MACAddr = macaddress;
heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
heth.Init.TxDesc = DMATxDscrTab;
heth.Init.RxDesc = DMARxDscrTab;
heth.Init.RxBuffLen = ETH_RX_BUF_SIZE;
/* Initialize ETH (MAC, DMA, GPIOs via MSP) first to enable MDC/MDIO */
hal_eth_init_status = HAL_ETH_Init(&heth);
if (hal_eth_init_status == HAL_OK)
{
/* Step 1: PHY address detection */
osal_log_i("Detecting PHY Address...");
detected_phy_addr = 0xFF; /* Invalid initial value */
for(uint8_t addr = 0; addr <= 31; addr++) {
/* Read PHY ID registers (typically Reg 2 and 3) */
/* Using 4-arg version: heth, PhyAddr, Reg, Value */
if(HAL_ETH_ReadPHYRegister(&heth, addr, 2, &phy_id1) == HAL_OK &&
HAL_ETH_ReadPHYRegister(&heth, addr, 3, &phy_id2) == HAL_OK) {
if((phy_id1 != 0xFFFF) && (phy_id1 != 0x0000) && (phy_id1 != 0)) {
detected_phy_addr = addr;
osal_log_i("Found PHY at Address %d (ID: %04x %04x)", addr, phy_id1, phy_id2);
break;
}
}
}
if (detected_phy_addr != 0xFF)
{
g_phy_address = detected_phy_addr;
/* Step 2: PHY Soft Reset */
osal_log_i("Resetting PHY...");
/* Write Reset Bit */
HAL_ETH_WritePHYRegister(&heth, g_phy_address, PHY_BCR, PHY_RESET);
/* Wait for Reset to clear */
uint32_t tickstart = osal_tick_get();
do {
HAL_ETH_ReadPHYRegister(&heth, g_phy_address, PHY_BCR, &regvalue);
if((regvalue & PHY_RESET) == 0) break;
} while ((osal_tick_get() - tickstart) < 500); // 500ms timeout
/* Add a delay to ensure PHY is stable */
osal_thread_mdelay(100);
netif->flags |= NETIF_FLAG_LINK_UP;
}
else
{
osal_log_e("No PHY found!");
}
}
else
{
osal_log_e("HAL_ETH_Init failed");
}
HAL_ETH_GetMACConfig(&heth, &macConf);
macConf.DuplexMode = ETH_FULLDUPLEX_MODE;
macConf.Speed = ETH_SPEED_100M;
macConf.ChecksumOffload = ENABLE; /* Enable HW Checksum */
HAL_ETH_SetMACConfig(&heth, &macConf);
/* Enable Promiscuous Mode manually as it's not in the struct */
heth.Instance->MACFFR |= ETH_MACFFR_PM;
HAL_ETH_Start_IT(&heth);
s_xSemaphore = osal_sem_create("eth_sem", 0);
netif->hwaddr_len = 6;
memcpy(netif->hwaddr, macaddress, 6);
netif->mtu = 1500;
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
#if LWIP_IPV6
netif->flags |= NETIF_FLAG_IGMP;
#endif
}
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
(void)netif;
err_t errval;
struct pbuf *q;
ETH_TxPacketConfigTypeDef txConfig;
ETH_BufferTypeDef txBuffers[16];
memset(&txConfig, 0, sizeof(ETH_TxPacketConfigTypeDef));
/* Disable Hardware Checksum Insertion */
txConfig.Attributes = 0; // ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
txConfig.ChecksumCtrl = ETH_CHECKSUM_DISABLE; // ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
txConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
int i = 0;
for(q = p; q != NULL; q = q->next)
{
if (i >= 16) break;
txBuffers[i].buffer = (uint8_t*)q->payload;
txBuffers[i].len = q->len;
if (q->next != NULL) {
txBuffers[i].next = &txBuffers[i+1];
} else {
txBuffers[i].next = NULL;
}
i++;
}
txConfig.Length = p->tot_len;
txConfig.TxBuffer = &txBuffers[0];
if (HAL_ETH_Transmit(&heth, &txConfig, 10) == HAL_OK) {
errval = ERR_OK;
} else {
errval = ERR_IF;
}
return errval;
}
static struct pbuf * low_level_input(struct netif *netif)
{
(void)netif;
struct pbuf *p = NULL;
uint8_t *buffer = NULL;
uint32_t rxLength = 0;
if (HAL_ETH_ReadData(&heth, (void**)&buffer) == HAL_OK)
{
rxLength = heth.RxDescList.RxDataLength;
// osal_log_i("Rx: rxLength=%d", rxLength);
if (rxLength > 0 && buffer != NULL) {
p = pbuf_alloc(PBUF_RAW, rxLength, PBUF_POOL);
if (p != NULL) {
/* Copy data */
pbuf_take(p, buffer, rxLength);
// osal_log_i("Rx: p->tot_len=%d", p->tot_len);
} else {
osal_log_e("pbuf_alloc failed");
}
/* HAL_ETH_ReadData internally calls ETH_UpdateDescriptor, so descriptors are rebuilt automatically */
}
} else {
/* ReadData failed, maybe no data available */
}
return p;
}
void ethernetif_input(struct netif *netif)
{
struct pbuf *p;
if (s_xSemaphore == NULL) {
osal_thread_mdelay(100);
return;
}
if (osal_sem_take(s_xSemaphore, 100) == OSAL_OK)
{
do {
p = low_level_input(netif);
if (p != NULL)
{
// osal_log_i("Rx: len=%d", p->tot_len); // Debug print
if (netif->input(p, netif) != ERR_OK)
{
pbuf_free(p);
}
}
} while(p != NULL);
}
}
err_t ethernetif_init(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", (netif != NULL));
#if LWIP_NETIF_HOSTNAME
netif->hostname = "lwip";
#endif
netif->name[0] = 'e';
netif->name[1] = 't';
netif->output = etharp_output;
netif->linkoutput = low_level_output;
low_level_init(netif);
return ERR_OK;
}
void ethernet_link_check_state(struct netif *netif)
{
uint32_t regvalue = 0;
/* Use configured PHY Address */
HAL_ETH_ReadPHYRegister(&heth, g_phy_address, PHY_BSR, &regvalue);
if ((regvalue & PHY_LINKED_STATUS) != (uint16_t)RESET)
{
if (!netif_is_link_up(netif))
{
netif_set_link_up(netif);
osal_log_i("Ethernet Link Up");
}
}
else
{
if (netif_is_link_up(netif))
{
netif_set_link_down(netif);
osal_log_i("Ethernet Link Down");
}
}
}