EMAC driver for the ENC28J60 Ethernet controller. This is a simplified fork of https://github.com/tobiasjaster/ENC28J60-EMAC-Driver published by Tobias Jaster.
Dependents: MQTT_Hello MQTT_HelloENC28J60
EMAC driver for the ENC28J60 Ethernet controller
This is a fork (the INT and RST pins are not used) of the ENC28J60-EMAC driver published by Tobias Jaster at
https://github.com/tobiasjaster/ENC28J60-EMAC-Driver
Usage:
- Connect the ENC28J60 module to the Mbed board as follows:
- Import (add) this ENC28J60-EMAC library to your program.
- Add a "mbed_app.json" file with the following content to the root directory of your program:
{ "target_overrides": { "*": { "platform.callback-nontrivial": true, "enc28j60-emac.mosi": "D11", "enc28j60-emac.miso": "D12", "enc28j60-emac.sck" : "D13", "enc28j60-emac.cs" : "D10" } } }
- Replace "D11", ..., "D10" with the actual pin names you selected on the Mbed board to be used for the SPI communication.
- To set the MAC address define an array with the desired address bytes and call the "set_hwaddr(mac)" function before calling the network interface "connect" function.
For example:
const uint8_t MAC[6] = { 0, 1, 2, 3, 4, 5 }; EthernetInterface net; int main() { net.get_emac().set_hwaddr(MAC); // set MAC address if (net.connect() != 0) { printf("Error: Unable to connect to the network.\n"); return -1; } ...
enc28j60.cpp@0:b599e748252c, 2021-03-26 (annotated)
- Committer:
- hudakz
- Date:
- Fri Mar 26 15:58:28 2021 +0000
- Revision:
- 0:b599e748252c
- Child:
- 1:bce04bfc41fe
Mbed OS Ethernet MAC (EMAC) driver for the ENC28J60 Ethernet controller.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 0:b599e748252c | 1 | /* |
hudakz | 0:b599e748252c | 2 | * Copyright (c) 2019 Tobias Jaster |
hudakz | 0:b599e748252c | 3 | * |
hudakz | 0:b599e748252c | 4 | * Modified by Zoltan Hudak |
hudakz | 0:b599e748252c | 5 | * |
hudakz | 0:b599e748252c | 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
hudakz | 0:b599e748252c | 7 | * you may not use this file except in compliance with the License. |
hudakz | 0:b599e748252c | 8 | * You may obtain a copy of the License at |
hudakz | 0:b599e748252c | 9 | * |
hudakz | 0:b599e748252c | 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
hudakz | 0:b599e748252c | 11 | * |
hudakz | 0:b599e748252c | 12 | * Unless required by applicable law or agreed to in writing, software |
hudakz | 0:b599e748252c | 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
hudakz | 0:b599e748252c | 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
hudakz | 0:b599e748252c | 15 | * See the License for the specific language governing permissions and |
hudakz | 0:b599e748252c | 16 | * limitations under the License. |
hudakz | 0:b599e748252c | 17 | */ |
hudakz | 0:b599e748252c | 18 | #include "cmsis.h" |
hudakz | 0:b599e748252c | 19 | #include "enc28j60.h" |
hudakz | 0:b599e748252c | 20 | |
hudakz | 0:b599e748252c | 21 | #ifndef NULL |
hudakz | 0:b599e748252c | 22 | #define NULL ((void*)0) |
hudakz | 0:b599e748252c | 23 | #endif |
hudakz | 0:b599e748252c | 24 | #define ENC28J60_DEBUG 0 |
hudakz | 0:b599e748252c | 25 | |
hudakz | 0:b599e748252c | 26 | #if ENC28J60_DEBUG |
hudakz | 0:b599e748252c | 27 | #define ENC28J60_DEBUG_PRINTF(...) printf(__VA_ARGS__) |
hudakz | 0:b599e748252c | 28 | #else |
hudakz | 0:b599e748252c | 29 | #define ENC28J60_DEBUG_PRINTF(...) |
hudakz | 0:b599e748252c | 30 | #endif |
hudakz | 0:b599e748252c | 31 | /** Millisec timeout macros */ |
hudakz | 0:b599e748252c | 32 | #define RESET_TIME_OUT_MS 10ms |
hudakz | 0:b599e748252c | 33 | #define REG_WRITE_TIME_OUT_MS 50ms |
hudakz | 0:b599e748252c | 34 | #define PHY_RESET_TIME_OUT_MS 100ms |
hudakz | 0:b599e748252c | 35 | #define INIT_FINISH_DELAY 2000ms |
hudakz | 0:b599e748252c | 36 | |
hudakz | 0:b599e748252c | 37 | /** |
hudakz | 0:b599e748252c | 38 | * \brief TX FIFO Size definitions |
hudakz | 0:b599e748252c | 39 | * |
hudakz | 0:b599e748252c | 40 | */ |
hudakz | 0:b599e748252c | 41 | #define TX_STATUS_FIFO_SIZE_BYTES 512U /*< fixed allocation in bytes */ |
hudakz | 0:b599e748252c | 42 | #define TX_DATA_FIFO_SIZE_KBYTES_POS 8U |
hudakz | 0:b599e748252c | 43 | #define TX_DATA_FIFO_SIZE_KBYTES_MASK 0x0FU |
hudakz | 0:b599e748252c | 44 | #define KBYTES_TO_BYTES_MULTIPLIER 1024U |
hudakz | 0:b599e748252c | 45 | |
hudakz | 0:b599e748252c | 46 | /** |
hudakz | 0:b599e748252c | 47 | * \brief FIFO Info definitions |
hudakz | 0:b599e748252c | 48 | * |
hudakz | 0:b599e748252c | 49 | */ |
hudakz | 0:b599e748252c | 50 | #define FIFO_USED_SPACE_MASK 0xFFFFU |
hudakz | 0:b599e748252c | 51 | #define DATA_FIFO_USED_SPACE_POS 0U |
hudakz | 0:b599e748252c | 52 | #define STATUS_FIFO_USED_SPACE_POS 16U |
hudakz | 0:b599e748252c | 53 | |
hudakz | 0:b599e748252c | 54 | #define HW_CFG_REG_RX_FIFO_POS 10U |
hudakz | 0:b599e748252c | 55 | #define HW_CFG_REG_RX_FIFO_SIZE_ALL 8U |
hudakz | 0:b599e748252c | 56 | #define HW_CFG_REG_RX_FIFO_SIZE_MIN 2U /*< Min Rx fifo size in KB */ |
hudakz | 0:b599e748252c | 57 | #define HW_CFG_REG_RX_FIFO_SIZE_MAX 6U /*< Max Rx fifo size in KB */ |
hudakz | 0:b599e748252c | 58 | #define HW_CFG_REG_RX_FIFO_SIZE 5U /*< Rx fifo size in KB */ |
hudakz | 0:b599e748252c | 59 | |
hudakz | 0:b599e748252c | 60 | /** |
hudakz | 0:b599e748252c | 61 | * \brief Chip ID definitions |
hudakz | 0:b599e748252c | 62 | * |
hudakz | 0:b599e748252c | 63 | */ |
hudakz | 0:b599e748252c | 64 | #define CHIP_ID 0x20C5U |
hudakz | 0:b599e748252c | 65 | |
hudakz | 0:b599e748252c | 66 | /** |
hudakz | 0:b599e748252c | 67 | * @brief |
hudakz | 0:b599e748252c | 68 | * @note |
hudakz | 0:b599e748252c | 69 | * @param |
hudakz | 0:b599e748252c | 70 | * @retval |
hudakz | 0:b599e748252c | 71 | */ |
hudakz | 0:b599e748252c | 72 | ENC28J60::ENC28J60(PinName mosi, PinName miso, PinName sclk, PinName cs) : |
hudakz | 0:b599e748252c | 73 | _spi(new SPI(mosi, miso, sclk)), |
hudakz | 0:b599e748252c | 74 | _cs(cs), |
hudakz | 0:b599e748252c | 75 | _bank(0), |
hudakz | 0:b599e748252c | 76 | _ready(true), |
hudakz | 0:b599e748252c | 77 | _next(ERXST_INI) |
hudakz | 0:b599e748252c | 78 | { |
hudakz | 0:b599e748252c | 79 | init(); |
hudakz | 0:b599e748252c | 80 | } |
hudakz | 0:b599e748252c | 81 | |
hudakz | 0:b599e748252c | 82 | /** |
hudakz | 0:b599e748252c | 83 | * @brief |
hudakz | 0:b599e748252c | 84 | * @note |
hudakz | 0:b599e748252c | 85 | * @param |
hudakz | 0:b599e748252c | 86 | * @retval |
hudakz | 0:b599e748252c | 87 | */ |
hudakz | 0:b599e748252c | 88 | ENC28J60::ENC28J60(mbed::SPI* spi, PinName cs) : |
hudakz | 0:b599e748252c | 89 | _cs(cs), |
hudakz | 0:b599e748252c | 90 | _bank(0), |
hudakz | 0:b599e748252c | 91 | _ready(true), |
hudakz | 0:b599e748252c | 92 | _next(ERXST_INI) |
hudakz | 0:b599e748252c | 93 | { |
hudakz | 0:b599e748252c | 94 | init(); |
hudakz | 0:b599e748252c | 95 | } |
hudakz | 0:b599e748252c | 96 | |
hudakz | 0:b599e748252c | 97 | /** |
hudakz | 0:b599e748252c | 98 | * @brief |
hudakz | 0:b599e748252c | 99 | * @note |
hudakz | 0:b599e748252c | 100 | * @param |
hudakz | 0:b599e748252c | 101 | * @retval |
hudakz | 0:b599e748252c | 102 | */ |
hudakz | 0:b599e748252c | 103 | void ENC28J60::init() |
hudakz | 0:b599e748252c | 104 | { |
hudakz | 0:b599e748252c | 105 | // Initialize SPI interface |
hudakz | 0:b599e748252c | 106 | |
hudakz | 0:b599e748252c | 107 | _cs = 1; |
hudakz | 0:b599e748252c | 108 | _spi->format(8, 0); // 8bit, mode 0 |
hudakz | 0:b599e748252c | 109 | _spi->frequency(20000000); // 20MHz |
hudakz | 0:b599e748252c | 110 | |
hudakz | 0:b599e748252c | 111 | // Wait SPI to become stable |
hudakz | 0:b599e748252c | 112 | ThisThread::sleep_for(RESET_TIME_OUT_MS); |
hudakz | 0:b599e748252c | 113 | |
hudakz | 0:b599e748252c | 114 | // Perform system reset |
hudakz | 0:b599e748252c | 115 | writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); |
hudakz | 0:b599e748252c | 116 | |
hudakz | 0:b599e748252c | 117 | // Check CLKRDY bit to see if reset is complete |
hudakz | 0:b599e748252c | 118 | // while(!(readReg(ESTAT) & ESTAT_CLKRDY)); |
hudakz | 0:b599e748252c | 119 | // The CLKRDY does not work. See Rev. B4 Silicon Errata point. |
hudakz | 0:b599e748252c | 120 | // Workaround: Just wait. |
hudakz | 0:b599e748252c | 121 | ThisThread::sleep_for(RESET_TIME_OUT_MS); |
hudakz | 0:b599e748252c | 122 | |
hudakz | 0:b599e748252c | 123 | // Set pointers to receive buffer boundaries |
hudakz | 0:b599e748252c | 124 | writeRegPair(ERXSTL, ERXST_INI); |
hudakz | 0:b599e748252c | 125 | writeRegPair(ERXNDL, ERXND_INI); |
hudakz | 0:b599e748252c | 126 | |
hudakz | 0:b599e748252c | 127 | // Set receive pointer. Receive hardware will write data up to, |
hudakz | 0:b599e748252c | 128 | // but not including the memory pointed to by ERXRDPT |
hudakz | 0:b599e748252c | 129 | writeReg(ERXRDPTL, ERXST_INI); |
hudakz | 0:b599e748252c | 130 | |
hudakz | 0:b599e748252c | 131 | // All memory which is not used by the receive buffer is considered the transmission buffer. |
hudakz | 0:b599e748252c | 132 | // No explicit action is required to initialize the transmission buffer. |
hudakz | 0:b599e748252c | 133 | // TX buffer start. |
hudakz | 0:b599e748252c | 134 | writeRegPair(ETXSTL, ETXST_INI); |
hudakz | 0:b599e748252c | 135 | |
hudakz | 0:b599e748252c | 136 | // TX buffer end at end of ethernet buffer memory. |
hudakz | 0:b599e748252c | 137 | writeRegPair(ETXNDL, ETXND_INI); |
hudakz | 0:b599e748252c | 138 | |
hudakz | 0:b599e748252c | 139 | // However, he host controller should leave at least seven bytes between each |
hudakz | 0:b599e748252c | 140 | // packet and the beginning of the receive buffer. |
hudakz | 0:b599e748252c | 141 | // do bank 1 stuff, packet filter: |
hudakz | 0:b599e748252c | 142 | // For broadcast packets we allow only ARP packtets |
hudakz | 0:b599e748252c | 143 | // All other packets should be unicast only for our mac (MAADR) |
hudakz | 0:b599e748252c | 144 | // |
hudakz | 0:b599e748252c | 145 | // The pattern to match is therefore |
hudakz | 0:b599e748252c | 146 | // Type ETH.DST |
hudakz | 0:b599e748252c | 147 | // ARP BROADCAST |
hudakz | 0:b599e748252c | 148 | // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 |
hudakz | 0:b599e748252c | 149 | // in binary these poitions are:11 0000 0011 1111 |
hudakz | 0:b599e748252c | 150 | // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 |
hudakz | 0:b599e748252c | 151 | //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN! |
hudakz | 0:b599e748252c | 152 | writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_BCEN); |
hudakz | 0:b599e748252c | 153 | writeRegPair(EPMM0, 0x303f); |
hudakz | 0:b599e748252c | 154 | writeRegPair(EPMCSL, 0xf7f9); |
hudakz | 0:b599e748252c | 155 | |
hudakz | 0:b599e748252c | 156 | // Enable MAC receive and bring MAC out of reset (writes 0x00 to MACON2) |
hudakz | 0:b599e748252c | 157 | writeRegPair(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS); |
hudakz | 0:b599e748252c | 158 | |
hudakz | 0:b599e748252c | 159 | // Enable automatic padding to 60bytes and CRC operations |
hudakz | 0:b599e748252c | 160 | writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN); |
hudakz | 0:b599e748252c | 161 | |
hudakz | 0:b599e748252c | 162 | // Set inter-frame gap (non-back-to-back) |
hudakz | 0:b599e748252c | 163 | writeRegPair(MAIPGL, 0x0C12); |
hudakz | 0:b599e748252c | 164 | |
hudakz | 0:b599e748252c | 165 | // Set inter-frame gap (back-to-back) |
hudakz | 0:b599e748252c | 166 | writeReg(MABBIPG, 0x12); |
hudakz | 0:b599e748252c | 167 | |
hudakz | 0:b599e748252c | 168 | // Set the maximum packet size which the controller will accept |
hudakz | 0:b599e748252c | 169 | // Do not send packets longer than MAX_FRAMELEN: |
hudakz | 0:b599e748252c | 170 | writeRegPair(MAMXFLL, MAX_FRAMELEN); |
hudakz | 0:b599e748252c | 171 | |
hudakz | 0:b599e748252c | 172 | // No loopback of transmitted frames |
hudakz | 0:b599e748252c | 173 | phyWrite(PHCON2, PHCON2_HDLDIS); |
hudakz | 0:b599e748252c | 174 | |
hudakz | 0:b599e748252c | 175 | // Switch to bank 0 |
hudakz | 0:b599e748252c | 176 | _setBank(ECON1); |
hudakz | 0:b599e748252c | 177 | |
hudakz | 0:b599e748252c | 178 | // Enable interrutps |
hudakz | 0:b599e748252c | 179 | writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE); |
hudakz | 0:b599e748252c | 180 | |
hudakz | 0:b599e748252c | 181 | // Enable packet reception |
hudakz | 0:b599e748252c | 182 | writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); |
hudakz | 0:b599e748252c | 183 | |
hudakz | 0:b599e748252c | 184 | // Configure leds |
hudakz | 0:b599e748252c | 185 | phyWrite(PHLCON, 0x476); |
hudakz | 0:b599e748252c | 186 | } |
hudakz | 0:b599e748252c | 187 | |
hudakz | 0:b599e748252c | 188 | /** |
hudakz | 0:b599e748252c | 189 | * @brief |
hudakz | 0:b599e748252c | 190 | * @note |
hudakz | 0:b599e748252c | 191 | * @param |
hudakz | 0:b599e748252c | 192 | * @retval |
hudakz | 0:b599e748252c | 193 | */ |
hudakz | 0:b599e748252c | 194 | enc28j60_error_t ENC28J60::getPacketInfo(packet_t* packet) |
hudakz | 0:b599e748252c | 195 | { |
hudakz | 0:b599e748252c | 196 | enc28j60_error_t ret; |
hudakz | 0:b599e748252c | 197 | uint8_t nextPacketAddrL; |
hudakz | 0:b599e748252c | 198 | uint8_t nextPacketAddrH; |
hudakz | 0:b599e748252c | 199 | uint8_t status[RX_STAT_LEN]; |
hudakz | 0:b599e748252c | 200 | |
hudakz | 0:b599e748252c | 201 | if (!_ready) |
hudakz | 0:b599e748252c | 202 | return ENC28J60_ERROR_LASTPACKET; |
hudakz | 0:b599e748252c | 203 | |
hudakz | 0:b599e748252c | 204 | // Check if a new packet has been received and buffered. |
hudakz | 0:b599e748252c | 205 | // The Receive Packet Pending Interrupt Flag (EIR.PKTIF) does not reliably |
hudakz | 0:b599e748252c | 206 | // report the status of pending packets. See Rev. B4 Silicon Errata point 6. |
hudakz | 0:b599e748252c | 207 | // Workaround: Check EPKTCNT |
hudakz | 0:b599e748252c | 208 | if (readReg(EPKTCNT) == 0) |
hudakz | 0:b599e748252c | 209 | return ENC28J60_ERROR_NOPACKET; |
hudakz | 0:b599e748252c | 210 | |
hudakz | 0:b599e748252c | 211 | _ready = false; |
hudakz | 0:b599e748252c | 212 | |
hudakz | 0:b599e748252c | 213 | // Packet pointer in receive buffer is wrapped by hardware. |
hudakz | 0:b599e748252c | 214 | packet->addr = _next; |
hudakz | 0:b599e748252c | 215 | |
hudakz | 0:b599e748252c | 216 | // Program the receive buffer read pointer to point to this packet. |
hudakz | 0:b599e748252c | 217 | writeRegPair(ERDPTL, packet->addr); |
hudakz | 0:b599e748252c | 218 | |
hudakz | 0:b599e748252c | 219 | // Read the next packet address |
hudakz | 0:b599e748252c | 220 | nextPacketAddrL = readOp(ENC28J60_READ_BUF_MEM, 0); |
hudakz | 0:b599e748252c | 221 | nextPacketAddrH = readOp(ENC28J60_READ_BUF_MEM, 0); |
hudakz | 0:b599e748252c | 222 | _next = (nextPacketAddrH << 8) | nextPacketAddrL; |
hudakz | 0:b599e748252c | 223 | |
hudakz | 0:b599e748252c | 224 | // Read the packet status vector bytes (see datasheet page 43) |
hudakz | 0:b599e748252c | 225 | for (uint8_t i = 0; i < RX_STAT_LEN; i++) { |
hudakz | 0:b599e748252c | 226 | status[i] = readOp(ENC28J60_READ_BUF_MEM, 0); |
hudakz | 0:b599e748252c | 227 | } |
hudakz | 0:b599e748252c | 228 | |
hudakz | 0:b599e748252c | 229 | // Get payload length (see datasheet page 43) |
hudakz | 0:b599e748252c | 230 | packet->payload.len = (status[1] << 8) | status[0]; |
hudakz | 0:b599e748252c | 231 | |
hudakz | 0:b599e748252c | 232 | // Remove CRC bytes |
hudakz | 0:b599e748252c | 233 | packet->payload.len -= RX_CRC_LEN; |
hudakz | 0:b599e748252c | 234 | |
hudakz | 0:b599e748252c | 235 | // Check CRC and symbol errors (see datasheet page 44, table 7-3): |
hudakz | 0:b599e748252c | 236 | // The ERXFCON.CRCEN is set by default. Normally we should not |
hudakz | 0:b599e748252c | 237 | // need to check this. |
hudakz | 0:b599e748252c | 238 | // Bit 7 in byte 3 of receive status vectors indicates that the packet |
hudakz | 0:b599e748252c | 239 | // had a valid CRC and no symbol errors. |
hudakz | 0:b599e748252c | 240 | if ((status[2] & (1 << 7)) != 0) { |
hudakz | 0:b599e748252c | 241 | ret = ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 242 | } |
hudakz | 0:b599e748252c | 243 | else { |
hudakz | 0:b599e748252c | 244 | // Drop faulty packet: |
hudakz | 0:b599e748252c | 245 | // Move the receive read pointer to the begin of the next packet. |
hudakz | 0:b599e748252c | 246 | // This frees the memory we just read out. |
hudakz | 0:b599e748252c | 247 | freeRxBuffer(); |
hudakz | 0:b599e748252c | 248 | ret = ENC28J60_ERROR_RECEIVE; |
hudakz | 0:b599e748252c | 249 | } |
hudakz | 0:b599e748252c | 250 | |
hudakz | 0:b599e748252c | 251 | // Decrement the packet counter to indicate we are done with this packet. |
hudakz | 0:b599e748252c | 252 | writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); |
hudakz | 0:b599e748252c | 253 | |
hudakz | 0:b599e748252c | 254 | return ret; |
hudakz | 0:b599e748252c | 255 | } |
hudakz | 0:b599e748252c | 256 | |
hudakz | 0:b599e748252c | 257 | /** |
hudakz | 0:b599e748252c | 258 | * @brief |
hudakz | 0:b599e748252c | 259 | * @note |
hudakz | 0:b599e748252c | 260 | * @param |
hudakz | 0:b599e748252c | 261 | * @retval |
hudakz | 0:b599e748252c | 262 | */ |
hudakz | 0:b599e748252c | 263 | void ENC28J60::readPacket(packet_t* packet) |
hudakz | 0:b599e748252c | 264 | { |
hudakz | 0:b599e748252c | 265 | // Read operation in receive buffer wraps the read pointer automatically. |
hudakz | 0:b599e748252c | 266 | // To utilize this feature we program the receive buffer read pointer (ERDPTL) |
hudakz | 0:b599e748252c | 267 | // to point to the begin of this packet (see datasheet page 43). |
hudakz | 0:b599e748252c | 268 | // Then we read the next packet pointer bytes + packet status vector bytes |
hudakz | 0:b599e748252c | 269 | // rather than calculating the payload position and advancing ERDPTL by software. |
hudakz | 0:b599e748252c | 270 | writeRegPair(ERDPTL, packet->addr); |
hudakz | 0:b599e748252c | 271 | |
hudakz | 0:b599e748252c | 272 | // Advance the read pointer to the payload by reading bytes out of interest. |
hudakz | 0:b599e748252c | 273 | for (uint8_t i = 0; i < (RX_NEXT_LEN + RX_STAT_LEN); i++) |
hudakz | 0:b599e748252c | 274 | readOp(ENC28J60_READ_BUF_MEM, 0); |
hudakz | 0:b599e748252c | 275 | |
hudakz | 0:b599e748252c | 276 | // The receive buffer read pointer is now pointing to the correct place. |
hudakz | 0:b599e748252c | 277 | // We can read packet payload bytes. |
hudakz | 0:b599e748252c | 278 | readBuf(packet->payload.buf, packet->payload.len); |
hudakz | 0:b599e748252c | 279 | } |
hudakz | 0:b599e748252c | 280 | |
hudakz | 0:b599e748252c | 281 | /** |
hudakz | 0:b599e748252c | 282 | * @brief Frees the memory occupied by last packet. |
hudakz | 0:b599e748252c | 283 | * @note Programs the Receive Pointer (ERXRDPT)to point to the next |
hudakz | 0:b599e748252c | 284 | * packet address. Receive hardware will write data up to, |
hudakz | 0:b599e748252c | 285 | * but not including the memory pointed to by ERXRDPT. |
hudakz | 0:b599e748252c | 286 | * @param |
hudakz | 0:b599e748252c | 287 | * @retval |
hudakz | 0:b599e748252c | 288 | */ |
hudakz | 0:b599e748252c | 289 | void ENC28J60::freeRxBuffer(void) |
hudakz | 0:b599e748252c | 290 | { |
hudakz | 0:b599e748252c | 291 | // Compensate for the errata rev B7, point 11: |
hudakz | 0:b599e748252c | 292 | // The receive hardware may corrupt the circular |
hudakz | 0:b599e748252c | 293 | // receive buffer (including the Next Packet Pointer |
hudakz | 0:b599e748252c | 294 | // and receive status vector fields) when an even value |
hudakz | 0:b599e748252c | 295 | // is programmed into the ERXRDPTH:ERXRDPTL registers. |
hudakz | 0:b599e748252c | 296 | // Workaround: Never write an even address! |
hudakz | 0:b599e748252c | 297 | if ((_next - 1 < ERXST_INI) || (_next - 1 > ERXND_INI)) |
hudakz | 0:b599e748252c | 298 | writeRegPair(ERXRDPTL, ERXND_INI); |
hudakz | 0:b599e748252c | 299 | else |
hudakz | 0:b599e748252c | 300 | writeRegPair(ERXRDPTL, _next - 1); |
hudakz | 0:b599e748252c | 301 | |
hudakz | 0:b599e748252c | 302 | _ready = true; // ready for next packet |
hudakz | 0:b599e748252c | 303 | } |
hudakz | 0:b599e748252c | 304 | |
hudakz | 0:b599e748252c | 305 | /** |
hudakz | 0:b599e748252c | 306 | * @brief |
hudakz | 0:b599e748252c | 307 | * @note |
hudakz | 0:b599e748252c | 308 | * @param |
hudakz | 0:b599e748252c | 309 | * @retval |
hudakz | 0:b599e748252c | 310 | */ |
hudakz | 0:b599e748252c | 311 | enc28j60_error_t ENC28J60::loadPacketInTxBuffer(packet_t* packet) |
hudakz | 0:b599e748252c | 312 | { |
hudakz | 0:b599e748252c | 313 | uint8_t controlByte = 0; |
hudakz | 0:b599e748252c | 314 | enc28j60_error_t error = ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 315 | uint16_t packetLen = TX_CTRL_LEN + packet->payload.len + TX_STAT_LEN; |
hudakz | 0:b599e748252c | 316 | |
hudakz | 0:b599e748252c | 317 | if (packetLen > ETXND_INI - ETXST_INI) { |
hudakz | 0:b599e748252c | 318 | error = ENC28J60_ERROR_FIFOFULL; |
hudakz | 0:b599e748252c | 319 | return error; |
hudakz | 0:b599e748252c | 320 | } |
hudakz | 0:b599e748252c | 321 | |
hudakz | 0:b599e748252c | 322 | setWritePrt(ETXST_INI, 0); |
hudakz | 0:b599e748252c | 323 | |
hudakz | 0:b599e748252c | 324 | //_tx_packet.payload.len = data_len; |
hudakz | 0:b599e748252c | 325 | writeBuf(&controlByte, sizeof(controlByte)); |
hudakz | 0:b599e748252c | 326 | error = setWritePrt(ETXST_INI, sizeof(controlByte)); |
hudakz | 0:b599e748252c | 327 | writeBuf(packet->payload.buf, packet->payload.len); |
hudakz | 0:b599e748252c | 328 | |
hudakz | 0:b599e748252c | 329 | return error; |
hudakz | 0:b599e748252c | 330 | } |
hudakz | 0:b599e748252c | 331 | |
hudakz | 0:b599e748252c | 332 | /** |
hudakz | 0:b599e748252c | 333 | * @brief |
hudakz | 0:b599e748252c | 334 | * @note |
hudakz | 0:b599e748252c | 335 | * @param |
hudakz | 0:b599e748252c | 336 | * @retval |
hudakz | 0:b599e748252c | 337 | */ |
hudakz | 0:b599e748252c | 338 | enc28j60_error_t ENC28J60::softReset(void) |
hudakz | 0:b599e748252c | 339 | { |
hudakz | 0:b599e748252c | 340 | writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); |
hudakz | 0:b599e748252c | 341 | |
hudakz | 0:b599e748252c | 342 | ThisThread::sleep_for(1ms); |
hudakz | 0:b599e748252c | 343 | return ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 344 | } |
hudakz | 0:b599e748252c | 345 | |
hudakz | 0:b599e748252c | 346 | /** |
hudakz | 0:b599e748252c | 347 | * @brief |
hudakz | 0:b599e748252c | 348 | * @note |
hudakz | 0:b599e748252c | 349 | * @param |
hudakz | 0:b599e748252c | 350 | * @retval |
hudakz | 0:b599e748252c | 351 | */ |
hudakz | 0:b599e748252c | 352 | void ENC28J60::setRxBufSize(uint32_t size_kb) |
hudakz | 0:b599e748252c | 353 | { |
hudakz | 0:b599e748252c | 354 | if (size_kb >= HW_CFG_REG_RX_FIFO_SIZE_MIN && size_kb <= HW_CFG_REG_RX_FIFO_SIZE_MAX) { |
hudakz | 0:b599e748252c | 355 | writeRegPair(ERXSTL, ERXST_INI); |
hudakz | 0:b599e748252c | 356 | |
hudakz | 0:b599e748252c | 357 | // set receive pointer address |
hudakz | 0:b599e748252c | 358 | writeRegPair(ERXRDPTL, ERXST_INI); |
hudakz | 0:b599e748252c | 359 | |
hudakz | 0:b599e748252c | 360 | // RX end |
hudakz | 0:b599e748252c | 361 | writeRegPair(ERXNDL, 0x1FFF - (size_kb << HW_CFG_REG_RX_FIFO_POS)); |
hudakz | 0:b599e748252c | 362 | } |
hudakz | 0:b599e748252c | 363 | } |
hudakz | 0:b599e748252c | 364 | |
hudakz | 0:b599e748252c | 365 | /** |
hudakz | 0:b599e748252c | 366 | * @brief |
hudakz | 0:b599e748252c | 367 | * @note |
hudakz | 0:b599e748252c | 368 | * @param |
hudakz | 0:b599e748252c | 369 | * @retval |
hudakz | 0:b599e748252c | 370 | */ |
hudakz | 0:b599e748252c | 371 | enc28j60_error_t ENC28J60::resetPhy(void) |
hudakz | 0:b599e748252c | 372 | { |
hudakz | 0:b599e748252c | 373 | enc28j60_error_t error = ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 374 | uint16_t phcon1 = 0; |
hudakz | 0:b599e748252c | 375 | error = phyRead(PHCON1, &phcon1); |
hudakz | 0:b599e748252c | 376 | if (error) |
hudakz | 0:b599e748252c | 377 | return ENC28J60_ERROR_TIMEOUT; |
hudakz | 0:b599e748252c | 378 | error = phyWrite(PHCON1, (phcon1 | PHCON1_PRST)); |
hudakz | 0:b599e748252c | 379 | if (error) |
hudakz | 0:b599e748252c | 380 | return ENC28J60_ERROR_TIMEOUT; |
hudakz | 0:b599e748252c | 381 | ThisThread::sleep_for(PHY_RESET_TIME_OUT_MS); |
hudakz | 0:b599e748252c | 382 | error = phyRead(PHCON1, &phcon1); |
hudakz | 0:b599e748252c | 383 | if (error || (phcon1 & PHCON1_PRST) != 0) { |
hudakz | 0:b599e748252c | 384 | return ENC28J60_ERROR_TIMEOUT; |
hudakz | 0:b599e748252c | 385 | } |
hudakz | 0:b599e748252c | 386 | |
hudakz | 0:b599e748252c | 387 | return ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 388 | } |
hudakz | 0:b599e748252c | 389 | |
hudakz | 0:b599e748252c | 390 | /** |
hudakz | 0:b599e748252c | 391 | * @brief |
hudakz | 0:b599e748252c | 392 | * @note |
hudakz | 0:b599e748252c | 393 | * @param |
hudakz | 0:b599e748252c | 394 | * @retval |
hudakz | 0:b599e748252c | 395 | */ |
hudakz | 0:b599e748252c | 396 | void ENC28J60::enableMacRecv(void) |
hudakz | 0:b599e748252c | 397 | { |
hudakz | 0:b599e748252c | 398 | writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); |
hudakz | 0:b599e748252c | 399 | } |
hudakz | 0:b599e748252c | 400 | |
hudakz | 0:b599e748252c | 401 | /** |
hudakz | 0:b599e748252c | 402 | * @brief |
hudakz | 0:b599e748252c | 403 | * @note |
hudakz | 0:b599e748252c | 404 | * @param |
hudakz | 0:b599e748252c | 405 | * @retval |
hudakz | 0:b599e748252c | 406 | */ |
hudakz | 0:b599e748252c | 407 | void ENC28J60::disableMacRecv(void) |
hudakz | 0:b599e748252c | 408 | { |
hudakz | 0:b599e748252c | 409 | writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN); |
hudakz | 0:b599e748252c | 410 | } |
hudakz | 0:b599e748252c | 411 | |
hudakz | 0:b599e748252c | 412 | /** |
hudakz | 0:b599e748252c | 413 | * @brief |
hudakz | 0:b599e748252c | 414 | * @note |
hudakz | 0:b599e748252c | 415 | * @param |
hudakz | 0:b599e748252c | 416 | * @retval |
hudakz | 0:b599e748252c | 417 | */ |
hudakz | 0:b599e748252c | 418 | enc28j60_error_t ENC28J60::readMacAddr(char* mac) |
hudakz | 0:b599e748252c | 419 | { |
hudakz | 0:b599e748252c | 420 | if (!mac) { |
hudakz | 0:b599e748252c | 421 | return ENC28J60_ERROR_PARAM; |
hudakz | 0:b599e748252c | 422 | } |
hudakz | 0:b599e748252c | 423 | |
hudakz | 0:b599e748252c | 424 | _setBank(MAADR0); |
hudakz | 0:b599e748252c | 425 | |
hudakz | 0:b599e748252c | 426 | mac[0] = readReg(MAADR5); |
hudakz | 0:b599e748252c | 427 | mac[1] = readReg(MAADR4); |
hudakz | 0:b599e748252c | 428 | mac[2] = readReg(MAADR3); |
hudakz | 0:b599e748252c | 429 | mac[3] = readReg(MAADR2); |
hudakz | 0:b599e748252c | 430 | mac[4] = readReg(MAADR1); |
hudakz | 0:b599e748252c | 431 | mac[5] = readReg(MAADR0); |
hudakz | 0:b599e748252c | 432 | |
hudakz | 0:b599e748252c | 433 | return ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 434 | } |
hudakz | 0:b599e748252c | 435 | |
hudakz | 0:b599e748252c | 436 | /** |
hudakz | 0:b599e748252c | 437 | * @brief |
hudakz | 0:b599e748252c | 438 | * @note |
hudakz | 0:b599e748252c | 439 | * @param |
hudakz | 0:b599e748252c | 440 | * @retval |
hudakz | 0:b599e748252c | 441 | */ |
hudakz | 0:b599e748252c | 442 | enc28j60_error_t ENC28J60::writeMacAddr(char* mac) |
hudakz | 0:b599e748252c | 443 | { |
hudakz | 0:b599e748252c | 444 | if (!mac) { |
hudakz | 0:b599e748252c | 445 | return ENC28J60_ERROR_PARAM; |
hudakz | 0:b599e748252c | 446 | } |
hudakz | 0:b599e748252c | 447 | |
hudakz | 0:b599e748252c | 448 | _setBank(MAADR0); |
hudakz | 0:b599e748252c | 449 | |
hudakz | 0:b599e748252c | 450 | writeReg(MAADR5, mac[0]); |
hudakz | 0:b599e748252c | 451 | writeReg(MAADR4, mac[1]); |
hudakz | 0:b599e748252c | 452 | writeReg(MAADR3, mac[2]); |
hudakz | 0:b599e748252c | 453 | writeReg(MAADR2, mac[3]); |
hudakz | 0:b599e748252c | 454 | writeReg(MAADR1, mac[4]); |
hudakz | 0:b599e748252c | 455 | writeReg(MAADR0, mac[5]); |
hudakz | 0:b599e748252c | 456 | |
hudakz | 0:b599e748252c | 457 | return ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 458 | } |
hudakz | 0:b599e748252c | 459 | |
hudakz | 0:b599e748252c | 460 | /** |
hudakz | 0:b599e748252c | 461 | * @brief |
hudakz | 0:b599e748252c | 462 | * @note |
hudakz | 0:b599e748252c | 463 | * @param |
hudakz | 0:b599e748252c | 464 | * @retval |
hudakz | 0:b599e748252c | 465 | */ |
hudakz | 0:b599e748252c | 466 | enc28j60_error_t ENC28J60::setWritePrt(uint16_t position, uint16_t offset) |
hudakz | 0:b599e748252c | 467 | { |
hudakz | 0:b599e748252c | 468 | uint32_t start = position + offset > ETXND_INI ? position + offset - ETXND_INI + ETXST_INI : position + offset; |
hudakz | 0:b599e748252c | 469 | |
hudakz | 0:b599e748252c | 470 | writeRegPair(EWRPTL, start); |
hudakz | 0:b599e748252c | 471 | |
hudakz | 0:b599e748252c | 472 | return ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 473 | } |
hudakz | 0:b599e748252c | 474 | |
hudakz | 0:b599e748252c | 475 | /** |
hudakz | 0:b599e748252c | 476 | * @brief |
hudakz | 0:b599e748252c | 477 | * @note |
hudakz | 0:b599e748252c | 478 | * @param |
hudakz | 0:b599e748252c | 479 | * @retval |
hudakz | 0:b599e748252c | 480 | */ |
hudakz | 0:b599e748252c | 481 | enc28j60_error_t ENC28J60::transmitPacket(packet_t* packet) |
hudakz | 0:b599e748252c | 482 | { |
hudakz | 0:b599e748252c | 483 | // Set Transmit Buffer Start pointer |
hudakz | 0:b599e748252c | 484 | writeRegPair(ETXSTL, ETXST_INI); |
hudakz | 0:b599e748252c | 485 | |
hudakz | 0:b599e748252c | 486 | // Set Transmit Buffer End pointer |
hudakz | 0:b599e748252c | 487 | writeRegPair(ETXNDL, ETXST_INI + TX_CTRL_LEN + packet->payload.len); |
hudakz | 0:b599e748252c | 488 | |
hudakz | 0:b599e748252c | 489 | // Enable transmittion |
hudakz | 0:b599e748252c | 490 | writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); |
hudakz | 0:b599e748252c | 491 | |
hudakz | 0:b599e748252c | 492 | // Wait until transmission is completed |
hudakz | 0:b599e748252c | 493 | while ((readReg(ECON1) & ECON1_TXRTS) != 0) { } |
hudakz | 0:b599e748252c | 494 | |
hudakz | 0:b599e748252c | 495 | // Chek whether the transmission was successfull |
hudakz | 0:b599e748252c | 496 | if ((readReg(ESTAT) & ESTAT_TXABRT) == 0) |
hudakz | 0:b599e748252c | 497 | return ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 498 | else |
hudakz | 0:b599e748252c | 499 | return ENC28J60_ERROR_NEXTPACKET; |
hudakz | 0:b599e748252c | 500 | } |
hudakz | 0:b599e748252c | 501 | |
hudakz | 0:b599e748252c | 502 | |
hudakz | 0:b599e748252c | 503 | /** |
hudakz | 0:b599e748252c | 504 | * @brief |
hudakz | 0:b599e748252c | 505 | * @note |
hudakz | 0:b599e748252c | 506 | * @param |
hudakz | 0:b599e748252c | 507 | * @retval |
hudakz | 0:b599e748252c | 508 | */ |
hudakz | 0:b599e748252c | 509 | uint32_t ENC28J60::getRxBufFreeSpace(void) |
hudakz | 0:b599e748252c | 510 | { |
hudakz | 0:b599e748252c | 511 | uint16_t readPointer = getRecvPointer(); |
hudakz | 0:b599e748252c | 512 | uint16_t writePointer = getWritePointer(); |
hudakz | 0:b599e748252c | 513 | uint32_t freeSpace = 0; |
hudakz | 0:b599e748252c | 514 | if (writePointer > readPointer) { |
hudakz | 0:b599e748252c | 515 | freeSpace = (uint32_t) (ERXND_INI - ERXST_INI) - (writePointer - readPointer); |
hudakz | 0:b599e748252c | 516 | } |
hudakz | 0:b599e748252c | 517 | else |
hudakz | 0:b599e748252c | 518 | if (writePointer == readPointer) { |
hudakz | 0:b599e748252c | 519 | freeSpace = (ERXND_INI - ERXST_INI); |
hudakz | 0:b599e748252c | 520 | } |
hudakz | 0:b599e748252c | 521 | else { |
hudakz | 0:b599e748252c | 522 | freeSpace = readPointer - writePointer - 1; |
hudakz | 0:b599e748252c | 523 | } |
hudakz | 0:b599e748252c | 524 | |
hudakz | 0:b599e748252c | 525 | return freeSpace; |
hudakz | 0:b599e748252c | 526 | } |
hudakz | 0:b599e748252c | 527 | |
hudakz | 0:b599e748252c | 528 | /** |
hudakz | 0:b599e748252c | 529 | * @brief Sets Ethernet buffer read pointer |
hudakz | 0:b599e748252c | 530 | * @note Points to a location in receive buffer to read from. |
hudakz | 0:b599e748252c | 531 | * @param |
hudakz | 0:b599e748252c | 532 | * @retval |
hudakz | 0:b599e748252c | 533 | */ |
hudakz | 0:b599e748252c | 534 | enc28j60_error_t ENC28J60::setRxBufReadPtr(uint16_t position) |
hudakz | 0:b599e748252c | 535 | { |
hudakz | 0:b599e748252c | 536 | // |
hudakz | 0:b599e748252c | 537 | // Wrap the start pointer of received data when greater than end of receive buffer |
hudakz | 0:b599e748252c | 538 | if (position > ERXND_INI) |
hudakz | 0:b599e748252c | 539 | position = ERXST_INI + (position - ERXND_INI - 1); |
hudakz | 0:b599e748252c | 540 | |
hudakz | 0:b599e748252c | 541 | writeRegPair(ERDPTL, position); |
hudakz | 0:b599e748252c | 542 | |
hudakz | 0:b599e748252c | 543 | return ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 544 | } |
hudakz | 0:b599e748252c | 545 | |
hudakz | 0:b599e748252c | 546 | /** |
hudakz | 0:b599e748252c | 547 | * @brief Sets receive pointer. |
hudakz | 0:b599e748252c | 548 | * @note Receive hardware will write received data up to, but not including |
hudakz | 0:b599e748252c | 549 | * the memory pointed to by the receive pointer. |
hudakz | 0:b599e748252c | 550 | * @param |
hudakz | 0:b599e748252c | 551 | * @retval |
hudakz | 0:b599e748252c | 552 | */ |
hudakz | 0:b599e748252c | 553 | uint16_t ENC28J60::getRecvPointer(void) |
hudakz | 0:b599e748252c | 554 | { |
hudakz | 0:b599e748252c | 555 | return readRegPair(ERXRDPTL); |
hudakz | 0:b599e748252c | 556 | } |
hudakz | 0:b599e748252c | 557 | |
hudakz | 0:b599e748252c | 558 | /** |
hudakz | 0:b599e748252c | 559 | * @brief Gets receive buffer's write pointer. |
hudakz | 0:b599e748252c | 560 | * @note Location within the receive buffer where the hardware will write bytes that it receives. |
hudakz | 0:b599e748252c | 561 | * The pointer is read-only and is automatically updated by the hardware whenever |
hudakz | 0:b599e748252c | 562 | * a new packet is successfully received. |
hudakz | 0:b599e748252c | 563 | * @param |
hudakz | 0:b599e748252c | 564 | * @retval |
hudakz | 0:b599e748252c | 565 | */ |
hudakz | 0:b599e748252c | 566 | uint16_t ENC28J60::getWritePointer(void) |
hudakz | 0:b599e748252c | 567 | { |
hudakz | 0:b599e748252c | 568 | uint16_t count_pre = readReg(EPKTCNT); |
hudakz | 0:b599e748252c | 569 | uint16_t writePointer = readRegPair(ERXWRPTL); |
hudakz | 0:b599e748252c | 570 | uint16_t count_post = readReg(EPKTCNT); |
hudakz | 0:b599e748252c | 571 | while (count_pre != count_post) { |
hudakz | 0:b599e748252c | 572 | count_pre = count_post; |
hudakz | 0:b599e748252c | 573 | writePointer = readRegPair(ERXWRPTL); |
hudakz | 0:b599e748252c | 574 | count_post = readReg(EPKTCNT); |
hudakz | 0:b599e748252c | 575 | } |
hudakz | 0:b599e748252c | 576 | |
hudakz | 0:b599e748252c | 577 | ENC28J60_DEBUG_PRINTF("[ENC28J60] rx_getWritePointer: %d", writePointer); |
hudakz | 0:b599e748252c | 578 | return writePointer; |
hudakz | 0:b599e748252c | 579 | } |
hudakz | 0:b599e748252c | 580 | |
hudakz | 0:b599e748252c | 581 | /** |
hudakz | 0:b599e748252c | 582 | * @brief |
hudakz | 0:b599e748252c | 583 | * @note |
hudakz | 0:b599e748252c | 584 | * @param |
hudakz | 0:b599e748252c | 585 | * @retval |
hudakz | 0:b599e748252c | 586 | */ |
hudakz | 0:b599e748252c | 587 | void ENC28J60::readBuf(uint8_t* data, uint16_t len) |
hudakz | 0:b599e748252c | 588 | { |
hudakz | 0:b599e748252c | 589 | _read(ENC28J60_READ_BUF_MEM, data, len, false); |
hudakz | 0:b599e748252c | 590 | data[len] = '\0'; |
hudakz | 0:b599e748252c | 591 | } |
hudakz | 0:b599e748252c | 592 | |
hudakz | 0:b599e748252c | 593 | /** |
hudakz | 0:b599e748252c | 594 | * @brief |
hudakz | 0:b599e748252c | 595 | * @note |
hudakz | 0:b599e748252c | 596 | * @param |
hudakz | 0:b599e748252c | 597 | * @retval |
hudakz | 0:b599e748252c | 598 | */ |
hudakz | 0:b599e748252c | 599 | void ENC28J60::writeBuf(uint8_t* data, uint16_t len) |
hudakz | 0:b599e748252c | 600 | { |
hudakz | 0:b599e748252c | 601 | _write(ENC28J60_WRITE_BUF_MEM, data, len, false); |
hudakz | 0:b599e748252c | 602 | } |
hudakz | 0:b599e748252c | 603 | |
hudakz | 0:b599e748252c | 604 | /** |
hudakz | 0:b599e748252c | 605 | * @brief |
hudakz | 0:b599e748252c | 606 | * @note |
hudakz | 0:b599e748252c | 607 | * @param |
hudakz | 0:b599e748252c | 608 | * @retval |
hudakz | 0:b599e748252c | 609 | */ |
hudakz | 0:b599e748252c | 610 | uint8_t ENC28J60::readReg(uint8_t address) |
hudakz | 0:b599e748252c | 611 | { |
hudakz | 0:b599e748252c | 612 | _setBank(address); |
hudakz | 0:b599e748252c | 613 | |
hudakz | 0:b599e748252c | 614 | // do the read |
hudakz | 0:b599e748252c | 615 | return readOp(ENC28J60_READ_CTRL_REG, address); |
hudakz | 0:b599e748252c | 616 | } |
hudakz | 0:b599e748252c | 617 | |
hudakz | 0:b599e748252c | 618 | /** |
hudakz | 0:b599e748252c | 619 | * @brief |
hudakz | 0:b599e748252c | 620 | * @note |
hudakz | 0:b599e748252c | 621 | * @param |
hudakz | 0:b599e748252c | 622 | * @retval |
hudakz | 0:b599e748252c | 623 | */ |
hudakz | 0:b599e748252c | 624 | uint16_t ENC28J60::readRegPair(uint8_t address) |
hudakz | 0:b599e748252c | 625 | { |
hudakz | 0:b599e748252c | 626 | uint16_t temp; |
hudakz | 0:b599e748252c | 627 | |
hudakz | 0:b599e748252c | 628 | _setBank(address); |
hudakz | 0:b599e748252c | 629 | |
hudakz | 0:b599e748252c | 630 | // do the read |
hudakz | 0:b599e748252c | 631 | temp = (uint16_t) (readOp(ENC28J60_READ_CTRL_REG, address + 1)) << 8; |
hudakz | 0:b599e748252c | 632 | temp |= readOp(ENC28J60_READ_CTRL_REG, address); |
hudakz | 0:b599e748252c | 633 | |
hudakz | 0:b599e748252c | 634 | return temp; |
hudakz | 0:b599e748252c | 635 | } |
hudakz | 0:b599e748252c | 636 | |
hudakz | 0:b599e748252c | 637 | /** |
hudakz | 0:b599e748252c | 638 | * @brief |
hudakz | 0:b599e748252c | 639 | * @note |
hudakz | 0:b599e748252c | 640 | * @param |
hudakz | 0:b599e748252c | 641 | * @retval |
hudakz | 0:b599e748252c | 642 | */ |
hudakz | 0:b599e748252c | 643 | void ENC28J60::writeReg(uint8_t address, uint8_t data) |
hudakz | 0:b599e748252c | 644 | { |
hudakz | 0:b599e748252c | 645 | _setBank(address); |
hudakz | 0:b599e748252c | 646 | |
hudakz | 0:b599e748252c | 647 | // do the write |
hudakz | 0:b599e748252c | 648 | writeOp(ENC28J60_WRITE_CTRL_REG, address, data); |
hudakz | 0:b599e748252c | 649 | } |
hudakz | 0:b599e748252c | 650 | |
hudakz | 0:b599e748252c | 651 | /** |
hudakz | 0:b599e748252c | 652 | * @brief |
hudakz | 0:b599e748252c | 653 | * @note |
hudakz | 0:b599e748252c | 654 | * @param |
hudakz | 0:b599e748252c | 655 | * @retval |
hudakz | 0:b599e748252c | 656 | */ |
hudakz | 0:b599e748252c | 657 | void ENC28J60::writeRegPair(uint8_t address, uint16_t data) |
hudakz | 0:b599e748252c | 658 | { |
hudakz | 0:b599e748252c | 659 | _setBank(address); |
hudakz | 0:b599e748252c | 660 | |
hudakz | 0:b599e748252c | 661 | // do the write |
hudakz | 0:b599e748252c | 662 | writeOp(ENC28J60_WRITE_CTRL_REG, address, (data & 0xFF)); |
hudakz | 0:b599e748252c | 663 | writeOp(ENC28J60_WRITE_CTRL_REG, address + 1, (data) >> 8); |
hudakz | 0:b599e748252c | 664 | } |
hudakz | 0:b599e748252c | 665 | |
hudakz | 0:b599e748252c | 666 | /** |
hudakz | 0:b599e748252c | 667 | * @brief |
hudakz | 0:b599e748252c | 668 | * @note |
hudakz | 0:b599e748252c | 669 | * @param |
hudakz | 0:b599e748252c | 670 | * @retval |
hudakz | 0:b599e748252c | 671 | */ |
hudakz | 0:b599e748252c | 672 | enc28j60_error_t ENC28J60::phyRead(uint8_t address, uint16_t* data) |
hudakz | 0:b599e748252c | 673 | { |
hudakz | 0:b599e748252c | 674 | uint8_t timeout = 0; |
hudakz | 0:b599e748252c | 675 | writeReg(MIREGADR, address); |
hudakz | 0:b599e748252c | 676 | writeReg(MICMD, MICMD_MIIRD); |
hudakz | 0:b599e748252c | 677 | |
hudakz | 0:b599e748252c | 678 | // wait until the PHY read completes |
hudakz | 0:b599e748252c | 679 | while (readReg(MISTAT) & MISTAT_BUSY) { |
hudakz | 0:b599e748252c | 680 | wait_us(15); |
hudakz | 0:b599e748252c | 681 | timeout++; |
hudakz | 0:b599e748252c | 682 | if (timeout > 10) |
hudakz | 0:b599e748252c | 683 | return ENC28J60_ERROR_TIMEOUT; |
hudakz | 0:b599e748252c | 684 | } //and MIRDH |
hudakz | 0:b599e748252c | 685 | |
hudakz | 0:b599e748252c | 686 | writeReg(MICMD, 0); |
hudakz | 0:b599e748252c | 687 | *data = (readReg(MIRDL) | readReg(MIRDH) << 8); |
hudakz | 0:b599e748252c | 688 | return ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 689 | } |
hudakz | 0:b599e748252c | 690 | |
hudakz | 0:b599e748252c | 691 | /** |
hudakz | 0:b599e748252c | 692 | * @brief |
hudakz | 0:b599e748252c | 693 | * @note |
hudakz | 0:b599e748252c | 694 | * @param |
hudakz | 0:b599e748252c | 695 | * @retval |
hudakz | 0:b599e748252c | 696 | */ |
hudakz | 0:b599e748252c | 697 | enc28j60_error_t ENC28J60::phyWrite(uint8_t address, uint16_t data) |
hudakz | 0:b599e748252c | 698 | { |
hudakz | 0:b599e748252c | 699 | uint8_t timeout = 0; |
hudakz | 0:b599e748252c | 700 | // set the PHY register address |
hudakz | 0:b599e748252c | 701 | |
hudakz | 0:b599e748252c | 702 | writeReg(MIREGADR, address); |
hudakz | 0:b599e748252c | 703 | |
hudakz | 0:b599e748252c | 704 | // write the PHY data |
hudakz | 0:b599e748252c | 705 | writeRegPair(MIWRL, data); |
hudakz | 0:b599e748252c | 706 | |
hudakz | 0:b599e748252c | 707 | // wait until the PHY write completes |
hudakz | 0:b599e748252c | 708 | while (readReg(MISTAT) & MISTAT_BUSY) { |
hudakz | 0:b599e748252c | 709 | wait_us(15); |
hudakz | 0:b599e748252c | 710 | timeout++; |
hudakz | 0:b599e748252c | 711 | if (timeout > 10) |
hudakz | 0:b599e748252c | 712 | return ENC28J60_ERROR_TIMEOUT; |
hudakz | 0:b599e748252c | 713 | } |
hudakz | 0:b599e748252c | 714 | |
hudakz | 0:b599e748252c | 715 | return ENC28J60_ERROR_OK; |
hudakz | 0:b599e748252c | 716 | } |
hudakz | 0:b599e748252c | 717 | |
hudakz | 0:b599e748252c | 718 | /** |
hudakz | 0:b599e748252c | 719 | * @brief |
hudakz | 0:b599e748252c | 720 | * @note |
hudakz | 0:b599e748252c | 721 | * @param |
hudakz | 0:b599e748252c | 722 | * @retval |
hudakz | 0:b599e748252c | 723 | */ |
hudakz | 0:b599e748252c | 724 | bool ENC28J60::linkStatus(void) |
hudakz | 0:b599e748252c | 725 | { |
hudakz | 0:b599e748252c | 726 | uint16_t data; |
hudakz | 0:b599e748252c | 727 | phyRead(PHSTAT2, &data); |
hudakz | 0:b599e748252c | 728 | return(data & 0x0400) > 0; |
hudakz | 0:b599e748252c | 729 | } |
hudakz | 0:b599e748252c | 730 | |
hudakz | 0:b599e748252c | 731 | /** |
hudakz | 0:b599e748252c | 732 | * @brief |
hudakz | 0:b599e748252c | 733 | * @note |
hudakz | 0:b599e748252c | 734 | * @param |
hudakz | 0:b599e748252c | 735 | * @retval |
hudakz | 0:b599e748252c | 736 | */ |
hudakz | 0:b599e748252c | 737 | uint8_t ENC28J60::readOp(uint8_t op, uint8_t address) |
hudakz | 0:b599e748252c | 738 | { |
hudakz | 0:b599e748252c | 739 | uint8_t result; |
hudakz | 0:b599e748252c | 740 | uint8_t data[2]; |
hudakz | 0:b599e748252c | 741 | |
hudakz | 0:b599e748252c | 742 | // issue read command |
hudakz | 0:b599e748252c | 743 | |
hudakz | 0:b599e748252c | 744 | if (address & 0x80) { |
hudakz | 0:b599e748252c | 745 | _read((op | (address & ADDR_MASK)), &data[0], 2, false); |
hudakz | 0:b599e748252c | 746 | result = data[1]; |
hudakz | 0:b599e748252c | 747 | return result; |
hudakz | 0:b599e748252c | 748 | } |
hudakz | 0:b599e748252c | 749 | else { |
hudakz | 0:b599e748252c | 750 | _read((op | (address & ADDR_MASK)), &data[0], 1, false); |
hudakz | 0:b599e748252c | 751 | } |
hudakz | 0:b599e748252c | 752 | |
hudakz | 0:b599e748252c | 753 | result = data[0]; |
hudakz | 0:b599e748252c | 754 | return result; |
hudakz | 0:b599e748252c | 755 | } |
hudakz | 0:b599e748252c | 756 | |
hudakz | 0:b599e748252c | 757 | /** |
hudakz | 0:b599e748252c | 758 | * @brief |
hudakz | 0:b599e748252c | 759 | * @note |
hudakz | 0:b599e748252c | 760 | * @param |
hudakz | 0:b599e748252c | 761 | * @retval |
hudakz | 0:b599e748252c | 762 | */ |
hudakz | 0:b599e748252c | 763 | void ENC28J60::writeOp(uint8_t op, uint8_t address, uint8_t data) |
hudakz | 0:b599e748252c | 764 | { |
hudakz | 0:b599e748252c | 765 | // issue write command |
hudakz | 0:b599e748252c | 766 | |
hudakz | 0:b599e748252c | 767 | _write(op | (address & ADDR_MASK), &data, 1, false); |
hudakz | 0:b599e748252c | 768 | } |
hudakz | 0:b599e748252c | 769 | |
hudakz | 0:b599e748252c | 770 | /** |
hudakz | 0:b599e748252c | 771 | * @brief |
hudakz | 0:b599e748252c | 772 | * @note |
hudakz | 0:b599e748252c | 773 | * @param |
hudakz | 0:b599e748252c | 774 | * @retval |
hudakz | 0:b599e748252c | 775 | */ |
hudakz | 0:b599e748252c | 776 | void ENC28J60::_setBank(uint8_t address) |
hudakz | 0:b599e748252c | 777 | { |
hudakz | 0:b599e748252c | 778 | if ((address & BANK_MASK) != _bank) { |
hudakz | 0:b599e748252c | 779 | writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0)); |
hudakz | 0:b599e748252c | 780 | writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5); |
hudakz | 0:b599e748252c | 781 | _bank = (address & BANK_MASK); |
hudakz | 0:b599e748252c | 782 | } |
hudakz | 0:b599e748252c | 783 | } |
hudakz | 0:b599e748252c | 784 | |
hudakz | 0:b599e748252c | 785 | /** |
hudakz | 0:b599e748252c | 786 | * @brief |
hudakz | 0:b599e748252c | 787 | * @note |
hudakz | 0:b599e748252c | 788 | * @param |
hudakz | 0:b599e748252c | 789 | * @retval |
hudakz | 0:b599e748252c | 790 | */ |
hudakz | 0:b599e748252c | 791 | void ENC28J60::_read(uint8_t cmd, uint8_t* buf, uint16_t len, bool blocking) |
hudakz | 0:b599e748252c | 792 | { |
hudakz | 0:b599e748252c | 793 | #ifndef ENC28J60_READWRITE |
hudakz | 0:b599e748252c | 794 | _SPIMutex.lock(); |
hudakz | 0:b599e748252c | 795 | _cs = 0; |
hudakz | 0:b599e748252c | 796 | |
hudakz | 0:b599e748252c | 797 | // issue read command |
hudakz | 0:b599e748252c | 798 | _spi->write((int)cmd); |
hudakz | 0:b599e748252c | 799 | while (len) { |
hudakz | 0:b599e748252c | 800 | len--; |
hudakz | 0:b599e748252c | 801 | |
hudakz | 0:b599e748252c | 802 | // read data |
hudakz | 0:b599e748252c | 803 | *buf = _spi->write(0x00); |
hudakz | 0:b599e748252c | 804 | buf++; |
hudakz | 0:b599e748252c | 805 | } |
hudakz | 0:b599e748252c | 806 | |
hudakz | 0:b599e748252c | 807 | _cs = 1; |
hudakz | 0:b599e748252c | 808 | _SPIMutex.unlock(); |
hudakz | 0:b599e748252c | 809 | #else |
hudakz | 0:b599e748252c | 810 | uint8_t* dummy = NULL; |
hudakz | 0:b599e748252c | 811 | _readwrite(cmd, buf, dummy, len, blocking); |
hudakz | 0:b599e748252c | 812 | #endif |
hudakz | 0:b599e748252c | 813 | } |
hudakz | 0:b599e748252c | 814 | |
hudakz | 0:b599e748252c | 815 | /** |
hudakz | 0:b599e748252c | 816 | * @brief |
hudakz | 0:b599e748252c | 817 | * @note |
hudakz | 0:b599e748252c | 818 | * @param |
hudakz | 0:b599e748252c | 819 | * @retval |
hudakz | 0:b599e748252c | 820 | */ |
hudakz | 0:b599e748252c | 821 | void ENC28J60::_write(uint8_t cmd, uint8_t* buf, uint16_t len, bool blocking) |
hudakz | 0:b599e748252c | 822 | { |
hudakz | 0:b599e748252c | 823 | #ifndef ENC28J60_READWRITE |
hudakz | 0:b599e748252c | 824 | _SPIMutex.lock(); |
hudakz | 0:b599e748252c | 825 | _cs = 0; |
hudakz | 0:b599e748252c | 826 | |
hudakz | 0:b599e748252c | 827 | // issue read command |
hudakz | 0:b599e748252c | 828 | _spi->write((int)cmd); |
hudakz | 0:b599e748252c | 829 | while (len) { |
hudakz | 0:b599e748252c | 830 | len--; |
hudakz | 0:b599e748252c | 831 | |
hudakz | 0:b599e748252c | 832 | // read data |
hudakz | 0:b599e748252c | 833 | _spi->write((int) *buf); |
hudakz | 0:b599e748252c | 834 | buf++; |
hudakz | 0:b599e748252c | 835 | } |
hudakz | 0:b599e748252c | 836 | |
hudakz | 0:b599e748252c | 837 | _cs = 1; |
hudakz | 0:b599e748252c | 838 | _SPIMutex.unlock(); |
hudakz | 0:b599e748252c | 839 | #else |
hudakz | 0:b599e748252c | 840 | uint8_t* dummy = NULL; |
hudakz | 0:b599e748252c | 841 | _readwrite(cmd, dummy, buf, len, blocking); |
hudakz | 0:b599e748252c | 842 | #endif |
hudakz | 0:b599e748252c | 843 | } |
hudakz | 0:b599e748252c | 844 | |
hudakz | 0:b599e748252c | 845 | #ifdef ENC28J60_READWRITE |
hudakz | 0:b599e748252c | 846 | |
hudakz | 0:b599e748252c | 847 | /** |
hudakz | 0:b599e748252c | 848 | * @brief |
hudakz | 0:b599e748252c | 849 | * @note |
hudakz | 0:b599e748252c | 850 | * @param |
hudakz | 0:b599e748252c | 851 | * @retval |
hudakz | 0:b599e748252c | 852 | */ |
hudakz | 0:b599e748252c | 853 | void ENC28J60::_readwrite(uint8_t cmd, uint8_t* readbuf, uint8_t* writebuf, uint16_t len, bool blocking) |
hudakz | 0:b599e748252c | 854 | { |
hudakz | 0:b599e748252c | 855 | _SPIMutex.lock(); |
hudakz | 0:b599e748252c | 856 | _cs = 0; |
hudakz | 0:b599e748252c | 857 | |
hudakz | 0:b599e748252c | 858 | // issue read command |
hudakz | 0:b599e748252c | 859 | _spi->write((int)cmd); |
hudakz | 0:b599e748252c | 860 | while (len) { |
hudakz | 0:b599e748252c | 861 | len--; |
hudakz | 0:b599e748252c | 862 | |
hudakz | 0:b599e748252c | 863 | if (readbuf == NULL) { |
hudakz | 0:b599e748252c | 864 | _spi->write((int) *writebuf); |
hudakz | 0:b599e748252c | 865 | writebuf++; |
hudakz | 0:b599e748252c | 866 | } |
hudakz | 0:b599e748252c | 867 | else |
hudakz | 0:b599e748252c | 868 | if (writebuf == NULL) { |
hudakz | 0:b599e748252c | 869 | *readbuf = _spi->write(0x00); |
hudakz | 0:b599e748252c | 870 | readbuf++; |
hudakz | 0:b599e748252c | 871 | } |
hudakz | 0:b599e748252c | 872 | else { |
hudakz | 0:b599e748252c | 873 | break; |
hudakz | 0:b599e748252c | 874 | } |
hudakz | 0:b599e748252c | 875 | } |
hudakz | 0:b599e748252c | 876 | |
hudakz | 0:b599e748252c | 877 | _cs = 1; |
hudakz | 0:b599e748252c | 878 | _SPIMutex.unlock(); |
hudakz | 0:b599e748252c | 879 | } |
hudakz | 0:b599e748252c | 880 | #endif |