Browse Source

init commit

curiousmuch 4 years ago
commit
542f63e5b4
65 changed files with 13901 additions and 0 deletions
  1. 249 0
      Makefile
  2. 44 0
      driver/Makefile
  3. 66 0
      driver/gpio16.c
  4. 155 0
      driver/hw_timer.c
  5. 330 0
      driver/i2c_master.c
  6. 176 0
      driver/key.c
  7. 457 0
      driver/sdio_slv.c
  8. 487 0
      driver/spi.c
  9. 502 0
      driver/spi_interface.c
  10. 422 0
      driver/spi_overlap.c
  11. 796 0
      driver/uart.c
  12. 42 0
      gdbstub/Makefile
  13. 785 0
      gdbstub/gdbstub.c
  14. 1565 0
      hal/lps25hb.c
  15. 364 0
      hal/lsm6ds3.c
  16. 175 0
      hal/max17043.c
  17. 164 0
      hal/ws2812.c
  18. 33 0
      include/driver/gpio16.h
  19. 93 0
      include/driver/i2c_master.h
  20. 51 0
      include/driver/key.h
  21. 40 0
      include/driver/sdio_slv.h
  22. 300 0
      include/driver/slc_register.h
  23. 74 0
      include/driver/spi.h
  24. 353 0
      include/driver/spi_interface.h
  25. 85 0
      include/driver/spi_overlap.h
  26. 222 0
      include/driver/spi_register.h
  27. 229 0
      include/driver/uart.h
  28. 159 0
      include/driver/uart_register.h
  29. 17 0
      include/esp_common.h
  30. 63 0
      include/gdbstub/gdbstub-cfg.h
  31. 25 0
      include/gdbstub/gdbstub-entry.h
  32. 14 0
      include/gdbstub/gdbstub.h
  33. 1309 0
      include/hal/lps25hb.h
  34. 269 0
      include/hal/lsm6ds3.h
  35. 58 0
      include/hal/max17043.h
  36. 35 0
      include/hal/ws2812.h
  37. 10 0
      include/interface/uart_interface.h
  38. 90 0
      include/log/esp_log.h
  39. 60 0
      include/user_config.h
  40. 57 0
      include/util/config.h
  41. 48 0
      include/util/ideasX.h
  42. 62 0
      include/util/wifi.h
  43. 61 0
      interface/uart_interface.c
  44. 42 0
      log/Makefile
  45. 31 0
      log/log.c
  46. 44 0
      mqtt/Makefile
  47. 19 0
      mqtt/include/debug.h
  48. 148 0
      mqtt/include/mqtt.h
  49. 141 0
      mqtt/include/mqtt_msg.h
  50. 32 0
      mqtt/include/proto.h
  51. 44 0
      mqtt/include/queue.h
  52. 19 0
      mqtt/include/ringbuf.h
  53. 17 0
      mqtt/include/typedef.h
  54. 9 0
      mqtt/include/utils.h
  55. 995 0
      mqtt/mqtt.c
  56. 487 0
      mqtt/mqtt_msg.c
  57. 129 0
      mqtt/proto.c
  58. 75 0
      mqtt/queue.c
  59. 67 0
      mqtt/ringbuf.c
  60. 149 0
      mqtt/utils.c
  61. 44 0
      user/Makefile
  62. 76 0
      user/rfinit.c
  63. 112 0
      user/user_main.c
  64. 140 0
      util/config.c
  65. 485 0
      util/wifi.c

+ 249 - 0
Makefile

@@ -0,0 +1,249 @@
+# none sdkota espboot rboot
+OTA ?= none
+OTA_APP_ADDR = 0x2000
+OTA_BOOTLOADER_PATH = ../esp-bootloader/firmware/espboot.bin
+
+THISDIR:=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+# Base directory for the compiler. Needs a / at the end; if not set it'll use the tools that are in
+# the PATH.
+XTENSA_TOOLS_ROOT ?=
+
+# base directory of the ESP8266 SDK package, absolute
+SDK_BASE	?= /home/curiousmuch/ideasX-repositories/esp8266/esp-open-sdk/sdk
+
+#Esptool.py path and port
+ESPTOOL		?= /home/curiousmuch/ideasX-repositories/esp8266/esp-open-sdk/esptool/esptool.py
+ESPPORT		?= /dev/ttyUSB0
+#ESPPORT		?= /dev/tty.wchusbserial1410
+#ESPDELAY indicates seconds to wait between flashing the two binary images
+ESPDELAY	?= 3
+#ESPBAUD		?= 115200
+ESPBAUD		?= 460800
+
+# 40m 26m 20m 80m
+ESP_FREQ = 40m
+# qio qout dio dout
+ESP_MODE = dio
+#4m 2m 8m 16m 32m
+ESP_SIZE = 32m
+
+
+VERBOSE = yes
+FLAVOR = debug
+# name for the target project
+TARGET		?= ideasX_
+# name for the target when compiling as library
+TARGET_LIB ?= ideasX.a
+
+# which modules (subdirectories) of the project to include in compiling
+USER_MODULES		= user driver gdbstub log hal
+USER_INC				= include
+USER_LIB				=
+
+# which modules (subdirectories) of the project to include when compiling as library
+LIB_MODULES			= mqtt
+
+SDK_LIBDIR = lib
+SDK_LIBS = c gcc phy pp net80211 wpa main lwip crypto ssl json driver
+SDK_INC = include include/json
+
+
+
+# Output directors to store intermediate compiled files
+# relative to the project directory
+BUILD_BASE				= build
+FIRMWARE_BASE		= firmware
+
+# Opensdk patches stdint.h when compiled with an internal SDK. If you run into compile problems pertaining to
+# redefinition of int types, try setting this to 'yes'.
+USE_OPENSDK ?= yes
+
+DATETIME := $(shell date "+%Y-%b-%d_%H:%M:%S_%Z")
+
+# select which tools to use as compiler, librarian and linker
+CC		:= $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc
+AR		:= $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-ar
+LD		:= $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc
+OBJCOPY	:= $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objcopy
+
+
+
+####
+#### no user configurable options below here
+####
+SRC_DIR				:= $(USER_MODULES)
+SRC_DIR_LIB		:= $(LIB_MODULES)
+BUILD_DIR			:= $(addprefix $(BUILD_BASE)/,$(USER_MODULES))
+
+INCDIR	:= $(addprefix -I,$(SRC_DIR))
+EXTRA_INCDIR	:= $(addprefix -I,$(USER_INC))
+MODULE_INCDIR	:= $(addsuffix /include,$(INCDIR))
+
+SDK_LIBDIR	:= $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR))
+SDK_LIBS 		:= $(addprefix -l,$(SDK_LIBS))
+
+SDK_INCDIR	:= $(addprefix -I$(SDK_BASE)/,$(SDK_INC))
+
+SRC		:= $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c))
+SRC_LIB	:= $(foreach sdir,$(SRC_DIR_LIB),$(wildcard $(sdir)/*.c))
+ASMSRC		= $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.S))
+ASMSRC_LIB = $(foreach sdir,$(SRC_DIR_LIB),$(wildcard $(sdir)/*.S))
+
+OBJ		= $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC))
+OBJ_LIB	= $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC_LIB))
+OBJ		+= $(patsubst %.S,$(BUILD_BASE)/%.o,$(ASMSRC))
+OBJ_LIB	+= $(patsubst %.c,$(BUILD_BASE)/%.o,$(ASMSRC_LIB))
+
+APP_AR		:= $(addprefix $(BUILD_BASE)/,$(TARGET).a)
+TARGET_OUT	:= $(addprefix $(BUILD_BASE)/,$(TARGET).out)
+
+
+
+# compiler flags using during compilation of source files
+CFLAGS		= -g			\
+						-Wpointer-arith		\
+						-Wundef			\
+						-Wl,-EL			\
+						-Wno-implicit-function-declaration \
+						-fno-inline-functions	\
+						-nostdlib       \
+						-mlongcalls	\
+						-mtext-section-literals \
+						-ffunction-sections \
+						-fdata-sections	\
+						-fno-builtin-printf\
+						-DICACHE_FLASH \
+						-DBUID_TIME=\"$(DATETIME)\"
+
+# linker flags used to generate the main object file
+LDFLAGS		= -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
+
+ifeq ($(FLAVOR),debug)
+    LDFLAGS += -g -O2
+    CFLAGS += -DMQTT_DEBUG_ON -DDEBUG_ON
+endif
+
+ifeq ($(FLAVOR),release)
+    LDFLAGS += -g -O0
+endif
+
+V ?= $(VERBOSE)
+ifeq ("$(V)","yes")
+Q :=
+vecho := @true
+else
+Q := @
+vecho := @echo
+endif
+
+ifeq ("$(USE_OPENSDK)","yes")
+CFLAGS		+= -DUSE_OPENSDK
+else
+CFLAGS		+= -D_STDINT_Hlocal
+endif
+
+ifneq ("$(wildcard $(THISDIR)/include/user_config.local.h)","")
+CFLAGS += -DLOCAL_CONFIG_AVAILABLE
+endif
+
+
+ESPTOOL_OPTS=--port $(ESPPORT) --baud $(ESPBAUD)
+
+#32m
+ESP_INIT_DATA_DEFAULT_ADDR = 0xfc000
+
+ifeq ("$(ESP_SIZE)","16m")
+	ESP_INIT_DATA_DEFAULT_ADDR = 0x1fc000
+else ifeq ("$(ESP_SIZE)","32m")
+	ESP_INIT_DATA_DEFAULT_ADDR = 0x3fc000
+endif
+
+ifeq ("$(OTA)","espboot")
+	OUTPUT := $(addprefix $(FIRMWARE_BASE)/,$(TARGET)-0x2000.bin)
+	ESPTOOL_WRITE = write_flash --flash_freq $(ESP_FREQ) --flash_mode $(ESP_MODE) --flash_size $(ESP_SIZE) \
+									0x00000 $(OTA_BOOTLOADER_PATH) \
+									$(OTA_APP_ADDR) $(OUTPUT) \
+									$(ESP_INIT_DATA_DEFAULT_ADDR) $(SDK_BASE)/bin/esp_init_data_default.bin
+
+	ESPTOOL_FLASHDEF=--version=2
+	LD_SCRIPT	= -Tld/with-espboot-flash-at-0x2000-size-1M.ld
+else
+	OUTPUT := $(addprefix $(FIRMWARE_BASE)/,$(TARGET))
+	ESPTOOL_WRITE = write_flash --flash_freq $(ESP_FREQ) --flash_mode $(ESP_MODE) --flash_size $(ESP_SIZE) \
+									0x00000 $(OUTPUT)0x00000.bin \
+									0x10000 $(OUTPUT)0x10000.bin \
+									$(ESP_INIT_DATA_DEFAULT_ADDR) $(SDK_BASE)/bin/esp_init_data_default.bin
+
+	ESPTOOL_FLASHDEF=
+	#LD_SCRIPT   = -T$(SDK_BASE)/ld/eagle.app.v6.new.2048.ld
+	LD_SCRIPT	= -T$(SDK_BASE)/ld/eagle.app.v6.ld
+endif
+OUTPUT_LIB := $(addprefix $(FIRMWARE_BASE)/,$(TARGET_LIB))
+
+
+vpath %.c $(SRC_DIR)
+
+define compile-objects
+$1/%.o: %.c
+	$(vecho) "CC $$<"
+	$(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS)  -c $$< -o $$@
+endef
+
+
+
+.PHONY: all lib checkdirs clean
+
+all: touch checkdirs $(OUTPUT)
+
+lib: checkdirs $(OUTPUT_LIB)
+
+touch:
+	$(vecho) "-------------------------------------------\n"
+	$(vecho) "BUID TIME $(DATETIME)"
+	$(vecho) "-------------------------------------------\n"
+	$(Q) touch user/user_main.c
+
+checkdirs: $(BUILD_DIR) $(FIRMWARE_BASE)
+
+$(OUTPUT): $(TARGET_OUT)
+	$(vecho) "FW $@"
+	$(Q) $(ESPTOOL) elf2image $(ESPTOOL_FLASHDEF) $< -o $(OUTPUT)
+
+$(OUTPUT_LIB): $(OBJ_LIB)
+	$(vecho) "AR $@"
+	$(Q) $(AR) cru $@ $^
+
+$(BUILD_DIR):
+	$(Q) mkdir -p $@
+
+$(FIRMWARE_BASE):
+	$(Q) mkdir -p $@
+
+$(TARGET_OUT): $(APP_AR)
+	$(vecho) "LD $@"
+	$(Q) $(LD) -L$(SDK_LIBDIR) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(SDK_LIBS) $(APP_AR) -Wl,--end-group -o $@
+
+$(APP_AR): $(OBJ)
+	$(vecho) "AR $@"
+	$(Q) $(AR) cru $@ $^
+
+flash:
+	$(ESPTOOL) $(ESPTOOL_OPTS) $(ESPTOOL_WRITE)
+
+wipe:
+	$(ESPTOOL) $(ESPTOOL_OPTS) erase_flash
+
+fast: all flash openport
+
+openport:
+	$(vecho) "After flash, terminal will enter serial port screen"
+	$(vecho) "Please exit with command:"
+	$(vecho) "\033[0;31m" "Ctrl + A + k" "\033[0m"
+
+	#@read -p "Press any key to continue... " -n1 -s
+	@screen $(ESPPORT) 115200
+
+clean:
+	$(Q) rm -rf $(BUILD_DIR)
+	$(Q) rm -rf $(FIRMWARE_BASE)
+$(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir))))

+ 44 - 0
driver/Makefile

@@ -0,0 +1,44 @@
+
+#############################################################
+# Required variables for each makefile
+# Discard this section from all parent makefiles
+# Expected variables (with automatic defaults):
+#   CSRCS (all "C" files in the dir)
+#   SUBDIRS (all subdirs with a Makefile)
+#   GEN_LIBS - list of libs to be generated ()
+#   GEN_IMAGES - list of images to be generated ()
+#   COMPONENTS_xxx - a list of libs/objs in the form
+#     subdir/lib to be extracted and rolled up into
+#     a generated lib/image xxx.a ()
+#
+ifndef PDIR
+GEN_LIBS = libdriver.a
+endif
+
+
+#############################################################
+# Configuration i.e. compile options etc.
+# Target specific stuff (defines etc.) goes in here!
+# Generally values applying to a tree are captured in the
+#   makefile at its root level - these are then overridden
+#   for a subtree within the makefile rooted therein
+#
+#DEFINES += 
+
+#############################################################
+# Recursion Magic - Don't touch this!!
+#
+# Each subtree potentially has an include directory
+#   corresponding to the common APIs applicable to modules
+#   rooted at that subtree. Accordingly, the INCLUDE PATH
+#   of a module can only contain the include directories up
+#   its parent path, and not its siblings
+#
+# Required for each makefile to inherit from the parent
+#
+
+INCLUDES := $(INCLUDES) -I $(PDIR)include
+INCLUDES += -I ./
+PDIR := ../$(PDIR)
+sinclude $(PDIR)Makefile
+

+ 66 - 0
driver/gpio16.c

@@ -0,0 +1,66 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "ets_sys.h"
+#include "osapi.h"
+#include "driver/gpio16.h"
+
+void ICACHE_FLASH_ATTR
+gpio16_output_conf(void)
+{
+    WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
+                   (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); 	// mux configuration for XPD_DCDC to output rtc_gpio0
+
+    WRITE_PERI_REG(RTC_GPIO_CONF,
+                   (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0);	//mux configuration for out enable
+
+    WRITE_PERI_REG(RTC_GPIO_ENABLE,
+                   (READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe) | (uint32)0x1);	//out enable
+}
+
+void ICACHE_FLASH_ATTR
+gpio16_output_set(uint8 value)
+{
+    WRITE_PERI_REG(RTC_GPIO_OUT,
+                   (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe) | (uint32)(value & 1));
+}
+
+void ICACHE_FLASH_ATTR
+gpio16_input_conf(void)
+{
+    WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
+                   (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); 	// mux configuration for XPD_DCDC and rtc_gpio0 connection
+
+    WRITE_PERI_REG(RTC_GPIO_CONF,
+                   (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0);	//mux configuration for out enable
+
+    WRITE_PERI_REG(RTC_GPIO_ENABLE,
+                   READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe);	//out disable
+}
+
+uint8 ICACHE_FLASH_ATTR
+gpio16_input_get(void)
+{
+    return (uint8)(READ_PERI_REG(RTC_GPIO_IN_DATA) & 1);
+}

+ 155 - 0
driver/hw_timer.c

@@ -0,0 +1,155 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "ets_sys.h"
+#include "os_type.h"
+#include "osapi.h"
+
+#define US_TO_RTC_TIMER_TICKS(t)          \
+    ((t) ?                                   \
+     (((t) > 0x35A) ?                   \
+      (((t)>>2) * ((APB_CLK_FREQ>>4)/250000) + ((t)&0x3) * ((APB_CLK_FREQ>>4)/1000000))  :    \
+      (((t) *(APB_CLK_FREQ>>4)) / 1000000)) :    \
+     0)
+
+#define FRC1_ENABLE_TIMER  BIT7
+#define FRC1_AUTO_LOAD  BIT6
+
+//TIMER PREDIVED MODE
+typedef enum {
+    DIVDED_BY_1 = 0,		//timer clock
+    DIVDED_BY_16 = 4,	//divided by 16
+    DIVDED_BY_256 = 8,	//divided by 256
+} TIMER_PREDIVED_MODE;
+
+typedef enum {			//timer interrupt mode
+    TM_LEVEL_INT = 1,	// level interrupt
+    TM_EDGE_INT   = 0,	//edge interrupt
+} TIMER_INT_MODE;
+
+typedef enum {
+    FRC1_SOURCE = 0,
+    NMI_SOURCE = 1,
+} FRC1_TIMER_SOURCE_TYPE;
+
+/******************************************************************************
+* FunctionName : hw_timer_arm
+* Description  : set a trigger timer delay for this timer.
+* Parameters   : uint32 val :
+in autoload mode
+                        50 ~ 0x7fffff;  for FRC1 source.
+                        100 ~ 0x7fffff;  for NMI source.
+in non autoload mode:
+                        10 ~ 0x7fffff;
+* Returns      : NONE
+*******************************************************************************/
+void  hw_timer_arm(u32 val)
+{
+    RTC_REG_WRITE(FRC1_LOAD_ADDRESS, US_TO_RTC_TIMER_TICKS(val));
+}
+
+static void (* user_hw_timer_cb)(void) = NULL;
+/******************************************************************************
+* FunctionName : hw_timer_set_func
+* Description  : set the func, when trigger timer is up.
+* Parameters   : void (* user_hw_timer_cb_set)(void):
+                        timer callback function,
+* Returns      : NONE
+*******************************************************************************/
+void  hw_timer_set_func(void (* user_hw_timer_cb_set)(void))
+{
+    user_hw_timer_cb = user_hw_timer_cb_set;
+}
+
+static void  hw_timer_isr_cb(void)
+{
+    if (user_hw_timer_cb != NULL) {
+        (*(user_hw_timer_cb))();
+    }
+}
+
+/******************************************************************************
+* FunctionName : hw_timer_init
+* Description  : initilize the hardware isr timer
+* Parameters   :
+FRC1_TIMER_SOURCE_TYPE source_type:
+                        FRC1_SOURCE,    timer use frc1 isr as isr source.
+                        NMI_SOURCE,     timer use nmi isr as isr source.
+u8 req:
+                        0,  not autoload,
+                        1,  autoload mode,
+* Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR hw_timer_init(FRC1_TIMER_SOURCE_TYPE source_type, u8 req)
+{
+    if (req == 1) {
+        RTC_REG_WRITE(FRC1_CTRL_ADDRESS,
+                      FRC1_AUTO_LOAD | DIVDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT);
+    } else {
+        RTC_REG_WRITE(FRC1_CTRL_ADDRESS,
+                      DIVDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT);
+    }
+
+    if (source_type == NMI_SOURCE) {
+        ETS_FRC_TIMER1_NMI_INTR_ATTACH(hw_timer_isr_cb);
+    } else {
+        ETS_FRC_TIMER1_INTR_ATTACH(hw_timer_isr_cb, NULL);
+    }
+
+    TM1_EDGE_INT_ENABLE();
+    ETS_FRC1_INTR_ENABLE();
+}
+
+//-------------------------------Test Code Below--------------------------------------
+#if 0
+void   hw_test_timer_cb(void)
+{
+    static uint16 j = 0;
+    j++;
+
+    if ((WDEV_NOW() - tick_now2) >= 1000000) {
+        static u32 idx = 1;
+        tick_now2 = WDEV_NOW();
+        os_printf("b%u:%d\n", idx++, j);
+        j = 0;
+    }
+
+    //hw_timer_arm(50);
+}
+
+void ICACHE_FLASH_ATTR user_init(void)
+{
+    hw_timer_init(FRC1_SOURCE, 1);
+    hw_timer_set_func(hw_test_timer_cb);
+    hw_timer_arm(100);
+}
+#endif
+/*
+NOTE:
+1 if use nmi source, for autoload timer , the timer setting val can't be less than 100.
+2 if use nmi source, this timer has highest priority, can interrupt other isr.
+3 if use frc1 source, this timer can't interrupt other isr.
+
+*/
+

+ 330 - 0
driver/i2c_master.c

@@ -0,0 +1,330 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "ets_sys.h"
+#include "osapi.h"
+#include "gpio.h"
+
+#include "driver/i2c_master.h"
+
+LOCAL uint8 m_nLastSDA;
+LOCAL uint8 m_nLastSCL;
+
+/******************************************************************************
+ * FunctionName : i2c_master_setDC
+ * Description  : Internal used function -
+ *                    set i2c SDA and SCL bit value for half clk cycle
+ * Parameters   : uint8 SDA
+ *                uint8 SCL
+ * Returns      : NONE
+*******************************************************************************/
+LOCAL void ICACHE_FLASH_ATTR
+i2c_master_setDC(uint8 SDA, uint8 SCL)
+{
+    SDA	&= 0x01;
+    SCL	&= 0x01;
+    m_nLastSDA = SDA;
+    m_nLastSCL = SCL;
+
+    if ((0 == SDA) && (0 == SCL)) {
+        I2C_MASTER_SDA_LOW_SCL_LOW();
+    } else if ((0 == SDA) && (1 == SCL)) {
+        I2C_MASTER_SDA_LOW_SCL_HIGH();
+    } else if ((1 == SDA) && (0 == SCL)) {
+        I2C_MASTER_SDA_HIGH_SCL_LOW();
+    } else {
+        I2C_MASTER_SDA_HIGH_SCL_HIGH();
+    }
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_getDC
+ * Description  : Internal used function -
+ *                    get i2c SDA bit value
+ * Parameters   : NONE
+ * Returns      : uint8 - SDA bit value
+*******************************************************************************/
+LOCAL uint8 ICACHE_FLASH_ATTR
+i2c_master_getDC(void)
+{
+    uint8 sda_out;
+    sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
+    return sda_out;
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_init
+ * Description  : initilize I2C bus to enable i2c operations
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_init(void)
+{
+    uint8 i;
+
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+
+    // when SCL = 0, toggle SDA to clear up
+    i2c_master_setDC(0, 0) ;
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 0) ;
+    i2c_master_wait(5);
+
+    // set data_cnt to max value
+    for (i = 0; i < 28; i++) {
+        i2c_master_setDC(1, 0);
+        i2c_master_wait(5);	// sda 1, scl 0
+        i2c_master_setDC(1, 1);
+        i2c_master_wait(5);	// sda 1, scl 1
+    }
+
+    // reset all
+    i2c_master_stop();
+    return;
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_gpio_init
+ * Description  : config SDA and SCL gpio to open-drain output mode,
+ *                mux and gpio num defined in i2c_master.h
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_gpio_init(void)
+{
+    ETS_GPIO_INTR_DISABLE() ;
+//    ETS_INTR_LOCK();
+
+    PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC);
+    PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC);
+
+    GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
+    GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SDA_GPIO));
+    GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
+    GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SCL_GPIO));
+
+    I2C_MASTER_SDA_HIGH_SCL_HIGH();
+
+    ETS_GPIO_INTR_ENABLE() ;
+//    ETS_INTR_UNLOCK();
+
+    i2c_master_init();
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_start
+ * Description  : set i2c to send state
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_start(void)
+{
+    i2c_master_setDC(1, m_nLastSCL);
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 1);
+    i2c_master_wait(5);	// sda 1, scl 1
+    i2c_master_setDC(0, 1);
+    i2c_master_wait(5);	// sda 0, scl 1
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_stop
+ * Description  : set i2c to stop sending state
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_stop(void)
+{
+    i2c_master_wait(5);
+
+    i2c_master_setDC(0, m_nLastSCL);
+    i2c_master_wait(5);	// sda 0
+    i2c_master_setDC(0, 1);
+    i2c_master_wait(5);	// sda 0, scl 1
+    i2c_master_setDC(1, 1);
+    i2c_master_wait(5);	// sda 1, scl 1
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_setAck
+ * Description  : set ack to i2c bus as level value
+ * Parameters   : uint8 level - 0 or 1
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_setAck(uint8 level)
+{
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);
+    i2c_master_setDC(level, 0);
+    i2c_master_wait(5);	// sda level, scl 0
+    i2c_master_setDC(level, 1);
+    i2c_master_wait(8);	// sda level, scl 1
+    i2c_master_setDC(level, 0);
+    i2c_master_wait(5);	// sda level, scl 0
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_getAck
+ * Description  : confirm if peer send ack
+ * Parameters   : NONE
+ * Returns      : uint8 - ack value, 0 or 1
+*******************************************************************************/
+uint8 ICACHE_FLASH_ATTR
+i2c_master_getAck(void)
+{
+    uint8 retVal;
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 1);
+    i2c_master_wait(5);
+
+    retVal = i2c_master_getDC();
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+
+    return retVal;
+}
+
+/******************************************************************************
+* FunctionName : i2c_master_checkAck
+* Description  : get dev response
+* Parameters   : NONE
+* Returns      : true : get ack ; false : get nack
+*******************************************************************************/
+bool ICACHE_FLASH_ATTR
+i2c_master_checkAck(void)
+{
+    if(i2c_master_getAck()){
+        return FALSE;
+    }else{
+        return TRUE;
+    }
+}
+
+/******************************************************************************
+* FunctionName : i2c_master_send_ack
+* Description  : response ack
+* Parameters   : NONE
+* Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_send_ack(void)
+{
+    i2c_master_setAck(0x0);
+}
+/******************************************************************************
+* FunctionName : i2c_master_send_nack
+* Description  : response nack
+* Parameters   : NONE
+* Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_send_nack(void)
+{
+    i2c_master_setAck(0x1);
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_readByte
+ * Description  : read Byte from i2c bus
+ * Parameters   : NONE
+ * Returns      : uint8 - readed value
+*******************************************************************************/
+uint8 ICACHE_FLASH_ATTR
+i2c_master_readByte(void)
+{
+    uint8 retVal = 0;
+    uint8 k, i;
+
+    i2c_master_wait(5);
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);	// sda 1, scl 0
+
+    for (i = 0; i < 8; i++) {
+        i2c_master_wait(5);
+        i2c_master_setDC(1, 0);
+        i2c_master_wait(5);	// sda 1, scl 0
+        i2c_master_setDC(1, 1);
+        i2c_master_wait(5);	// sda 1, scl 1
+
+        k = i2c_master_getDC();
+        i2c_master_wait(5);
+
+        if (i == 7) {
+            i2c_master_wait(3);   ////
+        }
+
+        k <<= (7 - i);
+        retVal |= k;
+    }
+
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);	// sda 1, scl 0
+
+    return retVal;
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_writeByte
+ * Description  : write wrdata value(one byte) into i2c
+ * Parameters   : uint8 wrdata - write value
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_writeByte(uint8 wrdata)
+{
+    uint8 dat;
+    sint8 i;
+
+    i2c_master_wait(5);
+
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);
+
+    for (i = 7; i >= 0; i--) {
+        dat = wrdata >> i;
+        i2c_master_setDC(dat, 0);
+        i2c_master_wait(5);
+        i2c_master_setDC(dat, 1);
+        i2c_master_wait(5);
+
+        if (i == 0) {
+            i2c_master_wait(3);   ////
+        }
+
+        i2c_master_setDC(dat, 0);
+        i2c_master_wait(5);
+    }
+}

+ 176 - 0
driver/key.c

@@ -0,0 +1,176 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "ets_sys.h"
+#include "os_type.h"
+#include "osapi.h"
+#include "mem.h"
+#include "gpio.h"
+#include "user_interface.h"
+
+#include "driver/key.h"
+
+LOCAL void key_intr_handler(struct keys_param *keys);
+
+/******************************************************************************
+ * FunctionName : key_init_single
+ * Description  : init single key's gpio and register function
+ * Parameters   : uint8 gpio_id - which gpio to use
+ *                uint32 gpio_name - gpio mux name
+ *                uint32 gpio_func - gpio function
+ *                key_function long_press - long press function, needed to install
+ *                key_function short_press - short press function, needed to install
+ * Returns      : single_key_param - single key parameter, needed by key init
+*******************************************************************************/
+struct single_key_param *ICACHE_FLASH_ATTR
+key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press)
+{
+    struct single_key_param *single_key = (struct single_key_param *)os_zalloc(sizeof(struct single_key_param));
+
+    single_key->gpio_id = gpio_id;
+    single_key->gpio_name = gpio_name;
+    single_key->gpio_func = gpio_func;
+    single_key->long_press = long_press;
+    single_key->short_press = short_press;
+
+    return single_key;
+}
+
+/******************************************************************************
+ * FunctionName : key_init
+ * Description  : init keys
+ * Parameters   : key_param *keys - keys parameter, which inited by key_init_single
+ * Returns      : none
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+key_init(struct keys_param *keys)
+{
+    uint8 i;
+
+    ETS_GPIO_INTR_ATTACH(key_intr_handler, keys);
+
+    ETS_GPIO_INTR_DISABLE();
+
+    for (i = 0; i < keys->key_num; i++) {
+        keys->single_key[i]->key_level = 1;
+
+        PIN_FUNC_SELECT(keys->single_key[i]->gpio_name, keys->single_key[i]->gpio_func);
+
+        gpio_output_set(0, 0, 0, GPIO_ID_PIN(keys->single_key[i]->gpio_id));
+
+        gpio_register_set(GPIO_PIN_ADDR(keys->single_key[i]->gpio_id), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE)
+                          | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE)
+                          | GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));
+
+        //clear gpio14 status
+        GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(keys->single_key[i]->gpio_id));
+
+        //enable interrupt
+        gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_NEGEDGE);
+    }
+
+    ETS_GPIO_INTR_ENABLE();
+}
+
+/******************************************************************************
+ * FunctionName : key_5s_cb
+ * Description  : long press 5s timer callback
+ * Parameters   : single_key_param *single_key - single key parameter
+ * Returns      : none
+*******************************************************************************/
+LOCAL void ICACHE_FLASH_ATTR
+key_5s_cb(struct single_key_param *single_key)
+{
+    os_timer_disarm(&single_key->key_5s);
+
+    // low, then restart
+    if (0 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {
+        if (single_key->long_press) {
+            single_key->long_press();
+        }
+    }
+}
+
+/******************************************************************************
+ * FunctionName : key_50ms_cb
+ * Description  : 50ms timer callback to check it's a real key push
+ * Parameters   : single_key_param *single_key - single key parameter
+ * Returns      : none
+*******************************************************************************/
+LOCAL void ICACHE_FLASH_ATTR
+key_50ms_cb(struct single_key_param *single_key)
+{
+    os_timer_disarm(&single_key->key_50ms);
+
+    // high, then key is up
+    if (1 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {
+        os_timer_disarm(&single_key->key_5s);
+        single_key->key_level = 1;
+        gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_NEGEDGE);
+
+        if (single_key->short_press) {
+            single_key->short_press();
+        }
+    } else {
+        gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_POSEDGE);
+    }
+}
+
+/******************************************************************************
+ * FunctionName : key_intr_handler
+ * Description  : key interrupt handler
+ * Parameters   : key_param *keys - keys parameter, which inited by key_init_single
+ * Returns      : none
+*******************************************************************************/
+LOCAL void
+key_intr_handler(struct keys_param *keys)
+{
+    uint8 i;
+    uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
+
+    for (i = 0; i < keys->key_num; i++) {
+        if (gpio_status & BIT(keys->single_key[i]->gpio_id)) {
+            //disable interrupt
+            gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_DISABLE);
+
+            //clear interrupt status
+            GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(keys->single_key[i]->gpio_id));
+
+            if (keys->single_key[i]->key_level == 1) {
+                // 5s, restart & enter softap mode
+                os_timer_disarm(&keys->single_key[i]->key_5s);
+                os_timer_setfn(&keys->single_key[i]->key_5s, (os_timer_func_t *)key_5s_cb, keys->single_key[i]);
+                os_timer_arm(&keys->single_key[i]->key_5s, 5000, 0);
+                keys->single_key[i]->key_level = 0;
+                gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_POSEDGE);
+            } else {
+                // 50ms, check if this is a real key up
+                os_timer_disarm(&keys->single_key[i]->key_50ms);
+                os_timer_setfn(&keys->single_key[i]->key_50ms, (os_timer_func_t *)key_50ms_cb, keys->single_key[i]);
+                os_timer_arm(&keys->single_key[i]->key_50ms, 50, 0);
+            }
+        }
+    }
+}
+

+ 457 - 0
driver/sdio_slv.c

@@ -0,0 +1,457 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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/slc_register.h"
+#include "driver/sdio_slv.h"
+#include "ets_sys.h"
+#include "osapi.h"
+#include "os_type.h"
+//#include "gpio.h"
+#include "user_interface.h"
+#include "mem.h"
+
+#define SDIO_TOKEN_SIZE		0//4
+#define RX_BUFFER_SIZE      512
+#define RX_BUFFER_NUM       4
+
+#define TX_BUFFER_SIZE		512
+#define SLC_INTEREST_EVENT (SLC_TX_EOF_INT_ENA | SLC_RX_EOF_INT_ENA | SLC_RX_UDF_INT_ENA | SLC_TX_DSCR_ERR_INT_ENA)
+#define TRIG_TOHOST_INT()	SET_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0);\
+							//CLEAR_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0)
+struct sdio_queue
+{
+	uint32	blocksize:12;
+	uint32	datalen:12;
+	uint32	unused:5;
+	uint32	sub_sof:1;
+	uint32 	eof:1;
+	uint32	owner:1;
+
+	uint32	buf_ptr;
+	uint32	next_link_ptr;
+};
+
+struct sdio_slave_status_element
+{
+	uint32 wr_busy:1;
+	uint32 rd_empty :1;
+	uint32 comm_cnt :3;
+	uint32 intr_no :3;
+	uint32 rx_length:16;
+	uint32 res:8;
+};
+
+union sdio_slave_status
+{
+	struct sdio_slave_status_element elm_value;
+	uint32 word_value;
+};
+
+//uint8 rx_buffer[RX_BUFFER_NUM][RX_BUFFER_SIZE],tx_buffer[1024];
+uint8 tx_buffer[TX_BUFFER_SIZE];
+
+uint32 data_len = 0;
+
+struct sdio_list {
+	uint8 buffer[RX_BUFFER_SIZE + SDIO_TOKEN_SIZE];
+	uint8* tail;
+	struct sdio_list* next;
+};
+
+static sdio_recv_data_callback_t sdio_recv_data_callback_ptr = NULL;
+struct sdio_list* pHead_ToSend;
+struct sdio_list* pTail_ToSend;
+struct sdio_list* pHead_Sended;
+struct sdio_list* pTail_Sended;
+
+
+
+os_event_t * sdioQueue;
+struct sdio_queue rx_que,tx_que;
+
+static bool has_read = 0;
+
+static void sdio_slave_isr(void *para);
+static void tx_buff_handle_done(void);
+static void rx_buff_read_done(void);
+static void tx_buff_write_done(void);
+
+static void sdio_try_to_load(void);
+static void sdio_read_done_process(void);
+
+void sdio_slave_init(void)
+{
+    uint32 regval = 0;
+    union sdio_slave_status sdio_sta;
+    ETS_SDIO_INTR_DISABLE();
+    ////reset orginal link
+    SET_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST);
+    CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST);
+
+    os_printf("RX&TX link reset!\n");
+
+    //set sdio mode
+    SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_EOF_MODE | SLC_RX_FILL_MODE);
+    //clear to host interrupt io signal for preventing from random initial signal.
+    WRITE_PERI_REG(SLC_HOST_INTR_CLR, 0xffffffff);
+    //enable 2 events to trigger the to host intr io
+    SET_PERI_REG_MASK(SLC_HOST_INTR_ENA , SLC_HOST_TOHOST_BIT0_INT_ENA);
+    ////initialize rx queue information
+
+    has_read = TRUE;
+	pHead_ToSend = NULL;
+
+	int loop = RX_BUFFER_NUM;
+	struct sdio_list* p = NULL;
+	while(loop--) {
+		if(pHead_Sended == NULL) {
+			pHead_Sended = (struct sdio_list*)os_malloc(sizeof(struct sdio_list));
+			p = pHead_Sended;
+		} else {
+			p->next = (struct sdio_list*)os_malloc(sizeof(struct sdio_list));
+			p = p->next;
+		}
+		//os_printf("p:0x%08x\r\n",p);
+		p->tail = p->buffer + SDIO_TOKEN_SIZE;
+		p->next = NULL;
+	}
+	pTail_Sended = p;
+	
+    rx_que.blocksize = RX_BUFFER_SIZE;
+    rx_que.datalen=0;
+    rx_que.eof=1;
+    rx_que.owner=1;
+    rx_que.sub_sof=0;
+    rx_que.unused=0;
+    rx_que.buf_ptr=(uint32)pHead_Sended->buffer;
+    rx_que.next_link_ptr=0;
+
+
+    ////initialize tx queue information
+    tx_que.blocksize=TX_BUFFER_SIZE;
+    tx_que.datalen=0;
+    tx_que.eof=0;
+    tx_que.owner=1;
+    tx_que.sub_sof=0;
+    tx_que.unused=0;
+    tx_que.buf_ptr=(uint32)tx_buffer;
+    tx_que.next_link_ptr=0;
+
+    ///////link tx&rx queue information address to sdio hardware
+    CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK);
+    regval= ((uint32)&rx_que);
+    SET_PERI_REG_MASK(SLC_RX_LINK, regval&SLC_RXLINK_DESCADDR_MASK);
+    CLEAR_PERI_REG_MASK(SLC_TX_LINK,SLC_TXLINK_DESCADDR_MASK);
+    regval= ((uint32)&tx_que);
+    SET_PERI_REG_MASK(SLC_TX_LINK, regval&SLC_TXLINK_DESCADDR_MASK);
+
+#if (SDIO_TOKEN_SIZE == 0)
+    SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_TOKEN_NO_REPLACE);
+#endif
+
+    /////config sdio_status reg
+    sdio_sta.elm_value.comm_cnt=7;
+    sdio_sta.elm_value.intr_no=INIT_STAGE;
+    sdio_sta.elm_value.wr_busy=0;
+    sdio_sta.elm_value.rd_empty=1;
+    sdio_sta.elm_value.rx_length=0;
+    sdio_sta.elm_value.res=0;
+    SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START);
+    WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);
+
+
+    /////attach isr func to sdio interrupt
+    ETS_SDIO_INTR_ATTACH(sdio_slave_isr, NULL);
+    /////enable sdio operation intr
+    WRITE_PERI_REG(SLC_INT_ENA,  SLC_INTEREST_EVENT);
+    /////clear sdio initial random active intr signal
+    WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
+    /////enable sdio intr in cpu
+    ETS_SDIO_INTR_ENABLE();
+}
+
+static void sdio_slave_isr(void *para)
+{
+    uint32 slc_intr_status,postval;
+    static uint8 state =0;
+    uint16 rx_len,i;
+    uint32* pword;
+    union sdio_slave_status sdio_sta;
+
+    slc_intr_status = READ_PERI_REG(SLC_INT_STATUS);
+
+    if (slc_intr_status == 0)
+    {
+        /* No interested interrupts pending */
+        return;
+    }
+    //clear all intrs
+    WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status);
+    //os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status);
+    //process every intr
+
+    //TO HOST DONE
+    if (slc_intr_status & SLC_RX_EOF_INT_ENA)
+    {
+        //following code must be called after a data pack has been read
+        rx_buff_read_done();
+        //TRIG_TOHOST_INT();
+        //system_os_post(2, 1, 0);
+		sdio_read_done_process();
+    }
+
+    //FROM HOST DONE
+    if (slc_intr_status & SLC_TX_EOF_INT_ENA)
+    {
+        //call the following function after host cpu data transmission finished
+        tx_buff_write_done();
+
+        //system_os_post(USER_TASK_PRIO_1,SDIO_DATA_ERROR,0);
+        //os_printf("%d,%s\r\n",tx_que.datalen,tx_que.buf_ptr);
+        //at_fake_uart_rx((uint8*)tx_que.buf_ptr,tx_que.datalen);
+		if(sdio_recv_data_callback_ptr) {
+			sdio_recv_data_callback_ptr((uint8*)tx_que.buf_ptr,tx_que.datalen);
+		}
+        tx_buff_handle_done();
+        TRIG_TOHOST_INT();
+		//system_os_post(2, 3, 0);
+    }
+
+    //TO HOST underflow
+    if(slc_intr_status & SLC_RX_UDF_INT_ENA)
+    {
+    }
+
+    //FROM HOST overflow
+    if(slc_intr_status & SLC_TX_DSCR_ERR_INT_ENA)
+    {
+    }
+
+    slc_intr_status = READ_PERI_REG(SLC_INT_STATUS);
+    if(slc_intr_status)
+    {
+        WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status);
+        os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status);
+    }
+
+}
+
+static void rx_buff_read_done(void)
+{
+    union sdio_slave_status sdio_sta;
+    /////modify sdio status reg
+    sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
+    sdio_sta.elm_value.comm_cnt++;
+    sdio_sta.elm_value.rd_empty=1;
+    sdio_sta.elm_value.rx_length=0;
+    sdio_sta.elm_value.intr_no &= (~RX_AVAILIBLE);
+    WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);  //update sdio status register
+    //os_printf("rx_buff_read_done\r\n");
+}
+
+static void tx_buff_write_done(void)
+{
+    union sdio_slave_status sdio_sta;
+    /////modify sdio status reg
+    sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
+    sdio_sta.elm_value.comm_cnt++;
+    sdio_sta.elm_value.wr_busy=1;
+	sdio_sta.elm_value.intr_no &= (~TX_AVAILIBLE);
+    WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);  //update sdio status register
+}
+
+static void tx_buff_handle_done(void)
+{
+    union sdio_slave_status sdio_sta;
+
+    /////config tx queue information
+    tx_que.blocksize=TX_BUFFER_SIZE;
+    tx_que.datalen=0;
+    tx_que.eof=0;
+    tx_que.owner=1;
+
+    /////modify sdio status reg
+    sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
+    sdio_sta.elm_value.wr_busy=0;
+    sdio_sta.elm_value.intr_no |= TX_AVAILIBLE;
+
+    SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START);       //tx buffer is ready for being written
+    WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);  //update sdio status register
+    //*******************************************************************//
+
+}
+static int32 rx_buff_load_done(uint16 rx_len)
+{
+    union sdio_slave_status sdio_sta;
+
+	if(rx_len == 0) {
+		return 0;
+	}
+    if(rx_len > rx_que.blocksize)
+    {
+        rx_len = rx_que.blocksize;
+    }
+
+    //os_memcpy(rx_que.buf_ptr,data,rx_len);
+    /////config rx queue information
+    rx_que.blocksize=RX_BUFFER_SIZE;
+    rx_que.datalen=rx_len + SDIO_TOKEN_SIZE;
+    rx_que.eof=1;
+    rx_que.owner=1;
+
+    //ETS_SDIO_INTR_DISABLE();
+    //available_buffer_amount--;
+
+    /////modify sdio status reg
+    sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
+    sdio_sta.elm_value.rd_empty=0;
+    sdio_sta.elm_value.intr_no |= RX_AVAILIBLE;
+    sdio_sta.elm_value.rx_length=rx_len;
+
+    SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START);       //rx buffer is ready for being read
+    WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);  //update sdio status register
+    //ETS_SDIO_INTR_ENABLE();
+    //os_printf("rx_buff_load_done(%d,0x%08x):%s\r\n",rx_len,rx_que.buf_ptr,rx_que.buf_ptr);
+    //os_printf("rx_buff_load_done:%d\r\n",rx_len);
+    return rx_len;
+}
+
+int32 ICACHE_FLASH_ATTR sdio_load_data(const uint8* data,uint32 len)
+{
+    int32 data_len = 0;
+
+	if (pHead_Sended == NULL) {
+		os_printf("no buf\r\n");
+		return 0;
+	}
+    int32 left_len = 0;
+    
+    while(len)
+    {
+		left_len = RX_BUFFER_SIZE + SDIO_TOKEN_SIZE - (uint32)(pHead_Sended->tail - pHead_Sended->buffer);
+        if(len < left_len)
+        {
+            os_memcpy(pHead_Sended->tail,data,len);
+			pHead_Sended->tail += len;
+			len = 0;
+			data_len += len;
+            //os_printf(">555:0x%08x,0x%08x\r\n",pHead_Sended->buffer,pHead_Sended->tail);
+        }
+        else
+        {
+            os_memcpy(pHead_Sended->tail,data,left_len);
+			pHead_Sended->tail += left_len;
+			len -= left_len;
+			data += left_len;
+			data_len += left_len;
+			if(pHead_ToSend == NULL) {
+				pTail_ToSend = pHead_Sended;
+				pHead_ToSend = pTail_ToSend;
+			} else {
+				pTail_ToSend->next = pHead_Sended;
+				pTail_ToSend = pTail_ToSend->next;
+			}
+			pHead_Sended = pHead_Sended->next;
+			
+			pTail_ToSend->next = NULL;
+            if(pHead_Sended == NULL)
+            {
+                os_printf("buf full\r\n");
+                break;
+            }
+            //os_printf(">666\r\n");
+        }
+    }
+
+	//os_printf(">>pHead_ToSend:0x%08x\r\n",pHead_ToSend);
+	
+	if(pHead_ToSend == NULL) {
+		pTail_ToSend = pHead_Sended;
+		pHead_ToSend = pTail_ToSend;
+
+		pHead_Sended = pHead_Sended->next;
+		pTail_ToSend->next = NULL;
+		//system_os_post(2, 2, 0);
+		sdio_try_to_load();
+	}
+    return data_len;
+}
+
+static void sdio_try_to_load(void)
+{
+	if((has_read == TRUE) && (pHead_ToSend != NULL))
+        {
+            rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;
+            rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
+			//pHead_ToSend = pHead_ToSend->next;
+            has_read = FALSE;
+            //os_printf("SLC_INT_STATUS:0x%08x\r\n",READ_PERI_REG(SLC_INT_STATUS));
+            TRIG_TOHOST_INT();
+        }
+}
+
+static void sdio_read_done_process(void)
+{
+	has_read = TRUE;
+		
+	pHead_ToSend->tail = pHead_ToSend->buffer + SDIO_TOKEN_SIZE;
+	if(pHead_Sended) {
+       	pTail_Sended->next = pHead_ToSend;
+		pTail_Sended = pTail_Sended->next;
+	}else {
+		pTail_Sended = pHead_ToSend;
+		pHead_Sended = pTail_Sended;
+	}
+	pHead_ToSend = pHead_ToSend->next;
+	pTail_Sended->next = NULL;
+	//os_printf(">>pHead_ToSend:0x%08x,pHead_Sended:0x%08x,0x%08x,0x%08x\r\n",pHead_ToSend,pHead_Sended,pHead_Sended->buffer,pHead_Sended->tail);
+	if(pHead_ToSend) {
+		rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;
+           rx_buff_load_done(pHead_ToSend->tail - pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
+		has_read = FALSE;
+		//os_printf("intr trig\r\n");
+		//TRIG_TOHOST_INT();
+	} else if ((pHead_Sended != NULL) && (pHead_Sended->buffer != (pHead_Sended->tail- SDIO_TOKEN_SIZE))) {
+		pHead_ToSend = pHead_Sended;
+		pTail_ToSend = pHead_ToSend;
+		pHead_Sended = pHead_Sended->next;
+		pTail_ToSend->next = NULL;
+			
+		rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;			
+        rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
+		has_read = FALSE;
+		//os_printf("intr trig\r\n");
+		//TRIG_TOHOST_INT();
+	}
+
+	TRIG_TOHOST_INT();
+}
+
+bool sdio_register_recv_cb(sdio_recv_data_callback_t cb)
+{
+	sdio_recv_data_callback_ptr = cb;
+	
+	return TRUE;
+}
+

+ 487 - 0
driver/spi.c

@@ -0,0 +1,487 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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"
+#include "driver/spi_overlap.h"
+
+#define CACHE_FLASH_CTRL_REG 0x3ff0000C
+#define CACHE_FLUSH_START_BIT BIT0
+#define CACHE_EMPTY_FLAG_BIT BIT1
+/******************************************************************************
+ * FunctionName : cache_flush
+ * Description  : clear all the cpu cache data for stability test.
+*******************************************************************************/
+void cache_flush(void)
+{
+   while(READ_PERI_REG(CACHE_FLASH_CTRL_REG)&CACHE_EMPTY_FLAG_BIT) {
+      CLEAR_PERI_REG_MASK(CACHE_FLASH_CTRL_REG, CACHE_FLUSH_START_BIT);
+      SET_PERI_REG_MASK(CACHE_FLASH_CTRL_REG, CACHE_FLUSH_START_BIT);
+   }
+   while(!(READ_PERI_REG(CACHE_FLASH_CTRL_REG)&CACHE_EMPTY_FLAG_BIT));
+   	
+   CLEAR_PERI_REG_MASK(CACHE_FLASH_CTRL_REG, CACHE_FLUSH_START_BIT);
+}
+/******************************************************************************
+ * FunctionName : spi_master_init
+ * Description  : SPI master initial function for common byte units transmission
+ * Parameters   : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_master_init(uint8 spi_no)
+{
+	uint32 regvalue; 
+
+	if(spi_no>1) 		return; //handle invalid input number
+	
+	SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND);
+	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);
+
+	WRITE_PERI_REG(SPI_CLOCK(spi_no), 
+					((3&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|
+					((1&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|
+					((3&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
+}
+/******************************************************************************
+ * FunctionName : spi_lcd_9bit_write
+ * Description  : SPI 9bits transmission function for driving LCD TM035PDZV36
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+ *				uint8 high_bit - first high bit of the data, 0 is for "0",the other value 1-255 is for "1"
+ *				uint8 low_8bit- the rest 8bits of the data.
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit)
+{
+	uint32 regvalue;
+	uint8 bytetemp;
+	if(spi_no>1) 		return; //handle invalid input number
+	
+	if(high_bit)		bytetemp=(low_8bit>>1)|0x80;
+	else				bytetemp=(low_8bit>>1)&0x7f;
+	
+	regvalue= ((8&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)bytetemp);		//configure transmission variable,9bit transmission length and first 8 command bit 
+	if(low_8bit&0x01) 	regvalue|=BIT15;        //write the 9th bit
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);		//waiting for spi module available
+	WRITE_PERI_REG(SPI_USER2(spi_no), regvalue);				//write  command and command length into spi reg
+	SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);		//transmission start
+//	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);	
+}
+/******************************************************************************
+ * FunctionName : spi_mast_byte_write
+ * Description  : SPI master 1 byte transmission function
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+ *				uint8 data- transmitted data
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_mast_byte_write(uint8 spi_no,uint8 data)
+ {
+	uint32 regvalue;
+
+	if(spi_no>1) 		return; //handle invalid input number
+
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
+	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_MISO);
+
+	//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
+	// bit15-0 is cmd value.
+	WRITE_PERI_REG(SPI_USER2(spi_no), 
+					((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)data));
+	SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);	
+ }  
+
+/******************************************************************************
+ * FunctionName : spi_byte_write_espslave
+ * Description  : SPI master 1 byte transmission function for esp8266 slave,
+ * 			transmit 1byte data to esp8266 slave buffer needs 16bit transmission ,
+ * 			first byte is command 0x04 to write slave buffer, second byte is data
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+ *				uint8 data- transmitted data
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_byte_write_espslave(uint8 spi_no,uint8 data)
+ {
+	uint32 regvalue;
+
+	if(spi_no>1) 		return; //handle invalid input number
+
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
+	SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);
+	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO|SPI_USR_ADDR|SPI_USR_DUMMY);
+
+	//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
+	// bit15-0 is cmd value.
+	//0x70000000 is for 8bits cmd, 0x04 is eps8266 slave write cmd value
+	WRITE_PERI_REG(SPI_USER2(spi_no), 
+					((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|4);
+	WRITE_PERI_REG(SPI_W0(spi_no), (uint32)(data));
+	SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
+ }
+/******************************************************************************
+ * FunctionName : spi_byte_read_espslave
+ * Description  : SPI master 1 byte read function for esp8266 slave,
+ * 			read 1byte data from esp8266 slave buffer needs 16bit transmission ,
+ * 			first byte is command 0x06 to read slave buffer, second byte is recieved data
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+ *				uint8* data- recieved data address
+*******************************************************************************/
+  void ICACHE_FLASH_ATTR
+      spi_byte_read_espslave(uint8 spi_no,uint8 *data)
+ {
+	uint32 regvalue;
+
+	if(spi_no>1) 		return; //handle invalid input number
+
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
+
+	SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO);
+	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_ADDR|SPI_USR_DUMMY);
+		//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
+	// bit15-0 is cmd value.
+	//0x70000000 is for 8bits cmd, 0x06 is eps8266 slave read cmd value
+	WRITE_PERI_REG(SPI_USER2(spi_no), 
+					((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|6);
+	SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
+	
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
+	*data=(uint8)(READ_PERI_REG(SPI_W0(spi_no))&0xff);
+ }
+
+/******************************************************************************
+ * FunctionName : spi_slave_init
+ * Description  : SPI slave mode initial funtion, including mode setting,
+ * 			IO setting, transmission interrupt opening, interrupt function registration
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+ *				uint8 data_len - read&write data pack length,using byte as unit,the range is 1-32
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_slave_init(uint8 spi_no,uint8 data_len)
+{
+    uint32 regvalue; 
+    uint32 data_bit_len;
+    if(spi_no>1)
+        return; //handle invalid input number
+    if(data_len<=1) data_bit_len=7;
+    else if(data_len>=32) data_bit_len=0xff;
+    else	data_bit_len=(data_len<<3)-1;
+
+    //clear bit9,bit8 of reg PERIPHS_IO_MUX
+    //bit9 should be cleared when HSPI clock doesn't equal CPU clock
+    //bit8 should be cleared when SPI clock doesn't equal CPU clock
+    ////WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9//TEST
+    if(spi_no==SPI){
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode	
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode	
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode	
+    }else if(spi_no==HSPI){
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode	
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode	
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode	
+    }
+
+    //regvalue=READ_PERI_REG(SPI_FLASH_SLAVE(spi_no));
+    //slave mode,slave use buffers which are register "SPI_FLASH_C0~C15", enable trans done isr
+    //set bit 30 bit 29 bit9,bit9 is trans done isr mask
+    SET_PERI_REG_MASK(	SPI_SLAVE(spi_no), 
+    						SPI_SLAVE_MODE|SPI_SLV_WR_RD_BUF_EN|
+                                         	SPI_SLV_WR_BUF_DONE_EN|SPI_SLV_RD_BUF_DONE_EN|
+                                         	SPI_SLV_WR_STA_DONE_EN|SPI_SLV_RD_STA_DONE_EN|
+                                         	SPI_TRANS_DONE_EN);
+    //disable general trans intr 
+    //CLEAR_PERI_REG_MASK(SPI_SLAVE(spi_no),SPI_TRANS_DONE_EN);
+
+    CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);//disable flash operation mode
+    SET_PERI_REG_MASK(SPI_USER(spi_no),SPI_USR_MISO_HIGHPART);//SLAVE SEND DATA BUFFER IN C8-C15 
+
+
+//////**************RUN WHEN SLAVE RECIEVE*******************///////
+   //tow lines below is to configure spi timing.
+    SET_PERI_REG_MASK(SPI_CTRL2(spi_no),(0x2&SPI_MOSI_DELAY_NUM)<<SPI_MOSI_DELAY_NUM_S) ;//delay num
+    os_printf("SPI_CTRL2 is %08x\n",READ_PERI_REG(SPI_CTRL2(spi_no)));
+    WRITE_PERI_REG(SPI_CLOCK(spi_no), 0);
+
+
+    
+/////***************************************************//////	
+
+    //set 8 bit slave command length, because slave must have at least one bit addr, 
+    //8 bit slave+8bit addr, so master device first 2 bytes can be regarded as a command 
+    //and the  following bytes are datas, 
+    //32 bytes input wil be stored in SPI_FLASH_C0-C7
+    //32 bytes output data should be set to SPI_FLASH_C8-C15
+    WRITE_PERI_REG(SPI_USER2(spi_no), (0x7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S); //0x70000000
+
+    //set 8 bit slave recieve buffer length, the buffer is SPI_FLASH_C0-C7
+    //set 8 bit slave status register, which is the low 8 bit of register "SPI_FLASH_STATUS"
+    SET_PERI_REG_MASK(SPI_SLAVE1(spi_no),  ((data_bit_len&SPI_SLV_BUF_BITLEN)<< SPI_SLV_BUF_BITLEN_S)|
+                                                                                        ((0x7&SPI_SLV_STATUS_BITLEN)<<SPI_SLV_STATUS_BITLEN_S)|
+                                                                                       ((0x7&SPI_SLV_WR_ADDR_BITLEN)<<SPI_SLV_WR_ADDR_BITLEN_S)|
+                                                                                       ((0x7&SPI_SLV_RD_ADDR_BITLEN)<<SPI_SLV_RD_ADDR_BITLEN_S));
+    
+    SET_PERI_REG_MASK(SPI_PIN(spi_no),BIT19);//BIT19   
+
+    //maybe enable slave transmission liston 
+    SET_PERI_REG_MASK(SPI_CMD(spi_no),SPI_USR);
+    //register level2 isr function, which contains spi, hspi and i2s events
+    ETS_SPI_INTR_ATTACH(spi_slave_isr_handler,NULL);
+    //enable level2 isr, which contains spi, hspi and i2s events
+    ETS_SPI_INTR_ENABLE(); 
+}
+
+
+
+
+
+/* =============================================================================================
+ * code below is for spi slave r/w testcase with 2 r/w state lines connected to the spi master mcu
+ * replace with your own process functions
+ * find "add system_os_post here" in spi_slave_isr_handler.
+ * =============================================================================================
+ */
+
+
+
+
+
+
+
+#ifdef SPI_SLAVE_DEBUG
+ /******************************************************************************
+ * FunctionName : hspi_master_readwrite_repeat
+ * Description  : SPI master test  function for reading and writing esp8266 slave buffer,
+ 			the function uses HSPI module 
+*******************************************************************************/
+os_timer_t timer2;
+
+void hspi_master_readwrite_repeat(void)
+{
+	static uint8 data=0;
+	uint8 temp;
+
+	os_timer_disarm(&timer2);
+	spi_byte_read_espslave(HSPI,&temp);
+
+	temp++;
+	spi_byte_write_espslave(HSPI,temp);
+       os_timer_setfn(&timer2, (os_timer_func_t *)hspi_master_readwrite_repeat, NULL);
+       os_timer_arm(&timer2, 500, 0);
+}
+#endif
+
+
+/******************************************************************************
+ * FunctionName : spi_slave_isr_handler
+ * Description  : SPI interrupt function, SPI HSPI and I2S interrupt can trig this function
+ 			   some basic operation like clear isr flag has been done, 
+ 			   and it is availible	for adding user coder in the funtion
+ * Parameters  : void *para- function parameter address, which has been registered in function spi_slave_init
+*******************************************************************************/
+#include "gpio.h"
+#include "user_interface.h"
+#include "mem.h"
+static uint8 spi_data[32] = {0};
+static uint8 idx = 0;
+static uint8 spi_flg = 0;
+#define SPI_MISO
+#define SPI_QUEUE_LEN 8
+os_event_t * spiQueue;
+#define MOSI  0
+#define MISO  1
+#define STATUS_R_IN_WR 2
+#define STATUS_W  3
+#define TR_DONE_ALONE  4
+#define WR_RD 5
+#define DATA_ERROR 6
+#define STATUS_R_IN_RD 7
+//init the two intr line of slave
+//gpio0: wr_ready ,and  
+//gpio2: rd_ready , controlled by slave
+void ICACHE_FLASH_ATTR
+    gpio_init()
+{
+
+    	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
+	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
+	//PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
+    	GPIO_OUTPUT_SET(0, 1);
+    	GPIO_OUTPUT_SET(2, 0);
+	//GPIO_OUTPUT_SET(4, 1);
+}
+
+
+
+void spi_slave_isr_handler(void *para)
+{
+	uint32 regvalue,calvalue;
+    	static uint8 state =0;
+	uint32 recv_data,send_data;
+
+	if(READ_PERI_REG(0x3ff00020)&BIT4){		
+        //following 3 lines is to clear isr signal
+        	CLEAR_PERI_REG_MASK(SPI_SLAVE(SPI), 0x3ff);
+    	}else if(READ_PERI_REG(0x3ff00020)&BIT7){ //bit7 is for hspi isr,
+        	regvalue=READ_PERI_REG(SPI_SLAVE(HSPI));
+         	CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),  
+								SPI_TRANS_DONE_EN|
+								SPI_SLV_WR_STA_DONE_EN|
+								SPI_SLV_RD_STA_DONE_EN|
+								SPI_SLV_WR_BUF_DONE_EN|
+								SPI_SLV_RD_BUF_DONE_EN);
+        	SET_PERI_REG_MASK(SPI_SLAVE(HSPI), SPI_SYNC_RESET);
+        	CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),  
+								SPI_TRANS_DONE|
+								SPI_SLV_WR_STA_DONE|
+								SPI_SLV_RD_STA_DONE|
+								SPI_SLV_WR_BUF_DONE|
+								SPI_SLV_RD_BUF_DONE); 
+		SET_PERI_REG_MASK(SPI_SLAVE(HSPI),  
+								SPI_TRANS_DONE_EN|
+								SPI_SLV_WR_STA_DONE_EN|
+								SPI_SLV_RD_STA_DONE_EN|
+								SPI_SLV_WR_BUF_DONE_EN|
+								SPI_SLV_RD_BUF_DONE_EN);
+
+		if(regvalue&SPI_SLV_WR_BUF_DONE){ 
+            		GPIO_OUTPUT_SET(0, 0);
+            		idx=0;
+            		while(idx<8){
+            			recv_data=READ_PERI_REG(SPI_W0(HSPI)+(idx<<2));
+            			spi_data[idx<<2] = recv_data&0xff;
+            			spi_data[(idx<<2)+1] = (recv_data>>8)&0xff;
+            			spi_data[(idx<<2)+2] = (recv_data>>16)&0xff;
+            			spi_data[(idx<<2)+3] = (recv_data>>24)&0xff;
+            			idx++;
+			}
+			//add system_os_post here
+            		GPIO_OUTPUT_SET(0, 1);
+		}
+        	if(regvalue&SPI_SLV_RD_BUF_DONE){
+			//it is necessary to call GPIO_OUTPUT_SET(2, 1), when new data is preped in SPI_W8-15 and needs to be sended.
+           		GPIO_OUTPUT_SET(2, 0);
+			//add system_os_post here
+			//system_os_post(USER_TASK_PRIO_1,WR_RD,regvalue);
+
+        	}
+    
+    }else if(READ_PERI_REG(0x3ff00020)&BIT9){ //bit7 is for i2s isr,
+
+    }
+}
+
+
+#ifdef SPI_SLAVE_DEBUG
+
+void ICACHE_FLASH_ATTR
+    set_miso_data()
+{
+    if(GPIO_INPUT_GET(2)==0){
+        WRITE_PERI_REG(SPI_W8(HSPI),0x05040302);
+        WRITE_PERI_REG(SPI_W9(HSPI),0x09080706);
+        WRITE_PERI_REG(SPI_W10(HSPI),0x0d0c0b0a);
+        WRITE_PERI_REG(SPI_W11(HSPI),0x11100f0e);
+
+        WRITE_PERI_REG(SPI_W12(HSPI),0x15141312);
+        WRITE_PERI_REG(SPI_W13(HSPI),0x19181716);
+        WRITE_PERI_REG(SPI_W14(HSPI),0x1d1c1b1a);
+        WRITE_PERI_REG(SPI_W15(HSPI),0x21201f1e);
+        GPIO_OUTPUT_SET(2, 1);
+    }
+}
+
+
+
+void ICACHE_FLASH_ATTR
+    disp_spi_data()
+{
+    uint8 i = 0;
+    for(i=0;i<32;i++){
+        os_printf("data %d : 0x%02x\n\r",i,spi_data[i]);
+    }
+    //os_printf("d31:0x%02x\n\r",spi_data[31]);
+}
+
+
+void ICACHE_FLASH_ATTR
+    spi_task(os_event_t *e)
+{
+    uint8 data;
+    switch(e->sig){
+       case MOSI:
+            	disp_spi_data();
+            	break;
+	case STATUS_R_IN_WR :
+		os_printf("SR ERR in WRPR,Reg:%08x \n",e->par);
+		break;
+	case STATUS_W:
+		os_printf("SW ERR,Reg:%08x\n",e->par);
+		break;	
+	case TR_DONE_ALONE:
+		os_printf("TD ALO ERR,Reg:%08x\n",e->par);
+		break;	
+	case WR_RD:
+		os_printf("WR&RD ERR,Reg:%08x\n",e->par);
+		break;	
+	case DATA_ERROR:
+		os_printf("Data ERR,Reg:%08x\n",e->par);
+		break;
+	case STATUS_R_IN_RD :
+		os_printf("SR ERR in RDPR,Reg:%08x\n",e->par);
+		break;	
+        default:
+            break;
+    }
+}
+
+void ICACHE_FLASH_ATTR
+    spi_task_init(void)
+{
+    spiQueue = (os_event_t*)os_malloc(sizeof(os_event_t)*SPI_QUEUE_LEN);
+    system_os_task(spi_task,USER_TASK_PRIO_1,spiQueue,SPI_QUEUE_LEN);
+}
+
+os_timer_t spi_timer_test;
+
+void ICACHE_FLASH_ATTR
+    spi_test_init()
+{
+    os_printf("spi init\n\r");
+    spi_slave_init(HSPI);
+    os_printf("gpio init\n\r");
+    gpio_init();
+    os_printf("spi task init \n\r");
+    spi_task_init();
+#ifdef SPI_MISO
+    os_printf("spi miso init\n\r");
+    set_miso_data();
+#endif
+    
+    //os_timer_disarm(&spi_timer_test);
+    //os_timer_setfn(&spi_timer_test, (os_timer_func_t *)set_miso_data, NULL);//wjl
+    //os_timer_arm(&spi_timer_test,50,1);
+}
+
+#endif
+
+

+ 502 - 0
driver/spi_interface.c

@@ -0,0 +1,502 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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.
+ *
+ */
+
+/**
+ * @file spi_interface.c
+ * @brief Defines and Macros for the SPI.
+ */
+
+#include "driver/spi_interface.h"
+#include "osapi.h"
+#include "ets_sys.h"
+
+//*****************************************************************************
+//
+// Make sure all of the definitions in this header have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @brief Based on pAttr initialize SPI module.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIInit(SpiNum spiNum, SpiAttr* pAttr)
+{
+    if ((spiNum > SpiNum_HSPI)
+        || (NULL == pAttr)) {
+        return;
+    }
+    // SPI_CPOL & SPI_CPHA
+    switch (pAttr->subMode) {
+    case SpiSubMode_1:
+        CLEAR_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE);
+        SET_PERI_REG_MASK(SPI_USER(spiNum),  SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
+        break;
+    case SpiSubMode_2:
+        SET_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE);
+        SET_PERI_REG_MASK(SPI_USER(spiNum),  SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
+        break;
+    case SpiSubMode_3:
+        SET_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE);
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum),  SPI_CK_OUT_EDGE);
+        break;
+    case SpiSubMode_0:
+    default:
+        CLEAR_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE);
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum),  SPI_CK_OUT_EDGE);
+        // To do nothing
+        break;
+    }
+
+    // SPI bit order
+    if (SpiBitOrder_MSBFirst == pAttr->bitOrder) {
+        CLEAR_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_WR_BIT_ORDER);
+        CLEAR_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_RD_BIT_ORDER);
+    } else if (SpiBitOrder_LSBFirst == pAttr->bitOrder) {
+        SET_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_WR_BIT_ORDER);
+        SET_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_RD_BIT_ORDER);
+    } else {
+        // To do nothing
+    }
+
+    // Disable flash operation mode
+    // As earlier as better, if not SPI_CTRL2 can not to be set delay cycles.
+    CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_FLASH_MODE);
+
+    // SPI mode type
+    if (SpiMode_Master == pAttr->mode) {
+        // SPI mode type
+        CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), SPI_SLAVE_MODE);
+        // SPI Send buffer
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO_HIGHPART );// By default slave send buffer C0-C7
+        // SPI Speed
+        if (1 < (pAttr->speed)) {
+            uint8 i, k;
+            i = (pAttr->speed / 40) ? (pAttr->speed / 40) : 1;
+            k = pAttr->speed / i;
+            CLEAR_PERI_REG_MASK(SPI_CLOCK(spiNum), SPI_CLK_EQU_SYSCLK);
+            WRITE_PERI_REG(SPI_CLOCK(spiNum),
+                           (((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
+                           (((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
+                           ((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
+                           (((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
+        } else {
+            WRITE_PERI_REG(SPI_CLOCK(spiNum), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
+        }
+        // By default format:CMD+ADDR+DATA
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_CS_SETUP | SPI_CS_HOLD | SPI_USR_MOSI );
+
+        //delay num
+        SET_PERI_REG_MASK(SPI_CTRL2(spiNum), ((0x1 & SPI_MISO_DELAY_NUM) << SPI_MISO_DELAY_NUM_S));
+    } else if (SpiMode_Slave == pAttr->mode) {
+        // BIT19 must do
+        SET_PERI_REG_MASK(SPI_PIN(spiNum), BIT19);
+
+        // SPI mode type
+        SET_PERI_REG_MASK(SPI_SLAVE(spiNum), SPI_SLAVE_MODE);
+        // SPI Send buffer
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO_HIGHPART);// By default slave send buffer C8-C15
+
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+
+        // If do not set delay cycles, slave not working,master cann't get the data.
+        SET_PERI_REG_MASK(SPI_CTRL2(spiNum), ((0x1 & SPI_MOSI_DELAY_NUM) << SPI_MOSI_DELAY_NUM_S)); //delay num
+        // SPI Speed
+        WRITE_PERI_REG(SPI_CLOCK(spiNum), 0);
+
+        // By default format::CMD(8bits)+ADDR(8bits)+DATA(32bytes).
+        SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN,
+                          7, SPI_USR_COMMAND_BITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_WR_ADDR_BITLEN,
+                          7, SPI_SLV_WR_ADDR_BITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_RD_ADDR_BITLEN,
+                          7, SPI_SLV_RD_ADDR_BITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_BUF_BITLEN,
+                          (32 * 8 - 1), SPI_SLV_BUF_BITLEN_S);
+        // For 8266 work on slave mode.
+        SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_STATUS_BITLEN,
+                          7, SPI_SLV_STATUS_BITLEN_S);
+    } else {
+        // To do nothing
+    }
+
+    //clear Daul or Quad lines transmission mode
+    CLEAR_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_QIO_MODE | SPI_DIO_MODE | SPI_DOUT_MODE | SPI_QOUT_MODE);
+    // Clear the data buffer.
+    uint8 i;
+    uint32 regAddr = REG_SPI_BASE(spiNum) + 0x40;
+    for (i = 0; i < 16; ++i) {
+        WRITE_PERI_REG(regAddr, 0);
+        regAddr += 4;
+    }
+    
+}
+
+/**
+ * @brief Set address value by master mode.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIMasterCfgAddr(SpiNum spiNum, uint32_t addr)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    // Set address
+    WRITE_PERI_REG(SPI_ADDR(spiNum), addr);
+}
+
+/**
+ * @brief Set command value by master mode.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIMasterCfgCmd(SpiNum spiNum, uint32_t cmd)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    // SPI_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
+    // bit15-0 is cmd value.
+    SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_VALUE, cmd, SPI_USR_COMMAND_VALUE_S);
+}
+
+/**
+ * @brief Send data to slave.
+ *
+ */
+int ICACHE_FLASH_ATTR SPIMasterSendData(SpiNum spiNum, SpiData* pInData)
+{
+    char idx = 0;
+    if ((spiNum > SpiNum_HSPI)
+        || (NULL == pInData)
+        || (64 < pInData->dataLen)) {
+        return -1;
+    }
+    uint32_t *value = pInData->data;
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+    // Set command by user.
+    if (pInData->cmdLen != 0) {
+        // Max command length 16 bits.
+        SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN,
+                          ((pInData->cmdLen << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
+        // Enable command
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND);
+        // Load command
+        SPIMasterCfgCmd(spiNum, pInData->cmd);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND);
+        SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN,
+                          0, SPI_USR_COMMAND_BITLEN_S);
+    }
+    // Set Address by user.
+    if (pInData->addrLen == 0) {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR);
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN,
+                          0, SPI_USR_ADDR_BITLEN_S);
+    } else {
+        if (NULL == pInData->addr) {
+            return -1;
+        }
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN,
+                          ((pInData->addrLen << 3) - 1), SPI_USR_ADDR_BITLEN_S);
+        // Enable address
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR);
+        // Load address
+        SPIMasterCfgAddr(spiNum, *pInData->addr);
+    }
+    // Set data by user.
+    if (pInData->dataLen != 0) {
+        if (NULL == value) {
+            return -1;
+        }
+        // Enable MOSI
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO);
+        // Load send buffer
+        do {
+            WRITE_PERI_REG((SPI_W0(spiNum) + (idx << 2)), *value++);
+        } while (++idx < ((pInData->dataLen / 4) + ((pInData->dataLen % 4) ? 1 : 0)));
+        // Set data send buffer length.Max data length 64 bytes.
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MOSI_BITLEN, ((pInData->dataLen << 3) - 1), SPI_USR_MOSI_BITLEN_S);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MOSI_BITLEN,
+                          0, SPI_USR_MOSI_BITLEN_S);
+    }
+    // Start send data
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+    // Wait for transmit done
+    while (!(READ_PERI_REG(SPI_SLAVE(spiNum))&SPI_TRANS_DONE));
+    CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), SPI_TRANS_DONE);
+    return 0;
+}
+
+/**
+ * @brief Receive data from slave.
+ *
+ */
+int ICACHE_FLASH_ATTR SPIMasterRecvData(SpiNum spiNum, SpiData* pOutData)
+{
+    char idx = 0;
+    if ((spiNum > SpiNum_HSPI)
+        || (NULL == pOutData)) {
+        return -1;
+    }
+
+    uint32_t *value = pOutData->data;
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+    // Set command by user.
+    if (pOutData->cmdLen != 0) {
+        // Max command length 16 bits.
+        SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN,
+                          ((pOutData->cmdLen << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
+        // Enable command
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND);
+        // Load command
+        SPIMasterCfgCmd(spiNum, pOutData->cmd);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND);
+        SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN,
+                          0, SPI_USR_COMMAND_BITLEN_S);
+    }
+    // Set Address by user.
+    if (pOutData->addrLen == 0) {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR);
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN,
+                          0, SPI_USR_ADDR_BITLEN_S);
+    } else {
+        if (NULL == pOutData->addr) {
+            return -1;
+        }
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN,
+                          ((pOutData->addrLen << 3) - 1), SPI_USR_ADDR_BITLEN_S);
+        // Enable address
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR);
+        // Load address
+        SPIMasterCfgAddr(spiNum, *pOutData->addr);
+    }
+    // Set data by user.
+    if (pOutData->dataLen != 0) {
+        if (NULL == value) {
+            return -1;
+        }
+        // Clear MOSI enable
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+        // Enable MOSI
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO);
+        // Set data send buffer length.Max data length 64 bytes.
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MISO_BITLEN, ((pOutData->dataLen << 3) - 1), SPI_USR_MISO_BITLEN_S);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO);
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MISO_BITLEN,
+                          0, SPI_USR_MISO_BITLEN_S);
+    }
+    // Start send data
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+    // Read data out
+    do {
+        *value++ = READ_PERI_REG(SPI_W0(spiNum) + (idx << 2));
+    } while (++idx < ((pOutData->dataLen / 4) + ((pOutData->dataLen % 4) ? 1 : 0)));
+    
+
+    return 0;
+}
+
+/**
+ * @brief Load data to send buffer by slave mode.
+ *
+ */
+int ICACHE_FLASH_ATTR SPISlaveSendData(SpiNum spiNum, uint32_t *pInData, uint8_t inLen)
+{
+    if (NULL == pInData) {
+        return -1;
+    }
+	uint32_t *value = pInData;
+    char i;
+    for (i = 0; i < inLen; ++i) {
+        WRITE_PERI_REG((SPI_W8(spiNum) + (i << 2)), *value++);
+    }
+    // Enable slave transmission liston
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+    return 0;
+}
+
+/**
+ * @brief Configurate slave prepare for receive data.
+ *
+ */
+int ICACHE_FLASH_ATTR SPISlaveRecvData(SpiNum spiNum)
+{
+    if ((spiNum > SpiNum_HSPI)) {
+        return -1;
+    }
+    // Enable slave transmission liston
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+
+    return 0;
+}
+
+/**
+ * @brief Send data to slave(ESP8266 register of RD_STATUS or WR_STATUS).
+ *
+ */
+void ICACHE_FLASH_ATTR SPIMasterSendStatus(SpiNum spiNum, uint8_t data)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+    // Enable MOSI
+    SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+    CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO | SPI_USR_DUMMY | SPI_USR_ADDR);
+
+    // 8bits cmd, 0x04 is eps8266 slave write cmd value
+    WRITE_PERI_REG(SPI_USER2(spiNum),
+                   ((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
+                   | MASTER_WRITE_STATUS_TO_SLAVE_CMD);
+    // Set data send buffer length.
+    SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MOSI_BITLEN,
+                      ((sizeof(data) << 3) - 1), SPI_USR_MOSI_BITLEN_S);
+
+    WRITE_PERI_REG(SPI_W0(spiNum), (uint32)(data));
+    // Start SPI
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+
+}
+
+/**
+ * @brief Receive status register from slave(ESP8266).
+ *
+ */
+int ICACHE_FLASH_ATTR SPIMasterRecvStatus(SpiNum spiNum)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return -1;
+    }
+
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+    // Enable MISO
+    SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO);
+    CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI | SPI_USR_DUMMY | SPI_USR_ADDR);
+
+    // 8bits cmd, 0x06 is eps8266 slave read status cmd value
+    WRITE_PERI_REG(SPI_USER2(spiNum),
+                   ((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
+                   | MASTER_READ_STATUS_FROM_SLAVE_CMD);
+    // Set revcive buffer length.
+    SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MISO_BITLEN,
+                      7, SPI_USR_MISO_BITLEN_S);
+
+    // start spi module.
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+
+    uint8_t data = (uint8)(READ_PERI_REG(SPI_W0(spiNum)) & 0xff);
+
+    return (uint8)(READ_PERI_REG(SPI_W0(spiNum)) & 0xff);
+}
+
+/**
+ * @brief Select SPI CS pin.
+ *
+ */
+void ICACHE_FLASH_ATTR SPICsPinSelect(SpiNum spiNum, SpiPinCS pinCs)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    // clear select
+    SET_PERI_REG_BITS(SPI_PIN(spiNum), 3, 0, 0);
+    SET_PERI_REG_MASK(SPI_PIN(spiNum), pinCs);
+}
+
+
+void SPIIntCfg(SpiNum spiNum, SpiIntInfo *pIntInfo)
+{
+    if ((spiNum > SpiNum_HSPI)
+        || (NULL == pIntInfo)) {
+        return;
+    }
+    // Clear the interrupt source and disable all of the interrupt.
+    CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), 0x3FF);
+    SPIIntEnable(spiNum, pIntInfo->src);
+    os_printf("src=%x\r\n,isrFunc=%x", (pIntInfo->src << 5), pIntInfo->isrFunc);
+    //
+    ETS_SPI_INTR_ATTACH(pIntInfo->isrFunc, NULL);
+    // Enable isr
+    ETS_SPI_INTR_ENABLE();    
+}
+
+
+/**
+ * @brief Enable SPI interrupt source.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIIntEnable(SpiNum spiNum, SpiIntSrc intSrc)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    SET_PERI_REG_MASK(SPI_SLAVE(spiNum), (intSrc << 5));
+}
+
+/**
+ * @brief Disable SPI interrupt source.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIIntDisable(SpiNum spiNum, SpiIntSrc intSrc)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), intSrc);
+}
+
+/**
+ * @brief Clear all of SPI interrupt source.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIIntClear(SpiNum spiNum)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), SpiIntSrc_TransDone
+                        | SpiIntSrc_WrStaDone
+                        | SpiIntSrc_RdStaDone
+                        | SpiIntSrc_WrBufDone
+                        | SpiIntSrc_RdBufDone);
+}
+
+
+#ifdef __cplusplus
+}
+#endif

+ 422 - 0
driver/spi_overlap.c

@@ -0,0 +1,422 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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_overlap.h"
+#include "driver/spi.h"
+#include "gpio.h"
+
+#define SPI_FLASH_READ_MODE_MASK 0x196000
+#define WAIT_HSPI_IDLE() 	while(READ_PERI_REG(SPI_EXT2(HSPI))||(READ_PERI_REG(SPI_CMD(HSPI))&0xfffc0000));
+#define CONF_HSPI_CLK_DIV(div)	WRITE_PERI_REG(SPI_CLOCK(HSPI), (((div<<1)+1)<<12)+(div<<6)+(div<<1)+1)
+#define HSPI_FALLING_EDGE_SAMPLE()		SET_PERI_REG_MASK(SPI_USER(HSPI),  SPI_CK_OUT_EDGE)
+#define HSPI_RISING_EDGE_SAMPLE()			CLEAR_PERI_REG_MASK(SPI_USER(HSPI),  SPI_CK_OUT_EDGE)
+#define ACTIVE_HSPI_CS0	 	CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS0_DIS);\
+						SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS1_DIS |SPI_CS2_DIS)
+#define ACTIVE_HSPI_CS1		CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS1_DIS);\
+						SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS0_DIS |SPI_CS2_DIS)
+#define ACTIVE_HSPI_CS2		CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS2_DIS);\
+						SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS0_DIS |SPI_CS1_DIS)
+#define ENABLE_HSPI_DEV_CS()		PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2)
+#define DISABLE_HSPI_DEV_CS()		GPIO_OUTPUT_SET(15, 1);\
+									PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15)
+struct hspi_device_register hspi_dev_reg;
+/******************************************************************************
+ * FunctionName : hspi_overlap_init
+ * Description  : enable hspi and spi module overlap mode
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+hspi_overlap_init(void)
+{
+	//hspi overlap to spi, two spi masters on cspi
+	SET_PERI_REG_MASK(HOST_INF_SEL, reg_cspi_overlap);
+
+	//set higher priority for spi than hspi
+	SET_PERI_REG_MASK(SPI_EXT3(SPI),0x1);
+	SET_PERI_REG_MASK(SPI_EXT3(HSPI),0x3);
+	SET_PERI_REG_MASK(SPI_USER(HSPI), BIT(5));
+}
+/******************************************************************************
+ * FunctionName : hspi_overlap_deinit
+ * Description  : recover hspi and spi module from overlap mode
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+hspi_overlap_deinit(void)
+{
+	//hspi overlap to spi, two spi masters on cspi
+	CLEAR_PERI_REG_MASK(HOST_INF_SEL, reg_cspi_overlap);
+
+	//set higher priority for spi than hspi
+	CLEAR_PERI_REG_MASK(SPI_EXT3(SPI),0x1);
+	CLEAR_PERI_REG_MASK(SPI_EXT3(HSPI),0x3);
+	CLEAR_PERI_REG_MASK(SPI_USER(HSPI), BIT(5));
+}
+
+/******************************************************************************
+ * FunctionName : spi_reg_backup
+ * Description  : backup SPI normal operation register value and disable CPU cache to modify some flash registers.
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_reg_backup(uint8 spi_no,uint32* backup_mem)
+{
+	if(spi_no>1) 		return; //handle invalid input number
+
+	backup_mem[PERIPHS_IO_MUX_BACKUP]	=READ_PERI_REG(PERIPHS_IO_MUX);
+	backup_mem[SPI_USER_BACKUP]	=READ_PERI_REG(SPI_USER(spi_no)); 	
+	backup_mem[SPI_CTRL_BACKUP]	=READ_PERI_REG(SPI_CTRL(spi_no)); 	
+	backup_mem[SPI_CLOCK_BACKUP]	=READ_PERI_REG(SPI_CLOCK(spi_no));
+	backup_mem[SPI_USER1_BACKUP]	=READ_PERI_REG(SPI_USER1(spi_no));
+	backup_mem[SPI_USER2_BACKUP]	=READ_PERI_REG(SPI_USER2(spi_no));	
+	backup_mem[SPI_CMD_BACKUP]	=READ_PERI_REG(SPI_CMD(spi_no));
+	backup_mem[SPI_PIN_BACKUP]	=READ_PERI_REG(SPI_PIN(spi_no));
+	backup_mem[SPI_SLAVE_BACKUP]	=READ_PERI_REG(SPI_SLAVE(spi_no));
+}
+/******************************************************************************
+ * FunctionName : spi_reg_recover
+ * Description  : recover SPI normal operation register value and enable CPU cache.
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+   spi_reg_recover(uint8 spi_no,uint32* backup_mem)
+{
+	if(spi_no>1) 		return; //handle invalid input number
+
+//	WRITE_PERI_REG(PERIPHS_IO_MUX, backup_mem[PERIPHS_IO_MUX_BACKUP]); 	
+	WRITE_PERI_REG(SPI_USER(spi_no), backup_mem[SPI_USER_BACKUP]); 	
+	WRITE_PERI_REG(SPI_CTRL(spi_no), backup_mem[SPI_CTRL_BACKUP]); 	
+	WRITE_PERI_REG(SPI_CLOCK(spi_no), backup_mem[SPI_CLOCK_BACKUP]); 	
+	WRITE_PERI_REG(SPI_USER1(spi_no), backup_mem[SPI_USER1_BACKUP]); 	
+	WRITE_PERI_REG(SPI_USER2(spi_no), backup_mem[SPI_USER2_BACKUP]); 	
+	WRITE_PERI_REG(SPI_CMD(spi_no), backup_mem[SPI_CMD_BACKUP]); 	
+	WRITE_PERI_REG(SPI_PIN(spi_no), backup_mem[SPI_PIN_BACKUP]); 
+//	WRITE_PERI_REG(SPI_SLAVE(spi_no), backup_mem[SPI_SLAVE_BACKUP]); 
+}
+
+void ICACHE_FLASH_ATTR  
+    hspi_master_dev_init(uint8 dev_no,uint8 clk_polar,uint8 clk_div)
+{
+	uint32 regtemp;
+	if((dev_no>3)||(clk_polar>1)||(clk_div>0x1f))
+	{
+		os_printf("hspi_master_dev_init parameter is out of range!\n\r");
+		return;
+	}
+	
+	WAIT_HSPI_IDLE();
+	if(!hspi_dev_reg.hspi_reg_backup_flag){
+		if(READ_PERI_REG(PERIPHS_IO_MUX)&BIT8){
+			hspi_dev_reg.spi_io_80m=1;
+			SET_PERI_REG_MASK(SPI_CLOCK(HSPI),SPI_CLK_EQU_SYSCLK);
+		}else{
+			hspi_dev_reg.spi_io_80m=0;
+			CLEAR_PERI_REG_MASK(SPI_CLOCK(HSPI),SPI_CLK_EQU_SYSCLK);
+		}
+		
+		regtemp=READ_PERI_REG(SPI_CTRL(SPI))&SPI_FLASH_READ_MODE_MASK;
+		CLEAR_PERI_REG_MASK(SPI_CTRL(HSPI), SPI_FLASH_READ_MODE_MASK);
+		SET_PERI_REG_MASK(SPI_CTRL(HSPI), regtemp);
+		spi_reg_backup(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+
+		spi_master_init(HSPI);
+		spi_reg_backup(HSPI, hspi_dev_reg.hspi_dev_reg_backup);
+
+		hspi_dev_reg.hspi_reg_backup_flag=1;
+		
+	//	spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+		hspi_dev_reg.selected_dev_num=HSPI_IDLE;
+	}
+
+	hspi_dev_reg.hspi_dev_conf[dev_no].active=1;
+	hspi_dev_reg.hspi_dev_conf[dev_no].clk_div=clk_div;
+	hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar=clk_polar;
+	
+	switch(dev_no){
+		case HSPI_CS_DEV :
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);	
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);
+			CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX, BIT9);
+			break;
+
+		case SPI_CS1_DEV :	
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_SPI_CS1);
+			if(hspi_dev_reg.spi_io_80m){	
+				os_printf("SPI CS1 device must work at 80Mhz");
+			}
+			break;
+			
+		case SPI_CS2_DEV :	
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_SPI_CS2);
+			if(hspi_dev_reg.spi_io_80m){	
+				os_printf("SPI CS2 device must work at 80Mhz");
+			}
+			break;
+			
+		default: break;
+	}
+}
+
+void ICACHE_FLASH_ATTR
+    hspi_dev_sel(uint8 dev_no)
+{
+	uint32 regval;
+	
+	if(dev_no>3){
+		os_printf("hspi_dev_sel parameter is out of range!\n\r");
+		return;
+	}
+
+	if(!hspi_dev_reg.hspi_dev_conf[dev_no].active){
+		os_printf("device%d has not been initialized!\n\r",dev_no);
+		return;
+	}
+	
+	switch(hspi_dev_reg.selected_dev_num){
+		case HSPI_CS_DEV:
+			if((dev_no==SPI_CS1_DEV)||(dev_no==SPI_CS2_DEV)){
+				WAIT_HSPI_IDLE();
+				DISABLE_HSPI_DEV_CS();
+				hspi_overlap_init();
+				
+				if(hspi_dev_reg.spi_io_80m)	{SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);}
+				else							{CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);}
+				
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+				
+				if(dev_no==SPI_CS1_DEV)		{ACTIVE_HSPI_CS1;}
+				else							{ACTIVE_HSPI_CS2;}
+			}
+			else if(dev_no==SPI_CS0_FLASH){
+				WAIT_HSPI_IDLE();
+				DISABLE_HSPI_DEV_CS();
+				hspi_overlap_init();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+
+				if(hspi_dev_reg.spi_io_80m)	{SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);}
+
+				HSPI_RISING_EDGE_SAMPLE();
+				ACTIVE_HSPI_CS0	;
+			}
+			break;
+
+		case SPI_CS1_DEV:
+			if(dev_no==SPI_CS2_DEV){
+				WAIT_HSPI_IDLE();
+				if(!hspi_dev_reg.spi_io_80m)	{CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);}
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+				ACTIVE_HSPI_CS2;			
+			}
+			else if(dev_no==SPI_CS0_FLASH){
+				WAIT_HSPI_IDLE();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+				HSPI_RISING_EDGE_SAMPLE();
+				ACTIVE_HSPI_CS0;
+			}
+			else if(dev_no==HSPI_CS_DEV){
+				WAIT_HSPI_IDLE();
+				ENABLE_HSPI_DEV_CS();
+				hspi_overlap_deinit();
+				CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				ACTIVE_HSPI_CS0;
+			}
+			break;
+
+		case SPI_CS2_DEV:
+			if(dev_no==SPI_CS1_DEV){
+				WAIT_HSPI_IDLE();
+				if(!hspi_dev_reg.spi_io_80m)	{CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);}
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				ACTIVE_HSPI_CS1;
+			}
+			else if(dev_no==SPI_CS0_FLASH){
+				WAIT_HSPI_IDLE();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+				HSPI_RISING_EDGE_SAMPLE();
+				ACTIVE_HSPI_CS0;
+			}
+			else if(dev_no==HSPI_CS_DEV){
+				WAIT_HSPI_IDLE();
+				ENABLE_HSPI_DEV_CS();
+				hspi_overlap_deinit();
+				CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				ACTIVE_HSPI_CS0;
+			}
+			break;
+			
+		case SPI_CS0_FLASH:
+			if((dev_no==SPI_CS1_DEV)||(dev_no==SPI_CS2_DEV)){
+				WAIT_HSPI_IDLE();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup);
+
+				if(hspi_dev_reg.spi_io_80m)	{SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);}
+				else							{CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);}
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				if(dev_no==SPI_CS1_DEV)		{ACTIVE_HSPI_CS1;}
+				else							{ACTIVE_HSPI_CS2;}			
+			}
+			else if(dev_no==HSPI_CS_DEV){
+				WAIT_HSPI_IDLE();
+				ENABLE_HSPI_DEV_CS();
+				hspi_overlap_deinit();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup);
+				CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				ACTIVE_HSPI_CS0;
+			}
+			break;
+
+		default: 
+			if((dev_no==SPI_CS1_DEV)||(dev_no==SPI_CS2_DEV)){
+				WAIT_HSPI_IDLE();
+				DISABLE_HSPI_DEV_CS();
+				hspi_overlap_init();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup);
+				
+				if(hspi_dev_reg.spi_io_80m)	{SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);}
+				else							{CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);}
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				if(dev_no==SPI_CS1_DEV)		{ACTIVE_HSPI_CS1;}
+				else							{ACTIVE_HSPI_CS2;}
+			}
+			else if(dev_no==SPI_CS0_FLASH){
+				WAIT_HSPI_IDLE();
+				DISABLE_HSPI_DEV_CS();
+				hspi_overlap_init();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+
+				if(hspi_dev_reg.spi_io_80m)	{SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);}
+				
+				HSPI_RISING_EDGE_SAMPLE();
+				ACTIVE_HSPI_CS0	;
+			}			
+			else if(dev_no==HSPI_CS_DEV){
+				WAIT_HSPI_IDLE();
+				ENABLE_HSPI_DEV_CS();
+				hspi_overlap_deinit();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup);
+				CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				ACTIVE_HSPI_CS0;
+			}
+			break;
+	}
+	hspi_dev_reg.selected_dev_num=dev_no;
+}
+
+/******************************************************************************
+ * FunctionName : spi_read_data
+ * Description  : use hspi to read flash data for stability test
+ * Parameters   : 	SpiFlashChip * spi-- flash parameter structure pointer
+ * 				uint32 flash_addr--flash start address
+ *				uint32 * addr_dest--start address for preped destination memory space
+ *				uint32 byte_length--length of the data which needs to be read from flash
+*******************************************************************************/
+SpiFlashOpResult ICACHE_FLASH_ATTR
+hspi_overlap_read_flash_data(SpiFlashChip * spi, uint32 flash_addr, uint32 * addr_dest, uint32 byte_length)
+{
+    uint32  temp_addr,reg_tmp;
+    sint32  temp_length;
+    uint8   i;
+    uint8   remain_word_num;	
+	
+   hspi_dev_sel(SPI_CS0_FLASH);
+
+      //address range check 	
+   if ((flash_addr+byte_length) > (spi->chip_size))
+   {
+        return SPI_FLASH_RESULT_ERR;
+   }
+   
+    temp_addr = flash_addr;
+    temp_length = byte_length;
+	
+    while(temp_length > 0)
+    {
+       if(temp_length >= SPI_BUFF_BYTE_NUM)
+       {
+	//   reg_tmp=((temp_addr&0xff)<<16)|(temp_addr&0xff00)|((temp_addr&0xff0000)>>16)|(SPI_BUFF_BYTE_NUM << SPI_FLASH_BYTES_LEN);
+	   reg_tmp= temp_addr |(SPI_BUFF_BYTE_NUM<< SPI_FLASH_BYTES_LEN) ;
+	   WRITE_PERI_REG(SPI_ADDR(HSPI), reg_tmp);
+          WRITE_PERI_REG(SPI_CMD(HSPI), SPI_FLASH_READ);
+          while(READ_PERI_REG(SPI_CMD(HSPI)) != 0);
+
+          for(i=0; i<(SPI_BUFF_BYTE_NUM>>2);i++)
+          {    
+              *addr_dest++ = READ_PERI_REG(SPI_W0(HSPI)+i*4);
+          }
+          temp_length = temp_length - SPI_BUFF_BYTE_NUM;
+          temp_addr = temp_addr + SPI_BUFF_BYTE_NUM;
+       }
+       else
+       {