src/ENC28J60.c
static int8_t enc28j60_init(struct enc28j60_dev *priv) {
    uint8_t revid, sreg, err;
    struct net_dev_s *net_dev = priv->net_dev;

    sreg = SREG;
    cli();

    chip_desel(priv->spi_dev->cs);
    
    // spi_set_speed(ENC28J60_MAX_FREQ);
    
    /* Oscillator Start-up Timer (OST) - 300 us delay after power-up */
    _delay_us(300);

    /* reset routine */
    enc28j60_soft_reset(priv);

    net_dev_set_upstate_stop(net_dev);

    /* INITIALIZATION */
    revid = rcr(priv, ENC28J60_EREVID) & 0x1F;
    if ((revid == 0x00) || (revid == 0xFFU)) {
        // device not connect
        printf_P(PSTR("enc28j60_init() - Invalid REVID %d\n"), revid);
        return -1;
    }
    
    /* Receive Buffer init*/
    err = rx_buf_init(priv, ENC28J60_RXSTART_INIT, ENC28J60_RXEND_INIT);
    if (err)
        return err;
    
    /* Transmit Buffer init */
    err = tx_buf_init(priv, ENC28J60_TXSTART_INIT, ENC28J60_TXEND_INIT);
    if (err)
        return err;

    /* Receive Filters
       The appropriate receive filters should be enabled or
       disabled by writing to the ERXFCON register.
       By default is set UCEN, CRCEN, BCEN
       (unicast, broadcast and CRC check)
     */
    wcr(priv, ENC28J60_ERXFCON, (_BV(UCEN) | _BV(CRCEN) | _BV(BCEN)));

    /* Waiting for OST
       CLKRDY bit must be polled before
       transmitting packets, enabling packet
       reception or accessing any MAC, MII or
       PHY registers.
     */
    while (!(rcr(priv, ENC28J60_ESTAT) & _BV(CLKRDY))) {}

    enc28j60_disable(net_dev);
    
    /* MAC Initialization Settings
        1. Set the MARXEN bit in MACON1 to enable the MAC to receive frames.
            If using full duplex, also set TXPAUS and RXPAUS.
        2. Configure the PADCFG (101), TXCRCEN and FULDPX bits of MACON3.
            Set the FRMLNEN bit to enable frame length status reporting.
            The FULDPX bit should be set if the app 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.
            0x15 for Full-Duplex mode;
            0x12 for Half-Duplex mode.
        6. Configure the Non-Back-to-Back Inter-Packet Gap register low byte, MAIPGL.
            Most applications will program this register with 0x12.
        7. If Half-Duplex is used, the MAIPGH should be programmed.
            Most applications will program this register to 0x0C.
        8. If Half-Duplex 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
            (after initialization).
     */
    if (net_dev->flags.full_duplex) {
        wcr(priv, ENC28J60_MACON1, (_BV(MARXEN) | _BV(TXPAUS) | _BV(RXPAUS)));  // 1.
        wcr(priv, ENC28J60_MACON3, (_BV(PADCFG2) | _BV(PADCFG0) | _BV(TXCRCEN) |
                                    _BV(FRMLNEN) | _BV(FULDPX)));   // 2.
        wcr(priv, ENC28J60_MACON4, _BV(DEFER));   // 3.
        wcr(priv, ENC28J60_MABBIPG, 0x15);   // 5.
    } else {
        wcr(priv, ENC28J60_MACON1, _BV(MARXEN));  // 1.
        wcr(priv, ENC28J60_MACON3, (_BV(PADCFG2) | _BV(PADCFG0) |
                                    _BV(TXCRCEN) | _BV(FRMLNEN)));  // 2.
        wcr(priv, ENC28J60_MACON4, (_BV(DEFER) | _BV(BPEN) | _BV(NOBKOFF)));    // 3.
        wcr(priv, ENC28J60_MABBIPG, 0x12);   // 5.
        wcr(priv, ENC28J60_MAIPGH, 0x0C);    // 7.
        wcr(priv, ENC28J60_MACLCON1, 0x0F);  // 8.   defaul value
        wcr(priv, ENC28J60_MACLCON2, 0x37);  // 8.   defaul value
    }

    wcr(priv, ENC28J60_MAMXFLL, (uint8_t)(ENC28J60_MAX_FRAME_LEN & 0xFFU)); // 4.
    wcr(priv, ENC28J60_MAMXFLH, (uint8_t)(ENC28J60_MAX_FRAME_LEN >> 8));    // MAMXFL = 1518
    wcr(priv, ENC28J60_MAIPGL, 0x12);    // 6.

    /* PHY Initialization Settings
        For proper duplex operation, the PHCON1.PDPXMD bit must
        also match the value of the MACON3.FULDPX bit.
        If using Half-Duplex, may to set the PHCON2.HDLDIS bit to
        prevent automatic loopback of the data which is transmitted.

        The PHLCON register 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.
     */
    if (net_dev->flags.full_duplex) {
        phy_write(priv, ENC28J60_PHCON1,
                  (phy_read(priv, ENC28J60_PHCON1) | _BV(PDPXMD)));
    } else {
        phy_write(priv, ENC28J60_PHCON1,
                  (phy_read(priv, ENC28J60_PHCON1) & ~_BV(PDPXMD)));
        phy_write(priv, ENC28J60_PHCON2,
                  (phy_read(priv, ENC28J60_PHCON2) | _BV(HDLDIS)));
    }

    net_dev->mtu = 1500;

    printf_P(PSTR("ENC28J60 initialized with RevID %d, %S Duplex\n"),
             revid, net_dev->flags.full_duplex ? PSTR("Full") : PSTR("Half"));

    SREG = sreg;

    return 0;
}
/*!
 * @brief Initial ethernet shield sequence
 * @param priv Private data of this device
 * @return 0 if success; errno if error
 */
@brief Initial ethernet shield sequence
@param priv Private data of this device
@return 0 if success; errno if error
@brief Initial ethernet shield sequence @param priv Private data of this device @return 0 if success ; errno if error
static int8_t enc28j60_init(struct enc28j60_dev *priv) {
    uint8_t revid, sreg, err;
    struct net_dev_s *net_dev = priv->net_dev;
    sreg = SREG;
    cli();
    chip_desel(priv->spi_dev->cs);
    _delay_us(300);
    enc28j60_soft_reset(priv);
    net_dev_set_upstate_stop(net_dev);
    revid = rcr(priv, ENC28J60_EREVID) & 0x1F;
    if ((revid == 0x00) || (revid == 0xFFU)) {
        printf_P(PSTR("enc28j60_init() - Invalid REVID %d\n"), revid);
        return -1;
    }
    err = rx_buf_init(priv, ENC28J60_RXSTART_INIT, ENC28J60_RXEND_INIT);
    if (err)
        return err;
    err = tx_buf_init(priv, ENC28J60_TXSTART_INIT, ENC28J60_TXEND_INIT);
    if (err)
        return err;
    wcr(priv, ENC28J60_ERXFCON, (_BV(UCEN) | _BV(CRCEN) | _BV(BCEN)));
    while (!(rcr(priv, ENC28J60_ESTAT) & _BV(CLKRDY))) {}
    enc28j60_disable(net_dev);
    if (net_dev->flags.full_duplex) {
        wcr(priv, ENC28J60_MACON1, (_BV(MARXEN) | _BV(TXPAUS) | _BV(RXPAUS)));  
        wcr(priv, ENC28J60_MACON3, (_BV(PADCFG2) | _BV(PADCFG0) | _BV(TXCRCEN) |
                                    _BV(FRMLNEN) | _BV(FULDPX)));   
        wcr(priv, ENC28J60_MACON4, _BV(DEFER));   
        wcr(priv, ENC28J60_MABBIPG, 0x15);   
    } else {
        wcr(priv, ENC28J60_MACON1, _BV(MARXEN));  
        wcr(priv, ENC28J60_MACON3, (_BV(PADCFG2) | _BV(PADCFG0) |
                                    _BV(TXCRCEN) | _BV(FRMLNEN)));  
        wcr(priv, ENC28J60_MACON4, (_BV(DEFER) | _BV(BPEN) | _BV(NOBKOFF)));    
        wcr(priv, ENC28J60_MABBIPG, 0x12);   
        wcr(priv, ENC28J60_MAIPGH, 0x0C);    
        wcr(priv, ENC28J60_MACLCON1, 0x0F);  
        wcr(priv, ENC28J60_MACLCON2, 0x37);  
    }
    wcr(priv, ENC28J60_MAMXFLL, (uint8_t)(ENC28J60_MAX_FRAME_LEN & 0xFFU)); 
    wcr(priv, ENC28J60_MAMXFLH, (uint8_t)(ENC28J60_MAX_FRAME_LEN >> 8));    
    wcr(priv, ENC28J60_MAIPGL, 0x12);    
    if (net_dev->flags.full_duplex) {
        phy_write(priv, ENC28J60_PHCON1,
                  (phy_read(priv, ENC28J60_PHCON1) | _BV(PDPXMD)));
    } else {
        phy_write(priv, ENC28J60_PHCON1,
                  (phy_read(priv, ENC28J60_PHCON1) & ~_BV(PDPXMD)));
        phy_write(priv, ENC28J60_PHCON2,
                  (phy_read(priv, ENC28J60_PHCON2) | _BV(HDLDIS)));
    }
    net_dev->mtu = 1500;
    printf_P(PSTR("ENC28J60 initialized with RevID %d, %S Duplex\n"),
             revid, net_dev->flags.full_duplex ? PSTR("Full") : PSTR("Half"));
    SREG = sreg;
    return 0;
}
static int8_t enc28j60_init ( struct enc28j60_dev * priv ) { uint8_t revid , sreg , err ; struct net_dev_s * net_dev = priv -> net_dev ; sreg = SREG ; cli ( ) ; chip_desel ( priv -> spi_dev -> cs ) ; _delay_us ( 300 ) ; enc28j60_soft_reset ( priv ) ; net_dev_set_upstate_stop ( net_dev ) ; revid = rcr ( priv , ENC28J60_EREVID ) & 0x1F ; if ( ( revid == 0x00 ) || ( revid == 0xFFU ) ) { printf_P ( PSTR ( " \n " ) , revid ) ; return -1 ; } err = rx_buf_init ( priv , ENC28J60_RXSTART_INIT , ENC28J60_RXEND_INIT ) ; if ( err ) return err ; err = tx_buf_init ( priv , ENC28J60_TXSTART_INIT , ENC28J60_TXEND_INIT ) ; if ( err ) return err ; wcr ( priv , ENC28J60_ERXFCON , ( _BV ( UCEN ) | _BV ( CRCEN ) | _BV ( BCEN ) ) ) ; while ( ! ( rcr ( priv , ENC28J60_ESTAT ) & _BV ( CLKRDY ) ) ) { } enc28j60_disable ( net_dev ) ; if ( net_dev -> flags . full_duplex ) { wcr ( priv , ENC28J60_MACON1 , ( _BV ( MARXEN ) | _BV ( TXPAUS ) | _BV ( RXPAUS ) ) ) ; wcr ( priv , ENC28J60_MACON3 , ( _BV ( PADCFG2 ) | _BV ( PADCFG0 ) | _BV ( TXCRCEN ) | _BV ( FRMLNEN ) | _BV ( FULDPX ) ) ) ; wcr ( priv , ENC28J60_MACON4 , _BV ( DEFER ) ) ; wcr ( priv , ENC28J60_MABBIPG , 0x15 ) ; } else { wcr ( priv , ENC28J60_MACON1 , _BV ( MARXEN ) ) ; wcr ( priv , ENC28J60_MACON3 , ( _BV ( PADCFG2 ) | _BV ( PADCFG0 ) | _BV ( TXCRCEN ) | _BV ( FRMLNEN ) ) ) ; wcr ( priv , ENC28J60_MACON4 , ( _BV ( DEFER ) | _BV ( BPEN ) | _BV ( NOBKOFF ) ) ) ; wcr ( priv , ENC28J60_MABBIPG , 0x12 ) ; wcr ( priv , ENC28J60_MAIPGH , 0x0C ) ; wcr ( priv , ENC28J60_MACLCON1 , 0x0F ) ; wcr ( priv , ENC28J60_MACLCON2 , 0x37 ) ; } wcr ( priv , ENC28J60_MAMXFLL , ( uint8_t ) ( ENC28J60_MAX_FRAME_LEN & 0xFFU ) ) ; wcr ( priv , ENC28J60_MAMXFLH , ( uint8_t ) ( ENC28J60_MAX_FRAME_LEN >> 8 ) ) ; wcr ( priv , ENC28J60_MAIPGL , 0x12 ) ; if ( net_dev -> flags . full_duplex ) { phy_write ( priv , ENC28J60_PHCON1 , ( phy_read ( priv , ENC28J60_PHCON1 ) | _BV ( PDPXMD ) ) ) ; } else { phy_write ( priv , ENC28J60_PHCON1 , ( phy_read ( priv , ENC28J60_PHCON1 ) & ~ _BV ( PDPXMD ) ) ) ; phy_write ( priv , ENC28J60_PHCON2 , ( phy_read ( priv , ENC28J60_PHCON2 ) | _BV ( HDLDIS ) ) ) ; } net_dev -> mtu = 1500 ; printf_P ( PSTR ( " \n " ) , revid , net_dev -> flags . full_duplex ? PSTR ( " " ) : PSTR ( " " ) ) ; SREG = sreg ; return 0 ; }
@brief Initial ethernet shield sequence
 @param priv Private data of this device
 @return 0 if success; errno if error
@brief Initial ethernet shield sequence @param priv Private data of this device @return 0 if success ; errno if error
// spi_set_speed(ENC28J60_MAX_FREQ); /* Oscillator Start-up Timer (OST) - 300 us delay after power-up */ /* reset routine */ /* INITIALIZATION */ // device not connect /* Receive Buffer init*/ /* Transmit Buffer init */ /* Receive Filters
       The appropriate receive filters should be enabled or
       disabled by writing to the ERXFCON register.
       By default is set UCEN, CRCEN, BCEN
       (unicast, broadcast and CRC check)
     */ /* Waiting for OST
       CLKRDY bit must be polled before
       transmitting packets, enabling packet
       reception or accessing any MAC, MII or
       PHY registers.
     */ /* MAC Initialization Settings
        1. Set the MARXEN bit in MACON1 to enable the MAC to receive frames.
            If using full duplex, also set TXPAUS and RXPAUS.
        2. Configure the PADCFG (101), TXCRCEN and FULDPX bits of MACON3.
            Set the FRMLNEN bit to enable frame length status reporting.
            The FULDPX bit should be set if the app 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.
            0x15 for Full-Duplex mode;
            0x12 for Half-Duplex mode.
        6. Configure the Non-Back-to-Back Inter-Packet Gap register low byte, MAIPGL.
            Most applications will program this register with 0x12.
        7. If Half-Duplex is used, the MAIPGH should be programmed.
            Most applications will program this register to 0x0C.
        8. If Half-Duplex 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
            (after initialization).
     */ // 1. // 2. // 3. // 5. // 1. // 2. // 3. // 5. // 7. // 8.   defaul value // 8.   defaul value // 4. // MAMXFL = 1518 // 6. /* PHY Initialization Settings
        For proper duplex operation, the PHCON1.PDPXMD bit must
        also match the value of the MACON3.FULDPX bit.
        If using Half-Duplex, may to set the PHCON2.HDLDIS bit to
        prevent automatic loopback of the data which is transmitted.

        The PHLCON register 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.
     */