轉載自:http://www.embed-net.com/thread-55-1-1.html
官方提供了W5500的最新驅動庫,下載地址如下:
http://wizwiki.net/wiki/doku.php?id=products:w5500:driver
下面簡單介紹下如何使用這套庫
首先下載庫源碼,文件目錄如下所示:
我們主要用到Ethernet文件夾下面的文件,將這些文件加入到自己的工程中,然後編譯,若編譯出現類似於如下錯誤
..UserEthernetwizchip_conf.c(113): error: #29: expected an expression
.id = _WIZCHIP_ID_,
..UserEthernetwizchip_conf.c(114): error: #29: expected an expression
.if_mode = _WIZCHIP_IO_MODE_,
..UserEthernetwizchip_conf.c(115): error: #29: expected an expression
.CRIS._enter = wizchip_cris_enter,
..UserEthernetwizchip_conf.c(116): error: #29: expected an expression
.CRIS._exit = wizchip_cris_exit,
..UserEthernetwizchip_conf.c(117): error: #29: expected an expression
.CS._select = wizchip_cs_select,
..UserEthernetwizchip_conf.c(118): error: #29: expected an expression
.CS._deselect = wizchip_cs_deselect,
..UserEthernetwizchip_conf.c(119): error: #29: expected an expression
.IF.BUS._read_byte = wizchip_bus_readbyte,
..UserEthernetwizchip_conf.c(120): error: #29: expected an expression
.IF.BUS._write_byte = wizchip_bus_writebyte
..UserEthernetwizchip_conf.c(123): warning: #12-D: parsing restarts here after previous syntax error
};
..UserEthernetwizchip_conf.c: 1 warning, 8 errors
則需要根據自己的編譯器做下設置,keil MDK設置如下所示:
<ignore_js_op>
主要原因是Keil MDK默認設置不支持按照結構體名稱初始化結構體的原因導致。
W5500和MCU是通過SPI接口通信的,庫是利用如下結構體中的相關函數指針實現SPI通信和其他功能。
_WIZCHIP WIZCHIP =
{
.id = _WIZCHIP_ID_,
.if_mode = _WIZCHIP_IO_MODE_,
.CRIS._enter = wizchip_cris_enter,
.CRIS._exit = wizchip_cris_exit,
.CS._select = wizchip_cs_select,
.CS._deselect = wizchip_cs_deselect,
.IF.BUS._read_byte = wizchip_bus_readbyte,
.IF.BUS._write_byte = wizchip_bus_writebyte
// .IF.SPI._read_byte = wizchip_spi_readbyte,
// .IF.SPI._write_byte = wizchip_spi_writebyte
};
根據函數名字和庫中的注釋,我們這裡也對要實現的函數做個簡單的說明
wizchip_cris_enter :進入臨界區的函數,可以不管
wizchip_cris_exit :退出臨界區的函數,也可以不管
wizchip_cs_select :輸出有效片選信號的函數,也就是控制CS輸出低電平的函數,必須實現
wizchip_cs_deselect :控制CS輸出高電平的函數,必須實現
wizchip_bus_readbyte :SPI總線讀取一字節數據函數,必須實現
wizchip_bus_writebyte :SPI總線寫一字節數據函數,必須實現根據以上可知,只要實現了SPI的基本操作,移植基本完成,是不是很簡單
下面我們就新建一個spi.c的文件來實現這幾個函數,當然這些函數名字可以不和這個結構體裡面的函數名字一樣,到時候可以調用相關的函數注冊下即可
/**
******************************************************************************
* @file spi.c
* $Author: 飛鴻踏雪 $
* $Revision: 17 $
* $Date:: 2014-10-25 11:16:48 +0800 #$
* @brief SPI驅動函數實現.
******************************************************************************
* @attention
*
*<h3><center>© Copyright 2009-2012, EmbedNet</center>
*<center><a href=“http:\[url]www.embed-net.com[/url]”>[url]http://www.embed-net.com[/url]</a></center>
*<center>All Rights Reserved</center></h3>
*
******************************************************************************
*/
/* Includes ——————————————————————*/
#include “main.h”
/* Private typedef ———————————————————–*/
/* Private define ————————————————————*/
/* Private macro ————————————————————-*/
/* Private variables ———————————————————*/
/* Private function prototypes ———————————————–*/
/* Private functions ———————————————————*/
/**
* @brief 使能SPI時鐘
* @retval None
*/
static void SPI_RCC_Configuration(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1,ENABLE);
}
/**
* @brief 配置指定SPI的引腳
* @retval None
*/
static void SPI_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//PA4->CS,PA5->SCK,PA6->MISO,PA7->MOSI
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
//初始化片選輸出引腳
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_SetBits(GPIOA,GPIO_Pin_4);
}
/**
* @brief 根據外部SPI設備配置SPI相關參數
* @retval None
*/
void SPI_Configuration(void)
{
SPI_InitTypeDef SPI_InitStruct;
SPI_RCC_Configuration();
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
SPI_InitStruct.SPI_Direction= SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(SPI1,&SPI_InitStruct);
SPI_GPIO_Configuration();
SPI_SSOutputCmd(SPI1, ENABLE);
SPI_Cmd(SPI1, ENABLE);
}
/**
* @brief 寫1字節數據到SPI總線
* @param TxData 寫到總線的數據
* @retval None
*/
void SPI_WriteByte(uint8_t TxData)
{
while((SPI1->SR&SPI_I2S_FLAG_TXE)==0); //等待發送區空
SPI1->DR=TxData; //發送一個byte
while((SPI1->SR&SPI_I2S_FLAG_RXNE)==0); //等待接收完一個byte
SPI1->DR;
}
/**
* @brief 從SPI總線讀取1字節數據
* @retval 讀到的數據
*/
uint8_t SPI_ReadByte(void)
{
while((SPI1->SR&SPI_I2S_FLAG_TXE)==0); //等待發送區空
SPI1->DR=0xFF; //發送一個空數據產生輸入數據的時鐘
while((SPI1->SR&SPI_I2S_FLAG_RXNE)==0); //等待接收完一個byte
return SPI1->DR;
}
/**
* @brief 進入臨界區
* @retval None
*/
void SPI_CrisEnter(void)
{
__set_PRIMASK(1);
}
/**
* @brief 退出臨界區
* @retval None
*/
void SPI_CrisExit(void)
{
__set_PRIMASK(0);
}
/**
* @brief 片選信號輸出低電平
* @retval None
*/
void SPI_CS_Select(void)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
}
/**
* @brief 片選信號輸出高電平
* @retval None
*/
void SPI_CS_Deselect(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_4);
}
/*********************************END OF FILE**********************************/
到這裡,移植基本上完成。
但是這些SPI的接口函數如何跟這套庫銜接呢?不用怕,庫提供有這樣的函數來注冊,只要在主函數中調用下就可以了,具體程序如下
// First of all, Should register SPI callback functions implemented by user for accessing WIZCHIP
/* Critical section callback */
reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit); //注冊臨界區函數
/* Chip selection call back */
#if _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_
reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect);//注冊SPI片選信號函數
#elif _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_FDM_
reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect); // CS must be tried with LOW.
#else
#if (_WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SIP_) != _WIZCHIP_IO_MODE_SIP_
#error “Unknown _WIZCHIP_IO_MODE_”
#else
reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);
#endif
#endif
/* SPI Read & Write callback function */
reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte); //注冊讀寫函數
到這裡,移植工程基本完成,下面我們就將官方提供的一個loopback的測試程序移植到我們自己的工程中來,基本上也沒做什麼修改,下面是測試工程用到的幾個測試函數
/**
* @brief Intialize the network information to be used in WIZCHIP
* @retval None
*/
void network_init(void)
{
uint8_t tmpstr[6];
ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);
ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);
// Display Network Information
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”);
}
/**
* @brief Loopback Test Example Code using ioLibrary_BSD
* @retval None
*/
int32_t loopback_tcps(uint8_t sn, uint8_t* buf, uint16_t port)
{
int32_t ret;
uint16_t size = 0, sentsize=0;
switch(getSn_SR(sn))
{
case SOCK_ESTABLISHED :
if(getSn_IR(sn) & Sn_IR_CON)
{
printf(“%d:Connected\r\n”,sn);
setSn_IR(sn,Sn_IR_CON);
}
if((size = getSn_RX_RSR(sn)) > 0)
{
if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
ret = recv(sn,buf,size);
if(ret <= 0) return ret;
sentsize = 0;
while(size != sentsize)
{
ret = send(sn,buf+sentsize,size-sentsize);
if(ret < 0)
{
close(sn);
return ret;
}
sentsize += ret; // Don’t care SOCKERR_BUSY, because it is zero.
}
}
break;
case SOCK_CLOSE_WAIT :
printf(“%d:CloseWait\r\n”,sn);
if((ret=disconnect(sn)) != SOCK_OK) return ret;
printf(“%d:Closed\r\n”,sn);
break;
case SOCK_INIT :
printf(“%d:Listen, port [%d]\r\n”,sn, port);
if( (ret = listen(sn)) != SOCK_OK) return ret;
break;
case SOCK_CLOSED:
printf(“%d:LBTStart\r\n”,sn);
if((ret=socket(sn,Sn_MR_TCP,port,0x00)) != sn)
return ret;
printf(“%d:Opened\r\n”,sn);
break;
default:
break;
}
return 1;
}
/**
* @brief Loopback Test Example Code using ioLibrary_BSD
* @retval None
*/
int32_t loopback_udps(uint8_t sn, uint8_t* buf, uint16_t port)
{
int32_t ret;
uint16_t size, sentsize;
uint8_t destip[4];
uint16_t destport;
//uint8_t packinfo = 0;
switch(getSn_SR(sn))
{
case SOCK_UDP :
if((size = getSn_RX_RSR(sn)) > 0)
{
if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
ret = recvfrom(sn,buf,size,destip,(uint16_t*)&destport);
if(ret <= 0)
{
printf(“%d: recvfrom error. %ld\r\n”,sn,ret);
return ret;
}
size = (uint16_t) ret;
sentsize = 0;
while(sentsize != size)
{
ret = sendto(sn,buf+sentsize,size-sentsize,destip,destport);
if(ret < 0)
{
printf(“%d: sendto error. %ld\r\n”,sn,ret);
return ret;
}
sentsize += ret; // Don’t care SOCKERR_BUSY, because it is zero.
}
}
break;
case SOCK_CLOSED:
printf(“%d:LBUStart\r\n”,sn);
if((ret=socket(sn,Sn_MR_UDP,port,0x00)) != sn)
return ret;
printf(“%d:Opened, port [%d]\r\n”,sn, port);
break;
default :
break;
}
return 1;
}
/**
* @brief Loopback Test Example Code using ioLibrary_BSD
* @retval None
*/
void platform_init(void)
{
SystemInit();//系統時鐘初始化
USART_Configuration();//串口1初始化
printf(“\x0c”);printf(“\x0c”);//超級終端清屏
printf(“\033[1;40;32m”);//設置超級終端背景為黑色,字符為綠色
printf(“\r\n*******************************************************************************”);
printf(“\r\n************************ Copyright 2009-2014, EmbedNet ************************”);
printf(“\r\n*************************** [url]http://www.embed-net.com[/url] **************************”);
printf(“\r\n***************************** All Rights Reserved *****************************”);
printf(“\r\n*******************************************************************************”);
printf(“\r\n”);
//Config SPI
SPI_Configuration();
//延時初始化
delay_init();
}
我們自己在工程中加了串口打印程序,程序運行後串口輸出信息如下:
能ping通,看來沒什麼大問題了
STM32工程源碼下載:http://www.embed-net.com/thread-55-1-1.html來源: iwiznet.cn