【程序】STM32H743ZI单⽚机驱动DP83848以太⽹PHY芯
⽚,移植lwip2.1。。。
HAL库版本:STM32Cube_FW_H7_V1.9.0
Keil5⼯程下载地址:(提取码:p3xd)
开发板:
【电路连线】
晶振采⽤的是XTAL-3225封装的50MHz有源晶振。
引脚名称单⽚机I/O⼝
ETH_REF_CLK PA1
ETH_MDIO PA2
ETH_CRS_DV PA7
ETH_TX_EN PG11
ETH_TXD0PB12
ETH_TXD1PB13
ETH_MDC PC1
ETH_RXD0PC4
ETH_RXD1PC5
DP83848_RST(复位)PE4(普通I/O⼝)
DP83848_INT(中断)PE5(普通I/O⼝)
【代码讲解】
程序⾥⾯使⽤的lwip2.1.3除了下⾯⼏个⽂件是修改过的以外,其余的都是官⽹的原始⽂件:
修改的⽂件:ethernetif.c(修改前的原始⽂件位于contrib-2.1.0.zip)
添加的⽂件:arch/cc.h lwipopts.h
(lwip 2.0.3版本中的ethernetif.c⽂件位于lwip-2.0.3.zip压缩包的src/netif⽂件夹下。⽽lwip 2.1.0~2.1.3版本中的ethernetif.c⽂件则被移动到了contrib-2.1.0.zip压缩包的examples/ethernetif⽂件夹⾥⾯了, ⾥⾯有⼀些细微的修改)
系统时钟的配置是在clock_init函数⾥⾯完成的:
/* 配置系统时钟 */
void clock_init(void)
{
HAL_StatusTypeDef status;
RCC_ClkInitTypeDef clk = {0};
RCC_OscInitTypeDef osc = {0};
经期多久HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while (__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY) == RESET);
osc.OscillatorType = RCC_OSCILLATORTYPE_HSE;
osc.HSEState = RCC_HSE_ON;
osc.PLL.PLLFRACN = 0;
osc.PLL.PLLM = 5;
osc.PLL.PLLN = 192;
osc.PLL.PLLP = 2;
osc.PLL.PLLQ = 2;
osc.PLL.PLLR = 2;
osc.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
osc.PLL.PLLSource = RCC_PLLSOURCE_HSE;
osc.PLL.PLLState = RCC_PLL_ON;
osc.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
status = HAL_RCC_OscConfig(&osc);
if (status != HAL_OK)
abort();
clk.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D1PC clk.SYSCLKDivider = RCC_SYSCLK_DIV1;
clk.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clk.AHBCLKDivider = RCC_HCLK_DIV2;开心的笑话
clk.APB1CLKDivider = RCC_APB1_DIV2;
clk.APB2CLKDivider = RCC_APB2_DIV2;
clk.APB3CLKDivider = RCC_APB3_DIV2;
clk.APB4CLKDivider = RCC_APB4_DIV2;
HAL_RCC_ClockConfig(&clk, FLASH_LATENCY_4);
}
该函数将系统时钟配置为480MHz:AHB时钟为240MHz,APB1~4时钟为120MHz。
初始化DP83848的函数是DP83848_Init,该函数是在netif_add添加⽹卡时调⽤的,调⽤关系如下:
main -> net_config -> netif_add(或netif_add_noaddr) -> ethernetif_init -> low_level_init -> DP83848_Init
其中,low_level_init函数的代码如下:
/**
* 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)
{
/
/struct ethernetif *ethernetif = netif->state;
/* t MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* t MAC hardware address */
DP83848_Init();
DP83848_GetMACAddress(netif->hwaddr);
printf("MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hw
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
/* don't t NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_MLD6; // 这⾥MLD6是启⽤IPv6多播
// 不设置NETIF_FLAG_LINK_UP这个标志, 开机时认为⽹络未接通
#if LWIP_IPV6 && LWIP_IPV6_MLD
/*
* For hardware/netifs that implement MAC filtering.
北京车牌摇号申请
* All-nodes link-local is handled by default, so we must let the hardware know
* to allow multicast packets in.
* Should t mld_mac_filter previously. */
if (netif->mld_mac_filter != NULL) {
ip6_addr_t ip6_allnodes_ll;
ip6_addr_t_allnodes_linklocal(&ip6_allnodes_ll);
netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
}
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
/* Do whatever el is needed to initialize interface. */
}
在这个函数⾥⾯,调⽤了DP83848_Init初始化⽹⼝,接着调⽤DP83848_GetMACAddress将⽹卡地址(在程序中由STM32单⽚机的器
件ID⽣成)告诉lwip。netif->flags不设置NETIF_FLAG_LINK_UP标志,告诉lwip⽹卡现在没有⽹。NETIF_FLAG_MLD6表⽰启⽤IPv6多
播功能,IPv6的运⾏依赖于多播,不打开多播的话IPv6是不能正常⼯作的。
接下来看看DP83848_Init函数:
void DP83848_Init(void)
{
int i;
uint32_t uid;
ETH_MACFilterConfigTypeDef macfilter;
GPIO_InitTypeDef gpio;
急救包扎
__HAL_RCC_GPIOA_CLK_ENABLE();冬笋炖排骨的做法
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
// PA1: ETH_REF_CLK, PA2: ETH_MDIO, PA7: ETH_CRS_DV
gpio.Alternate = GPIO_AF11_ETH;
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &gpio);
// PB12~13: ETH_TXD0~1
gpio.Pin = GPIO_PIN_12 | GPIO_PIN_13;
HAL_GPIO_Init(GPIOB, &gpio);
// PC1: ETH_MDC, PC4~5: ETH_RXD0~1
gpio.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOC, &gpio);
// PE4: DP83848_RST
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Pin = GPIO_PIN_4;
HAL_GPIO_Init(GPIOE, &gpio);
// PE5: DP83848_INT
gpio.Mode = GPIO_MODE_INPUT;
gpio.Pin = GPIO_PIN_5;
HAL_GPIO_Init(GPIOE, &gpio);
// PG11: ETH_TX_EN
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pin = GPIO_PIN_11;
HAL_GPIO_Init(GPIOG, &gpio);
如何清理电脑缓存HAL_Delay(100); // 延长复位时间, 以免通电后检测不到中断
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_SET); // 撤销DP83848复位信号
// 根据器件ID⽣成MAC地址
uid = HAL_GetUIDw0() + HAL_GetUIDw1() + HAL_GetUIDw2();
memcpy(dp83848_mac + 3, &uid, 3);
// 初始化ETH
__HAL_RCC_ETH1MAC_CLK_ENABLE();
消炎面膜__HAL_RCC_ETH1RX_CLK_ENABLE();
__HAL_RCC_ETH1TX_CLK_ENABLE();
heth.Instance = ETH;
heth.Init.MACAddr = dp83848_mac;
heth.Init.MediaInterface = HAL_ETH_RMII_MODE;
heth.Init.RxBuffLen = ETH_MAX_PACKET_SIZE;
heth.Init.RxDesc = dp83848_rx;
heth.Init.TxDesc = dp83848_tx;
HAL_ETH_Init(&heth);
HAL_ETH_WritePHYRegister(&heth, DP83848_PHY_ADDRESS, PHY_MICR, PHY_MICR_INT_OE | PHY_MICR_INT_EN); // 打开中断输出 HAL_ETH_WritePHYRegister(&heth, DP83848_PHY_ADDRESS, PHY_MISR, PHY_MISR_LINK_INT_EN); // 打开链路状态中断
HAL_ETH_GetMACFilterConfig(&heth, &macfilter);
macfilter.BroadcastFilter = ENABLE; // 要使⽤IPv4, 必须要能接收⼴播帧
macfilter.PassAllMulticast = ENABLE; // 要使⽤IPv6, 必须要能接收多播帧
HAL_ETH_SetMACFilterConfig(&heth, &macfilter);
for (i = 0; i < ETH_RX_DESC_CNT; i++)
处暑节气HAL_ETH_DescAssignMemory(&heth, i, dp83848_rxbuf[i], NULL);
}