没有合适的资源?快使用搜索试试~ 我知道了~
首页【程序】STM32F107VC单片机驱动DP83848以太网PHY芯片,移植lwip 2.1.2协议栈,并加入网线热插拔检测的功能(HAL库)
Keil5工程下载地址:https://pan.baidu.com/s/1Uf0eRFB35_-Sw_ovQf2Kwg(提取码:694k) 开发板: 杜邦线传输高速数字信号容易出错,所以在用面包板搭建开发环境时,最好使用25MHz时钟的MII接口。如果要用50MHz的RMII接口,那么杜邦线必须要非常非常短,否则时钟信号一旦失真,就无法收发数据! 如果DP83848的运行时钟是由单片机的PA8 MCO引脚输出的,那么DP83848的复位引脚一定要接一个下拉电阻。当单片机没有启动的时候,这个下拉电阻会使DP83848处于复位状态。因为单片机没有运行的时候,DP83848没有时钟信号,如果此时D
资源详情
资源评论
资源推荐

【程序】【程序】STM32F107VC单片机驱动单片机驱动DP83848以太网以太网PHY芯芯
片,移植片,移植lwip 2.1.2协议栈,并加入网线热插拔检测的功能协议栈,并加入网线热插拔检测的功能
((HAL库)库)
Keil5工程下载地址:https://pan.baidu.com/s/1Uf0eRFB35_-Sw_ovQf2Kwg(提取码:694k)
开发板:
杜邦线传输高速数字信号容易出错,所以在用面包板搭建开发环境时,最好使用25MHz时钟的MII接口。如果要用50MHz的
RMII接口,那么杜邦线必须要非常非常短,否则时钟信号一旦失真,就无法收发数据!
如果如果DP83848的运行时钟是由单片机的的运行时钟是由单片机的PA8 MCO引脚输出的,那么引脚输出的,那么DP83848的复位引脚一定要接一个下拉电阻。的复位引脚一定要接一个下拉电阻。当单片机没
有启动的时候,这个下拉电阻会使DP83848处于复位状态。因为单片机没有运行的时候,DP83848没有时钟信号,如果此时
DP83848没有处于复位状态,将会对电路产生很大的影响!比如启动时单片机的串口输出会乱码。
网口的灯不要接反了,黄灯接LED_ACT,绿灯接LED_LINK。插了网线后,正常情况下是黄灯闪烁,绿灯常亮。
程序里面的USE_MII宏决定了是使用MII接口还是RMII接口。ETH_REMAP宏决定了是否重映射ETH引脚。
#define ETH_REMAP 1
#define USE_MII 0
DP83848的复位引脚接到PB15上(带外部下拉电阻),中断引脚接到PB14上(带外部上拉电阻)。
【代码讲解】
程序里面使用的lwip2.1.2除了下面几个文件是修改过的以外,其余的都是官网的原始文件:
修改的文件: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.2版本中的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};
osc.OscillatorType = RCC_OSCILLATORTYPE_HSE;
osc.HSEPredivValue = RCC_HSE_PREDIV_DIV5;
osc.HSEState = RCC_HSE_ON;

osc.PLL.PLLMUL = RCC_PLL_MUL9;
osc.PLL.PLLSource = RCC_PLLSOURCE_HSE;
osc.PLL.PLLState = RCC_PLL_ON;
osc.PLL2.HSEPrediv2Value = RCC_HSE_PREDIV2_DIV5;
osc.PLL2.PLL2MUL = RCC_PLL2_MUL8;
osc.PLL2.PLL2State = RCC_PLL2_ON;
osc.Prediv1Source = RCC_PREDIV1_SOURCE_PLL2;
status = HAL_RCC_OscConfig(&osc);
assert_param(status == HAL_OK);
// ADC时钟不能超过14MHz, 所以需要6分频, 72MHz经过分频后是12MHz
__HAL_RCC_ADC_CONFIG(RCC_ADCPCLK2_DIV6);
// 配置AHB和APB2总线时钟为72MHz, APB1总线时钟为36MHz
clk.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 |
RCC_CLOCKTYPE_PCLK2;
clk.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clk.AHBCLKDivider = RCC_SYSCLK_DIV1;
clk.APB1CLKDivider = RCC_HCLK_DIV2;
clk.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&clk, FLASH_LATENCY_2);
}
该函数将系统时钟配置为72MHz:AHB和APB2时钟为72MHz,APB1时钟为36MHz。
初始化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;
int ret;
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* set MAC hardware address */
ret = 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->hwaddr[5]);
/* maximum transfer unit */
netif->mtu = 1500;
/* 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_MLD6; // 这里MLD6是启用IPv6多播
if (ret == 0)
netif->flags |= 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 set mld_mac_filter previously. */
if (netif->mld_mac_filter != NULL) {
ip6_addr_t ip6_allnodes_ll;
ip6_addr_set_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 else is needed to initialize interface. */
}
在这个函数里面,调用了DP83848_Init初始化网口。如果此时板子是插了网线的,那么函数返回0,没有插网线时返回-1。接
着调用DP83848_GetMACAddress将网卡地址(在程序中由STM32单片机的器件ID生成)告诉lwip。接下来,如果插了网线
(ret==0),则设置NETIF_FLAG_LINK_UP标志,告诉lwip网卡现在有网,这个操作和netif_set_link_up是等价的。
NETIF_FLAG_MLD6表示启用IPv6多播功能,IPv6的运行依赖于多播,不打开多播的话IPv6是不能正常工作的。
接下来看看DP83848_Init函数:
int DP83848_Init(void)
{
uint32_t uid;
ETH_MACInitTypeDef macconf = {0};
GPIO_InitTypeDef gpio;
HAL_StatusTypeDef status;
RCC_PLLI2SInitTypeDef plli2s;
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
// PA2: MDIO, PA8: MCO
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pin = GPIO_PIN_2 | GPIO_PIN_8;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &gpio);
// PB11: TX_EN, PB12~13: TXD0~1
gpio.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
HAL_GPIO_Init(GPIOB, &gpio);
// PC1: MDC
gpio.Pin = GPIO_PIN_1;
HAL_GPIO_Init(GPIOC, &gpio);
#if ETH_REMAP
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_AFIO_REMAP_ETH_ENABLE();
#endif
#if USE_MII
// PB8: TXD3
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pin = GPIO_PIN_8;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &gpio);
// PC2: TXD2
gpio.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOC, &gpio);
#else
// 必须在打开ETH的三个时钟前选择好RMII接口
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_ETH_RMII();
#endif
// PB15: RESET_N (必须接外部下拉电阻, 否则单片机启动时串口会乱码)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET); // 保证DP83848处于复位状态
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Pin = GPIO_PIN_15;
gpio.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &gpio);
// MCO给DP83848提供25MHz或50MHz的时钟
plli2s.HSEPrediv2Value = RCC_HSE_PREDIV2_DIV5;
plli2s.PLLI2SMUL = RCC_PLLI2S_MUL10;
HAL_RCCEx_EnablePLLI2S(&plli2s);
剩余12页未读,继续阅读

















安全验证
文档复制为VIP权益,开通VIP直接复制

评论0