接到一个任务,验证硬件同事的一块板子上网卡芯片W5500的功能是否正常,MCU使用的是STM32F103RCT6 ,从了解到的信息看,W5500和MCU之间使用SPI接口进行通信,跟最近调了好久的DW1000的使用方法相同,驱动是厂家提供的,也就是只需要调通SPI通信,基本上就能驱动W5500工作!
标准库版本:STM32F10x_StdPeriph_Lib_V3.5.0
W5500与STM32F103RCT6 的引脚关系如下,使用的是STM32F103RCT6 芯片的SPI2:
PA8 -> W5500_RST
PB12 -> W5500_SCS
PB13 -> W5500_SCK
PB14 -> W5500_MISO
PB15 -> W5500_MOSI
PA15 -> W5500_INT
关键的第一个点是GPIO的初始化(参考CSDN的文档实现):
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
/*使能GPIOA的rcc时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
/*配置GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_15| GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure SPI1 pins: SCK, MISO and MOSI -------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Set Chip Select pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_Pin_12);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_8);//RST
/*配置GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*初始化GPIO*/
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Set SPI interface */
SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode=SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2;
SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial=7;
SPI_Init(SPI2,&SPI_InitStructure);
SPI_Cmd(SPI2,ENABLE);
SPI_I2S_ClearFlag(SPI2, SPI_I2S_FLAG_TXE);
SPI_I2S_ClearFlag(SPI2, SPI_I2S_FLAG_RXNE);
W5500的上电,根据W5500的驱动文档,需要把W5500的RST引脚拉低超过500us
void func_w5500_reset(void)
{
GPIO_ResetBits(W5500_RST_GPIO_PORT, W5500_RST_PIN);
delay_ms(2);
GPIO_SetBits(W5500_RST_GPIO_PORT, W5500_RST_PIN);
delay_ms(1600);
}
SPI读写:
/* NSS pin is SW controllable */
#define port_SPIx_set_chip_select() GPIO_SetBits(W5500_SPI2_CS_GPIO_PORT, W5500_SPI2_CS_PIN)
#define port_SPIx_clear_chip_select() GPIO_ResetBits(W5500_SPI2_CS_GPIO_PORT, W5500_SPI2_CS_PIN)
uint8_t func_spi_write_a_byte(uint8_t byte)
{
//port_SPIx_set_chip_select();
/* Wait until TXE flag is set to send data */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
{
}
//SPI_I2S_SendData(SPI2, byte);
SPI2->DR = byte; /* set output to 0 (MOSI), this is necessary for
e.g. when waking up DW1000 from DEEPSLEEP via dwt_spicswakeup() function.
*/
/* Wait until RXNE flag is set to read data */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
{
}
//return SPI_I2S_ReceiveData(SPI2);
uint8_t byte_read = SPI2->DR; //copy data read form (MISO)
//port_SPIx_clear_chip_select();
return byte_read;
}
void func_spi_cs_select(void)
{
port_SPIx_clear_chip_select();
}
void func_spi_cs_deselect(void)
{
port_SPIx_set_chip_select();
}
测试程序
#include "SEGGER_RTT.h"
#define logD(...) SEGGER_RTT_printf(0, __VA_ARGS__)
int main(void)
{
reset_w5500();
config_eth();
uint8_t test_0 = 0;
uint8_t test_1 = 1;
while(1)
{
int i;
SEGGER_RTT_printf(0, "times:%d\r\n", times++);
test_eth();
delay_ms(500);
}
}
typedef uint8_t uint8;
static uint8 test_ip[8] = {'\0'};
static char print_str[1024] = "\0";
void test_eth(){
int index = 0;
memset(test_ip, 0x00, 8);
memset(print_str, 0x00, 1024);
getGAR(test_ip);
index = 0;
for(int i=0; i<4; i++){
sprintf(print_str + index, "%d.", test_ip[i]);
index = strlen(print_str);
}
logD("gateway:%s\r\n", print_str);
memset(test_ip, 0x00, 8);
memset(print_str, 0x00, 1024);
getSIPR(test_ip);
index = 0;
for(int i=0; i<4; i++){
sprintf(print_str + index, "%d.", test_ip[i]);
index = strlen(print_str);
}
logD("ip:%s\r\n", print_str);
}
void config_eth(){
uint8 mac[6]={0, };
uint8 lip[4]={192,168,86,197};
uint8 sub[4]={255,255,255,0};
uint8 gw[4]={192,168,86,1};//根据网络所在的IP地址段和网关信息修改
char print_str[1024] = "\0";
memset(print_str, 0x00, 1024);
memset(mac, 0x00, 6);
getMacByLockCode(mac);
int index = 0;
for(int i=0; i<6; i++){
sprintf(print_str + index, "%d.", mac[i]);
index = strlen(print_str);
}
logD("mac:%s\r\n", print_str);
uint8 test_ip[8] = {'\0'};
memset(test_ip, 0x00, 8);
memset(print_str, 0x00, 1024);
getSIPR(test_ip);
index = 0;
for(int i=0; i<4; i++){
sprintf(print_str + index, "%d.", test_ip[i]);
index = strlen(print_str);
}
logD("old ip:%s\r\n", print_str);
setSHAR(mac);
memset(test_ip, 0x00, 8);
memset(print_str, 0x00, 1024);
getSHAR(test_ip);
index = 0;
for(int i=0; i<6; i++){
sprintf(print_str + index, "%d.", test_ip[i]);
index = strlen(print_str);
}
logD("new mac:%s\r\n", print_str);
setSUBR(sub);
setGAR(gw);
setSIPR(lip);
memset(test_ip, 0x00, 8);
memset(print_str, 0x00, 1024);
getGAR(test_ip);
index = 0;
for(int i=0; i<4; i++){
sprintf(print_str + index, "%d.", test_ip[i]);
index = strlen(print_str);
}
logD("gateway:%s\r\n", print_str);
memset(test_ip, 0x00, 8);
memset(print_str, 0x00, 1024);
getSIPR(test_ip);
index = 0;
for(int i=0; i<4; i++){
sprintf(print_str + index, "%d.", test_ip[i]);
index = strlen(print_str);
}
logD("ip:%s\r\n", print_str);
}
使用参考连接中提供的下载iolibarary,修改了基本的方法后,调通了ping程序
遗留问题:
STM32 CubeMX生成基于Hal库的工程,在SPI口配置为输出时,拉低和拉高均不生效;