SDK 3.0 release (#2692)

* Rebaseline firmware to non-OS SDK version 3.0
* Note that SDK version 3.0 introduces the concept of a Flash Partition Table(PT).  This is located at Flash offset 0x10000 in our firmware build.
* The firmware is now PT aware with both LFS and SPIFFS taking their partition size and location from the PT
* A new tool `tools/nodemcu-partition.py` is now used to initialise these data and can also download LFS and SPIFFS images to these partitions.
This commit is contained in:
Terry Ellison 2019-04-05 16:01:45 +01:00 committed by GitHub
parent b6cd2c3edd
commit 9a47107920
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 716 additions and 1931 deletions

View File

@ -5,20 +5,14 @@
TOOLCHAIN_VERSION:=20181106.0 TOOLCHAIN_VERSION:=20181106.0
# SDK base version, as released by Espressif # SDK base version, as released by Espressif
SDK_BASE_VER:=2.2.1 SDK_BASE_VER:=3.0
# no patch: SDK_VER equals SDK_BASE_VER and sdk dir depends on sdk_extracted
SDK_VER:=$(SDK_BASE_VER) SDK_VER:=$(SDK_BASE_VER)
SDK_DIR_DEPENDS:=sdk_extracted SDK_DIR_DEPENDS:=sdk_extracted
# with patch: SDK_VER differs from SDK_BASE_VER and sdk dir depends on sdk_patched
#SDK_PATCH_VER:=f8f27ce
#SDK_VER:=$(SDK_BASE_VER)-$(SDK_PATCH_VER)
#SDK_DIR_DEPENDS:=sdk_patched
SDK_FILE_VER:=$(SDK_BASE_VER) SDK_FILE_VER:=$(SDK_BASE_VER)
SDK_FILE_SHA1:=48f2242d5895823709f222bf0fffce9d525996c8 SDK_FILE_SHA1:=029fc23fe87e03c9852de636490b2d7b9e07f01a
# SDK_PATCH_SHA1:=0bc21ec77b08488f04d3e1c9d161b711d07201a8 ESPTOOL_VER:=2.6
# Ensure we search "our" SDK before the tool-chain's SDK (if any) # Ensure we search "our" SDK before the tool-chain's SDK (if any)
TOP_DIR:=$(abspath $(dir $(lastword $(MAKEFILE_LIST)))) TOP_DIR:=$(abspath $(dir $(lastword $(MAKEFILE_LIST))))
SDK_REL_DIR=sdk/esp_iot_sdk_v$(SDK_VER) SDK_REL_DIR=sdk/esp_iot_sdk_v$(SDK_VER)
@ -109,6 +103,7 @@ else
CPP = $(WRAPCC) xtensa-lx106-elf-gcc -E CPP = $(WRAPCC) xtensa-lx106-elf-gcc -E
OBJCOPY = xtensa-lx106-elf-objcopy OBJCOPY = xtensa-lx106-elf-objcopy
FIRMWAREDIR = ../bin/ FIRMWAREDIR = ../bin/
WGET = wget --tries=10 --timeout=15 --waitretry=30 --read-timeout=20 --retry-connrefused
UNAME_S := $(shell uname -s) UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux) ifeq ($(UNAME_S),Linux)
# LINUX # LINUX
@ -128,8 +123,12 @@ else
endif endif
endif endif
############################################################# #############################################################
ESPTOOL ?= ../tools/esptool.py
GITHUB_TOOLCHAIN = https://github.com/jmattsson/esp-toolchains
GITHUB_SDK = https://github.com/espressif/ESP8266_NONOS_SDK
GITHUB_ESPTOOL = https://github.com/espressif/esptool
ESPTOOL ?= $(TOP_DIR)/tools/toolchains/esptool.py
CSRCS ?= $(wildcard *.c) CSRCS ?= $(wildcard *.c)
CXXSRCS ?= $(wildcard *.cpp) CXXSRCS ?= $(wildcard *.cpp)
@ -234,18 +233,16 @@ $(BINODIR)/%.bin: $(IMAGEODIR)/%.out
all: toolchain sdk_pruned pre_build .subdirs $(OBJS) $(OLIBS) $(OIMAGES) $(OBINS) $(SPECIAL_MKTARGETS) all: toolchain sdk_pruned pre_build .subdirs $(OBJS) $(OLIBS) $(OIMAGES) $(OBINS) $(SPECIAL_MKTARGETS)
.PHONY: sdk_extracted .PHONY: sdk_extracted
.PHONY: sdk_patched
.PHONY: sdk_pruned .PHONY: sdk_pruned
.PHONY: toolchain .PHONY: toolchain
sdk_extracted: $(TOP_DIR)/sdk/.extracted-$(SDK_BASE_VER) sdk_extracted: $(TOP_DIR)/sdk/.extracted-$(SDK_BASE_VER)
sdk_patched: sdk_extracted $(TOP_DIR)/sdk/.patched-$(SDK_VER)
sdk_pruned: $(SDK_DIR_DEPENDS) $(TOP_DIR)/sdk/.pruned-$(SDK_VER) sdk_pruned: $(SDK_DIR_DEPENDS) $(TOP_DIR)/sdk/.pruned-$(SDK_VER)
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
toolchain: toolchain:
else else
toolchain: $(TOP_DIR)/tools/toolchains/esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION)/bin/xtensa-lx106-elf-gcc toolchain: $(TOP_DIR)/tools/toolchains/esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION)/bin/xtensa-lx106-elf-gcc $(TOP_DIR)/tools/toolchains/esptool.py
$(TOP_DIR)/tools/toolchains/esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION)/bin/xtensa-lx106-elf-gcc: $(TOP_DIR)/cache/toolchain-esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION).tar.xz $(TOP_DIR)/tools/toolchains/esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION)/bin/xtensa-lx106-elf-gcc: $(TOP_DIR)/cache/toolchain-esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION).tar.xz
mkdir -p $(TOP_DIR)/tools/toolchains/ mkdir -p $(TOP_DIR)/tools/toolchains/
@ -256,22 +253,34 @@ $(TOP_DIR)/tools/toolchains/esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION)/bin/xtensa-
$(TOP_DIR)/cache/toolchain-esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION).tar.xz: $(TOP_DIR)/cache/toolchain-esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION).tar.xz:
mkdir -p $(TOP_DIR)/cache mkdir -p $(TOP_DIR)/cache
$(summary) WGET $(patsubst $(TOP_DIR)/%,%,$@) $(summary) WGET $(patsubst $(TOP_DIR)/%,%,$@)
wget --tries=10 --timeout=15 --waitretry=30 --read-timeout=20 --retry-connrefused https://github.com/jmattsson/esp-toolchains/releases/download/$(PLATFORM)-$(TOOLCHAIN_VERSION)/toolchain-esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION).tar.xz -O $@ || { rm -f "$@"; exit 1; } $(WGET) $(GITHUB_TOOLCHAIN)/releases/download/$(PLATFORM)-$(TOOLCHAIN_VERSION)/toolchain-esp8266-$(PLATFORM)-$(TOOLCHAIN_VERSION).tar.xz -O $@ \
|| { rm -f "$@"; exit 1; }
endif endif
$(TOP_DIR)/tools/toolchains/esptool.py: $(TOP_DIR)/cache/esptool/v$(ESPTOOL_VER).tar.gz
mkdir -p $(TOP_DIR)/tools/toolchains/
tar -C $(TOP_DIR)/tools/toolchains/ -xzf $< --strip-components=1 esptool-$(ESPTOOL_VER)/esptool.py
chmod +x $@
touch $@
$(TOP_DIR)/cache/esptool/v$(ESPTOOL_VER).tar.gz:
mkdir -p $(TOP_DIR)/cache/esptool/
$(WGET) $(GITHUB_ESPTOOL)/archive/v$(ESPTOOL_VER).tar.gz -O $@ || { rm -f "$@"; exit 1; }
$(TOP_DIR)/sdk/.extracted-$(SDK_BASE_VER): $(TOP_DIR)/cache/v$(SDK_FILE_VER).zip $(TOP_DIR)/sdk/.extracted-$(SDK_BASE_VER): $(TOP_DIR)/cache/v$(SDK_FILE_VER).zip
mkdir -p "$(dir $@)" mkdir -p "$(dir $@)"
$(summary) UNZIP $(patsubst $(TOP_DIR)/%,%,$<) $(summary) UNZIP $(patsubst $(TOP_DIR)/%,%,$<)
(cd "$(dir $@)" && rm -fr esp_iot_sdk_v$(SDK_VER) ESP8266_NONOS_SDK-$(SDK_BASE_VER) && unzip $(TOP_DIR)/cache/v$(SDK_FILE_VER).zip ESP8266_NONOS_SDK-$(SDK_BASE_VER)/lib/* ESP8266_NONOS_SDK-$(SDK_BASE_VER)/ld/eagle.rom.addr.v6.ld ESP8266_NONOS_SDK-$(SDK_BASE_VER)/include/* ESP8266_NONOS_SDK-$(SDK_BASE_VER)/bin/esp_init_data_default_v05.bin) (cd "$(dir $@)" && \
rm -fr esp_iot_sdk_v$(SDK_VER) ESP8266_NONOS_SDK-$(SDK_BASE_VER) && \
unzip $(TOP_DIR)/cache/v$(SDK_FILE_VER).zip \
'ESP8266_NONOS_SDK-$(SDK_BASE_VER)/lib/*' \
'ESP8266_NONOS_SDK-$(SDK_BASE_VER)/ld/*.v6.ld' \
'ESP8266_NONOS_SDK-$(SDK_BASE_VER)/include/*' \
'ESP8266_NONOS_SDK-$(SDK_BASE_VER)/bin/esp_init_data_default_v05.bin' \
)
mv $(dir $@)/ESP8266_NONOS_SDK-$(SDK_BASE_VER) $(dir $@)/esp_iot_sdk_v$(SDK_BASE_VER) mv $(dir $@)/ESP8266_NONOS_SDK-$(SDK_BASE_VER) $(dir $@)/esp_iot_sdk_v$(SDK_BASE_VER)
touch $@ touch $@
$(TOP_DIR)/sdk/.patched-$(SDK_VER): $(TOP_DIR)/cache/$(SDK_PATCH_VER).patch
mv $(dir $@)/esp_iot_sdk_v$(SDK_BASE_VER) $(dir $@)/esp_iot_sdk_v$(SDK_VER)
$(summary) APPLY $(patsubst $(TOP_DIR)/%,%,$<)
git apply --verbose -p1 --exclude='*VERSION' --exclude='*bin/at*' --directory=$(SDK_REL_DIR) $<
touch $@
$(TOP_DIR)/sdk/.pruned-$(SDK_VER): $(TOP_DIR)/sdk/.pruned-$(SDK_VER):
rm -f $(SDK_DIR)/lib/liblwip.a $(SDK_DIR)/lib/libssl.a $(SDK_DIR)/lib/libmbedtls.a rm -f $(SDK_DIR)/lib/liblwip.a $(SDK_DIR)/lib/libssl.a $(SDK_DIR)/lib/libmbedtls.a
$(summary) PRUNE libmain.a libc.a $(summary) PRUNE libmain.a libc.a
@ -282,15 +291,9 @@ $(TOP_DIR)/sdk/.pruned-$(SDK_VER):
$(TOP_DIR)/cache/v$(SDK_FILE_VER).zip: $(TOP_DIR)/cache/v$(SDK_FILE_VER).zip:
mkdir -p "$(dir $@)" mkdir -p "$(dir $@)"
$(summary) WGET $(patsubst $(TOP_DIR)/%,%,$@) $(summary) WGET $(patsubst $(TOP_DIR)/%,%,$@)
wget --tries=10 --timeout=15 --waitretry=30 --read-timeout=20 --retry-connrefused https://github.com/espressif/ESP8266_NONOS_SDK/archive/v$(SDK_FILE_VER).zip -O $@ || { rm -f "$@"; exit 1; } $(WGET) $(GITHUB_SDK)/archive/v$(SDK_FILE_VER).zip -O $@ || { rm -f "$@"; exit 1; }
(echo "$(SDK_FILE_SHA1) $@" | sha1sum -c -) || { rm -f "$@"; exit 1; } (echo "$(SDK_FILE_SHA1) $@" | sha1sum -c -) || { rm -f "$@"; exit 1; }
$(TOP_DIR)/cache/$(SDK_PATCH_VER).patch:
mkdir -p "$(dir $@)"
$(summary) WGET $(SDK_PATCH_VER).patch
wget --tries=10 --timeout=15 --waitretry=30 --read-timeout=20 --retry-connrefused "https://github.com/espressif/ESP8266_NONOS_SDK/compare/v$(SDK_BASE_VER)...$(SDK_PATCH_VER).patch" -O $@ || { rm -f "$@"; exit 1; }
(echo "$(SDK_PATCH_SHA1) $@" | sha1sum -c -) || { rm -f "$@"; exit 1; }
clean: clean:
$(foreach d, $(SUBDIRS), $(MAKE) -C $(d) clean;) $(foreach d, $(SUBDIRS), $(MAKE) -C $(d) clean;)
$(RM) -r $(ODIR)/$(TARGET)/$(FLAVOR) $(RM) -r $(ODIR)/$(TARGET)/$(FLAVOR)

View File

@ -97,7 +97,6 @@ LINKFLAGS_eagle.app.v6 = \
-T$(LD_FILE) \ -T$(LD_FILE) \
-Wl,@../ld/defsym.rom \ -Wl,@../ld/defsym.rom \
-Wl,--no-check-sections \ -Wl,--no-check-sections \
-Wl,--wrap=_xtos_set_exception_handler \
-Wl,-static \ -Wl,-static \
$(addprefix -u , $(SELECTED_MODULE_SYMS)) \ $(addprefix -u , $(SELECTED_MODULE_SYMS)) \
-Wl,--start-group \ -Wl,--start-group \
@ -116,6 +115,8 @@ LINKFLAGS_eagle.app.v6 = \
$(DEP_LIBS_eagle.app.v6) \ $(DEP_LIBS_eagle.app.v6) \
-Wl,--end-group \ -Wl,--end-group \
-lm -lm
# -Wl,--cref
# -Wl,--wrap=_xtos_set_exception_handler
DEPENDS_eagle.app.v6 = \ DEPENDS_eagle.app.v6 = \
$(LD_FILE) \ $(LD_FILE) \

View File

@ -659,11 +659,22 @@ static void ATTR_GDBFN gdb_semihost_putchar1(char c) {
} }
#if !GDBSTUB_FREERTOS #if !GDBSTUB_FREERTOS
//The OS-less SDK uses the Xtensa HAL to handle exceptions. We can use those functions to catch any /* The non-OS SDK uses the Xtensa HAL to handle exceptions, and the SDK now establishes exception
//fatal exceptions and invoke the debugger when this happens. * handlers for EXCCAUSE errors: ILLEGAL, INSTR_ERROR, LOAD_STORE_ERROR, PRIVILEGED, UNALIGNED,
* LOAD_PROHIBITED and STORE_PROHIBITED. These handlers are established in SDK/app_main.c.
* LOAD_STORE_ERROR is handled by SDK/user_exceptions.o:load_non_32_wide_handler() which is a
* fork of our version. The remaining are handled by a static function at
* SDK:app+main.c:offset 0x0348.
*
* Our SDK 2 load_non_32_wide_handler chained into the gdb stub handler if the error was anything
* other than a L8UI, L16SI or L16UI at a flash mapped address. However in this current
* implementation, we have left the Espressif handler in place and handle the other errors with
* the debugger. This means that the debugger will not capture other load store errors. I
* might revise this.
*/
static void ATTR_GDBINIT install_exceptions() { static void ATTR_GDBINIT install_exceptions() {
int i; int i;
int exno[]={EXCCAUSE_ILLEGAL, EXCCAUSE_SYSCALL, EXCCAUSE_INSTR_ERROR, EXCCAUSE_LOAD_STORE_ERROR, const int exno[]={EXCCAUSE_ILLEGAL, EXCCAUSE_SYSCALL, EXCCAUSE_INSTR_ERROR, /* EXCCAUSE_LOAD_STORE_ERROR, */
EXCCAUSE_DIVIDE_BY_ZERO, EXCCAUSE_UNALIGNED, EXCCAUSE_INSTR_DATA_ERROR, EXCCAUSE_LOAD_STORE_DATA_ERROR, EXCCAUSE_DIVIDE_BY_ZERO, EXCCAUSE_UNALIGNED, EXCCAUSE_INSTR_DATA_ERROR, EXCCAUSE_LOAD_STORE_DATA_ERROR,
EXCCAUSE_INSTR_ADDR_ERROR, EXCCAUSE_LOAD_STORE_ADDR_ERROR, EXCCAUSE_INSTR_PROHIBITED, EXCCAUSE_INSTR_ADDR_ERROR, EXCCAUSE_LOAD_STORE_ADDR_ERROR, EXCCAUSE_INSTR_PROHIBITED,
EXCCAUSE_LOAD_PROHIBITED, EXCCAUSE_STORE_PROHIBITED}; EXCCAUSE_LOAD_PROHIBITED, EXCCAUSE_STORE_PROHIBITED};

View File

@ -51,40 +51,39 @@ typedef size_t mem_size_t;
* allow these defines to be overridden. * allow these defines to be overridden.
*/ */
#ifndef MEMLEAK_DEBUG #ifndef MEMLEAK_DEBUG
#ifndef mem_free #ifndef mem_free
#define mem_free vPortFree #define mem_free(s) vPortFree(s, "", __LINE__)
#endif #endif
#ifndef mem_malloc #ifndef mem_malloc
#define mem_malloc pvPortMalloc #define mem_malloc(s) pvPortMalloc(s, "", __LINE__,false)
#endif #endif
#ifndef mem_calloc #ifndef mem_calloc
#define mem_calloc pvPortCalloc #define mem_calloc(l, s) pvPortCalloc(l, s, "", __LINE__)
#endif #endif
#ifndef mem_realloc #ifndef mem_realloc
#define mem_realloc pvPortRealloc #define mem_realloc(p, s) pvPortRealloc(p, s, "", __LINE__)
#endif #endif
#ifndef mem_zalloc #ifndef mem_zalloc
#define mem_zalloc pvPortZalloc #define mem_zalloc(s) pvPortZalloc(s, "", __LINE__)
#endif #endif
#else #else
#ifndef mem_free #ifndef mem_free
#define mem_free(s) \ #define mem_free(s) vPortFree(s, mem_debug_file, __LINE__)
do{\
const char *file = mem_debug_file;\
vPortFree(s, file, __LINE__);\
}while(0)
#endif #endif
#ifndef mem_malloc #ifndef mem_malloc
#define mem_malloc(s) ({const char *file = mem_debug_file; pvPortMalloc(s, file, __LINE__);}) #define mem_malloc(s) pvPortMalloc(s, mem_debug_file, __LINE__,false)
#endif #endif
#ifndef mem_calloc #ifndef mem_calloc
#define mem_calloc(l, s) ({const char *file = mem_debug_file; pvPortCalloc(l, s, file, __LINE__);}) #define mem_calloc(l, s) pvPortCalloc(l, s, mem_debug_file, __LINE__)
#endif #endif
#ifndef mem_realloc #ifndef mem_realloc
#define mem_realloc(p, s) ({const char *file = mem_debug_file; pvPortRealloc(p, s, file, __LINE__);}) #define mem_realloc(p, s) pvPortRealloc(p, s, mem_debug_file, __LINE__)
#endif #endif
#ifndef mem_zalloc #ifndef mem_zalloc
#define mem_zalloc(s) ({const char *file = mem_debug_file; pvPortZalloc(s, file, __LINE__);}) #define mem_zalloc(s) pvPortZalloc(s, mem_debug_file, __LINE__)
#endif #endif
#endif #endif

View File

@ -7,8 +7,8 @@
// this out and enabling the explicitly size, e.g. FLASH_4M. Valid sizes are // this out and enabling the explicitly size, e.g. FLASH_4M. Valid sizes are
// FLASH_512K, FLASH_1M, FLASH_2M, FLASH_4M, FLASH_8M, FLASH_16M. // FLASH_512K, FLASH_1M, FLASH_2M, FLASH_4M, FLASH_8M, FLASH_16M.
#define FLASH_AUTOSIZE //#define FLASH_AUTOSIZE
//#define FLASH_4M #define FLASH_4M
// The firmware now selects a baudrate of 115,200 by default, but the driver // The firmware now selects a baudrate of 115,200 by default, but the driver
@ -41,11 +41,8 @@
// The Lua Flash Store (LFS) allows you to store Lua code in Flash memory and // The Lua Flash Store (LFS) allows you to store Lua code in Flash memory and
// the Lua VMS will execute this code directly from flash without needing any // the Lua VMS will execute this code directly from flash without needing any
// RAM overhead. If you want to enable LFS then set the following define to // RAM overhead. Note that you should now configure LFS directly in the
// the size of the store that you need. This can be any multiple of 4kB up to // System Partition Table and not at build time.
// a maximum 256Kb.
//#define LUA_FLASH_STORE 0x10000
// By default Lua executes the file init.lua at start up. The following // By default Lua executes the file init.lua at start up. The following
@ -71,10 +68,10 @@
// general, limiting the size of the FS only to what your application needs // general, limiting the size of the FS only to what your application needs
// gives the fastest start-up and imaging times. // gives the fastest start-up and imaging times.
// Note that you should now configure SPIFFS size and position directly in the
// System Partition Table and not at build time.
#define BUILD_SPIFFS #define BUILD_SPIFFS
//#define SPIFFS_FIXED_LOCATION 0x100000
//#define SPIFFS_MAX_FILESYSTEM_SIZE 0x20000
//#define SPIFFS_SIZE_1M_BOUNDARY
#define SPIFFS_CACHE 1 // Enable if you use you SPIFFS in R/W mode #define SPIFFS_CACHE 1 // Enable if you use you SPIFFS in R/W mode
#define SPIFFS_MAX_OPEN_FILES 4 // maximum number of open files for SPIFFS #define SPIFFS_MAX_OPEN_FILES 4 // maximum number of open files for SPIFFS
#define FS_OBJ_NAME_LEN 31 // maximum length of a filename #define FS_OBJ_NAME_LEN 31 // maximum length of a filename
@ -206,6 +203,19 @@
// change this if you have tracked the implications through the Firmware sources // change this if you have tracked the implications through the Firmware sources
// and understand the these. // and understand the these.
#define NODEMCU_EAGLEROM_PARTITION 1
#define NODEMCU_IROM0TEXT_PARTITION 2
#define NODEMCU_LFS0_PARTITION 3
#define NODEMCU_LFS1_PARTITION 4
#define NODEMCU_TLSCERT_PARTITION 5
#define NODEMCU_SPIFFS0_PARTITION 6
#define NODEMCU_SPIFFS1_PARTITION 7
#define LUA_FLASH_STORE 0x0
#define SPIFFS_FIXED_LOCATION 0x0
#define SPIFFS_MAX_FILESYSTEM_SIZE (~0x0)
//#define SPIFFS_SIZE_1M_BOUNDARY
#define LUA_TASK_PRIO USER_TASK_PRIO_0 #define LUA_TASK_PRIO USER_TASK_PRIO_0
#define LUA_PROCESS_LINE_SIG 2 #define LUA_PROCESS_LINE_SIG 2
#define LUA_OPTIMIZE_DEBUG 2 #define LUA_OPTIMIZE_DEBUG 2

View File

@ -11,7 +11,7 @@ double floor(double x)
#define MINEXP -2047 /* (MIN_EXP * 16) - 1 */ #define MINEXP -2047 /* (MIN_EXP * 16) - 1 */
#define HUGE MAXFLOAT #define HUGE MAXFLOAT
double a1[] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = static const double a1[] =
{ {
1.0, 1.0,
0.95760328069857365, 0.95760328069857365,
@ -31,7 +31,7 @@ double a1[] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR =
0.52213689121370692, 0.52213689121370692,
0.50000000000000000 0.50000000000000000
}; };
double a2[] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = static const double a2[] =
{ {
0.24114209503420288E-17, 0.24114209503420288E-17,
0.92291566937243079E-18, 0.92291566937243079E-18,
@ -42,18 +42,19 @@ double a2[] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR =
0.29306999570789681E-17, 0.29306999570789681E-17,
0.11260851040933474E-17 0.11260851040933474E-17
}; };
double p1 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.833333333333332114e-1; static const double
double p2 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.125000000005037992e-1; p1 = 0.833333333333332114e-1,
double p3 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.223214212859242590e-2; p2 = 0.125000000005037992e-1,
double p4 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.434457756721631196e-3; p3 = 0.223214212859242590e-2,
double q1 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.693147180559945296e0; p4 = 0.434457756721631196e-3,
double q2 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.240226506959095371e0; q1 = 0.693147180559945296e0,
double q3 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.555041086640855953e-1; q2 = 0.240226506959095371e0,
double q4 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.961812905951724170e-2; q3 = 0.555041086640855953e-1,
double q5 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.133335413135857847e-2; q4 = 0.961812905951724170e-2,
double q6 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.154002904409897646e-3; q5 = 0.133335413135857847e-2,
double q7 ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.149288526805956082e-4; q6 = 0.154002904409897646e-3,
double k ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = 0.442695040888963407; q7 = 0.149288526805956082e-4,
k = 0.442695040888963407;
double pow(double x, double y) double pow(double x, double y)
{ {

View File

@ -28,12 +28,12 @@ static int db_getregistry (lua_State *L) {
} }
static int db_getstrings (lua_State *L) { static int db_getstrings (lua_State *L) {
size_t i,n; size_t i,n=0;
stringtable *tb; stringtable *tb;
GCObject *o; GCObject *o;
#if defined(LUA_FLASH_STORE) && !defined(LUA_CROSS_COMPILER) #ifndef LUA_CROSS_COMPILER
const char *opt = lua_tolstring (L, 1, &n); const char *opt = lua_tolstring (L, 1, &n);
if (n==3 && memcmp(opt, "ROM", 4) == 0) { if (n==3 && c_memcmp(opt, "ROM", 4) == 0) {
if (G(L)->ROstrt.hash == NULL) if (G(L)->ROstrt.hash == NULL)
return 0; return 0;
tb = &G(L)->ROstrt; tb = &G(L)->ROstrt;

View File

@ -8,7 +8,6 @@
#define LUAC_CROSS_FILE #define LUAC_CROSS_FILE
#include "lua.h" #include "lua.h"
#ifdef LUA_FLASH_STORE
#include "lobject.h" #include "lobject.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lstate.h" #include "lstate.h"
@ -31,6 +30,7 @@
*/ */
static char *flashAddr; static char *flashAddr;
static uint32_t flashSize;
static uint32_t flashAddrPhys; static uint32_t flashAddrPhys;
static uint32_t flashSector; static uint32_t flashSector;
static uint32_t curOffset; static uint32_t curOffset;
@ -38,9 +38,8 @@ static uint32_t curOffset;
#define ALIGN(s) (((s)+sizeof(size_t)-1) & ((size_t) (- (signed) sizeof(size_t)))) #define ALIGN(s) (((s)+sizeof(size_t)-1) & ((size_t) (- (signed) sizeof(size_t))))
#define ALIGN_BITS(s) (((uint32_t)s) & (sizeof(size_t)-1)) #define ALIGN_BITS(s) (((uint32_t)s) & (sizeof(size_t)-1))
#define ALL_SET (~0) #define ALL_SET (~0)
#define FLASH_SIZE LUA_FLASH_STORE
#define FLASH_PAGE_SIZE INTERNAL_FLASH_SECTOR_SIZE #define FLASH_PAGE_SIZE INTERNAL_FLASH_SECTOR_SIZE
#define FLASH_PAGES (FLASH_SIZE/FLASH_PAGE_SIZE) #define FLASH_PAGES (flashSize/FLASH_PAGE_SIZE)
#define READ_BLOCKSIZE 1024 #define READ_BLOCKSIZE 1024
#define WRITE_BLOCKSIZE 2048 #define WRITE_BLOCKSIZE 2048
#define DICTIONARY_WINDOW 16384 #define DICTIONARY_WINDOW 16384
@ -49,8 +48,6 @@ static uint32_t curOffset;
#define WRITE_BLOCKS ((DICTIONARY_WINDOW/WRITE_BLOCKSIZE)+1) #define WRITE_BLOCKS ((DICTIONARY_WINDOW/WRITE_BLOCKSIZE)+1)
#define WRITE_BLOCK_WORDS (WRITE_BLOCKSIZE/WORDSIZE) #define WRITE_BLOCK_WORDS (WRITE_BLOCKSIZE/WORDSIZE)
char flash_region_base[FLASH_SIZE] ICACHE_FLASH_RESERVED_ATTR;
struct INPUT { struct INPUT {
int fd; int fd;
int len; int len;
@ -152,11 +149,16 @@ static void flashErase(uint32_t start, uint32_t end){
* Hook in lstate.c:f_luaopen() to set up ROstrt and ROpvmain if needed * Hook in lstate.c:f_luaopen() to set up ROstrt and ROpvmain if needed
*/ */
LUAI_FUNC void luaN_init (lua_State *L) { LUAI_FUNC void luaN_init (lua_State *L) {
curOffset = 0;
flashAddr = flash_region_base; flashSize = platform_flash_get_partition (NODEMCU_LFS0_PARTITION, &flashAddrPhys);
flashAddrPhys = platform_flash_mapped2phys((uint32_t)flashAddr); if (flashSize == 0) {
return; // Nothing to do if the size is zero
}
G(L)->LFSsize = flashSize;
flashAddr = cast(char *, platform_flash_phys2mapped(flashAddrPhys));
flashSector = platform_flash_get_sector_of_address(flashAddrPhys); flashSector = platform_flash_get_sector_of_address(flashAddrPhys);
FlashHeader *fh = cast(FlashHeader *, flashAddr); FlashHeader *fh = cast(FlashHeader *, flashAddr);
curOffset = 0;
/* /*
* For the LFS to be valid, its signature has to be correct for this build * For the LFS to be valid, its signature has to be correct for this build
@ -201,6 +203,13 @@ LUALIB_API int luaN_reload_reboot (lua_State *L) {
// luaL_dbgbreak(); // luaL_dbgbreak();
const char *fn = lua_tostring(L, 1), *msg = ""; const char *fn = lua_tostring(L, 1), *msg = "";
int status; int status;
if (G(L)->LFSsize == 0) {
lua_pushstring(L, "No LFS partition allocated");
return 1;
}
/* /*
* Do a protected call of loadLFS. * Do a protected call of loadLFS.
* *
@ -264,13 +273,18 @@ LUAI_FUNC int luaN_index (lua_State *L) {
int i; int i;
int n = lua_gettop(L); int n = lua_gettop(L);
/* Return nil + the LFS base address if the LFS isn't loaded */ /* Return nil + the LFS base address if the LFS size > 0 and it isn't loaded */
if (!(G(L)->ROpvmain)) { if (!(G(L)->ROpvmain)) {
lua_settop(L, 0); lua_settop(L, 0);
lua_pushnil(L); lua_pushnil(L);
if (G(L)->LFSsize) {
lua_pushinteger(L, (lua_Integer) flashAddr); lua_pushinteger(L, (lua_Integer) flashAddr);
lua_pushinteger(L, flashAddrPhys); lua_pushinteger(L, flashAddrPhys);
return 3; lua_pushinteger(L, G(L)->LFSsize);
return 4;
} else {
return 1;
}
} }
/* Push the LClosure of the LFS index function */ /* Push the LClosure of the LFS index function */
@ -409,10 +423,10 @@ int procFirstPass (void) {
flash_error("Incorrect LFS build type"); flash_error("Incorrect LFS build type");
if ((fh->flash_sig & ~FLASH_SIG_ABSOLUTE) != FLASH_SIG) if ((fh->flash_sig & ~FLASH_SIG_ABSOLUTE) != FLASH_SIG)
flash_error("incorrect LFS header signature"); flash_error("incorrect LFS header signature");
if (fh->flash_size > FLASH_SIZE) if (fh->flash_size > flashSize)
flash_error("LFS Image too big for configured LFS region"); flash_error("LFS Image too big for configured LFS region");
if ((fh->flash_size & 0x3) || if ((fh->flash_size & 0x3) ||
fh->flash_size > FLASH_SIZE || fh->flash_size > flashSize ||
out->flagsLen != 1 + (out->flashLen/WORDSIZE - 1) / BITS_PER_WORD) out->flagsLen != 1 + (out->flashLen/WORDSIZE - 1) / BITS_PER_WORD)
flash_error("LFS length mismatch"); flash_error("LFS length mismatch");
out->flags = luaM_newvector(out->L, out->flagsLen, uint); out->flags = luaM_newvector(out->L, out->flagsLen, uint);
@ -557,4 +571,3 @@ static int loadLFSgc (lua_State *L) {
} }
return 0; return 0;
} }
#endif

View File

@ -3,7 +3,7 @@
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
#if defined(LUA_FLASH_STORE) && !defined(lflash_h) #ifndef lflash_h
#define lflash_h #define lflash_h
#include "lobject.h" #include "lobject.h"

View File

@ -28,10 +28,6 @@
#define GCSWEEPCOST 10 #define GCSWEEPCOST 10
#define GCFINALIZECOST 100 #define GCFINALIZECOST 100
#if READONLYMASK != (1<<READONLYBIT) || (defined(LUA_FLASH_STORE) && LFSMASK != (1<<LFSBIT))
#error "lgc.h and object.h out of sync on READONLYMASK / LFSMASK"
#endif
#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) #define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS))
#define makewhite(g,x) \ #define makewhite(g,x) \

View File

@ -101,7 +101,7 @@
#define isfixedstack(x) testbit((x)->marked, FIXEDSTACKBIT) #define isfixedstack(x) testbit((x)->marked, FIXEDSTACKBIT)
#define fixedstack(x) l_setbit((x)->marked, FIXEDSTACKBIT) #define fixedstack(x) l_setbit((x)->marked, FIXEDSTACKBIT)
#define unfixedstack(x) resetbit((x)->marked, FIXEDSTACKBIT) #define unfixedstack(x) resetbit((x)->marked, FIXEDSTACKBIT)
#ifdef LUA_FLASH_STORE #ifndef LUA_CROSS_COMPILER
#define isLFSobject(x) testbit(getmarked(x), LFSBIT) #define isLFSobject(x) testbit(getmarked(x), LFSBIT)
#define stringfix(s) if (!test2bits(getmarked(&(s)->tsv), FIXEDBIT, LFSBIT)) {l_setbit((s)->tsv.marked, FIXEDBIT);} #define stringfix(s) if (!test2bits(getmarked(&(s)->tsv), FIXEDBIT, LFSBIT)) {l_setbit((s)->tsv.marked, FIXEDBIT);}
#else #else

View File

@ -24,9 +24,7 @@
#define NUM_TAGS (LAST_TAG+1) #define NUM_TAGS (LAST_TAG+1)
#define READONLYMASK (1<<7) /* denormalised bitmask for READONLYBIT and */ #define READONLYMASK (1<<7) /* denormalised bitmask for READONLYBIT and */
#ifdef LUA_FLASH_STORE
#define LFSMASK (1<<6) /* LFSBIT to avoid include proliferation */ #define LFSMASK (1<<6) /* LFSBIT to avoid include proliferation */
#endif
/* /*
** Extra tags for non-values ** Extra tags for non-values
*/ */

View File

@ -73,7 +73,7 @@ static void f_luaopen (lua_State *L, void *ud) {
sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */
sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
#if defined(LUA_FLASH_STORE) && !defined(LUA_CROSS_COMPILER) #ifndef LUA_CROSS_COMPILER
luaN_init(L); /* optionally map RO string table */ luaN_init(L); /* optionally map RO string table */
#endif #endif
luaT_init(L); luaT_init(L);
@ -196,11 +196,12 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
#else #else
g->memlimit = 0; g->memlimit = 0;
#endif #endif
#if defined(LUA_FLASH_STORE) && !defined(LUA_CROSS_COMPILER) #ifndef LUA_CROSS_COMPILER
g->ROstrt.size = 0; g->ROstrt.size = 0;
g->ROstrt.nuse = 0; g->ROstrt.nuse = 0;
g->ROstrt.hash = NULL; g->ROstrt.hash = NULL;
g->ROpvmain = NULL; g->ROpvmain = NULL;
g->LFSsize = 0;
#endif #endif
for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL; for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {

View File

@ -94,9 +94,10 @@ typedef struct global_State {
UpVal uvhead; /* head of double-linked list of all open upvalues */ UpVal uvhead; /* head of double-linked list of all open upvalues */
struct Table *mt[NUM_TAGS]; /* metatables for basic types */ struct Table *mt[NUM_TAGS]; /* metatables for basic types */
TString *tmname[TM_N]; /* array with tag-method names */ TString *tmname[TM_N]; /* array with tag-method names */
#if defined(LUA_FLASH_STORE) && !defined(LUA_CROSS_COMPILER) #ifndef LUA_CROSS_COMPILER
stringtable ROstrt; /* Flash-based hash table for RO strings */ stringtable ROstrt; /* Flash-based hash table for RO strings */
Proto *ROpvmain; /* Flash-based Proto main */ Proto *ROpvmain; /* Flash-based Proto main */
int LFSsize; /* Size of Lua Flash Store */
#endif #endif
} global_State; } global_State;

View File

@ -112,7 +112,7 @@ LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
return ts; return ts;
} }
} }
#if defined(LUA_FLASH_STORE) && !defined(LUA_CROSS_COMPILER) #ifndef LUA_CROSS_COMPILER
/* /*
* The RAM strt is searched first since RAM access is faster tham Flash access. * The RAM strt is searched first since RAM access is faster tham Flash access.
* If a miss, then search the RO string table. * If a miss, then search the RO string table.

View File

@ -22,9 +22,7 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "lualib.h" #include "lualib.h"
#include "legc.h" #include "legc.h"
#ifdef LUA_FLASH_STORE
#include "lflash.h" #include "lflash.h"
#endif
#include "os_type.h" #include "os_type.h"
lua_State *globalL = NULL; lua_State *globalL = NULL;

View File

@ -16,8 +16,6 @@
#define LUA_CORE #define LUA_CORE
#include "lobject.h" #include "lobject.h"
#include "lstring.h" #include "lstring.h"
#undef LUA_FLASH_STORE
#define LUA_FLASH_STORE
#include "lflash.h" #include "lflash.h"
#include "uzlib.h" #include "uzlib.h"

View File

@ -17,9 +17,7 @@
#include "platform.h" #include "platform.h"
#include "lrodefs.h" #include "lrodefs.h"
#ifdef LUA_FLASH_STORE
#include "lflash.h" #include "lflash.h"
#endif
#include "c_types.h" #include "c_types.h"
#include "c_string.h" #include "c_string.h"
#include "driver/uart.h" #include "driver/uart.h"
@ -162,10 +160,6 @@ static int node_flashid( lua_State* L )
// Lua: flashsize() // Lua: flashsize()
static int node_flashsize( lua_State* L ) static int node_flashsize( lua_State* L )
{ {
if (lua_type(L, 1) == LUA_TNUMBER)
{
flash_rom_set_size_byte(luaL_checkinteger(L, 1));
}
uint32_t sz = flash_rom_get_size_byte(); uint32_t sz = flash_rom_get_size_byte();
lua_pushinteger( L, sz ); lua_pushinteger( L, sz );
return 1; return 1;
@ -603,10 +597,8 @@ static const LUA_REG_TYPE node_map[] =
{ LSTRKEY( "heap" ), LFUNCVAL( node_heap ) }, { LSTRKEY( "heap" ), LFUNCVAL( node_heap ) },
{ LSTRKEY( "info" ), LFUNCVAL( node_info ) }, { LSTRKEY( "info" ), LFUNCVAL( node_info ) },
{ LSTRKEY( "task" ), LROVAL( node_task_map ) }, { LSTRKEY( "task" ), LROVAL( node_task_map ) },
#ifdef LUA_FLASH_STORE
{ LSTRKEY( "flashreload" ), LFUNCVAL( luaN_reload_reboot ) }, { LSTRKEY( "flashreload" ), LFUNCVAL( luaN_reload_reboot ) },
{ LSTRKEY( "flashindex" ), LFUNCVAL( luaN_index ) }, { LSTRKEY( "flashindex" ), LFUNCVAL( luaN_index ) },
#endif
{ LSTRKEY( "restart" ), LFUNCVAL( node_restart ) }, { LSTRKEY( "restart" ), LFUNCVAL( node_restart ) },
{ LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) }, { LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) },
{ LSTRKEY( "dsleepMax" ), LFUNCVAL( dsleepMax ) }, { LSTRKEY( "dsleepMax" ), LFUNCVAL( dsleepMax ) },

View File

@ -46,10 +46,10 @@ void __attribute__((noreturn)) TEXT_SECTION_ATTR rtc_time_enter_deep_sleep_final
void rtctime_early_startup (void) void rtctime_early_startup (void)
{ {
Cache_Read_Enable (0, 0, 1); // Cache_Read_Enable (0, 0, 1);
rtc_time_register_bootup (); rtc_time_register_bootup ();
rtc_time_switch_clocks (); rtc_time_switch_clocks ();
Cache_Read_Disable (); // Cache_Read_Disable ();
} }
void rtctime_late_startup (void) void rtctime_late_startup (void)

View File

@ -39,16 +39,19 @@ uint32_t flash_detect_size_byte(void)
#undef FLASH_BUFFER_SIZE_DETECT #undef FLASH_BUFFER_SIZE_DETECT
} }
SPIFlashInfo flash_rom_getinfo(void) static SPIFlashInfo spi_flash_info = {0};
SPIFlashInfo *flash_rom_getinfo(void)
{ {
volatile SPIFlashInfo spi_flash_info ICACHE_STORE_ATTR; if (spi_flash_info.entry_point == 0) {
spi_flash_read(0, (uint32 *)(& spi_flash_info), sizeof(spi_flash_info)); spi_flash_read(0, (uint32 *)(& spi_flash_info), sizeof(spi_flash_info));
return spi_flash_info; }
return &spi_flash_info;
} }
uint8_t flash_rom_get_size_type(void) uint8_t flash_rom_get_size_type(void)
{ {
return flash_rom_getinfo().size; return flash_rom_getinfo()->size;
} }
uint32_t flash_rom_get_size_byte(void) uint32_t flash_rom_get_size_byte(void)
@ -56,7 +59,7 @@ uint32_t flash_rom_get_size_byte(void)
static uint32_t flash_size = 0; static uint32_t flash_size = 0;
if (flash_size == 0) if (flash_size == 0)
{ {
switch (flash_rom_getinfo().size) switch (flash_rom_getinfo()->size)
{ {
case SIZE_2MBIT: case SIZE_2MBIT:
// 2Mbit, 256kByte // 2Mbit, 256kByte
@ -107,99 +110,15 @@ uint32_t flash_rom_get_size_byte(void)
return flash_size; return flash_size;
} }
bool flash_rom_set_size_type(uint8_t size)
{
// Dangerous, here are dinosaur infested!!!!!
// Reboot required!!!
// If you don't know what you're doing, your nodemcu may turn into stone ...
NODE_DBG("\nBEGIN SET FLASH HEADER\n");
uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR;
if (SPI_FLASH_RESULT_OK == spi_flash_read(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nflash_rom_set_size_type(%u), was %u\n", size, ((SPIFlashInfo *)data)->size );
((SPIFlashInfo *)data)->size = size;
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(0 * SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nSECTOR 0 ERASE SUCCESS\n");
}
if (SPI_FLASH_RESULT_OK == spi_flash_write(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nWRITE SUCCESS, %u\n", size);
}
}
NODE_DBG("\nEND SET FLASH HEADER\n");
return true;
}
bool flash_rom_set_size_byte(uint32_t size)
{
// Dangerous, here are dinosaur infested!!!!!
// Reboot required!!!
// If you don't know what you're doing, your nodemcu may turn into stone ...
bool result = true;
uint32_t flash_size = 0;
switch (size)
{
case 256 * 1024:
// 2Mbit, 256kByte
flash_size = SIZE_2MBIT;
flash_rom_set_size_type(flash_size);
break;
case 512 * 1024:
// 4Mbit, 512kByte
flash_size = SIZE_4MBIT;
flash_rom_set_size_type(flash_size);
break;
case 1 * 1024 * 1024:
// 8Mbit, 1MByte
flash_size = SIZE_8MBIT;
flash_rom_set_size_type(flash_size);
break;
case 2 * 1024 * 1024:
// 16Mbit, 2MByte
flash_size = SIZE_16MBIT;
flash_rom_set_size_type(flash_size);
break;
case 4 * 1024 * 1024:
// 32Mbit, 4MByte
flash_size = SIZE_32MBIT;
flash_rom_set_size_type(flash_size);
break;
case 8 * 1024 * 1024:
// 64Mbit, 8MByte
flash_size = SIZE_64MBIT;
flash_rom_set_size_type(flash_size);
break;
case 16 * 1024 * 1024:
// 128Mbit, 16MByte
flash_size = SIZE_128MBIT;
flash_rom_set_size_type(flash_size);
break;
default:
// Unknown flash size.
result = false;
break;
}
return result;
}
uint16_t flash_rom_get_sec_num(void) uint16_t flash_rom_get_sec_num(void)
{ {
//static uint16_t sec_num = 0;
// return flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE);
// c_printf("\nflash_rom_get_size_byte()=%d\n", ( flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE) ));
// if( sec_num == 0 )
//{
// sec_num = 4 * 1024 * 1024 / (SPI_FLASH_SEC_SIZE);
//}
//return sec_num;
return ( flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE) ); return ( flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE) );
} }
uint8_t flash_rom_get_mode(void) uint8_t flash_rom_get_mode(void)
{ {
SPIFlashInfo spi_flash_info = flash_rom_getinfo(); uint8_t mode = flash_rom_getinfo()->mode;
switch (spi_flash_info.mode) switch (mode)
{ {
// Reserved for future use // Reserved for future use
case MODE_QIO: case MODE_QIO:
@ -211,14 +130,14 @@ uint8_t flash_rom_get_mode(void)
case MODE_DOUT: case MODE_DOUT:
break; break;
} }
return spi_flash_info.mode; return mode;
} }
uint32_t flash_rom_get_speed(void) uint32_t flash_rom_get_speed(void)
{ {
uint32_t speed = 0; uint32_t speed = 0;
SPIFlashInfo spi_flash_info = flash_rom_getinfo(); uint8_t spi_speed = flash_rom_getinfo()->speed;
switch (spi_flash_info.speed) switch (spi_speed)
{ {
case SPEED_40MHZ: case SPEED_40MHZ:
// 40MHz // 40MHz
@ -240,47 +159,6 @@ uint32_t flash_rom_get_speed(void)
return speed; return speed;
} }
bool flash_rom_set_speed(uint32_t speed)
{
// Dangerous, here are dinosaur infested!!!!!
// Reboot required!!!
// If you don't know what you're doing, your nodemcu may turn into stone ...
NODE_DBG("\nBEGIN SET FLASH HEADER\n");
uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR;
uint8_t speed_type = SPEED_40MHZ;
if (speed < 26700000)
{
speed_type = SPEED_20MHZ;
}
else if (speed < 40000000)
{
speed_type = SPEED_26MHZ;
}
else if (speed < 80000000)
{
speed_type = SPEED_40MHZ;
}
else if (speed >= 80000000)
{
speed_type = SPEED_80MHZ;
}
if (SPI_FLASH_RESULT_OK == spi_flash_read(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{
((SPIFlashInfo *)(&data[0]))->speed = speed_type;
NODE_DBG("\nflash_rom_set_speed(%u), was %u\n", speed_type, ((SPIFlashInfo *)(&data[0]))->speed );
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(0 * SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nERASE SUCCESS\n");
}
if (SPI_FLASH_RESULT_OK == spi_flash_write(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nWRITE SUCCESS, %u\n", speed_type);
}
}
NODE_DBG("\nEND SET FLASH HEADER\n");
return true;
}
uint8_t byte_of_aligned_array(const uint8_t *aligned_array, uint32_t index) uint8_t byte_of_aligned_array(const uint8_t *aligned_array, uint32_t index)
{ {
if ( (((uint32_t)aligned_array) % 4) != 0 ) if ( (((uint32_t)aligned_array) % 4) != 0 )
@ -303,31 +181,5 @@ uint16_t word_of_aligned_array(const uint16_t *aligned_array, uint32_t index)
volatile uint32_t v = ((uint32_t *)aligned_array)[ index / 2 ]; volatile uint32_t v = ((uint32_t *)aligned_array)[ index / 2 ];
uint16_t *p = (uint16_t *) (&v); uint16_t *p = (uint16_t *) (&v);
return (index % 2 == 0) ? p[ 0 ] : p[ 1 ]; return (index % 2 == 0) ? p[ 0 ] : p[ 1 ];
// return p[ (index % 2) ]; // -- why error???
// (byte_of_aligned_array((uint8_t *)aligned_array, index * 2 + 1) << 8) | byte_of_aligned_array((uint8_t *)aligned_array, index * 2);
} }
// uint8_t flash_rom_get_checksum(void)
// {
// // SPIFlashInfo spi_flash_info ICACHE_STORE_ATTR = flash_rom_getinfo();
// // uint32_t address = sizeof(spi_flash_info) + spi_flash_info.segment_size;
// // uint32_t address_aligned_4bytes = (address + 3) & 0xFFFFFFFC;
// // uint8_t buffer[64] = {0};
// // spi_flash_read(address, (uint32 *) buffer, 64);
// // uint8_t i = 0;
// // c_printf("\nBEGIN DUMP\n");
// // for (i = 0; i < 64; i++)
// // {
// // c_printf("%02x," , buffer[i]);
// // }
// // i = (address + 0x10) & 0x10 - 1;
// // c_printf("\nSIZE:%d CHECK SUM:%02x\n", spi_flash_info.segment_size, buffer[i]);
// // c_printf("\nEND DUMP\n");
// // return buffer[0];
// return 0;
// }
// uint8_t flash_rom_calc_checksum(void)
// {
// return 0;
// }

View File

@ -79,18 +79,14 @@ typedef struct
uint32_t segment_size; uint32_t segment_size;
} ICACHE_STORE_TYPEDEF_ATTR SPIFlashInfo; } ICACHE_STORE_TYPEDEF_ATTR SPIFlashInfo;
SPIFlashInfo flash_rom_getinfo(void); SPIFlashInfo *flash_rom_getinfo(void);
uint8_t flash_rom_get_size_type(void); uint8_t flash_rom_get_size_type(void);
uint32_t flash_rom_get_size_byte(void); uint32_t flash_rom_get_size_byte(void);
uint32_t flash_detect_size_byte(void); uint32_t flash_detect_size_byte(void);
bool flash_rom_set_size_type(uint8_t);
bool flash_rom_set_size_byte(uint32_t);
uint16_t flash_rom_get_sec_num(void); uint16_t flash_rom_get_sec_num(void);
uint8_t flash_rom_get_mode(void); uint8_t flash_rom_get_mode(void);
uint32_t flash_rom_get_speed(void); uint32_t flash_rom_get_speed(void);
uint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index); uint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index);
uint16_t word_of_aligned_array(const uint16_t *aligned_array, uint32_t index); uint16_t word_of_aligned_array(const uint16_t *aligned_array, uint32_t index);
// uint8_t flash_rom_get_checksum(void);
// uint8_t flash_rom_calc_checksum(void);
#endif // __FLASH_API_H__ #endif // __FLASH_API_H__

View File

@ -946,6 +946,15 @@ uint32_t platform_flash_phys2mapped (uint32_t phys_addr) {
return (meg&1) ? -1 : phys_addr + INTERNAL_FLASH_MAPPED_ADDRESS - meg; return (meg&1) ? -1 : phys_addr + INTERNAL_FLASH_MAPPED_ADDRESS - meg;
} }
uint32_t platform_flash_get_partition (uint32_t part_id, uint32_t *addr) {
partition_item_t pt = {0,0,0};
system_partition_get_item(SYSTEM_PARTITION_CUSTOMER_BEGIN + part_id, &pt);
if (addr) {
*addr = pt.addr;
}
return pt.type == 0 ? 0 : pt.size;
}
void* platform_print_deprecation_note( const char *msg, const char *time_frame) void* platform_print_deprecation_note( const char *msg, const char *time_frame)
{ {
c_printf( "Warning, deprecated API! %s. It will be removed %s. See documentation for details.\n", msg, time_frame ); c_printf( "Warning, deprecated API! %s. It will be removed %s. See documentation for details.\n", msg, time_frame );

View File

@ -289,6 +289,7 @@ int platform_flash_erase_sector( uint32_t sector_id );
*/ */
uint32_t platform_flash_mapped2phys (uint32_t mapped_addr); uint32_t platform_flash_mapped2phys (uint32_t mapped_addr);
uint32_t platform_flash_phys2mapped (uint32_t phys_addr); uint32_t platform_flash_phys2mapped (uint32_t phys_addr);
uint32_t platform_flash_get_partition (uint32_t part_id, uint32_t *addr);
// ***************************************************************************** // *****************************************************************************
// Allocator support // Allocator support

View File

@ -33,11 +33,14 @@ sint32_t vfs_get_rtc( vfs_time *tm )
static int dir_level = 1; static int dir_level = 1;
#if ! LDRV_TRAVERSAL
#define normalize_path(p) (p)
#else
static const char *normalize_path( const char *path ) static const char *normalize_path( const char *path )
{ {
#if ! LDRV_TRAVERSAL
return path;
#else
const char *temp = path; const char *temp = path;
size_t len; size_t len;
@ -63,8 +66,8 @@ static const char *normalize_path( const char *path )
// path traverses via root // path traverses via root
return temp; return temp;
} }
#endif
} }
#endif
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -23,6 +23,7 @@ endif
# for a subtree within the makefile rooted therein # for a subtree within the makefile rooted therein
# #
DEFINES += -Dprintf=c_printf DEFINES += -Dprintf=c_printf
#DEFINES += -DDEVELOPMENT_TOOLS -DNODE_DEBUG -DSPIFFS_API_DBG=NODE_DBG
############################################################# #############################################################
# Recursion Magic - Don't touch this!! # Recursion Magic - Don't touch this!!

View File

@ -1,20 +0,0 @@
#include "spiffs.h"
bool myspiffs_mount();
void myspiffs_unmount();
int myspiffs_open(const char *name, int flags);
int myspiffs_close( int fd );
size_t myspiffs_write( int fd, const void* ptr, size_t len );
size_t myspiffs_read( int fd, void* ptr, size_t len);
int myspiffs_lseek( int fd, int off, int whence );
int myspiffs_eof( int fd );
int myspiffs_tell( int fd );
int myspiffs_getc( int fd );
int myspiffs_ungetc( int c, int fd );
int myspiffs_flush( int fd );
int myspiffs_error( int fd );
void myspiffs_clearerr( int fd );
int myspiffs_check( void );
int myspiffs_rename( const char *old, const char *newname );
size_t myspiffs_size( int fd );
int myspiffs_format (void);

View File

@ -2,14 +2,31 @@
#include "platform.h" #include "platform.h"
#include "spiffs.h" #include "spiffs.h"
/*
* With the intoduction of a unified FatFS and SPIFFS support (#1397), the SPIFFS
* interface is now abstracted through a uses a single SPIFFS entry point
* myspiffs_realm() which returns a vfs_fs_fns object (as does myfatfs_realm()).
* All other functions and data are static.
*
* Non-OS SDK V3.0 introduces a flash partition table (PT) and SPIFFS has now been
* updated to support this:
* - SPIFFS limits search to the specifed SPIFFS0 address and size.
* - Any headroom / offset from other partitions is reflected in the PT allocations.
* - Unforced mounts will attempt to mount any valid SPIFSS found in this range
* (NodeMCU uses the SPIFFS_USE_MAGIC setting to make existing FS discoverable).
* - Subject to the following, no offset or FS search is done. The FS is assumed
* to be at the first valid location at the start of the partition.
*/
#include "spiffs_nucleus.h" #include "spiffs_nucleus.h"
spiffs fs; static spiffs fs;
#define LOG_PAGE_SIZE 256 #define LOG_PAGE_SIZE 256
#define LOG_BLOCK_SIZE (INTERNAL_FLASH_SECTOR_SIZE * 2) #define LOG_BLOCK_SIZE (INTERNAL_FLASH_SECTOR_SIZE * 2)
#define LOG_BLOCK_SIZE_SMALL_FS (INTERNAL_FLASH_SECTOR_SIZE) #define LOG_BLOCK_SIZE_SMALL_FS (INTERNAL_FLASH_SECTOR_SIZE)
#define MIN_BLOCKS_FS 4 #define MIN_BLOCKS_FS 4
#define MASK_1MB (0x100000-1)
#define ALIGN (0x2000)
static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2]; static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
static u8_t spiffs_fds[sizeof(spiffs_fd) * SPIFFS_MAX_OPEN_FILES]; static u8_t spiffs_fds[sizeof(spiffs_fd) * SPIFFS_MAX_OPEN_FILES];
@ -42,131 +59,64 @@ void myspiffs_check_callback(spiffs_check_type type, spiffs_check_report report,
} }
/******************* /*******************
The W25Q32BV array is organized into 16,384 programmable pages of 256-bytes each. Up to 256 bytes can be programmed at a time.  * Note that the W25Q32BV array is organized into 16,384 programmable pages of 256-bytes 
Pages can be erased in groups of 16 (4KB sector erase), groups of 128 (32KB block erase), groups of 256 (64KB block erase) or  * each. Up to 256 bytes can be programmed at a time. Pages can be erased in groups of 
the entire chip (chip erase). The W25Q32BV has 1,024 erasable sectors and 64 erasable blocks respectively.  * 16 (4KB sector erase), groups of 128 (32KB block erase), groups of 256 (64KB block 
The small 4KB sectors allow for greater flexibility in applications that require data and parameter storage.  * erase) or the entire chip (chip erase). The W25Q32BV has 1,024 erasable sectors and 
* 64 erasable blocks respectively. The small 4KB sectors allow for greater flexibility 
* in applications that require data and parameter storage. 
*
* Returns TRUE if FS was found.
*/
static bool myspiffs_set_cfg(spiffs_config *cfg, bool force_create) {
uint32 pt_start, pt_size, pt_end;
********************/ pt_size = platform_flash_get_partition (NODEMCU_SPIFFS0_PARTITION, &pt_start);
if (pt_size == 0) {
static bool myspiffs_set_location(spiffs_config *cfg, int align, int offset, int block_size) {
#ifdef SPIFFS_FIXED_LOCATION
cfg->phys_addr = (SPIFFS_FIXED_LOCATION + block_size - 1) & ~(block_size-1);
#else
cfg->phys_addr = ( u32_t )platform_flash_get_first_free_block_address( NULL ) + offset;
cfg->phys_addr = (cfg->phys_addr + align - 1) & ~(align - 1);
#endif
#ifdef SPIFFS_SIZE_1M_BOUNDARY
cfg->phys_size = ((0x100000 - (SYS_PARAM_SEC_NUM * INTERNAL_FLASH_SECTOR_SIZE) - ( ( u32_t )cfg->phys_addr )) & ~(block_size - 1)) & 0xfffff;
#else
cfg->phys_size = (INTERNAL_FLASH_SIZE - ( ( u32_t )cfg->phys_addr )) & ~(block_size - 1);
#endif
if ((int) cfg->phys_size < 0) {
return FALSE; return FALSE;
} }
cfg->log_block_size = block_size; pt_end = pt_start + pt_size;
return (cfg->phys_size / block_size) >= MIN_BLOCKS_FS;
}
/*
* Returns TRUE if FS was found
* align must be a power of two
*/
static bool myspiffs_set_cfg_block(spiffs_config *cfg, int align, int offset, int block_size, bool force_create) {
cfg->phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet
cfg->log_page_size = LOG_PAGE_SIZE; // as we said
cfg->hal_read_f = my_spiffs_read; cfg->hal_read_f = my_spiffs_read;
cfg->hal_write_f = my_spiffs_write; cfg->hal_write_f = my_spiffs_write;
cfg->hal_erase_f = my_spiffs_erase; cfg->hal_erase_f = my_spiffs_erase;
cfg->phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE;
cfg->log_page_size = LOG_PAGE_SIZE;
cfg->phys_addr = (pt_start + ALIGN - 1) & ~(ALIGN - 1);
cfg->phys_size = (pt_end & ~(ALIGN - 1)) - cfg->phys_addr;
if (!myspiffs_set_location(cfg, align, offset, block_size)) { if (cfg->phys_size < MIN_BLOCKS_FS * LOG_BLOCK_SIZE_SMALL_FS) {
return FALSE; return FALSE;
} else if (cfg->phys_size < MIN_BLOCKS_FS * LOG_BLOCK_SIZE_SMALL_FS) {
cfg->log_block_size = LOG_BLOCK_SIZE_SMALL_FS;
} else {
cfg->log_block_size = LOG_BLOCK_SIZE;
} }
NODE_DBG("fs.start:%x,max:%x\n",cfg->phys_addr,cfg->phys_size);
#ifdef SPIFFS_USE_MAGIC_LENGTH #ifdef SPIFFS_USE_MAGIC_LENGTH
if (force_create) { if (!force_create) {
return TRUE;
}
int size = SPIFFS_probe_fs(cfg); int size = SPIFFS_probe_fs(cfg);
if (size > 0 && size < cfg->phys_size) { if (size > 0 && size < cfg->phys_size) {
NODE_DBG("Overriding size:%x\n",size); NODE_DBG("Overriding size:%x\n",size);
cfg->phys_size = size; cfg->phys_size = size;
} }
if (size > 0) { if (size <= 0) {
return TRUE;
}
return FALSE;
#else
return TRUE;
#endif
}
static bool myspiffs_set_cfg(spiffs_config *cfg, int align, int offset, bool force_create) {
if (force_create) {
return myspiffs_set_cfg_block(cfg, align, offset, LOG_BLOCK_SIZE , TRUE) ||
myspiffs_set_cfg_block(cfg, align, offset, LOG_BLOCK_SIZE_SMALL_FS, TRUE);
}
return myspiffs_set_cfg_block(cfg, align, offset, LOG_BLOCK_SIZE_SMALL_FS, FALSE) ||
myspiffs_set_cfg_block(cfg, align, offset, LOG_BLOCK_SIZE , FALSE);
}
static bool myspiffs_find_cfg(spiffs_config *cfg, bool force_create) {
int i;
if (!force_create) {
#ifdef SPIFFS_FIXED_LOCATION
if (myspiffs_set_cfg(cfg, 0, 0, FALSE)) {
return TRUE;
}
#else
if (INTERNAL_FLASH_SIZE >= 700000) {
for (i = 0; i < 8; i++) {
if (myspiffs_set_cfg(cfg, 0x10000, 0x10000 * i, FALSE)) {
return TRUE;
}
}
}
for (i = 0; i < 8; i++) {
if (myspiffs_set_cfg(cfg, LOG_BLOCK_SIZE, LOG_BLOCK_SIZE * i, FALSE)) {
return TRUE;
}
}
#endif
}
// No existing file system -- set up for a format
if (INTERNAL_FLASH_SIZE >= 700000) {
myspiffs_set_cfg(cfg, 0x10000, 0x10000, TRUE);
#ifndef SPIFFS_MAX_FILESYSTEM_SIZE
if (cfg->phys_size < 400000) {
// Don't waste so much in alignment
myspiffs_set_cfg(cfg, LOG_BLOCK_SIZE, LOG_BLOCK_SIZE * 4, TRUE);
}
#endif
} else {
myspiffs_set_cfg(cfg, LOG_BLOCK_SIZE, 0, TRUE);
}
#ifdef SPIFFS_MAX_FILESYSTEM_SIZE
if (cfg->phys_size > SPIFFS_MAX_FILESYSTEM_SIZE) {
cfg->phys_size = (SPIFFS_MAX_FILESYSTEM_SIZE) & ~(cfg->log_block_size - 1);
}
#endif
return FALSE; return FALSE;
} }
}
#endif
static bool myspiffs_mount_internal(bool force_mount) { NODE_DBG("myspiffs set cfg block: %x %x %x %x %x %x\n", pt_start, pt_end,
cfg->phys_size, cfg->phys_addr, cfg->phys_size, cfg->log_block_size);
return TRUE;
}
static bool myspiffs_mount(bool force_mount) {
spiffs_config cfg; spiffs_config cfg;
if (!myspiffs_find_cfg(&cfg, force_mount) && !force_mount) { if (!myspiffs_set_cfg(&cfg, force_mount) && !force_mount) {
return FALSE; return FALSE;
} }
@ -189,10 +139,6 @@ static bool myspiffs_mount_internal(bool force_mount) {
return res == SPIFFS_OK; return res == SPIFFS_OK;
} }
bool myspiffs_mount() {
return myspiffs_mount_internal(FALSE);
}
void myspiffs_unmount() { void myspiffs_unmount() {
SPIFFS_unmount(&fs); SPIFFS_unmount(&fs);
} }
@ -202,7 +148,7 @@ void myspiffs_unmount() {
int myspiffs_format( void ) int myspiffs_format( void )
{ {
SPIFFS_unmount(&fs); SPIFFS_unmount(&fs);
myspiffs_mount_internal(TRUE); myspiffs_mount(TRUE);
SPIFFS_unmount(&fs); SPIFFS_unmount(&fs);
NODE_DBG("Formatting: size 0x%x, addr 0x%x\n", fs.cfg.phys_size, fs.cfg.phys_addr); NODE_DBG("Formatting: size 0x%x, addr 0x%x\n", fs.cfg.phys_size, fs.cfg.phys_addr);
@ -211,7 +157,7 @@ int myspiffs_format( void )
return 0; return 0;
} }
return myspiffs_mount(); return myspiffs_mount(FALSE);
} }
#if 0 #if 0
@ -555,7 +501,7 @@ static sint32_t myspiffs_vfs_fscfg( uint32_t *phys_addr, uint32_t *phys_size ) {
static vfs_vol *myspiffs_vfs_mount( const char *name, int num ) { static vfs_vol *myspiffs_vfs_mount( const char *name, int num ) {
// volume descriptor not supported, just return TRUE / FALSE // volume descriptor not supported, just return TRUE / FALSE
return myspiffs_mount() ? (vfs_vol *)1 : NULL; return myspiffs_mount(FALSE) ? (vfs_vol *)1 : NULL;
} }
static sint32_t myspiffs_vfs_format( void ) { static sint32_t myspiffs_vfs_format( void ) {
@ -574,12 +520,12 @@ static void myspiffs_vfs_clearerr( void ) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// VFS interface functions // VFS interface functions
// //
vfs_fs_fns *myspiffs_realm( const char *inname, char **outname, int set_current_drive ) { vfs_fs_fns *myspiffs_realm( const char *inname, char **outname, int set_current_drive ) {
if (inname[0] == '/') { if (inname[0] == '/') {
size_t idstr_len = c_strlen( MY_LDRV_ID );
// logical drive is specified, check if it's our id // logical drive is specified, check if it's our id
if (0 == c_strncmp( &(inname[1]), MY_LDRV_ID, idstr_len )) { if (0 == c_strncmp(inname + 1, MY_LDRV_ID, sizeof(MY_LDRV_ID)-1)) {
*outname = (char *)&(inname[1 + idstr_len]); *outname = (char *)(inname + sizeof(MY_LDRV_ID));
if (*outname[0] == '/') { if (*outname[0] == '/') {
// skip leading / // skip leading /
(*outname)++; (*outname)++;

View File

@ -165,7 +165,7 @@
// Lower value generates more read/writes. No meaning having it bigger // Lower value generates more read/writes. No meaning having it bigger
// than logical page size. // than logical page size.
#ifndef SPIFFS_COPY_BUFFER_STACK #ifndef SPIFFS_COPY_BUFFER_STACK
#define SPIFFS_COPY_BUFFER_STACK (64) #define SPIFFS_COPY_BUFFER_STACK (256)
#endif #endif
// Enable this to have an identifiable spiffs filesystem. This will look for // Enable this to have an identifiable spiffs filesystem. This will look for

View File

@ -1,115 +0,0 @@
/*
* Copyright 2015 Dius Computing Pty Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the copyright holders nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Johny Mattsson <jmattsson@dius.com.au>
*/
#include "user_exceptions.h"
static exception_handler_fn load_store_handler;
void load_non_32_wide_handler (struct exception_frame *ef, uint32_t cause)
{
uint32_t val, insn;
(void)cause; /* If this is not EXCCAUSE_LOAD_STORE_ERROR you're doing it wrong! */
asm (
/*
* Move the aligned content of the exception addr to val
*/
"rsr a6, EXCVADDR;" /* read out the faulting address */
"movi a5, ~3;" /* prepare a mask for the EPC */
"and a5, a5, a6;" /* apply mask for 32bit aligned base */
"l32i a5, a5, 0;" /* load aligned value */
"ssa8l a6;" /* set up shift register for value */
"srl %[val], a5;" /* shift left to align value */
/* we are done with a6 = EXCVADDR */
/*
* Move the aligned instruction to insn
*/
"movi a5, ~3;" /* prepare a mask for the insn */
"and a6, a5, %[epc];" /* apply mask for 32bit aligned base */
"l32i a5, a6, 0;" /* load part 1 */
"l32i a6, a6, 4;" /* load part 2 */
"ssa8l %[epc];" /* set up shift register for src op */
"src %[op], a6, a5;" /* right shift to get faulting instruction */
:[val]"=r"(val), [op]"=r"(insn)
:[epc]"r"(ef->epc)
:"a5", "a6"
);
/* These instructions have the format 0xADSBII where AB = opcode and D = dest reg */
uint32_t regno = (insn>>4)&0x0f; /* pick out nibble D*/
uint32_t opcode = (uint8_t) (((insn>>12)<<4)|(insn&0xf)); /* and nibbles AB */
#define L8UI 0x02u
#define L16UI 0x12u
#define L16SI 0x92u
if (opcode == L8UI) { /* L8UI */
val = (uint8_t) val;
} else {
val = (uint16_t) val; /* assume L16SI or L16UI */
if (opcode == L16SI) {
val = (unsigned)((int)((sint16_t)val)); /* force signed 16->32 bit */
} else if (opcode != L16UI) {
/*
* Anything other than L8UI, L16SI or L16UI then chain to the next handler
* if set (typically a remote GDB break). Otherwise execute the default action
* which is to trigger a system break and hang if the break doesn't get handled
*/
if (load_store_handler) {
load_store_handler(NULL, 0 /* ef , cause */);
return;
} else {
asm ("break 1, 1");
while (1) {}
}
}
}
ef->a_reg[regno ? regno-1: regno] = val; /* carry out the load */
ef->epc += 3; /* resume at following instruction */
}
/**
* The SDK's user_main function installs a debugging handler regardless
* of whether there's a proper handler installed for EXCCAUSE_LOAD_STORE_ERROR,
* which of course breaks everything if we allow that to go through. As such,
* we use the linker to wrap that call and stop the SDK from shooting itself in
* its proverbial foot. We do save the EXCCAUSE_LOAD_STORE_ERROR handler so that
* we can chain to it above.
*/
exception_handler_fn TEXT_SECTION_ATTR
__wrap__xtos_set_exception_handler (uint32_t cause, exception_handler_fn fn)
{
if (cause != EXCCAUSE_LOAD_STORE_ERROR)
__real__xtos_set_exception_handler (cause, fn);
else
load_store_handler = fn;
}

View File

@ -16,7 +16,6 @@
#include "vfs.h" #include "vfs.h"
#include "flash_api.h" #include "flash_api.h"
#include "user_interface.h" #include "user_interface.h"
#include "user_exceptions.h"
#include "user_modules.h" #include "user_modules.h"
#include "ets_sys.h" #include "ets_sys.h"
@ -24,6 +23,7 @@
#include "task/task.h" #include "task/task.h"
#include "mem.h" #include "mem.h"
#include "espconn.h" #include "espconn.h"
#include "sections.h"
#ifdef LUA_USE_MODULES_RTCTIME #ifdef LUA_USE_MODULES_RTCTIME
#include "rtc/rtctime.h" #include "rtc/rtctime.h"
@ -36,74 +36,163 @@ static uint8 input_sig_flag = 0;
extern const uint32_t init_data[]; extern const uint32_t init_data[];
extern const uint32_t init_data_end[]; extern const uint32_t init_data_end[];
__asm__( __asm__(
/* Place in .text for same reason as user_start_trampoline */
".section \".rodata.dram\"\n"
".align 4\n" ".align 4\n"
"init_data:\n" "init_data: .incbin \"" ESP_INIT_DATA_DEFAULT "\"\n"
".incbin \"" ESP_INIT_DATA_DEFAULT "\"\n"
"init_data_end:\n" "init_data_end:\n"
".previous\n"
); );
extern const char _irom0_text_start[], _irom0_text_end[],_flash_used_end[];
#define IROM0_SIZE (_irom0_text_end - _irom0_text_start)
/* Note: the trampoline *must* be explicitly put into the .text segment, since #define INIT_DATA_SIZE (init_data_end - init_data)
* by the time it is invoked the irom has not yet been mapped. This naturally
* also goes for anything the trampoline itself calls. #define PRE_INIT_TEXT_ATTR __attribute__((section(".p3.pre_init")))
#define IROM_PTABLE_ATTR __attribute__((section(".irom0.ptable")))
#define PARTITION(n) (SYSTEM_PARTITION_CUSTOMER_BEGIN + n)
#define SIZE_256K 0x00040000
#define SIZE_1024K 0x00100000
#define FLASH_BASE_ADDR ((char *) 0x40200000)
//TODO: map the TLS server and client certs into NODEMCU_TLSCERT_PARTITION
const partition_item_t partition_init_table[] IROM_PTABLE_ATTR = {
{ PARTITION(NODEMCU_EAGLEROM_PARTITION), 0x00000, 0x0B000},
{ SYSTEM_PARTITION_RF_CAL, 0x0B000, 0x1000},
{ SYSTEM_PARTITION_PHY_DATA, 0x0C000, 0x1000},
{ SYSTEM_PARTITION_SYSTEM_PARAMETER, 0x0D000, 0x3000},
{ PARTITION(NODEMCU_IROM0TEXT_PARTITION), 0x10000, 0x0000},
{ PARTITION(NODEMCU_LFS0_PARTITION), 0x0, LUA_FLASH_STORE},
{ PARTITION(NODEMCU_SPIFFS0_PARTITION), 0x0, SPIFFS_MAX_FILESYSTEM_SIZE},
{0,(uint32_t) &_irom0_text_end,0}
};
// The following enum must maintain the partition table order
enum partition {iram0=0, rf_call, phy_data, sys_parm, irom0, lfs, spiffs};
#define PTABLE_SIZE ((sizeof(partition_init_table)/sizeof(partition_item_t))-1)
#define PT_CHUNK 0x8000
#define PT_ALIGN(n) ((n + (PT_CHUNK-1)) & (~((PT_CHUNK-1))))
/*
* The non-OS SDK prolog has been fundamentally revised in V3. See SDK EN document
* Partition Table.md for further discussion. This version of user_main.c is a
* complete rework aligned to V3, with the redundant pre-V3 features removed.
*
* SDK V3 significantly reduces the RAM footprint required by the SDK and introduces
* the use of a partition table (PT) to control flash allocation. The NodeMCU uses
* this PT for overall allocation of its flash resources. A constant copy PT is
* maintained at the start of IROM0 (flash offset 0x10000) -- see partition_init_table
* declaration above -- to facilitate its modification either in the firmware binary
* or in the flash itself. This is Flash PT used during startup to create the live PT
* in RAM that is used by the SDK.
*
* Note that user_pre_init() runs with Icache enabled -- that is the IROM0 partition
* is already mapped the address space at 0x40210000 and so that most SDK services
* are available, such as system_get_flash_size_map() which returns the valid flash
* size (including the 8Mb and 16Mb variants).
*
* We will be separately releasing a host PC-base python tool to configure the PT,
* etc., but the following code will initialise the PT to sensible defaults even if
* this tool isn't used.
*/ */
void TEXT_SECTION_ATTR user_start_trampoline (void) static int setup_partition_table(partition_item_t *pt, uint32_t *n) {
{
__real__xtos_set_exception_handler (
EXCCAUSE_LOAD_STORE_ERROR, load_non_32_wide_handler);
// Flash size lookup is SIZE_256K*2^N where N is as follows (see SDK/user_interface.h)
static char flash_size_scaler[] =
/* 0 1 2 3 4 5 6 7 8 9 */
/* ½M ¼M 1M 2M 4M 2M 4M 4M 8M 16M */
"\001\000\002\003\004\003\004\004\005\006";
enum flash_size_map fs_size_code = system_get_flash_size_map();
uint32_t flash_size = SIZE_256K << flash_size_scaler[fs_size_code];
uint32_t first_free_flash_addr = partition_init_table[PTABLE_SIZE].addr
- (uint32_t) FLASH_BASE_ADDR;
int i,j;
os_memcpy(pt, partition_init_table, PTABLE_SIZE * sizeof(*pt));
if (flash_size < SIZE_1024K) {
os_printf("Flash size (%u) too small to support NodeMCU\n", flash_size);
return -1;
} else {
os_printf("system SPI FI size:%u, Flash size: %u\n", fs_size_code, flash_size );
}
// Calculate the runtime sized partitions
// The iram0, rf_call, phy_data, sys_parm partitions are as-is.
if (pt[irom0].size == 0) {
pt[irom0].size = first_free_flash_addr - pt[irom0].addr;
}
if (pt[lfs].addr == 0) {
pt[lfs].addr = PT_ALIGN(pt[irom0].addr + pt[irom0].size);
os_printf("LFS base: %08X\n", pt[lfs].addr);
}
if (pt[lfs].size == 0) {
pt[lfs].size = 0x10000;
os_printf("LFS size: %08X\n", pt[lfs].size);
}
if (pt[spiffs].addr == 0) {
pt[spiffs].addr = PT_ALIGN(pt[lfs].addr + pt[lfs].size);
os_printf("SPIFFS base: %08X\n", pt[spiffs].addr);
}
if (pt[spiffs].size == SPIFFS_MAX_FILESYSTEM_SIZE) {
pt[spiffs].size = flash_size - pt[spiffs].addr;
os_printf("SPIFFS size: %08X\n", pt[spiffs].size);
}
// Check that the phys data partition has been initialised and if not then do this
// now to prevent the SDK halting on a "rf_cal[0] !=0x05,is 0xFF" error.
uint32_t init_data_hdr = 0xffffffff, data_addr = pt[phy_data].addr;
int status = spi_flash_read(data_addr, &init_data_hdr, sizeof (uint32_t));
if (status == SPI_FLASH_RESULT_OK && *(char *)&init_data_hdr != 0x05) {
uint32_t idata[INIT_DATA_SIZE];
os_printf("Writing Init Data to 0x%08x\n",data_addr);
spi_flash_erase_sector(data_addr/SPI_FLASH_SEC_SIZE);
os_memcpy(idata, init_data, sizeof(idata));
spi_flash_write(data_addr, idata, sizeof(idata));
os_delay_us(1000);
}
// Check partitions are page aligned and remove and any zero-length partitions.
// This must be done last as this might break the enum partition ordering.
for (i = 0, j = 0; i < PTABLE_SIZE; i++) {
const partition_item_t *p = pt + i;
if ((p->addr| p->size) & (SPI_FLASH_SEC_SIZE-1)) {
os_printf("Partitions must be flash page aligned\n");
return -1;
}
if (p->size == 0)
continue;
if (j < i) {
pt[j] = *p;
p = pt + j;
}
os_printf("%2u: %08x %08x %08x\n", j, p->type, p->addr, p->size);
j++;
}
*n = j;
return fs_size_code;
}
void user_pre_init(void) {
#ifdef LUA_USE_MODULES_RTCTIME #ifdef LUA_USE_MODULES_RTCTIME
// Note: Keep this as close to call_user_start() as possible, since it // Note: Keep this as close to call_user_start() as possible, since it
// is where the cpu clock actually gets bumped to 80MHz. // is where the cpu clock actually gets bumped to 80MHz.
rtctime_early_startup (); rtctime_early_startup ();
#endif #endif
static partition_item_t pt[PTABLE_SIZE];
/* Re-implementation of default init data deployment. The SDK does not uint32_t pt_size;
* appear to be laying down its own version of init data anymore, so uint32_t fs_size_code = setup_partition_table(pt, &pt_size);
* we have to do it again. To see whether we need to, we read out if( fs_size_code > 0 && system_partition_table_regist(pt, pt_size, fs_size_code)) {
* the flash size and do a test for esp_init_data based on that size. return;
* If it's missing, we need to initialize it *right now* before the SDK
* starts up and gets stuck at "rf_cal[0] !=0x05,is 0xFF".
* If the size byte is wrong, then we'll end up fixing up the init data
* again on the next boot, after we've corrected the size byte.
* Only remaining issue is lack of spare code bytes in iram, so this
* is deliberately quite terse and not as readable as one might like.
*/
SPIFlashInfo sfi;
// enable operations on >4MB flash chip
extern SpiFlashChip * flashchip;
uint32 orig_chip_size = flashchip->chip_size;
flashchip->chip_size = FLASH_SIZE_16MBYTE;
SPIRead (0, (uint32_t *)(&sfi), sizeof (sfi)); // Cache read not enabled yet, safe to use
// handle all size entries
switch (sfi.size) {
case 0: sfi.size = 1; break; // SIZE_4MBIT
case 1: sfi.size = 0; break; // SIZE_2MBIT
case 5: sfi.size = 3; break; // SIZE_16MBIT_8M_8M
case 6: // fall-through
case 7: sfi.size = 4; break; // SIZE_32MBIT_8M_8M, SIZE_32MBIT_16M_16M
case 8: sfi.size = 5; break; // SIZE_64MBIT
case 9: sfi.size = 6; break; // SIZE_128MBIT
default: break;
} }
uint32_t flash_end_addr = (256 * 1024) << sfi.size; os_printf("system_partition_table_regist fail (%u)\n", fs_size_code);
uint32_t init_data_hdr = 0xffffffff; while(1);
uint32_t init_data_addr = flash_end_addr - 4 * SPI_FLASH_SEC_SIZE;
SPIRead (init_data_addr, &init_data_hdr, sizeof (init_data_hdr));
if (init_data_hdr == 0xffffffff)
{
SPIEraseSector (init_data_addr);
SPIWrite (init_data_addr, init_data, 4 * (init_data_end - init_data));
} }
// revert temporary setting uint32 ICACHE_RAM_ATTR user_iram_memory_is_enabled(void) {
flashchip->chip_size = orig_chip_size; return FALSE; // NodeMCU runs like a dog if iRAM is enabled
call_user_start ();
} }
// +================== New task interface ==================+ // +================== New task interface ==================+
@ -138,18 +227,6 @@ void nodemcu_init(void) {
NODE_DBG("Can not init platform for modules.\n"); NODE_DBG("Can not init platform for modules.\n");
return; return;
} }
uint32_t size_detected = flash_detect_size_byte();
uint32_t size_from_rom = flash_rom_get_size_byte();
if( size_detected != size_from_rom ) {
NODE_ERR("Self adjust flash size. 0x%x (ROM) -> 0x%x (Detected)\n",
size_from_rom, size_detected);
// Fit hardware real flash size.
flash_rom_set_size_byte(size_detected);
system_restart ();
// Don't post the start_lua task, we're about to reboot...
return;
}
#ifdef BUILD_SPIFFS #ifdef BUILD_SPIFFS
if (!vfs_mount("/FLASH", 0)) { if (!vfs_mount("/FLASH", 0)) {
@ -159,11 +236,8 @@ void nodemcu_init(void) {
NODE_ERR( "\n*** ERROR ***: unable to format. FS might be compromised.\n" ); NODE_ERR( "\n*** ERROR ***: unable to format. FS might be compromised.\n" );
NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" ); NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
} }
// Note that fs_format leaves the file system mounted
} }
// test_spiffs();
#endif #endif
// endpoint_setup();
if (!task_post_low(task_get_id(start_lua),'s')) if (!task_post_low(task_get_id(start_lua),'s'))
NODE_ERR("Failed to post the start_lua task!\n"); NODE_ERR("Failed to post the start_lua task!\n");
@ -179,59 +253,6 @@ void user_rf_pre_init(void)
} }
#endif #endif
/******************************************************************************
* FunctionName : user_rf_cal_sector_set
* Description : SDK just reversed 4 sectors, used for rf init data and paramters.
* We add this function to force users to set rf cal sector, since
* we don't know which sector is free in user's application.
* sector map for last several sectors : ABCCC
* A : rf cal
* B : rf init data
* C : sdk parameters
* Parameters : none
* Returns : rf cal sector
*******************************************************************************/
uint32
user_rf_cal_sector_set(void)
{
enum flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
break;
case FLASH_SIZE_16M_MAP_512_512:
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_32M_MAP_512_512:
case FLASH_SIZE_32M_MAP_1024_1024:
case FLASH_SIZE_32M_MAP_2048_2048:
rf_cal_sec = 1024 - 5;
break;
case FLASH_SIZE_64M_MAP_1024_1024:
rf_cal_sec = 2048 - 5;
break;
case FLASH_SIZE_128M_MAP_1024_1024:
rf_cal_sec = 4096 - 5;
break;
default:
rf_cal_sec = 0;
break;
}
return rf_cal_sec;
}
/****************************************************************************** /******************************************************************************
* FunctionName : user_init * FunctionName : user_init
@ -241,6 +262,7 @@ user_rf_cal_sector_set(void)
*******************************************************************************/ *******************************************************************************/
void user_init(void) void user_init(void)
{ {
#ifdef LUA_USE_MODULES_RTCTIME #ifdef LUA_USE_MODULES_RTCTIME
rtctime_late_startup (); rtctime_late_startup ();
#endif #endif
@ -255,3 +277,18 @@ void user_init(void)
#endif #endif
system_init_done_cb(nodemcu_init); system_init_done_cb(nodemcu_init);
} }
/*
* The SDK now establishes exception handlers for EXCCAUSE errors: ILLEGAL,
* INSTR_ERROR, LOAD_STORE_ERROR, PRIVILEGED, UNALIGNED, LOAD_PROHIBITED,
* STORE_PROHIBITED. These handlers are established in SDK/app_main.c.
* LOAD_STORE_ERROR is handled by SDK/user_exceptions.o:load_non_32_wide_handler()
* which is a fork of our version. The remaining are handled by a static function
* at SDK:app+main.c:offset 0x0348.
*
void __real__xtos_set_exception_handler (uint32_t cause, exception_handler_fn fn);
void __wrap__xtos_set_exception_handler (uint32_t cause, exception_handler_fn fn) {
os_printf("Exception handler %x %x\n", cause, fn);
__real__xtos_set_exception_handler (cause, fn);
}
*/

View File

@ -50,19 +50,20 @@ mode is enabled by specifying the `-f`option.
- **Compact relocatable**. This is selected by the `-f` option. Here the compiler compresses the compiled binary so that image is small for downloading over Wifi/WAN (e.g. a full 64Kb LFS image is compressed down to a 22Kb file.) The LVM processes such image in two passes with the integrity of the image validated on the first, and the LFS itself gets updated on the second. The LVM also checks that the image will fit in the allocated LFS region before loading, but you can also use the `-m` option to throw a compile error if the image is too large, for example `-m 0x10000` will raise an error if the image will not load into a 64Kb regions. - **Compact relocatable**. This is selected by the `-f` option. Here the compiler compresses the compiled binary so that image is small for downloading over Wifi/WAN (e.g. a full 64Kb LFS image is compressed down to a 22Kb file.) The LVM processes such image in two passes with the integrity of the image validated on the first, and the LFS itself gets updated on the second. The LVM also checks that the image will fit in the allocated LFS region before loading, but you can also use the `-m` option to throw a compile error if the image is too large, for example `-m 0x10000` will raise an error if the image will not load into a 64Kb regions.
- **Absolute**. This is selected by the `-a <baseAddr>` option. Here the compiler fixes all addresses relative to the base address specified. This allows an LFS absolute image to be loaded directly into the ESP flash using a tool such as `esptool.py`. - **Absolute**. This is selected by the `-a <baseAddr>` option. Here the compiler fixes all addresses relative to the base address specified. This allows an LFS absolute image to be loaded directly into the ESP flash using a tool such as `esptool.py`. _Note that the new NodeMCU loader uses the `-f` compact relocatable form and does relocation based on the Partition Table, so this option is deprecated and will be removed in future releases.
These two modes target two separate use cases: the compact relocatable format These two modes target two separate use cases: the compact relocatable format
facilitates simple OTA updates to an LFS based Lua application; the absolute format facilitates simple OTA updates to an LFS based Lua application; the absolute format
facilitates factory installation of LFS based applications. facilitates factory installation of LFS based applications.
Also note that the `app/lua/luac_cross` make and Makefile can be executed to build Also note that the `app/lua/luac_cross` make and Makefile can be executed to build
just the `luac.cross` image. You must first ensure that the following options in just the `luac.cross` image. You must first ensure that the following option in
`app/include/user_config.h` are matched to your target configuration: `app/include/user_config.h` is matched to your target configuration:
```c ```c
//#define LUA_NUMBER_INTEGRAL // uncomment if you want an integer build //#define LUA_NUMBER_INTEGRAL // uncomment if you want an integer build
//#define LUA_FLASH_STORE 0x10000 // uncomment if you LFS support
``` ```
Note that the use of LFS and the LFS region size is now configured through the partition table.
Developers have successfully built this on Linux (including docker builds), MacOS, Win10/WSL and WinX/Cygwin. Developers have successfully built this on Linux (including docker builds), MacOS, Win10/WSL and WinX/Cygwin.

View File

@ -226,7 +226,7 @@ Detailed instructions available in the image's README. As for available config o
### For LFS ### For LFS
1. In `app/include/user_config.h` uncomment `#define LUA_FLASH_STORE 0x10000` and adjust the size if necessary. 1. In `app/include/user_config.h` edit the line `#define LUA_FLASH_STORE 0x0` and adjust the size to that needed. Note that this must be a multiple of 4Kb.
2. Build as you would otherwise build with this image (i.e. see its README) 2. Build as you would otherwise build with this image (i.e. see its README)
[↑ back to matrix](#task-os-selector) [↑ back to matrix](#task-os-selector)
@ -238,24 +238,25 @@ _Note that this Docker image is not an official NodeMCU offering. It's maintaine
A local copy of `luac.cross` is only needed if you want to compile the Lua files into an LFS image yourself and you are _not_ using Docker. A local copy of `luac.cross` is only needed if you want to compile the Lua files into an LFS image yourself and you are _not_ using Docker.
### Windows ### Windows
Windows 10 users can install and use the Windows Subsystem for Linux (WSL). Alternatively all Windows users can [install Cygwin](https://www.cygwin.com/install.html) (only Cygwin core + **gcc-core** + **gnu make**). Either way, you will need a copy of the `luac.cross` compiler: Windows users can compile a local copy of the `luac.cross` executable for use on a development PC. To this you need:
- To download the current NodeMCU sources (this [dev ZIP file](https://github.com/nodemcu/nodemcu-firmware/archive/dev.zip) or [master ZIP file](https://github.com/nodemcu/nodemcu-firmware/archive/master.zip)) and unpack into a local folder, say `C:\nodemcu-firmware`; choose the master / dev versions to match the firmware version that you want to use. If you want an Integer buld then edit the `app/includes/user_config.h` file to select this.
- You can either download this from Terry's fileserver. The [ELF variant](http://files.ellisons.org.uk/esp8266/luac.cross) is used for all recent Linux and WSL flavours, or the [cygwin binary](http://files.ellisons.org.uk/esp8266/luac.cross.cygwin)) for the Cygwin environment. - Choose a preferred toolchain to build your `luac.cross` executable. You have a number of options here:
- Or you can compile it yourself by downloading the current NodeMCU sources (this [ZIPfile](https://github.com/nodemcu/nodemcu-firmware/archive/master.zip)); edit the `app/includes/user_config.h` file and then `cd` to the `app/lua/luac_cross` and run make to build the compiler in the NodeMCU firmware root directory. Note that the `luac.cross` make only needs the host toolchain which is installed by default. - If you are a Windows 10 user with the Windows Subsystem for Linux (WSL) already installed, then this is a Linux environment so you can follow the [Linux build instructions](#Linux) below.
- A less resource intensive option which works on all Windows OS variants is to use Cygwin or MinGW, which are varaint ports of the [GNU Compiler Collection](https://gcc.gnu.org/) to Windows and which can both compile to native Windows executables. In the case of Cygwin, [install Cygwin](https://www.cygwin.com/install.html) (selecting the Cygwin core + **gcc-core** + **gnu make** in the install menu). In the case of MinGW you again only need a very basic C build environment so [install the MINGW](http://mingw.org/wiki/InstallationHOWTOforMinGW); you only need the core GCC and mingw32-make. Both both these create a **Cmd** prompt which paths in the relevant GCC toolchain. Switch to the `app/lua/luac_cross` and run make to build the compiler in the NodeMCU firmware root directory. You do this by rning `make` in Cygwin and `mingw32-make -f mingw32-Makefile.mak` in MinGW.
### macOS - If you can C development experience on the PC and a version of the MS Visual Studio on your PC then you can also simply build the image using the supplied MS project file.
- Once you have a built `luac.cross` executable, then you can use this to compile Lua code into an LFS image. You might wish to move this out of the nodemcu-firmware hierarchy, since this folder hierarchy is no longer required and can be trashed.
TBD
1. `$ cd app/lua/luac_cross`
2. `$ make`
### Linux ### Linux
TBD - Ensure that you have a "build essential" GCC toolchain installed.
- Download the current NodeMCU sources (this [dev ZIP file](https://github.com/nodemcu/nodemcu-firmware/archive/dev.zip) or [master ZIP file](https://github.com/nodemcu/nodemcu-firmware/archive/master.zip)) and unpack into a local folder; choose the master / dev versions to match the firmware version that you want to use. If you want an Integer buld then edit the `app/includes/user_config.h` file to select this.
- Change directory to the `app/lua/luac_cross` sub-folder
- Run `make` to build the executable.
- Once you have a built `luac.cross` executable, then you can use this to compile Lua code into an LFS image. You might wish to move this out of the nodemcu-firmware hierarchy, since this folder hierarchy is no longer required and can be trashed.
1. `$ cd app/lua/luac_cross` ### macOS
2. `$ make`
As for [Linux](#linux)
[↑ back to matrix](#task-os-selector) [↑ back to matrix](#task-os-selector)

View File

@ -183,7 +183,7 @@ Returns the function reference for a function in the [LFS (Lua Flash Store)](../
`modulename` The name of the module to be loaded. If this is `nil` or invalid then an info list is returned `modulename` The name of the module to be loaded. If this is `nil` or invalid then an info list is returned
#### Returns #### Returns
- In the case where the LFS in not loaded, `node.flashindex` evaluates to `nil`, followed by the flash and mapped base addresss of the LFS - In the case where the LFS in not loaded, `node.flashindex` evaluates to `nil`, followed by the flash mapped base addresss of the LFS, its flash offset, and the size of the LFS.
- If the LFS is loaded and the function is called with the name of a valid module in the LFS, then the function is returned in the same way the `load()` and the other Lua load functions do. - If the LFS is loaded and the function is called with the name of a valid module in the LFS, then the function is returned in the same way the `load()` and the other Lua load functions do.
- Otherwise an extended info list is returned: the Unix time of the LFS build, the flash and mapped base addresses of the LFS and its current length, and an array of the valid module names in the LFS. - Otherwise an extended info list is returned: the Unix time of the LFS build, the flash and mapped base addresses of the LFS and its current length, and an array of the valid module names in the LFS.

View File

@ -5,6 +5,7 @@ MEMORY
dport0_0_seg : org = 0x3FF00000, len = 0x10 dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000 dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000 iram1_0_seg : org = 0x40100000, len = 0x8000
iram0_0_seg : org = 0x4010E000, len = 0x2000
irom0_0_seg : org = 0x40210000, len = 0xE0000 irom0_0_seg : org = 0x40210000, len = 0xE0000
} }
@ -14,12 +15,13 @@ PHDRS
dram0_0_phdr PT_LOAD; dram0_0_phdr PT_LOAD;
dram0_0_bss_phdr PT_LOAD; dram0_0_bss_phdr PT_LOAD;
iram1_0_phdr PT_LOAD; iram1_0_phdr PT_LOAD;
iram0_0_phdr PT_LOAD;
irom0_0_phdr PT_LOAD; irom0_0_phdr PT_LOAD;
} }
/* Default entry point: */ /* Default entry point: */
ENTRY(user_start_trampoline) ENTRY(call_user_start)
EXTERN(_DebugExceptionVector) EXTERN(_DebugExceptionVector)
EXTERN(_DoubleExceptionVector) EXTERN(_DoubleExceptionVector)
EXTERN(_KernelExceptionVector) EXTERN(_KernelExceptionVector)
@ -221,11 +223,21 @@ SECTIONS
_lit4_end = ABSOLUTE(.); _lit4_end = ABSOLUTE(.);
} >iram1_0_seg :iram1_0_phdr } >iram1_0_seg :iram1_0_phdr
.pre_init_ram : ALIGN(0x1000)
{
_iram0_start = ABSOLUTE(.);
*(*.pre_init)
_iram0_end = ABSOLUTE(.);
} >iram0_0_seg :iram0_0_phdr
.irom0.text : ALIGN(0x1000) .irom0.text : ALIGN(0x1000)
{ {
_irom0_text_start = ABSOLUTE(.); _irom0_text_start = ABSOLUTE(.);
*(.irom0.ptable)
. = ALIGN(0x1000);
*(.servercert.flash) *(.servercert.flash)
*(.clientcert.flash) *(.clientcert.flash)
. = ALIGN(0x1000);
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
*(.literal .text .literal.* .text.*) *(.literal .text .literal.* .text.*)
*(.rodata*) *(.rodata*)

View File

@ -1,11 +0,0 @@
#ifndef _SDK_OVERRIDE_MEM_H_
#define _SDK_OVERRIDE_MEM_H_
void *pvPortMalloc (size_t sz, const char *, unsigned);
void vPortFree (void *p, const char *, unsigned);
void *pvPortZalloc (size_t sz, const char *, unsigned);
void *pvPortRealloc (void *p, size_t n, const char *, unsigned);
#include_next "mem.h"
#endif

File diff suppressed because it is too large Load Diff

286
tools/nodemcu-partition.py Executable file
View File

@ -0,0 +1,286 @@
#!/usr/bin/env python
#
# ESP8266 LFS Loader Utility
#
# Copyright (C) 2019 Terry Ellison, NodeMCU Firmware Community Project. drawing
# heavily from and including content from esptool.py with full acknowledgement
# under GPL 2.0, with said content: Copyright (C) 2014-2016 Fredrik Ahlberg, Angus
# Gratton, Espressif Systems (Shanghai) PTE LTD, other contributors as noted.
# https://github.com/espressif/esptool
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA 02110-1301 USA.
import os
import sys
sys.path.append(os.path.realpath(os.path.dirname(__file__) + '/toolchains/'))
import esptool
import io
import tempfile
import shutil
from pprint import pprint
import argparse
import gzip
import copy
import inspect
import struct
import string
__version__ = '1.0'
__program__ = 'nodemcu-partition.py'
ROM0_Seg = 0x010000
FLASH_PAGESIZE = 0x001000
FLASH_BASE_ADDR = 0x40200000
PARTITION_TYPES = {
4: 'RF_CAL',
5: 'PHY_DATA',
6: 'SYSTEM_PARAMETER',
101: 'EAGLEROM',
102: 'IROM0TEXT',
103: 'LFS0',
104: 'LFS1',
105: 'TLSCERT',
106: 'SPIFFS0',
107: 'SPIFFS1'}
MAX_PT_SIZE = 20*3
FLASH_SIG = 0xfafaa150
FLASH_SIG_MASK = 0xfffffff0
FLASH_SIG_ABSOLUTE = 0x00000001
WORDSIZE = 4
WORDBITS = 32
PACK_INT = struct.Struct("<I")
class FatalError(RuntimeError):
def __init__(self, message):
RuntimeError.__init__(self, message)
def WithResult(message, result):
message += " (result was %s)" % hexify(result)
return FatalError(message)
def load_PT(data, args):
"""
Load the Flash copy of the Partition Table from the first segment of the IROM0
segment, that is at 0x10000. If nececessary the LFS partition is then correctly
positioned and adjusted according to the optional start and len arguments.
The (possibly) updated PT is then returned with the LFS sizing.
"""
pt = [PACK_INT.unpack_from(data,4*i)[0] for i in range(0, MAX_PT_SIZE)]
n, flash_used_end, rewrite = 0, 0, False
LFSaddr, LFSsize = None, None
# The partition table format is a set of 3*uint32 fields (type, addr, size),
# with the last slot being an end marker (0,size,0) where size is the size of
# the firmware image.
pt_map = dict()
for i in range(0,MAX_PT_SIZE,3):
if pt[i] == 0:
n = i // 3
break
elif pt[i] in PARTITION_TYPES:
pt_map[PARTITION_TYPES[pt[i]]] = i
else:
raise FatalError("Unknown partition type: %u" % pt[i])
flash_used_end = pt[3*n+1]
if not ('IROM0TEXT' in pt_map and 'LFS0' in pt_map):
raise FatalError("Partition table must contain IROM0 and LFS segments")
i = pt_map['IROM0TEXT']
if pt[i+2] == 0:
pt[i+2] = (flash_used_end - FLASH_BASE_ADDR) - pt[i+1]
j = pt_map['LFS0']
if args.la is not None:
pt[j+1] = args.la
elif pt[j+1] == 0:
pt[j+1] = pt[i+1] + pt[i+2]
if args.ls is not None:
pt[j+2] = args.ls
elif pt[j+2] == 0:
pt[j+2] = 0x10000
k = pt_map['SPIFFS0']
if args.sa is not None:
pt[k+1] = args.sa
elif pt[k+1] == 0:
pt[k+1] = pt[j+1] + pt[j+2]
if args.ss is not None:
pt[k+2] = args.ss
LFSaddr, LFSsize = pt[j+1], pt[j+2]
print ('\nDump of Partition Table\n')
for i in range(0,3*n,3):
print ('%-18s 0x%06x 0x%06x' % (PARTITION_TYPES[pt[i]], pt[i+1], pt[i+2]))
return pt, pt_map, n
def relocate_lfs(data, addr, size):
"""
The unpacked LFS image comprises the relocatable image itself, followed by a bit
map (one bit per word) flagging if the corresponding word of the image needs
relocating. The image and bitmap are enumerated with any addresses being
relocated by the LFS base address. (Note that the PIC format of addresses is word
aligned and so first needs scaling by the wordsize.)
"""
addr += FLASH_BASE_ADDR
w = [PACK_INT.unpack_from(data,WORDSIZE*i)[0] \
for i in range(0, len(data) // WORDSIZE)]
flash_sig, flash_size = w[0], w[1]
assert ((flash_sig & FLASH_SIG_MASK) == FLASH_SIG and
(flash_sig & FLASH_SIG_ABSOLUTE) == 0 and
flash_size % WORDSIZE == 0)
flash_size //= WORDSIZE
flags_size = (flash_size + WORDBITS - 1) // WORDBITS
assert (WORDSIZE*flash_size <= size and
len(data) == WORDSIZE*(flash_size + flags_size))
image,flags,j = w[0:flash_size], w[flash_size:], 0
for i in range(0,len(image)):
if i % WORDBITS == 0:
flag_word = flags[j]
j += 1
if (flag_word & 1) == 1:
o = image[i]
image[i] = WORDSIZE*image[i] + addr
flag_word >>= 1
return ''.join([PACK_INT.pack(i) for i in image])
def main():
def arg_auto_int(x):
ux = x.upper()
if "MB" in ux:
return int(ux[:ux.index("MB")]) * 1024 * 1024
elif "KB" in ux:
return int(ux[:ux.index("KB")]) * 1024
else:
return int(ux, 0)
print('%s V%s' %(__program__, __version__))
# ---------- process the arguments ---------- #
a = argparse.ArgumentParser(
description='%s V%s - ESP8266 NodeMCU Loader Utility' %
(__program__, __version__),
prog='esplfs')
a.add_argument('--port', '-p', help='Serial port device')
a.add_argument('--baud', '-b', type=arg_auto_int,
help='Serial port baud rate used when flashing/reading')
a.add_argument('--lfs-addr', '-la', dest="la", type=arg_auto_int,
help='(Overwrite) start address of LFS partition')
a.add_argument('--lfs-size', '-ls', dest="ls", type=arg_auto_int,
help='(Overwrite) length of LFS partition')
a.add_argument('--lfs-file', '-lf', dest="lf", help='LFS image file')
a.add_argument('--spiffs-addr', '-sa', dest="sa", type=arg_auto_int,
help='(Overwrite) start address of SPIFFS partition')
a.add_argument('--spiffs-size', '-ss', dest="ss", type=arg_auto_int,
help='(Overwrite) length of SPIFFS partition')
a.add_argument('--spiffs-file', '-sf', dest="sf", help='SPIFFS image file')
arg = a.parse_args()
if arg.lf is not None:
if not os.path.exists(arg.lf):
raise FatalError("LFS image %s does not exist" % arg.lf)
if arg.sf is not None:
if not os.path.exists(arg.sf):
raise FatalError("SPIFFS image %s does not exist" % arg.sf)
base = [] if arg.port is None else ['--port',arg.port]
if arg.baud is not None: base.extend(['--baud',arg.baud])
# ---------- Use esptool to read the PT ---------- #
tmpdir = tempfile.mkdtemp()
pt_file = tmpdir + '/pt.dmp'
espargs = base+['--after', 'no_reset', 'read_flash', '--no-progress',
str(ROM0_Seg), str(FLASH_PAGESIZE), pt_file]
esptool.main(espargs)
with open(pt_file,"rb") as f:
data = f.read()
pt, pt_map, n = load_PT(data, arg)
n = n+1
odata = ''.join([PACK_INT.pack(pt[i]) for i in range(0,3*n)]) + \
"\xFF" * len(data[3*4*n:])
# ---------- If the PT has changed then use esptool to rewrite it ---------- #
if odata != data:
print("PT updated")
pt_file = tmpdir + '/opt.dmp'
with open(pt_file,"wb") as f:
f.write(odata)
espargs = base+['--after', 'no_reset', 'write_flash', '--no-progress',
str(ROM0_Seg), pt_file]
esptool.main(espargs)
if arg.lf is not None:
i = pt_map['LFS0']
la,ls = pt[i+1], pt[i+2]
# ---------- Read and relocate the LFS image ---------- #
with gzip.open(arg.lf) as f:
lfs = f.read()
lfs = relocate_lfs(lfs, la, ls)
# ---------- Write to a temp file and use esptool to write it to flash ---------- #
img_file = tmpdir + '/lfs.img'
espargs = base + ['write_flash', str(la), img_file]
with open(img_file,"wb") as f:
f.write(lfs)
esptool.main(espargs)
if arg.sf is not None:
sa = pt[pt_map['SPIFFS0']+1]
# ---------- Write to a temp file and use esptool to write it to flash ---------- #
spiffs_file = arg.sf
espargs = base + ['', str(sa), spiffs_file]
esptool.main(espargs)
# ---------- Clean up temp directory ---------- #
espargs = base + ['--after', 'hard_reset', 'flash_id']
esptool.main(espargs)
shutil.rmtree(tmpdir)
def _main():
main()
if __name__ == '__main__':
_main()