Skip to content

Commit

Permalink
Make GPIO state buffer dynamic
Browse files Browse the repository at this point in the history
Saves a bit of RAM on unused GPIOs.

CL: Make GPIO state buffer dynamic. Saves a bit of RAM.

PUBLISHED_FROM=aeb78f67edd221265d446a47edd64aca7b5e0acd
  • Loading branch information
Deomid Ryabkov authored and cesantabot committed Sep 25, 2018
1 parent a021235 commit 6cf690c
Show file tree
Hide file tree
Showing 15 changed files with 102 additions and 55 deletions.
1 change: 0 additions & 1 deletion fw/include/mgos_init.h
Expand Up @@ -39,7 +39,6 @@ enum mgos_init_result {
MGOS_INIT_MDNS_FAILED = -17,
MGOS_INIT_MQTT_FAILED = -18,
MGOS_INIT_I2C_FAILED = -19,
MGOS_INIT_ATCA_FAILED = -20,
MGOS_INIT_APPLY_UPDATE_FAILED = -21,
MGOS_INIT_CONSOLE_INIT_FAILED = -22,
MGOS_INIT_GPIO_INIT_FAILED = -23,
Expand Down
2 changes: 1 addition & 1 deletion fw/platforms/cc3200/Makefile.build
Expand Up @@ -99,7 +99,7 @@ IPATH = $(MGOS_IPATH) $(sort $(APP_SOURCE_DIRS) $(APP_INCLUDES)) \

# Note: CC3200 has only 32 GPIO but our port uses pin-based numbering
# and those go from 1 to 64.
MGOS_CC3200_FEATURES ?= -DMGOS_NUM_GPIO=65 '-DUMM_ONFREE(ptr, size)=memset(ptr, 0xff, size)'
MGOS_CC3200_FEATURES ?= '-DUMM_ONFREE(ptr, size)=memset(ptr, 0xff, size)'

MG_FEATURES ?= $(MG_FEATURES_TINY) \
-DMG_LOCALS -DMG_ENABLE_SSL \
Expand Down
2 changes: 1 addition & 1 deletion fw/platforms/cc3220/Makefile.build
Expand Up @@ -94,7 +94,7 @@ IPATH = $(MGOS_IPATH) $(sort $(APP_SOURCE_DIRS) $(APP_INCLUDES)) \

# Note: CC3220 has only 32 GPIO but our port uses pin-based numbering
# and those go from 1 to 64.
MGOS_CC3220_FEATURES ?= -DMGOS_NUM_GPIO=65 '-DUMM_ONFREE(ptr, size)=memset(ptr, 0xff, size)' \
MGOS_CC3220_FEATURES ?= '-DUMM_ONFREE(ptr, size)=memset(ptr, 0xff, size)' \
-DMGOS_FS_OFFSET=$(FS_OFFSET) \
-DMGOS_FS_SIZE=$(FS_SIZE) \
-DMGOS_FS_BLOCK_SIZE=$(FS_BLOCK_SIZE) \
Expand Down
10 changes: 3 additions & 7 deletions fw/platforms/esp32/src/esp32_gpio.c
Expand Up @@ -32,12 +32,8 @@

#include "common/cs_dbg.h"

#if MGOS_NUM_GPIO != GPIO_PIN_COUNT
#error MGOS_NUM_GPIO must match GPIO_PIN_COUNT
#endif

gpio_isr_handle_t s_int_handle;
static uint8_t s_int_ena[MGOS_NUM_GPIO];
static uint8_t s_int_ena[GPIO_PIN_COUNT];

/* Invoked by SDK, runs in ISR context. */
IRAM static void esp32_gpio_isr(void *arg) {
Expand All @@ -49,7 +45,7 @@ IRAM static void esp32_gpio_isr(void *arg) {
mgos_gpio_hal_int_cb(i);
}
int_st = GPIO.status1.intr_st;
for (uint32_t i = 32, mask = 1; i < MGOS_NUM_GPIO; i++, mask <<= 1) {
for (uint32_t i = 32, mask = 1; i < GPIO_PIN_COUNT; i++, mask <<= 1) {
if (s_int_ena[i] == 0 || !(int_st & mask)) continue;
GPIO.pin[i].int_ena = 0;
mgos_gpio_clear_int(i);
Expand Down Expand Up @@ -217,7 +213,7 @@ uint32_t mgos_bitbang_n100_cal;

enum mgos_init_result mgos_gpio_hal_init() {
/* Soft reset does not clear GPIO_PINn_INT_ENA, we have to do it ourselves. */
for (int i = 0; i < MGOS_NUM_GPIO; i++) {
for (int i = 0; i < GPIO_PIN_COUNT; i++) {
if (GPIO_IS_VALID_GPIO(i)) gpio_intr_disable(i);
}
esp_err_t r = gpio_isr_register(esp32_gpio_isr, NULL, 0, &s_int_handle);
Expand Down
1 change: 0 additions & 1 deletion fw/platforms/esp32/src/esp32_src.mk
Expand Up @@ -75,7 +75,6 @@ C_CXX_CFLAGS += -DMGOS_APP=\"$(APP)\" -DFW_ARCHITECTURE=$(APP_PLATFORM) \
$(MG_FEATURES_TINY) -DMG_NET_IF=MG_NET_IF_LWIP_LOW_LEVEL \
$(MGOS_FEATURES) -DMGOS_MAX_NUM_UARTS=3 \
-DMGOS_DEBUG_UART=$(MGOS_DEBUG_UART) \
-DMGOS_NUM_GPIO=40 \
-DMG_ENABLE_FILESYSTEM \
-DMG_ENABLE_DIRECTORY_LISTING \
-DCS_DISABLE_MD5 -DMG_EXT_MD5 \
Expand Down
3 changes: 1 addition & 2 deletions fw/platforms/esp8266/Makefile.build
Expand Up @@ -180,7 +180,6 @@ MEMORY_FLAGS = -DFS_MAX_OPEN_FILES=5

MGOS_CFLAGS = -DMGOS_APP=\"$(APP)\" \
-DMGOS_MAX_NUM_UARTS=2 \
-DMGOS_NUM_GPIO=16 \
-DC_DISABLE_BUILTIN_SNPRINTF

MGOS_LIB = $(BUILD_DIR)/mongoose-os.a
Expand Down Expand Up @@ -392,7 +391,7 @@ $(BREAKDOWN_FILE): $(APP_ELF)
# -- Linking.

# Link the main ELF output file.
BIN_PARTS = $(BUILD_DIR)/esp_cache.c.o $(APP_OBJS) $(FFI_EXPORTS_O) $(BUILD_INFO_O) $(MG_BUILD_INFO_O) $(MGOS_LIB) $(ATCA_LIB) $(LWIP_LIB) $(APP_BIN_LIB_FILES)
BIN_PARTS = $(BUILD_DIR)/esp_cache.c.o $(APP_OBJS) $(FFI_EXPORTS_O) $(BUILD_INFO_O) $(MG_BUILD_INFO_O) $(MGOS_LIB) $(LWIP_LIB) $(APP_BIN_LIB_FILES)
$(APP_ELF): $(BIN_PARTS) $(LD_SCRIPT)
ifeq "$(MGOS_ESP8266_RTOS)" "1"
$(OBJCOPY) --weaken-symbol printf --weaken-symbol puts /opt/Espressif/esp-open-sdk/xtensa-lx106-elf/xtensa-lx106-elf/lib/libc.a
Expand Down
4 changes: 0 additions & 4 deletions fw/platforms/esp8266/src/esp_gpio.c
Expand Up @@ -32,10 +32,6 @@
#include "common/cs_dbg.h"
#include "esp_periph.h"

#if MGOS_NUM_GPIO != GPIO_PIN_COUNT
#error MGOS_NUM_GPIO must match GPIO_PIN_COUNT
#endif

#define GPIO_PIN_COUNT 16

static uint8_t s_int_config[GPIO_PIN_COUNT];
Expand Down
2 changes: 1 addition & 1 deletion fw/platforms/pic32/Makefile.build
Expand Up @@ -71,7 +71,7 @@ VPATH = $(APP_SOURCE_DIRS) $(MGOS_PIC32_SRC_PATH) \
IPATH = $(APP_SOURCE_DIRS) $(MGOS_PIC32_SRC_PATH) $(GEN_DIR) $(MGOS_PATH)
###IPATH += $(BOOT_PATH)/lib

MGOS_PIC32_FEATURES ?= -DMGOS_NUM_GPIO=16
MGOS_PIC32_FEATURES ?=

MG_FEATURES ?= $(MG_FEATURES_TINY) \
-DMG_LOCALS \
Expand Down
2 changes: 1 addition & 1 deletion fw/platforms/posix/Makefile
Expand Up @@ -26,7 +26,7 @@ MGOS_ENABLE_SYS_SERVICE = 0
LDFLAGS ?=

MGOS_POSIX_FEATURES ?= -DMGOS_PROMPT_DISABLE_ECHO -DMGOS_MAX_NUM_UARTS=2 \
-DMGOS_NUM_GPIO=16 -DMGOS_HAVE_ETHERNET \
-DMGOS_HAVE_ETHERNET \
-DMGOS_NUM_HW_TIMERS=0
MONGOOSE_FEATURES = \
-DMG_USE_READ_WRITE -DMG_ENABLE_THREADS -DMG_ENABLE_THREADS \
Expand Down
2 changes: 1 addition & 1 deletion fw/platforms/stm32/mk/devices/stm32f412rg.mk
@@ -1,5 +1,5 @@
FAMILY = stm32f4
SRAM_SIZE = 262144
FLASH_SIZE = 1048576
STM32_CFLAGS += -DSTM32F412Rx -DMGOS_NUM_GPIO=114
STM32_CFLAGS += -DSTM32F412Rx
MGOS_SRCS += stm32f412.c
2 changes: 1 addition & 1 deletion fw/platforms/stm32/mk/devices/stm32f746ng.mk
@@ -1,5 +1,5 @@
FAMILY = stm32f7
SRAM_SIZE = 327680
FLASH_SIZE = 1048576
STM32_CFLAGS += -DSTM32F746xx -DMGOS_NUM_GPIO=144
STM32_CFLAGS += -DSTM32F746xx
MGOS_SRCS += stm32f74x.c
2 changes: 1 addition & 1 deletion fw/platforms/stm32/mk/devices/stm32f746zg.mk
@@ -1,5 +1,5 @@
FAMILY = stm32f7
SRAM_SIZE = 327680
FLASH_SIZE = 1048576
STM32_CFLAGS += -DSTM32F746xx -DMGOS_NUM_GPIO=128
STM32_CFLAGS += -DSTM32F746xx
MGOS_SRCS += stm32f74x.c
2 changes: 1 addition & 1 deletion fw/platforms/stm32/mk/devices/stm32l475vg.mk
Expand Up @@ -2,5 +2,5 @@ FAMILY = stm32l4
SRAM_SIZE = 98304
SRAM2_SIZE = 32768
FLASH_SIZE = 1048576
STM32_CFLAGS += -DSTM32L475xx -DMGOS_NUM_GPIO=80
STM32_CFLAGS += -DSTM32L475xx
MGOS_SRCS += stm32l475.c
119 changes: 87 additions & 32 deletions fw/src/mgos_gpio.c
Expand Up @@ -20,34 +20,57 @@

#include "mgos_gpio_hal.h"
#include "mgos_gpio_internal.h"
#include "mgos_hal.h"
#include "mgos_system.h"
#include "mgos_timers.h"

#ifndef MGOS_NUM_GPIO
#error Please define MGOS_NUM_GPIO
#endif

#ifndef IRAM
#define IRAM
#endif

struct mgos_gpio_state {
mgos_gpio_int_handler_f cb;
void *cb_arg;
int pin;
unsigned int isr : 1;
unsigned int cb_pending : 1;
unsigned int btn_active_state : 1;
unsigned int debounce_ms : 16;
mgos_gpio_int_handler_f cb;
void *cb_arg;
};
static struct mgos_gpio_state s_state[MGOS_NUM_GPIO];

static struct mgos_gpio_state *s_state = NULL;
static int s_num_gpio_states = 0;
struct mgos_rlock_type *s_lock = NULL;

static void mgos_gpio_int_cb(void *arg);
static void mgos_gpio_dbnc_done_cb(void *arg);

static struct mgos_gpio_state *mgos_gpio_get_state(int pin) {
for (int i = 0; i < s_num_gpio_states; i++) {
if (s_state[i].pin == pin) return &s_state[i];
}
return NULL;
};

static struct mgos_gpio_state *mgos_gpio_get_or_create_state(int pin) {
struct mgos_gpio_state *s = mgos_gpio_get_state(pin);
if (s != NULL) return s;
s = (struct mgos_gpio_state *) calloc(s_num_gpio_states + 1, sizeof(*s));
if (s == NULL) return NULL;
/* State may be accessed from ISR. Disable ints for the time
* we swap the buffer. */
mgos_ints_disable();
memcpy(s, s_state, s_num_gpio_states * sizeof(*s));
s_state = s;
s = &s_state[s_num_gpio_states++];
s->pin = pin;
mgos_ints_enable();
return s;
}

/* In ISR context */
IRAM void mgos_gpio_hal_int_cb(int pin) {
struct mgos_gpio_state *s = &s_state[pin];
if (s->cb == NULL) return;
struct mgos_gpio_state *s = mgos_gpio_get_state(pin);
if (s == NULL || s->cb == NULL) return;
if (s->isr) {
s->cb(pin, s->cb_arg);
mgos_gpio_hal_int_done(pin);
Expand All @@ -69,8 +92,9 @@ IRAM void mgos_gpio_hal_int_cb(int pin) {
/* In MGOS task context. */
static void mgos_gpio_int_cb(void *arg) {
int pin = (intptr_t) arg;
struct mgos_gpio_state *s = (struct mgos_gpio_state *) &s_state[pin];
if (!s->cb_pending || s->cb == NULL) return;
mgos_rlock(s_lock);
struct mgos_gpio_state *s = mgos_gpio_get_state(pin);
if (s == NULL || !s->cb_pending || s->cb == NULL) goto out;
if (s->debounce_ms == 0) {
s->cb(pin, s->cb_arg);
s->cb_pending = false;
Expand All @@ -79,13 +103,29 @@ static void mgos_gpio_int_cb(void *arg) {
/* Keep the int disabled for the duration of the debounce time */
mgos_set_timer(s->debounce_ms, false, mgos_gpio_dbnc_done_cb, arg);
}
out:
mgos_runlock(s_lock);
}

static void mgos_gpio_dbnc_done_cb(void *arg) {
int pin = (intptr_t) arg;
struct mgos_gpio_state *s = (struct mgos_gpio_state *) &s_state[pin];
if (mgos_gpio_read(pin) == s->btn_active_state) s->cb(pin, s->cb_arg);
s->cb_pending = false;
bool active_state;
mgos_gpio_int_handler_f cb = NULL;
void *cb_arg = NULL;
{
mgos_rlock(s_lock);
struct mgos_gpio_state *s = mgos_gpio_get_state(pin);
if (s != NULL) {
active_state = s->btn_active_state;
cb = s->cb;
cb_arg = s->cb_arg;
s->cb_pending = false;
}
mgos_runlock(s_lock);
}
if (cb != NULL && mgos_gpio_read(pin) == active_state) {
cb(pin, cb_arg);
}
/* Clear any noise that happened during debounce timer. */
mgos_gpio_clear_int(pin);
mgos_gpio_hal_int_done(pin);
Expand All @@ -94,16 +134,21 @@ static void mgos_gpio_dbnc_done_cb(void *arg) {
static bool gpio_set_int_handler_common(int pin, enum mgos_gpio_int_mode mode,
mgos_gpio_int_handler_f cb, void *arg,
bool isr) {
if (pin < 0 || pin > MGOS_NUM_GPIO) return false;
bool ret = false;
if (!mgos_gpio_hal_set_int_mode(pin, mode)) return false;
if (mode == MGOS_GPIO_INT_NONE) return true;
struct mgos_gpio_state *s = (struct mgos_gpio_state *) &s_state[pin];
s->isr = isr;
s->cb = cb;
s->cb_arg = arg;
s->debounce_ms = 0;
s->cb_pending = false;
return true;
{
mgos_rlock(s_lock);
struct mgos_gpio_state *s = mgos_gpio_get_or_create_state(pin);
if (s != NULL) {
s->isr = isr;
s->cb = cb;
s->cb_arg = arg;
ret = true;
}
mgos_runlock(s_lock);
}
return ret;
}

bool mgos_gpio_set_int_handler(int pin, enum mgos_gpio_int_mode mode,
Expand All @@ -120,13 +165,17 @@ void mgos_gpio_remove_int_handler(int pin, mgos_gpio_int_handler_f *old_cb,
void **old_arg) {
mgos_gpio_int_handler_f cb = NULL;
void *cb_arg = NULL;
if (pin >= 0 && pin < MGOS_NUM_GPIO) {
struct mgos_gpio_state *s = (struct mgos_gpio_state *) &s_state[pin];
mgos_gpio_disable_int(pin);
cb = s->cb;
cb_arg = s->cb_arg;
s->cb = NULL;
s->cb_arg = NULL;
{
mgos_rlock(s_lock);
struct mgos_gpio_state *s = mgos_gpio_get_state(pin);
if (s != NULL) {
cb = s->cb;
cb_arg = s->cb_arg;
s->cb = NULL;
s->cb_arg = NULL;
mgos_gpio_disable_int(pin);
}
mgos_runlock(s_lock);
}
if (old_cb != NULL) *old_cb = cb;
if (old_arg != NULL) *old_arg = cb_arg;
Expand All @@ -143,8 +192,13 @@ bool mgos_gpio_set_button_handler(int pin, enum mgos_gpio_pull_type pull_type,
!mgos_gpio_set_int_handler(pin, int_mode, cb, arg)) {
return false;
}
s_state[pin].btn_active_state = (int_mode == MGOS_GPIO_INT_EDGE_POS);
s_state[pin].debounce_ms = debounce_ms;
{
mgos_rlock(s_lock);
struct mgos_gpio_state *s = mgos_gpio_get_state(pin);
s->btn_active_state = (int_mode == MGOS_GPIO_INT_EDGE_POS);
s->debounce_ms = debounce_ms;
mgos_runlock(s_lock);
}
return mgos_gpio_enable_int(pin);
}

Expand All @@ -155,5 +209,6 @@ IRAM bool mgos_gpio_toggle(int pin) {
}

enum mgos_init_result mgos_gpio_init() {
s_lock = mgos_rlock_create();
return mgos_gpio_hal_init();
}
3 changes: 3 additions & 0 deletions fw/src/mgos_hal_freertos.c
Expand Up @@ -280,14 +280,17 @@ IRAM struct mgos_rlock_type *mgos_rlock_create(void) {
}

IRAM void mgos_rlock(struct mgos_rlock_type *l) {
if (l == NULL) return;
xSemaphoreTakeRecursive((SemaphoreHandle_t) l, portMAX_DELAY);
}

IRAM void mgos_runlock(struct mgos_rlock_type *l) {
if (l == NULL) return;
xSemaphoreGiveRecursive((SemaphoreHandle_t) l);
}

IRAM void mgos_rlock_destroy(struct mgos_rlock_type *l) {
if (l == NULL) return;
vSemaphoreDelete((SemaphoreHandle_t) l);
}
#endif /* MGOS_BOOT_BUILD */

0 comments on commit 6cf690c

Please sign in to comment.