/*#include "platform.h" #include "enc28j60.h"*/ #include "platform.h" #include "eth.h" #include "enc28j60.h" #include "ap.h" #include "arp.h" #include "icmp.h" #include "ip.h" #include "udp.h" #include "stdlib.h" /* ========================================================================== Low level SPI routines */ void spi_cs (unsigned char level) { SPI_nCS = 1; // deselect first in any case SPI_nCS =!level; asm("nop"); } void spi_putc (unsigned char data) { unsigned char mask; for (mask = 0x80; mask; mask >>= 1) { SPI_SCK = 0; asm("nop"); asm("nop"); if (data & mask) SPI_MOSI = 1; else { SPI_MOSI = 0; asm("nop");asm("nop"); asm("nop"); //musíme počkat alespoň jednu instrukci } SPI_SCK = 1; } asm("nop"); asm("nop"); asm("nop"); SPI_SCK = 0; } //přečte znak z SPI //vrací char //bez argumentů unsigned char spi_getc (void) { unsigned char mask; unsigned char data; data = 0; for (mask = 0x80; mask; mask >>= 1) { SPI_SCK = 0; asm("nop"); asm("nop"); asm("nop"); //musíme počkat alespoň jednu instrukci if (SPI_MISO) data |= mask; SPI_SCK = 1;asm("nop"); asm("nop"); } SPI_SCK = 0;asm("nop"); asm("nop"); return data; } void spi_init (void) { spi_cs(0); } unsigned char enc28_curbank = 0xFF; // initialized to 0xff, ie consider bank selection to be undefined at startup /* ========================================================================== bank select nastavení stránky - argumenty - reg (!název registru, který leží na stránce!!) - nic nevrací - nastavuje globální proměnnou enc28_curbank (aktuální stránka) */ void enc28_banksel (unsigned char reg) { if ((reg&ENC28_ADDR_MASK) >= 0x1b) return; // common register if ((reg&ENC28_BANK_MASK) == enc28_curbank) return; // bank already selected spi_cs(1); spi_putc(ENC28_BFC | ECON1); spi_putc(ECON1_BSEL1 | ECON1_BSEL0); spi_cs(0); spi_cs(1); spi_putc(ENC28_BFS | ECON1); spi_putc((reg & ENC28_BANK_MASK) >> 5); spi_cs(0); enc28_curbank = reg & ENC28_BANK_MASK; } /* ========================================================================== control register write zapiš do ovládacího registru - argumenty - reg (název registru) - data (výplň registru) - nic nevrací - samo nastaví stránku */ void enc28_ctlreg_wr (unsigned char reg, unsigned char data) { enc28_banksel(reg); spi_cs(1); spi_putc(ENC28_WCR | (reg & ENC28_ADDR_MASK)); spi_putc(data); spi_cs(0); } /* ========================================================================== control register read přečti ovládací registr - argumenty - reg (název registru) - vrací výplň registru - samo nastaví stránku */ unsigned char enc28_ctlreg_rd (unsigned char reg) { unsigned char data; enc28_banksel(reg); spi_cs(1); spi_putc(ENC28_RCR | (reg & ENC28_ADDR_MASK)); if (reg & ENC28_SPRD_MASK) spi_putc(0); // read from certain registers delayed data = spi_getc(); spi_cs(0); return data; } /* ========================================================================== control register set nastavuje požadované bity registru - argumenty - reg (název registru) - data (maska pro registr, 0 = nech být, 1 = nastav) - nic nevrací - samo nastaví stránku */ void enc28_ctlreg_set (unsigned char reg, unsigned char data) { enc28_banksel(reg); spi_cs(1); spi_putc(ENC28_BFS | (reg & ENC28_ADDR_MASK)); spi_putc(data); spi_cs(0); } /* ========================================================================== control register clear nuluje požadované bity registru - argumenty - reg (název registru) - data (maska pro registr, 0 = nech být, 1 = vynuluj) - nic nevrací - samo nastaví stránku */ void enc28_ctlreg_clr (unsigned char reg, unsigned char data) { enc28_banksel(reg); spi_cs(1); spi_putc(ENC28_BFC | (reg & ENC28_ADDR_MASK)); spi_putc(data); spi_cs(0); } /* ========================================================================== convenient write to 16 bit registers, pass lower address as parameter zapíše 16-bitové číslo do registru (vyšší bajt na nižší adrese) - argumenty - reg (název nižšího registru) - data (výplň registrů - inteeger) */ void enc28_ctlreg_wr16 (unsigned char reg, unsigned int data) { enc28_ctlreg_wr(reg, data & 0xff); enc28_ctlreg_wr(reg + 1, data >> 8); } /* ========================================================================== convenient read of 16 bit registers, pass lower address as parameter přečte data ze 16-ti bitového registru - aragumenty - reg (název bižšího registru) - vrací výplň registru (inteeger!) */ unsigned int enc28_ctlreg_rd16 (unsigned char reg) { unsigned int data; data = enc28_ctlreg_rd(reg); data |= enc28_ctlreg_rd(reg + 1) << 8; return data; } /* ========================================================================== write PHY register, takes 11 us - MCU is slow, no waiting needed */ void enc28_phyreg_wr (unsigned char reg, unsigned int data) { enc28_ctlreg_wr(MIREGADR, reg); enc28_ctlreg_wr16(MIWRL, data); } /* ========================================================================== read PHY register, takes 11 us - MCU is slow, no waiting needed */ unsigned int enc28_phyreg_rd (unsigned char reg) { enc28_ctlreg_wr(MIREGADR, reg); enc28_ctlreg_wr(MICMD, MICMD_MIIRD); enc28_ctlreg_wr(MICMD, 0); return enc28_ctlreg_rd16(MIRDL); } /* ========================================================================== ========================================================================== ENC28J60 network buffer access API */ static unsigned char netbuf_pending; // pending network buffer operation (SPI is left open for performance) static unsigned int netbuf_rdpt; // locally kept read and write pointers for relative seek operations static unsigned int netbuf_wrpt; /* ========================================================================== rx buffer wrapping */ unsigned int netbuf_rxwrap (int pt) { if (pt > ENC28_RXBUF_END) do pt -= ENC28_RXBUF_LEN; while (pt > ENC28_RXBUF_END); else while (pt < ENC28_RXBUF_START) pt += ENC28_RXBUF_LEN; return pt; } /* ========================================================================== read */ void netbuf_rd_seek (int pos, unsigned char origin) { netbuf_close(); if (origin == NB_SEEK_ABS) { netbuf_rdpt = pos; netbuf_rdpt &= ENC28_BUFSIZE - 1; } else if (origin == NB_SEEK_CUR) netbuf_rdpt = netbuf_rxwrap(netbuf_rdpt + pos); else netbuf_rdpt = netbuf_rxwrap(pos); enc28_ctlreg_wr16(ERDPTL, netbuf_rdpt); } /* ========================================================================== rd */ unsigned int netbuf_rd_tell (void) { return netbuf_rdpt; } /* ========================================================================== getc */ unsigned char netbuf_getc(void) { if (netbuf_pending != ENC28_RBM) { spi_cs(1); spi_putc(netbuf_pending = ENC28_RBM); // ERDPT is preset } netbuf_rdpt = netbuf_rxwrap(netbuf_rdpt + 1); return spi_getc(); } // leave SPI open /* ========================================================================== read */ void netbuf_read (void *buffer, int len) { if (len > BUFFER_SIZE) len = BUFFER_SIZE; if (netbuf_pending != ENC28_RBM) { spi_cs(1); spi_putc(netbuf_pending = ENC28_RBM); // ERDPT is preset } netbuf_rdpt = netbuf_rxwrap(netbuf_rdpt + len); while (len--) { *((unsigned char *)buffer) = spi_getc(); buffer = ((unsigned char *)buffer) + 1; } } // leave SPI open /* ========================================================================== skip */ void netbuf_skip (int len) { if (len <= 10) while (len--) netbuf_getc(); else netbuf_rd_seek(len, NB_SEEK_CUR); } /* ========================================================================== write */ void netbuf_wr_seek (int pos, unsigned char origin) { netbuf_close(); if (origin == NB_SEEK_CUR) netbuf_wrpt += pos; else netbuf_wrpt = pos; netbuf_wrpt &= ENC28_BUFSIZE - 1; enc28_ctlreg_wr16(EWRPTL, netbuf_wrpt); } /* ========================================================================== write tell */ unsigned int netbuf_wr_tell (void) { return netbuf_wrpt; } /* ========================================================================== putc */ void netbuf_putc (unsigned char data) { if (netbuf_pending != ENC28_WBM) { spi_cs(1); spi_putc(netbuf_pending = ENC28_WBM); // EWRPT is preset } netbuf_wrpt++; netbuf_wrpt &= ENC28_BUFSIZE - 1; spi_putc(data); } // leave SPI open /* ========================================================================== putc */ void netbuf_write (void *buffer, int len) { if (netbuf_pending != ENC28_WBM) { spi_cs(1); spi_putc(netbuf_pending = ENC28_WBM); // EWRPT is preset } netbuf_wrpt += len; netbuf_wrpt &= ENC28_BUFSIZE - 1; while (len--) { spi_putc(*((unsigned char *)buffer)); buffer = ((unsigned char *)buffer) + 1; } /* leave SPI open */ } void netbuf_fill (unsigned char data, int len) { if (netbuf_pending!=ENC28_WBM) { spi_cs(1); spi_putc(netbuf_pending=ENC28_WBM); /* EWRPT is preset */ } netbuf_wrpt+=len; netbuf_wrpt&=ENC28_BUFSIZE-1; while (len--) spi_putc(data); /* leave SPI open */ } void netbuf_copy(unsigned int len) { unsigned int end; if (len==0) return; if (len==1) netbuf_putc(netbuf_getc()); /* ENC28_RXBUF_START is always zero (see errata) */ if (/* (netbuf_rdpt>=ENC28_RXBUF_START) && */(netbuf_rdpt<=ENC28_RXBUF_END)) end=netbuf_rxwrap(netbuf_rdpt+len-1); else end=netbuf_rdpt+len; netbuf_close(); enc28_ctlreg_wr16(EDMASTL, netbuf_rdpt); enc28_ctlreg_wr16(EDMANDL, end); enc28_ctlreg_wr16(EDMADSTL, netbuf_wrpt); /* fire the copy operation */ enc28_ctlreg_set(ECON1, ECON1_DMAST); /* wait for DMA operation to complete */ while (enc28_ctlreg_rd(ECON1)&ECON1_DMAST); } void netbuf_close(void) { spi_cs(0); netbuf_pending=0; } /* * ENC28J60 higher level API - packet reception and transmission * ============================================================================ */ static unsigned int nic_rx_nextpt; void nic_init(void) { enc28_curbank=0xff; spi_init(); spi_cs(1); spi_putc(ENC28_SRC); /* issue soft reset command */ spi_cs(0); /* delay for the device to be ready after reset, * not necessary to check ESTAT_CLKRDY, the delay is long enough, * see errata no. 1 delay(400); vzhodili jsem delaz a misto toho mame pockej delaz SNAD melo cekat yadanz pocet mikrosekund, to pockej dela */ pockej(730) ; // je tam jeste nejaka rezie na volani atd. - tohle ceka 400 mikrosekund /* allocate reception buffer */ enc28_ctlreg_wr16(ERXSTL, ENC28_RXBUF_START); enc28_ctlreg_wr16(ERXNDL, ENC28_RXBUF_END); /* free reception buffer assuming ENC28_RXBUF_END odd, errata no. 11 */ enc28_ctlreg_wr16(ERXRDPTL, ENC28_RXBUF_END); /* allocate transmission buffer */ enc28_ctlreg_wr16(ETXSTL, ENC28_TXBUF_START); /* set next rx pointer to beginning of rx buffer */ nic_rx_nextpt=ENC28_RXBUF_START; /* configure MAC */ enc28_ctlreg_wr(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); enc28_ctlreg_wr(MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); enc28_ctlreg_wr16(MAMXFLL, MAX_FRAMELEN); enc28_ctlreg_wr(MABBIPG, 0x12); // set inter-frame gap (back-to-back) enc28_ctlreg_wr(MAIPGL, 0x12); // set inter-frame gap (non-back-to-back) enc28_ctlreg_wr(MAIPGH, 0x0C); /* set MAC address */ enc28_ctlreg_wr(MAADR1, ENC28J60_MAC0); enc28_ctlreg_wr(MAADR2, ENC28J60_MAC1); enc28_ctlreg_wr(MAADR3, ENC28J60_MAC2); enc28_ctlreg_wr(MAADR4, ENC28J60_MAC3); enc28_ctlreg_wr(MAADR5, ENC28J60_MAC4); enc28_ctlreg_wr(MAADR6, ENC28J60_MAC5); enc28_phyreg_wr(PHCON1, 0x0100); /* to be sure we operate half in duplex mode */ //enc28_phyreg_wr(PHCON2, PHCON2_HDLDIS); /* no loopback of transmitted frames */ enc28_phyreg_wr(PHLCON, 0x0470); /* LED configureation */ enc28_ctlreg_set(ECON1, ECON1_RXEN); /* enable packet reception */ //#ifdef DEBUG // printf("erevid %d\n",enc28_ctlreg_rd(EREVID)); //#endif } /* packet reception, returns length of data and opens netbuf for reading */ unsigned int nic_rx(void) { unsigned int nextpt; /* next packet pointer */ unsigned int rxstat; /* reception status */ unsigned int len; /* packet length */ /* check packet count instead of interrupt flag - errata no. 4 */ if (enc28_ctlreg_rd(EPKTCNT)==0) { return 0; } /* set read pointer to next packet */ netbuf_rd_seek(nic_rx_nextpt, NB_SEEK_SET); nextpt=netbuf_getc(); nextpt|=((unsigned int)netbuf_getc())<<8; len=netbuf_getc(); len|=((unsigned int)netbuf_getc())<<8; rxstat=netbuf_getc(); rxstat|=((unsigned int)netbuf_getc())<<8; /* update packet/data counters */ /* nic_rx_packets++; nic_rx_bytes+=len; */ nic_rx_nextpt=nextpt; if (((rxstat&0x80)==0) || (len<=4)) { /* there was an error */ nic_rx_free(); return 0; } /* the upper layer does not need CRC (already checked by device) */ return len-4; } /* return netbuf provided by nic_rx() back to controller */ void nic_rx_free(void) { netbuf_close(); enc28_ctlreg_set(ECON2, ECON2_PKTDEC); /* decrement pending packet count */ /* workaround for errata no. 11, always write odd value to ERXRDPT, * assuming ENC28_RXBUF_END is an odd value */ if (nic_rx_nextpt==ENC28_RXBUF_START) enc28_ctlreg_wr16(ERXRDPTL, ENC28_RXBUF_END); else enc28_ctlreg_wr16(ERXRDPTL, nic_rx_nextpt-1); } /* allocate transmission buffer and open it for writing */ unsigned int nic_tx_alloc(unsigned int *pt) { netbuf_close(); /* wait for previous packet to be transmitted first */ while (enc28_ctlreg_rd(ECON1)&ECON1_TXRTS); /* seek to beginning of transmission buffer */ netbuf_wr_seek(ENC28_TXBUF_START, NB_SEEK_SET); netbuf_putc(0); /* per packet control byte */ if (pt) *pt=ENC28_TXBUF_START+1; return MAX_FRAMELEN-4; /* return max size of the buffer */ } /* send previously allocated buffer */ void nic_tx(unsigned int len) { netbuf_close(); /* workaround for silicon errata no. 10 */ enc28_ctlreg_set(ECON1, ECON1_TXRST); enc28_ctlreg_clr(ECON1, ECON1_TXRST); /* update packet/data counters */ /* nic_tx_packets++; nic_tx_bytes+=len; */ /* set transmit tx buffer end adddress accordingly to packet length, * tx buffer start is preset during initialization and remains untouched */ enc28_ctlreg_wr16(ETXNDL, ENC28_TXBUF_START+len); /* fire the transmittion */ enc28_ctlreg_set(ECON1, ECON1_TXRTS); } unsigned int nic_link(void) { if (enc28_phyreg_rd(PHSTAT1)&PHSTAT1_LLSTAT) return 1; return 0; } /*============================================================================ function: delay description: delay us kyz se zada 400 , ceka to 217 ms !!!! To urcite neni ono !!!! =========================================================================== void delay (unsigned int us) { unsigned long delrg = (us * 100); asm("NOP"); while (delrg--); asm("NOP"); } */ void reset_enc (void) { spi_cs(1); spi_putc(ENC28_SRC); /* issue soft reset command */ spi_cs(0); }