Subversion Repositories HomeAutomation

Rev

Rev 211 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*********************************************
  2.  * vim:sw=8:ts=8:si:et
  3.  * To use the above modeline in vim you must have "set modeline" in your .vimrc
  4.  * Author: Guido Socher
  5.  * Copyright: GPL V2
  6.  * http://www.gnu.org/licenses/gpl.html
  7.  *
  8.  * Based on the enc28j60.c file from the AVRlib library by Pascal Stang.
  9.  * For AVRlib See http://www.procyonengineering.com/
  10.  * Used with explicit permission of Pascal Stang.
  11.  *
  12.  * Title: Microchip ENC28J60 Ethernet Interface Driver
  13.  * Chip type           : ATMEGA88 with ENC28J60
  14.  *********************************************/
  15. #include <avr/io.h>
  16. #include "avr_compat.h"
  17. #include "enc28j60.h"
  18. #include "enc28j60_cfg.h"
  19. #include "timeout.h"
  20. //
  21. #ifndef ALIBC_OLD
  22. #include <util/delay.h>
  23. #else
  24. #include <avr/delay.h>
  25. #endif
  26.  
  27.  
  28. static uint8_t Enc28j60Bank;
  29. static uint16_t NextPacketPtr;
  30. // set CS to 0 = active
  31. #define CSACTIVE ENC28J60_CONTROL_PORT&=~(1<<ENC28J60_CONTROL_CS)
  32. // set CS to 1 = passive
  33. #define CSPASSIVE ENC28J60_CONTROL_PORT|=(1<<ENC28J60_CONTROL_CS)
  34. //
  35. #define waitspi() while(!(SPSR&(1<<SPIF)))
  36.  
  37. uint8_t enc28j60ReadOp(uint8_t op, uint8_t address)
  38. {
  39.         CSACTIVE;
  40.         // issue read command
  41.         SPDR = op | (address & ADDR_MASK);
  42.         waitspi();
  43.         // read data
  44.         SPDR = 0x00;
  45.         waitspi();
  46.         // do dummy read if needed (for mac and mii, see datasheet page 29)
  47.         if(address & 0x80)
  48.         {
  49.                 SPDR = 0x00;
  50.                 waitspi();
  51.         }
  52.         // release CS
  53.         CSPASSIVE;
  54.         return(SPDR);
  55. }
  56.  
  57. void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data)
  58. {
  59.         CSACTIVE;
  60.         // issue write command
  61.         SPDR = op | (address & ADDR_MASK);
  62.         waitspi();
  63.         // write data
  64.         SPDR = data;
  65.         waitspi();
  66.         CSPASSIVE;
  67. }
  68.  
  69. void enc28j60ReadBuffer(uint16_t len, uint8_t* data)
  70. {
  71.         CSACTIVE;
  72.         // issue read command
  73.         SPDR = ENC28J60_READ_BUF_MEM;
  74.         waitspi();
  75.         while(len)
  76.         {
  77.                 len--;
  78.                 // read data
  79.                 SPDR = 0x00;
  80.                 waitspi();
  81.                 *data = SPDR;
  82.                 data++;
  83.         }
  84.         *data='\0';
  85.         CSPASSIVE;
  86. }
  87.  
  88. void enc28j60WriteBuffer(uint16_t len, uint8_t* data)
  89. {
  90.         CSACTIVE;
  91.         // issue write command
  92.         SPDR = ENC28J60_WRITE_BUF_MEM;
  93.         waitspi();
  94.         while(len)
  95.         {
  96.                 len--;
  97.                 // write data
  98.                 SPDR = *data;
  99.                 data++;
  100.                 waitspi();
  101.         }
  102.         CSPASSIVE;
  103. }
  104.  
  105. void enc28j60SetBank(uint8_t address)
  106. {
  107.         // set the bank (if needed)
  108.         if((address & BANK_MASK) != Enc28j60Bank)
  109.         {
  110.                 // set the bank
  111.                 enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
  112.                 enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
  113.                 Enc28j60Bank = (address & BANK_MASK);
  114.         }
  115. }
  116.  
  117. uint8_t enc28j60Read(uint8_t address)
  118. {
  119.         // set the bank
  120.         enc28j60SetBank(address);
  121.         // do the read
  122.         return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
  123. }
  124.  
  125. void enc28j60Write(uint8_t address, uint8_t data)
  126. {
  127.         // set the bank
  128.         enc28j60SetBank(address);
  129.         // do the write
  130.         enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
  131. }
  132.  
  133. void enc28j60PhyWrite(uint8_t address, uint16_t data)
  134. {
  135.         // set the PHY register address
  136.         enc28j60Write(MIREGADR, address);
  137.         // write the PHY data
  138.         enc28j60Write(MIWRL, data);
  139.         enc28j60Write(MIWRH, data>>8);
  140.         // wait until the PHY write completes
  141.         while(enc28j60Read(MISTAT) & MISTAT_BUSY){
  142.                 _delay_us(15);
  143.         }
  144. }
  145.  
  146.  
  147. void enc28j60Init(uint8_t* macaddr)
  148. {
  149.     // initialize I/O
  150.     ENC28J60_CONTROL_DDR |= 1<<ENC28J60_CONTROL_CS;
  151.     CSPASSIVE;
  152.         // 
  153.     DDRB  |= 1<<PB3 | 1<<PB5; // mosi, sck output
  154.     cbi(DDRB,PINB4); // MISO is input
  155.         //
  156.     CSPASSIVE;
  157.         cbi(PORTB,PB3); // MOSI low
  158.         cbi(PORTB,PB5); // SCK low
  159.     //
  160.     // initialize SPI interface
  161.     // master mode and Fosc/2 clock:
  162.         SPCR = (1<<SPE)|(1<<MSTR);
  163.         SPSR |= (1<<SPI2X);
  164.     // perform system reset
  165.     enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
  166.     delay_ms(50);
  167.     // check CLKRDY bit to see if reset is complete
  168.         // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
  169.     //while(!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));
  170.     // do bank 0 stuff
  171.     // initialize receive buffer
  172.     // 16-bit transfers, must write low byte first
  173.     // set receive buffer start address
  174.     NextPacketPtr = RXSTART_INIT;
  175.         // Rx start
  176.     enc28j60Write(ERXSTL, RXSTART_INIT&0xFF);
  177.     enc28j60Write(ERXSTH, RXSTART_INIT>>8);
  178.     // set receive pointer address
  179.     enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF);
  180.     enc28j60Write(ERXRDPTH, RXSTART_INIT>>8);
  181.     // RX end
  182.     enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF);
  183.     enc28j60Write(ERXNDH, RXSTOP_INIT>>8);
  184.     // TX start
  185.     enc28j60Write(ETXSTL, TXSTART_INIT&0xFF);
  186.     enc28j60Write(ETXSTH, TXSTART_INIT>>8);
  187.     // TX end
  188.     enc28j60Write(ETXNDL, TXSTOP_INIT&0xFF);
  189.     enc28j60Write(ETXNDH, TXSTOP_INIT>>8);
  190.     // do bank 1 stuff, packet filter:
  191.         // For broadcast packets we allow only ARP packtets
  192.         // All other packets should be unicast only for our mac (MAADR)
  193.         //
  194.         // The pattern to match on is therefore
  195.         // Type     ETH.DST
  196.         // ARP      BROADCAST
  197.         // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
  198.         // in binary these poitions are:11 0000 0011 1111
  199.         // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
  200.     enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);
  201.     enc28j60Write(EPMM0, 0x3f);
  202.     enc28j60Write(EPMM1, 0x30);
  203.     enc28j60Write(EPMCSL, 0xf9);
  204.     enc28j60Write(EPMCSH, 0xf7);
  205.         //
  206.         //
  207.     // do bank 2 stuff
  208.     // enable MAC receive
  209.     enc28j60Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
  210.     // bring MAC out of reset
  211.     enc28j60Write(MACON2, 0x00);
  212.     // enable automatic padding to 60bytes and CRC operations
  213.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
  214.     // set inter-frame gap (non-back-to-back)
  215.     enc28j60Write(MAIPGL, 0x12);
  216.     enc28j60Write(MAIPGH, 0x0C);
  217.     // set inter-frame gap (back-to-back)
  218.     enc28j60Write(MABBIPG, 0x12);
  219.     // Set the maximum packet size which the controller will accept
  220.         // Do not send packets longer than MAX_FRAMELEN:
  221.     enc28j60Write(MAMXFLL, MAX_FRAMELEN&0xFF); 
  222.     enc28j60Write(MAMXFLH, MAX_FRAMELEN>>8);
  223.     // do bank 3 stuff
  224.         // write MAC address
  225.         // NOTE: MAC address in ENC28J60 is byte-backward
  226.         enc28j60Write(MAADR5, macaddr[0]);
  227.         enc28j60Write(MAADR4, macaddr[1]);
  228.         enc28j60Write(MAADR3, macaddr[2]);
  229.         enc28j60Write(MAADR2, macaddr[3]);
  230.         enc28j60Write(MAADR1, macaddr[4]);
  231.         enc28j60Write(MAADR0, macaddr[5]);
  232.     // no loopback of transmitted frames
  233.     enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS);
  234.     // switch to bank 0
  235.     enc28j60SetBank(ECON1);
  236.     // enable interrutps
  237.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
  238.     // enable packet reception
  239.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
  240. }
  241.  
  242. // read the revision of the chip:
  243. uint8_t enc28j60getrev(void)
  244. {
  245.     return(enc28j60Read(EREVID));
  246. }
  247.  
  248. void enc28j60PacketSend(uint16_t len, uint8_t* packet)
  249. {
  250.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
  251.     enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
  252.     // Set the write pointer to start of transmit buffer area
  253.     enc28j60Write(EWRPTL, TXSTART_INIT&0xFF);
  254.     enc28j60Write(EWRPTH, TXSTART_INIT>>8);
  255.     // Set the TXND pointer to correspond to the packet size given
  256.     enc28j60Write(ETXNDL, (TXSTART_INIT+len)&0xFF);
  257.     enc28j60Write(ETXNDH, (TXSTART_INIT+len)>>8);
  258.     // write per-packet control byte (0x00 means use macon3 settings)
  259.     enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
  260.     // copy the packet into the transmit buffer
  261.     enc28j60WriteBuffer(len, packet);
  262.         // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
  263.     if( (enc28j60Read(EIR) & EIR_TXERIF) ){
  264.         enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
  265.         enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
  266.         //enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
  267.         enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF);
  268.     }
  269.     // send the contents of the transmit buffer onto the network
  270.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
  271. }
  272.  
  273. // Gets a packet from the network receive buffer, if one is available.
  274. // The packet will by headed by an ethernet header.
  275. //      maxlen  The maximum acceptable length of a retrieved packet.
  276. //      packet  Pointer where packet data should be stored.
  277. // Returns: Packet length in bytes if a packet was retrieved, zero otherwise.
  278. uint16_t enc28j60PacketReceive(uint16_t maxlen, uint8_t* packet)
  279. {
  280.     uint16_t rxstat;
  281.     uint16_t len;
  282.     // check if a packet has been received and buffered
  283.     //if( !(enc28j60Read(EIR) & EIR_PKTIF) ){
  284.         // The above does not work. See Rev. B4 Silicon Errata point 6.
  285.     if( enc28j60Read(EPKTCNT) ==0 ){
  286.         return(0);
  287.         }
  288.  
  289.     // Set the read pointer to the start of the received packet
  290.     enc28j60Write(ERDPTL, (NextPacketPtr));
  291.     enc28j60Write(ERDPTH, (NextPacketPtr)>>8);
  292.     // read the next packet pointer
  293.     NextPacketPtr  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
  294.     NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
  295.     // read the packet length (see datasheet page 43)
  296.     len  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
  297.     len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
  298.         len-=4; //remove the CRC count
  299.     // read the receive status (see datasheet page 43)
  300.     rxstat  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
  301.     rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
  302.     // limit retrieve length
  303.         if (len>maxlen-1){
  304.                 len=maxlen-1;
  305.         }
  306.         // check CRC and symbol errors (see datasheet page 44, table 7-3):
  307.         // The ERXFCON.CRCEN is set by default. Normally we should not
  308.         // need to check this.
  309.         if ((rxstat & 0x80)==0){
  310.                 // invalid
  311.                 len=0;
  312.         }else{
  313.                 // copy the packet from the receive buffer
  314.                 enc28j60ReadBuffer(len, packet);
  315.         }
  316.     // Move the RX read pointer to the start of the next received packet
  317.     // This frees the memory we just read out
  318.     enc28j60Write(ERXRDPTL, (NextPacketPtr));
  319.     enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8);
  320.     // decrement the packet counter indicate we are done with this packet
  321.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
  322.     return(len);
  323. }
  324.  
  325.