SAM D21G + ENC28J60 ... What I am doing wrong

Discussions around product based on ARM Cortex M0+ core.

Moderator: nferre

mirch25
Posts: 1
Joined: Fri Jun 05, 2015 10:09 am

SAM D21G + ENC28J60 ... What I am doing wrong

Mon Sep 12, 2016 2:41 pm

Hello.

I try connect IC SAM D21G17A with ENC28J60 Board over SPI. I use this reference: https://github.com/bprayudha/avr-enc28j60

When I asking in while loop by "plen = ENC28J60_PacketReceive(BUFFER_SIZE,buf);" ... "plen" is always 0! Why? What I am doing it wrong?

main.c

Code: Select all

void CL_controller_run(void)
{
	uint16_t dat_p;

	ENC28J60_Initialization(myMACaddress);
	
	//DelayLoop();
	for (int i = 0; i < 50; i++)
	{
		// delay
	}

	ENC28J60_PhyWrite(PHLCON,0x0476);
	//DelayLoop();
	for (int i = 0; i < 50; i++)
	{
		// delay
	}

	ENC28J60_Init_Network(myMACaddress, myIPaddress, myPORT);

	while(1)
	{
		
		


		plen = ENC28J60_PacketReceive(BUFFER_SIZE,buf);
		
		if(plen == 0)
		{
			continue;
		}
		
		
		if(eth_is_arp(buf,plen))
		{
			arp_reply(buf);
			continue;
		}

		if(eth_is_ip(buf,plen)==0)
		{
			continue;
		}
		
		if(buf[IP_PROTO]==IP_ICMP && buf[ICMP_TYPE]==ICMP_REQUEST) {
			icmp_reply(buf,plen);
			continue;
		}

		if(buf[IP_PROTO]==IP_TCP && buf[TCP_DST_PORT]==0 && buf[TCP_DST_PORT+1]==myPORT)
		{
			
			if(buf[TCP_FLAGS] & TCP_SYN)
			{
				tcp_synack(buf);
				continue;
			}
			
			if(buf[TCP_FLAGS] & TCP_ACK)
			{
				init_len_info(buf);
				dat_p = get_tcp_data_ptr();
				if(dat_p==0)
				{
					if(buf[TCP_FLAGS] & TCP_FIN) tcp_ack(buf);
					continue;
				}
				
				if(strstr((char*)&(buf[dat_p]),"User Agent"))
				{
					browser=0;
				}
				else if(strstr((char*)&(buf[dat_p]),"MSIE"))
				{
					browser=1;
				}
				else 
				{
					browser=2;
				}
				
				if(strncmp("/ ",(char*)&(buf[dat_p+4]),2)==0)
				{
					//testpage();
					//sendpage();
					continue;
				}
			}
		}
		
	}
}
// SPI & ENC28J60 configuration

Code: Select all

#include "DL_spi.h"

bool transrev_complete_spi_master = false;


static uint8_t ENC28J60_Bank;
static uint16_t gNextPacketPtr;

void configure_spi_master(void)
{
	struct spi_config config_spi_master;
	struct spi_slave_inst_config slave_dev_config;
	spi_slave_inst_get_config_defaults(&slave_dev_config);
	slave_dev_config.ss_pin = SLAVE_SELECT_PIN;
	spi_attach_slave(&slave, &slave_dev_config);
	spi_get_config_defaults(&config_spi_master);
	config_spi_master.mux_setting = EXT1_SPI_SERCOM_MUX_SETTING;
	config_spi_master.pinmux_pad0 = EXT1_SPI_SERCOM_PINMUX_PAD0;
	config_spi_master.pinmux_pad1 = PINMUX_UNUSED;
	config_spi_master.pinmux_pad2 = EXT1_SPI_SERCOM_PINMUX_PAD2;
	config_spi_master.pinmux_pad3 = EXT1_SPI_SERCOM_PINMUX_PAD3;
	config_spi_master.transfer_mode = SPI_TRANSFER_MODE_0;
	spi_init(&spi_master_instance, EXT1_SPI_MODULE, &config_spi_master);
	spi_enable(&spi_master_instance);
}

static void callback_spi_master( struct spi_module *const module)
{
	transrev_complete_spi_master = true;
}

void configure_spi_master_callbacks(void)
{
	spi_register_callback(&spi_master_instance, callback_spi_master,
	SPI_CALLBACK_BUFFER_TRANSCEIVED);
	spi_enable_callback(&spi_master_instance, SPI_CALLBACK_BUFFER_TRANSCEIVED);
}

bool DL_spi_get_flag(void)
{
	bool temp_transrev_complete_spi_master = transrev_complete_spi_master;
	transrev_complete_spi_master = false;
	return temp_transrev_complete_spi_master;
}

void ENC28J60_Initialization(uint8_t* MACaddress)
{
	ENC28J60_WriteOpSR(SC,0,SC);
	
	for (int i = 0; i < 3000; i++)
	{
		// delay
	}

	gNextPacketPtr = RXSTART_INIT;

	// Setup the 8kB Memory space on the ENC28J60 by defining ERXST and ERXND
	ENC28J60_Write(ERXSTL,(RXSTART_INIT&0xFF)); // ERXST => ERXSTL & ERXSTH
	ENC28J60_Write(ERXSTH,(RXSTART_INIT>>8));

	ENC28J60_Write(ERXNDL,(RXSTART_INIT&0xFF)); // ERXND => ERXNDL & ERXNDH
	ENC28J60_Write(ERXNDH,(RXSTART_INIT>>8));

	// Set RX Read pointer to start of RX Buffer
	ENC28J60_Write(ERXRDPTL,(RXSTART_INIT&0xFF));  // ERXRDPT => ERXRDPTL & ERXRDPTH
	ENC28J60_Write(ERXRDPTH,(RXSTART_INIT>>8));

	// Setup TRANSMIT BUFFER
	ENC28J60_Write(ETXSTL,TXSTART_INIT&0xFF); // ETXST => ETXSTL & ETXSTH
	ENC28J60_Write(ETXSTH,TXSTART_INIT>>8);


	// Receive filters
	/*ENC28J60_Write(ERXFCON,UCEN|CRCEN|PMEN);
	ENC28J60_Write(EPMM0,0x3f);
	ENC28J60_Write(EPMM1,0x30);
	ENC28J60_Write(EPMCSL,0xf9);
	ENC28J60_Write(EPMCSH,0xf7);*/





	ENC28J60_Write(MACON1,(MARXEN|TXPAUS|RXPAUS));
	ENC28J60_Write(MACON2,0x00);
	ENC28J60_WriteOp(BFS,MACON3,(PADCFG0|TXCRCEN|FRMLNEN));


	ENC28J60_Write(MAIPGL,0x12);
	ENC28J60_Write(MAIPGH,0x0C);
	ENC28J60_Write(MABBIPG,0x12);
	ENC28J60_Write(MAMXFLL,MAX_FRAMELEN&0xFF);
	ENC28J60_Write(MAMXFLH,MAX_FRAMELEN>>8);

	ENC28J60_Write(MAADR5,MACaddress[0]);
	ENC28J60_Write(MAADR4,MACaddress[1]);
	ENC28J60_Write(MAADR3,MACaddress[2]);
	ENC28J60_Write(MAADR2,MACaddress[3]);
	ENC28J60_Write(MAADR1,MACaddress[4]);
	ENC28J60_Write(MAADR0,MACaddress[5]);







	ENC28J60_PhyWrite(PHCON2,HDLDIS);
	ENC28J60_SetBank(ECON1);
	ENC28J60_WriteOp(BFS,EIE,(INTIE|PKTIE));
	ENC28J60_WriteOp(BFS,ECON1,RXEN);
}

void ENC28J60_Write(uint8_t address, uint8_t data) {
	ENC28J60_SetBank(address);
	ENC28J60_WriteOp(WCR,address,data);
}

void ENC28J60_SetBank(uint8_t address) {
	if((address & BANK_MASK) != ENC28J60_Bank) {
		ENC28J60_WriteOp(BFC,ECON1,(BSEL1|BSEL0));
		ENC28J60_WriteOp(BFS,ECON1,(address & BANK_MASK)>>5);
		ENC28J60_Bank = (address & BANK_MASK);
	}
}

void ENC28J60_WriteOpSR(uint8_t op,uint8_t address,uint8_t data) {
	uint8_t tx[SOFT_RESET_BUFFER_LENGTH];
	tx[0] = (op | (address & ADDR_MASK));
	spi_select_slave(&spi_master_instance, &slave, true);
	spi_write_buffer_job(&spi_master_instance, tx, SOFT_RESET_BUFFER_LENGTH);
	spi_select_slave(&spi_master_instance, &slave, false);
}

void ENC28J60_WriteOp(uint8_t op,uint8_t address,uint8_t data) {
	uint8_t tx[BUFFER_LENGTH];
	tx[0] = (op | (address & ADDR_MASK));
	tx[1] = data;
	spi_select_slave(&spi_master_instance, &slave, true);
	spi_write_buffer_job(&spi_master_instance, tx, BUFFER_LENGTH);
	spi_select_slave(&spi_master_instance, &slave, false);
}

void ENC28J60_ReadBuffer(uint16_t len, uint8_t* data) {
	uint8_t rx[BUFFER_LENGTH];
	spi_select_slave(&spi_master_instance, &slave, true);
	spi_read_buffer_job(&spi_master_instance, rx, BUFFER_LENGTH, 0);
	spi_select_slave(&spi_master_instance, &slave, false);
}

void ENC28J60_WriteBuffer(uint16_t len, uint8_t* data) {
	uint8_t tx[BUFFER_LENGTH];
	tx[0] = WBM;
	tx[1] = data;
	spi_select_slave(&spi_master_instance, &slave, true);
	spi_write_buffer_job(&spi_master_instance, tx, BUFFER_LENGTH);
	spi_select_slave(&spi_master_instance, &slave, false);
}

void ENC28J60_WriteReadBuffer(uint16_t len, uint8_t* data)
{
	uint8_t tx[BUFFER_LENGTH];
	uint8_t rx[BUFFER_LENGTH];
	tx[0] = WBM;
	tx[1] = data;
	spi_select_slave(&spi_master_instance, &slave, true);
	spi_transceive_buffer_job(&spi_master_instance, tx, rx, BUFFER_LENGTH);
	spi_select_slave(&spi_master_instance, &slave, false);
	rx[1] = data;
}

void ENC28J60_PhyWrite(uint8_t address,uint16_t data) {
	ENC28J60_Write(MIREGADR,address);
	ENC28J60_Write(MIWRL,data);
	ENC28J60_Write(MIWRH,data>>8);
	while(ENC28J60_Read(MISTAT) & BUSY)
	{
		for (int i = 0; i < 100; i++)
		{
			// delay
		}
	}
}

uint8_t ENC28J60_Read(uint8_t address) {
	ENC28J60_SetBank(address);
	return ENC28J60_ReadOp(RCR,address);
}

uint8_t ENC28J60_ReadOp(uint8_t op,uint8_t address) {
	uint8_t tx[BUFFER_LENGTH];
	uint8_t rx[BUFFER_LENGTH];

	for (int i = 0; i < BUFFER_LENGTH; i++)
	{
		tx[i] = 0;
		rx[i] = 0;
	}
	
	spi_select_slave(&spi_master_instance, &slave, true);
	tx[0] = (op | (address & ADDR_MASK));
	tx[1] = 0x00;
	spi_transceive_buffer_job(&spi_master_instance, tx, rx, BUFFER_LENGTH);
	spi_select_slave(&spi_master_instance, &slave, false);

	return rx[0];
}

void ENC28J60_ClkOut(uint8_t clock) {
	ENC28J60_Write(ECOCON,clock & 0x7);
}

static uint8_t macaddr[6];
static uint8_t ipaddr[4];
static uint16_t wwwport;
static int16_t info_hdr_len = 0x0000;
static int16_t info_data_len = 0x0000;
static uint8_t seqnum = 0x0A;

void ENC28J60_Init_Network(uint8_t *mymac, uint8_t *myip, uint16_t mywwwport) {
	uint8_t i;
	wwwport = mywwwport;
	for(i=0;i<4;i++) ipaddr[i]=myip[i];
	for(i=0;i<6;i++) macaddr[i]=mymac[i];
}

uint16_t ENC28J60_PacketReceive(uint16_t maxlen,uint8_t* packet) {
	
	uint16_t rxstat;
	uint16_t len;

	if(ENC28J60_Read(EPKTCNT)==0)
	{
		return(0);
	}

	ENC28J60_Write(ERDPTL,(gNextPacketPtr & 0xFF));
	ENC28J60_Write(ERDPTH,(gNextPacketPtr)>>8);

	gNextPacketPtr  = ENC28J60_ReadOp(RBM,0);
	gNextPacketPtr |= ENC28J60_ReadOp(RBM,0)<<8;

	len  = ENC28J60_ReadOp(RBM,0);
	len |= ENC28J60_ReadOp(RBM,0)<<8;
	len -= 4;

	rxstat  = ENC28J60_ReadOp(RBM,0);
	rxstat |= ((uint16_t)ENC28J60_ReadOp(RBM,0))<<8;

	if (len>maxlen-1)
	{
		len=maxlen-1;
	}

	if ((rxstat & 0x80)==0)
	{
		len=0;
	}
	else
	{
		ENC28J60_ReadBuffer(len,packet);
	}

	ENC28J60_Write(ERXRDPTL,(gNextPacketPtr & 0xFF));
	ENC28J60_Write(ERXRDPTH,(gNextPacketPtr)>>8);

	if ((gNextPacketPtr-1 < RXSTART_INIT)||(gNextPacketPtr-1 > RXSTOP_INIT))
	{
		ENC28J60_Write(ERXRDPTL,(RXSTOP_INIT)&0xFF);
		ENC28J60_Write(ERXRDPTH,(RXSTOP_INIT)>>8);
	}
	else
	{
		ENC28J60_Write(ERXRDPTL,(gNextPacketPtr-1)&0xFF);
		ENC28J60_Write(ERXRDPTH,(gNextPacketPtr-1)>>8);
	}
	
	ENC28J60_WriteOp(BFS,ECON2,PKTDEC);
	return(len);
}

uint8_t eth_is_arp(uint8_t *buf,uint16_t len) {
	uint8_t i=0;
	if (len<41) return(0);
	if(buf[ETH_TYPE] != ETH_ARP_H) return(0);
	if(buf[ETH_TYPE+1] != ETH_ARP_L) return(0);
	for(i=0;i<4;i++) if(buf[ARP_DST_IP+i] != ipaddr[i]) return(0);
	return(1);
}

void arp_reply(uint8_t *buf) {
	uint8_t i=0;
	make_eth_hdr(buf);
	buf[ARP_OPCODE] = ARP_REPLY_H;
	buf[ARP_OPCODE+1] = ARP_REPLY_L;
	for(i=0;i<6;i++) {
		buf[ARP_DST_MAC+i] = buf[ARP_SRC_MAC+i];
		buf[ARP_SRC_MAC+i] = macaddr[i];
	}
	for(i=0;i<4;i++) {
		buf[ARP_DST_IP+i]=buf[ARP_SRC_IP+i];
		buf[ARP_SRC_IP+i]=ipaddr[i];
	}
	ENC28J60_PacketSend(42,buf);
}

void make_eth_hdr(uint8_t *buf) {
	uint8_t i=0;
	for(i=0;i<6;i++) {
		buf[ETH_DST_MAC+i]=buf[ETH_SRC_MAC+i];
		buf[ETH_SRC_MAC+i]=macaddr[i];
	}
}

void ENC28J60_PacketSend(uint16_t len,uint8_t* packet) {
	while (ENC28J60_ReadOp(RCR,ECON1) & TXRTS) {
		if(ENC28J60_Read(EIR) & TXERIF) {
			ENC28J60_WriteOp(BFS,ECON1,TXRST);
			ENC28J60_WriteOp(BFC,ECON1,TXRST);
		}
	}
	ENC28J60_Write(EWRPTL,TXSTART_INIT&0xFF);
	ENC28J60_Write(EWRPTH,TXSTART_INIT>>8);
	ENC28J60_Write(ETXNDL,(TXSTART_INIT+len)&0xFF);
	ENC28J60_Write(ETXNDH,(TXSTART_INIT+len)>>8);
	ENC28J60_WriteOp(WBM,0,0x00);
	ENC28J60_WriteBuffer(len,packet);
	ENC28J60_WriteOp(BFS,ECON1,TXRTS);
}

uint8_t eth_is_ip(uint8_t *buf,uint16_t len) {
	uint8_t i=0;
	if(len<42) return(0);
	if(buf[ETH_TYPE] != ETH_IP_H) return(0);
	if(buf[ETH_TYPE+1] != ETH_IP_L) return(0);
	if(buf[IP_VERSION] != 0x45) return(0);
	for(i=0;i<4;i++) if(buf[IP_DST+i]!=ipaddr[i]) return(0);
	return(1);
}

void icmp_reply(uint8_t *buf,uint16_t len) {
	make_eth_hdr(buf);
	make_ip_hdr(buf);
	buf[ICMP_TYPE] = ICMP_REPLY;
	if(buf[ICMP_CHECKSUM] > (0xFF-0x08)) buf[ICMP_CHECKSUM+1]++;
	buf[ICMP_CHECKSUM] += 0x08;
	ENC28J60_PacketSend(len,buf);
}

void make_ip_hdr(uint8_t *buf) {
	uint8_t i=0;
	while(i<4){
		buf[IP_DST+i]=buf[IP_SRC+i];
		buf[IP_SRC+i]=ipaddr[i];
		i++;
	}
	make_ip_checksum(buf);
}

void make_ip_checksum(uint8_t *buf) {
	uint16_t ck;
	buf[IP_CHECKSUM]=0;
	buf[IP_CHECKSUM+1]=0;
	buf[IP_FLAGS]=0x40;
	buf[IP_FLAGS+1]=0;
	buf[IP_TTL]=64;
	ck = checksum(&buf[0x0E],IP_HEADER_LEN,0);
	buf[IP_CHECKSUM] = ck >> 8;
	buf[IP_CHECKSUM+1] = ck & 0xFF;
}

uint16_t checksum(uint8_t *buf, uint16_t len,uint8_t type) {
	uint32_t sum = 0;
	if(type==1) {
		sum += IP_UDP;
		sum += len-8;
	}
	if(type==2){
		sum+=IP_TCP;
		sum+=len-8;
	}
	while(len>1){
		sum += 0xFFFF & (((uint32_t)*buf<<8)|*(buf+1));
		buf+=2;
		len-=2;
	}
	if(len) sum += ((uint32_t)(0xFF & *buf))<<8;
	while(sum>>16) sum = (sum & 0xFFFF)+(sum >> 16);
	return( (uint16_t) sum ^ 0xFFFF);
}

void tcp_synack(uint8_t *buf) {
	uint16_t ck;
	make_eth_hdr(buf);
	buf[IP_TOTLEN] = 0;
	buf[IP_TOTLEN+1] = IP_HEADER_LEN+TCP_LEN_PLAIN+4;
	make_ip_hdr(buf);
	buf[TCP_FLAGS] = TCP_SYN|TCP_ACK;
	make_tcp_hdr(buf,1,1,0);
	ck=checksum(&buf[IP_SRC],8+TCP_LEN_PLAIN+4,2);
	buf[TCP_CHECKSUM] = ck >> 8;
	buf[TCP_CHECKSUM+1] = ck & 0xFF;
	ENC28J60_PacketSend(IP_HEADER_LEN+TCP_LEN_PLAIN+4+ETH_HEADER_LEN,buf);
}

void make_tcp_hdr(uint8_t *buf,uint16_t rel_ack_num,uint8_t mss,uint8_t cp_seq) {
	uint8_t i=4;
	uint8_t tseq;
	buf[TCP_DST_PORT] = buf[TCP_SRC_PORT];
	buf[TCP_DST_PORT+1] = buf[TCP_SRC_PORT+1];
	buf[TCP_SRC_PORT] = wwwport >> 8;
	buf[TCP_SRC_PORT+1] = wwwport & 0xFF;
	while(i>0){
		rel_ack_num=buf[TCP_SEQ+i-1]+rel_ack_num;
		tseq=buf[TCP_SEQACK+i-1];
		buf[TCP_SEQACK+i-1]=0xFF&rel_ack_num;
		if (cp_seq) buf[TCP_SEQ+i-1]=tseq;
		else buf[TCP_SEQ+i-1] = 0;
		rel_ack_num=rel_ack_num>>8;
		i--;
	}
	if(cp_seq==0) {
		buf[TCP_SEQ] = 0;
		buf[TCP_SEQ+1] = 0;
		buf[TCP_SEQ+2] = seqnum;
		buf[TCP_SEQ+3] = 0;
		seqnum += 2;
	}
	buf[TCP_CHECKSUM] = 0;
	buf[TCP_CHECKSUM+1] = 0;
	if(mss) {
		buf[TCP_OPTIONS] = 0x02;
		buf[TCP_OPTIONS+1] = 0x04;
		buf[TCP_OPTIONS+2] = 0x05;
		buf[TCP_OPTIONS+3] = 0x80;
		buf[TCP_HEADER_LEN] = 0x60;
	}
	else buf[TCP_HEADER_LEN] = 0x50;
}

void init_len_info(uint8_t *buf) {
	info_data_len = (((int16_t)buf[IP_TOTLEN])<<8)|(buf[IP_TOTLEN+1]&0xFF);
	info_data_len -= IP_HEADER_LEN;
	info_hdr_len = (buf[TCP_HEADER_LEN]>>4)*4;
	info_data_len -= info_hdr_len;
	if(info_data_len<=0) info_data_len=0;
}

uint16_t get_tcp_data_ptr(void) {
	if(info_data_len) return((uint16_t)TCP_SRC_PORT+info_hdr_len);
	else return(0);
}

void tcp_ack(uint8_t *buf) {
	uint16_t j;
	make_eth_hdr(buf);
	buf[TCP_FLAGS] = TCP_ACK;
	if(info_data_len==0) make_tcp_hdr(buf,1,0,1);
	else make_tcp_hdr(buf,info_data_len,0,1);
	j = IP_HEADER_LEN+TCP_LEN_PLAIN;
	buf[IP_TOTLEN] = j >> 8;
	buf[IP_TOTLEN+1] = j & 0xFF;
	make_ip_hdr(buf);
	j = checksum(&buf[IP_SRC],8+TCP_LEN_PLAIN,2);
	buf[TCP_CHECKSUM] = j >> 8;
	buf[TCP_CHECKSUM+1] = j & 0xFF;
	ENC28J60_PacketSend(IP_HEADER_LEN+TCP_LEN_PLAIN+ETH_HEADER_LEN,buf);
}

Return to “SAM D20 Cortex-M0+ MCU”

Who is online

Users browsing this forum: No registered users and 1 guest