OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2960|回复: 2

STM32F429+ENC28J60 网卡驱动初始化失败???

[复制链接]

81

主题

270

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
452
金钱
452
注册时间
2014-8-11
在线时间
87 小时
发表于 2018-8-21 18:15:13 | 显示全部楼层 |阅读模式
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;      
}


我是一只菜鸟,但我会大鹏展翅
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

81

主题

270

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
452
金钱
452
注册时间
2014-8-11
在线时间
87 小时
 楼主| 发表于 2018-8-21 18:17:29 | 显示全部楼层
我在u8 ENC28J60_Init(u8* macaddr)函数中把寄存器的配置顺序懂了下,因为按照原子的程序我读校验出来的都是0x00
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2019-10-30
在线时间
6 小时
发表于 2020-2-27 17:04:42 | 显示全部楼层
我也是 一样的问题  一样的程序 放在F405上就不行
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-25 22:07

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表