/* W5500.c - Driver for WIZnet W5500. Copyright (c) 2018 Patrick F. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with program. If not, see . */ #include "W5500.h" #include "SPI.h" #include "System32.h" #ifndef SPI_W5500 #define SPI_W5500 SPI3 #endif #define RESET_BIT 7 static inline void Write(uint16_t _addr, uint8_t _cb, uint8_t _data); static inline uint16_t WriteArray(uint16_t addr, uint8_t _cb, const uint8_t *buf, uint16_t len); static inline uint8_t Read(uint16_t addr, uint8_t _cb); static inline uint16_t ReadArray(uint16_t addr, uint8_t _cb, uint8_t *buf, uint16_t len); static inline uint8_t ReadSn(SOCKET _s, uint16_t _addr); static inline void WriteSn(SOCKET _s, uint16_t _addr, uint8_t _data); static inline uint16_t ReadSnArray(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); static inline uint16_t WriteSnArray(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); void W5500_Init(void) { Spi_Init(SPI_W5500, SPI_MODE0); // Set clock to 21 Mhz (W5500 should support up to about 80 Mhz) Spi_SetPrescaler(SPI_W5500, SPI_PRESCALER_2); GPIO_ResetBits(GPIOA, GPIO_Pin_15); Delay_ms(40); GPIO_SetBits(GPIOA, GPIO_Pin_15); Delay_ms(40); W5500_SoftReset(); Delay_ms(40); for(uint8_t i = 0; i < MAX_SOCK_NUM; i++) { uint8_t cntl_byte = (0x0C + (i<<5)); Write(0x1E, cntl_byte, 4); //0x1E - Sn_RXBUF_SIZE - 4k Write(0x1F, cntl_byte, 2); //0x1F - Sn_TXBUF_SIZE - 2k } } void W5500_SoftReset(void) { uint8_t cnt = 0; // Write reset bit W5500_WRITE_GP_REG8(REG8_MR, 1<> 8); Spi_WriteByte(SPI_W5500, _addr & 0xFF); Spi_WriteByte(SPI_W5500, _cb); Spi_WriteByte(SPI_W5500, _data); Spi_ChipSelect(SPI_W5500, false); __ASM("nop"); __ASM("nop"); } static inline uint16_t WriteArray(uint16_t _addr, uint8_t _cb, const uint8_t *_buf, uint16_t _len) { Spi_ChipSelect(SPI_W5500, true); Spi_WriteByte(SPI_W5500, _addr >> 8); Spi_WriteByte(SPI_W5500, _addr & 0xFF); Spi_WriteByte(SPI_W5500, _cb); for(uint16_t i = 0; i < _len; i++) { Spi_WriteByte(SPI_W5500, _buf[i]); } Spi_ChipSelect(SPI_W5500, false); __ASM("nop"); __ASM("nop"); return _len; } static inline uint8_t Read(uint16_t _addr, uint8_t _cb) { Spi_ChipSelect(SPI_W5500, true); Spi_WriteByte(SPI_W5500, _addr >> 8); Spi_WriteByte(SPI_W5500, _addr & 0xFF); Spi_WriteByte(SPI_W5500, _cb); uint8_t _data = Spi_ReadByte(SPI_W5500); Spi_ChipSelect(SPI_W5500, false); __ASM("nop"); __ASM("nop"); return _data; } static inline uint16_t ReadArray(uint16_t _addr, uint8_t _cb, uint8_t *_buf, uint16_t _len) { Spi_ChipSelect(SPI_W5500, true); Spi_WriteByte(SPI_W5500, _addr >> 8); Spi_WriteByte(SPI_W5500, _addr & 0xFF); Spi_WriteByte(SPI_W5500, _cb); for(uint16_t i = 0; i < _len; i++) { _buf[i] = Spi_ReadByte(SPI_W5500); } Spi_ChipSelect(SPI_W5500, false); __ASM("nop"); __ASM("nop"); return _len; } static inline uint8_t ReadSn(SOCKET _s, uint16_t _addr) { uint8_t cntl_byte = (_s<<5) + 0x08; return Read(_addr, cntl_byte); } static inline void WriteSn(SOCKET _s, uint16_t _addr, uint8_t _data) { uint8_t cntl_byte = (_s<<5) + 0x0C; Write(_addr, cntl_byte, _data); } static inline uint16_t ReadSnArray(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { uint8_t cntl_byte = (_s<<5) + 0x08; return ReadArray(_addr, cntl_byte, _buf, _len); } static inline uint16_t WriteSnArray(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { uint8_t cntl_byte = (_s<<5) + 0x0C; return WriteArray(_addr, cntl_byte, _buf, _len); } // W5500 Registers // --------------- void W5500_WRITE_GP_REG8(uint16_t address, uint8_t _data) { Write(address, 0x04, _data); } uint8_t W5500_READ_GP_REG8(uint16_t address) { return Read(address, 0x00); } void W5500_WRITE_GP_REG16(uint16_t address, uint16_t _data) { Write(address, 0x04, _data >> 8); Write(address + 1, 0x04, _data & 0xFF); } uint16_t W5500_READ_GP_REG16(uint16_t address) { uint16_t res = Read(address, 0x00); res = (res << 8) + Read(address + 1, 0x00); return res; } uint16_t W5500_WRITE_GP_REGN(uint16_t address, uint8_t *_buff, uint16_t size) { return WriteArray(address, 0x04, _buff, size); } uint16_t W5500_READ_GP_REGN(uint16_t address, uint8_t *_buff, uint16_t size) { return ReadArray(address, 0x00, _buff, size); } // W5500 Socket registers // ---------------------- void W5500_WRITE_SOCK_REG8(SOCKET _s, uint16_t address, uint8_t _data) { WriteSn(_s, address, _data); } uint8_t W5500_READ_SOCK_REG8(SOCKET _s, uint16_t address) { return ReadSn(_s, address); } void W5500_WRITE_SOCK_REG16(SOCKET _s, uint16_t address, uint16_t _data) { WriteSn(_s, address, _data >> 8); \ WriteSn(_s, address+1, _data & 0xFF); } uint16_t W5500_READ_SOCK_REG16(SOCKET _s, uint16_t address) { uint16_t res = ReadSn(_s, address); uint16_t res2 = ReadSn(_s, address + 1); res = res << 8; res2 = res2 & 0xFF; res = res | res2; return res; } uint16_t W5500_WRITE_SOCK_REGN(SOCKET _s, uint16_t address, uint8_t *_buff, uint16_t size) { return WriteSnArray(_s, address, _buff, size); } uint16_t W5500_READ_SOCK_REGN(SOCKET _s, uint16_t address, uint8_t *_buff, uint16_t size) { return ReadSnArray(_s, address, _buff, size); }