Subversion Repositories HomeAutomation

Rev

Rev 669 | 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. #include <config.h>
  21.  
  22. #ifndef ALIBC_OLD
  23. #include <util/delay.h>
  24. #else
  25. #include <avr/delay.h>
  26. #endif
  27.  
  28.  
  29. static uint8_t Enc28j60Bank;
  30. static uint16_t NextPacketPtr;
  31. // set CS to 0 = active
  32. #define CSACTIVE ENC28J60_CS_PORT&=~(1<<ENC28J60_CS)
  33. // set CS to 1 = passive
  34. #define CSPASSIVE ENC28J60_CS_PORT|=(1<<ENC28J60_CS)
  35. //
  36. #ifdef ENC28J60_USART_SPI_MODE
  37. #define waitspi() while(!(UCSR0A&(1<<RXC0)))
  38. #else
  39. #define waitspi() while(!(SPSR&(1<<SPIF)))
  40. #endif
  41.  
  42. #ifdef ENC28J60_USART_SPI_MODE
  43. uint8_t enc28j60ReadOp(uint8_t op, uint8_t address) {
  44.     CSACTIVE;
  45.     uint8_t dummy = 0;
  46.     /* Wait for empty transmit buffer */
  47.     while ( !( UCSR0A & (1<<UDRE0)) );
  48.     // issue read command
  49.     dummy = UDR0;
  50.     UDR0 = op | (address & ADDR_MASK);
  51.     waitspi();
  52.     // read data
  53.     dummy = UDR0;
  54.     UDR0 = 0x00;
  55.     waitspi();
  56.     // do dummy read if needed (for mac and mii, see datasheet page 29)
  57.     if(address & 0x80) {
  58.         dummy = UDR0;
  59.         UDR0 = 0x00;
  60.         waitspi();
  61.     }  
  62.     // release CS
  63.     CSPASSIVE;
  64.     return UDR0;
  65. }
  66.  
  67. void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data) {
  68.     CSACTIVE;
  69.     uint8_t dummy = 0;
  70.     /* Wait for empty transmit buffer */
  71.     while ( !( UCSR0A & (1<<UDRE0)) );
  72.     // issue write command
  73.     dummy = UDR0;
  74.     UDR0 = op | (address & ADDR_MASK);
  75.     waitspi();
  76.     // write data
  77.     dummy = UDR0;
  78.     UDR0 = data;
  79.     waitspi();
  80.     CSPASSIVE;
  81. }
  82.  
  83. void enc28j60ReadBuffer(uint16_t len, uint8_t* data) {
  84.     CSACTIVE;
  85.     uint8_t dummy = 0;
  86.     /* Wait for empty transmit buffer */
  87.     while ( !( UCSR0A & (1<<UDRE0)) );
  88.     // issue read command
  89.     dummy = UDR0;
  90.     UDR0 = ENC28J60_READ_BUF_MEM;
  91.     waitspi();
  92.     while(len) {
  93.         len--;
  94.         // read data
  95.         dummy = UDR0;
  96.         UDR0 = 0x00;
  97.         waitspi();
  98.         *data = UDR0;
  99.         data++;
  100.     }
  101.     *data='\0';
  102.     CSPASSIVE;
  103. }
  104.  
  105. void enc28j60WriteBuffer(uint16_t len, uint8_t* data) {
  106.     CSACTIVE;
  107.     uint8_t dummy = 0;
  108.     /* Wait for empty transmit buffer */
  109.     while ( !( UCSR0A & (1<<UDRE0)) );
  110.     // issue write command
  111.     dummy = UDR0;
  112.     UDR0 = ENC28J60_WRITE_BUF_MEM;
  113.     waitspi();
  114.     while(len) {
  115.         len--;
  116.         // write data
  117.         dummy = UDR0;
  118.         UDR0 = *data;
  119.         data++;
  120.         waitspi();
  121.     }
  122.     CSPASSIVE;
  123. }
  124.  
  125. #else
  126. uint8_t enc28j60ReadOp(uint8_t op, uint8_t address) {
  127.     CSACTIVE;
  128.     // issue read command
  129.     SPDR = op | (address & ADDR_MASK);
  130.     waitspi();
  131.     // read data
  132.     SPDR = 0x00;
  133.     waitspi();
  134.     // do dummy read if needed (for mac and mii, see datasheet page 29)
  135.     if(address & 0x80) {
  136.         SPDR = 0x00;
  137.         waitspi();
  138.     }
  139.     // release CS
  140.     CSPASSIVE;
  141.     return(SPDR);
  142. }
  143.  
  144. void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data) {
  145.     CSACTIVE;
  146.     // issue write command
  147.     SPDR = op | (address & ADDR_MASK);
  148.     waitspi();
  149.     // write data
  150.     SPDR = data;
  151.     waitspi();
  152.     CSPASSIVE;
  153. }
  154.  
  155. void enc28j60ReadBuffer(uint16_t len, uint8_t* data) {
  156.     CSACTIVE;
  157.     // issue read command
  158.     SPDR = ENC28J60_READ_BUF_MEM;
  159.     waitspi();
  160.     while(len) {
  161.         len--;
  162.         // read data
  163.         SPDR = 0x00;
  164.         waitspi();
  165.         *data = SPDR;
  166.         data++;
  167.     }
  168.     *data='\0';
  169.     CSPASSIVE;
  170. }
  171.  
  172. void enc28j60WriteBuffer(uint16_t len, uint8_t* data) {
  173.     CSACTIVE;
  174.     // issue write command
  175.     SPDR = ENC28J60_WRITE_BUF_MEM;
  176.     waitspi();
  177.     while(len) {
  178.         len--;
  179.         // write data
  180.         SPDR = *data;
  181.         data++;
  182.         waitspi();
  183.     }
  184.     CSPASSIVE;
  185. }
  186. #endif
  187.  
  188. void enc28j60SetBank(uint8_t address)
  189. {
  190.     // set the bank (if needed)
  191.     if((address & BANK_MASK) != Enc28j60Bank)
  192.     {
  193.         // set the bank
  194.         enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
  195.         enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
  196.         Enc28j60Bank = (address & BANK_MASK);
  197.     }
  198. }
  199.  
  200. uint8_t enc28j60Read(uint8_t address)
  201. {
  202.     // set the bank
  203.     enc28j60SetBank(address);
  204.     // do the read
  205.     return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
  206. }
  207.  
  208. void enc28j60Write(uint8_t address, uint8_t data)
  209. {
  210.     // set the bank
  211.     enc28j60SetBank(address);
  212.     // do the write
  213.     enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
  214. }
  215.  
  216. void enc28j60PhyWrite(uint8_t address, uint16_t data)
  217. {
  218.     // set the PHY register address
  219.     enc28j60Write(MIREGADR, address);
  220.     // write the PHY data
  221.     enc28j60Write(MIWRL, data);
  222.     enc28j60Write(MIWRH, data>>8);
  223.     // wait until the PHY write completes
  224.     while(enc28j60Read(MISTAT) & MISTAT_BUSY){
  225.         _delay_us(15);
  226.     }
  227. }
  228.  
  229.  
  230. uint8_t enc28j60Init(uint8_t* macaddr) {
  231.     // initialize I/O
  232.     ENC28J60_CS_DDR |= 1<<ENC28J60_CS;
  233.     /* enable PB0, reset as output */
  234.     ENC28J60_RESET_DDR|= (1<<ENC28J60_RESET);
  235.    
  236.     /* set output to gnd, reset the ethernet chip */
  237.     ENC28J60_RESET_PORT &= ~(1<<ENC28J60_RESET);
  238.     delay_ms(20);
  239.    
  240.     /* set output to Vcc, reset inactive */
  241.     ENC28J60_RESET_PORT|= (1<<ENC28J60_RESET);
  242.     delay_ms(100);
  243.  
  244.     CSPASSIVE;
  245.     // 
  246. #ifdef ENC28J60_USART_SPI_MODE
  247.     //cli();
  248.     UBRR0 = 0;
  249.     XCK_DDR |= (1<<XCK); // xck (sck) output
  250. //  TXD_DDR |= (1<<TXD); // txd (mosi) output
  251.     UCSR0C = (1<<UMSEL01)|(1<<UMSEL00)|(0<<UCPHA0)|(0<<UCPOL0);
  252.     UCSR0B = (1<<RXEN0)|(1<<TXEN0);
  253.     UBRR0 = 0;
  254.     //sei();
  255.    
  256. #else
  257.     DDRB  |= 1<<PB3 | 1<<PB5; // mosi, sck output
  258.     cbi(DDRB,PINB4); // MISO is input
  259.     //
  260.     CSPASSIVE;
  261.     cbi(PORTB,PB3); // MOSI low
  262.     cbi(PORTB,PB5); // SCK low
  263.     //
  264.     // initialize SPI interface
  265.     // master mode and Fosc/2 clock:
  266.     SPCR = (1<<SPE)|(1<<MSTR);
  267.     SPSR |= (1<<SPI2X);
  268. #endif
  269.     // perform system reset
  270.     enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
  271.     delay_ms(50);
  272.    
  273.     uint8_t chiprev = enc28j60getrev();
  274.    
  275.     // check CLKRDY bit to see if reset is complete
  276.     // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
  277.     //while(!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));
  278.     // do bank 0 stuff
  279.     // initialize receive buffer
  280.     // 16-bit transfers, must write low byte first
  281.     // set receive buffer start address
  282.     NextPacketPtr = RXSTART_INIT;
  283.     // Rx start
  284.     enc28j60Write(ERXSTL, RXSTART_INIT&0xFF);
  285.     enc28j60Write(ERXSTH, RXSTART_INIT>>8);
  286.     // set receive pointer address
  287.     enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF);
  288.     enc28j60Write(ERXRDPTH, RXSTART_INIT>>8);
  289.     // RX end
  290.     enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF);
  291.     enc28j60Write(ERXNDH, RXSTOP_INIT>>8);
  292.     // TX start
  293.     enc28j60Write(ETXSTL, TXSTART_INIT&0xFF);
  294.     enc28j60Write(ETXSTH, TXSTART_INIT>>8);
  295.     // TX end
  296.     enc28j60Write(ETXNDL, TXSTOP_INIT&0xFF);
  297.     enc28j60Write(ETXNDH, TXSTOP_INIT>>8);
  298.     // do bank 1 stuff, packet filter:
  299.     // For broadcast packets we allow only ARP packtets
  300.     // All other packets should be unicast only for our mac (MAADR)
  301.     //
  302.     // The pattern to match on is therefore
  303.     // Type     ETH.DST
  304.     // ARP      BROADCAST
  305.     // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
  306.     // in binary these poitions are:11 0000 0011 1111
  307.     // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
  308.     enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);
  309.     enc28j60Write(EPMM0, 0x3f);
  310.     enc28j60Write(EPMM1, 0x30);
  311.     enc28j60Write(EPMCSL, 0xf9);
  312.     enc28j60Write(EPMCSH, 0xf7);
  313.     //
  314.     //
  315.     // do bank 2 stuff
  316.     // enable MAC receive
  317.     enc28j60Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
  318.     // bring MAC out of reset
  319.     enc28j60Write(MACON2, 0x00);
  320.     // enable automatic padding to 60bytes and CRC operations
  321.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
  322.     // set inter-frame gap (non-back-to-back)
  323.     enc28j60Write(MAIPGL, 0x12);
  324.     enc28j60Write(MAIPGH, 0x0C);
  325.     // set inter-frame gap (back-to-back)
  326.     enc28j60Write(MABBIPG, 0x12);
  327.     // Set the maximum packet size which the controller will accept
  328.     // Do not send packets longer than MAX_FRAMELEN:
  329.     enc28j60Write(MAMXFLL, MAX_FRAMELEN&0xFF); 
  330.     enc28j60Write(MAMXFLH, MAX_FRAMELEN>>8);
  331.     // do bank 3 stuff
  332.     // write MAC address
  333.     // NOTE: MAC address in ENC28J60 is byte-backward
  334.     enc28j60Write(MAADR5, macaddr[0]);
  335.     enc28j60Write(MAADR4, macaddr[1]);
  336.     enc28j60Write(MAADR3, macaddr[2]);
  337.     enc28j60Write(MAADR2, macaddr[3]);
  338.     enc28j60Write(MAADR1, macaddr[4]);
  339.     enc28j60Write(MAADR0, macaddr[5]);
  340.     // no loopback of transmitted frames
  341.     enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS);
  342.     // switch to bank 0
  343.     enc28j60SetBank(ECON1);
  344.     // enable interrutps
  345.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
  346.     // enable packet reception
  347.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
  348.  
  349.     if (chiprev != 2 && chiprev != 4 && chiprev != 5) {
  350.         return 0;
  351.     }
  352.     return 1;
  353. }
  354.  
  355. // read the revision of the chip:
  356. uint8_t enc28j60getrev(void)
  357. {
  358.     return(enc28j60Read(EREVID));
  359. }
  360.  
  361. void enc28j60PacketSend(uint16_t len, uint8_t* packet)
  362. {
  363.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
  364.     enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
  365.     // Set the write pointer to start of transmit buffer area
  366.     enc28j60Write(EWRPTL, TXSTART_INIT&0xFF);
  367.     enc28j60Write(EWRPTH, TXSTART_INIT>>8);
  368.     // Set the TXND pointer to correspond to the packet size given
  369.     enc28j60Write(ETXNDL, (TXSTART_INIT+len)&0xFF);
  370.     enc28j60Write(ETXNDH, (TXSTART_INIT+len)>>8);
  371.     // write per-packet control byte (0x00 means use macon3 settings)
  372.     enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
  373.     // copy the packet into the transmit buffer
  374.     enc28j60WriteBuffer(len, packet);
  375.     // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
  376.     if( (enc28j60Read(EIR) & EIR_TXERIF) ){
  377.         enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
  378.         enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
  379.         //enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
  380.         enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF);
  381.     }
  382.     // send the contents of the transmit buffer onto the network
  383.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
  384. }
  385.  
  386. // Gets a packet from the network receive buffer, if one is available.
  387. // The packet will by headed by an ethernet header.
  388. //      maxlen  The maximum acceptable length of a retrieved packet.
  389. //      packet  Pointer where packet data should be stored.
  390. // Returns: Packet length in bytes if a packet was retrieved, zero otherwise.
  391. uint16_t enc28j60PacketReceive(uint16_t maxlen, uint8_t* packet)
  392. {
  393.     uint16_t rxstat;
  394.     uint16_t len;
  395.     // check if a packet has been received and buffered
  396.     //if( !(enc28j60Read(EIR) & EIR_PKTIF) ){
  397.     // The above does not work. See Rev. B4 Silicon Errata point 6.
  398.     if( enc28j60Read(EPKTCNT) ==0 ){
  399.         return(0);
  400.     }
  401.  
  402.     // Set the read pointer to the start of the received packet
  403.     enc28j60Write(ERDPTL, (NextPacketPtr));
  404.     enc28j60Write(ERDPTH, (NextPacketPtr)>>8);
  405.     // read the next packet pointer
  406.     NextPacketPtr  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
  407.     NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
  408.     // read the packet length (see datasheet page 43)
  409.     len  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
  410.     len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
  411.     len-=4; //remove the CRC count
  412.     // read the receive status (see datasheet page 43)
  413.     rxstat  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
  414.     rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
  415.     // limit retrieve length
  416.     if (len>maxlen-1){
  417.         len=maxlen-1;
  418.     }
  419.     // check CRC and symbol errors (see datasheet page 44, table 7-3):
  420.     // The ERXFCON.CRCEN is set by default. Normally we should not
  421.     // need to check this.
  422.     if ((rxstat & 0x80)==0){
  423.         // invalid
  424.         len=0;
  425.     }else{
  426.         // copy the packet from the receive buffer
  427.         enc28j60ReadBuffer(len, packet);
  428.     }
  429.     // Move the RX read pointer to the start of the next received packet
  430.     // This frees the memory we just read out
  431.     enc28j60Write(ERXRDPTL, (NextPacketPtr));
  432.     enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8);
  433.     // decrement the packet counter indicate we are done with this packet
  434.     enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
  435.     return(len);
  436. }
  437.  
  438.