Add New Tasking I/F and rework GPIO, UART, etc to support it

As with the last commit this rolls up the follwowing, but include the various
review comments on the PR.

-   **Documentation changes**. I've added the taks FAQ as a stub new Extension
developer FAQ, and split the old FAQ into a Lua Developer FAQ and a Hardware
FAQ.

-   **Tasking I/F**.  New `app/task/Makefile`, `app/task/task.c`,
`app/include/task/task.h` and `app/Makefile` as per previous commit.  Cascade
changes to `app/driver/uart.c`, `app/include/driver/uart.h`,
`app/user/user_main.c` and `app/modules/node.c`

-   **GPIO Rework** to `app/modules/gpio.c` and `pin_map.[hc]`, `platform.[hc]`
in `app/platform`

-   **Other Optimisations** Move the `platform_*_exists()` from
`app/platform/common.c` to static inline declarations in `platform.h` as
this generates faster, smaller code. Move lgc.a routines out of iram0.
This commit is contained in:
TerryE 2016-02-17 17:13:17 +00:00
parent 19471f54ad
commit 49733f6f6d
20 changed files with 637 additions and 437 deletions

View File

@ -32,6 +32,7 @@ SUBDIRS= \
lwip \ lwip \
coap \ coap \
mqtt \ mqtt \
task \
u8glib \ u8glib \
ucglib \ ucglib \
smart \ smart \
@ -73,6 +74,7 @@ COMPONENTS_eagle.app.v6 = \
json/libjson.a \ json/libjson.a \
upgrade/libupgrade.a \ upgrade/libupgrade.a \
platform/libplatform.a \ platform/libplatform.a \
task/libtask.a \
libc/liblibc.a \ libc/liblibc.a \
lua/liblua.a \ lua/liblua.a \
lwip/liblwip.a \ lwip/liblwip.a \

View File

@ -12,6 +12,7 @@
#include "ets_sys.h" #include "ets_sys.h"
#include "osapi.h" #include "osapi.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "task/task.h"
#include "user_config.h" #include "user_config.h"
#include "user_interface.h" #include "user_interface.h"
@ -27,8 +28,7 @@
// For event signalling // For event signalling
static uint8 task = USER_TASK_PRIO_MAX; static task_handle_t sig = 0;
static os_signal_t sig;
// UartDev is defined and initialized in rom code. // UartDev is defined and initialized in rom code.
extern UartDevice UartDev; extern UartDevice UartDev;
@ -248,7 +248,7 @@ uart0_rx_intr_handler(void *para)
if (RcvChar == '\r' || RcvChar == '\n' ) { if (RcvChar == '\r' || RcvChar == '\n' ) {
pRxBuff->BuffState = WRITE_OVER; pRxBuff->BuffState = WRITE_OVER;
} }
if (pRxBuff->pWritePos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) { if (pRxBuff->pWritePos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) {
// overflow ...we may need more error handle here. // overflow ...we may need more error handle here.
pRxBuff->pWritePos = pRxBuff->pRcvMsgBuff ; pRxBuff->pWritePos = pRxBuff->pRcvMsgBuff ;
@ -258,7 +258,7 @@ uart0_rx_intr_handler(void *para)
if (pRxBuff->pWritePos == pRxBuff->pReadPos){ // overflow one byte, need push pReadPos one byte ahead if (pRxBuff->pWritePos == pRxBuff->pReadPos){ // overflow one byte, need push pReadPos one byte ahead
if (pRxBuff->pReadPos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) { if (pRxBuff->pReadPos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) {
pRxBuff->pReadPos = pRxBuff->pRcvMsgBuff ; pRxBuff->pReadPos = pRxBuff->pRcvMsgBuff ;
} else { } else {
pRxBuff->pReadPos++; pRxBuff->pReadPos++;
} }
@ -267,8 +267,8 @@ uart0_rx_intr_handler(void *para)
got_input = true; got_input = true;
} }
if (got_input && task != USER_TASK_PRIO_MAX) if (got_input && sig)
system_os_post (task, sig, UART0); task_post_low (sig, false);
} }
/****************************************************************************** /******************************************************************************
@ -281,9 +281,8 @@ uart0_rx_intr_handler(void *para)
* Returns : NONE * Returns : NONE
*******************************************************************************/ *******************************************************************************/
void ICACHE_FLASH_ATTR void ICACHE_FLASH_ATTR
uart_init(UartBautRate uart0_br, UartBautRate uart1_br, uint8 task_prio, os_signal_t sig_input) uart_init(UartBautRate uart0_br, UartBautRate uart1_br, os_signal_t sig_input)
{ {
task = task_prio;
sig = sig_input; sig = sig_input;
// rom use 74880 baut_rate, here reinitialize // rom use 74880 baut_rate, here reinitialize

View File

@ -101,7 +101,7 @@ typedef struct {
int buff_uart_no; //indicate which uart use tx/rx buffer int buff_uart_no; //indicate which uart use tx/rx buffer
} UartDevice; } UartDevice;
void uart_init(UartBautRate uart0_br, UartBautRate uart1_br, uint8 task_prio, os_signal_t sig_input); void uart_init(UartBautRate uart0_br, UartBautRate uart1_br, os_signal_t sig_input);
void uart0_alt(uint8 on); void uart0_alt(uint8 on);
void uart0_sendStr(const char *str); void uart0_sendStr(const char *str);
void uart0_putc(const char c); void uart0_putc(const char c);

34
app/include/task/task.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef _TASK_H_
#define _TASK_H_
#include "ets_sys.h"
#include "osapi.h"
#include "os_type.h"
/* use LOW / MEDIUM / HIGH since it isn't clear from the docs which is higher */
#define TASK_PRIORITY_LOW 0
#define TASK_PRIORITY_MEDIUM 1
#define TASK_PRIORITY_HIGH 2
#define TASK_PRIORITY_COUNT 3
/*
* Signals are a 32-bit number of the form header:14; count:16, priority:2. The header
* is just a fixed fingerprint and the count is allocated serially by the task get_id()
* function.
*/
#define task_post_low(handle,param) system_os_post(0, (handle | TASK_PRIORITY_LOW), param)
#define task_post_medium(handle,param) system_os_post(1, (handle | TASK_PRIORITY_MEDIUM), param)
#define task_post_high(handle,param) system_os_post(2, (handle | TASK_PRIORITY_HIGH), param)
#define task_handle_t os_signal_t
#define task_param_t os_param_t
typedef void (*task_callback_t)(task_param_t param, uint8 prio);
bool task_init_handler(uint8 priority, uint8 qlen);
task_handle_t task_get_id(task_callback_t t);
#endif

View File

@ -41,12 +41,19 @@
#define NODE_ERR #define NODE_ERR
#endif /* NODE_ERROR */ #endif /* NODE_ERROR */
#define GPIO_INTERRUPT_ENABLE
// #define GPIO_SAFE_NO_INTR_ENABLE
#define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed)) #define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed))
#define ICACHE_STORE_ATTR __attribute__((aligned(4))) #define ICACHE_STORE_ATTR __attribute__((aligned(4)))
#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text"))) #define ICACHE_RAM_ATTR __attribute__((section(".iram0.text")))
#ifdef GPIO_SAFE_NO_INTR_ENABLE
#define NO_INTR_CODE ICACHE_RAM_ATTR __attribute__ ((noinline))
#else
#define NO_INTR_CODE inline
#endif
#define CLIENT_SSL_ENABLE #define CLIENT_SSL_ENABLE
#define GPIO_INTERRUPT_ENABLE
//#define MD2_ENABLE //#define MD2_ENABLE
#define SHA2_ENABLE #define SHA2_ENABLE

View File

@ -2,9 +2,9 @@
#include "module.h" #include "module.h"
#include "lauxlib.h" #include "lauxlib.h"
#include "lmem.h"
#include "platform.h" #include "platform.h"
#include "rom.h" #include "user_interface.h"
#include "c_types.h" #include "c_types.h"
#include "c_string.h" #include "c_string.h"
@ -16,139 +16,115 @@
#define HIGH PLATFORM_GPIO_HIGH #define HIGH PLATFORM_GPIO_HIGH
#define LOW PLATFORM_GPIO_LOW #define LOW PLATFORM_GPIO_LOW
#ifdef GPIO_INTERRUPT_ENABLE #ifdef GPIO_INTERRUPT_ENABLE
static int gpio_cb_ref[GPIO_PIN_NUM]; static int gpio_cb_ref[GPIO_PIN_NUM];
static lua_State* gL = NULL;
void lua_gpio_unref(unsigned pin){ // This task is scheduled by the ISP if pin_trigger[pin] is true and is used
if(gpio_cb_ref[pin] != LUA_NOREF){ // to intitied the Lua-land gpio.trig() callback function
if(gL!=NULL) static void gpio_intr_callback_task (task_param_t param, uint8 priority)
luaL_unref(gL, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
}
gpio_cb_ref[pin] = LUA_NOREF;
}
void gpio_intr_callback( unsigned pin, unsigned level )
{ {
unsigned pin = param >> 1;
unsigned level = param & 1;
UNUSED(priority);
NODE_DBG("pin:%d, level:%d \n", pin, level); NODE_DBG("pin:%d, level:%d \n", pin, level);
if(gpio_cb_ref[pin] == LUA_NOREF) if(gpio_cb_ref[pin] != LUA_NOREF) {
return; // GPIO callbacks are run in L0 and inlcude the level as a parameter
if(!gL) lua_State *L = lua_getstate();
return; NODE_DBG("Calling: %08x\n", gpio_cb_ref[pin]);
lua_rawgeti(gL, LUA_REGISTRYINDEX, gpio_cb_ref[pin]); // The trigger is reset before the callback, as the callback itself might reset the trigger
lua_pushinteger(gL, level); pin_trigger[pin] = true;
lua_call(gL, 1, 0); lua_rawgeti(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
lua_pushinteger(L, level);
lua_call(L, 1, 0);
}
} }
// Lua: trig( pin, type, function ) // Lua: trig( pin, type, function )
static int lgpio_trig( lua_State* L ) static int lgpio_trig( lua_State* L )
{ {
unsigned type; unsigned pin = luaL_checkinteger( L, 1 );
unsigned pin; static const char * const opts[] = {"", "up", "down", "both", "low", "high"};
size_t sl; static const int opts_type[] = {
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_POSEDGE, GPIO_PIN_INTR_NEGEDGE,
pin = luaL_checkinteger( L, 1 ); GPIO_PIN_INTR_ANYEDGE, GPIO_PIN_INTR_LOLEVEL, GPIO_PIN_INTR_HILEVEL
MOD_CHECK_ID( gpio, pin ); };
if(pin==0) int type = opts_type[luaL_checkoption(L, 2, "", opts)];
return luaL_error( L, "no interrupt for D0" );
const char *str = luaL_checklstring( L, 2, &sl ); luaL_argcheck(L, platform_gpio_exists(pin) && pin>0, 1, "Invalid interrupt pin");
if (str == NULL)
return luaL_error( L, "wrong arg type" );
if(sl == 2 && c_strcmp(str, "up") == 0){ if (type != GPIO_PIN_INTR_DISABLE) {
type = GPIO_PIN_INTR_POSEDGE; int cbtype = lua_type(L, 3);
}else if(sl == 4 && c_strcmp(str, "down") == 0){ luaL_argcheck(L, cbtype == LUA_TFUNCTION || cbtype == LUA_TLIGHTFUNCTION, 3,
type = GPIO_PIN_INTR_NEGEDGE; "invalid callback type");
}else if(sl == 4 && c_strcmp(str, "both") == 0){
type = GPIO_PIN_INTR_ANYEDGE;
}else if(sl == 3 && c_strcmp(str, "low") == 0){
type = GPIO_PIN_INTR_LOLEVEL;
}else if(sl == 4 && c_strcmp(str, "high") == 0){
type = GPIO_PIN_INTR_HILEVEL;
}else{
type = GPIO_PIN_INTR_DISABLE;
}
// luaL_checkanyfunction(L, 3);
if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION){
lua_pushvalue(L, 3); // copy argument (func) to the top of stack lua_pushvalue(L, 3); // copy argument (func) to the top of stack
if(gpio_cb_ref[pin] != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
gpio_cb_ref[pin] = luaL_ref(L, LUA_REGISTRYINDEX); gpio_cb_ref[pin] = luaL_ref(L, LUA_REGISTRYINDEX);
} }
NODE_DBG("Pin data: %d %d %08x, %d %d %d %d, %08x\n",
pin, type, pin_mux[pin], pin_num[pin], pin_func[pin], pin_int_type[pin], pin_trigger[pin], gpio_cb_ref[pin]);
platform_gpio_intr_init(pin, type); platform_gpio_intr_init(pin, type);
return 0; return 0;
} }
#endif #endif
// Lua: mode( pin, mode, pullup ) // Lua: mode( pin, mode, pullup )
static int lgpio_mode( lua_State* L ) static int lgpio_mode( lua_State* L )
{ {
unsigned mode, pullup = FLOAT; unsigned pin = luaL_checkinteger( L, 1 );
unsigned pin; unsigned mode = luaL_checkinteger( L, 2 );
unsigned pullup = luaL_optinteger( L, 3, FLOAT );
luaL_argcheck(L, platform_gpio_exists(pin) && (mode!=INTERRUPT || pin>0), 1, "Invalid pin");
luaL_argcheck(L, mode==OUTPUT || mode==INPUT
#ifdef GPIO_INTERRUPT_ENABLE
|| mode==INTERRUPT
#endif
, 2, "wrong arg type" );
if(pullup!=FLOAT) pullup = PULLUP;
NODE_DBG("pin,mode,pullup= %d %d %d\n",pin,mode,pullup);
NODE_DBG("Pin data at mode: %d %08x, %d %d %d %d, %08x\n",
pin, pin_mux[pin], pin_num[pin], pin_func[pin], pin_int_type[pin], pin_trigger[pin], gpio_cb_ref[pin]);
pin = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( gpio, pin );
mode = luaL_checkinteger( L, 2 );
if ( mode!=OUTPUT && mode!=INPUT && mode!=INTERRUPT)
return luaL_error( L, "wrong arg type" );
if(pin==0 && mode==INTERRUPT)
return luaL_error( L, "no interrupt for D0" );
if(lua_isnumber(L, 3))
pullup = lua_tointeger( L, 3 );
if(pullup!=FLOAT)
pullup = PULLUP;
#ifdef GPIO_INTERRUPT_ENABLE #ifdef GPIO_INTERRUPT_ENABLE
gL = L; // save to local gL, for callback function if (mode != INTERRUPT){ // disable interrupt
if (mode!=INTERRUPT){ // disable interrupt
if(gpio_cb_ref[pin] != LUA_NOREF){ if(gpio_cb_ref[pin] != LUA_NOREF){
luaL_unref(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]); luaL_unref(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
gpio_cb_ref[pin] = LUA_NOREF;
} }
gpio_cb_ref[pin] = LUA_NOREF;
} }
#endif #endif
int r = platform_gpio_mode( pin, mode, pullup );
if( r<0 ) if( platform_gpio_mode( pin, mode, pullup ) < 0 )
return luaL_error( L, "wrong pin num." ); return luaL_error( L, "wrong pin num." );
return 0;
return 0;
} }
// Lua: read( pin ) // Lua: read( pin )
static int lgpio_read( lua_State* L ) static int lgpio_read( lua_State* L )
{ {
unsigned pin; unsigned pin = luaL_checkinteger( L, 1 );
pin = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( gpio, pin ); MOD_CHECK_ID( gpio, pin );
lua_pushinteger( L, platform_gpio_read( pin ) );
unsigned level = platform_gpio_read( pin ); return 1;
lua_pushinteger( L, level );
return 1;
} }
// Lua: write( pin, level ) // Lua: write( pin, level )
static int lgpio_write( lua_State* L ) static int lgpio_write( lua_State* L )
{ {
unsigned level; unsigned pin = luaL_checkinteger( L, 1 );
unsigned pin; unsigned level = luaL_checkinteger( L, 2 );
pin = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( gpio, pin ); MOD_CHECK_ID( gpio, pin );
level = luaL_checkinteger( L, 2 ); luaL_argcheck(L, level==HIGH || level==LOW, 2, "wrong level type" );
if ( level!=HIGH && level!=LOW )
return luaL_error( L, "wrong arg type" );
platform_gpio_write(pin, level); platform_gpio_write(pin, level);
return 0; return 0;
} }
#define DELAY_TABLE_MAX_LEN 256 #define DELAY_TABLE_MAX_LEN 256
#define noInterrupts ets_intr_lock
#define interrupts ets_intr_unlock
#define delayMicroseconds os_delay_us #define delayMicroseconds os_delay_us
#define DIRECT_WRITE(pin, level) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), level))
// Lua: serout( pin, firstLevel, delay_table, [repeatNum] ) // Lua: serout( pin, firstLevel, delay_table, [repeatNum] )
// -- serout( pin, firstLevel, delay_table, [repeatNum] ) // -- serout( pin, firstLevel, delay_table, [repeatNum] )
// gpio.mode(1,gpio.OUTPUT,gpio.PULLUP) // gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
@ -161,62 +137,41 @@ static int lgpio_write( lua_State* L )
// gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles // gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles
static int lgpio_serout( lua_State* L ) static int lgpio_serout( lua_State* L )
{ {
unsigned level; unsigned clocks_per_us = system_get_cpu_freq();
unsigned pin; unsigned pin = luaL_checkinteger( L, 1 );
unsigned table_len = 0; unsigned level = luaL_checkinteger( L, 2 );
unsigned repeat = 0; unsigned repeats = luaL_optint( L, 4, 1 );
int delay_table[DELAY_TABLE_MAX_LEN]; unsigned table_len, i, j;
pin = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( gpio, pin );
level = luaL_checkinteger( L, 2 );
if ( level!=HIGH && level!=LOW )
return luaL_error( L, "wrong arg type" );
if( lua_istable( L, 3 ) )
{
table_len = lua_objlen( L, 3 );
if (table_len <= 0 || table_len>DELAY_TABLE_MAX_LEN)
return luaL_error( L, "wrong arg range" );
int i;
for( i = 0; i < table_len; i ++ )
{
lua_rawgeti( L, 3, i + 1 );
delay_table[i] = ( int )luaL_checkinteger( L, -1 );
lua_pop( L, 1 );
if( delay_table[i] < 0 || delay_table[i] > 1000000 ) // can not delay more than 1000000 us
return luaL_error( L, "delay must < 1000000 us" );
}
} else {
return luaL_error( L, "wrong arg range" );
}
if(lua_isnumber(L, 4)) luaL_argcheck(L, platform_gpio_exists(pin), 1, "Invalid pin");
repeat = lua_tointeger( L, 4 ); luaL_argcheck(L, level==HIGH || level==LOW, 2, "Wrong arg type" );
if( repeat < 0 || repeat > DELAY_TABLE_MAX_LEN ) luaL_argcheck(L, lua_istable( L, 3 ) &&
return luaL_error( L, "delay must < 256" ); ((table_len = lua_objlen( L, 3 )<DELAY_TABLE_MAX_LEN)), 3, "Invalid table" );
luaL_argcheck(L, repeats<256, 4, "repeats >= 256" );
if(repeat==0) uint32 *delay_table = luaM_newvector(L, table_len*repeats, uint32);
repeat = 1; for( i = 1; i <= table_len; i++ ) {
int j; lua_rawgeti( L, 3, i + 1 );
bool skip_loop = true; unsigned delay = (unsigned) luaL_checkinteger( L, -1 );
do if (delay > 1000000) return luaL_error( L, "delay %u must be < 1,000,000 us", i );
{ delay_table[i-1] = delay;
if(skip_loop){ // skip the first loop. lua_pop( L, 1 );
skip_loop = false; }
for( i = 0; i <= repeats; i++ ) {
if (!i) // skip the first loop (presumably this is some form of icache priming??).
continue; continue;
}
for(j=0;j<table_len;j++){
noInterrupts();
// platform_gpio_write(pin, level);
DIRECT_WRITE(pin, level);
interrupts();
delayMicroseconds(delay_table[j]);
level=!level;
}
repeat--;
} while (repeat>0);
return 0; for( j = 0;j < table_len; j++ ){
/* Direct Write is a ROM function which already disables interrupts for the atomic bit */
GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), level);
delayMicroseconds(delay_table[j]);
level = level==LOW ? HIGH : LOW;
}
}
luaM_freearray(L, delay_table, table_len, uint32);
return 0;
} }
#undef DELAY_TABLE_MAX_LEN #undef DELAY_TABLE_MAX_LEN
@ -245,7 +200,7 @@ int luaopen_gpio( lua_State *L ) {
for(i=0;i<GPIO_PIN_NUM;i++){ for(i=0;i<GPIO_PIN_NUM;i++){
gpio_cb_ref[i] = LUA_NOREF; gpio_cb_ref[i] = LUA_NOREF;
} }
platform_gpio_init(gpio_intr_callback); platform_gpio_init(task_get_id(gpio_intr_callback_task));
#endif #endif
return 0; return 0;
} }

View File

@ -145,8 +145,6 @@ static int node_heap( lua_State* L )
return 1; return 1;
} }
static lua_State *gL = NULL;
#ifdef DEVKIT_VERSION_0_9 #ifdef DEVKIT_VERSION_0_9
static int led_high_count = LED_HIGH_COUNT_DEFAULT; static int led_high_count = LED_HIGH_COUNT_DEFAULT;
static int led_low_count = LED_LOW_COUNT_DEFAULT; static int led_low_count = LED_LOW_COUNT_DEFAULT;
@ -174,27 +172,25 @@ static void default_short_press(void *arg) {
} }
static void key_long_press(void *arg) { static void key_long_press(void *arg) {
lua_State *L = lua_getstate();
NODE_DBG("key_long_press is called.\n"); NODE_DBG("key_long_press is called.\n");
if (long_key_ref == LUA_NOREF) { if (long_key_ref == LUA_NOREF) {
default_long_press(arg); default_long_press(arg);
return; return;
} }
if (!gL) lua_rawgeti(L, LUA_REGISTRYINDEX, long_key_ref);
return; lua_call(L, 0, 0);
lua_rawgeti(gL, LUA_REGISTRYINDEX, long_key_ref);
lua_call(gL, 0, 0);
} }
static void key_short_press(void *arg) { static void key_short_press(void *arg) {
lua_State *L = lua_getstate();
NODE_DBG("key_short_press is called.\n"); NODE_DBG("key_short_press is called.\n");
if (short_key_ref == LUA_NOREF) { if (short_key_ref == LUA_NOREF) {
default_short_press(arg); default_short_press(arg);
return; return;
} }
if (!gL) lua_rawgeti(L, LUA_REGISTRYINDEX, short_key_ref);
return; lua_call(L, 0, 0);
lua_rawgeti(gL, LUA_REGISTRYINDEX, short_key_ref);
lua_call(gL, 0, 0);
} }
static void update_key_led (void *p) static void update_key_led (void *p)
@ -286,7 +282,6 @@ static int node_key( lua_State* L )
} else { } else {
ref = &short_key_ref; ref = &short_key_ref;
} }
gL = L;
// luaL_checkanyfunction(L, 2); // luaL_checkanyfunction(L, 2);
if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION) { if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION) {
lua_pushvalue(L, 2); // copy argument (func) to the top of stack lua_pushvalue(L, 2); // copy argument (func) to the top of stack
@ -305,6 +300,7 @@ static int node_key( lua_State* L )
#endif #endif
extern lua_Load gLoad; extern lua_Load gLoad;
extern bool user_process_input(bool force);
// Lua: input("string") // Lua: input("string")
static int node_input( lua_State* L ) static int node_input( lua_State* L )
{ {
@ -321,7 +317,7 @@ static int node_input( lua_State* L )
NODE_DBG("Get command:\n"); NODE_DBG("Get command:\n");
NODE_DBG(load->line); // buggy here NODE_DBG(load->line); // buggy here
NODE_DBG("\nResult(if any):\n"); NODE_DBG("\nResult(if any):\n");
system_os_post (LUA_TASK_PRIO, LUA_PROCESS_LINE_SIG, 0); user_process_input(true);
} }
} }
return 0; return 0;
@ -330,12 +326,13 @@ static int node_input( lua_State* L )
static int output_redir_ref = LUA_NOREF; static int output_redir_ref = LUA_NOREF;
static int serial_debug = 1; static int serial_debug = 1;
void output_redirect(const char *str) { void output_redirect(const char *str) {
lua_State *L = lua_getstate();
// if(c_strlen(str)>=TX_BUFF_SIZE){ // if(c_strlen(str)>=TX_BUFF_SIZE){
// NODE_ERR("output too long.\n"); // NODE_ERR("output too long.\n");
// return; // return;
// } // }
if (output_redir_ref == LUA_NOREF || !gL) { if (output_redir_ref == LUA_NOREF || !L) {
uart0_sendStr(str); uart0_sendStr(str);
return; return;
} }
@ -344,15 +341,14 @@ void output_redirect(const char *str) {
uart0_sendStr(str); uart0_sendStr(str);
} }
lua_rawgeti(gL, LUA_REGISTRYINDEX, output_redir_ref); lua_rawgeti(L, LUA_REGISTRYINDEX, output_redir_ref);
lua_pushstring(gL, str); lua_pushstring(L, str);
lua_call(gL, 1, 0); // this call back function should never user output. lua_call(L, 1, 0); // this call back function should never user output.
} }
// Lua: output(function(c), debug) // Lua: output(function(c), debug)
static int node_output( lua_State* L ) static int node_output( lua_State* L )
{ {
gL = L;
// luaL_checkanyfunction(L, 1); // luaL_checkanyfunction(L, 1);
if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION) { if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION) {
lua_pushvalue(L, 1); // copy argument (func) to the top of stack lua_pushvalue(L, 1); // copy argument (func) to the top of stack

View File

@ -10,89 +10,13 @@ void cmn_platform_init(void)
} }
// ****************************************************************************
// GPIO functions
int platform_gpio_exists( unsigned pin )
{
return pin < NUM_GPIO;
}
// ****************************************************************************
// CAN functions
int platform_can_exists( unsigned id )
{
return id < NUM_CAN;
}
// ****************************************************************************
// SPI functions
int platform_spi_exists( unsigned id )
{
return id < NUM_SPI;
}
// ****************************************************************************
// PWM functions
int platform_pwm_exists( unsigned id )
{
return ((id < NUM_PWM) && (id > 0));
}
// ****************************************************************************
// ADC functions
int platform_adc_exists( unsigned id )
{
return id < NUM_ADC;
}
// ****************************************************************************
// UART functions
int platform_uart_exists( unsigned id )
{
return id < NUM_UART;
}
// ****************************************************************************
// OneWire functions
int platform_ow_exists( unsigned id )
{
return ((id < NUM_OW) && (id > 0));
}
// ****************************************************************************
// Timer functions
int platform_tmr_exists( unsigned id )
{
return id < NUM_TMR;
}
// ****************************************************************************
// I2C support
int platform_i2c_exists( unsigned id )
{
#ifndef NUM_I2C
return 0;
#else
return id < NUM_I2C;
#endif
}
// **************************************************************************** // ****************************************************************************
// Internal flash support functions // Internal flash support functions
// This symbol must be exported by the linker command file and must reflect the // This symbol must be exported by the linker command file and must reflect the
// TOTAL size of flash used by the eLua image (not only the code and constants, // TOTAL size of flash used by the eLua image (not only the code and constants,
// but also .data and whatever else ends up in the eLua image). FS will start // but also .data and whatever else ends up in the eLua image). FS will start
// at the next usable (aligned to a flash sector boundary) address after // at the next usable (aligned to a flash sector boundary) address after
// flash_used_size. // flash_used_size.
// extern char flash_used_size[]; // extern char flash_used_size[];
@ -151,12 +75,12 @@ uint32_t platform_flash_get_first_free_block_address( uint32_t *psect )
if(_flash_used_end>0){ // find the used sector if(_flash_used_end>0){ // find the used sector
sect = flashh_find_sector( platform_flash_mapped2phys ( (uint32_t)_flash_used_end - 1), NULL, &end ); sect = flashh_find_sector( platform_flash_mapped2phys ( (uint32_t)_flash_used_end - 1), NULL, &end );
if( psect ) if( psect )
*psect = sect + 1; *psect = sect + 1;
return end + 1; return end + 1;
}else{ }else{
sect = flashh_find_sector( 0, &start, NULL ); // find the first free sector sect = flashh_find_sector( 0, &start, NULL ); // find the first free sector
if( psect ) if( psect )
*psect = sect; *psect = sect;
return start; return start;
} }
} }
@ -231,7 +155,7 @@ uint32_t platform_flash_read( void *to, uint32_t fromaddr, uint32_t size )
platform_s_flash_read( tmpdata, temp, blksize ); platform_s_flash_read( tmpdata, temp, blksize );
for( i = rest; size && ( i < blksize ); i ++, size --, pto ++ ) for( i = rest; size && ( i < blksize ); i ++, size --, pto ++ )
*pto = tmpdata[ i ]; *pto = tmpdata[ i ];
if( size == 0 ) if( size == 0 )
return ssize; return ssize;
fromaddr = temp + blksize; fromaddr = temp + blksize;

View File

@ -1,45 +1,59 @@
#include "pin_map.h" #include "pin_map.h"
#include "eagle_soc.h" #include "eagle_soc.h"
#if 0 #include "mem.h"
uint32_t pin_mux[GPIO_PIN_NUM] = {PERIPHS_IO_MUX_MTDI_U, PERIPHS_IO_MUX_MTCK_U, PERIPHS_IO_MUX_MTMS_U, PERIPHS_IO_MUX_MTDO_U, #include "osapi.h"
PERIPHS_IO_MUX_U0RXD_U, PERIPHS_IO_MUX_U0TXD_U, PERIPHS_IO_MUX_SD_DATA2_U, PERIPHS_IO_MUX_SD_DATA3_U,
PERIPHS_IO_MUX_GPIO0_U, PERIPHS_IO_MUX_GPIO2_U, PERIPHS_IO_MUX_GPIO4_U, PERIPHS_IO_MUX_GPIO5_U};
uint8_t pin_num[GPIO_PIN_NUM] = {12, 13, 14, 15,
3, 1, 9, 10,
0, 2, 4, 5};
uint8_t pin_func[GPIO_PIN_NUM] = {FUNC_GPIO12, FUNC_GPIO13, FUNC_GPIO14, FUNC_GPIO15,
FUNC_GPIO3, FUNC_GPIO1, FUNC_GPIO9, FUNC_GPIO10,
FUNC_GPIO0, FUNC_GPIO2, FUNC_GPIO4, FUNC_GPIO5};
uint32_t pin_mux[GPIO_PIN_NUM];
uint8_t pin_num[GPIO_PIN_NUM];
uint8_t pin_func[GPIO_PIN_NUM];
#ifdef GPIO_INTERRUPT_ENABLE #ifdef GPIO_INTERRUPT_ENABLE
GPIO_INT_TYPE pin_int_type[GPIO_PIN_NUM] = { uint8_t pin_num_inv[GPIO_PIN_NUM_INV];
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, uint8_t pin_int_type[GPIO_PIN_NUM];
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, uint8_t pin_trigger[GPIO_PIN_NUM];
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE};
#endif #endif
#else
uint32_t pin_mux[GPIO_PIN_NUM] = {PAD_XPD_DCDC_CONF, PERIPHS_IO_MUX_GPIO5_U, PERIPHS_IO_MUX_GPIO4_U, PERIPHS_IO_MUX_GPIO0_U,
PERIPHS_IO_MUX_GPIO2_U, PERIPHS_IO_MUX_MTMS_U, PERIPHS_IO_MUX_MTDI_U, PERIPHS_IO_MUX_MTCK_U,
PERIPHS_IO_MUX_MTDO_U, PERIPHS_IO_MUX_U0RXD_U, PERIPHS_IO_MUX_U0TXD_U, PERIPHS_IO_MUX_SD_DATA2_U,
PERIPHS_IO_MUX_SD_DATA3_U };
uint8_t pin_num[GPIO_PIN_NUM] = {16, 5, 4, 0, typedef struct {
2, 14, 12, 13, int8 mux;
15, 3, 1, 9, uint8 num;
10}; uint8 func;
uint8 intr_type;
uint8_t pin_func[GPIO_PIN_NUM] = {0, FUNC_GPIO5, FUNC_GPIO4, FUNC_GPIO0, } pin_rec;
FUNC_GPIO2, FUNC_GPIO14, FUNC_GPIO12, FUNC_GPIO13, #define DECLARE_PIN(n,p) { (PERIPHS_IO_MUX_##p##_U - PERIPHS_IO_MUX), n, FUNC_GPIO##n, GPIO_PIN_INTR_DISABLE}
FUNC_GPIO15, FUNC_GPIO3, FUNC_GPIO1, FUNC_GPIO9, static const pin_rec pin_map[] = {
FUNC_GPIO10}; {PAD_XPD_DCDC_CONF - PERIPHS_IO_MUX, 16, 0, GPIO_PIN_INTR_DISABLE},
DECLARE_PIN( 5, GPIO5),
DECLARE_PIN( 4, GPIO4),
DECLARE_PIN( 0, GPIO0),
DECLARE_PIN( 2, GPIO2),
DECLARE_PIN(14, MTMS),
DECLARE_PIN(12, MTDI),
DECLARE_PIN(13, MTCK),
DECLARE_PIN(15, MTDO),
DECLARE_PIN( 3, U0RXD),
DECLARE_PIN( 1, U0TXD),
DECLARE_PIN( 9, SD_DATA2),
DECLARE_PIN(10, SD_DATA3)
};
void get_pin_map(void) {
/*
* Flash copy of the pin map. This has to be copied to RAM to be accessible from the ISR.
* Note that the mux field is a signed offset from PERIPHS_IO_MUX to allow the whole struct
* to be stored in a single 32-bit record.
*/
int i;
/* Take temporary stack copy to avoid unaligned exceptions on Flash version */
pin_rec pin[GPIO_PIN_NUM];
os_memcpy(pin, pin_map, sizeof(pin_map) );
for (i=0; i<GPIO_PIN_NUM; i++) {
pin_mux[i] = pin[i].mux + PERIPHS_IO_MUX;
pin_func[i] = pin[i].func;
pin_num[i] = pin[i].num;
#ifdef GPIO_INTERRUPT_ENABLE #ifdef GPIO_INTERRUPT_ENABLE
GPIO_INT_TYPE pin_int_type[GPIO_PIN_NUM] = { pin_num_inv[pin_num[i]] = i;
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, pin_int_type[i] = pin[i].intr_type;
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, pin_trigger[i] = false;
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,
GPIO_PIN_INTR_DISABLE};
#endif
#endif #endif
}
}

View File

@ -7,11 +7,17 @@
#include "gpio.h" #include "gpio.h"
#define GPIO_PIN_NUM 13 #define GPIO_PIN_NUM 13
#define GPIO_PIN_NUM_INV 17
extern uint8_t pin_num[GPIO_PIN_NUM];
extern uint8_t pin_func[GPIO_PIN_NUM];
extern uint32_t pin_mux[GPIO_PIN_NUM]; extern uint32_t pin_mux[GPIO_PIN_NUM];
extern uint8_t pin_num[GPIO_PIN_NUM];
extern uint8_t pin_func[GPIO_PIN_NUM];
#ifdef GPIO_INTERRUPT_ENABLE #ifdef GPIO_INTERRUPT_ENABLE
extern GPIO_INT_TYPE pin_int_type[GPIO_PIN_NUM]; extern uint8_t pin_num_inv[GPIO_PIN_NUM_INV];
extern uint8_t pin_int_type[GPIO_PIN_NUM];
extern uint8_t pin_trigger[GPIO_PIN_NUM];
#endif #endif
void get_pin_map(void);
#endif // #ifndef __PIN_MAP_H__ #endif // #ifndef __PIN_MAP_H__

View File

@ -1,17 +1,17 @@
// Platform-dependent functions // Platform-dependent functions and includes
#include "platform.h" #include "platform.h"
#include "common.h" #include "common.h"
#include "c_stdio.h" #include "c_stdio.h"
#include "c_string.h" #include "c_string.h"
#include "c_stdlib.h" #include "c_stdlib.h"
#include "llimits.h"
#include "gpio.h" #include "gpio.h"
#include "user_interface.h" #include "user_interface.h"
#include "driver/uart.h"
#include "driver/gpio16.h" #include "driver/gpio16.h"
#include "driver/i2c_master.h" #include "driver/i2c_master.h"
#include "driver/spi.h" #include "driver/spi.h"
// Platform specific includes #include "driver/uart.h"
static void pwms_init(); static void pwms_init();
@ -39,72 +39,90 @@ uint8_t platform_key_led( uint8_t level){
// **************************************************************************** // ****************************************************************************
// GPIO functions // GPIO functions
/*
* Set GPIO mode to output. Optionally in RAM helper because interrupts are dsabled
*/
static void NO_INTR_CODE set_gpio_no_interrupt(uint8 pin) {
unsigned pnum = pin_num[pin];
ETS_GPIO_INTR_DISABLE();
#ifdef GPIO_INTERRUPT_ENABLE #ifdef GPIO_INTERRUPT_ENABLE
extern void lua_gpio_unref(unsigned pin); pin_trigger[pin] = false;
pin_int_type[pin] = GPIO_PIN_INTR_DISABLE;
#endif #endif
PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]);
//disable interrupt
gpio_pin_intr_state_set(GPIO_ID_PIN(pnum), GPIO_PIN_INTR_DISABLE);
//clear interrupt status
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pnum));
GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pnum)),
GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pnum))) &
(~ GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE))); //disable open drain;
ETS_GPIO_INTR_ENABLE();
}
/*
* Set GPIO mode to interrupt. Optionally RAM helper because interrupts are dsabled
*/
#ifdef GPIO_INTERRUPT_ENABLE
static void NO_INTR_CODE set_gpio_interrupt(uint8 pin) {
ETS_GPIO_INTR_DISABLE();
PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]);
GPIO_DIS_OUTPUT(pin_num[pin]);
gpio_register_set(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin])),
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));
pin_trigger[pin] = true;
ETS_GPIO_INTR_ENABLE();
}
#endif
int platform_gpio_mode( unsigned pin, unsigned mode, unsigned pull ) int platform_gpio_mode( unsigned pin, unsigned mode, unsigned pull )
{ {
// NODE_DBG("Function platform_gpio_mode() is called. pin_mux:%d, func:%d\n",pin_mux[pin],pin_func[pin]); NODE_DBG("Function platform_gpio_mode() is called. pin_mux:%d, func:%d\n", pin_mux[pin], pin_func[pin]);
if (pin >= NUM_GPIO) if (pin >= NUM_GPIO)
return -1; return -1;
if(pin == 0){ if(pin == 0){
if(mode==PLATFORM_GPIO_INPUT) if(mode==PLATFORM_GPIO_INPUT)
gpio16_input_conf(); gpio16_input_conf();
else else
gpio16_output_conf(); gpio16_output_conf();
return 1; return 1;
} }
platform_pwm_close(pin); // closed from pwm module, if it is used in pwm platform_pwm_close(pin); // closed from pwm module, if it is used in pwm
switch(pull){ if (pull == PLATFORM_GPIO_PULLUP) {
case PLATFORM_GPIO_PULLUP: PIN_PULLUP_EN(pin_mux[pin]);
PIN_PULLUP_EN(pin_mux[pin]); } else {
break; PIN_PULLUP_DIS(pin_mux[pin]);
case PLATFORM_GPIO_FLOAT:
PIN_PULLUP_DIS(pin_mux[pin]);
break;
default:
PIN_PULLUP_DIS(pin_mux[pin]);
break;
} }
switch(mode){ switch(mode){
case PLATFORM_GPIO_INPUT: case PLATFORM_GPIO_INPUT:
#ifdef GPIO_INTERRUPT_ENABLE
lua_gpio_unref(pin); // unref the lua ref call back.
#endif
GPIO_DIS_OUTPUT(pin_num[pin]); GPIO_DIS_OUTPUT(pin_num[pin]);
/* run on */
case PLATFORM_GPIO_OUTPUT: case PLATFORM_GPIO_OUTPUT:
ETS_GPIO_INTR_DISABLE(); set_gpio_no_interrupt(pin);
#ifdef GPIO_INTERRUPT_ENABLE
pin_int_type[pin] = GPIO_PIN_INTR_DISABLE;
#endif
PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]);
//disable interrupt
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), GPIO_PIN_INTR_DISABLE);
//clear interrupt status
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin]));
GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin])), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin]))) & (~ GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE))); //disable open drain;
ETS_GPIO_INTR_ENABLE();
break; break;
#ifdef GPIO_INTERRUPT_ENABLE #ifdef GPIO_INTERRUPT_ENABLE
case PLATFORM_GPIO_INT: case PLATFORM_GPIO_INT:
ETS_GPIO_INTR_DISABLE(); set_gpio_interrupt(pin);
PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]);
GPIO_DIS_OUTPUT(pin_num[pin]);
gpio_register_set(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin])), 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));
ETS_GPIO_INTR_ENABLE();
break; break;
#endif #endif
default: default:
break; break;
} }
return 1; return 1;
} }
int platform_gpio_write( unsigned pin, unsigned level ) int platform_gpio_write( unsigned pin, unsigned level )
{ {
// NODE_DBG("Function platform_gpio_write() is called. pin:%d, level:%d\n",GPIO_ID_PIN(pin_num[pin]),level); // NODE_DBG("Function platform_gpio_write() is called. pin:%d, level:%d\n",GPIO_ID_PIN(pin_num[pin]),level);
@ -135,41 +153,62 @@ int platform_gpio_read( unsigned pin )
} }
#ifdef GPIO_INTERRUPT_ENABLE #ifdef GPIO_INTERRUPT_ENABLE
static void platform_gpio_intr_dispatcher( void *arg) { static task_handle_t gpio_task_handle;
platform_gpio_intr_handler_fn_t cb = arg;
uint8 i, level; static void ICACHE_RAM_ATTR platform_gpio_intr_dispatcher (void *dummy){
uint32 j=0;
uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
for (i = 0; i < GPIO_PIN_NUM; i++) { UNUSED(dummy);
if (pin_int_type[i] && (gpio_status & BIT(pin_num[i])) ) { /*
//disable interrupt * gpio_status is a bit map where bit 0 is set if unmapped gpio pin 0 (pin3) has
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[i]), GPIO_PIN_INTR_DISABLE); * triggered the ISR. bit 1 if unmapped gpio pin 1 (pin10=U0TXD), etc. Since this
//clear interrupt status * in the ISR, it makes sense to optimize this by doing a fast scan of the status
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(pin_num[i])); * and reverse mapping any set bits.
level = 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[i])); */
if(cb){ for (j = 0; gpio_status>0; j++, gpio_status >>= 1) {
cb(i, level); if (gpio_status&1) {
int i = pin_num_inv[j];
if (pin_int_type[i]) {
//disable interrupt
gpio_pin_intr_state_set(GPIO_ID_PIN(j), GPIO_PIN_INTR_DISABLE);
//clear interrupt status
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(j));
uint32 level = 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(j));
if (pin_trigger[i]) {
/* the task is only posted if a trigger callback is defined */
pin_trigger[i] = false;
task_post_high (gpio_task_handle, (i<<1) + level);
}
// Interrupts are re-enabled but any interrupt occuring before pin_trigger[i] is reset will be ignored.
gpio_pin_intr_state_set(GPIO_ID_PIN(j), pin_int_type[i]);
} }
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[i]), pin_int_type[i]);
} }
} }
} }
void platform_gpio_init( platform_gpio_intr_handler_fn_t cb ) void platform_gpio_init( task_handle_t gpio_task )
{ {
ETS_GPIO_INTR_ATTACH(platform_gpio_intr_dispatcher, cb); int i;
} gpio_task_handle = gpio_task;
int platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type ) get_pin_map();
ETS_GPIO_INTR_ATTACH(platform_gpio_intr_dispatcher, NULL);
}
/*
* Initialise GPIO interrupt mode. Optionally in RAM because interrupts are dsabled
*/
void NO_INTR_CODE platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type )
{ {
if (pin >= NUM_GPIO) if (platform_gpio_exists(pin)) {
return -1; ETS_GPIO_INTR_DISABLE();
ETS_GPIO_INTR_DISABLE(); //clear interrupt status
//clear interrupt status GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin]));
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin])); pin_int_type[pin] = type;
pin_int_type[pin] = type; pin_trigger[pin] = true;
//enable interrupt //enable interrupt
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), type); gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), type);
ETS_GPIO_INTR_ENABLE(); ETS_GPIO_INTR_ENABLE();
}
} }
#endif #endif
@ -269,7 +308,7 @@ void platform_uart_alt( int set )
// Send: version with and without mux // Send: version with and without mux
void platform_uart_send( unsigned id, u8 data ) void platform_uart_send( unsigned id, u8 data )
{ {
uart_tx_one_char(id, data); uart_tx_one_char(id, data);
} }
@ -353,7 +392,7 @@ uint32_t platform_pwm_setup( unsigned pin, uint32_t frequency, unsigned duty )
if ( pin < NUM_PWM) if ( pin < NUM_PWM)
{ {
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT); // disable gpio interrupt first platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT); // disable gpio interrupt first
if(!pwm_add(pin)) if(!pwm_add(pin))
return 0; return 0;
// pwm_set_duty(DUTY(duty), pin); // pwm_set_duty(DUTY(duty), pin);
pwm_set_duty(0, pin); pwm_set_duty(0, pin);
@ -410,7 +449,7 @@ uint32_t platform_i2c_setup( unsigned id, uint8_t sda, uint8_t scl, uint32_t spe
// platform_pwm_close(sda); // platform_pwm_close(sda);
// platform_pwm_close(scl); // platform_pwm_close(scl);
// disable gpio interrupt first // disable gpio interrupt first
platform_gpio_mode(sda, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); // inside this func call platform_pwm_close platform_gpio_mode(sda, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); // inside this func call platform_pwm_close
platform_gpio_mode(scl, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); // disable gpio interrupt first platform_gpio_mode(scl, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); // disable gpio interrupt first

View File

@ -7,6 +7,8 @@
#include "c_types.h" #include "c_types.h"
#include "driver/pwm.h" #include "driver/pwm.h"
#include "task/task.h"
// Error / status codes // Error / status codes
enum enum
{ {
@ -35,14 +37,12 @@ uint8_t platform_key_led( uint8_t level);
#define PLATFORM_GPIO_HIGH 1 #define PLATFORM_GPIO_HIGH 1
#define PLATFORM_GPIO_LOW 0 #define PLATFORM_GPIO_LOW 0
/* GPIO interrupt handler */ static inline int platform_gpio_exists( unsigned pin ) { return pin < NUM_GPIO; }
typedef void (* platform_gpio_intr_handler_fn_t)( unsigned pin, unsigned level );
int platform_gpio_mode( unsigned pin, unsigned mode, unsigned pull ); int platform_gpio_mode( unsigned pin, unsigned mode, unsigned pull );
int platform_gpio_write( unsigned pin, unsigned level ); int platform_gpio_write( unsigned pin, unsigned level );
int platform_gpio_read( unsigned pin ); int platform_gpio_read( unsigned pin );
void platform_gpio_init( platform_gpio_intr_handler_fn_t cb ); void platform_gpio_init( task_handle_t gpio_task );
int platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type ); void platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type );
// ***************************************************************************** // *****************************************************************************
// Timer subsection // Timer subsection
@ -62,7 +62,7 @@ enum
ELUA_CAN_ID_EXT ELUA_CAN_ID_EXT
}; };
int platform_can_exists( unsigned id ); static inline int platform_can_exists( unsigned id ) { return id < NUM_CAN; }
uint32_t platform_can_setup( unsigned id, uint32_t clock ); uint32_t platform_can_setup( unsigned id, uint32_t clock );
int platform_can_send( unsigned id, uint32_t canid, uint8_t idtype, uint8_t len, const uint8_t *data ); int platform_can_send( unsigned id, uint32_t canid, uint8_t idtype, uint8_t len, const uint8_t *data );
int platform_can_recv( unsigned id, uint32_t *canid, uint8_t *idtype, uint8_t *len, uint8_t *data ); int platform_can_recv( unsigned id, uint32_t *canid, uint8_t *idtype, uint8_t *len, uint8_t *data );
@ -95,7 +95,7 @@ int platform_can_recv( unsigned id, uint32_t *canid, uint8_t *idtype, uint8_t *l
typedef uint32_t spi_data_type; typedef uint32_t spi_data_type;
// The platform SPI functions // The platform SPI functions
int platform_spi_exists( unsigned id ); static inline int platform_spi_exists( unsigned id ) { return id < NUM_SPI; }
uint32_t platform_spi_setup( uint8_t id, int mode, unsigned cpol, unsigned cpha, uint32_t clock_div); uint32_t platform_spi_setup( uint8_t id, int mode, unsigned cpol, unsigned cpha, uint32_t clock_div);
int platform_spi_send( uint8_t id, uint8_t bitlen, spi_data_type data ); int platform_spi_send( uint8_t id, uint8_t bitlen, spi_data_type data );
spi_data_type platform_spi_send_recv( uint8_t id, uint8_t bitlen, spi_data_type data ); spi_data_type platform_spi_send_recv( uint8_t id, uint8_t bitlen, spi_data_type data );
@ -140,7 +140,7 @@ enum
#define PLATFORM_UART_FLOW_CTS 2 #define PLATFORM_UART_FLOW_CTS 2
// The platform UART functions // The platform UART functions
int platform_uart_exists( unsigned id ); static inline int platform_uart_exists( unsigned id ) { return id < NUM_UART; }
uint32_t platform_uart_setup( unsigned id, uint32_t baud, int databits, int parity, int stopbits ); uint32_t platform_uart_setup( unsigned id, uint32_t baud, int databits, int parity, int stopbits );
int platform_uart_set_buffer( unsigned id, unsigned size ); int platform_uart_set_buffer( unsigned id, unsigned size );
void platform_uart_send( unsigned id, uint8_t data ); void platform_uart_send( unsigned id, uint8_t data );
@ -163,7 +163,7 @@ void platform_uart_alt( int set );
#define DUTY(d) ((uint16_t)( ((unsigned)(d)*PWM_DEPTH) / NORMAL_PWM_DEPTH) ) #define DUTY(d) ((uint16_t)( ((unsigned)(d)*PWM_DEPTH) / NORMAL_PWM_DEPTH) )
// The platform PWM functions // The platform PWM functions
int platform_pwm_exists( unsigned id ); static inline int platform_pwm_exists( unsigned id ) { return ((id < NUM_PWM) && (id > 0)); }
uint32_t platform_pwm_setup( unsigned id, uint32_t frequency, unsigned duty ); uint32_t platform_pwm_setup( unsigned id, uint32_t frequency, unsigned duty );
void platform_pwm_close( unsigned id ); void platform_pwm_close( unsigned id );
void platform_pwm_start( unsigned id ); void platform_pwm_start( unsigned id );
@ -185,7 +185,7 @@ uint32_t platform_adc_set_clock( unsigned id, uint32_t frequency);
int platform_adc_check_timer_id( unsigned id, unsigned timer_id ); int platform_adc_check_timer_id( unsigned id, unsigned timer_id );
// ADC Common Functions // ADC Common Functions
int platform_adc_exists( unsigned id ); static inline int platform_adc_exists( unsigned id ) { return id < NUM_ADC; }
uint32_t platform_adc_get_maxval( unsigned id ); uint32_t platform_adc_get_maxval( unsigned id );
uint32_t platform_adc_set_smoothing( unsigned id, uint32_t length ); uint32_t platform_adc_set_smoothing( unsigned id, uint32_t length );
void platform_adc_set_blocking( unsigned id, uint32_t mode ); void platform_adc_set_blocking( unsigned id, uint32_t mode );
@ -193,6 +193,16 @@ void platform_adc_set_freerunning( unsigned id, uint32_t mode );
uint32_t platform_adc_is_done( unsigned id ); uint32_t platform_adc_is_done( unsigned id );
void platform_adc_set_timer( unsigned id, uint32_t timer ); void platform_adc_set_timer( unsigned id, uint32_t timer );
// ****************************************************************************
// OneWire functions
static inline int platform_ow_exists( unsigned id ) { return ((id < NUM_OW) && (id > 0)); }
// ****************************************************************************
// Timer functions
static inline int platform_tmr_exists( unsigned id ) { return id < NUM_TMR; }
// ***************************************************************************** // *****************************************************************************
// I2C platform interface // I2C platform interface
@ -210,7 +220,11 @@ enum
PLATFORM_I2C_DIRECTION_RECEIVER PLATFORM_I2C_DIRECTION_RECEIVER
}; };
int platform_i2c_exists( unsigned id ); #ifdef NUM_I2C
static inline int platform_i2c_exists( unsigned id ) { return id < NUM_I2C; }
#else
static inline int platform_i2c_exists( unsigned id ) { return 0; }
#endif
uint32_t platform_i2c_setup( unsigned id, uint8_t sda, uint8_t scl, uint32_t speed ); uint32_t platform_i2c_setup( unsigned id, uint8_t sda, uint8_t scl, uint32_t speed );
void platform_i2c_send_start( unsigned id ); void platform_i2c_send_start( unsigned id );
void platform_i2c_send_stop( unsigned id ); void platform_i2c_send_stop( unsigned id );
@ -271,7 +285,7 @@ int platform_tmr_exists( unsigned id );
#define MOD_CHECK_TIMER( id )\ #define MOD_CHECK_TIMER( id )\
if( id == PLATFORM_TIMER_SYS_ID && !platform_timer_sys_available() )\ if( id == PLATFORM_TIMER_SYS_ID && !platform_timer_sys_available() )\
return luaL_error( L, "the system timer is not available on this platform" );\ return luaL_error( L, "the system timer is not available on this platform" );\
if( !platform_timer_exists( id ) )\ if( !platform_tmr_exists( id ) )\
return luaL_error( L, "timer %d does not exist", ( unsigned )id )\ return luaL_error( L, "timer %d does not exist", ( unsigned )id )\
#define MOD_CHECK_RES_ID( mod, id, resmod, resid )\ #define MOD_CHECK_RES_ID( mod, id, resmod, resid )\

44
app/task/Makefile Normal file
View File

@ -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 = libtask.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 ./
INCLUDES += -I ../libc
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

72
app/task/task.c Normal file
View File

@ -0,0 +1,72 @@
/**
This file encapsulates the SDK-based task handling for the NodeMCU Lua firmware.
*/
#include "task/task.h"
#include "mem.h"
#include "c_stdio.h"
#define TASK_HANDLE_MONIKER 0x68680000
#define TASK_HANDLE_MASK 0xFFF80000
#define TASK_HANDLE_UNMASK (~TASK_HANDLE_MASK)
#define TASK_HANDLE_SHIFT 2
#define TASK_HANDLE_ALLOCATION_BRICK 4 // must be a power of 2
#define TASK_DEFAULT_QUEUE_LEN 8
#define TASK_PRIORITY_MASK 3
#define CHECK(p,v,msg) if (!(p)) { NODE_DBG ( msg ); return (v); }
/*
* Private arrays to hold the 3 event task queues and the dispatch callbacks
*/
LOCAL os_event_t *task_Q[TASK_PRIORITY_COUNT];
LOCAL task_callback_t *task_func;
LOCAL int task_count;
LOCAL void task_dispatch (os_event_t *e) {
task_handle_t handle = e->sig;
if ( (handle & TASK_HANDLE_MASK) == TASK_HANDLE_MONIKER) {
uint16 entry = (handle & TASK_HANDLE_UNMASK) >> TASK_HANDLE_SHIFT;
uint8 priority = handle & TASK_PRIORITY_MASK;
if ( priority <= TASK_PRIORITY_HIGH && task_func && entry < task_count ){
/* call the registered task handler with the specified parameter and priority */
task_func[entry](e->par, priority);
return;
}
}
/* Invalid signals are ignored */
NODE_DBG ( "Invalid signal issued: %08x", handle);
}
/*
* Initialise the task handle callback for a given priority. This doesn't need
* to be called explicitly as the get_id function will call this lazily.
*/
bool task_init_handler(uint8 priority, uint8 qlen) {
if (priority <= TASK_PRIORITY_HIGH && task_Q[priority] == NULL) {
task_Q[priority] = (os_event_t *) os_malloc( sizeof(os_event_t)*qlen );
os_memset (task_Q[priority], 0, sizeof(os_event_t)*qlen);
if (task_Q[priority]) {
return system_os_task( task_dispatch, priority, task_Q[priority], qlen );
}
}
return false;
}
task_handle_t task_get_id(task_callback_t t) {
int p = TASK_PRIORITY_COUNT;
/* Initialise and uninitialised Qs with the default Q len */
while(p--) if (!task_Q[p]) {
CHECK(task_init_handler( p, TASK_DEFAULT_QUEUE_LEN ), 0, "Task initialisation failed");
}
if ( (task_count & (TASK_HANDLE_ALLOCATION_BRICK - 1)) == 0 ) {
/* With a brick size of 4 this branch is taken at 0, 4, 8 ... and the new size is +4 */
task_func =(task_callback_t *) os_realloc(task_func,
sizeof(task_callback_t)*(task_count+TASK_HANDLE_ALLOCATION_BRICK));
CHECK(task_func, 0 , "Malloc failure in task_get_id");
os_memset (task_func+task_count, 0, sizeof(task_callback_t)*TASK_HANDLE_ALLOCATION_BRICK);
}
task_func[task_count++] = t;
return TASK_HANDLE_MONIKER + ((task_count-1) << TASK_HANDLE_SHIFT);
}

View File

@ -12,8 +12,6 @@
#include "platform.h" #include "platform.h"
#include "c_string.h" #include "c_string.h"
#include "c_stdlib.h" #include "c_stdlib.h"
#include "c_stdio.h"
#include "flash_fs.h" #include "flash_fs.h"
#include "user_interface.h" #include "user_interface.h"
#include "user_exceptions.h" #include "user_exceptions.h"
@ -21,6 +19,7 @@
#include "ets_sys.h" #include "ets_sys.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "task/task.h"
#include "mem.h" #include "mem.h"
#ifdef LUA_USE_MODULES_RTCTIME #ifdef LUA_USE_MODULES_RTCTIME
@ -81,35 +80,27 @@ void TEXT_SECTION_ATTR user_start_trampoline (void)
call_user_start (); call_user_start ();
} }
// +================== New task interface ==================+
void task_lua(os_event_t *e){ static void start_lua(task_param_t param, uint8 priority) {
char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL }; char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL };
NODE_DBG("Task task_lua started.\n"); NODE_DBG("Task task_lua started.\n");
switch(e->sig){ lua_main( 2, lua_argv );
case SIG_LUA:
NODE_DBG("SIG_LUA received.\n");
lua_main( 2, lua_argv );
break;
case SIG_UARTINPUT:
lua_handle_input (false);
break;
case LUA_PROCESS_LINE_SIG:
lua_handle_input (true);
break;
default:
break;
}
} }
void task_init(void){ static void handle_input(task_param_t flag, uint8 priority) {
taskQueue = (os_event_t *)os_malloc(sizeof(os_event_t) * TASK_QUEUE_LEN); // c_printf("HANDLE_INPUT: %u %u\n", flag, priority); REMOVE
system_os_task(task_lua, USER_TASK_PRIO_0, taskQueue, TASK_QUEUE_LEN); lua_handle_input (flag);
} }
// extern void test_spiffs(); static task_handle_t input_sig;
// extern int test_romfs();
// extern uint16_t flash_get_sec_num(); task_handle_t user_get_input_sig(void) {
return input_sig;
}
bool user_process_input(bool force) {
return task_post_low(input_sig, force);
}
void nodemcu_init(void) void nodemcu_init(void)
{ {
@ -153,34 +144,13 @@ void nodemcu_init(void)
system_restart (); system_restart ();
} }
#if defined( BUILD_WOFS ) #if defined ( BUILD_SPIFFS )
romfs_init();
// if( !wofs_format() )
// {
// NODE_ERR( "\ni*** ERROR ***: unable to erase the flash. WOFS might be compromised.\n" );
// NODE_ERR( "It is advised to re-flash the NodeWifi image.\n" );
// }
// else
// NODE_ERR( "format done.\n" );
// test_romfs();
#elif defined ( BUILD_SPIFFS )
fs_mount(); fs_mount();
// test_spiffs(); // test_spiffs();
#endif #endif
// endpoint_setup(); // endpoint_setup();
// char* lua_argv[] = { (char *)"lua", (char *)"-e", (char *)"print(collectgarbage'count');ttt={};for i=1,100 do table.insert(ttt,i*2 -1);print(i);end for k, v in pairs(ttt) do print('<'..k..' '..v..'>') end print(collectgarbage'count');", NULL }; task_post_low(task_get_id(start_lua),'s');
// lua_main( 3, lua_argv );
// char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL };
// lua_main( 2, lua_argv );
// char* lua_argv[] = { (char *)"lua", (char *)"-e", (char *)"pwm.setup(0,100,50) pwm.start(0) pwm.stop(0)", NULL };
// lua_main( 3, lua_argv );
// NODE_DBG("Flash sec num: 0x%x\n", flash_get_sec_num());
task_init();
system_os_post(LUA_TASK_PRIO,SIG_LUA,'s');
} }
/****************************************************************************** /******************************************************************************
@ -194,14 +164,11 @@ void user_init(void)
#ifdef LUA_USE_MODULES_RTCTIME #ifdef LUA_USE_MODULES_RTCTIME
rtctime_late_startup (); rtctime_late_startup ();
#endif #endif
// NODE_DBG("SDK version:%s\n", system_get_sdk_version());
// system_print_meminfo();
// os_printf("Heap size::%d.\n",system_get_free_heap_size());
// os_delay_us(50*1000); // delay 50ms before init uart
UartBautRate br = BIT_RATE_DEFAULT; UartBautRate br = BIT_RATE_DEFAULT;
uart_init (br, br, USER_TASK_PRIO_0, SIG_UARTINPUT); input_sig = task_get_id(handle_input);
uart_init (br, br, input_sig);
#ifndef NODE_DEBUG #ifndef NODE_DEBUG
system_set_os_print(0); system_set_os_print(0);

View File

@ -0,0 +1,96 @@
# Extension Developer FAQ
**# # # Work in Progress # # #**
## How does the non-OS SDK structure execution
Details of the execution model for the **non-OS SDK** is not well documented by
Espressif. This section summarises the project's understanding of how this execution
model works based on the Espressif-supplied examples and SDK documentation, plus
various posts on the Espressif BBS and other forums, and an examination of the
BootROM code.
The ESP8266 boot ROM contains a set of primitive tasking and dispatch functions
which are also used by the SDK. In this model, execution units are either:
- **INTERRUPT SERVICE ROUTINES (ISRs)** which are declared and controlled
through the `ets_isr_attach()` and other `ets_isr_*` and `ets_intr_*`
functions. ISRs can be defined on a range of priorities, where a higher
priority ISR is able to interrupt a lower priority one. ISRs are time
critical and should complete in no more than 50 µSec.
ISR code and data constants should be run out of RAM or ROM, for two reasons:
if an ISR interrupts a flash I/O operation (which must disable the Flash
instruction cache) and a cache miss occurs, then the ISR will trigger a
fatal exception; secondly, the
execution time for Flash memory (that is located in the `irom0` load section)
is indeterminate: whilst cache-hits can run at full memory bandwidth, any
cache-misses require the code to be read from Flash; and even though
H/W-based, this is at roughly 26x slower than memory bandwidth (for DIO
flash); this will cause ISR execution to fall outside the require time
guidelines. (Note that any time critical code within normal execution and that
is bracketed by interrupt lock / unlock guards should also follow this 50
µSec guideline.)<br/><br/>
- **TASKS**. A task is a normal execution unit running at a non-interrupt priority.
Tasks can be executed from Flash memory. An executing task can be interrupted
by one or more ISRs being delivered, but it won't be preempted by another
queued task. The Espressif guideline is that no individual task should run for
more than 15 mSec, before returning control to the SDK.
The ROM will queue up to 32 pending tasks at priorities 0..31 and will
execute the highest priority queued task next (or wait on interrupt if none
is runnable). The SDK tasking system is layered on this ROM dispatcher and
it reserves 29 of these task priorities for its own use, including the
implementation of the various SDK timer, WiFi and other callback mechanisms
such as the software WDT.
Three of these task priorities are allocated for and exposed directly at an
application level. The application can declare a single task handler for each
level, and associate a task queue with the level. Tasks can be posted to this
queue. (The post will fail is the queue is full). Tasks are then delivered
FIFO within task priority.
How the three user task priorities USER0 .. USER2 are positioned relative to
the SDK task priorities is undocumented, but some SDK tasks definitely run at
a lower priority than USER0. As a result if you always have a USER task queued
for execution, then you can starve SDK housekeeping tasks and you will start
to get WiFi and other failures. Espressif therefore recommends that you don't
stay computable for more than 500 mSec to avoid such timeouts.
Note that the 50µS, 15mSec and 500mSec limits are guidelines
and not hard constraints -- that is if you break them (slightly) then your code
may (usually) work, but you can get very difficult to diagnose and intermittent
failures. Also running ISRs from Flash may work until there is a collision with
SPIFFS I/O which will then a cause CPU exception.
Also note that the SDK API function `system_os_post()`, and the `task_post_*()`
macros which generate this can be safely called from an ISR.
The Lua runtime is NOT reentrant, and hence any code which calls any Lua API
must run within a task context. Any such task is what we call a _Lua-Land Task_
(or **LLT**). _ISRs must not access the Lua API or Lua resources._ LLTs can be
executed as SDK API callbacks or OS tasks. They can also, of course, call the
Lua execution system to execute Lua code (e.g. `luaL_dofile()` and related
calls).
Also since the application has no control over the relative time ordering of
tasks and SDK API callbacks, LLTs can't make any assumptions about whether a
task and any posted successors will run consecutively.
This API is designed to complement the Lua library model, so that a library can
declare one or more task handlers and that both ISPs and LLTs can then post a
message for delivery to a task handler. Each task handler has a unique message
associated with it, and may bind a single uint32 parameter. How this parameter
is interpreted is left to the task poster and task handler to coordinate.
The interface is exposed through `#include "task/task.h"` and involves two API
calls. Any task handlers are declared, typically in the module_init function by
assigning `task_get_id(some_task_callback)` to a (typically globally) accessible
handle variable, say `XXX_callback_handle`. This can then be used in an ISR or
normal LLT to execute a `task_post_YYY(XXX_callback_handle,param)` where YYY is
one of `low`, `medium`, `high`. The callback will then be executed when the SDK
delivers the task.
_Note_: `task_post_YYY` can fail with a false return if the task Q is full.

45
docs/en/hardware-faq.md Normal file
View File

@ -0,0 +1,45 @@
# Hardware FAQ
## What is this FAQ for?
This FAQ addresses hardware-specific issues relating to the NodeMcu firmware on
NoceMCU Inc Devkits and other ESP-8266 modules.
## Hardware Specifics
## Why file writes fail all the time on DEVKIT V1.0?
NodeMCU DEVKIT V1.0 uses ESP12-E-DIO(ESP-12-D) module. This module runs the
Flash memory in [Dual IO SPI](#whats-the-different-between-dio-and-qio-mode)
(DIO) mode. This firmware will not be correctly loaded if you use old flashtool
versions, and the filesystem will not work if you used a pre 0.9.6 firmware
version (<0.9.5) or old. The easiest way to resolve this problem s update all
the firmware and flash tool to current version.
- Use the latest [esptool.py](https://github.com/themadinventor/esptool) with
DIO support and command option to flash firmware, or
- Use the latest [NodeMCU flasher](https://github.com/NodeMCU/NodeMCU-flasher)
with default option. (You must select the `restore to default` option in advanced
menu tab), or
- Use the latest Espressif's flash tool -- see [this Espressif forum
topic](http://bbs.espressif.com/viewtopic.php?f=5&t=433) (without auto download
support). Use DIO mode and 32M flash size option, and flash latest firmware to
0x00000. Before flashing firmware, remember to hold FLASH button, and press RST
button once. Note that the new NodeMCU our firmware download tool, when
released, will be capable of flashing firmware automatically without any button
presses.
## What's the different between DIO and QIO mode?
Whether DIO or QIO modes are available depends on the physical connection
between the ESP8266 CPU and its onboard flash chip. QIO connects to the flash
using 5 data pins as compared to DIO's 3. This frees up an extra 2 IO pins for
GPIO use, but this also halves the read/write data-rate to Flash compared to
QIO modules.
## How to use DEVKIT V0.9 on Mac OS X?
<TODO>
### How does DEVKIT use DTR and RTS enter download mode?
<TODO>

View File

@ -338,21 +338,4 @@ Of course you should still use functions to structure your code and encapsulate
### How to save memory? ### How to save memory?
* The NodeMCU development team recommends that you consider using a tailored firmware build, which only includes the modules that you plan to use before developing any Lua application. Once you have the ability to make and flash custom builds, the you also have the option of moving time sensitive or logic intensive code into your own custom module. Doing this can save a large amount of RAM as C code can be run directly from Flash memory. If you want an easy-to-use intermediate option then why note try the [cloud based NodeMCU custom build service](http://frightanic.com/NodeMCU-custom-build)?. * The NodeMCU development team recommends that you consider using a tailored firmware build, which only includes the modules that you plan to use before developing any Lua application. Once you have the ability to make and flash custom builds, the you also have the option of moving time sensitive or logic intensive code into your own custom module. Doing this can save a large amount of RAM as C code can be run directly from Flash memory. If you want an easy-to-use intermediate option then why note try the [cloud based NodeMCU custom build service](http://frightanic.com/NodeMCU-custom-build)?.
## Hardware Specifics
### Why file writes fail all the time on DEVKIT V1.0?
NodeMCU DEVKIT V1.0 uses ESP12-E-DIO(ESP-12-D) module. This module runs the Flash memory in [Dual IO SPI](#whats-the-different-between-dio-and-qio-mode) (DIO) mode. This firmware will not be correctly loaded if you uses old flashtool version, and the filesystem will not work if you used a pre 0.9.6 firmware version (<0.9.5) or old. The easiest way to resolve this problem s update all the firmware and flash tool to current version.
- Use the latest [esptool.py](https://github.com/themadinventor/esptool) with DIO support and command option to flash firmware, or
- Use the latest [NodeMCU flasher](https://github.com/NodeMCU/NodeMCU-flasher) with default option. (You must select the `restore to default` option in advanced menu tab), or
- Use the latest Espressif's flash tool -- see [this Espressif forum topic](http://bbs.espressif.com/viewtopic.php?f=5&t=433) (without auto download support). Use DIO mode and 32M flash size option, and flash latest firmware to 0x00000. Before flashing firmware, remember to hold FLASH button, and press RST button once. Note that the new NodeMCU our firmware download tool, when released, will be capable of flashing firmware automatically without any button presses.
### What's the different between DIO and QIO mode?
<TODO>
### How to use DEVKIT V0.9 on Mac OS X?
<TODO>
### How does DEVKIT use DTR and RTS enter download mode?
<TODO>

View File

@ -90,7 +90,7 @@ SECTIONS
LONG(0) LONG(0) /* Null-terminate the array */ LONG(0) LONG(0) /* Null-terminate the array */
/* SDK doesn't use libc functions, and are therefore safe to put in flash */ /* SDK doesn't use libc functions, and are therefore safe to put in flash */
*/libc.a(.text* .literal*) */libc.a:*.o(.text* .literal*)
/* end libc functions */ /* end libc functions */
_irom0_text_end = ABSOLUTE(.); _irom0_text_end = ABSOLUTE(.);

View File

@ -27,7 +27,10 @@ pages:
- Building the firmware: 'en/build.md' - Building the firmware: 'en/build.md'
- Flashing the firmware: 'en/flash.md' - Flashing the firmware: 'en/flash.md'
- Uploading code: 'en/upload.md' - Uploading code: 'en/upload.md'
- FAQ: 'en/faq.md' - FAQs:
- Lua Developer FAQ: 'en/lua-developer-faq.md'
- Extension Developer FAQ: 'en/extn-developer-faq.md'
- Hardware FAQ: 'en/hardware-faq.md'
- Support: 'en/support.md' - Support: 'en/support.md'
- Modules: - Modules:
- 'adc': 'en/modules/adc.md' - 'adc': 'en/modules/adc.md'