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; } ...
Diff: enc28j60_emac.h
- Revision:
- 2:19d290369c66
- Parent:
- 1:bce04bfc41fe
- Child:
- 3:aa88808326b9
--- a/enc28j60_emac.h Sat Mar 27 22:45:46 2021 +0000 +++ b/enc28j60_emac.h Sat Mar 27 22:52:41 2021 +0000 @@ -15,216 +15,173 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef ENC28J60_ETH_DRV_H_ -#define ENC28J60_ETH_DRV_H_ +#ifndef ENC28J60_EMAC_H_ +#define ENC28J60_EMAC_H_ +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> #include "mbed.h" +#include "EMAC.h" +#include "rtos.h" + #include "enc28j60_reg.h" +#include "enc28j60.h" #include "enc28j60_emac_config.h" -#define ENC28J60_READWRITE 1 - -/** - * \brief Error code definitions - * - */ -typedef struct -{ - uint8_t* buf; - uint16_t len; -} payload_t; - -typedef struct -{ - uint32_t addr; - payload_t payload; -} packet_t; - -/** - * \brief Error code definitions - * - */ -typedef enum -{ - ENC28J60_ERROR_OK = 0U, /*!< no error */ - ENC28J60_ERROR_TIMEOUT = 1U, /*!< timeout */ - ENC28J60_ERROR_BUSY = 2U, /*!< no error */ - ENC28J60_ERROR_PARAM = 3U, /*!< invalid parameter */ - ENC28J60_ERROR_INTERNAL = 4U, /*!< internal error */ - ENC28J60_ERROR_WRONG_ID = 5U, /*!< internal error */ - ENC28J60_ERROR_NOPACKET = 10U, - ENC28J60_ERROR_RECEIVE = 11U, - ENC28J60_ERROR_LASTPACKET = 12U, - ENC28J60_ERROR_POSITIONLENGTH = 13U, /*!< internal error */ - ENC28J60_ERROR_SIZE = 20U, /*!< internal error */ - ENC28J60_ERROR_FIFOFULL = 21U, /*!< internal error */ - ENC28J60_ERROR_NEXTPACKET = 22U, /*!< internal error */ -} enc28j60_error_t; - -/** - * \brief Interrupt source definitions - * - */ -typedef enum -{ - ENC28J60_INTERRUPT_ENABLE = EIE_INTIE, - ENC28J60_INTERRUPT_RX_PENDING_ENABLE= EIE_PKTIE, - ENC28J60_INTERRUPT_DMA_ENABLE = EIE_DMAIE, - ENC28J60_INTERRUPT_LINK_STATE_ENABLE= EIE_LINKIE, - ENC28J60_INTERRUPT_TX_ENABLE = EIE_TXIE, - ENC28J60_INTERRUPT_TX_ERROR_ENABLE = EIE_TXERIE, - ENC28J60_INTERRUPT_RX_ERROR_ENABLE = EIE_RXERIE -} enc28j60_interrupt_source; - -class ENC28J60 +class ENC28J60_EMAC : + public EMAC { public: - ENC28J60(PinName mosi, PinName miso, PinName sclk, PinName cs); + ENC28J60_EMAC(); + + /** Return the ENC28J60 EMAC + * + * Returns the default on-board EMAC - this will be target-specific, and + * may not be available on all targets. + */ + static ENC28J60_EMAC& get_instance(void); - ENC28J60(mbed::SPI * spi, PinName cs); + /** + * Return maximum transmission unit + * + * @return MTU in bytes + */ + virtual uint32_t get_mtu_size(void) const; + + /** + * Gets memory buffer alignment preference + * + * Gets preferred memory buffer alignment of the Emac device. IP stack may + * or may not align link out memory buffer chains using the alignment. + * + * @return Memory alignment requirement in bytes + */ + virtual uint32_t get_align_preference(void) const; /** - * \brief Initializes ENC28J60 Ethernet controller to a known default state: - * - device ID is checked - * - global interrupt is enabled, but all irq sources are disabled - * - Establish link enabled - * - Rx enabled - * - Tx enabled - * Init should be called prior to any other process and - * it's the caller's responsibility to follow proper call order. + * Return interface name * - * \return error code /ref enc28j60_error_t + * @param name Pointer to where the name should be written + * @param size Maximum number of character to copy */ - void init(void); - - /** This returns a unique 6-byte MAC address, based on the device UID - * This function overrides hal/common/mbed_interface.c function - * @param mac A 6-byte array to write the MAC address - */ - void mbed_mac_address(char* mac); - MBED_WEAK uint8_t mbed_otp_mac_address(char* mac); - void mbed_default_mac_address(char* mac); + virtual void get_ifname(char* name, uint8_t size) const; /** - * \brief Initiates a soft reset, returns failure or success. + * Returns size of the underlying interface HW address size. * - * \return error code /ref enc28j60_error_t + * @return HW address size in bytes */ - enc28j60_error_t softReset(void); + virtual uint8_t get_hwaddr_size(void) const; /** - * \brief Set maximum transition unit by Rx fifo size. - * Note: The MTU will be smaller by 512 bytes, - * because the status uses this fixed space. + * Return interface-supplied HW address + * + * Copies HW address to provided memory, @param addr has to be of correct + * size see @a get_hwaddr_size * - * \param[in] val Size of the fifo in kbytes + * HW address need not be provided if this interface does not have its own + * HW address configuration; stack will choose address from central system + * configuration if the function returns false and does not write to addr. + * + * @param addr HW address for underlying interface + * @return true if HW address is available */ - void setRxBufSize(uint32_t val); + virtual bool get_hwaddr(uint8_t* addr) const; /** - * \brief Reset PHY + * Set HW address for interface + * + * Provided address has to be of correct size, see @a get_hwaddr_size * - * \return error code /ref enc28j60_error_t + * Called to set the MAC address to actually use - if @a get_hwaddr is + * provided the stack would normally use that, but it could be overridden, + * eg for test purposes. + * + * @param addr Address to be set */ - enc28j60_error_t resetPhy(void); - - /** - * \brief Enable receive - */ - void enableMacRecv(void); - - /** - * \brief Disable receive - */ - void disableMacRecv(void); + virtual void set_hwaddr(const uint8_t* addr); /** - * \brief Read MAC address from EEPROM. + * Sends the packet over the link + * + * That can not be called from an interrupt context. * - * \param[in,out] mac array will include the read MAC address in - * 6 bytes hexadecimal format. - * It should be allocated by the caller to 6 bytes. - * - * \return error code /ref enc28j60_error_t + * @param buf Packet to be send + * @return True if the packet was send successfully, False otherwise */ - enc28j60_error_t readMacAddr(char* mac); + virtual bool link_out(emac_mem_buf_t* buf); /** - * \brief Write MAC address to EEPROM. + * Initializes the HW * - * \param[in,out] mac array will include the write MAC address in - * 6 bytes hexadecimal format. - * It should be allocated by the caller to 6 bytes. - * - * \return error code /ref enc28j60_error_t + * @return True on success, False in case of an error. */ - enc28j60_error_t writeMacAddr(char* mac); + virtual bool power_up(void); /** - * \brief Check device ID. + * Deinitializes the HW * - * \return error code /ref enc28j60_error_t */ - bool check_id(void); + virtual void power_down(void); + + /** + * Sets a callback that needs to be called for packets received for that + * interface + * + * @param input_cb Function to be register as a callback + */ + virtual void set_link_input_cb(emac_link_input_cb_t input_cb); /** - * \brief Get the data size of the Rx buffer, aka Maximum Transition Unit + * Sets a callback that needs to be called on link status changes for given + * interface * - * \return Fifo data size in bytes + * @param state_cb Function to be register as a callback */ - enc28j60_error_t setWritePrt(uint16_t position, uint16_t offset); - enc28j60_error_t transmitPacket(packet_t* packet); - enc28j60_error_t loadPacketInTxBuffer(packet_t* packet); + virtual void set_link_state_cb(emac_link_state_change_cb_t state_cb); - /** - * \brief Get the free space of Rx fifo in bytes. - * - * \param[in] dev Ethernet device structure \ref enc28j60_eth_dev_t + /** Add device to a multicast group * - * \return Space available to store received data in bytes + * @param address A multicast group hardware address */ - uint32_t getRxBufFreeSpace(void); + virtual void add_multicast_group(const uint8_t* address); - /** - * \brief Get the size of next unread packet in Rx buffer, using the peak - * register, which is not destructive so can be read asynchronously. - * Warning: In case of heavy receiving load, it's possible this register - * is not perfectly in sync. + /** Remove device from a multicast group * - * \param[in] dev Ethernet device structure \ref enc28j60_eth_dev_t + * @param address A multicast group hardware address + */ + virtual void remove_multicast_group(const uint8_t* address); + + /** Request reception of all multicast packets * - * \return Size in bytes of the next packet can be read from Rx fifo, according - * to the peek register. + * @param all True to receive all multicasts + * False to receive only multicasts addressed to specified groups */ - enc28j60_error_t setRxBufReadPtr(uint16_t position); - enc28j60_error_t getPacketInfo(packet_t* packet); - void readPacket(packet_t* packet); - void freeRxBuffer(void); - uint16_t getRecvPointer(void); - uint16_t getWritePointer(void); - void readBuf(uint8_t* data, uint16_t len); - void writeBuf(uint8_t* data, uint16_t len); - uint8_t readReg(uint8_t address); - uint16_t readRegPair(uint8_t address); - void writeReg(uint8_t address, uint8_t data); - void writeRegPair(uint8_t address, uint16_t data); - enc28j60_error_t phyRead(uint8_t address, uint16_t* data); - enc28j60_error_t phyWrite(uint8_t address, uint16_t data); - bool linkStatus(void); - uint8_t readOp(uint8_t op, uint8_t address); - void writeOp(uint8_t op, uint8_t address, uint8_t data); + virtual void set_all_multicast(bool all); + + /** Sets memory manager that is used to handle memory buffers + * + * @param mem_mngr Pointer to memory manager + */ + virtual void set_memory_manager(EMACMemoryManager& mem_mngr); private: - void _setBank(uint8_t address); - void _read(uint8_t cmd, uint8_t* buf, uint16_t len, bool blocking); - void _write(uint8_t cmd, uint8_t* buf, uint16_t len, bool blocking); -#ifdef ENC28J60_READWRITE - void _readwrite(uint8_t cmd, uint8_t* readbuf, uint8_t* writebuf, uint16_t len, bool blocking); -#endif - SPI* _spi; - Mutex _SPIMutex; - DigitalOut _cs; - uint8_t _bank; - bool _ready; - uint32_t _next; + void link_status_task(); + void receive_task(); + bool low_level_init_successful(); + emac_mem_buf_t* low_level_input(); + + ENC28J60* _enc28j60; + bool _prev_link_status_up; + int _link_status_task_handle; + int _receive_task_handle; + EMACMemoryManager* _memory_manager; + Mutex _ethLockMutex; + uint8_t _hwaddr[ENC28J60_HWADDR_SIZE]; + + emac_link_input_cb_t _emac_link_input_cb; + emac_link_state_change_cb_t _emac_link_state_cb; }; -#endif /* ENC28J60_ETH_DRV_H_ */ +#endif /* ENC28J60_EMAC_H_ */