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