【MCU】STM32F107VC单片机驱动DP83848以太网PHY芯片,移植LWIP 2.1.2协议栈,并加入网线热插拔检测的功能(HAL库)

本文详细介绍了如何在STM32微控制器上配置DP83848以太网控制器,包括时钟设置、GPIO初始化、MII/RMII接口选择、MAC地址生成、中断处理和DP83848初始化函数。还讲解了 lwip 网络协议栈的初始化过程,如设置IP地址、启动DHCP、创建IPv6本地链路地址以及处理数据包发送和接收。最后展示了程序运行时的输出结果,包括DHCP获取IP地址、网线插拔中断处理和网络通信功能。

开发板:

 杜邦线传输高速数字信号容易出错,所以在用面包板搭建开发环境时,最好使用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_Sta
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值