Files
NE_YuR/network/start/lib/xnet/enc28j60_device.c
2025-11-17 22:22:52 +08:00

318 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include "enc28j60_device.h"
// 一共8KB的以太网缓存
static u8 ENC28J60BANK;
int NextPacketPtr;
//delay for ms unit
//suitable for crystal is 8MHz
//static function for ENC28J60
static void ENC28J60_delayms(u32 ms)
{
u16 i=0;
while(ms--)
{
for(i=0;i<8000;i++);
}
}
static inline void ENC28J60_cs_delayms(void)
{
}
//Reset ENC28J60
//Initialize SPI2 and related I/O for ENC28J60
static void ENC28J60_SPI2_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC, ENABLE );
// INT A7
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource7);
EXTI_InitStructure.EXTI_Line= EXTI_Line7;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //使能外部中断所在的通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据结构体信息进行优先级初始化
//CS pin
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
//RST pin
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_5);
//setup SPI2
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);
SPI2_ReadWriteByte(0xff);
}
void ENC28J60_Reset(void)
{
ENC28J60_SPI2_Init(); //re-init SPI2
ENC28J60_RST_CLEAR(); //reset ENC28J60
ENC28J60_delayms(10);
ENC28J60_RST_SET(); //finish reset
ENC28J60_delayms(10);
}
//Read ENC28J60 register
//op: command
//addr: register address
//return: read out data
u8 ENC28J60_Read_Op(u8 op,u8 addr)
{
u8 dat=0;
ENC28J60_SELECT();
ENC28J60_cs_delayms();
dat=op|(addr&ADDR_MASK);
SPI2_ReadWriteByte(dat);
dat=SPI2_ReadWriteByte(0xFF);
//datasheet p.29, read two times to get MAC/MII register value
if(addr&0x80)dat=SPI2_ReadWriteByte(0xFF);
ENC28J60_cs_delayms();
ENC28J60_NO_SELECT();
return dat;
}
//Write ENC28J60 register
//op: command
//addr: register address
//data: parameter to write
void ENC28J60_Write_Op(u8 op,u8 addr,u8 data)
{
u8 dat = 0;
ENC28J60_SELECT();
ENC28J60_cs_delayms();
dat=op|(addr&ADDR_MASK);
SPI2_ReadWriteByte(dat);
SPI2_ReadWriteByte(data);
ENC28J60_cs_delayms();
ENC28J60_NO_SELECT();
}
//Read Rx buffer data from ENC28J60
//len: data length to read
//data: pointer to store data
void ENC28J60_Read_Buf(u32 len,u8* data)
{
ENC28J60_SELECT();
ENC28J60_cs_delayms();
SPI2_ReadWriteByte(ENC28J60_READ_BUF_MEM);
while(len--) {
*data++=(u8)SPI2_ReadWriteByte(0);
}
ENC28J60_cs_delayms();
ENC28J60_NO_SELECT();
}
//Write data to send via ENC28J60
//len: data length to send
//data: data pointer
void ENC28J60_Write_Buf(u32 len,u8* data)
{
ENC28J60_SELECT();
ENC28J60_cs_delayms();
SPI2_ReadWriteByte(ENC28J60_WRITE_BUF_MEM);
while(len--)
{
SPI2_ReadWriteByte(*data++);
}
ENC28J60_cs_delayms();
ENC28J60_NO_SELECT();
}
//Setup ENC28J60 register bank
//ban: Bank to be setup
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);
}
}
//Read ENC28J60 register
//addr: register address
//return: read out value
u8 ENC28J60_Read(u8 addr)
{
ENC28J60_Set_Bank(addr);//select bank
return ENC28J60_Read_Op(ENC28J60_READ_CTRL_REG,addr);
}
//Write ENC28J60 register
//addr: register address
void ENC28J60_Write(u8 addr,u8 data)
{
ENC28J60_Set_Bank(addr);
ENC28J60_Write_Op(ENC28J60_WRITE_CTRL_REG,addr,data);
}
//Write into PHY register of ENC28J60
//addr: register address
//data: parameter written into register
void ENC28J60_PHY_Write(u8 addr,u32 data)
{
u16 retry=0;
ENC28J60_Write(MIREGADR,addr);
ENC28J60_Write(MIWRL,data);
ENC28J60_Write(MIWRH,data>>8);
while((ENC28J60_Read(MISTAT)&MISTAT_BUSY)&&retry<0XFFF)retry++;//wait until PHY writing finish
}
//Setup ENC28J60
//macaddr: assigned MAC address
//return: 0=success, 1=failed
u8 ENC28J60_Init(u8* macaddr)
{
u16 retry=0;
ENC28J60_Reset();
ENC28J60_Write_Op(ENC28J60_SOFT_RESET,0,ENC28J60_SOFT_RESET); //software reset
while(!(ENC28J60_Read(ESTAT)&ESTAT_CLKRDY)&&retry<500) //wait until clock is stable
{
retry++;
ENC28J60_delayms(1);
};
if(retry>=500)return 1;//initialization failed
//set Rx buffer address with 8k capacity
NextPacketPtr=RXSTART_INIT;
//初始化接收缓冲区,设置接收起始地址
ENC28J60_Write(ERXSTL,RXSTART_INIT&0xFF);
ENC28J60_Write(ERXSTH,RXSTART_INIT>>8);
//设置接收读指针指向地址
ENC28J60_Write(ERXRDPTL, RXSTART_INIT &0xFF);
ENC28J60_Write(ERXRDPTH, RXSTART_INIT>>8);
//设置接收缓冲区的末尾地址
ENC28J60_Write(ERXNDL,RXSTOP_INIT&0xFF);
ENC28J60_Write(ERXNDH,RXSTOP_INIT>>8);
//设置发送缓冲区的起始地址
ENC28J60_Write(ETXSTL,TXSTART_INIT&0xFF);
ENC28J60_Write(ETXSTH,TXSTART_INIT>>8);
//setup "eno of tx" byte
ENC28J60_Write(ETXNDL,TXSTOP_INIT&0xFF);
ENC28J60_Write(ETXNDH,TXSTOP_INIT>>8);
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);
//MAC接收使能下行程序段表示使能MAC接收使能IEEE流量控制
ENC28J60_Write(MACON1,MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
// bring MAC out of reset
ENC28J60_Write(MACON2,0x00); //MACON2清零让MAC退出复位状态
// 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);
// set inter-frame gap (back-to-back)
ENC28J60_Write(MABBIPG,0x15);
// 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);
// do bank 3 stuff
// write MAC address
// NOTE: MAC address in ENC28J60 is byte-backward
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]);
//setup PHY as Duplex
ENC28J60_PHY_Write(PHCON1,PHCON1_PDPXMD);
// no loopback of transmitted frames 禁止环回
//HDLDISPHY 半双工环回禁止位
ENC28J60_PHY_Write(PHCON2,PHCON2_HDLDIS);
// switch to bank 0
ENC28J60_Set_Bank(ECON1);
// enable interrutps
ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,EIE,EIE_INTIE|EIE_PKTIE);
// enable packet reception
ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_RXEN);
if(ENC28J60_Read(MAADR5)== macaddr[0]) {
ENC28J60_delayms(10);
return 0;//initialization success
}
if(ENC28J60_Read(MAADR4)== macaddr[1]) {
ENC28J60_delayms(10);
return 0;//initialization success
}
if(ENC28J60_Read(MAADR3)== macaddr[2]) {
ENC28J60_delayms(10);
return 0;//initialization success
}
if(ENC28J60_Read(MAADR2)== macaddr[3]) {
ENC28J60_delayms(10);
return 0;//initialization success
}
if(ENC28J60_Read(MAADR1)== macaddr[4]) {
ENC28J60_delayms(10);
return 0;//initialization success
}
if(ENC28J60_Read(MAADR0)== macaddr[5]) {
ENC28J60_delayms(10);
return 0;//initialization success
}
return -1;
}
//Read EREVID
u8 ENC28J60_Get_EREVID(void)
{
return ENC28J60_Read(EREVID);
}