ENC28J60学习笔记——第3部分

0.相关资料

    相关资料中包括其他精彩博文和代码仓库
    【嵌入式 TCP IP 资料汇总】   
    【ENC28J60学习笔记——索引】 【第1部分】【第2部分】【第3部分】【第4部分】
    【STM32NET学习笔记——索引】
    【uIP学习笔记】
    【LwIP学习笔记——STM32 ENC28J60移植与入门】


4.ENC28J60写操作

通过ENC28J60发送以太网数据包,操作ENC28J60硬件缓冲区的发送部分即可。每次发送时总是从发送缓冲区的起始地址开始填充数据,数据填充的结束地址和数据包长度有关。设置发送缓冲区大小之后可向发送缓冲区填充数据,即调用ENC28J60_WRITE_BUF_MEM操作命令,接着置位ECON1中的 ECON1_TXRTS位启动发送,并使用等待法不断查询是否发送完毕。基本的思路还是和SPI或UART发送数据相似,即填充数据,启动发送,查询发送完成。写操作的输入参数为数据包的长度len和数据包指针packet,该参数正好和uIP的网络层操作函数相对应。 
void enc28j60PacketSend(unsigned int len, unsigned char* packet)
{
	/* 查询发送逻辑复位位 */
	while((enc28j60Read(ECON1) & ECON1_TXRTS)!= 0);
  
  /* 设置发送缓冲区起始地址 */    
	enc28j60Write(EWRPTL, TXSTART_INIT & 0xFF);
	enc28j60Write(EWRPTH, TXSTART_INIT >> 8);


	/* 设置发送缓冲区结束地址 该值对应发送数据包长度 */   
	enc28j60Write(ETXNDL, (TXSTART_INIT + len) & 0xFF);
	enc28j60Write(ETXNDH, (TXSTART_INIT + len) >>8);


	/* 发送之前发送控制包格式字 */
	enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);


	/* 通过ENC28J60发送数据包 */
	enc28j60WriteBuffer(len, packet);


	/* 开始发送 */
	enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);


  /* 复位发送逻辑的问题 */
	if( (enc28j60Read(EIR) & EIR_TXERIF) )
	{
		enc28j60SetBank(ECON1);
    enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
  }
}

5 ENC28J60读操作

读操作要比写操作复杂一些。写操作时每次总是从硬件发送缓冲区的起始地址开始操作,而读操作时需要不断修改接收缓冲区的读指针地址,该参数需要通过NextPacketPtr完成,该变量为uint16_t类型的全局变量。读操作时,先通过寄存器查看是否存在以太网数据包,读EPKTCNT寄存器便可返回以太网数据包的个数;若存在以太网数据包则设定读指针的地址,执行读缓冲区操作,ENC28J60的以太网接收数据包中前两个字节为下一个以太网数据包的起始地址,立即保存该参数至NextPacketPtr全局变量;以太网数据包中的后两个字节为该数据包的长度,该长度指从目标MAC地址开始的数据包的长度,进行处理时还需要舍弃最后的4字节CRC校验结果;通过读缓冲区操作码把长度为Len的以太网接收数据包保存至RAM中的某个位置,例如rxtx_buf全局数组。最后根据NextPacketPtr移动读指针以便下次操作,并通过操作ECON2的ECON2_PKTDEC位递减了以太网数据包个数。
unsigned int enc28j60PacketReceive(unsigned int maxlen, unsigned char* packet)
{
	unsigned int rxstat;
	unsigned int len;


	/* 是否收到以太网数据包 */
	if( enc28j60Read(EPKTCNT) == 0 )
	{
		return(0);
    }


	/* 设置接收缓冲器读指针 */
	enc28j60Write(ERDPTL, (NextPacketPtr));
	enc28j60Write(ERDPTH, (NextPacketPtr)>>8);


  /* 接收数据包结构示例 数据手册43页 */


	/* 读下一个包的指针 */
	NextPacketPtr  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
	NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;


	/* 读包的长度 */
	len  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
	len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;


   /* 去除CRC校验部分 */
   len-= 4; 	
  			
	/* 读取接收状态 */
	rxstat  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
	rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;


	/* 限制检索的长度	*/  
  if (len > maxlen-1)
	{
    len = maxlen-1;
  }
  /* 检查CRC和符号错误 */
  /* ERXFCON.CRCEN是默认设置。通常我们不需要检查 */
  if ((rxstat & 0x80)==0)
	{
	   //无效的
	   len = 0;
	}
	else
	{
    /* 从接收缓冲器中复制数据包 */
    enc28j60ReadBuffer(len, packet);
  }


  /* 移动接收缓冲区 读指针*/
	enc28j60Write(ERXRDPTL, (NextPacketPtr));
	enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8);


	/* 数据包递减 */
	enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);


  /* 返回长度 */
	return(len);
}


你可能感兴趣的:(ENC28J60,嵌入式以太网)