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:
parent
19471f54ad
commit
49733f6f6d
|
@ -32,6 +32,7 @@ SUBDIRS= \
|
|||
lwip \
|
||||
coap \
|
||||
mqtt \
|
||||
task \
|
||||
u8glib \
|
||||
ucglib \
|
||||
smart \
|
||||
|
@ -73,6 +74,7 @@ COMPONENTS_eagle.app.v6 = \
|
|||
json/libjson.a \
|
||||
upgrade/libupgrade.a \
|
||||
platform/libplatform.a \
|
||||
task/libtask.a \
|
||||
libc/liblibc.a \
|
||||
lua/liblua.a \
|
||||
lwip/liblwip.a \
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "ets_sys.h"
|
||||
#include "osapi.h"
|
||||
#include "driver/uart.h"
|
||||
#include "task/task.h"
|
||||
#include "user_config.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
|
@ -27,8 +28,7 @@
|
|||
|
||||
|
||||
// For event signalling
|
||||
static uint8 task = USER_TASK_PRIO_MAX;
|
||||
static os_signal_t sig;
|
||||
static task_handle_t sig = 0;
|
||||
|
||||
// UartDev is defined and initialized in rom code.
|
||||
extern UartDevice UartDev;
|
||||
|
@ -267,8 +267,8 @@ uart0_rx_intr_handler(void *para)
|
|||
got_input = true;
|
||||
}
|
||||
|
||||
if (got_input && task != USER_TASK_PRIO_MAX)
|
||||
system_os_post (task, sig, UART0);
|
||||
if (got_input && sig)
|
||||
task_post_low (sig, false);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -281,9 +281,8 @@ uart0_rx_intr_handler(void *para)
|
|||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
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;
|
||||
|
||||
// rom use 74880 baut_rate, here reinitialize
|
||||
|
|
|
@ -101,7 +101,7 @@ typedef struct {
|
|||
int buff_uart_no; //indicate which uart use tx/rx buffer
|
||||
} 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_sendStr(const char *str);
|
||||
void uart0_putc(const char c);
|
||||
|
|
|
@ -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
|
||||
|
|
@ -41,12 +41,19 @@
|
|||
#define NODE_ERR
|
||||
#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_ATTR __attribute__((aligned(4)))
|
||||
#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 GPIO_INTERRUPT_ENABLE
|
||||
//#define MD2_ENABLE
|
||||
#define SHA2_ENABLE
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
#include "module.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lmem.h"
|
||||
#include "platform.h"
|
||||
#include "rom.h"
|
||||
|
||||
#include "user_interface.h"
|
||||
#include "c_types.h"
|
||||
#include "c_string.h"
|
||||
|
||||
|
@ -16,69 +16,52 @@
|
|||
#define HIGH PLATFORM_GPIO_HIGH
|
||||
#define LOW PLATFORM_GPIO_LOW
|
||||
|
||||
|
||||
#ifdef GPIO_INTERRUPT_ENABLE
|
||||
static int gpio_cb_ref[GPIO_PIN_NUM];
|
||||
static lua_State* gL = NULL;
|
||||
|
||||
void lua_gpio_unref(unsigned pin){
|
||||
if(gpio_cb_ref[pin] != LUA_NOREF){
|
||||
if(gL!=NULL)
|
||||
luaL_unref(gL, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
|
||||
}
|
||||
gpio_cb_ref[pin] = LUA_NOREF;
|
||||
}
|
||||
|
||||
void gpio_intr_callback( unsigned pin, unsigned level )
|
||||
// This task is scheduled by the ISP if pin_trigger[pin] is true and is used
|
||||
// to intitied the Lua-land gpio.trig() callback function
|
||||
static void gpio_intr_callback_task (task_param_t param, uint8 priority)
|
||||
{
|
||||
unsigned pin = param >> 1;
|
||||
unsigned level = param & 1;
|
||||
UNUSED(priority);
|
||||
|
||||
NODE_DBG("pin:%d, level:%d \n", pin, level);
|
||||
if(gpio_cb_ref[pin] == LUA_NOREF)
|
||||
return;
|
||||
if(!gL)
|
||||
return;
|
||||
lua_rawgeti(gL, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
|
||||
lua_pushinteger(gL, level);
|
||||
lua_call(gL, 1, 0);
|
||||
if(gpio_cb_ref[pin] != LUA_NOREF) {
|
||||
// GPIO callbacks are run in L0 and inlcude the level as a parameter
|
||||
lua_State *L = lua_getstate();
|
||||
NODE_DBG("Calling: %08x\n", gpio_cb_ref[pin]);
|
||||
// The trigger is reset before the callback, as the callback itself might reset the trigger
|
||||
pin_trigger[pin] = true;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
|
||||
lua_pushinteger(L, level);
|
||||
lua_call(L, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Lua: trig( pin, type, function )
|
||||
static int lgpio_trig( lua_State* L )
|
||||
{
|
||||
unsigned type;
|
||||
unsigned pin;
|
||||
size_t sl;
|
||||
unsigned pin = luaL_checkinteger( L, 1 );
|
||||
static const char * const opts[] = {"", "up", "down", "both", "low", "high"};
|
||||
static const int opts_type[] = {
|
||||
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_POSEDGE, GPIO_PIN_INTR_NEGEDGE,
|
||||
GPIO_PIN_INTR_ANYEDGE, GPIO_PIN_INTR_LOLEVEL, GPIO_PIN_INTR_HILEVEL
|
||||
};
|
||||
int type = opts_type[luaL_checkoption(L, 2, "", opts)];
|
||||
|
||||
pin = luaL_checkinteger( L, 1 );
|
||||
MOD_CHECK_ID( gpio, pin );
|
||||
if(pin==0)
|
||||
return luaL_error( L, "no interrupt for D0" );
|
||||
luaL_argcheck(L, platform_gpio_exists(pin) && pin>0, 1, "Invalid interrupt pin");
|
||||
|
||||
const char *str = luaL_checklstring( L, 2, &sl );
|
||||
if (str == NULL)
|
||||
return luaL_error( L, "wrong arg type" );
|
||||
|
||||
if(sl == 2 && c_strcmp(str, "up") == 0){
|
||||
type = GPIO_PIN_INTR_POSEDGE;
|
||||
}else if(sl == 4 && c_strcmp(str, "down") == 0){
|
||||
type = GPIO_PIN_INTR_NEGEDGE;
|
||||
}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){
|
||||
if (type != GPIO_PIN_INTR_DISABLE) {
|
||||
int cbtype = lua_type(L, 3);
|
||||
luaL_argcheck(L, cbtype == LUA_TFUNCTION || cbtype == LUA_TLIGHTFUNCTION, 3,
|
||||
"invalid callback type");
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -87,68 +70,61 @@ static int lgpio_trig( lua_State* L )
|
|||
// Lua: mode( pin, mode, pullup )
|
||||
static int lgpio_mode( lua_State* L )
|
||||
{
|
||||
unsigned mode, pullup = FLOAT;
|
||||
unsigned pin;
|
||||
unsigned pin = luaL_checkinteger( L, 1 );
|
||||
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
|
||||
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){
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
|
||||
gpio_cb_ref[pin] = LUA_NOREF;
|
||||
}
|
||||
gpio_cb_ref[pin] = LUA_NOREF;
|
||||
}
|
||||
#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 0;
|
||||
}
|
||||
|
||||
// Lua: read( pin )
|
||||
static int lgpio_read( lua_State* L )
|
||||
{
|
||||
unsigned pin;
|
||||
|
||||
pin = luaL_checkinteger( L, 1 );
|
||||
unsigned pin = luaL_checkinteger( L, 1 );
|
||||
MOD_CHECK_ID( gpio, pin );
|
||||
|
||||
unsigned level = platform_gpio_read( pin );
|
||||
lua_pushinteger( L, level );
|
||||
lua_pushinteger( L, platform_gpio_read( pin ) );
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua: write( pin, level )
|
||||
static int lgpio_write( lua_State* L )
|
||||
{
|
||||
unsigned level;
|
||||
unsigned pin;
|
||||
unsigned pin = luaL_checkinteger( L, 1 );
|
||||
unsigned level = luaL_checkinteger( L, 2 );
|
||||
|
||||
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" );
|
||||
luaL_argcheck(L, level==HIGH || level==LOW, 2, "wrong level type" );
|
||||
|
||||
platform_gpio_write(pin, level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DELAY_TABLE_MAX_LEN 256
|
||||
#define noInterrupts ets_intr_lock
|
||||
#define interrupts ets_intr_unlock
|
||||
#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] )
|
||||
// -- serout( pin, firstLevel, delay_table, [repeatNum] )
|
||||
// gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
|
||||
|
@ -161,61 +137,40 @@ static int lgpio_write( lua_State* L )
|
|||
// gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles
|
||||
static int lgpio_serout( lua_State* L )
|
||||
{
|
||||
unsigned level;
|
||||
unsigned pin;
|
||||
unsigned table_len = 0;
|
||||
unsigned repeat = 0;
|
||||
int delay_table[DELAY_TABLE_MAX_LEN];
|
||||
unsigned clocks_per_us = system_get_cpu_freq();
|
||||
unsigned pin = luaL_checkinteger( L, 1 );
|
||||
unsigned level = luaL_checkinteger( L, 2 );
|
||||
unsigned repeats = luaL_optint( L, 4, 1 );
|
||||
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" );
|
||||
luaL_argcheck(L, platform_gpio_exists(pin), 1, "Invalid pin");
|
||||
luaL_argcheck(L, level==HIGH || level==LOW, 2, "Wrong arg type" );
|
||||
luaL_argcheck(L, lua_istable( L, 3 ) &&
|
||||
((table_len = lua_objlen( L, 3 )<DELAY_TABLE_MAX_LEN)), 3, "Invalid table" );
|
||||
luaL_argcheck(L, repeats<256, 4, "repeats >= 256" );
|
||||
|
||||
uint32 *delay_table = luaM_newvector(L, table_len*repeats, uint32);
|
||||
for( i = 1; i <= table_len; i++ ) {
|
||||
lua_rawgeti( L, 3, i + 1 );
|
||||
unsigned delay = (unsigned) luaL_checkinteger( L, -1 );
|
||||
if (delay > 1000000) return luaL_error( L, "delay %u must be < 1,000,000 us", i );
|
||||
delay_table[i-1] = delay;
|
||||
lua_pop( L, 1 );
|
||||
}
|
||||
|
||||
if(lua_isnumber(L, 4))
|
||||
repeat = lua_tointeger( L, 4 );
|
||||
if( repeat < 0 || repeat > DELAY_TABLE_MAX_LEN )
|
||||
return luaL_error( L, "delay must < 256" );
|
||||
|
||||
if(repeat==0)
|
||||
repeat = 1;
|
||||
int j;
|
||||
bool skip_loop = true;
|
||||
do
|
||||
{
|
||||
if(skip_loop){ // skip the first loop.
|
||||
skip_loop = false;
|
||||
for( i = 0; i <= repeats; i++ ) {
|
||||
if (!i) // skip the first loop (presumably this is some form of icache priming??).
|
||||
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);
|
||||
|
||||
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
|
||||
|
@ -245,7 +200,7 @@ int luaopen_gpio( lua_State *L ) {
|
|||
for(i=0;i<GPIO_PIN_NUM;i++){
|
||||
gpio_cb_ref[i] = LUA_NOREF;
|
||||
}
|
||||
platform_gpio_init(gpio_intr_callback);
|
||||
platform_gpio_init(task_get_id(gpio_intr_callback_task));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -145,8 +145,6 @@ static int node_heap( lua_State* L )
|
|||
return 1;
|
||||
}
|
||||
|
||||
static lua_State *gL = NULL;
|
||||
|
||||
#ifdef DEVKIT_VERSION_0_9
|
||||
static int led_high_count = LED_HIGH_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) {
|
||||
lua_State *L = lua_getstate();
|
||||
NODE_DBG("key_long_press is called.\n");
|
||||
if (long_key_ref == LUA_NOREF) {
|
||||
default_long_press(arg);
|
||||
return;
|
||||
}
|
||||
if (!gL)
|
||||
return;
|
||||
lua_rawgeti(gL, LUA_REGISTRYINDEX, long_key_ref);
|
||||
lua_call(gL, 0, 0);
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, long_key_ref);
|
||||
lua_call(L, 0, 0);
|
||||
}
|
||||
|
||||
static void key_short_press(void *arg) {
|
||||
lua_State *L = lua_getstate();
|
||||
NODE_DBG("key_short_press is called.\n");
|
||||
if (short_key_ref == LUA_NOREF) {
|
||||
default_short_press(arg);
|
||||
return;
|
||||
}
|
||||
if (!gL)
|
||||
return;
|
||||
lua_rawgeti(gL, LUA_REGISTRYINDEX, short_key_ref);
|
||||
lua_call(gL, 0, 0);
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, short_key_ref);
|
||||
lua_call(L, 0, 0);
|
||||
}
|
||||
|
||||
static void update_key_led (void *p)
|
||||
|
@ -286,7 +282,6 @@ static int node_key( lua_State* L )
|
|||
} else {
|
||||
ref = &short_key_ref;
|
||||
}
|
||||
gL = L;
|
||||
// luaL_checkanyfunction(L, 2);
|
||||
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
|
||||
|
@ -305,6 +300,7 @@ static int node_key( lua_State* L )
|
|||
#endif
|
||||
|
||||
extern lua_Load gLoad;
|
||||
extern bool user_process_input(bool force);
|
||||
// Lua: input("string")
|
||||
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(load->line); // buggy here
|
||||
NODE_DBG("\nResult(if any):\n");
|
||||
system_os_post (LUA_TASK_PRIO, LUA_PROCESS_LINE_SIG, 0);
|
||||
user_process_input(true);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -330,12 +326,13 @@ static int node_input( lua_State* L )
|
|||
static int output_redir_ref = LUA_NOREF;
|
||||
static int serial_debug = 1;
|
||||
void output_redirect(const char *str) {
|
||||
lua_State *L = lua_getstate();
|
||||
// if(c_strlen(str)>=TX_BUFF_SIZE){
|
||||
// NODE_ERR("output too long.\n");
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (output_redir_ref == LUA_NOREF || !gL) {
|
||||
if (output_redir_ref == LUA_NOREF || !L) {
|
||||
uart0_sendStr(str);
|
||||
return;
|
||||
}
|
||||
|
@ -344,15 +341,14 @@ void output_redirect(const char *str) {
|
|||
uart0_sendStr(str);
|
||||
}
|
||||
|
||||
lua_rawgeti(gL, LUA_REGISTRYINDEX, output_redir_ref);
|
||||
lua_pushstring(gL, str);
|
||||
lua_call(gL, 1, 0); // this call back function should never user output.
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, output_redir_ref);
|
||||
lua_pushstring(L, str);
|
||||
lua_call(L, 1, 0); // this call back function should never user output.
|
||||
}
|
||||
|
||||
// Lua: output(function(c), debug)
|
||||
static int node_output( lua_State* L )
|
||||
{
|
||||
gL = L;
|
||||
// luaL_checkanyfunction(L, 1);
|
||||
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
|
||||
|
|
|
@ -10,82 +10,6 @@ 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
|
||||
|
||||
|
|
|
@ -1,45 +1,59 @@
|
|||
#include "pin_map.h"
|
||||
#include "eagle_soc.h"
|
||||
#if 0
|
||||
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,
|
||||
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};
|
||||
#include "mem.h"
|
||||
#include "osapi.h"
|
||||
|
||||
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
|
||||
GPIO_INT_TYPE pin_int_type[GPIO_PIN_NUM] = {
|
||||
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,
|
||||
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,
|
||||
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE};
|
||||
uint8_t pin_num_inv[GPIO_PIN_NUM_INV];
|
||||
uint8_t pin_int_type[GPIO_PIN_NUM];
|
||||
uint8_t pin_trigger[GPIO_PIN_NUM];
|
||||
#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,
|
||||
2, 14, 12, 13,
|
||||
15, 3, 1, 9,
|
||||
10};
|
||||
|
||||
uint8_t pin_func[GPIO_PIN_NUM] = {0, FUNC_GPIO5, FUNC_GPIO4, FUNC_GPIO0,
|
||||
FUNC_GPIO2, FUNC_GPIO14, FUNC_GPIO12, FUNC_GPIO13,
|
||||
FUNC_GPIO15, FUNC_GPIO3, FUNC_GPIO1, FUNC_GPIO9,
|
||||
FUNC_GPIO10};
|
||||
typedef struct {
|
||||
int8 mux;
|
||||
uint8 num;
|
||||
uint8 func;
|
||||
uint8 intr_type;
|
||||
} pin_rec;
|
||||
#define DECLARE_PIN(n,p) { (PERIPHS_IO_MUX_##p##_U - PERIPHS_IO_MUX), n, FUNC_GPIO##n, GPIO_PIN_INTR_DISABLE}
|
||||
static const pin_rec pin_map[] = {
|
||||
{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
|
||||
GPIO_INT_TYPE pin_int_type[GPIO_PIN_NUM] = {
|
||||
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,
|
||||
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,
|
||||
GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,
|
||||
GPIO_PIN_INTR_DISABLE};
|
||||
#endif
|
||||
pin_num_inv[pin_num[i]] = i;
|
||||
pin_int_type[i] = pin[i].intr_type;
|
||||
pin_trigger[i] = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,17 @@
|
|||
#include "gpio.h"
|
||||
|
||||
#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 uint8_t pin_num[GPIO_PIN_NUM];
|
||||
extern uint8_t pin_func[GPIO_PIN_NUM];
|
||||
#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
|
||||
|
||||
void get_pin_map(void);
|
||||
|
||||
#endif // #ifndef __PIN_MAP_H__
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
// Platform-dependent functions
|
||||
// Platform-dependent functions and includes
|
||||
|
||||
#include "platform.h"
|
||||
#include "common.h"
|
||||
#include "c_stdio.h"
|
||||
#include "c_string.h"
|
||||
#include "c_stdlib.h"
|
||||
#include "llimits.h"
|
||||
#include "gpio.h"
|
||||
#include "user_interface.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/gpio16.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/spi.h"
|
||||
// Platform specific includes
|
||||
#include "driver/uart.h"
|
||||
|
||||
static void pwms_init();
|
||||
|
||||
|
@ -39,72 +39,90 @@ uint8_t platform_key_led( uint8_t level){
|
|||
|
||||
// ****************************************************************************
|
||||
// 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
|
||||
extern void lua_gpio_unref(unsigned pin);
|
||||
pin_trigger[pin] = false;
|
||||
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(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 )
|
||||
{
|
||||
// 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)
|
||||
return -1;
|
||||
|
||||
if(pin == 0){
|
||||
if(mode==PLATFORM_GPIO_INPUT)
|
||||
gpio16_input_conf();
|
||||
else
|
||||
gpio16_output_conf();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
platform_pwm_close(pin); // closed from pwm module, if it is used in pwm
|
||||
|
||||
switch(pull){
|
||||
case PLATFORM_GPIO_PULLUP:
|
||||
PIN_PULLUP_EN(pin_mux[pin]);
|
||||
break;
|
||||
case PLATFORM_GPIO_FLOAT:
|
||||
PIN_PULLUP_DIS(pin_mux[pin]);
|
||||
break;
|
||||
default:
|
||||
PIN_PULLUP_DIS(pin_mux[pin]);
|
||||
break;
|
||||
if (pull == PLATFORM_GPIO_PULLUP) {
|
||||
PIN_PULLUP_EN(pin_mux[pin]);
|
||||
} else {
|
||||
PIN_PULLUP_DIS(pin_mux[pin]);
|
||||
}
|
||||
|
||||
switch(mode){
|
||||
|
||||
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]);
|
||||
/* run on */
|
||||
case PLATFORM_GPIO_OUTPUT:
|
||||
ETS_GPIO_INTR_DISABLE();
|
||||
#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();
|
||||
set_gpio_no_interrupt(pin);
|
||||
break;
|
||||
|
||||
#ifdef GPIO_INTERRUPT_ENABLE
|
||||
case PLATFORM_GPIO_INT:
|
||||
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));
|
||||
ETS_GPIO_INTR_ENABLE();
|
||||
set_gpio_interrupt(pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
@ -135,41 +153,62 @@ int platform_gpio_read( unsigned pin )
|
|||
}
|
||||
|
||||
#ifdef GPIO_INTERRUPT_ENABLE
|
||||
static void platform_gpio_intr_dispatcher( void *arg) {
|
||||
platform_gpio_intr_handler_fn_t cb = arg;
|
||||
uint8 i, level;
|
||||
static task_handle_t gpio_task_handle;
|
||||
|
||||
static void ICACHE_RAM_ATTR platform_gpio_intr_dispatcher (void *dummy){
|
||||
uint32 j=0;
|
||||
uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
|
||||
for (i = 0; i < GPIO_PIN_NUM; i++) {
|
||||
if (pin_int_type[i] && (gpio_status & BIT(pin_num[i])) ) {
|
||||
//disable interrupt
|
||||
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[i]), GPIO_PIN_INTR_DISABLE);
|
||||
//clear interrupt status
|
||||
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(pin_num[i]));
|
||||
level = 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[i]));
|
||||
if(cb){
|
||||
cb(i, level);
|
||||
UNUSED(dummy);
|
||||
/*
|
||||
* gpio_status is a bit map where bit 0 is set if unmapped gpio pin 0 (pin3) has
|
||||
* triggered the ISR. bit 1 if unmapped gpio pin 1 (pin10=U0TXD), etc. Since this
|
||||
* in the ISR, it makes sense to optimize this by doing a fast scan of the status
|
||||
* and reverse mapping any set bits.
|
||||
*/
|
||||
for (j = 0; gpio_status>0; j++, gpio_status >>= 1) {
|
||||
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)
|
||||
return -1;
|
||||
ETS_GPIO_INTR_DISABLE();
|
||||
//clear interrupt status
|
||||
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin]));
|
||||
pin_int_type[pin] = type;
|
||||
//enable interrupt
|
||||
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), type);
|
||||
ETS_GPIO_INTR_ENABLE();
|
||||
if (platform_gpio_exists(pin)) {
|
||||
ETS_GPIO_INTR_DISABLE();
|
||||
//clear interrupt status
|
||||
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin]));
|
||||
pin_int_type[pin] = type;
|
||||
pin_trigger[pin] = true;
|
||||
//enable interrupt
|
||||
gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), type);
|
||||
ETS_GPIO_INTR_ENABLE();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "c_types.h"
|
||||
#include "driver/pwm.h"
|
||||
#include "task/task.h"
|
||||
|
||||
// Error / status codes
|
||||
enum
|
||||
{
|
||||
|
@ -35,14 +37,12 @@ uint8_t platform_key_led( uint8_t level);
|
|||
#define PLATFORM_GPIO_HIGH 1
|
||||
#define PLATFORM_GPIO_LOW 0
|
||||
|
||||
/* GPIO interrupt handler */
|
||||
typedef void (* platform_gpio_intr_handler_fn_t)( unsigned pin, unsigned level );
|
||||
|
||||
static inline int platform_gpio_exists( unsigned pin ) { return pin < NUM_GPIO; }
|
||||
int platform_gpio_mode( unsigned pin, unsigned mode, unsigned pull );
|
||||
int platform_gpio_write( unsigned pin, unsigned level );
|
||||
int platform_gpio_read( unsigned pin );
|
||||
void platform_gpio_init( platform_gpio_intr_handler_fn_t cb );
|
||||
int platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type );
|
||||
void platform_gpio_init( task_handle_t gpio_task );
|
||||
void platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type );
|
||||
// *****************************************************************************
|
||||
// Timer subsection
|
||||
|
||||
|
@ -62,7 +62,7 @@ enum
|
|||
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 );
|
||||
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 );
|
||||
|
@ -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;
|
||||
|
||||
// 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);
|
||||
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 );
|
||||
|
@ -140,7 +140,7 @@ enum
|
|||
#define PLATFORM_UART_FLOW_CTS 2
|
||||
|
||||
// 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 );
|
||||
int platform_uart_set_buffer( unsigned id, unsigned size );
|
||||
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) )
|
||||
|
||||
// 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 );
|
||||
void platform_pwm_close( 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 );
|
||||
|
||||
// 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_set_smoothing( unsigned id, uint32_t length );
|
||||
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 );
|
||||
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
|
||||
|
||||
|
@ -210,7 +220,11 @@ enum
|
|||
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 );
|
||||
void platform_i2c_send_start( unsigned id );
|
||||
void platform_i2c_send_stop( unsigned id );
|
||||
|
@ -271,7 +285,7 @@ int platform_tmr_exists( unsigned id );
|
|||
#define MOD_CHECK_TIMER( id )\
|
||||
if( id == PLATFORM_TIMER_SYS_ID && !platform_timer_sys_available() )\
|
||||
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 )\
|
||||
|
||||
#define MOD_CHECK_RES_ID( mod, id, resmod, resid )\
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -12,8 +12,6 @@
|
|||
#include "platform.h"
|
||||
#include "c_string.h"
|
||||
#include "c_stdlib.h"
|
||||
#include "c_stdio.h"
|
||||
|
||||
#include "flash_fs.h"
|
||||
#include "user_interface.h"
|
||||
#include "user_exceptions.h"
|
||||
|
@ -21,6 +19,7 @@
|
|||
|
||||
#include "ets_sys.h"
|
||||
#include "driver/uart.h"
|
||||
#include "task/task.h"
|
||||
#include "mem.h"
|
||||
|
||||
#ifdef LUA_USE_MODULES_RTCTIME
|
||||
|
@ -81,35 +80,27 @@ void TEXT_SECTION_ATTR user_start_trampoline (void)
|
|||
call_user_start ();
|
||||
}
|
||||
|
||||
|
||||
void task_lua(os_event_t *e){
|
||||
char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL };
|
||||
NODE_DBG("Task task_lua started.\n");
|
||||
switch(e->sig){
|
||||
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;
|
||||
}
|
||||
// +================== New task interface ==================+
|
||||
static void start_lua(task_param_t param, uint8 priority) {
|
||||
char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL };
|
||||
NODE_DBG("Task task_lua started.\n");
|
||||
lua_main( 2, lua_argv );
|
||||
}
|
||||
|
||||
void task_init(void){
|
||||
taskQueue = (os_event_t *)os_malloc(sizeof(os_event_t) * TASK_QUEUE_LEN);
|
||||
system_os_task(task_lua, USER_TASK_PRIO_0, taskQueue, TASK_QUEUE_LEN);
|
||||
static void handle_input(task_param_t flag, uint8 priority) {
|
||||
// c_printf("HANDLE_INPUT: %u %u\n", flag, priority); REMOVE
|
||||
lua_handle_input (flag);
|
||||
}
|
||||
|
||||
// extern void test_spiffs();
|
||||
// extern int test_romfs();
|
||||
static task_handle_t input_sig;
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -153,34 +144,13 @@ void nodemcu_init(void)
|
|||
system_restart ();
|
||||
}
|
||||
|
||||
#if defined( BUILD_WOFS )
|
||||
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 )
|
||||
#if defined ( BUILD_SPIFFS )
|
||||
fs_mount();
|
||||
// test_spiffs();
|
||||
#endif
|
||||
// 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 };
|
||||
// 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');
|
||||
task_post_low(task_get_id(start_lua),'s');
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -194,14 +164,11 @@ void user_init(void)
|
|||
#ifdef LUA_USE_MODULES_RTCTIME
|
||||
rtctime_late_startup ();
|
||||
#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;
|
||||
|
||||
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
|
||||
system_set_os_print(0);
|
||||
|
|
|
@ -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.
|
||||
|
|
@ -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>
|
|
@ -338,21 +338,4 @@ Of course you should still use functions to structure your code and encapsulate
|
|||
### 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)?.
|
||||
|
||||
## 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>
|
|
@ -90,7 +90,7 @@ SECTIONS
|
|||
LONG(0) LONG(0) /* Null-terminate the array */
|
||||
|
||||
/* 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 */
|
||||
|
||||
_irom0_text_end = ABSOLUTE(.);
|
||||
|
|
|
@ -27,7 +27,10 @@ pages:
|
|||
- Building the firmware: 'en/build.md'
|
||||
- Flashing the firmware: 'en/flash.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'
|
||||
- Modules:
|
||||
- 'adc': 'en/modules/adc.md'
|
||||
|
|
Loading…
Reference in New Issue