From a8b9423daad24a1f98939b7f035a1341d6266ca8 Mon Sep 17 00:00:00 2001 From: Martin Ger Date: Wed, 4 Apr 2018 23:00:38 +0200 Subject: [PATCH] fix in MAC read, initial ENC28J60 support --- driver/spi.c | 343 ++++++++++++++++++++++++++++++++++ firmware/0x00000.bin | Bin 37664 -> 37664 bytes firmware/0x10000.bin | Bin 266116 -> 266324 bytes firmware/sha1sums | 4 +- include/driver/spi.h | 79 ++++++++ include/driver/spi_register.h | 278 +++++++++++++++++++++++++++ include/lwip/netif/espenc.h | 253 +++++++++++++++++++++++++ user/user_config.h | 9 +- user/user_main.c | 26 ++- 9 files changed, 979 insertions(+), 13 deletions(-) create mode 100644 driver/spi.c create mode 100755 include/driver/spi.h create mode 100755 include/driver/spi_register.h create mode 100644 include/lwip/netif/espenc.h diff --git a/driver/spi.c b/driver/spi.c new file mode 100644 index 0000000..271d7b6 --- /dev/null +++ b/driver/spi.c @@ -0,0 +1,343 @@ +/* +* The MIT License (MIT) +* +* Copyright (c) 2015 David Ogilvy (MetalPhreak) +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + + +#include "driver/spi.h" + + +//////////////////////////////////////////////////////////////////////////////// +// +// Function Name: spi_init +// Description: Wrapper to setup HSPI/SPI GPIO pins and default SPI clock +// Parameters: spi_no - SPI (0) or HSPI (1) +// +//////////////////////////////////////////////////////////////////////////////// + +void spi_init(uint8 spi_no){ + + if(spi_no > 1) return; //Only SPI and HSPI are valid spi modules. + + spi_init_gpio(spi_no, SPI_CLK_USE_DIV); + spi_clock(spi_no, SPI_CLK_PREDIV, SPI_CLK_CNTDIV); + spi_tx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW); + spi_rx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW); + + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD); + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE); + +} + +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// +// Function Name: spi_mode +// Description: Configures SPI mode parameters for clock edge and clock polarity. +// Parameters: spi_no - SPI (0) or HSPI (1) +// spi_cpha - (0) Data is valid on clock leading edge +// (1) Data is valid on clock trailing edge +// spi_cpol - (0) Clock is low when inactive +// (1) Clock is high when inactive +// +//////////////////////////////////////////////////////////////////////////////// + +void spi_mode(uint8 spi_no, uint8 spi_cpha,uint8 spi_cpol){ + if(!spi_cpha == !spi_cpol) { + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE); + } else { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE); + } + + if (spi_cpol) { + SET_PERI_REG_MASK(SPI_PIN(spi_no), SPI_IDLE_EDGE); + } else { + CLEAR_PERI_REG_MASK(SPI_PIN(spi_no), SPI_IDLE_EDGE); + } +} + + +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// +// Function Name: spi_init_gpio +// Description: Initialises the GPIO pins for use as SPI pins. +// Parameters: spi_no - SPI (0) or HSPI (1) +// sysclk_as_spiclk - SPI_CLK_80MHZ_NODIV (1) if using 80MHz +// sysclock for SPI clock. +// SPI_CLK_USE_DIV (0) if using divider to +// get lower SPI clock speed. +// +//////////////////////////////////////////////////////////////////////////////// + +void spi_init_gpio(uint8 spi_no, uint8 sysclk_as_spiclk){ + +// if(spi_no > 1) return; //Not required. Valid spi_no is checked with if/elif below. + + uint32 clock_div_flag = 0; + if(sysclk_as_spiclk){ + clock_div_flag = 0x0001; + } + + if(spi_no==SPI){ + WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005|(clock_div_flag<<8)); //Set bit 8 if 80MHz sysclock required + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1); + }else if(spi_no==HSPI){ + WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105|(clock_div_flag<<9)); //Set bit 9 if 80MHz sysclock required + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); //GPIO12 is HSPI MISO pin (Master Data In) + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); //GPIO13 is HSPI MOSI pin (Master Data Out) + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); //GPIO14 is HSPI CLK pin (Clock) + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2); //GPIO15 is HSPI CS pin (Chip Select / Slave Select) + } + +} + +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// +// Function Name: spi_clock +// Description: sets up the control registers for the SPI clock +// Parameters: spi_no - SPI (0) or HSPI (1) +// prediv - predivider value (actual division value) +// cntdiv - postdivider value (actual division value) +// Set either divider to 0 to disable all division (80MHz sysclock) +// +//////////////////////////////////////////////////////////////////////////////// + +void spi_clock(uint8 spi_no, uint16 prediv, uint8 cntdiv){ + + if(spi_no > 1) return; + + if((prediv==0)|(cntdiv==0)){ + + WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK); + + } else { + + WRITE_PERI_REG(SPI_CLOCK(spi_no), + (((prediv-1)&SPI_CLKDIV_PRE)<>1)&SPI_CLKCNT_H)< 1) return; + + if(byte_order){ + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER); + } +} +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// +// Function Name: spi_rx_byte_order +// Description: Setup the byte order for shifting data into buffer +// Parameters: spi_no - SPI (0) or HSPI (1) +// byte_order - SPI_BYTE_ORDER_HIGH_TO_LOW (1) +// Data is read in starting with Bit31 and down to Bit0 +// +// SPI_BYTE_ORDER_LOW_TO_HIGH (0) +// Data is read in starting with the lowest BYTE, from +// MSB to LSB, followed by the second lowest BYTE, from +// MSB to LSB, followed by the second highest BYTE, from +// MSB to LSB, followed by the highest BYTE, from MSB to LSB +// 0xABCDEFGH would be read as 0xGHEFCDAB +// +// +//////////////////////////////////////////////////////////////////////////////// + +void spi_rx_byte_order(uint8 spi_no, uint8 byte_order){ + + if(spi_no > 1) return; + + if(byte_order){ + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER); + } +} +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// +// Function Name: spi_transaction +// Description: SPI transaction function +// Parameters: spi_no - SPI (0) or HSPI (1) +// cmd_bits - actual number of bits to transmit +// cmd_data - command data +// addr_bits - actual number of bits to transmit +// addr_data - address data +// dout_bits - actual number of bits to transmit +// dout_data - output data +// din_bits - actual number of bits to receive +// +// Returns: read data - uint32 containing read in data only if RX was set +// 0 - something went wrong (or actual read data was 0) +// 1 - data sent ok (or actual read data is 1) +// Note: all data is assumed to be stored in the lower bits of +// the data variables (for anything <32 bits). +// +//////////////////////////////////////////////////////////////////////////////// + +uint32 spi_transaction(uint8 spi_no, uint8 cmd_bits, uint16 cmd_data, uint32 addr_bits, uint32 addr_data, uint32 dout_bits, uint32 dout_data, + uint32 din_bits, uint32 dummy_bits){ + + if(spi_no > 1) return 0; //Check for a valid SPI + + //code for custom Chip Select as GPIO PIN here + + while(spi_busy(spi_no)); //wait for SPI to be ready + +//########## Enable SPI Functions ##########// + //disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set. + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_MISO|SPI_USR_COMMAND|SPI_USR_ADDR|SPI_USR_DUMMY); + + //enable functions based on number of bits. 0 bits = disabled. + //This is rather inefficient but allows for a very generic function. + //CMD ADDR and MOSI are set below to save on an extra if statement. +// if(cmd_bits) {SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND);} +// if(addr_bits) {SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR);} + if(din_bits) {SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO);} + if(dummy_bits) {SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY);} +//########## END SECTION ##########// + +//########## Setup Bitlengths ##########// + WRITE_PERI_REG(SPI_USER1(spi_no), ((addr_bits-1)&SPI_USR_ADDR_BITLEN)<>8)&0xff) | ((command<<8)&0xff00); //swap byte order + WRITE_PERI_REG(SPI_USER2(spi_no), ((((cmd_bits-1)&SPI_USR_COMMAND_BITLEN)<>(32-(dout_bits - dout_extra_bits)))&dout_data)); + } else { + WRITE_PERI_REG(SPI_W0(spi_no), dout_data); + } + } + } +//########## END SECTION ##########// + +//########## Begin SPI Transaction ##########// + SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); +//########## END SECTION ##########// + +//########## Return DIN data ##########// + if(din_bits) { + while(spi_busy(spi_no)); //wait for SPI transaction to complete + + if(READ_PERI_REG(SPI_USER(spi_no))&SPI_RD_BYTE_ORDER) { + return READ_PERI_REG(SPI_W0(spi_no)) >> (32-din_bits); //Assuming data in is written to MSB. TBC + } else { + return READ_PERI_REG(SPI_W0(spi_no)); //Read in the same way as DOUT is sent. Note existing contents of SPI_W0 remain unless overwritten! + } + + return 0; //something went wrong + } +//########## END SECTION ##########// + + //Transaction completed + return 1; //success +} + +//////////////////////////////////////////////////////////////////////////////// + +/*/////////////////////////////////////////////////////////////////////////////// +// +// Function Name: func +// Description: +// Parameters: +// +//////////////////////////////////////////////////////////////////////////////// + +void func(params){ + +} + +///////////////////////////////////////////////////////////////////////////////*/ + + diff --git a/firmware/0x00000.bin b/firmware/0x00000.bin index c19e2ca1353dbb5d6a70c869791327837e17ff95..22812228c4a27f47f5cb385276638d4e06533475 100644 GIT binary patch delta 1011 zcmZwGZ%ma{90%}o&U5eGO%X*CQ;FT4=b#N07@@ek;{Ghwvd}r_v_DR9VG61D=`MMZ ziOBi`&P~?2TMVh)*~TcH;(pqn7Zz)@gbeQrtsyotUVxIL;Z{1kx9>Brs~5fa?EC$l zv-9lPdG;haRiaaMpI3pAi<)L7c|i3mVzd9_Z#}3yjPjK`ptW zNx-ZtJg_h&OP{~4sV$I>bU+z;7F42F`qPo&aZO*Mw;^44v?~=U88@ki^H&RRJe-P* zjA8*J-4S#LZ&LW#u4%#&Kt3&iLUWd2mvn9KD zzCBYtlDvZ#6QVi~1h{xo7P1TLwdiqPt)t#0e6h&!%N}!e$r0JhyO&01E4pibsrXP; z-{po#g-`nU+*4l#)w%+1sJe-ZN%NkyF9u~6_ic2htL8M{+?MT^XZY_|7Fz+51+=Ty z6xKcM_Z@dA$$RS-TXL8`*nLz6vTixFdCF8o>s5Tpd>SqCPyFT3s2PtItHaaG0{2*M zTORIBXc~1i#eKN)Ihg125AHiMAgqnP4s~pWDx9+lXrfwB5?UJ^+F+T${wCRMTJ}G7z->=O-h^g|L)j^t zo&YaB4*YrY9&cU>&*BTb1YY(*c_zL7e_qG>tN+>a&bk delta 1011 zcmZwFVQ5ul7zgn8eeXSoYu>Fb*EZc8w{u=|P1~le#1*?wI70Cj7Ya>3=me`da`$v$ zGpKFXTEa?d^cKW4xzrfT4{1Cm2GfQ_OoeUbQYK`JzHGE?XvEAq>wnmV{LqIV|Nry6 z=N`D{oa}(g4ycnO%1(}H%8c=-x~SCDW$v@m%9^{ZNtnXOZdqVniM*Bk)3 z>H+!-8zGv?L4b!lMUkc0??Vss7M)UZmcM$?wd9cbam{yBkGjq&cqF=GCsFHvoj(id|{irRGsnp#-4mjmhwL@t`6CrSViN_rmE#B ztNFM~b==mnI)o?w@%|&y_HMZ}eA6_f+SU9`b2?RRCFfn*Y-Un5YG{dB;eAs4cNw1P z0+z0(`H&{P4092G?;Vo%Ui{Hv$Lva1$*Ac`uff;xWxB@Ne8r^%&!pp_@SjKgxcQ>p z|izQa6~ z+x?F8ArI%}+}6247XI|BOJ%c*9tyfS+x5$y!HlNUP@T)?kzH^MG6yxin`0wu@0z#g zdONc3TTRzTG(B-q(*bC_wAlNRB`gmvNDjZ5Ql%TJHwy7=TWjn|FCB}mi>+Hw`QC-=E-r0g0f05dZ)H diff --git a/firmware/0x10000.bin b/firmware/0x10000.bin index b57231a4ce4ec281195122dd79bf5463f63b33b9..7faa44ccd52be5abec31ed5bb4a373689920f041 100644 GIT binary patch delta 34691 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
$5@T;6s z0#7DSq#}!*uT!;N1;`<2_>OFL7`*JNN!TjjeP3JNIF49uG%f$dzvUOWbnJ;bJ||x( zfoSjOZ$v{Jj*Z2|qTzt-T?$c_iKGzL$~%U~pM1R&d}DmBk{^8&Njm=I%ik8cmEq(0 znBLPzMMvVz05jP03v_CGP&nQS5Y5*XZZ?O6|8r00Q=J`Cojm|NNoSC5C^~YWBomcz z&EtbFe$P<@ki2+4IyS!Vk3+04_Pre7-BaY%m$wE*^W2%9_1( z5L}#n7F{!pl3y){G4PN4bvcffV{%ty6ZM=)6>IVq-y|xK8iSbUrAIhK7+0PfZ{{V9U zPRcVXpb9>d2VQ^yG5f^n*k^C(IVM(Z7!s%BKNSaF&td~T8WsGxD^@%I2`ye> z@x}#w8EBVWZ~;bfliKiWMfv&#cp*?lgz)_Op-k47-Gv$jl>Fkk7eU7cB$6C*@E>7d zp58f!1%v!iC06K^{ADE!fVuLGO6cqLYXz3VpWvcpz6vsMS^Gj2$~i9QS3zj#>Q=m1 zCz&B`(n~_;m37QpXjh=We5wkT!&~y;YLL30c^eTD$ZI-b^7GYT@Q>JLFl$S+%mfzy zO=pd1@~LV_hNE(~pJ5^3{PZ&nx9Eu6|Fa-x$lB^$H-@Qf$GQ!R3{GL{$4o_W!}7G8Rg z?9Ey-0?RT2YBT&Uu&oWymn_GHS_R%DbrEhTF+9emv%()r^=$SwEBvlpVGFpFxJN0` zM!nHbH2S9*1Co51O6|+n0wQ*aM!(gym^jKL8Ux5$Br70TJbVC?#lw}DE*7r94AK^O z*W8RXu=H&U%9*|f?}MmZY{a8g?;E#Y&NK#A8-r?%!H`9?z$suk1Z6^C8U*OU&jkK4 zAe1P)56q?6yH4p#{rCmgr)QIR8u;-d-X|dL`l>TM&FBZyNLJNx#dusv@P0nl`do|g z7(R&=mMHt;7G705DT`kqRxE-)$$XnewI(w}+>ApCrPCu!>cG82|NezwHpmwr9uUXx;E8Dy)J1H-F-0UfNlePNE zV(nxhFMC2>_C#aa1#xn$DLY^iA8DGshfg%k{&dt?Q+B#>i~QuT_+9!sB`

k+E^h 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 N_uNZT{>?KS{tw3dWM=>X delta 34491 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 diff --git a/firmware/sha1sums b/firmware/sha1sums index 93af013..08ed86f 100644 --- a/firmware/sha1sums +++ b/firmware/sha1sums @@ -1,2 +1,2 @@ -d0124cb0c7353cb60e9040b6b7e9d443ea20da81 0x00000.bin -867be732084cc79058e216adb37e45315c296e98 0x10000.bin +1990dbd3f155732aea22da501bfccce2cdde44d7 0x00000.bin +13a5fb80a15276aec64d9b7772b5aace9b286568 0x10000.bin diff --git a/include/driver/spi.h b/include/driver/spi.h new file mode 100755 index 0000000..b20a91b --- /dev/null +++ b/include/driver/spi.h @@ -0,0 +1,79 @@ +/* +* The MIT License (MIT) +* +* Copyright (c) 2015 David Ogilvy (MetalPhreak) +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#ifndef SPI_APP_H +#define SPI_APP_H + +#include "spi_register.h" +#include "ets_sys.h" +#include "osapi.h" +//#include "uart.h" +#include "os_type.h" + +//Define SPI hardware modules +#define SPI 0 +#define HSPI 1 + +#define SPI_CLK_USE_DIV 0 +#define SPI_CLK_80MHZ_NODIV 1 + +#define SPI_BYTE_ORDER_HIGH_TO_LOW 1 +#define SPI_BYTE_ORDER_LOW_TO_HIGH 0 + +#ifndef CPU_CLK_FREQ //Should already be defined in eagle_soc.h +#define CPU_CLK_FREQ 80*1000000 +#endif + +//Define some default SPI clock settings +#define SPI_CLK_PREDIV 10 +#define SPI_CLK_CNTDIV 2 +#define SPI_CLK_FREQ CPU_CLK_FREQ/(SPI_CLK_PREDIV*SPI_CLK_CNTDIV) // 80 / 20 = 4 MHz + + + + + +void spi_init(uint8 spi_no); +void spi_mode(uint8 spi_no, uint8 spi_cpha,uint8 spi_cpol); +void spi_init_gpio(uint8 spi_no, uint8 sysclk_as_spiclk); +void spi_clock(uint8 spi_no, uint16 prediv, uint8 cntdiv); +void spi_tx_byte_order(uint8 spi_no, uint8 byte_order); +void spi_rx_byte_order(uint8 spi_no, uint8 byte_order); +uint32 spi_transaction(uint8 spi_no, uint8 cmd_bits, uint16 cmd_data, uint32 addr_bits, uint32 addr_data, uint32 dout_bits, uint32 dout_data, uint32 din_bits, uint32 dummy_bits); + +//Expansion Macros +#define spi_busy(spi_no) READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR + +#define spi_txd(spi_no, bits, data) spi_transaction(spi_no, 0, 0, 0, 0, bits, (uint32) data, 0, 0) +#define spi_tx8(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 8, (uint32) data, 0, 0) +#define spi_tx16(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 16, (uint32) data, 0, 0) +#define spi_tx32(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 32, (uint32) data, 0, 0) + +#define spi_rxd(spi_no, bits) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, bits, 0) +#define spi_rx8(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 8, 0) +#define spi_rx16(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 16, 0) +#define spi_rx32(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 32, 0) + +#endif + diff --git a/include/driver/spi_register.h b/include/driver/spi_register.h new file mode 100755 index 0000000..0c480b0 --- /dev/null +++ b/include/driver/spi_register.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2010 - 2011 Espressif System + * Modified by David Ogilvy (MetalPhreak) + * Based on original file included in SDK 1.0.0 + * + * Missing defines from previous SDK versions have + * been added and are noted with comments. The + * names of these defines are likely to change. + */ + +#ifndef SPI_REGISTER_H_INCLUDED +#define SPI_REGISTER_H_INCLUDED + +#define REG_SPI_BASE(i) (0x60000200-i*0x100) + +#define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0) +#define SPI_FLASH_READ (BIT(31)) //From previous SDK +#define SPI_FLASH_WREN (BIT(30)) //From previous SDK +#define SPI_FLASH_WRDI (BIT(29)) //From previous SDK +#define SPI_FLASH_RDID (BIT(28)) //From previous SDK +#define SPI_FLASH_RDSR (BIT(27)) //From previous SDK +#define SPI_FLASH_WRSR (BIT(26)) //From previous SDK +#define SPI_FLASH_PP (BIT(25)) //From previous SDK +#define SPI_FLASH_SE (BIT(24)) //From previous SDK +#define SPI_FLASH_BE (BIT(23)) //From previous SDK +#define SPI_FLASH_CE (BIT(22)) //From previous SDK +#define SPI_FLASH_DP (BIT(21)) //From previous SDK +#define SPI_FLASH_RES (BIT(20)) //From previous SDK +#define SPI_FLASH_HPM (BIT(19)) //From previous SDK +#define SPI_USR (BIT(18)) + +#define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4) + +#define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8) +#define SPI_WR_BIT_ORDER (BIT(26)) +#define SPI_RD_BIT_ORDER (BIT(25)) +#define SPI_QIO_MODE (BIT(24)) +#define SPI_DIO_MODE (BIT(23)) +#define SPI_TWO_BYTE_STATUS_EN (BIT(22)) //From previous SDK +#define SPI_WP_REG (BIT(21)) //From previous SDK +#define SPI_QOUT_MODE (BIT(20)) +#define SPI_SHARE_BUS (BIT(19)) //From previous SDK +#define SPI_HOLD_MODE (BIT(18)) //From previous SDK +#define SPI_ENABLE_AHB (BIT(17)) //From previous SDK +#define SPI_SST_AAI (BIT(16)) //From previous SDK +#define SPI_RESANDRES (BIT(15)) //From previous SDK +#define SPI_DOUT_MODE (BIT(14)) +#define SPI_FASTRD_MODE (BIT(13)) + +#define SPI_CTRL1(i) (REG_SPI_BASE (i) + 0xC) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_CS_HOLD_DELAY 0x0000000F //Espressif BBS +#define SPI_CS_HOLD_DELAY_S 28 //Espressif BBS +#define SPI_CS_HOLD_DELAY_RES 0x00000FFF //Espressif BBS +#define SPI_CS_HOLD_DELAY_RES_S 16 //Espressif BBS +#define SPI_BUS_TIMER_LIMIT 0x0000FFFF //From previous SDK +#define SPI_BUS_TIMER_LIMIT_S 0 //From previous SDK + + +#define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10) +#define SPI_STATUS_EXT 0x000000FF //From previous SDK +#define SPI_STATUS_EXT_S 24 //From previous SDK +#define SPI_WB_MODE 0x000000FF //From previous SDK +#define SPI_WB_MODE_S 16 //From previous SDK +#define SPI_FLASH_STATUS_PRO_FLAG (BIT(7)) //From previous SDK +#define SPI_FLASH_TOP_BOT_PRO_FLAG (BIT(5)) //From previous SDK +#define SPI_FLASH_BP2 (BIT(4)) //From previous SDK +#define SPI_FLASH_BP1 (BIT(3)) //From previous SDK +#define SPI_FLASH_BP0 (BIT(2)) //From previous SDK +#define SPI_FLASH_WRENABLE_FLAG (BIT(1)) //From previous SDK +#define SPI_FLASH_BUSY_FLAG (BIT(0)) //From previous SDK + +#define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14) +#define SPI_CS_DELAY_NUM 0x0000000F +#define SPI_CS_DELAY_NUM_S 28 +#define SPI_CS_DELAY_MODE 0x00000003 +#define SPI_CS_DELAY_MODE_S 26 +#define SPI_MOSI_DELAY_NUM 0x00000007 +#define SPI_MOSI_DELAY_NUM_S 23 +#define SPI_MOSI_DELAY_MODE 0x00000003 //mode 0 : posedge; data set at positive edge of clk + //mode 1 : negedge + 1 cycle delay, only if freq<10MHz ; data set at negitive edge of clk + //mode 2 : Do not use this mode. +#define SPI_MOSI_DELAY_MODE_S 21 +#define SPI_MISO_DELAY_NUM 0x00000007 +#define SPI_MISO_DELAY_NUM_S 18 +#define SPI_MISO_DELAY_MODE 0x00000003 +#define SPI_MISO_DELAY_MODE_S 16 +#define SPI_CK_OUT_HIGH_MODE 0x0000000F +#define SPI_CK_OUT_HIGH_MODE_S 12 +#define SPI_CK_OUT_LOW_MODE 0x0000000F +#define SPI_CK_OUT_LOW_MODE_S 8 +#define SPI_HOLD_TIME 0x0000000F +#define SPI_HOLD_TIME_S 4 +#define SPI_SETUP_TIME 0x0000000F +#define SPI_SETUP_TIME_S 0 + +#define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18) +#define SPI_CLK_EQU_SYSCLK (BIT(31)) +#define SPI_CLKDIV_PRE 0x00001FFF +#define SPI_CLKDIV_PRE_S 18 +#define SPI_CLKCNT_N 0x0000003F +#define SPI_CLKCNT_N_S 12 +#define SPI_CLKCNT_H 0x0000003F +#define SPI_CLKCNT_H_S 6 +#define SPI_CLKCNT_L 0x0000003F +#define SPI_CLKCNT_L_S 0 + +#define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C) +#define SPI_USR_COMMAND (BIT(31)) +#define SPI_USR_ADDR (BIT(30)) +#define SPI_USR_DUMMY (BIT(29)) +#define SPI_USR_MISO (BIT(28)) +#define SPI_USR_MOSI (BIT(27)) +#define SPI_USR_DUMMY_IDLE (BIT(26)) //From previous SDK +#define SPI_USR_MOSI_HIGHPART (BIT(25)) +#define SPI_USR_MISO_HIGHPART (BIT(24)) +#define SPI_USR_PREP_HOLD (BIT(23)) //From previous SDK +#define SPI_USR_CMD_HOLD (BIT(22)) //From previous SDK +#define SPI_USR_ADDR_HOLD (BIT(21)) //From previous SDK +#define SPI_USR_DUMMY_HOLD (BIT(20)) //From previous SDK +#define SPI_USR_DIN_HOLD (BIT(19)) //From previous SDK +#define SPI_USR_DOUT_HOLD (BIT(18)) //From previous SDK +#define SPI_USR_HOLD_POL (BIT(17)) //From previous SDK +#define SPI_SIO (BIT(16)) +#define SPI_FWRITE_QIO (BIT(15)) +#define SPI_FWRITE_DIO (BIT(14)) +#define SPI_FWRITE_QUAD (BIT(13)) +#define SPI_FWRITE_DUAL (BIT(12)) +#define SPI_WR_BYTE_ORDER (BIT(11)) +#define SPI_RD_BYTE_ORDER (BIT(10)) +#define SPI_AHB_ENDIAN_MODE 0x00000003 //From previous SDK +#define SPI_AHB_ENDIAN_MODE_S 8 //From previous SDK +#define SPI_CK_OUT_EDGE (BIT(7)) +#define SPI_CK_I_EDGE (BIT(6)) +#define SPI_CS_SETUP (BIT(5)) +#define SPI_CS_HOLD (BIT(4)) +#define SPI_AHB_USR_COMMAND (BIT(3)) //From previous SDK +#define SPI_FLASH_MODE (BIT(2)) +#define SPI_AHB_USR_COMMAND_4BYTE (BIT(1)) //From previous SDK +#define SPI_DOUTDIN (BIT(0)) //From previous SDK + +//AHB = http://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture ? + + +#define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20) +#define SPI_USR_ADDR_BITLEN 0x0000003F +#define SPI_USR_ADDR_BITLEN_S 26 +#define SPI_USR_MOSI_BITLEN 0x000001FF +#define SPI_USR_MOSI_BITLEN_S 17 +#define SPI_USR_MISO_BITLEN 0x000001FF +#define SPI_USR_MISO_BITLEN_S 8 +#define SPI_USR_DUMMY_CYCLELEN 0x000000FF +#define SPI_USR_DUMMY_CYCLELEN_S 0 + +#define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24) +#define SPI_USR_COMMAND_BITLEN 0x0000000F +#define SPI_USR_COMMAND_BITLEN_S 28 +#define SPI_USR_COMMAND_VALUE 0x0000FFFF +#define SPI_USR_COMMAND_VALUE_S 0 + +#define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28) + //previously defined as SPI_FLASH_USER3. No further info available. + +#define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C) +#define SPI_IDLE_EDGE (BIT(29)) +#define SPI_CS2_DIS (BIT(2)) +#define SPI_CS1_DIS (BIT(1)) +#define SPI_CS0_DIS (BIT(0)) + +#define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30) +#define SPI_SYNC_RESET (BIT(31)) +#define SPI_SLAVE_MODE (BIT(30)) +#define SPI_SLV_WR_RD_BUF_EN (BIT(29)) +#define SPI_SLV_WR_RD_STA_EN (BIT(28)) +#define SPI_SLV_CMD_DEFINE (BIT(27)) +#define SPI_TRANS_CNT 0x0000000F +#define SPI_TRANS_CNT_S 23 +#define SPI_SLV_LAST_STATE 0x00000007 //From previous SDK +#define SPI_SLV_LAST_STATE_S 20 //From previous SDK +#define SPI_SLV_LAST_COMMAND 0x00000007 //From previous SDK +#define SPI_SLV_LAST_COMMAND_S 17 //From previous SDK +#define SPI_CS_I_MODE 0x00000003 //From previous SDK +#define SPI_CS_I_MODE_S 10 //From previous SDK +#define SPI_TRANS_DONE_EN (BIT(9)) +#define SPI_SLV_WR_STA_DONE_EN (BIT(8)) +#define SPI_SLV_RD_STA_DONE_EN (BIT(7)) +#define SPI_SLV_WR_BUF_DONE_EN (BIT(6)) +#define SPI_SLV_RD_BUF_DONE_EN (BIT(5)) +#define SLV_SPI_INT_EN 0x0000001f +#define SLV_SPI_INT_EN_S 5 +#define SPI_TRANS_DONE (BIT(4)) +#define SPI_SLV_WR_STA_DONE (BIT(3)) +#define SPI_SLV_RD_STA_DONE (BIT(2)) +#define SPI_SLV_WR_BUF_DONE (BIT(1)) +#define SPI_SLV_RD_BUF_DONE (BIT(0)) + +#define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34) +#define SPI_SLV_STATUS_BITLEN 0x0000001F +#define SPI_SLV_STATUS_BITLEN_S 27 +#define SPI_SLV_STATUS_FAST_EN (BIT(26)) //From previous SDK +#define SPI_SLV_STATUS_READBACK (BIT(25)) //From previous SDK +#define SPI_SLV_BUF_BITLEN 0x000001FF +#define SPI_SLV_BUF_BITLEN_S 16 +#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F +#define SPI_SLV_RD_ADDR_BITLEN_S 10 +#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F +#define SPI_SLV_WR_ADDR_BITLEN_S 4 +#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3)) +#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2)) +#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1)) +#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0)) + + + +#define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38) +#define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24 +#define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16 +#define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8 +#define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF +#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0 + +#define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C) +#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF +#define SPI_SLV_WRSTA_CMD_VALUE_S 24 +#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF +#define SPI_SLV_RDSTA_CMD_VALUE_S 16 +#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF +#define SPI_SLV_WRBUF_CMD_VALUE_S 8 +#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF +#define SPI_SLV_RDBUF_CMD_VALUE_S 0 + +//Previous SDKs referred to these following registers as SPI_C0 etc. + +#define SPI_W0(i) (REG_SPI_BASE(i) +0x40) +#define SPI_W1(i) (REG_SPI_BASE(i) +0x44) +#define SPI_W2(i) (REG_SPI_BASE(i) +0x48) +#define SPI_W3(i) (REG_SPI_BASE(i) +0x4C) +#define SPI_W4(i) (REG_SPI_BASE(i) +0x50) +#define SPI_W5(i) (REG_SPI_BASE(i) +0x54) +#define SPI_W6(i) (REG_SPI_BASE(i) +0x58) +#define SPI_W7(i) (REG_SPI_BASE(i) +0x5C) +#define SPI_W8(i) (REG_SPI_BASE(i) +0x60) +#define SPI_W9(i) (REG_SPI_BASE(i) +0x64) +#define SPI_W10(i) (REG_SPI_BASE(i) +0x68) +#define SPI_W11(i) (REG_SPI_BASE(i) +0x6C) +#define SPI_W12(i) (REG_SPI_BASE(i) +0x70) +#define SPI_W13(i) (REG_SPI_BASE(i) +0x74) +#define SPI_W14(i) (REG_SPI_BASE(i) +0x78) +#define SPI_W15(i) (REG_SPI_BASE(i) +0x7C) + + // +0x80 to +0xBC could be SPI_W16 through SPI_W31? + + // +0xC0 to +0xEC not currently defined. + +#define SPI_EXT0(i) (REG_SPI_BASE(i) + 0xF0) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_T_PP_ENA (BIT(31)) //From previous SDK +#define SPI_T_PP_SHIFT 0x0000000F //From previous SDK +#define SPI_T_PP_SHIFT_S 16 //From previous SDK +#define SPI_T_PP_TIME 0x00000FFF //From previous SDK +#define SPI_T_PP_TIME_S 0 //From previous SDK + +#define SPI_EXT1(i) (REG_SPI_BASE(i) + 0xF4) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_T_ERASE_ENA (BIT(31)) //From previous SDK +#define SPI_T_ERASE_SHIFT 0x0000000F //From previous SDK +#define SPI_T_ERASE_SHIFT_S 16 //From previous SDK +#define SPI_T_ERASE_TIME 0x00000FFF //From previous SDK +#define SPI_T_ERASE_TIME_S 0 //From previous SDK + +#define SPI_EXT2(i) (REG_SPI_BASE(i) + 0xF8) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_ST 0x00000007 //From previous SDK +#define SPI_ST_S 0 //From previous SDK + +#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC) +#define SPI_INT_HOLD_ENA 0x00000003 +#define SPI_INT_HOLD_ENA_S 0 +#endif // SPI_REGISTER_H_INCLUDED diff --git a/include/lwip/netif/espenc.h b/include/lwip/netif/espenc.h new file mode 100644 index 0000000..dbc0640 --- /dev/null +++ b/include/lwip/netif/espenc.h @@ -0,0 +1,253 @@ +#include +//#include +#include + +err_t enc28j60_link_output(struct netif *netif, struct pbuf *p); +err_t enc28j60_init(struct netif *netif); +void espenc_init(); + +#define log(s, ...) os_printf ("[%s:%s:%d] " s "\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__) + +#define ESP_CS 15 +#define ESP_INT 5 + + +// ENC28J60 Control Registers +// Control register definitions are a combination of address, +// bank number, and Ethernet/MAC/PHY indicator bits. +// - Register address (bits 0-4) +// - Bank number (bits 5-6) +// - MAC/PHY indicator (bit 7) +#define ADDR_MASK 0x1F +#define BANK_MASK 0x60 +#define SPRD_MASK 0x80 +// All-bank registers +#define EIE 0x1B +#define EIR 0x1C +#define ESTAT 0x1D +#define ECON2 0x1E +#define ECON1 0x1F +// Bank 0 registers +#define ERDPT (0x00|0x00) +#define EWRPT (0x02|0x00) +#define ETXST (0x04|0x00) +#define ETXND (0x06|0x00) +#define ERXST (0x08|0x00) +#define ERXND (0x0A|0x00) +#define ERXRDPT (0x0C|0x00) +// #define ERXWRPT (0x0E|0x00) +#define EDMAST (0x10|0x00) +#define EDMAND (0x12|0x00) +// #define EDMADST (0x14|0x00) +#define EDMACS (0x16|0x00) +// Bank 1 registers +#define EHT0 (0x00|0x20) +#define EHT1 (0x01|0x20) +#define EHT2 (0x02|0x20) +#define EHT3 (0x03|0x20) +#define EHT4 (0x04|0x20) +#define EHT5 (0x05|0x20) +#define EHT6 (0x06|0x20) +#define EHT7 (0x07|0x20) +#define EPMM0 (0x08|0x20) +#define EPMM1 (0x09|0x20) +#define EPMM2 (0x0A|0x20) +#define EPMM3 (0x0B|0x20) +#define EPMM4 (0x0C|0x20) +#define EPMM5 (0x0D|0x20) +#define EPMM6 (0x0E|0x20) +#define EPMM7 (0x0F|0x20) +#define EPMCS (0x10|0x20) +// #define EPMO (0x14|0x20) +#define EWOLIE (0x16|0x20) +#define EWOLIR (0x17|0x20) +#define ERXFCON (0x18|0x20) +#define EPKTCNT (0x19|0x20) +// Bank 2 registers +#define MACON1 (0x00|0x40|0x80) +#define MACON2 (0x01|0x40|0x80) +#define MACON3 (0x02|0x40|0x80) +#define MACON4 (0x03|0x40|0x80) +#define MABBIPG (0x04|0x40|0x80) +#define MAIPG (0x06|0x40|0x80) +#define MACLCON1 (0x08|0x40|0x80) +#define MACLCON2 (0x09|0x40|0x80) +#define MAMXFL (0x0A|0x40|0x80) +#define MAPHSUP (0x0D|0x40|0x80) +#define MICON (0x11|0x40|0x80) +#define MICMD (0x12|0x40|0x80) +#define MIREGADR (0x14|0x40|0x80) +#define MIWR (0x16|0x40|0x80) +#define MIRD (0x18|0x40|0x80) +// Bank 3 registers +#define MAADR1 (0x00|0x60|0x80) +#define MAADR0 (0x01|0x60|0x80) +#define MAADR3 (0x02|0x60|0x80) +#define MAADR2 (0x03|0x60|0x80) +#define MAADR5 (0x04|0x60|0x80) +#define MAADR4 (0x05|0x60|0x80) +#define EBSTSD (0x06|0x60) +#define EBSTCON (0x07|0x60) +#define EBSTCS (0x08|0x60) +#define MISTAT (0x0A|0x60|0x80) +#define EREVID (0x12|0x60) +#define ECOCON (0x15|0x60) +#define EFLOCON (0x17|0x60) +#define EPAUS (0x18|0x60) + +// ENC28J60 ERXFCON Register Bit Definitions +#define ERXFCON_UCEN 0x80 +#define ERXFCON_ANDOR 0x40 +#define ERXFCON_CRCEN 0x20 +#define ERXFCON_PMEN 0x10 +#define ERXFCON_MPEN 0x08 +#define ERXFCON_HTEN 0x04 +#define ERXFCON_MCEN 0x02 +#define ERXFCON_BCEN 0x01 +// ENC28J60 EIE Register Bit Definitions +#define EIE_INTIE 0x80 +#define EIE_PKTIE 0x40 +#define EIE_DMAIE 0x20 +#define EIE_LINKIE 0x10 +#define EIE_TXIE 0x08 +#define EIE_WOLIE 0x04 +#define EIE_TXERIE 0x02 +#define EIE_RXERIE 0x01 +// ENC28J60 EIR Register Bit Definitions +#define EIR_PKTIF 0x40 +#define EIR_DMAIF 0x20 +#define EIR_LINKIF 0x10 +#define EIR_TXIF 0x08 +#define EIR_WOLIF 0x04 +#define EIR_TXERIF 0x02 +#define EIR_RXERIF 0x01 +// ENC28J60 ESTAT Register Bit Definitions +#define ESTAT_INT 0x80 +#define ESTAT_LATECOL 0x10 +#define ESTAT_RXBUSY 0x04 +#define ESTAT_TXABRT 0x02 +#define ESTAT_CLKRDY 0x01 +// ENC28J60 ECON2 Register Bit Definitions +#define ECON2_AUTOINC 0x80 +#define ECON2_PKTDEC 0x40 +#define ECON2_PWRSV 0x20 +#define ECON2_VRPS 0x08 +// ENC28J60 ECON1 Register Bit Definitions +#define ECON1_TXRST 0x80 +#define ECON1_RXRST 0x40 +#define ECON1_DMAST 0x20 +#define ECON1_CSUMEN 0x10 +#define ECON1_TXRTS 0x08 +#define ECON1_RXEN 0x04 +#define ECON1_BSEL1 0x02 +#define ECON1_BSEL0 0x01 +// ENC28J60 MACON1 Register Bit Definitions +#define MACON1_LOOPBK 0x10 +#define MACON1_TXPAUS 0x08 +#define MACON1_RXPAUS 0x04 +#define MACON1_PASSALL 0x02 +#define MACON1_MARXEN 0x01 +// ENC28J60 MACON2 Register Bit Definitions +#define MACON2_MARST 0x80 +#define MACON2_RNDRST 0x40 +#define MACON2_MARXRST 0x08 +#define MACON2_RFUNRST 0x04 +#define MACON2_MATXRST 0x02 +#define MACON2_TFUNRST 0x01 +// ENC28J60 MACON3 Register Bit Definitions +#define MACON3_PADCFG2 0x80 +#define MACON3_PADCFG1 0x40 +#define MACON3_PADCFG0 0x20 +#define MACON3_TXCRCEN 0x10 +#define MACON3_PHDRLEN 0x08 +#define MACON3_HFRMLEN 0x04 +#define MACON3_FRMLNEN 0x02 +#define MACON3_FULDPX 0x01 +// ENC28J60 MICMD Register Bit Definitions +#define MICMD_MIISCAN 0x02 +#define MICMD_MIIRD 0x01 +// ENC28J60 MISTAT Register Bit Definitions +#define MISTAT_NVALID 0x04 +#define MISTAT_SCAN 0x02 +#define MISTAT_BUSY 0x01 + +// ENC28J60 EBSTCON Register Bit Definitions +#define EBSTCON_PSV2 0x80 +#define EBSTCON_PSV1 0x40 +#define EBSTCON_PSV0 0x20 +#define EBSTCON_PSEL 0x10 +#define EBSTCON_TMSEL1 0x08 +#define EBSTCON_TMSEL0 0x04 +#define EBSTCON_TME 0x02 +#define EBSTCON_BISTST 0x01 + +// PHY registers +#define PHCON1 0x00 +#define PHSTAT1 0x01 +#define PHHID1 0x02 +#define PHHID2 0x03 +#define PHCON2 0x10 +#define PHSTAT2 0x11 +#define PHIE 0x12 +#define PHIR 0x13 +#define PHLCON 0x14 + +// ENC28J60 PHY PHCON1 Register Bit Definitions +#define PHCON1_PRST 0x8000 +#define PHCON1_PLOOPBK 0x4000 +#define PHCON1_PPWRSV 0x0800 +#define PHCON1_PDPXMD 0x0100 +// ENC28J60 PHY PHSTAT1 Register Bit Definitions +#define PHSTAT1_PFDPX 0x1000 +#define PHSTAT1_PHDPX 0x0800 +#define PHSTAT1_LLSTAT 0x0004 +#define PHSTAT1_JBSTAT 0x0002 +// ENC28J60 PHY PHCON2 Register Bit Definitions +#define PHCON2_FRCLINK 0x4000 +#define PHCON2_TXDIS 0x2000 +#define PHCON2_JABBER 0x0400 +#define PHCON2_HDLDIS 0x0100 + +// ENC28J60 Packet Control Byte Bit Definitions +#define PKTCTRL_PHUGEEN 0x08 +#define PKTCTRL_PPADEN 0x04 +#define PKTCTRL_PCRCEN 0x02 +#define PKTCTRL_POVERRIDE 0x01 + +// SPI operation codes +#define ENC28J60_READ_CTRL_REG 0x00 +#define ENC28J60_READ_BUF_MEM 0x3A +#define ENC28J60_WRITE_CTRL_REG 0x40 +#define ENC28J60_WRITE_BUF_MEM 0x7A +#define ENC28J60_BIT_FIELD_SET 0x80 +#define ENC28J60_BIT_FIELD_CLR 0xA0 +#define ENC28J60_SOFT_RESET 0xFF + + +// max frame length which the controller will accept: +// (note: maximum ethernet frame length would be 1518) +#define MAX_FRAMELEN 1500 + +#define FULL_SPEED 1 // switch to full-speed SPI for bulk transfers + + +// buffer boundaries applied to internal 8K ram +// the entire available packet buffer space is allocated + +#define RXSTART_INIT 0x0000 // start of RX buffer, (must be zero, Rev. B4 Errata point 5) +#define RXSTOP_INIT 0x0BFF // end of RX buffer, room for 2 packets + +#define TXSTART_INIT 0x0C00 // start of TX buffer, room for 1 packet +#define TXSTOP_INIT 0x11FF // end of TX buffer + +#define SCRATCH_START 0x1200 // start of scratch area +#define SCRATCH_LIMIT 0x2000 // past end of area, i.e. 3 Kb +#define SCRATCH_PAGE_SHIFT 6 // addressing is in pages of 64 bytes +#define SCRATCH_PAGE_SIZE (1 << SCRATCH_PAGE_SHIFT) +#define SCRATCH_PAGE_NUM ((SCRATCH_LIMIT-SCRATCH_START) >> SCRATCH_PAGE_SHIFT) +#define SCRATCH_MAP_SIZE (((SCRATCH_PAGE_NUM % 8) == 0) ? (SCRATCH_PAGE_NUM / 8) : (SCRATCH_PAGE_NUM/8+1)) + +// area in the enc memory that can be used via enc_malloc; by default 0 bytes; decrease SCRATCH_LIMIT in order +// to use this functionality +#define ENC_HEAP_START SCRATCH_LIMIT +#define ENC_HEAP_END 0x2000 diff --git a/user/user_config.h b/user/user_config.h index 877f8fc..8de2a03 100644 --- a/user/user_config.h +++ b/user/user_config.h @@ -1,7 +1,7 @@ #ifndef _USER_CONFIG_ #define _USER_CONFIG_ -#define ESP_REPEATER_VERSION "V1.7.9" +#define ESP_REPEATER_VERSION "V1.8.0" #define LOCAL_ACCESS 0x01 #define REMOTE_ACCESS 0x02 @@ -30,7 +30,7 @@ // Defines the default GPIO pin for HW factory reset (when this GPIO is pulled low for more than 3 secs) // Any value > 16 disables this feature // -#define FACTORY_RESET_PIN 12 +#define FACTORY_RESET_PIN 4 // // Define this to support the "scan" command for AP search @@ -58,6 +58,11 @@ // #define PHY_MODE 1 +// +// Define this to support an ENC28J60 Ethernet interface +// +//#define HAVE_ENC28J60 1 + // // Define this to support a loopback device (127.0.0.1) // diff --git a/user/user_main.c b/user/user_main.c index 84c3d17..5d05062 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -15,7 +15,9 @@ #ifdef ALLOW_PING #include "lwip/app/ping.h" #endif - +#ifdef HAVE_ENC28J60 +#include "netif/espenc.h" +#endif #include "user_interface.h" #include "string.h" #include "driver/uart.h" @@ -125,10 +127,9 @@ void ICACHE_FLASH_ATTR mac_2_buff(char *buf, uint8_t mac[6]) { #define MQTT_TOPIC_VDD 0x0040 #define MQTT_TOPIC_ACLDENY 0x0080 #define MQTT_TOPIC_BYTES 0x0100 -#define MQTT_TOPIC_PIN 0x0200 -#define MQTT_TOPIC_POUT 0x0400 -#define MQTT_TOPIC_BPSIN 0x0800 -#define MQTT_TOPIC_BPSOUT 0x0800 +#define MQTT_TOPIC_PACKETS 0x0200 +#define MQTT_TOPIC_BPD 0x0400 +#define MQTT_TOPIC_BPS 0x0800 #define MQTT_TOPIC_TOPOLOGY 0x1000 #define MQTT_TOPIC_NOSTATIONS 0x2000 #define MQTT_TOPIC_GPIOIN 0x4000 @@ -2619,15 +2620,19 @@ uint32_t Bps; mqtt_publish_int(MQTT_TOPIC_VDD, "Vdd", "%d", Vdd); mqtt_publish_int(MQTT_TOPIC_BYTES, "Bin", "%d", (uint32_t)(Bytes_in/1024)); mqtt_publish_int(MQTT_TOPIC_BYTES, "Bout", "%d", (uint32_t)(Bytes_out/1024)); - mqtt_publish_int(MQTT_TOPIC_PIN, "Ppsin", "%d", (Packets_in-Packets_in_last)/t_diff); - mqtt_publish_int(MQTT_TOPIC_POUT, "Ppsout", "%d", (Packets_out-Packets_out_last)/t_diff); + mqtt_publish_int(MQTT_TOPIC_PACKETS, "Ppsin", "%d", (Packets_in-Packets_in_last)/t_diff); + mqtt_publish_int(MQTT_TOPIC_PACKETS, "Ppsout", "%d", (Packets_out-Packets_out_last)/t_diff); mqtt_publish_int(MQTT_TOPIC_NOSTATIONS, "NoStations", "%d", config.ap_on?wifi_softap_get_station_num():0); - mqtt_publish_int(MQTT_TOPIC_BPSIN, "Bpsin", "%d", (uint32_t)(Bytes_in-Bytes_in_last)/t_diff); - mqtt_publish_int(MQTT_TOPIC_BPSOUT, "Bpsout", "%d", (uint32_t)(Bytes_out-Bytes_out_last)/t_diff); + mqtt_publish_int(MQTT_TOPIC_BPS, "Bpsin", "%d", (uint32_t)(Bytes_in-Bytes_in_last)/t_diff); + mqtt_publish_int(MQTT_TOPIC_BPS, "Bpsout", "%d", (uint32_t)(Bytes_out-Bytes_out_last)/t_diff); +#ifdef DAILY_LIMIT + mqtt_publish_int(MQTT_TOPIC_BPD, "Bpd", "%d", (uint32_t)(Bytes_per_day/1024)); +#endif #ifdef USER_GPIO_OUT mqtt_publish_int(MQTT_TOPIC_GPIOOUT, "GpioOut", "%d", (uint32_t)config.gpio_out_status); #endif + if (config.mqtt_topic_mask & MQTT_TOPIC_TOPOLOGY) { uint8_t *buffer = (uint8_t *)os_malloc(1024); @@ -3263,6 +3268,9 @@ struct ip_info info; #ifdef HAVE_LOOPBACK loopback_netif_init((netif_status_callback_fn)schedule_netif_poll); #endif +#ifdef HAVE_ENC28J60 + espenc_init(); +#endif #ifdef REMOTE_CONFIG if (config.config_port != 0) {