W5500简介(w5500具有8个Socket,TCPserver模式下最多支持8个客户端同时访问)

本文详细介绍了如何在STM32平台上移植W5500以太网芯片,从库文件介绍、移植步骤到官方库源码分析,涵盖了SPI驱动接口实现、网络信息配置和Socket测试。通过实例展示了TCP客户端的回环测试,以及W5500的初始化和配置,为开发者提供了清晰的移植指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://blog.csdn.net/wiznet2012/article/details/41279113
(此论坛为一个WIZnet用户开设的,论坛积累了大量的W5500相关应用及例程,具有很大的参考价值。)

1. 前言

W5500是一款高性价比的以太网芯片,其全球独一无二的全硬件TCPIP协议栈专利技术,解决了嵌入式以太网的接入问题,简单易用,安全稳定,是物联网设备的首选解决方案。

WIZnet的官方库,官方库写得很好,移植也很简单,功能全面。
https://github.com/Wiznet/ioLibrary_Driver
官方资源:
https://www.iwiznet.cn/
https://www.w5500.com/

分以下几个方面介绍W5500:

W5500芯片简介

库文件组成介绍

库文件移植过程

官方库源码分析

2. W5500芯片简介

W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方 案。W5500 集成了 TCP/IP 协议栈,10/100M 以太网数据链路层(MAC) 及物理层(PHY),使得 用户使用单芯片就能够在他们的应用中拓展网络连接。

久经市场考验的 WIZnet 全硬件 TCP/IP 协议栈支持 TCP,UDP,IPv4,ICMP,ARP,IGMP 以及 PPPoE 协议。W5500 内嵌 32K 字节片上缓存以供以太网包处理。如果你使用 W5500, 你只需要一些简单 的 Socket 编程就能实现以太网应用。这将会比其他嵌入式以太网方案 更加快捷、简便。用户可以同 时使用 8 个硬件 Socket 独立通讯。

W5500 提供了 SPI(外设串行接口)从而能够更加容易与外设 MCU 整合。而且, W5500 的使用了新的高效SPI协议支持 80MHz 速率,从而能够更好的实现高速网络通讯。 为了减少系统能耗, W5500 提供了网络唤醒模式(WOL)及掉电模式供客户选择使用。

特点:

支持硬件 TCP/IP 协议:TCP, UDP, ICMP, IPv4, ARP, IGMP, PPPoE
支持 8 个独立端口(Socket)同时通讯
支持掉电模式,支持网络唤醒
支持高速串行外设接口(SPI 模式 0,3)
内部 32K 字节收发缓存
内嵌 10BaseT/100BaseTX 以太网物理层(PHY)
支持自动协商(10/100-Based 全双工/半双工)
不支持 IP 分片
3.3V 工作电压,I/O 信号口 5V 耐压;
LED 状态显示(全双工/半双工,网络连接,网络速度,活动状态)
48 引脚 LQFP 无铅封装(7x7mm, 0.5mm 间距)
适用领域:

家庭网络设备: 机顶盒、个人录像机、数码媒体适配器
串行转以太网: 门禁控制、LED 显示屏、无线 AP 继电器等
并行转以太网: POS/微型打印机、复印机
USB 转以太网: 存储设备、网络打印机
GPIO 转以太网: 家庭网络传感器
安全系统: 数字录像机、网络摄像机、信息亭
工厂和楼宇自动化控制系统
医疗监测设备
嵌入式服务器

在这里插入图片描述

3. 库文件组成介绍

W5500官方提供了ioLibrary 4.0.0,ioLibrary是WIZnet芯片的以太网驱动库,它包括驱动程序和应用程序协议。该驱动程序(ioLibrary)可用于WIZnet TCP / IP芯片的应用设计,如W5500,W5300,W5200,W5100 W5100S。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 库文件移植过程

软件准备

需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码;
准备一个串口调试助手,这里我使用的是Serial Port Utility;
准备一个网络调试助手,这里我使用的是sockettool;
链接:https://pan.baidu.com/s/1Cpp4yCPaDDEcdybWZKIsDw
提取码:q14o

4.1 添加驱动库到工程中

在工程目录下新建 Hardware/W5500,将驱动库中的三个文件夹都复制过来:
在这里插入图片描述
注意,这其中只有Ethernet下的文件是必需的,其余两个文件夹的文件可选添加,在后面进行测试时会用到。

4.2 接下来将Ethernet目录下和W5500相关的文件添加到MDK工程中

在这里插入图片描述
添加头文件路径:
在这里插入图片描述
确保C99模式开启(STM32Cubemx生成的工程中默认开启):
在这里插入图片描述

4.3 配置所使用的芯片型号

打开wizchip_conf.h文件,在最开始修改宏定义_WIZCHIP_,该宏定义指明了我们所用的芯片型号,设置为W5500:
在这里插入图片描述

5. 适配W5500官方驱动

W5500官方驱动库中通过 _WIZCHIP 结构体中定义的一组函数指针来管理spi驱动,为了防止添加后直接报错,在 wizchip_conf.c 中提供了这些函数指针的默认实现,都为空函数,所以此时编译时不会报错。

5.1 添加移植适配文件

接下来我们在项目工程中,新建w5500_port_hal.h文件和w5500_port_hal.c文件来存放自己的实现,并利用驱动库提供的接口,注册到驱动库中。

在这里插入图片描述
加入到MDK工程中:
在这里插入图片描述
添加头文件路径:
在这里插入图片描述

5.2 编写头文件

编写w5500_port_hal.h文件:

#ifndef _W5500_PORT_HAL_
#define _W5500_PORT_HAL_

#include "wizchip_conf.h"
#include "stm32l4xx.h"
#include <string.h>
#include <stdio.h>

#define W5500_SPI_HANDLE    hspi1
#define W5500_CS_PORT       GPIOA
#define W5500_CS_PIN        GPIO_PIN_4
#define W5500_RST_PORT      GPIOC
#define W5500_RST_PIN       GPIO_PIN_9

#define DEFAULT_MAC_ADDR    {0x00,0xf1,0xbe,0xc4,0xa1,0x05}
#define DEFAULT_IP_ADDR     {192,168,0,136}
#define DEFAULT_SUB_MASK    {255,255,255,0}
#define DEFAULT_GW_ADDR     {192,168,0,1}
#define DEFAULT_DNS_ADDR    {8,8,8,8}

/* 定义该宏则表示使用自动协商模式,取消则设置为100M全双工模式 */
#define USE_AUTONEGO

/* 定义该宏则表示在初始化网络信息时设置DHCP */
//#define USE_DHCP

extern SPI_HandleTypeDef W5500_SPI_HANDLE;

void w5500_network_info_show(void);
int w5500_init(void);

#endif


5.3 编写c文件

首先包含头文件:

#include "w5500_port_hal.h"

5.3.1 SPI驱动接口实现

接着用HAL库实现W5500驱动所需要的8个SPI函数指针的具体函数:

/**
 * @brief   enter critical section
 * @param   none
 * @return  none
 */
static void w5500_cris_enter(void)
{
    __set_PRIMASK(1);
}

/**
 * @brief   exit critical section
 * @param   none
 * @return  none
 */
static void w5500_cris_exit(void)
{
    __set_PRIMASK(0);
}

/**
 * @brief   select chip
 * @param   none
 * @return  none
 */
static void w5500_cs_select(void)
{
    HAL_GPIO_WritePin(W5500_CS_PORT, W5500_CS_PIN, GPIO_PIN_RESET);
}

/**
 * @brief   deselect chip
 * @param   none
 * @return  none
 */
static void w5500_cs_deselect(void)
{
    HAL_GPIO_WritePin(W5500_CS_PORT, W5500_CS_PIN, GPIO_PIN_SET);
}

/**
 * @brief   read byte in SPI interface
 * @param   none
 * @return  the value of the byte read
 */
static uint8_t w5500_spi_readbyte(void)
{
    uint8_t value;
    
    if (HAL_SPI_Receive(&W5500_SPI_HANDLE, &value, 1, 1000) != HAL_OK) {
        value = 0;
    }
    
    return value;
}

/**
 * @brief   write byte in SPI interface
 * @param   wb  the value to write
 * @return  none
 */
static void w5500_spi_writebyte(uint8_t wb)
{
    HAL_SPI_Transmit(&W5500_SPI_HANDLE, &wb, 1, 1000);
}

/**
 * @brief   burst read byte in SPI interface
 * @param   pBuf    pointer of data buf
 * @param   len     number of bytes to read
 * @return  none
 */
static void w5500_spi_readburst(uint8_t* pBuf, uint16_t len)
{
    if (!pBuf) {
        return;
    }
    
    HAL_SPI_Receive(&W5500_SPI_HANDLE, pBuf, len, 1000);
}

/**
 * @brief   burst write byte in SPI interface
 * @param   pBuf    pointer of data buf
 * @param   len     number of bytes to write
 * @return  none
 */
static void w5500_spi_writeburst(uint8_t* pBuf, uint16_t len)
{
    if (!pBuf) {
        return;
    }
    
    HAL_SPI_Transmit(&W5500_SPI_HANDLE, pBuf, len, 1000);
}

/**
 * @brief   hard reset
 * @param   none
 * @return  none
 */
static void w5500_hard_reset(void)
{
    HAL_GPIO_WritePin(W5500_RST_PORT, W5500_RST_PIN, GPIO_PIN_RESET);
    HAL_Delay(50);
    HAL_GPIO_WritePin(W5500_RST_PORT, W5500_RST_PIN, GPIO_PIN_SET);
    HAL_Delay(10);
}

5.3.2 芯片操作实现

基于官方驱动库编写芯片初始化函数,并设置socket的发送和接收缓冲大小(默认2KB):

/**
 * @brief   Initializes WIZCHIP with socket buffer size
 * @param   none
 * @return  errcode
 * @retval  0   success
 * @retval  -1  fail
 */
static int w5500_chip_init(void)
{
    /* default size is 2KB */
    
    return wizchip_init(NULL, NULL);
}

再编写硬件PHY配置函数,比如工作模式、速率,以及是否协商等配置:
自动协商功能需要在上电前连接好网线至路由器,手动配置模式不需要。

/**
 * @brief   set phy config if autonego is disable
 * @param   none
 * @return  none
 */
static void w5500_phy_init(void)
{
#ifdef USE_AUTONEGO
    // no thing to do
#else
    wiz_PhyConf conf;
    
    conf.by = PHY_CONFBY_SW;
    conf.mode = PHY_MODE_MANUAL;
    conf.speed = PHY_SPEED_100;
    conf.duplex = PHY_DUPLEX_FULL;
    
    wizphy_setphyconf(&conf);
#endif
}

再编写配置和打印网络信息函数:

/**
 * @brief   initializes the network infomation
 * @param   none
 * @return  none
 */
static void w5500_network_info_init(void)
{
    wiz_NetInfo info;
    
    uint8_t mac[6] = DEFAULT_MAC_ADDR;
    uint8_t ip[4] = DEFAULT_IP_ADDR;
    uint8_t sn[4] = DEFAULT_SUB_MASK;
    uint8_t gw[4] = DEFAULT_GW_ADDR;
    uint8_t dns[4] = DEFAULT_DNS_ADDR;
    
    memcpy(info.mac, mac, 6);
    memcpy(info.ip, ip, 4);
    memcpy(info.sn, sn, 4);
    memcpy(info.gw, gw, 4);
    memcpy(info.dns, dns, 4);
    
#ifdef USE_DHCP
    info.dhcp = NETINFO_DHCP;
#else
    info.dhcp = NETINFO_STATIC;
#endif
    
    wizchip_setnetinfo(&info);
}

/**
 * @brief   read and show the network infomation
 * @param   none
 * @return  none
 */
void w5500_network_info_show(void)
{
    wiz_NetInfo info;
    
    wizchip_getnetinfo(&info);
    
    printf("w5500 network infomation:\r\n");
    printf("  -mac:%d:%d:%d:%d:%d:%d\r\n", info.mac[0], info.mac[1], info.mac[2], 
            info.mac[3], info.mac[4], info.mac[5]);
    printf("  -ip:%d.%d.%d.%d\r\n", info.ip[0], info.ip[1], info.ip[2], info.ip[3]);
    printf("  -sn:%d.%d.%d.%d\r\n", info.sn[0], info.sn[1], info.sn[2], info.sn[3]);
    printf("  -gw:%d.%d.%d.%d\r\n", info.gw[0], info.gw[1], info.gw[2], info.gw[3]);
    printf("  -dns:%d.%d.%d.%d\r\n", info.dns[0], info.dns[1], info.dns[2], info.dns[3]);
    
    if (info.dhcp == NETINFO_DHCP) {
        printf("  -dhcp_mode: dhcp\r\n");
    } else {
        printf("  -dhcp_mode: static\r\n");
    }
}

最后编写w5500初始化函数:

/**
 * @brief   w5500 init
 * @param   none
 * @return  errcode
 * @retval  0   success
 * @retval  -1  chip init fail
 */
int w5500_init(void)
{
    /* W5500 hard reset */
    w5500_hard_reset();
    
    /* Register spi driver function */
    reg_wizchip_cris_cbfunc(w5500_cris_enter, w5500_cris_exit);
    reg_wizchip_cs_cbfunc(w5500_cs_select, w5500_cs_deselect);
    reg_wizchip_spi_cbfunc(w5500_spi_readbyte, w5500_spi_writebyte);
    reg_wizchip_spiburst_cbfunc(w5500_spi_readburst, w5500_spi_writeburst);

    /* socket buffer size init */
    if (w5500_chip_init() != 0) {
        return -1;
    }
    
    /* phy init */
    w5500_phy_init();
    
    /* network infomation init */
    w5500_network_info_init();
    
    /* show network infomation */
    w5500_network_info_show();
    
    return 0;
}

5.4 测试W5500初始化

在main.c中包含头文件:

#include "w5500_port_hal.h"

在main函数中测试初始化函数:

/* USER CODE BEGIN 2 */
 printf("W5500 test on BearPi board by Mculover666\r\n");
 
 int ret;
 ret = w5500_init();
 if (ret != 0) {
   printf("w5500 init fail, ret is %d\r\n", ret);
 } else {
   printf("w5500 init success\r\n");
 }

 /* USER CODE END 2 */

编译,下载,暂不运行。

因为使用的是自动协商模式,确保W5500网线连接至路由器,然后上电运行,串口日志如下:
在这里插入图片描述
确保windows主机和开发板连接至同一个路由器(或者同一网段之下),ping一下开发板测试:
在这里插入图片描述

5.5 W5500的Socket测试

W5500官方驱动库中实现了标准Socket API,在socket.h和socket.c中,可以直接调用编写TCP或者UDP测试程序。

W5500官方驱动库中也提供了一个Socket的使用案例,其中包括TCP服务端、TCP客户端、UDP服务端的回环测试,在application/loopback文件夹中:
在这里插入图片描述
本文接下来将进行TCP客户端的回环测试。

5.6 开启TCP服务器

在电脑上开启网络调试助手,建立一个TCP server,监听本机8000端口:
在这里插入图片描述

5.7 添加loopback测试文件

在MDK中添加c文件:
在这里插入图片描述

添加头文件路径:
在这里插入图片描述

5.8 调用loopback测试函数

在main函数的开始创建变量:

/* USER CODE BEGIN 1 */
int ret;
uint8_t destip[4] = {192, 168, 0, 100};
uint16_t destport = 8000;
/* USER CODE END 1 */

然后在while循环中调用:

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
  ret = loopback_tcpc(0, buffer, destip, destport);
  if (ret != 1) {
      printf("loopback_tcpc err is %d\r\n", ret);
  }
}
/* USER CODE END 3 */

5.9 测试结果

编译、下载到开发板中运行,串口日志如下:

在这里插入图片描述

在网络调试助手向开发板发送消息,会收到开发板发回的消息:
在这里插入图片描述
若开发板提示连接超时,无法连接TCP服务器,应当检查是否关闭windows网络防火墙。

6. 官方库源码分析

7 RT1052移植W5500

pin_mux.c内容截取

void BOARD_InitPins(void) {
  CLOCK_EnableClock(kCLOCK_Iomuxc);           

  IOMUXC_SetPinMux(
		IOMUXC_GPIO_B0_00_GPIO2_IO00,		
		0U); 
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_B0_01_GPIO2_IO01,        
      0U); 
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_B0_02_GPIO2_IO02,        
      0U); 
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_B0_03_GPIO2_IO03,        
      0U); 
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_B0_04_GPIO2_IO04,        
      0U); 

  IOMUXC_SetPinMux(
      IOMUXC_GPIO_AD_B0_04_GPIO1_IO04,        /* GPIO_AD_B0_04 is configured as GPIO1_IO04 */
      0U); 

  IOMUXC_SetPinMux(
      IOMUXC_GPIO_AD_B0_09_GPIO1_IO09,        /* GPIO_AD_B0_09 is configured as GPIO1_IO09 */
      0U); 	

  IOMUXC_SetPinMux(
      IOMUXC_GPIO_AD_B0_00_LPSPI3_SCK,        /* GPIO_AD_B0_00 is configured as LPSPI3_SCK */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_AD_B0_01_LPSPI3_SDO,        /* GPIO_AD_B0_01 is configured as LPSPI3_SDO */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_AD_B0_02_LPSPI3_SDI,        /* GPIO_AD_B0_02 is configured as LPSPI3_SDI */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_AD_B0_03_LPSPI3_PCS0,       /* GPIO_AD_B0_03 is configured as LPSPI3_PCS0 */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_AD_B0_12_LPUART1_TX,        /* GPIO_AD_B0_12 is configured as LPUART1_TX */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_AD_B0_13_LPUART1_RX,        /* GPIO_AD_B0_13 is configured as LPUART1_RX */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK,        /* GPIO_SD_B0_00 is configured as LPSPI1_SCK */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0,       /* GPIO_SD_B0_01 is configured as LPSPI1_PCS0 */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO,        /* GPIO_SD_B0_02 is configured as LPSPI1_SDO */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI,        /* GPIO_SD_B0_03 is configured as LPSPI1_SDI */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */

  IOMUXC_SetPinConfig(
	  IOMUXC_GPIO_AD_B0_09_GPIO1_IO09,		/* GPIO_AD_B0_09 PAD functional properties : */
      0x10B0u);								/* Slew Rate Field: Slow Slew Rate
													   Drive Strength Field: R0/6
													   Speed Field: medium(100MHz)
													   Open Drain Enable Field: Open Drain Disabled
													   Pull / Keep Enable Field: Pull/Keeper Enabled
													   Pull / Keep Select Field: Keeper
													   Pull Up / Down Config. Field: 100K Ohm Pull Down
													   Hyst. Enable Field: Hysteresis Disabled */
														 
  IOMUXC_SetPinConfig(
	  IOMUXC_GPIO_AD_B0_04_GPIO1_IO04,		/* GPIO_AD_B0_04 PAD functional properties : */
      0x10B0u);								/* Slew Rate Field: Slow Slew Rate
													   Drive Strength Field: R0/6
													   Speed Field: medium(100MHz)
													   Open Drain Enable Field: Open Drain Disabled
													   Pull / Keep Enable Field: Pull/Keeper Enabled
													   Pull / Keep Select Field: Keeper
													   Pull Up / Down Config. Field: 100K Ohm Pull Down
													   Hyst. Enable Field: Hysteresis Disabled */														 
														 

  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_AD_B0_00_LPSPI3_SCK,        /* GPIO_AD_B0_00 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_AD_B0_01_LPSPI3_SDO,        /* GPIO_AD_B0_01 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_AD_B0_02_LPSPI3_SDI,        /* GPIO_AD_B0_02 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_AD_B0_03_LPSPI3_PCS0,       /* GPIO_AD_B0_03 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_AD_B0_12_LPUART1_TX,        /* GPIO_AD_B0_12 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_AD_B0_13_LPUART1_RX,        /* GPIO_AD_B0_13 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK,        /* GPIO_SD_B0_00 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0,       /* GPIO_SD_B0_01 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO,        /* GPIO_SD_B0_02 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI,        /* GPIO_SD_B0_03 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
IOMUXC_SetPinConfig(
      IOMUXC_GPIO_B0_00_GPIO2_IO00,        
      0x10B0u);  
IOMUXC_SetPinConfig(
      IOMUXC_GPIO_B0_01_GPIO2_IO01,        
      0x10B0u); 
IOMUXC_SetPinConfig(
      IOMUXC_GPIO_B0_02_GPIO2_IO02,        
      0x10B0u); 
IOMUXC_SetPinConfig(
      IOMUXC_GPIO_B0_03_GPIO2_IO03,        
      0x10B0u); 
IOMUXC_SetPinConfig(
      IOMUXC_GPIO_B0_04_GPIO2_IO04,        
      0x10B0u); 

}

lpspi_interrupt.c内容截取

#include "fsl_device_registers.h"
#include "fsl_debug_console.h"
#include "fsl_lpspi.h"
#include "fsl_gpio.h"
#include "system_MIMXRT1052.h"
#include "clock_config.h"
#include "board.h"
#include "wizchip_conf.h"
#include "w5500.h"
#include "socket.h"
#include "fsl_common.h"
#include "pin_mux.h"
#if ((defined FSL_FEATURE_SOC_INTMUX_COUNT) && (FSL_FEATURE_SOC_INTMUX_COUNT))
#include "fsl_intmux.h"
#endif
/*******************************************************************************
* Definitions
******************************************************************************/
#define EXAMPLE_LED_GPIO BOARD_USER_LED_GPIO
#define EXAMPLE_LED_GPIO_PIN BOARD_USER_LED_GPIO_PIN

/* Master related */
#define EXAMPLE_LPSPI_MASTER_BASEADDR (LPSPI3)
#define EXAMPLE_LPSPI_MASTER_IRQN (LPSPI3_IRQn)
#define EXAMPLE_LPSPI_MASTER_IRQHandler (LPSPI3_IRQHandler)

#define EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT (kLPSPI_Pcs0)
#define EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER (kLPSPI_MasterPcs0)

/* Slave related */
#define EXAMPLE_LPSPI_SLAVE_BASEADDR (LPSPI1)
#define EXAMPLE_LPSPI_SLAVE_IRQN (LPSPI1_IRQn)
#define EXAMPLE_LPSPI_SLAVE_IRQHandler (LPSPI1_IRQHandler)

#define EXAMPLE_LPSPI_SLAVE_PCS_FOR_INIT (kLPSPI_Pcs0)
#define EXAMPLE_LPSPI_SLAVE_PCS_FOR_TRANSFER (kLPSPI_SlavePcs0)

/* Select USB1 PLL PFD0 (720 MHz) as lpspi clock source */
#define EXAMPLE_LPSPI_CLOCK_SOURCE_SELECT (1U)
/* Clock divider for master lpspi clock source */
#define EXAMPLE_LPSPI_CLOCK_SOURCE_DIVIDER (7U)

#define EXAMPLE_LPSPI_CLOCK_FREQ (CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (EXAMPLE_LPSPI_CLOCK_SOURCE_DIVIDER + 1U))

#define EXAMPLE_LPSPI_MASTER_CLOCK_FREQ EXAMPLE_LPSPI_CLOCK_FREQ
#define EXAMPLE_LPSPI_SLAVE_CLOCK_FREQ EXAMPLE_LPSPI_CLOCK_FREQ

#define TRANSFER_SIZE (512U)        /*! Transfer dataSize .*/
#define TRANSFER_BAUDRATE (1000000U) /*! Transfer baudrate - 1000k */

/*******************************************************************************
* Prototypes
******************************************************************************/
/* LPSPI user callback */
void LPSPI_SlaveUserCallback(LPSPI_Type *base, lpspi_slave_handle_t *handle, status_t status, void *userData);
void LPSPI_MasterUserCallback(LPSPI_Type *base, lpspi_master_handle_t *handle, status_t status, void *userData);
uint8_t LPSPI3_ReadWriteByte(uint8_t TxData);

void SysTick_DelayTicks(uint32_t n);

/*******************************************************************************
* W5500移植相关函数
******************************************************************************/
#define W5500_RST_GPIO      GPIO2
#define W5500_RST_GPIO_PIN  (0U)
#define W5500_CS_GPIO       GPIO2
#define W5500_CS_GPIO_PIN   (2U)


#define W5500_REST_L GPIO_PinWrite(W5500_RST_GPIO, W5500_RST_GPIO_PIN, 0)
#define W5500_REST_H GPIO_PinWrite(W5500_RST_GPIO, W5500_RST_GPIO_PIN, 1)
#define W5500_CS_L GPIO_PinWrite(W5500_CS_GPIO, W5500_CS_GPIO_PIN, 0)
#define W5500_CS_H GPIO_PinWrite(W5500_CS_GPIO, W5500_CS_GPIO_PIN, 1)


//W5500芯片复位
void W5500_RST(void)
{
	W5500_REST_L; //RST置低复位
	SysTick_DelayTicks(100U);
	W5500_REST_H; //RST置高
	SysTick_DelayTicks(100U);
}

//SPI写一字节数据
void SPI_WriteByte(uint8_t data)
{
	uint8_t ret;

	ret = LPSPI3_ReadWriteByte(data);
	SysTick_DelayTicks(1U);
}

//SPI读取一字节数据
uint8_t SPI_ReadByte(void)
{
	uint8_t ret;

	ret = LPSPI3_ReadWriteByte(0xff);
	SysTick_DelayTicks(1U);
	
	return ret;
}

uint8_t W5500_WRITE_REG(uint16_t AddrSel, uint8_t data)
{
    uint8_t ret;

    SysTick_DelayTicks(1U);
	W5500_CS_H;
    SysTick_DelayTicks(1U);
	W5500_CS_L;
	
    ret = LPSPI3_ReadWriteByte(AddrSel>>8);
    SysTick_DelayTicks(1U);
	ret = LPSPI3_ReadWriteByte(AddrSel&0x00ff);
    SysTick_DelayTicks(1U);
	ret = LPSPI3_ReadWriteByte(0x04); //BSB[4:0] = '00000', RWB = '1'
    SysTick_DelayTicks(1U);
    ret = LPSPI3_ReadWriteByte(data);
    SysTick_DelayTicks(1U);
	
    W5500_CS_H;
	
    return ret;
}

uint8_t W5500_READ_REG(uint16_t AddrSel)
{
	uint8_t ret = 0;
	SysTick_DelayTicks(1U);
	W5500_CS_H;
	SysTick_DelayTicks(1U);
	W5500_CS_L;

	ret = LPSPI3_ReadWriteByte(AddrSel>>8);
    SysTick_DelayTicks(1U);
    ret = LPSPI3_ReadWriteByte(AddrSel&0xff);
    SysTick_DelayTicks(1U);
	ret = LPSPI3_ReadWriteByte(0x00); //BSB[4:0] = '00000', RWB = '0'
    SysTick_DelayTicks(1U);
	ret = LPSPI3_ReadWriteByte(0xff);
	SysTick_DelayTicks(1U);

	W5500_CS_H;

    return ret;
}

/*******************************************************************************
* W5500移植4个回调函数定义如下
******************************************************************************/
//进入临界区
void SPI_CrisEnter(void)
{

}

//退出临界区
void SPI_CrisExit(void)
{
  
}

//W5500片选使能
void SPI_CS_Select(void)
{
	SysTick_DelayTicks(1U);
	W5500_CS_H;
    SysTick_DelayTicks(1U);
	W5500_CS_L;
}

//W5500片选取消
void SPI_CS_Deselect(void)
{
	SysTick_DelayTicks(1);
	W5500_CS_H;
}

//Ethernet通信配置初始化
/*******************************************************************************
* Ethernet通信配置初始化
* 通信配置初始化主要按照顺序依次执行以下3个函数。
* 1. 注册TCP/IP通信相关的回调函数 RegisterFunction();
* 2. 初始化芯片参数 ChipParametersConfig();
* 3. 初始化网络通信参数 NetworkParametersConfig();
******************************************************************************/
//初始化配置定义
wiz_NetInfo gWIZNETINFO = {
.mac = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
.ip = {192, 168, 0, 188},
.sn = {255, 255, 255, 0},
.gw = {192, 168, 0, 1},
.dns = {192, 168, 0, 1},
.dhcp = NETINFO_DHCP
};

//注册TCP/IP通信相关的回调函数 RegisterFunction()
void RegisterFunction(void)
{
	reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit); //注册临界区回调函数
	reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Select); //注册片选回调函数
	reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte); //注册SPI读写字节回调函数
}


//初始化芯片参数 ChipParametersConfig()
void ChipParametersConfig(void)
{
	uint8_t tmp;
	uint8_t memsize[2][8] = {{2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2}};
	  if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1)
		  {
			  PRINTF("WIZCHIP Initialized fail.\r\n");
			  while(1);
		  }
	
	  do{
		  if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1)
			  {
			  PRINTF("Unknown PHY Link stauts.\r\n");
			  }
		}while(tmp == PHY_LINK_OFF);

}

//初始化网络通信参数 NetworkParametersConfig()
void NetworkParametersConfig(void)
{
	uint8_t tmpstr[6];
	
	  ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);
	
	  ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);
	
	  ctlwizchip(CW_GET_ID,(void*)tmpstr);
		//串口打印出参数
		printf("\r\n=== %s NET CONF ===\r\n",(char*)tmpstr);
		printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",gWIZNETINFO.mac[0],gWIZNETINFO.mac[1],gWIZNETINFO.mac[2],
				gWIZNETINFO.mac[3],gWIZNETINFO.mac[4],gWIZNETINFO.mac[5]);
		printf("SIP: %d.%d.%d.%d\r\n", gWIZNETINFO.ip[0],gWIZNETINFO.ip[1],gWIZNETINFO.ip[2],gWIZNETINFO.ip[3]);
		printf("GAR: %d.%d.%d.%d\r\n", gWIZNETINFO.gw[0],gWIZNETINFO.gw[1],gWIZNETINFO.gw[2],gWIZNETINFO.gw[3]);
		printf("SUB: %d.%d.%d.%d\r\n", gWIZNETINFO.sn[0],gWIZNETINFO.sn[1],gWIZNETINFO.sn[2],gWIZNETINFO.sn[3]);
		printf("DNS: %d.%d.%d.%d\r\n", gWIZNETINFO.dns[0],gWIZNETINFO.dns[1],gWIZNETINFO.dns[2],gWIZNETINFO.dns[3]);
		printf("======================\r\n");

}

/*******************************************************************************
* 调用上述3个配置函数进行初始化即可,至此,W5500的移植全部完成,芯片配置完成。
******************************************************************************/
void W5500_ChipInit(void)
{
	gpio_pin_config_t sw_config = { 													\
				kGPIO_DigitalOutput, 1, kGPIO_NoIntmode,							\
			};																					\
	GPIO_PinInit(W5500_RST_GPIO, W5500_RST_GPIO_PIN, &sw_config);
	GPIO_PinInit(W5500_CS_GPIO, W5500_CS_GPIO_PIN, &sw_config);

	W5500_RST();
	RegisterFunction();
	ChipParametersConfig();
	NetworkParametersConfig();
	
}

/*******************************************************************************
* Variables
******************************************************************************/
uint8_t regData = 0xff;
uint16_t regRTD = 0;
float rtdValue = 0.0;
float rtdTemp = 0.0;


uint8_t masterRxData[TRANSFER_SIZE] = {0};
uint8_t masterTxData[TRANSFER_SIZE] = {0};
uint8_t slaveRxData[TRANSFER_SIZE] = {0};
uint8_t slaveTxData[TRANSFER_SIZE] = {0};

volatile uint32_t slaveTxCount;
volatile uint32_t slaveRxCount;
uint8_t g_slaveRxWatermark;
uint8_t g_slaveFifoSize;

volatile uint32_t masterTxCount;
volatile uint32_t masterRxCount;
uint8_t g_masterRxWatermark;
uint8_t g_masterFifoSize;

volatile bool isSlaveTransferCompleted = false;
volatile bool isMasterTransferCompleted = false;

volatile uint32_t g_systickCounter;
/* The PIN status */
volatile bool g_pinSet = false;

uint16_t reg = 0x0005;
uint8_t regRead = 0;
uint8_t regvalue = 192;

/*******************************************************************************
* Code
******************************************************************************/
void SysTick_Handler(void)
{
    if (g_systickCounter != 0U)
    {
        g_systickCounter--;
    }
}

void SysTick_DelayTicks(uint32_t n)
{
    g_systickCounter = n;
    while(g_systickCounter != 0U)
    {
    }
}

#if 1
void LPSPI_SlaveUserCallback(LPSPI_Type *base, lpspi_slave_handle_t *handle, status_t status, void *userData)
{
    if (status == kStatus_Success)
    {
        PRINTF("This is LPSPI slave transfer completed callback. \r\n");
        PRINTF("It's a successful transfer. \r\n\r\n");
    }
    else if (status == kStatus_LPSPI_Error)
    {
        PRINTF("This is LPSPI slave transfer completed callback. \r\n");
        PRINTF("Error occured in this transfer. \r\n\r\n");
    }
    else
    {
        __NOP();
    }

    isSlaveTransferCompleted = true;
}

void LPSPI_MasterUserCallback(LPSPI_Type *base, lpspi_master_handle_t *handle, status_t status, void *userData)
{
    isMasterTransferCompleted = true;
}

void EXAMPLE_LPSPI_SLAVE_IRQHandler(void)
{
    if (slaveRxCount < TRANSFER_SIZE)
    {
        while (LPSPI_GetRxFifoCount(EXAMPLE_LPSPI_SLAVE_BASEADDR))
        {
            slaveRxData[slaveRxCount] = LPSPI_ReadData(EXAMPLE_LPSPI_SLAVE_BASEADDR);
            slaveRxCount++;

            if (slaveTxCount < TRANSFER_SIZE)
            {
                LPSPI_WriteData(EXAMPLE_LPSPI_SLAVE_BASEADDR, slaveTxData[slaveTxCount]);
                slaveTxCount++;
            }
            if (slaveRxCount == TRANSFER_SIZE)
            {
                break;
            }
        }
    }

    /*Update rxWatermark. There isn't RX interrupt for the last datas if the RX count is not greater than rxWatermark.*/
    if ((TRANSFER_SIZE - slaveRxCount) <= g_slaveRxWatermark)
    {
        EXAMPLE_LPSPI_SLAVE_BASEADDR->FCR =
            (EXAMPLE_LPSPI_SLAVE_BASEADDR->FCR & (~LPSPI_FCR_RXWATER_MASK)) |
            LPSPI_FCR_RXWATER(((TRANSFER_SIZE - slaveRxCount) > 1) ? ((TRANSFER_SIZE - slaveRxCount) - 1U) : (0U));
    }

    /* Check if remaining receive byte count matches user request */
    if ((slaveRxCount == TRANSFER_SIZE) && (slaveTxCount == TRANSFER_SIZE))
    {
        isSlaveTransferCompleted = true;
        /* Disable interrupt requests */
        LPSPI_DisableInterrupts(EXAMPLE_LPSPI_SLAVE_BASEADDR, kLPSPI_RxInterruptEnable);
    }

#endif
    /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
        exception return operation might vector to incorrect interrupt */
#if defined __CORTEX_M && (__CORTEX_M == 4U)
    __DSB();
#endif
}

void EXAMPLE_LPSPI_MASTER_IRQHandler(void)
{
    if (masterRxCount < TRANSFER_SIZE)
    {
        /* First, disable the interrupts to avoid potentially triggering another interrupt
        * while reading out the RX FIFO as more data may be coming into the RX FIFO. We'll
        * re-enable the interrupts EXAMPLE_LPSPI_MASTER_BASEADDRd on the LPSPI state after reading out the FIFO.
        */
        LPSPI_DisableInterrupts(EXAMPLE_LPSPI_MASTER_BASEADDR, kLPSPI_RxInterruptEnable);

        while (LPSPI_GetRxFifoCount(EXAMPLE_LPSPI_MASTER_BASEADDR))
        {
            /*Read out the data*/
            masterRxData[masterRxCount] = LPSPI_ReadData(EXAMPLE_LPSPI_MASTER_BASEADDR);

            masterRxCount++;

            if (masterRxCount == TRANSFER_SIZE)
            {
                break;
            }
        }

        /* Re-enable the interrupts only if rxCount indicates there is more data to receive,
        * else we may get a spurious interrupt.
        * */
        if (masterRxCount < TRANSFER_SIZE)
        {
            /* Set the TDF and RDF interrupt enables simultaneously to avoid race conditions */
            LPSPI_EnableInterrupts(EXAMPLE_LPSPI_MASTER_BASEADDR, kLPSPI_RxInterruptEnable);
        }
    }

    /*Update rxWatermark. There isn't RX interrupt for the last datas if the RX count is not greater than rxWatermark.*/
    if ((TRANSFER_SIZE - masterRxCount) <= g_masterRxWatermark)
    {
        EXAMPLE_LPSPI_MASTER_BASEADDR->FCR =
            (EXAMPLE_LPSPI_MASTER_BASEADDR->FCR & (~LPSPI_FCR_RXWATER_MASK)) |
            LPSPI_FCR_RXWATER(((TRANSFER_SIZE - masterRxCount) > 1) ? ((TRANSFER_SIZE - masterRxCount) - 1U) : (0U));
    }

    if (masterTxCount < TRANSFER_SIZE)
    {
        while ((LPSPI_GetTxFifoCount(EXAMPLE_LPSPI_MASTER_BASEADDR) < g_masterFifoSize) &&
               (masterTxCount - masterRxCount < g_masterFifoSize))
        {
            /*Write the word to TX register*/
            LPSPI_WriteData(EXAMPLE_LPSPI_MASTER_BASEADDR, masterTxData[masterTxCount]);
            ++masterTxCount;

            if (masterTxCount == TRANSFER_SIZE)
            {
                break;
            }
        }
    }

    /* Check if we're done with this transfer.*/
    if ((masterTxCount == TRANSFER_SIZE) && (masterRxCount == TRANSFER_SIZE))
    {
        isMasterTransferCompleted = true;
        /* Complete the transfer and disable the interrupts */
        LPSPI_DisableInterrupts(EXAMPLE_LPSPI_MASTER_BASEADDR, kLPSPI_AllInterruptEnable);
    }
    /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
        exception return operation might vector to incorrect interrupt */
#if defined __CORTEX_M && (__CORTEX_M == 4U)
    __DSB();
#endif
}

void LPSPI3_Init()
{
    uint32_t i;
    lpspi_master_config_t masterConfig;
    lpspi_slave_config_t slaveConfig;
    uint32_t whichPcs;
    uint8_t txWatermark;

    /*Set up the transfer data*/
    for (i = 0; i < TRANSFER_SIZE; i++)
    {
        masterTxData[i] = i % 256;
        masterRxData[i] = 0;

        slaveTxData[i] = ~masterTxData[i];
        slaveRxData[i] = 0;
    }

    /*Master config*/
    masterConfig.baudRate = TRANSFER_BAUDRATE;
    masterConfig.bitsPerFrame = 8;
    masterConfig.cpol = kLPSPI_ClockPolarityActiveHigh;
    masterConfig.cpha = kLPSPI_ClockPhaseFirstEdge;
    masterConfig.direction = kLPSPI_MsbFirst;

    masterConfig.pcsToSckDelayInNanoSec = 1000000000 / masterConfig.baudRate;
    masterConfig.lastSckToPcsDelayInNanoSec = 1000000000 / masterConfig.baudRate;
    masterConfig.betweenTransferDelayInNanoSec = 1000000000 / masterConfig.baudRate;

    masterConfig.whichPcs = EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT;
    masterConfig.pcsActiveHighOrLow = kLPSPI_PcsActiveLow;

    masterConfig.pinCfg = kLPSPI_SdiInSdoOut;
    masterConfig.dataOutConfig = kLpspiDataOutRetained;

    LPSPI_MasterInit(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterConfig, EXAMPLE_LPSPI_MASTER_CLOCK_FREQ);

    /*Slave config*/
    slaveConfig.bitsPerFrame = masterConfig.bitsPerFrame;
    slaveConfig.cpol = masterConfig.cpol;
    slaveConfig.cpha = masterConfig.cpha;
    slaveConfig.direction = masterConfig.direction;

    slaveConfig.whichPcs = EXAMPLE_LPSPI_SLAVE_PCS_FOR_INIT;
    slaveConfig.pcsActiveHighOrLow = masterConfig.pcsActiveHighOrLow;

    slaveConfig.pinCfg = kLPSPI_SdiInSdoOut;
    slaveConfig.dataOutConfig = kLpspiDataOutRetained;

    LPSPI_SlaveInit(EXAMPLE_LPSPI_SLAVE_BASEADDR, &slaveConfig);

    /******************Set up slave first ******************/
    isSlaveTransferCompleted = false;
    slaveTxCount = 0;
    slaveRxCount = 0;
    whichPcs = EXAMPLE_LPSPI_SLAVE_PCS_FOR_INIT;

    /*The TX and RX FIFO sizes are always the same*/
    g_slaveFifoSize = LPSPI_GetRxFifoSize(EXAMPLE_LPSPI_SLAVE_BASEADDR);

    /*Set the RX and TX watermarks to reduce the ISR times.*/
    if (g_slaveFifoSize > 1)
    {
        txWatermark = 1;
        g_slaveRxWatermark = g_slaveFifoSize - 2;
    }
    else
    {
        txWatermark = 0;
        g_slaveRxWatermark = 0;
    }

    LPSPI_SetFifoWatermarks(EXAMPLE_LPSPI_SLAVE_BASEADDR, txWatermark, g_slaveRxWatermark);

    LPSPI_Enable(EXAMPLE_LPSPI_SLAVE_BASEADDR, false);
    EXAMPLE_LPSPI_SLAVE_BASEADDR->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
    LPSPI_Enable(EXAMPLE_LPSPI_SLAVE_BASEADDR, true);

    /*Flush FIFO , clear status , disable all the interrupts.*/
    LPSPI_FlushFifo(EXAMPLE_LPSPI_SLAVE_BASEADDR, true, true);
    LPSPI_ClearStatusFlags(EXAMPLE_LPSPI_SLAVE_BASEADDR, kLPSPI_AllStatusFlag);
    LPSPI_DisableInterrupts(EXAMPLE_LPSPI_SLAVE_BASEADDR, kLPSPI_AllInterruptEnable);

    EXAMPLE_LPSPI_SLAVE_BASEADDR->TCR =
        (EXAMPLE_LPSPI_SLAVE_BASEADDR->TCR &
         ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) |
        LPSPI_TCR_CONT(0) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(0) | LPSPI_TCR_TXMSK(0) | LPSPI_TCR_PCS(whichPcs);

    /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX ,
    * and you should also enable the INTMUX interrupt in your application.
    */
    //EnableIRQ(EXAMPLE_LPSPI_SLAVE_IRQN);

}


//LPSPI3 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
uint8_t LPSPI3_ReadWriteByte(uint8_t TxData)
{
    uint8_t spirxdata=0;
    uint8_t spitxdata=TxData;
    lpspi_transfer_t spi_tranxfer;
    lpspi_master_handle_t master_handle;

    spi_tranxfer.configFlags=kLPSPI_MasterPcs1|kLPSPI_MasterPcsContinuous;     //PCS1
    spi_tranxfer.txData=&spitxdata;                 //要发送的数据
    spi_tranxfer.rxData=&spirxdata;                 //接收到的数据
    spi_tranxfer.dataSize=1;                        //数据长度
    LPSPI_MasterTransferBlocking(LPSPI3,&spi_tranxfer);     //SPI阻塞发送
    return spirxdata;
}


/*!
* @brief Main function
*/
int main(void)
{
    /* Define the init structure for the output LED pin*/
    gpio_pin_config_t led_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
    uint8_t txData =0x15;

    BOARD_ConfigMPU();
    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();

    /*Set clock source for LPSPI*/
    CLOCK_SetMux(kCLOCK_LpspiMux, EXAMPLE_LPSPI_CLOCK_SOURCE_SELECT);
    CLOCK_SetDiv(kCLOCK_LpspiDiv, EXAMPLE_LPSPI_CLOCK_SOURCE_DIVIDER);

    /* Set systick reload value to generate 1ms interrupt */
    if(SysTick_Config(SystemCoreClock / 1000U))
    {
        while(1)
        {
        }
    }

    PRINTF("LPSPI functional example start.\r\n");
    /* Init output LED GPIO. */
    GPIO_PinInit(EXAMPLE_LED_GPIO, EXAMPLE_LED_GPIO_PIN, &led_config);
    GPIO_PinInit(BOARD_USER_SPI_CS0, BOARD_USER_SPI_CS0_PIN, &led_config);
    LPSPI3_Init(); //SPI3初始化
    W5500_ChipInit();

    while (1)
    {
        /* Delay 10 ms */
        SysTick_DelayTicks(500U);
#if 0
		W5500_WRITE_REG(reg, regvalue);
		regvalue++;
		regRead = W5500_READ_REG(reg);
		printf("%d\n", regRead);
#endif	
        if (g_pinSet)
        {
            GPIO_PinWrite(EXAMPLE_LED_GPIO, EXAMPLE_LED_GPIO_PIN, 0U);
            g_pinSet = false;
        }
        else
        {
            GPIO_PinWrite(EXAMPLE_LED_GPIO, EXAMPLE_LED_GPIO_PIN, 1U);
            g_pinSet = true;
        }
    }

}

在这里插入图片描述
在这里插入图片描述
http://www.wisioe.com/content/163.html

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考链接:
https://mculover666.blog.csdn.net/article/details/114711391?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-17.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-17.no_search_link
https://blog.csdn.net/YinShiJiaW/article/details/102956975

freemodbus 在stm32+W5500平台上的移植

FreeModbus移植到STM32F107(以太网传输方式)

Modbus TCP移植二

freemodbus modbus TCP 学习笔记

8 freemodbus 在stm32+W5500平台上的移植(w5500具有8个Socket,TCPserver模式下最多支持8个客户端同时访问)

原文链接:https://blog.csdn.net/jordan20052009/article/details/46967451

1、理解freemodbus的运行机制

在W5500平台上移植freemodbus,主要就是要理解eMBpoll()函数的状态机,在理解过程中我主要参考这样几篇文章,甚至可以说是抄袭吧(部分代码),在此表示衷心感谢!http://bbs.eeworld.com.cn/thread-362508-1-1.html,http://bbs.eeworld.com.cn/thread-362508-1-1.html,这两篇文章讲的如如何将freemodbus RTU模式的移植,希望大家能仔细领悟,一篇详细描述了移植过程病给了移植的代码,另一篇对freemodbus的运行机制讲的比较透彻,仔细阅读会对整个移植过程有个比较深刻的理解。

2、理解W5500的运行机制
如果能在理解freemodbus RTU,我们再来看modbus TCP到底在W500平台上如何实现。这里我先首先说明,在此之前还要明白W5500的运行过程,如果这个也不懂请参考http://blog.csdn.net/wiznet2012/article/details/41279113这篇文章,将W5500库函数移植一定要看明白,并且读懂其中int32_t loopback_tcps这个函数,我们移植的平台就是基于这样一个函数的简单改编而已。

3、移植过程

(1)移植环境搭建

 在以上两个前提下我们来移植freemodbus—TCP。首先我们按照http://bbs.eeworld.com.cn/thread-362508-1-1.html这篇博文的要求,建立起freemodbus_RTU环境,这几个回调函数写的很好,既然我人家写好了,我就比较懒没有自己重写,直接抄了过来。
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs );

eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode );

eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,USHORT usNCoils,eMBRegisterMode eMode);

eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete)
(2)编写porttcp.c文件

在此我参考这篇博文http://blog.csdn.net/xukai871105/article/details/21652287,这篇博文讲的是采用uIP协议实现移植,对于modbus的移植有着非常好参考意义,移植前请仔细阅读。主要是建立
//modbus 接收发送寄存器,全局变量
#define MB_TCP_BUF_SIZE  2048
uint8_t ucTCPRequestFrame[MB_TCP_BUF_SIZE];   //接收寄存器
uint16_t ucTCPRequestLen;
uint8_t ucTCPResponseFrame[MB_TCP_BUF_SIZE];   //发送寄存器
uint16_t ucTCPResponseLen;
uint8_t bFrameSent = FALSE;   //是否进行发送响应判断
    建立porttcp.c文件,实现这样几个函数

BOOL  xMBTCPPortInit( USHORT usTCPPort )
{
    SOCKET sn;
    sn=0;
    if(getSn_SR(sn)==SOCK_CLOSED)
    {
       socket(sn,Sn_MR_TCP,usTCPPort,0x00);   //打开socket
    }
    if (getSn_SR(sn)==SOCK_INIT)
    {
     listen(sn);  //监听
     return TRUE;
    }
    return FALSE;
}

BOOL  xMBTCPPortGetRequest( UCHAR **ppucMBTCPFrame, USHORT * usTCPLength )
{
    *ppucMBTCPFrame = (uint8_t *) &ucTCPRequestFrame[0];  
    *usTCPLength = ucTCPRequestLen;    
    /* Reset the buffer. */  
    ucTCPRequestLen = 0;  
    return TRUE;  
}


BOOL xMBTCPPortSendResponse( const UCHAR *pucMBTCPFrame, USHORT usTCPLength )
{  
      memcpy(ucTCPResponseFrame,pucMBTCPFrame , usTCPLength);  
      ucTCPResponseLen = usTCPLength;  
      bFrameSent = TRUE; // 通过W5500发送数据  
      return bFrameSent;
}


void  vMBTCPPortClose( void )
{
};

void vMBTCPPortDisable( void )
{
}

这其中 xMBTCPPortInit()函数的内容写不写,貌似影响不大。

(3)编写main.c文件

 以上说了半天都是参考别人的,而且和W5500没什么关系。现在是freemodbus 和 w5500 库函数如何结合使用的时候了。看一下main函数
int main(void)
{
   uint8_t tmp;
   uint8_t sn=0;
   uint16_t port=MBTCP_PORT;
   eMBErrorCode eStatus;
   w5500_SPI_Init();
   reg_callback_func();//注册W5500回调函数,移植W5500库函数必须
   Socket_buffer_init();//W5500 SOCKET Buffer 初始化
    /* PHY link 状态检查*/
    if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1){
// printf("Unknown PHY Link stauts.\r\n");
     }
    /* 网络初始化 */
    network_init();
  //启动FreeModbus 
    eStatus = eMBTCPInit(port );
    eStatus =eMBEnable();
    while(1)
    {
         modbus_tcps(sn,port);
    }
}

   w5500_SPI_Init();
   reg_callback_func();//注册W5500回调函数,移植W5500库函数必须
   Socket_buffer_init();//W5500 SOCKET Buffer 初始化
    /* PHY link 状态检查*/
    if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) 
     }
    /* 网络初始化 */
    network_init();

    等都是W5500初始化的过程,  

    eStatus = eMBTCPInit(port );
    eStatus =eMBEnable();

    是freemodbus初始化的过程。

    来看一下modbus_tcps(sn,port)函数

    //W5500在TCP server模式下,接收、发送modbus-TCP报文
void modbus_tcps(uint8_t sn, uint16_t port)
{
   switch(getSn_SR(sn))    //获取socket状态
   {
      case SOCK_CLOSED:     //socket处于关闭状态
          socket(sn,Sn_MR_TCP,port,0x00);  //打开socket
         break;
      case SOCK_INIT :  //socket处于已经初始化状态
          listen(sn);  //监听
      case SOCK_ESTABLISHED :   //socket处于连接状态
                  if(getSn_IR(sn) & Sn_IR_CON)
                     {
                     setSn_IR(sn,Sn_IR_CON);
                      }
                  ucTCPRequestLen = getSn_RX_RSR(sn); //获取接收数据长度
                  if(ucTCPRequestLen>0)
                     {
                        recv(sn,ucTCPRequestFrame, ucTCPRequestLen); //W5500接收数据
                        xMBPortEventPost(EV_FRAME_RECEIVED);  //发送EV_FRAME_RECEIVED事件,以驱动eMBpoll()函数中的状态机
                        eMBPoll();   //处理EV_FRAME_RECEIVED事件
                        eMBPoll();   //处理EV_EXECUTE事件
                        if(bFrameSent)  
                          {  
                            bFrameSent = FALSE;  
                             //W5500发送Modbus应答数据包  
                            send(sn,ucTCPResponseFrame,ucTCPResponseLen);
                            }  
                      }
         break;
      case SOCK_CLOSE_WAIT :   //socket处于等待关闭状态
          disconnect(sn); //关闭连接
          break;
      default:
         break;
   }
} 

这个函数就是不断检查W5500的状态,如果检查到有收到数据包之后开始接受数据,并启动freemodbus状态机。具体流程是,W5500接受数据包存入ucTCPRequestFrame数组中 → 发送EV_FRAME_RECEIVED事件 → 两次调用freemodbus状态机,完成对接受报文的解析,并生成响应的报文存入ucTCPRequestFrame数组中 → 最后W5500将数组中的报文中发送出去。

即每次收到数据包之后就执行这样一个流程即可。ucTCPRequestFrame,ucTCPResponseFrame正是W5500和freemodbus结合的媒介。

5、多客户端支持

主函数这样修改

 while(1)
    {    

        for(sn=1;sn<8;sn++)

         modbus_tcps(sn,port);

    }

w5500具有8个Socket,TCPserver模式下最多支持8个客户端同时访问。

### W5500 芯片 Socket 编程实例 #### 创建 TCP 客户端连接 为了创建一个到服务器的TCP客户端连接,可以按照如下方式编写代码: ```c #include "w5500.h" int main(void) { uint8_t sock = 0; // 初始化W5500模块 wizchip_init(); // 设置本地IP地址和其他网络参数 uint8_t local_ip[] = {192, 168, 1, 10}; setSHAR(MAC_ADDRESS); setSIPR(local_ip); // 打开一个新的套接字并配置为TCP模式 if ((sock = socket(Sn_MR_TCP, 5000, 0)) != NO_SOCK_ERR) { struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(DEST_PORT); /* 目标端口 */ server_addr.sin_addr.s_addr = inet_addr("192.168.1.1");/* 目标IP */ // 连接到远程主机 connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)); // 发送数据给服务器 char *msg = "Hello Server"; send(sock, msg, strlen(msg), 0); // 接收来自服务器的数据 char buffer[BUF_SIZE]; int recv_len = recv(sock, buffer, BUF_SIZE - 1, 0); if(recv_len > 0){ buffer[recv_len] = '\0'; printf("Received data from server: %s\n", buffer); } close(sock); } } ``` 这段程序展示了如何初始化W5500设备、建立与指定目标机器之间的TCP连接以及发送接收消息的过程[^1]。 #### UDP 数据报传输示例 对于不需要可靠性的应用场景可以选择使用UDP协议来简化设计。这里给出一段简单的UDP广播例子: ```c #include "w5500.h" void udp_broadcast_example() { uint8_t sock = 0; // 初始化W5500模块 wizchip_init(); // 配置本机网络设置... ... // 建立UDP类型的socket if((sock=socket(AF_INET, SOCK_DGRAM, 0))==NO_SOCK_ERR){ return ; } // 构建目的地址结构体 struct sockaddr_in broadcastAddr; memset(&broadcastAddr, 0, sizeof(broadcastAddr)); broadcastAddr.sin_family = AF_INET; broadcastAddr.sin_port = htons(PORT_NUMBER); /* 广播端口号 */ broadcastAddr.sin_addr.s_addr = INADDR_BROADCAST; /* 使用INADDR_BROADCAST表示向整个子网广播 */ // 向局域网内所有节点发送一条测试信息 const char* message = "This is a test!"; sendto(sock,(char*)message,strlen(message)+1,broadcastAddr,sizeof(struct sockaddr)); // 关闭socket disconnect(sock); } ``` 此片段说明了怎样利用`sendto()`函数来进行无连接的数据包传递操作[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值