void ENC28J60_PhyRegisterWrite(uint8_t address, uint16_t data) { // set the PHY register address ENC28J60_Write(MIREGADR, address); // write the PHY data ENC28J60_Write(MIWRL, data); ENC28J60_Write(MIWRH, data>>8); // wait until the PHY write completes while(ENC28J60_Read(MISTAT) & MISTAT_BUSY); }
// Gets a packet from the network receive buffer, if one is available. // The packet will by headed by an ethernet header. // maxlen The maximum acceptable length of a retrieved packet. // packet Pointer where packet data should be stored. // Returns: Packet length in bytes if a packet was retrieved, zero otherwise. uint16_t ENC28J60_PacketReceived(uint16_t maxlen, uint8_t* packet) { uint16_t rxstat; uint16_t len; // check if a packet has been received and buffered //if( !(enc28j60Read(EIR) & EIR_PKTIF) ){ // The above does not work. See Rev. B4 Silicon Errata point 6. if( ENC28J60_Read(EPKTCNT) ==0 ){ return(0); } // Set the read pointer to the start of the received packet ENC28J60_Write(ERDPTL, (nextPacketPtr)); ENC28J60_Write(ERDPTH, (nextPacketPtr)>>8); // read the next packet pointer nextPacketPtr = ENC28J60_ReadOp(ENC28J60_READ_BUF_MEM, 0); nextPacketPtr |= ENC28J60_ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8; // read the packet length (see datasheet page 43) len = ENC28J60_ReadOp(ENC28J60_READ_BUF_MEM, 0); len |= ENC28J60_ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8; len-=4; //remove the CRC count // read the receive status (see datasheet page 43) rxstat = ENC28J60_ReadOp(ENC28J60_READ_BUF_MEM, 0); rxstat |= ENC28J60_ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8; // limit retrieve length if (len>maxlen-1){ len=maxlen-1; } // check CRC and symbol errors (see datasheet page 44, table 7-3): // The ERXFCON.CRCEN is set by default. Normally we should not // need to check this. if ((rxstat & 0x80)==0){ // invalid len=0; }else{ // copy the packet from the receive buffer ENC28J60_ReadBuffer(len, packet); } // Move the RX read pointer to the start of the next received packet // This frees the memory we just read out ENC28J60_Write(ERXRDPTL, (nextPacketPtr)); ENC28J60_Write(ERXRDPTH, (nextPacketPtr)>>8); // decrement the packet counter indicate we are done with this packet ENC28J60_WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); return(len); }
void ENC28J60_PacketSend(uint16_t len, uint8_t* packet) { // Set the write pointer to start of transmit buffer area ENC28J60_Write(EWRPTL, TXSTART_INIT&0xFF); ENC28J60_Write(EWRPTH, TXSTART_INIT>>8); // Set the TXND pointer to correspond to the packet size given ENC28J60_Write(ETXNDL, (TXSTART_INIT+len)&0xFF); ENC28J60_Write(ETXNDH, (TXSTART_INIT+len)>>8); // write per-packet control byte (0x00 means use macon3 settings) ENC28J60_WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00); // copy the packet into the transmit buffer ENC28J60_WriteBuffer(len, packet); // send the contents of the transmit buffer onto the network ENC28J60_WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. if( (ENC28J60_Read(EIR) & EIR_TXERIF) ){ ENC28J60_WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS); } }
//初始化ENC28J60 //macaddr:MAC地址 //返回值:0,初始化成功; // 1,初始化失败; u8 ENC28J60_Init(void) { u8 version; u16 retry=0; u32 temp; GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE); //使能PA,C端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4); //PA2,3,4置高 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //PC4 推挽 GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC,GPIO_Pin_4); //PC4上拉 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //中断引脚PA1上拉输入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); //PA1外部中断,中断线1 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1); EXTI_InitStructure.EXTI_Line = EXTI_Line1; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); EXTI_ClearITPendingBit(EXTI_Line1); //清除中断线1挂起标志位 NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //外部中断线1 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); SPI1_Init(); //初始化SPI SPI_Cmd(SPI1, DISABLE); // SPI外设不使能 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI设置为双线双向全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //SPI主机 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //发送接收8位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟悬空低 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //数据捕获于第1个时钟沿 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由软件控制 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式 SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器 SPI_Cmd(SPI1, ENABLE); //使能SPI外设 SPI1_SetSpeed(SPI_BaudRatePrescaler_8); //SPI1 SCK频率为36M/4=4.5Mhz //初始化MAC地址 temp=*(vu32*)(0x1FFFF7E8); //获取STM32的唯一ID的前24位作为MAC地址后三字节 enc28j60_dev.macaddr[0]=2; enc28j60_dev.macaddr[1]=0; enc28j60_dev.macaddr[2]=0; enc28j60_dev.macaddr[3]=(temp>>16)&0XFF; //低三字节用STM32的唯一ID enc28j60_dev.macaddr[4]=(temp>>8)&0XFFF; enc28j60_dev.macaddr[5]=temp&0XFF; ENC28J60_RST=0; //复位ENC28J60 delay_ms(10); ENC28J60_RST=1; //复位结束 delay_ms(10); ENC28J60_Write_Op(ENC28J60_SOFT_RESET,0,ENC28J60_SOFT_RESET); //软件复位 while(!(ENC28J60_Read(ESTAT)&ESTAT_CLKRDY)&&retry<250) //等待时钟稳定 { retry++; delay_ms(1); } if(retry>=250)return 1; //ENC28J60初始化失败 version=ENC28J60_Get_EREVID(); //获取ENC28J60的版本号 printf("ENC28J60 Version:%d\r\n",version); enc28j60_dev.NextPacketPtr=RXSTART_INIT; //接收缓冲器由一个硬件管理的循环FIFO 缓冲器构成。 //寄存器对ERXSTH:ERXSTL 和ERXNDH:ERXNDL 作 //为指针,定义缓冲器的容量和其在存储器中的位置。 //ERXST和ERXND指向的字节均包含在FIFO缓冲器内。 //当从以太网接口接收数据字节时,这些字节被顺序写入 //接收缓冲器。 但是当写入由ERXND 指向的存储单元 //后,硬件会自动将接收的下一字节写入由ERXST 指向 //的存储单元。 因此接收硬件将不会写入FIFO 以外的单 //元。 //设置接收起始字节 ENC28J60_Write(ERXSTL,RXSTART_INIT&0XFF); //设置接收缓冲区起始地址低8位 ENC28J60_Write(ERXSTH,RXSTART_INIT>>8); //设置接收缓冲区起始地址高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); //设置发送结束字节 ENC28J60_Write(ETXNDL,TXSTOP_INIT&0XFF); ENC28J60_Write(ETXNDH,TXSTOP_INIT>>8); //ERXWRPTH:ERXWRPTL 寄存器定义硬件向FIFO 中 //的哪个位置写入其接收到的字节。 指针是只读的,在成 //功接收到一个数据包后,硬件会自动更新指针。 指针可 //用于判断FIFO 内剩余空间的大小 8K-1500。 //设置接收读指针字节 ENC28J60_Write(ERXRDPTL,RXSTART_INIT&0XFF); ENC28J60_Write(ERXRDPTH,RXSTART_INIT>>8); //接收过滤器 //UCEN:单播过滤器使能位 //当ANDOR = 1 时: //1 = 目标地址与本地MAC 地址不匹配的数据包将被丢弃 //0 = 禁止过滤器 //当ANDOR = 0 时: //1 = 目标地址与本地MAC 地址匹配的数据包会被接受 //0 = 禁止过滤器 //CRCEN:后过滤器CRC 校验使能位 //1 = 所有CRC 无效的数据包都将被丢弃 //0 = 不考虑CRC 是否有效 //PMEN:格式匹配过滤器使能位 //当ANDOR = 1 时: //1 = 数据包必须符合格式匹配条件,否则将被丢弃 //0 = 禁止过滤器 //当ANDOR = 0 时: //1 = 符合格式匹配条件的数据包将被接受 //0 = 禁止过滤器 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); //bit 0 MARXEN:MAC 接收使能位 //1 = 允许MAC 接收数据包 //0 = 禁止数据包接收 //bit 3 TXPAUS:暂停控制帧发送使能位 //1 = 允许MAC 发送暂停控制帧(用于全双工模式下的流量控制) //0 = 禁止暂停帧发送 //bit 2 RXPAUS:暂停控制帧接收使能位 //1 = 当接收到暂停控制帧时,禁止发送(正常操作) //0 = 忽略接收到的暂停控制帧 ENC28J60_Write(MACON1,MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); //将MACON2 中的MARST 位清零,使MAC 退出复位状态。 ENC28J60_Write(MACON2,0x00); //bit 7-5 PADCFG2:PACDFG0:自动填充和CRC 配置位 //111 = 用0 填充所有短帧至64 字节长,并追加一个有效的CRC //110 = 不自动填充短帧 //101 = MAC 自动检测具有8100h 类型字段的VLAN 协议帧,并自动填充到64 字节长。如果不 //是VLAN 帧,则填充至60 字节长。填充后还要追加一个有效的CRC //100 = 不自动填充短帧 //011 = 用0 填充所有短帧至64 字节长,并追加一个有效的CRC //010 = 不自动填充短帧 //001 = 用0 填充所有短帧至60 字节长,并追加一个有效的CRC //000 = 不自动填充短帧 //bit 4 TXCRCEN:发送CRC 使能位 //1 = 不管PADCFG如何,MAC都会在发送帧的末尾追加一个有效的CRC。 如果PADCFG规定要 //追加有效的CRC,则必须将TXCRCEN 置1。 //0 = MAC不会追加CRC。 检查最后4 个字节,如果不是有效的CRC 则报告给发送状态向量。 //bit 0 FULDPX:MAC 全双工使能位 //1 = MAC工作在全双工模式下。 PHCON1.PDPXMD 位必须置1。 //0 = MAC工作在半双工模式下。 PHCON1.PDPXMD 位必须清零。 ENC28J60_Write(MACON3,MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN|MACON3_FULDPX); // 最大帧长度 1518 ENC28J60_Write(MAMXFLL,MAX_FRAMELEN&0XFF); ENC28J60_Write(MAMXFLH,MAX_FRAMELEN>>8); //配置背对背包间间隔寄存器MABBIPG。当使用 //全双工模式时,大多数应用使用15h 编程该寄存 //器,而使用半双工模式时则使用12h 进行编程。 ENC28J60_Write(MABBIPG,0x15); //配置非背对背包间间隔寄存器的低字节 //MAIPGL。 大多数应用使用12h 编程该寄存器。 //如果使用半双工模式,应编程非背对背包间间隔 //寄存器的高字节MAIPGH。 大多数应用使用0Ch //编程该寄存器。 ENC28J60_Write(MAIPGL,0x12); ENC28J60_Write(MAIPGH,0x0C); //设置MAC地址 ENC28J60_Write(MAADR5,enc28j60_dev.macaddr[0]); ENC28J60_Write(MAADR4,enc28j60_dev.macaddr[1]); ENC28J60_Write(MAADR3,enc28j60_dev.macaddr[2]); ENC28J60_Write(MAADR2,enc28j60_dev.macaddr[3]); ENC28J60_Write(MAADR1,enc28j60_dev.macaddr[4]); ENC28J60_Write(MAADR0,enc28j60_dev.macaddr[5]); //配置PHY为全双工 LEDB为拉电流 ENC28J60_PHY_Write(PHCON1,PHCON1_PDPXMD); //HDLDIS:PHY 半双工环回禁止位 //当PHCON1.PDPXMD = 1 或PHCON1.PLOOPBK = 1 时: //此位可被忽略。 //当PHCON1.PDPXMD = 0 且PHCON1.PLOOPBK = 0 时: //1 = 要发送的数据仅通过双绞线接口发出 //0 = 要发送的数据会环回到MAC 并通过双绞线接口发出 ENC28J60_PHY_Write(PHCON2,PHCON2_HDLDIS); //ECON1 寄存器 //寄存器3-1 所示为ECON1 寄存器,它用于控制 //ENC28J60 的主要功能。 ECON1 中包含接收使能、发 //送请求、DMA 控制和存储区选择位。 ENC28J60_Set_Bank(ECON1); //EIE: 以太网中断允许寄存器 //bit 7 INTIE: 全局INT 中断允许位 //1 = 允许中断事件驱动INT 引脚 //0 = 禁止所有INT 引脚的活动(引脚始终被驱动为高电平) //bit 6 PKTIE: 接收数据包待处理中断允许位 //1 = 允许接收数据包待处理中断 //0 = 禁止接收数据包待处理中断 ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,EIE,EIE_INTIE|EIE_PKTIE|EIE_TXIE|EIE_TXERIE|EIE_RXERIE); // enable packet reception //bit 2 RXEN:接收使能位 //1 = 通过当前过滤器的数据包将被写入接收缓冲器 //0 = 忽略所有接收的数据包 ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_RXEN); printf("ENC28J60 Duplex:%s\r\n",ENC28J60_Get_Duplex()?"Full Duplex":"Half Duplex"); //获取双工方式 return 0; }
void ENC28J60_Init(volatile avr32_spi_t *spi, uint8_t spiDeviceId, spi_flags_t spiFlags, uint32_t spiBaudrate, uint8_t* macaddr) { spiDevice.id = spiDeviceId; avr32SPI = spi; spi_master_init(avr32SPI); spi_master_setup_device(avr32SPI, &spiDevice, spiFlags, spiBaudrate, spiDevice.id); spi_enable(avr32SPI); ENC28J60_WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); while(!(ENC28J60_Read(ESTAT) & ESTAT_CLKRDY)); // do bank 0 stuff // initialize receive buffer // 16-bit transfers, must write low byte first // set receive buffer start address nextPacketPtr = RXSTARTBUFFER; // Rx start ENC28J60_Write(ERXSTL, RXSTARTBUFFER&0xFF); ENC28J60_Write(ERXSTH, RXSTARTBUFFER>>8); // set receive pointer address ENC28J60_Write(ERXRDPTL, RXSTARTBUFFER&0xFF); ENC28J60_Write(ERXRDPTH, RXSTARTBUFFER>>8); // RX end ENC28J60_Write(ERXNDL, RXSTOPBUFFER&0xFF); ENC28J60_Write(ERXNDH, RXSTOPBUFFER>>8); // TX start ENC28J60_Write(ETXSTL, TXSTART_INIT&0xFF); ENC28J60_Write(ETXSTH, TXSTART_INIT>>8); // TX end ENC28J60_Write(ETXNDL, TXSTOP_INIT&0xFF); ENC28J60_Write(ETXNDH, TXSTOP_INIT>>8); // do bank 1 stuff, packet filter: // For broadcast packets we allow only ARP packtets // All other packets should be unicast only for our mac (MAADR) // // The pattern to match on is therefore // Type ETH.DST // ARP BROADCAST // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 // in binary these poitions are:11 0000 0011 1111 // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 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); // // // do bank 2 stuff // enable MAC receive ENC28J60_Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); // bring MAC out of reset ENC28J60_Write(MACON2, 0x00); // enable automatic padding to 60bytes and CRC operations ENC28J60_WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); // 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, 0x12); // 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]); // no loopback of transmitted frames ENC28J60_PhyRegisterWrite(PHCON2, PHCON2_HDLDIS); // switch to bank 0 ENC28J60_SetBank(ECON1); // enable interrutps ENC28J60_WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE); // enable packet reception ENC28J60_WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); // MagJack LED config // LEDA=greed LEDB=yellow // // 0x880 is PHLCON LEDB=on, LEDA=on // enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00); ENC28J60_PhyRegisterWrite(PHLCON,0x880); // // 0x990 is PHLCON LEDB=off, LEDA=off // enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00); ENC28J60_PhyRegisterWrite(PHLCON,0x990); // // 0x880 is PHLCON LEDB=on, LEDA=on // enc28j60PhyWrite(PHLCON,0b0000 1000 1000 00 00); ENC28J60_PhyRegisterWrite(PHLCON,0x880); // // 0x990 is PHLCON LEDB=off, LEDA=off // enc28j60PhyWrite(PHLCON,0b0000 1001 1001 00 00); ENC28J60_PhyRegisterWrite(PHLCON,0x990); // // 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit // enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10); ENC28J60_PhyRegisterWrite(PHLCON,0x476); }
void ENC28J60_Clkout(uint8_t clk) { //setup clkout: 2 is 12.5MHz: ENC28J60_Write(ECOCON, clk & 0x7); }