基于STM32F4移植W5500官方驱动库ioLibrary_Driver

STM32F4与W5500的ioLibrary移植
本文介绍如何将ioLibrary_Driver移植到STM32F4平台,并实现与W5500芯片的通信。包括解决编译错误、SPI接口配置、网络配置等关键步骤,最后通过功能测试验证移植成果。
1.关于 ioLibrary_Driver
1.1. ioLibrary 概述
The ioLibrary means “Internet Offload Library” for WIZnet chip. It includes drivers and application protocols. The driver (ioLibrary) can be used for the application design of WIZnet TCP/IP chips as W5500, W5300, W5200 and W5100.
更多信息参考ioLibrary的 wiki : http://wizwiki.net/wiki/doku.php?id=products:w5500:driver
1.2. ioLibrary 下载
从 github ( https://github.com/Wiznet/ioLibrary_Driver ) 下载驱动库
2. ioLibrary 移植STM32F4
2.1. 准备工作
首先,下载库源码,解压,文件目录如下所示:

然后,准备一个基本的STM32F4的工程,将 ioLibrary_Driver 放到工程目录下。

2.2. 移植过程
步骤一、将用到 ioLibrary_Driver\Ethernet 下面的文件,将这些文件加入到自己的工程中。

步骤二、添加对应的头文件目录到工程中。


然后编译,出现如下错误,将问题行注释掉。


若编译出现类似于如下错误
..\User\Ethernet\wizchip_conf.c(113): error:  #29: expected an expression
        .id                  = _WIZCHIP_ID_,
..\User\Ethernet\wizchip_conf.c(114): error:  #29: expected an expression
        .if_mode             = _WIZCHIP_IO_MODE_,
..\User\Ethernet\wizchip_conf.c(115): error:  #29: expected an expression
        .CRIS._enter         = wizchip_cris_enter,
..\User\Ethernet\wizchip_conf.c(116): error:  #29: expected an expression
        .CRIS._exit          = wizchip_cris_exit,
..\User\Ethernet\wizchip_conf.c(117): error:  #29: expected an expression
        .CS._select          = wizchip_cs_select,
..\User\Ethernet\wizchip_conf.c(118): error:  #29: expected an expression
        .CS._deselect        = wizchip_cs_deselect,
..\User\Ethernet\wizchip_conf.c(119): error:  #29: expected an expression
        .IF.BUS._read_byte   = wizchip_bus_readbyte,
..\User\Ethernet\wizchip_conf.c(120): error:  #29: expected an expression
        .IF.BUS._write_byte  = wizchip_bus_writebyte
..\User\Ethernet\wizchip_conf.c(123): warning:  #12-D: parsing restarts here after previous syntax error
        };
..\User\Ethernet\wizchip_conf.c: 1 warning, 8 errors
主要原因是Keil MDK默认设置不支持按照结构体名称初始化结构体的原因导致。则需要根据自己的编译器做下设置,keil MDK设置如下所示:

直到编译全部通过,编译器无错误,无警告提示。
步骤三、W5500和STM32F4是通过SPI接口通信的,所以要配置底层SPI管脚功能及SPI工作模式。
/**
* @brief : WIZ_SPI_Init
* @note : SPI接口初始化
* 硬件连接: PA3 -> W5500_RST
* PA4 -> W5500_SCS
* PA5 -> W5500_SCK
* PA6 -> W5500_MISO
* PA7 -> W5500_MOSI
* PA8 -> W5500_INT
* @param :
* @retval :
*/
static void W5500_SPI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能GPIOA时钟

/* W5500_RST引脚初始化配置(PA2) */
GPIO_InitStructure.GPIO_Pin = W5500_RST;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(W5500_RST_PORT, &GPIO_InitStructure);
GPIO_SetBits(W5500_RST_PORT, W5500_RST); // 设置高电平,W5500不会进入复位模式

/* 初始化CS引脚 */
GPIO_InitStructure.GPIO_Pin = W5500_SCS;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(W5500_SCS_PORT, &GPIO_InitStructure);
GPIO_SetBits(W5500_SCS_PORT, W5500_SCS);

// Enable SPI and GPIO clocks
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
//SPI口初始化 Set PA5,6,7 as Output push-pull - SCK, MISO and MOSI
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
SPI_I2S_DeInit(SPI1);
//初始化SPI结构体
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI设置为两线全双工
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //串行时钟在不操作时,时钟为低电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //第一个时钟沿开始采样数据
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由软件(使用SSI位)管理
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //SPI波特率预分频值为 2
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI为主模式
SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPI1寄存器
SPI_Cmd(SPI1, DISABLE);
/* Enable SPI1 */ //使能SPI外设
SPI_Cmd(SPI1, ENABLE); //启动传输
}
步骤四、在 wizchip_conf.h 文件中,有以下几个功能回调注册函数:
void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void));
void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void));
void reg_wizchip_bus_cbfunc(iodata_t (*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, iodata_t wb));
void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), void (*spi_wb)(uint8_t wb));
void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t* pBuf, uint16_t len), void (*spi_wb)(uint8_t* pBuf, uint16_t len));
根据以上几个接口设定的函数接口,添加如下代码
/**
* @brief : WIZ_CS
* @note : 选择W5500
* @param :
* @retval :
*/
static void W5500_CS_Select(void)
{
GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
}
/**
* @brief : SPI_CS_Deselect
* @note : 去选择W5500
* @param :
* @retval :
*/
static void W5500_CS_Deselect(void)
{
GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
}

/**
* @brief : W5500_WriteByte
* @note : W5500 写
* @param :
* @retval :
*/
static void W5500_WriteByte(uint8_t byte)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, byte);

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
SPI_I2S_ReceiveData(SPI1);
}

/**
* @brief : W5500_ReadByte
* @note : W5500 读
* @param :
* @retval :
*/
static uint8_t W5500_ReadByte(void)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, 0xFF);

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
return (SPI_I2S_ReceiveData(SPI1));
}

步骤五、W5500正常工作还需配置MAC地址,IP地址,子网掩码等网络配置信息。
/**
* @brief : W5500_Network_Init
* @note : W5500 网络初始化
* @param :
* @retval :
*/
static void W5500_Network_Init(void)
{
uint8_t chipid[6];
wiz_NetInfo gWIZNETINFO;
uint8_t mac[6]={0x00,0x08,0xdc,0x11,0x11,0x11}; ///< Source Mac Address
uint8_t ip[4]={192,168,100,150}; ///< Source IP Address
uint8_t sn[4]={255,255,255,0}; ///< Subnet Mask
uint8_t gw[4]={192,168,100,1}; ///< Gateway IP Address
uint8_t dns[4]={8,8,8,8}; ///< DNS server IP Address

memcpy(gWIZNETINFO.ip, ip, 4);
memcpy(gWIZNETINFO.sn, sn, 4);
memcpy(gWIZNETINFO.gw, gw, 4);
memcpy(gWIZNETINFO.mac, mac,6);
memcpy(gWIZNETINFO.dns,dns,4);
gWIZNETINFO.dhcp = NETINFO_STATIC; //< 1 - Static, 2 - DHCP
ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);

ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);
// Display Network Information
ctlwizchip(CW_GET_ID,(void*)chipid);
printf("\r\n=== %s NET CONF ===\r\n",(char*)chipid);
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");

wizchip_init(NULL, NULL);

wiz_NetTimeout w_NetTimeout;
w_NetTimeout.retry_cnt = 50;
w_NetTimeout.time_100us = 1000;
wizchip_settimeout(&w_NetTimeout);
}
步骤六、初始化W5500相关设定。
/**
* @brief : W5500_Init
* @note : 初始化
* @param :
* @retval :
*/
void W5500_Init(void)
{
W5500_SPI_Init();

for(int i=0x5FFF; i>0; i--); // 短暂延时,不然导致初始化失败

reg_wizchip_cris_cbfunc(NULL, NULL); // 注册临界区函数
reg_wizchip_cs_cbfunc(W5500_CS_Select, W5500_CS_Deselect);// 注册片选函数
reg_wizchip_spi_cbfunc(W5500_ReadByte, W5500_WriteByte); // 注册读写函数

W5500_Network_Init();
}

步骤七、到这里,移植基本上完成。编译工程保证无错误,无警告输出。
3. 基于ioLibrary的应用
3.1. 功能测试
步骤一、将用到 ioLibrary_Driver\Application 的文件添加到工程

步骤二、包含对应头文件路径。

步骤三、添加应用代码到主流程中。
/**
* @brief Main program
* @param None
* @retval None
*/
int main(void)
{
uint8_t dest_ip[4] = {192, 168, 10, 13};
uint16_t dest_port = 8080;

uint8_t dataBuffer[DATA_BUF_SIZE]={0x0};

RCC_ClocksTypeDef RCC_Clocks;

/* SysTick end of count event each 10ms */
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);

/* Add your application code here */

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
USART1_NVIC_Config(0,1);

LED_Init();
USART1_Init();
W5500_Init();
/* Infinite loop */
while (1)
{
loopback_tcpc(0x0, dataBuffer, dest_ip, dest_port);
LEDA_ON;LEDB_OFF;
Delay(50);
LEDA_OFF;LEDB_ON;
Delay(50);
}
}
步骤四、调整工程堆栈配置(根据功能需要,自定大小)。

步骤五、启动网络调试助手,适当配置。

步骤六、编译程序,烧写到单片机中,重启。查看连接对象中是否出现,TCP-Client,选择点击发送按钮,能收到回文,代表测试成功。

3.2. ping 测试
我们ping下程序里面的IP试试,能ping通,看来没什么大问题了。

4、测试代码
优快云下载链接:https://download.youkuaiyun.com/download/xiayufeng520/10293822




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值