中级会员
积分 452
金钱 452
注册时间 2014-8-11
在线时间 87 小时
20 金钱
/*
函数没有做注释,基本都是千篇一律,所以就把注释去掉了,不要问我为什么,因为MDK5注释拷贝出来是乱码的,删了满足观赏性
不要问我为什么不用STM32F4自带的网口,因为接口被我占用了
*/
//问题:照搬F103+ENC28J60的网卡驱动发现无法ping通192.168.1.16,调试工具也不通
//一开始是照搬F103的,指示把SPI对应的接口改了改,网卡可以初始化成功,只是ping不通
//于是乎纠结下初始化。。。发现
//u8 ENC28J60_Init(u8* macaddr)函数返回的状态只涉及
//if(ENC28J60_Read(MAADR5)== macaddr[0])return 0;
//else return 1;
//其余寄存器的配合都未校验
//为了实现初始化的可靠性,我在每配置一个寄存器后面都加入了读校验结果的返回(不知道是不是多余了)
//但这么一折腾发现读校验有问题,详见代码
---------------------------SPI2引脚使用------------------------------
PB12->CS
PB13->SCK
PB14->MISO
PB15->MOSI
PH6 ->INT
PH7 ->RST
-----------------------------SPI相关程序----------------------------------
[mw_shl_code=c,true]SPI_HandleTypeDef SPI5_Handler;
SPI_HandleTypeDef SPI2_Handler;
void SPI2_Init(void)
{
SPI2_Handler.Instance=SPI2;
SPI2_Handler.Init.Mode=SPI_MODE_MASTER;
SPI2_Handler.Init.Direction=SPI_DIRECTION_2LINES;
SPI2_Handler.Init.DataSize=SPI_DATASIZE_8BIT;
SPI2_Handler.Init.CLKPolarity=SPI_POLARITY_HIGH;
SPI2_Handler.Init.CLKPhase=SPI_PHASE_2EDGE;
SPI2_Handler.Init.NSS=SPI_NSS_SOFT;
SPI2_Handler.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_256;
SPI2_Handler.Init.FirstBit=SPI_FIRSTBIT_MSB;
SPI2_Handler.Init.TIMode=SPI_TIMODE_DISABLE;
SPI2_Handler.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE;
SPI2_Handler.Init.CRCPolynomial=7;
HAL_SPI_Init(&SPI2_Handler);
__HAL_SPI_ENABLE(&SPI2_Handler);
SPI2_ReadWriteByte(0Xff);
}
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_SPI2_CLK_ENABLE();
GPIO_Initure.Mode=GPIO_MODE_AF_PP;
GPIO_Initure.Pull=GPIO_PULLUP;
GPIO_Initure.Speed=GPIO_SPEED_FAST;
GPIO_Initure.Pin=GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_Initure.Alternate=GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}
void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
__HAL_SPI_DISABLE(&SPI2_Handler);
SPI2_Handler.Instance->CR1&=0XFFC7;
SPI2_Handler.Instance->CR1|=SPI_BaudRatePrescaler;
__HAL_SPI_ENABLE(&SPI2_Handler);
}
u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 Rxdata;
HAL_SPI_TransmitReceive(&SPI2_Handler,&TxData,&Rxdata,1, 1000);
return Rxdata;
}[/mw_shl_code]
-----------------------------ENC28J60相关程序----------------------------------
static u8 ENC28J60BANK;
static u32 NextPacketPtr;
void ENC28J60_Reset(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7;
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;
GPIO_Initure.Pull=GPIO_PULLUP;
GPIO_Initure.Speed=GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOH,&GPIO_Initure);
GPIO_Initure.Pin=GPIO_PIN_12;
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;
GPIO_Initure.Pull=GPIO_PULLUP;
GPIO_Initure.Speed=GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOB,&GPIO_Initure); //PB12
SPI2_Init();
//重新配置了下SPI2的部分参数,以满足ENC28J60的通信需求
SPI2->CR1&=~(1<<6);
SPI2->CR1&=~(1<<1);
SPI2->CR1&=~(1<<0);
SPI2->CR1|=1<<6;
//最后一次取8分频调试的,因为从机时钟是依赖主机的,所以我的理解上是取多少都可以(只要从机扛得住),分频系数高一点,用速率的牺牲实现通信稳定
SPI2_SetSpeed(SPI_BAUDRATEPRESCALER_8);
//这是提供给uIP的一个时钟 产生10ms一次的频率
TIM5_Init(1000-1,900-1); //TIM5_Init(1000-1,900-1)=10ms
ENC28J60_RST=0;
delay_ms(10);
ENC28J60_RST=1;
delay_ms(10);
}
u8 ENC28J60_Read_Op(u8 op,u8 addr)
{
u8 dat=0;
ENC28J60_CS=0;
dat=op|(addr&ADDR_MASK);
SPI2_ReadWriteByte(dat);
dat=SPI2_ReadWriteByte(0xFF);
if(addr&0x80)dat=SPI2_ReadWriteByte(0xFF);
ENC28J60_CS=1;
return dat;
}
void ENC28J60_Write_Op(u8 op,u8 addr,u8 data)
{
u8 dat = 0;
ENC28J60_CS=0;
dat=op|(addr&ADDR_MASK);
SPI2_ReadWriteByte(dat);
SPI2_ReadWriteByte(data);
ENC28J60_CS=1;
}
void ENC28J60_Read_Buf(u32 len,u8* data)
{
ENC28J60_CS=0;
SPI2_ReadWriteByte(ENC28J60_READ_BUF_MEM);
while(len)
{
len--;
*data=(u8)SPI2_ReadWriteByte(0);
data++;
}
*data='\0';
ENC28J60_CS=1;
}
void ENC28J60_Write_Buf(u32 len,u8* data)
{
ENC28J60_CS=0;
SPI2_ReadWriteByte(ENC28J60_WRITE_BUF_MEM);
while(len)
{
len--;
SPI2_ReadWriteByte(*data);
data++;
}
ENC28J60_CS=1;
}
void ENC28J60_Set_Bank(u8 bank)
{
if((bank&BANK_MASK)!=ENC28J60BANK)
{
ENC28J60_Write_Op(ENC28J60_BIT_FIELD_CLR,ECON1,(ECON1_BSEL1|ECON1_BSEL0));
ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,(bank&BANK_MASK)>>5);
ENC28J60BANK=(bank&BANK_MASK);
}
}
u8 ENC28J60_Read(u8 addr)
{
u8 data;
ENC28J60_Set_Bank(addr);
data=ENC28J60_Read_Op(ENC28J60_READ_CTRL_REG,addr);
return data;
}
void ENC28J60_Write(u8 addr,u8 data)
{
ENC28J60_Set_Bank(addr);
ENC28J60_Write_Op(ENC28J60_WRITE_CTRL_REG,addr,data);
}
u8 ENC28J60_Write_Check(u8 addr,u8 data,u8 return_sta)
{
u16 retry=0;
u8 sta=0;
ENC28J60_Set_Bank(addr);
ENC28J60_Write_Op(ENC28J60_WRITE_CTRL_REG,addr,data);
while((ENC28J60_Read(MISTAT)&MISTAT_BUSY)&&retry<0XFFF)
{
retry++;
}
if(return_sta)
{
if(ENC28J60_Read(addr)!=data)
{
sta=1;
}
else
{
sta=0;
}
}
return sta;
}
void ENC28J60_PHY_Write(u8 addr,u32 data)
{
u16 retry=0;
ENC28J60_Write(MIREGADR,addr);
ENC28J60_Write(MIWRL,data&0xFF);
ENC28J60_Write(MIWRH,data>>8);
while((ENC28J60_Read(MISTAT)&MISTAT_BUSY)&&retry<0XFFF)retry++;
}
u8 ENC28J60_Init(u8* macaddr)
{
u16 retry=0;
ENC28J60_Reset();
ENC28J60_Write_Op(ENC28J60_SOFT_RESET,0,ENC28J60_SOFT_RESET);
while(!(ENC28J60_Read(ESTAT)&ESTAT_CLKRDY)&&retry<500)
{
retry++;
delay_ms(1);
};
if(retry>=500)return 1;
// do bank 0 stuff
// initialize receive buffer
// 16-bit transfers,must write low byte first
// set receive buffer start address
NextPacketPtr=RXSTART_INIT;
/***************以下是按照F103+ENC28J60照搬的,但是在F4上操作的时候设置部分寄存器失败*****************/
//寄存器设置 后我会去读一下这个寄存器的值,如果读出来的值和 预设的值不一致函数直接返回1-失败 //调试中发现如果在此处配置 寄存器ERXSTL ERXSTH ERXRDPTL ERXRDPTH ERXNDL ERXNDH ETXSTL ETXSTH ETXNDL ETXNDH,
//读取校验收到的值都是0x00
//基于这个现象我把这部分设置(红色代码)放到了后面去(蓝色代码)
// ENC28J60_Write(ERXSTL,RXSTART_INIT&0xFF);
// ENC28J60_Write(ERXSTH,RXSTART_INIT>>8);
// if(ENC28J60_Read(ERXSTL)!=(RXSTART_INIT&0xFF))return 1;
// if(ENC28J60_Read(ERXSTH)!=(RXSTART_INIT>>8))return 1;
// ENC28J60_Write(ERXRDPTL,RXSTART_INIT&0xFF);
// ENC28J60_Write(ERXRDPTH,RXSTART_INIT>>8);
// if(ENC28J60_Read(ERXRDPTL)!=(RXSTART_INIT&0xFF))return 1;
// if(ENC28J60_Read(ERXRDPTH)!=(RXSTART_INIT>>8))return 1;
// ENC28J60_Write(ERXNDL,RXSTOP_INIT&0xFF);
// ENC28J60_Write(ERXNDH,RXSTOP_INIT>>8);
// if(ENC28J60_Read(ERXNDH)!=(RXSTOP_INIT>>8))return 1;
// if(ENC28J60_Read(ERXNDL)!=(RXSTOP_INIT&0xFF))return 1;
// ENC28J60_Write(ETXSTL,TXSTART_INIT&0xFF);
// ENC28J60_Write(ETXSTH,TXSTART_INIT>>8);
// if(ENC28J60_Read(ETXSTL)!=(TXSTART_INIT&0xFF))return 1;
// if(ENC28J60_Read(ETXSTH)!=(TXSTART_INIT>>8))return 1;
// ENC28J60_Write(ETXNDL,TXSTOP_INIT&0xFF);
// ENC28J60_Write(ETXNDH,TXSTOP_INIT>>8);
// if(ENC28J60_Read(ETXNDL)!=(TXSTOP_INIT&0xFF))return 1;
// if(ENC28J60_Read(ETXNDH)!=(TXSTOP_INIT>>8))return 1;
ENC28J60_Write(ERXFCON,ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);
ENC28J60_Write(EPMM0,0x3f);
ENC28J60_Write(EPMM1,0x30);
ENC28J60_Write(EPMCSL,0xf9);
ENC28J60_Write(EPMCSH,0xf7);
if(ENC28J60_Read(EPMM0)!=0x3f)return 1;
if(ENC28J60_Read(EPMM1)!=0x30)return 1;
if(ENC28J60_Read(EPMCSL)!=0xf9)return 1;
if(ENC28J60_Read(EPMCSH)!=0xf7)return 1;
ENC28J60_Write(MACON1,MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
if(ENC28J60_Read(MACON1)!=(MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS))return 1;
// bring MAC out of reset
ENC28J60_Write(MACON2,0x00);
if(ENC28J60_Read(MACON2)!=0x00)return 1;
// enable automatic padding to 60bytes and CRC operations
ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,MACON3,MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN|MACON3_FULDPX);
// set inter-frame gap (non-back-to-back)
ENC28J60_Write(MAIPGL,0x12);
ENC28J60_Write(MAIPGH,0x0C);
if(ENC28J60_Read(MAIPGL)!=0x12)return 1;
if(ENC28J60_Read(MAIPGH)!=0x0C)return 1;
// set inter-frame gap (back-to-back)
ENC28J60_Write(MABBIPG,0x15);
if(ENC28J60_Read(MABBIPG)!=0x15)return 1;
// Set the maximum packet size which the controller will accept
// Do not send packets longer than MAX_FRAMELEN:
ENC28J60_Write(MAMXFLL,MAX_FRAMELEN&0xFF);
ENC28J60_Write(MAMXFLH,MAX_FRAMELEN>>8);
if(ENC28J60_Read(MAMXFLL)!=(MAX_FRAMELEN&0xFF))return 1;
if(ENC28J60_Read(MAMXFLH)!=(MAX_FRAMELEN>>8))return 1;
// do bank 3 stuff
// write MAC address
ENC28J60_Write(MAADR5,macaddr[0]);
ENC28J60_Write(MAADR4,macaddr[1]);
ENC28J60_Write(MAADR3,macaddr[2]);
ENC28J60_Write(MAADR2,macaddr[3]);
ENC28J60_Write(MAADR1,macaddr[4]);
ENC28J60_Write(MAADR0,macaddr[5]);
//此处配置寄存器读出来的值都是与预设值一致
ENC28J60_Write(ERXSTL,RXSTART_INIT&0xFF);
ENC28J60_Write(ERXSTH,RXSTART_INIT>>8);
if(ENC28J60_Read(ERXSTL)!=(RXSTART_INIT&0xFF))return 1;
if(ENC28J60_Read(ERXSTH)!=(RXSTART_INIT>>8))return 1;
ENC28J60_Write(ERXRDPTL,RXSTART_INIT&0xFF);
ENC28J60_Write(ERXRDPTH,RXSTART_INIT>>8);
if(ENC28J60_Read(ERXRDPTL)!=(RXSTART_INIT&0xFF))return 1;
if(ENC28J60_Read(ERXRDPTH)!=(RXSTART_INIT>>8))return 1;
ENC28J60_Write(ERXNDL,RXSTOP_INIT&0xFF);
ENC28J60_Write(ERXNDH,RXSTOP_INIT>>8);
if(ENC28J60_Read(ERXNDH)!=(RXSTOP_INIT>>8))return 1;
if(ENC28J60_Read(ERXNDL)!=(RXSTOP_INIT&0xFF))return 1; //fuck
ENC28J60_Write(ETXSTL,TXSTART_INIT&0xFF);
ENC28J60_Write(ETXSTH,TXSTART_INIT>>8);
if(ENC28J60_Read(ETXSTL)!=(TXSTART_INIT&0xFF))return 1;
if(ENC28J60_Read(ETXSTH)!=(TXSTART_INIT>>8))return 1;
ENC28J60_Write(ETXNDL,TXSTOP_INIT&0xFF);
ENC28J60_Write(ETXNDH,TXSTOP_INIT>>8);
if(ENC28J60_Read(ETXNDL)!=(TXSTOP_INIT&0xFF))return 1;
if(ENC28J60_Read(ETXNDH)!=(TXSTOP_INIT>>8))return 1;
ENC28J60_PHY_Write(PHCON1,PHCON1_PDPXMD);
if(ENC28J60_Read(MIREGADR)!=PHCON1)return 1;
if(ENC28J60_Read(MIWRL)!=(PHCON1_PDPXMD&0xFF))return 1;
if(ENC28J60_Read(MIWRH)!=(PHCON1_PDPXMD>>8))return 1;
ENC28J60_PHY_Write(PHCON2,PHCON2_HDLDIS);
if(ENC28J60_Read(MIREGADR)!=PHCON2)return 1;
if(ENC28J60_Read(MIWRL)!=(PHCON2_HDLDIS&0xFF))return 1;
if(ENC28J60_Read(MIWRH)!=(PHCON2_HDLDIS>>8))return 1;
//以下紫色部分的代码也是为了查询相关寄存器的设置值是否和预设值一致,但是调试中发现读出的值都是0xFF
// switch to bank 0
ENC28J60_Set_Bank(ECON1); //执行后SPI2-DR缓冲区的值为0xFF
// if(ENC28J60_Read_Op(ENC28J60_BIT_FIELD_CLR,ECON1)!=(ECON1_BSEL1|ECON1_BSEL0))return 1;
// if(ENC28J60_Read_Op(ENC28J60_BIT_FIELD_SET,ECON1)!=((ECON1&BANK_MASK)>>5))return 1;
// enable interrutps
ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,EIE,EIE_INTIE|EIE_PKTIE);//执行前后SPI2-DR缓冲区的值为0xFF
// if(ENC28J60_Read_Op(ENC28J60_BIT_FIELD_SET,EIE)!=(EIE_INTIE|EIE_PKTIE))return 1;
//enable packet reception
ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_RXEN);//执行前后SPI2-DR缓冲区的值为0xFF
// if(ENC28J60_Read_Op(ENC28J60_BIT_FIELD_SET,ECON1)!=ECON1_RXEN)return 1;
if(ENC28J60_Read(MAADR5)== macaddr[0]&&ENC28J60_Read(MAADR4)== macaddr[1]&&ENC28J60_Read(MAADR3)== macaddr[2]&&ENC28J60_Read(MAADR2)== macaddr[3]&&ENC28J60_Read(MAADR1)== macaddr[4]&&ENC28J60_Read(MAADR0)== macaddr[5])return 0;
else return 1;
}
我来回答