Ejemplo n.º 1
0
static uint8_t
readrev(void)
{
  uint8_t rev;
  setregbank(MAADRX_BANK);
  rev = readreg(EREVID);
  switch(rev) {
  case 2:
    return 1;
  case 6:
    return 7;
  default:
    return rev;
  }
}
Ejemplo n.º 2
0
/*---------------------------------------------------------------------------*/
int
enc28j60_send(const uint8_t *data, uint16_t datalen)
{
  uint16_t dataend;

  if(!initialized) {
    return -1;
  }

  /*
    1. Appropriately program the ETXST pointer to point to an unused
       location in memory. It will point to the per packet control
       byte. In the uart_demo, it would be programmed to 0120h. It is
       recommended that an even address be used for ETXST.

    2. Use the WBM SPI command to write the per packet control byte,
       the destination address, the source MAC address, the
       type/length and the data payload.

    3. Appropriately program the ETXND pointer. It should point to the
       last byte in the data payload.  In the uart_demo, it would be
       programmed to 0156h.

    4. Clear EIR.TXIF, set EIE.TXIE and set EIE.INTIE to enable an
       interrupt when done (if desired).

    5. Start the transmission process by setting
       ECON1.TXRTS.
  */

  setregbank(ERXTX_BANK);
  /* Set up the transmit buffer pointer */
  writereg(ETXSTL, TX_BUF_START & 0xff);
  writereg(ETXSTH, TX_BUF_START >> 8);
  writereg(EWRPTL, TX_BUF_START & 0xff);
  writereg(EWRPTH, TX_BUF_START >> 8);

  /* Write the transmission control register as the first byte of the
     output packet. We write 0x00 to indicate that the default
     configuration (the values in MACON3) will be used.  */
  writedatabyte(0x00); /* MACON3 */

  writedata(data, datalen);

  /* Write a pointer to the last data byte. */
  dataend = TX_BUF_START + datalen;
  writereg(ETXNDL, dataend & 0xff);
  writereg(ETXNDH, dataend >> 8);

  /* Clear EIR.TXIF */
  clearregbitfield(EIR, EIR_TXIF);

  /* Don't care about interrupts for now */

  /* Send the packet */
  setregbitfield(ECON1, ECON1_TXRTS);
  while((readreg(ECON1) & ECON1_TXRTS) > 0);

#if DEBUG
  if((readreg(ESTAT) & ESTAT_TXABRT) != 0) {
    uint16_t erdpt;
    uint8_t tsv[7];
    erdpt = (readreg(ERDPTH) << 8) | readreg(ERDPTL);
    writereg(ERDPTL, (dataend + 1) & 0xff);
    writereg(ERDPTH, (dataend + 1) >> 8);
    readdata(tsv, sizeof(tsv));
    writereg(ERDPTL, erdpt & 0xff);
    writereg(ERDPTH, erdpt >> 8);
    PRINTF("enc28j60: tx err: %d: %02x:%02x:%02x:%02x:%02x:%02x\n"
           "                  tsv: %02x%02x%02x%02x%02x%02x%02x\n", datalen,
           0xff & data[0], 0xff & data[1], 0xff & data[2],
           0xff & data[3], 0xff & data[4], 0xff & data[5],
           tsv[6], tsv[5], tsv[4], tsv[3], tsv[2], tsv[1], tsv[0]);
  } else {
Ejemplo n.º 3
0
/*---------------------------------------------------------------------------*/
static void
reset(void)
{
  PRINTF("enc28j60: resetting chip\n");

  enc28j60_arch_spi_init();

  /*
    6.0 INITIALIZATION

    Before the ENC28J60 can be used to transmit and receive packets,
    certain device settings must be initialized. Depending on the
    application, some configuration options may need to be
    changed. Normally, these tasks may be accomplished once after
    Reset and do not need to be changed thereafter.

    6.1 Receive Buffer

    Before receiving any packets, the receive buffer must be
    initialized by programming the ERXST and ERXND pointers. All
    memory between and including the ERXST and ERXND addresses will be
    dedicated to the receive hardware. It is recommended that the
    ERXST pointer be programmed with an even address.

    Applications expecting large amounts of data and frequent packet
    delivery may wish to allocate most of the memory as the receive
    buffer. Applications that may need to save older packets or have
    several packets ready for transmission should allocate less
    memory.

    When programming the ERXST pointer, the ERXWRPT registers will
    automatically be updated with the same values. The address in
    ERXWRPT will be used as the starting location when the receive
    hardware begins writing received data. For tracking purposes, the
    ERXRDPT registers should additionally be programmed with the same
    value. To program ERXRDPT, the host controller must write to
    ERXRDPTL first, followed by ERXRDPTH.  See Section 7.2.4 “Freeing
    Receive Buffer Space for more information

    6.2 Transmission Buffer

    All memory which is not used by the receive buffer is considered
    the transmission buffer. Data which is to be transmitted should be
    written into any unused space.  After a packet is transmitted,
    however, the hardware will write a seven-byte status vector into
    memory after the last byte in the packet. Therefore, the host
    controller should leave at least seven bytes between each packet
    and the beginning of the receive buffer. No explicit action is
    required to initialize the transmission buffer.

    6.3 Receive Filters

    The appropriate receive filters should be enabled or disabled by
    writing to the ERXFCON register. See Section 8.0 “Receive Filters
    for information on how to configure it.

    6.4 Waiting For OST

    If the initialization procedure is being executed immediately
    following a Power-on Reset, the ESTAT.CLKRDY bit should be polled
    to make certain that enough time has elapsed before proceeding to
    modify the MAC and PHY registers. For more information on the OST,
    see Section 2.2 “Oscillator Start-up Timer.
  */

  softreset();

  /* Workaround for erratum #2. */
  clock_delay_usec(1000);

  /* Wait for OST */
  while((readreg(ESTAT) & ESTAT_CLKRDY) == 0);

  setregbank(ERXTX_BANK);
  /* Set up receive buffer */
  writereg(ERXSTL, RX_BUF_START & 0xff);
  writereg(ERXSTH, RX_BUF_START >> 8);
  writereg(ERXNDL, RX_BUF_END & 0xff);
  writereg(ERXNDH, RX_BUF_END >> 8);
  writereg(ERDPTL, RX_BUF_START & 0xff);
  writereg(ERDPTH, RX_BUF_START >> 8);
  writereg(ERXRDPTL, RX_BUF_END & 0xff);
  writereg(ERXRDPTH, RX_BUF_END >> 8);

  /* Receive filters */
  setregbank(EPKTCNT_BANK);
  writereg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN);

  /*
    6.5 MAC Initialization Settings

    Several of the MAC registers require configuration during
    initialization. This only needs to be done once; the order of
    programming is unimportant.

    1. Set the MARXEN bit in MACON1 to enable the MAC to receive
    frames. If using full duplex, most applications should also set
    TXPAUS and RXPAUS to allow IEEE defined flow control to function.

    2. Configure the PADCFG, TXCRCEN and FULDPX bits of MACON3. Most
    applications should enable automatic padding to at least 60 bytes
    and always append a valid CRC. For convenience, many applications
    may wish to set the FRMLNEN bit as well to enable frame length
    status reporting. The FULDPX bit should be set if the application
    will be connected to a full-duplex configured remote node;
    otherwise, it should be left clear.

    3. Configure the bits in MACON4. For conformance to the IEEE 802.3
    standard, set the DEFER bit.

    4. Program the MAMXFL registers with the maximum frame length to
    be permitted to be received or transmitted. Normal network nodes
    are designed to handle packets that are 1518 bytes or less.

    5. Configure the Back-to-Back Inter-Packet Gap register,
    MABBIPG. Most applications will program this register with 15h
    when Full-Duplex mode is used and 12h when Half-Duplex mode is
    used.

    6. Configure the Non-Back-to-Back Inter-Packet Gap register low
    byte, MAIPGL. Most applications will program this register with
    12h.

    7. If half duplex is used, the Non-Back-to-Back Inter-Packet Gap
    register high byte, MAIPGH, should be programmed. Most
    applications will program this register to 0Ch.

    8. If Half-Duplex mode is used, program the Retransmission and
    Collision Window registers, MACLCON1 and MACLCON2. Most
    applications will not need to change the default Reset values.  If
    the network is spread over exceptionally long cables, the default
    value of MACLCON2 may need to be increased.

    9. Program the local MAC address into the MAADR1:MAADR6 registers.
  */

  setregbank(MACONX_BANK);

  /* Turn on reception and IEEE-defined flow control */
  setregbitfield(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);

  /* Set padding, crc, full duplex */
  setregbitfield(MACON3, MACON3_PADCFG_FULL | MACON3_TXCRCEN | MACON3_FULDPX |
                         MACON3_FRMLNEN);

  /* Don't modify MACON4 */

  /* Set maximum frame length in MAMXFL */
  writereg(MAMXFLL, MAX_MAC_LENGTH & 0xff);
  writereg(MAMXFLH, MAX_MAC_LENGTH >> 8);

  /* Set back-to-back inter packet gap */
  writereg(MABBIPG, 0x15);

  /* Set non-back-to-back packet gap */
  writereg(MAIPGL, 0x12);

  /* Set MAC address */
  setregbank(MAADRX_BANK);
  writereg(MAADR6, enc_mac_addr[5]);
  writereg(MAADR5, enc_mac_addr[4]);
  writereg(MAADR4, enc_mac_addr[3]);
  writereg(MAADR3, enc_mac_addr[2]);
  writereg(MAADR2, enc_mac_addr[1]);
  writereg(MAADR1, enc_mac_addr[0]);

  /*
    6.6 PHY Initialization Settings

    Depending on the application, bits in three of the PHY module’s
    registers may also require configuration.  The PHCON1.PDPXMD bit
    partially controls the device’s half/full-duplex
    configuration. Normally, this bit is initialized correctly by the
    external circuitry (see Section 2.6 “LED Configuration). If the
    external circuitry is not present or incorrect, however, the host
    controller must program the bit properly. Alternatively, for an
    externally configurable system, the PDPXMD bit may be read and the
    FULDPX bit be programmed to match.

    For proper duplex operation, the PHCON1.PDPXMD bit must also match
    the value of the MACON3.FULDPX bit.

    If using half duplex, the host controller may wish to set the
    PHCON2.HDLDIS bit to prevent automatic loopback of the data which
    is transmitted.  The PHY register, PHLCON, controls the outputs of
    LEDA and LEDB. If an application requires a LED configuration
    other than the default, PHLCON must be altered to match the new
    requirements. The settings for LED operation are discussed in
    Section 2.6 “LED Configuration. The PHLCON register is shown in
    Register 2-2 (page 9).
  */

  /* Don't worry about PHY configuration for now */

  /* Turn on autoincrement for buffer access */
  setregbitfield(ECON2, ECON2_AUTOINC);

  /* Turn on reception */
  writereg(ECON1, ECON1_RXEN);
}
Ejemplo n.º 4
0
/*---------------------------------------------------------------------------*/
int
enc28j60_read(uint8_t *buffer, uint16_t bufsize)
{
  int n, len, next, err;

  uint8_t nxtpkt[2];
  uint8_t status[2];
  uint8_t length[2];

  err = 0;

  setregbank(EPKTCNT_BANK);
  n = readreg(EPKTCNT);

  if(n == 0) {
    return 0;
  }

  PRINTF("enc28j60: EPKTCNT 0x%02x\n", n);

  setregbank(ERXTX_BANK);
  /* Read the next packet pointer */
  nxtpkt[0] = readdatabyte();
  nxtpkt[1] = readdatabyte();

  PRINTF("enc28j60: nxtpkt 0x%02x%02x\n", nxtpkt[1], nxtpkt[0]);


  length[0] = readdatabyte();
  length[1] = readdatabyte();

  PRINTF("enc28j60: length 0x%02x%02x\n", length[1], length[0]);

  status[0] = readdatabyte();
  status[1] = readdatabyte();

  /* This statement is just to avoid a compiler warning: */
  status[0] = status[0];
  PRINTF("enc28j60: status 0x%02x%02x\n", status[1], status[0]);

  len = (length[1] << 8) + length[0];
  if(bufsize >= len) {
    readdata(buffer, len);
  } else {
    uint16_t i;

    err = 1;

    /* flush rx fifo */
    for(i = 0; i < len; i++) {
      readdatabyte();
    }
  }

  /* Read an additional byte at odd lengths, to avoid FIFO corruption */
  if((len % 2) != 0) {
    readdatabyte();
  }

  /* Errata #14 */
  next = (nxtpkt[1] << 8) + nxtpkt[0];
  if(next == RX_BUF_START) {
    next = RX_BUF_END;
  } else {
    next = next - 1;
  }
  writereg(ERXRDPTL, next & 0xff);
  writereg(ERXRDPTH, next >> 8);

  writereg(ECON2, readreg(ECON2) | ECON2_PKTDEC);

  if(err) {
    PRINTF("enc28j60: rx err: flushed %d\n", len);
    return 0;
  }
  PRINTF("enc28j60: rx: %d: %02x:%02x:%02x:%02x:%02x:%02x\n", len,
         0xff&buffer[0], 0xff&buffer[1], 0xff&buffer[2],
         0xff&buffer[3], 0xff&buffer[4], 0xff&buffer[5]);

  received_packets++;
  PRINTF("enc28j60: received_packets %d\n", received_packets);
  return len;
}
Ejemplo n.º 5
0
/*---------------------------------------------------------------------------*/
int
enc28j60_send(uint8_t *data, uint16_t datalen)
{
  int padding = 0;

  if(!initialized) {
    return -1;
  }

  /*
    1. Appropriately program the ETXST pointer to point to an unused
       location in memory. It will point to the per packet control
       byte. In the example, it would be programmed to 0120h. It is
       recommended that an even address be used for ETXST.

    2. Use the WBM SPI command to write the per packet control byte,
       the destination address, the source MAC address, the
       type/length and the data payload.

    3. Appropriately program the ETXND pointer. It should point to the
       last byte in the data payload.  In the example, it would be
       programmed to 0156h.

    4. Clear EIR.TXIF, set EIE.TXIE and set EIE.INTIE to enable an
       interrupt when done (if desired).

    5. Start the transmission process by setting
       ECON1.TXRTS.
  */

  setregbank(ERXTX_BANK);
  /* Set up the transmit buffer pointer */
  writereg(ETXSTL, TX_BUF_START & 0xff);
  writereg(ETXSTH, TX_BUF_START >> 8);
  writereg(EWRPTL, TX_BUF_START & 0xff);
  writereg(EWRPTH, TX_BUF_START >> 8);

  /* Write the transmission control register as the first byte of the
     output packet. We write 0x00 to indicate that the default
     configuration (the values in MACON3) will be used.  */
#define WITH_MANUAL_PADDING 1
#if WITH_MANUAL_PADDING
#define PADDING_MIN_SIZE 60
  writedatabyte(0x0B); /* POVERRIDE, PCRCEN, PHUGEEN. Not PPADEN */
  if(datalen < PADDING_MIN_SIZE) {
    padding = PADDING_MIN_SIZE - datalen;
  } else {
    padding = 0;
  }
#else /* WITH_MANUAL_PADDING */
  writedatabyte(0x00); /* MACON3 */
  padding = 0;
#endif /* WITH_MANUAL_PADDING */

  /* Write a pointer to the last data byte. */
  writereg(ETXNDL, (TX_BUF_START + datalen + 0 + padding) & 0xff);
  writereg(ETXNDH, (TX_BUF_START + datalen + 0 + padding) >> 8);

  writedata(data, datalen);
  if(padding > 0) {
    uint8_t padding_buf[60];
    memset(padding_buf, 0, padding);
    writedata(padding_buf, padding);
  }

  /* Clear EIR.TXIF */
  writereg(EIR, readreg(EIR) & (~EIR_TXIF));

  /* Don't care about interrupts for now */

  /* Send the packet */
  writereg(ECON1, readreg(ECON1) | ECON1_TXRTS);
  while((readreg(ECON1) & ECON1_TXRTS) > 0);

  if((readreg(ESTAT) & ESTAT_TXABRT) != 0) {
    PRINTF("enc28j60: tx err: %d: %02x:%02x:%02x:%02x:%02x:%02x\n", datalen,
           0xff&data[0], 0xff&data[1], 0xff&data[2],
           0xff&data[3], 0xff&data[4], 0xff&data[5]);
  } else {
    PRINTF("enc28j60: tx: %d: %02x:%02x:%02x:%02x:%02x:%02x\n", datalen,
           0xff&data[0], 0xff&data[1], 0xff&data[2],
           0xff&data[3], 0xff&data[4], 0xff&data[5]);
  }
  sent_packets++;
  PRINTF("enc28j60: sent_packets %d\n", sent_packets);
  return datalen;
}