stm32f103C8T6移植enc28j60+UIP1.0(吐槽篇)

移植环境(蓝色粗体字为特别注意内容)
1,开发板:STM32F103C8T6最小系统开发板。
2,开发环境:Keil uv5

3,参考文献:https://blog.csdn.net/wzs298/article/details/12228481

移植ENC28J60这个网络模块可谓是困难重重啊,。。。。。找了很多个例子都没有成功的,只能说很坑很坑,我不知道网上为什么那么多人抄袭,,没有经过自己验证就copy出来。。。。捣鼓了一天终于把这个坑爹的模块搞定了,,,,

先来贴一张图片:

stm32f103C8T6移植enc28j60+UIP1.0(吐槽篇)_第1张图片    

stm32f103C8T6移植enc28j60+UIP1.0(吐槽篇)_第2张图片


本例程移植uIP-1.0协议栈,演示开发板和PC间的TCP通信。自定义了一个简单的应用层
通信协议。本例程实现的功能有:
(1)通过PC机控制板子上的LED;
(2)实现了一个简单的Web服务器。
  选用的网卡芯片ENC28J60,10M带宽。
本例程设置的缺省IP地址是 192.168.1.15,默认的TCP服务器监听端口是1200, WEB服务器监听端口80,
   UDP服务器监听端口2000。
开发板工作在TCP服务器模式。PC机工作在TCP客户端模式。
PC机上需要运行网络调试助手软件。
用户可以做如下测试:
(1)ping 试验 (ICMP)
点击windows 开始-运行,执行cmd命令,然后在dos窗口输入 ping 192.168.1.15
应该看到如下结果:
Reply from 192.168.1.15: bytes=32 time<1ms TTL=128
Reply from 192.168.1.15: bytes=32 time<1ms TTL=128
Reply from 192.168.1.15: bytes=32 time<1ms TTL=128

Reply from 192.168.1.15: bytes=32 time<1ms TTL=128

遇到的问题:

1、模块引脚的连接方式

一般接线为:(左边主设备,右边从设备):
SPIx_nSS(PA4)======CS
SPIx_SCK(PA5)======SCK
SPIx_MISO(PA6)======SDO(SO)
SPIx_MOSI(PA7)======SDI(SI)
PA1===========INT

其中很多教程都没提到要连接INT引脚,测试发现,没有连接该引脚,无法初始化!!!

2、SPI初始化方式,网上流行的很多方式都试过,都存在各种各样的问题,需要的朋友我把文件放到了本文末尾,需要的同学可以自行下载~~~

以上两个问题可以把人搞的晕头转向,还好我手头有示波器,示波器真是个好帮手~~~~~~

ENC28J60.c文件如下(如需要完整的工程,请点击本文末尾的下载连接下载,下载之后按照工程说明连接好引脚即可下载到开发板,非常方便,1000%成功!!!!!!!!!

#include "ENC28J60.h"
#include "spi.h"
#include  "uip.h"
#include 
#include  "uart.h"
#include  "delay.h"

static uint8_t Enc28j60Bank;
static uint16_t gNextPacketPtr;
static uint8_t erxfcon;


unsigned char ENC28J60_SendByte(unsigned char dt)
{
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

	SPI_I2S_SendData(SPI1, dt);

	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

	return SPI_I2S_ReceiveData(SPI1);
}

uint8_t enc28j60ReadOp(uint8_t op, uint8_t address)
{
	uint8_t temp;
	enableChip;
	// issue read command
	ENC28J60_SendByte(op | (address & ADDR_MASK));
	temp = ENC28J60_SendByte(0xFF);
	if (address & 0x80)
		temp = ENC28J60_SendByte(0xFF);

	// release CS
	disableChip;
	return temp;
}

void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data)
{
	enableChip;
	ENC28J60_SendByte(op | (address & ADDR_MASK));
	ENC28J60_SendByte(data);
	disableChip;
}

void enc28j60PowerDown()
{
	enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
	while(enc28j60Read(ESTAT) & ESTAT_RXBUSY);
	while(enc28j60Read(ECON1) & ECON1_TXRTS);
	enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
}

void enc28j60PowerUp()
{
	enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
	while(!enc28j60Read(ESTAT) & ESTAT_CLKRDY);
}


void enc28j60ReadBuffer(uint16_t len, uint8_t *data)
{
	enableChip;
	ENC28J60_SendByte(ENC28J60_READ_BUF_MEM);
	while (len--)
	{
		*data++ = ENC28J60_SendByte(0x00);
	}
	disableChip;
	// Remove next line suggested by user epam - not needed
	//    *data='\0';
}

static uint16_t enc28j60ReadBufferWord()
{
	uint16_t result;
	enc28j60ReadBuffer(2, (uint8_t *) &result);
	return result;
}


void enc28j60WriteBuffer(uint16_t len, uint8_t *data)
{
	enableChip;
	ENC28J60_SendByte(ENC28J60_WRITE_BUF_MEM);
	while (len--)
		ENC28J60_SendByte(*data++);

	disableChip;
}

void enc28j60SetBank(uint8_t address)
{
	if ((address & BANK_MASK) != Enc28j60Bank)
	{
		enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_BSEL1 | ECON1_BSEL0);
		Enc28j60Bank = address & BANK_MASK;
		enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, Enc28j60Bank >> 5);
	}
}

uint8_t enc28j60Read(uint8_t address)
{
	// set the bank
	enc28j60SetBank(address);
	// do the read
	return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
}

void enc28j60WriteWord(uint8_t address, uint16_t data)
{
	enc28j60Write(address, data & 0xff);
	enc28j60Write(address + 1, data >> 8);
}

// read upper 8 bits
uint16_t enc28j60PhyReadH(uint8_t address)
{
	// Set the right address and start the register read operation
	enc28j60Write(MIREGADR, address);
	enc28j60Write(MICMD, MICMD_MIIRD);
	delay_us(15);

	// wait until the PHY read completes
	while(enc28j60Read(MISTAT) & MISTAT_BUSY);

	// reset reading bit
	enc28j60Write(MICMD, 0x00);

	return (enc28j60Read(MIRDH));
}


void enc28j60Write(uint8_t address, uint8_t data)
{
	// set the bank
	enc28j60SetBank(address);
	// do the write
	enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
}


void enc28j60PhyWrite(uint8_t address, uint16_t data)
{
	// set the PHY register address
	enc28j60Write(MIREGADR, address);
	// write the PHY data
	enc28j60Write(MIWRL, data);
	enc28j60Write(MIWRH, data >> 8);
	// wait until the PHY write completes
	while(enc28j60Read(MISTAT) & MISTAT_BUSY)
	{
		delay_us(15);
	}
}
/*
static void enc28j60PhyWriteWord(byte address, word data) {
    enc28j60Write(MIREGADR, address);
    //enc28j60WriteByte(MIREGADR, address);
    enc28j60WriteWord(MIWRL, data);
    while (enc28j60ReadByte(MISTAT) & MISTAT_BUSY)
        ;
}
*/
void enc28j60clkout(uint8_t clk)
{
	//setup clkout: 2 is 12.5MHz:
	enc28j60Write(ECOCON, clk & 0x7);
}

void enc28j60Init( uint8_t *macaddr )
{
	enableChip; // ss=0

	// perform system reset
	enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
	delay_ms(50);
	// check CLKRDY bit to see if reset is complete
	// The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
	//while(!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));
	// do bank 0 stuff
	// initialize receive buffer
	// 16-bit transfers, must write low byte first
	// set receive buffer start address
	gNextPacketPtr = RXSTART_INIT;
	// Rx start
	enc28j60WriteWord(ERXSTL, RXSTART_INIT);
	// set receive pointer address
	enc28j60WriteWord(ERXRDPTL, RXSTART_INIT);
	// RX end
	enc28j60WriteWord(ERXNDL, RXSTOP_INIT);
	// TX start
	enc28j60WriteWord(ETXSTL, TXSTART_INIT);
	// TX end
	enc28j60WriteWord(ETXNDL, TXSTOP_INIT);
	// 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

	//enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);
	//Change to add ERXFCON_BCEN recommended by epam
	//enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN);
	erxfcon =  ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_BCEN;
	enc28j60Write(ERXFCON, erxfcon );
	enc28j60WriteWord(EPMM0, 0x303f);
	enc28j60WriteWord(EPMCSL, 0xf7f9);
	//
	// do bank 2 stuff
	// enable MAC receive
	enc28j60Write(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
	// bring MAC out of reset
	enc28j60Write(MACON2, 0x00);
	// enable automatic padding to 60bytes and CRC operations
	enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN); //|MACON3_FULDPX);
	// set inter-frame gap (non-back-to-back)
	enc28j60WriteWord(MAIPGL, 0x0C12);
	// set inter-frame gap (back-to-back)
	enc28j60Write(MABBIPG, 0x12);
	// Set the maximum packet size which the controller will accept
	// Do not send packets longer than MAX_FRAMELEN:
	enc28j60WriteWord(MAMXFLL, MAX_FRAMELEN);
	// do bank 3 stuff
	// write MAC address
	// NOTE: MAC address in ENC28J60 is byte-backward
	enc28j60Write(MAADR5, macaddr[0]);
	enc28j60Write(MAADR4, macaddr[1]);
	enc28j60Write(MAADR3, macaddr[2]);
	enc28j60Write(MAADR2, macaddr[3]);
	enc28j60Write(MAADR1, macaddr[4]);
	enc28j60Write(MAADR0, macaddr[5]);
	// no loopback of transmitted frames
	enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS);
	// switch to bank 0
	enc28j60SetBank(ECON1);
	// enable interrutps
	enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE);
	// enable packet reception
	enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);


}

// read the revision of the chip:
uint8_t enc28j60getrev(void)
{
	uint8_t rev;
	rev = enc28j60Read(EREVID);
	// microchip forgot to step the number on the silcon when they
	// released the revision B7. 6 is now rev B7. We still have
	// to see what they do when they release B8. At the moment
	// there is no B8 out yet
	if (rev > 5) rev++;
	return(rev);
}

// A number of utility functions to enable/disable broadcast and multicast bits
void enc28j60EnableBroadcast( void )
{
	erxfcon |= ERXFCON_BCEN;
	enc28j60Write(ERXFCON, erxfcon);
}

void enc28j60DisableBroadcast( void )
{
	erxfcon &= (0xff ^ ERXFCON_BCEN);
	enc28j60Write(ERXFCON, erxfcon);
}

void enc28j60EnableMulticast( void )
{
	erxfcon |= ERXFCON_MCEN;
	enc28j60Write(ERXFCON, erxfcon);
}

void enc28j60DisableMulticast( void )
{
	erxfcon &= (0xff ^ ERXFCON_MCEN);
	enc28j60Write(ERXFCON, erxfcon);
}


// link status
uint8_t enc28j60linkup(void)
{
	// bit 10 (= bit 3 in upper reg)
	return(enc28j60PhyReadH(PHSTAT2) && 4);
}

void enc28j60PacketSend(uint16_t len, uint8_t *packet)
{
	// Check no transmit in progress
	while (enc28j60ReadOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS)
	{
		// Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
		if( (enc28j60Read(EIR) & EIR_TXERIF) )
		{
			enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
			enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
		}
	}

	// Set the write pointer to start of transmit buffer area
	enc28j60WriteWord(EWRPTL, TXSTART_INIT);
	// Set the TXND pointer to correspond to the packet size given
	enc28j60WriteWord(ETXNDL, (TXSTART_INIT + len));
	// write per-packet control byte (0x00 means use macon3 settings)
	enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
	// copy the packet into the transmit buffer
	enc28j60WriteBuffer(len, packet);
	// send the contents of the transmit buffer onto the network
	enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
	// Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
}

// just probe if there might be a packet
//uint8_t enc28j60hasRxPkt(void)
//{
//       return enc28j60ReadByte(EPKTCNT) > 0;
//}

// 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 enc28j60PacketReceive(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( enc28j60Read(EPKTCNT) == 0 )
	{
		return(0);
	}

	// Set the read pointer to the start of the received packet
	enc28j60WriteWord(ERDPTL, gNextPacketPtr);
	//enc28j60Write(ERDPTL, (gNextPacketPtr &0xFF));
	//enc28j60Write(ERDPTH, (gNextPacketPtr)>>8);
	// read the next packet pointer
	gNextPacketPtr  = enc28j60ReadBufferWord();
	//gNextPacketPtr  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
	//gNextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
	// read the packet length (see datasheet page 43)
	len = enc28j60ReadBufferWord() - 4;
	//len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
	//len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
	//len-=4; //remove the CRC count
	// read the receive status (see datasheet page 43)
	rxstat  = enc28j60ReadBufferWord();
	//rxstat  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
	//rxstat |= ((uint16_t)enc28j60ReadOp(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
		enc28j60ReadBuffer(len, packet);
	}
	// Move the RX read pointer to the start of the next received packet
	// This frees the memory we just read out
	enc28j60WriteWord(ERXRDPTL, gNextPacketPtr );
	//enc28j60Write(ERXRDPTL, (gNextPacketPtr &0xFF));
	//enc28j60Write(ERXRDPTH, (gNextPacketPtr)>>8);
	// However, compensate for the errata point 13, rev B4: enver write an even address!
	if ((gNextPacketPtr - 1 < RXSTART_INIT)
	        || (gNextPacketPtr - 1 > RXSTOP_INIT))
	{
		enc28j60WriteWord(ERXRDPTL, RXSTOP_INIT);
		//enc28j60Write(ERXRDPTL, (RXSTOP_INIT)&0xFF);
		//enc28j60Write(ERXRDPTH, (RXSTOP_INIT)>>8);
	}
	else
	{
		enc28j60WriteWord(ERXRDPTL, (gNextPacketPtr - 1));
		//enc28j60Write(ERXRDPTL, (gNextPacketPtr-1)&0xFF);
		//enc28j60Write(ERXRDPTH, (gNextPacketPtr-1)>>8);
	}
	// decrement the packet counter indicate we are done with this packet
	enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
	return(len);

}



/****************************************************************************
* 名    称:void tapdev_init(void)
* 功    能:配置网卡硬件,设置IP地址
* 入口参数:
* 出口参数:
* 说    明:
* 调用方法:
****************************************************************************/
void tapdev_init(void)
{
	etherdev_init();
}

/****************************************************************************
* 名    称:uint16_t tapdev_read(void)
* 功    能:读取一包数据
* 入口参数:
* 出口参数: 如果一个数据包收到返回数据包长度,以字节为单位,否则为零。
* 说    明:
* 调用方法:
****************************************************************************/
uint16_t tapdev_read(void)
{
	return  enc28j60PacketReceive(1500, uip_buf);
}
/****************************************************************************
* 名    称:void tapdev_send(void)
* 功    能:发送一包数据
* 入口参数:
* 出口参数:
* 说    明:
* 调用方法:
****************************************************************************/
void tapdev_send(void)
{
	enc28j60PacketSend(uip_len, uip_buf);
}

/******************* (C) COPYRIGHT Pang 2018 *****END OF FILE****/



点击下载工程


你可能感兴趣的:(stm32f103C8T6移植enc28j60+UIP1.0(吐槽篇))