From 7a074a14ced0c9ea890793aa7dc43c896cfdf9b9 Mon Sep 17 00:00:00 2001 From: danicampora Date: Wed, 25 Feb 2015 22:38:33 +0100 Subject: [PATCH] cc3200: Implement safe boot pin and system led behaviour. The safe boot pin, when pulled high during reset rolls back the firmware to the "factory" image and skips execution of 'boot.py' and 'main.py'. This is useful to recover from a crash condition. The system led is used mostly to signal errors. --- cc3200/boards/LAUNCHXL/mpconfigboard.h | 9 ++++ cc3200/bootmgr/bootloader.mk | 8 ++- cc3200/bootmgr/main.c | 56 +++++++++----------- cc3200/main.c | 2 +- cc3200/misc/FreeRTOSHooks.c | 11 ++-- cc3200/misc/mperror.c | 72 +++++++++++++++++++++++++- cc3200/misc/mperror.h | 16 ++++-- cc3200/mods/pybextint.c | 5 +- cc3200/mptask.c | 64 ++++++++++++++--------- cc3200/telnet/telnet.c | 4 +- 10 files changed, 172 insertions(+), 75 deletions(-) diff --git a/cc3200/boards/LAUNCHXL/mpconfigboard.h b/cc3200/boards/LAUNCHXL/mpconfigboard.h index c4472c77bd..2d12d4f6cb 100644 --- a/cc3200/boards/LAUNCHXL/mpconfigboard.h +++ b/cc3200/boards/LAUNCHXL/mpconfigboard.h @@ -37,3 +37,12 @@ #define MICROPY_STDIO_UART PYB_UART_0 #define MICROPY_STDIO_UART_BAUD 115200 +#define MICROPY_SYS_LED_PRCM PRCM_GPIOA1 +#define MICROPY_SAFE_BOOT_PRCM PRCM_GPIOA2 +#define MICROPY_SYS_LED_PORT GPIOA1_BASE +#define MICROPY_SAFE_BOOT_PORT GPIOA2_BASE +#define MICROPY_SYS_LED_PIN_NUM PIN_64 // GPIO9 +#define MICROPY_SAFE_BOOT_PIN_NUM PIN_15 // GPIO22 +#define MICROPY_SYS_LED_PORT_PIN GPIO_PIN_1 +#define MICROPY_SAFE_BOOT_PORT_PIN GPIO_PIN_6 + diff --git a/cc3200/bootmgr/bootloader.mk b/cc3200/bootmgr/bootloader.mk index 64d7f671a9..1f687d9b88 100644 --- a/cc3200/bootmgr/bootloader.mk +++ b/cc3200/bootmgr/bootloader.mk @@ -5,6 +5,7 @@ BOOT_INC += -Ibootmgr/sl BOOT_INC += -Ihal BOOT_INC += -Ihal/inc BOOT_INC += -I../drivers/cc3100/inc +BOOT_INC += -Imisc BOOT_INC += -Imods BOOT_INC += -Isimplelink BOOT_INC += -Isimplelink/oslib @@ -39,6 +40,10 @@ BOOT_CC3100_SRC_C = $(addprefix drivers/cc3100/,\ src/wlan.c \ ) +BOOT_MISC_SRC_C = $(addprefix misc/,\ + mperror.c \ + ) + BOOT_MODS_SRC_C = $(addprefix mods/,\ pybwdt.c \ ) @@ -68,7 +73,7 @@ BOOT_STM_SRC_C = $(addprefix stmhal/,\ ) OBJ = $(addprefix $(BUILD)/, $(BOOT_HAL_SRC_C:.c=.o) $(BOOT_MODS_SRC_C:.c=.o) $(BOOT_SL_SRC_C:.c=.o) $(BOOT_CC3100_SRC_C:.c=.o) $(BOOT_UTIL_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(BOOT_MAIN_SRC_C:.c=.o) $(BOOT_MAIN_SRC_S:.s=.o) $(BOOT_PY_SRC_C:.c=.o) $(BOOT_STM_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(BOOT_MISC_SRC_C:.c=.o) $(BOOT_MAIN_SRC_C:.c=.o) $(BOOT_MAIN_SRC_S:.s=.o) $(BOOT_PY_SRC_C:.c=.o) $(BOOT_STM_SRC_C:.c=.o)) # Add the linker script LINKER_SCRIPT = bootmgr/bootmgr.lds @@ -90,6 +95,7 @@ ifeq ($(BTYPE), debug) CFLAGS += -DDEBUG=DEBUG # Optimize the stable sources only $(BUILD)/hal/%.o: CFLAGS += -Os +$(BUILD)/misc/%.o: CFLAGS += -Os $(BUILD)/simplelink/%.o: CFLAGS += -Os $(BUILD)/drivers/cc3100/%.o: CFLAGS += -Os $(BUILD)/py/%.o: CFLAGS += -Os diff --git a/cc3200/bootmgr/main.c b/cc3200/bootmgr/main.c index 839e23ecdd..0e7ecd01b0 100644 --- a/cc3200/bootmgr/main.c +++ b/cc3200/bootmgr/main.c @@ -26,8 +26,10 @@ #include #include - #include + +#include "py/mpconfig.h" +#include MICROPY_HAL_H #include "hw_ints.h" #include "hw_types.h" #include "hw_gpio.h" @@ -50,6 +52,7 @@ #include "cc3200_hal.h" #include "debug.h" #include "pybwdt.h" +#include "mperror.h" //***************************************************************************** @@ -60,19 +63,11 @@ #define BOOTMGR_HASH_SIZE 32 #define BOOTMGR_BUFF_SIZE 512 -#define BOOTMGR_WAIT_SAFE_MODE_MS 2000 -#define BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS 250 - -#define BOOTMGR_SAFE_MODE_ENTER_MS 1000 -#define BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS 100 - -#define BOOTMGR_PINS_PRCM PRCM_GPIOA3 -#define BOOTMGR_PINS_PORT GPIOA3_BASE -#define BOOTMGR_LED_PIN_NUM PIN_21 -#define BOOTMGR_SFE_PIN_NUM PIN_18 -#define BOOTMGR_LED_PORT_PIN GPIO_PIN_1 // GPIO25 -#define BOOTMGR_SFE_PORT_PIN GPIO_PIN_4 // GPIO28 +#define BOOTMGR_WAIT_SAFE_MODE_MS 1600 +#define BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS 200 +#define BOOTMGR_SAFE_MODE_ENTER_MS 700 +#define BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS 70 //***************************************************************************** // Exported functions declarations @@ -159,18 +154,12 @@ static void bootmgr_board_init(void) { // Enable the Data Hashing Engine HASH_Init(); - // Enable GPIOA3 Peripheral Clock - MAP_PRCMPeripheralClkEnable(BOOTMGR_PINS_PRCM, PRCM_RUN_MODE_CLK); - - // Configure the bld - MAP_PinTypeGPIO(BOOTMGR_LED_PIN_NUM, PIN_MODE_0, false); - MAP_PinConfigSet(BOOTMGR_LED_PIN_NUM, PIN_STRENGTH_6MA, PIN_TYPE_STD); - MAP_GPIODirModeSet(BOOTMGR_PINS_PORT, BOOTMGR_LED_PORT_PIN, GPIO_DIR_MODE_OUT); + // Init the system led and the system switch + mperror_init0(); - // Configure the safe mode pin - MAP_PinTypeGPIO(BOOTMGR_SFE_PIN_NUM, PIN_MODE_0, false); - MAP_PinConfigSet(BOOTMGR_SFE_PIN_NUM, PIN_STRENGTH_4MA, PIN_TYPE_STD_PU); - MAP_GPIODirModeSet(BOOTMGR_PINS_PORT, BOOTMGR_SFE_PORT_PIN, GPIO_DIR_MODE_IN); + // clear the safe boot request, since we should not trust + // the register's state after reset + mperror_clear_safe_boot(); } //***************************************************************************** @@ -252,13 +241,14 @@ static void bootmgr_load_and_execute (_u8 *image) { //***************************************************************************** static bool safe_mode_boot (void) { _u32 count = 0; - while (!MAP_GPIOPinRead(BOOTMGR_PINS_PORT, BOOTMGR_SFE_PORT_PIN) && - ((BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS * count++) < BOOTMGR_WAIT_SAFE_MODE_MS)) { + while (MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) && + ((BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS * count++) < BOOTMGR_WAIT_SAFE_MODE_MS)) { // toogle the led - MAP_GPIOPinWrite(BOOTMGR_PINS_PORT, BOOTMGR_LED_PORT_PIN, ~MAP_GPIOPinRead(GPIOA3_BASE, BOOTMGR_LED_PORT_PIN)); + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN)); UtilsDelay(UTILS_DELAY_US_TO_COUNT(BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS * 1000)); } - return MAP_GPIOPinRead(BOOTMGR_PINS_PORT, BOOTMGR_SFE_PORT_PIN) ? false : true; + mperror_deinit_sfe_pin(); + return MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) ? true : false; } //***************************************************************************** @@ -268,14 +258,16 @@ static void bootmgr_image_loader(sBootInfo_t *psBootInfo) { _i32 fhandle; if (safe_mode_boot()) { _u32 count = 0; - while ((BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS * count++) > BOOTMGR_SAFE_MODE_ENTER_MS) { + while ((BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS * count++) < BOOTMGR_SAFE_MODE_ENTER_MS) { // toogle the led - MAP_GPIOPinWrite(BOOTMGR_PINS_PORT, BOOTMGR_LED_PORT_PIN, ~MAP_GPIOPinRead(GPIOA3_BASE, BOOTMGR_LED_PORT_PIN)); + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN)); UtilsDelay(UTILS_DELAY_US_TO_COUNT(BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS * 1000)); } psBootInfo->ActiveImg = IMG_ACT_FACTORY; // turn the led off - MAP_GPIOPinWrite(BOOTMGR_PINS_PORT, BOOTMGR_LED_PORT_PIN, 0); + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0); + // request a safe boot to the application + mperror_request_safe_boot(); } // do we have a new update image that needs to be verified? else if ((psBootInfo->ActiveImg == IMG_ACT_UPDATE) && (psBootInfo->Status == IMG_STATUS_CHECK)) { @@ -350,7 +342,7 @@ int main (void) { // could not be loaded, so, loop forever and signal the crash to the user while (true) { // keep the bld on - MAP_GPIOPinWrite(BOOTMGR_PINS_PORT, BOOTMGR_LED_PORT_PIN, BOOTMGR_LED_PORT_PIN); + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN); __asm volatile(" dsb \n" " isb \n" " wfi \n"); diff --git a/cc3200/main.c b/cc3200/main.c index 6f0ce3f1b6..24a42c5247 100644 --- a/cc3200/main.c +++ b/cc3200/main.c @@ -63,7 +63,7 @@ int main (void) { // Initialize the clocks and the interrupt system HAL_SystemInit(); - // Start the watchdog + // Init the watchdog pybwdt_init0(); #ifdef DEBUG diff --git a/cc3200/misc/FreeRTOSHooks.c b/cc3200/misc/FreeRTOSHooks.c index 4268980d6c..9383000b0e 100644 --- a/cc3200/misc/FreeRTOSHooks.c +++ b/cc3200/misc/FreeRTOSHooks.c @@ -35,6 +35,7 @@ #include "pybuart.h" #include "osi.h" #include "pybwdt.h" +#include "mperror.h" //***************************************************************************** @@ -66,15 +67,13 @@ void vApplicationIdleHook (void) void vApplicationMallocFailedHook (void) { #ifdef DEBUG - // Break into the debugger + // break into the debugger __asm volatile ("bkpt #0 \n"); - - printf("\nFATAL ERROR: FreeRTOS malloc failed!\n"); #endif for ( ; ; ) { - // TODO: Blink the BLD + __fatal_error("FreeRTOS malloc failed!"); } } @@ -92,13 +91,11 @@ void vApplicationStackOverflowHook (OsiTaskHandle *pxTask, signed char *pcTaskNa #ifdef DEBUG // Break into the debugger __asm volatile ("bkpt #0 \n"); - - printf("\nFATAL ERROR: Application: %s stack overflow!\n", pcTaskName); #endif for ( ; ; ) { - // TODO: Blink the BLD + __fatal_error("Stack overflow!"); } } diff --git a/cc3200/misc/mperror.c b/cc3200/misc/mperror.c index a615a0f06d..bfb17a2b41 100644 --- a/cc3200/misc/mperror.c +++ b/cc3200/misc/mperror.c @@ -32,12 +32,78 @@ #include "py/mpconfig.h" #include MICROPY_HAL_H #include "py/obj.h" -#include "inc/hw_memmap.h" +#include "hw_ints.h" +#include "hw_types.h" +#include "hw_gpio.h" +#include "hw_memmap.h" +#include "hw_gprcm.h" +#include "hw_common_reg.h" +#include "pin.h" +#include "gpio.h" +#include "rom.h" +#include "rom_map.h" +#include "prcm.h" #include "pybuart.h" #include "utils.h" +#define MPERROR_TOOGLE_MS (200) +#define MPERROR_SIGNAL_ERROR_MS (2000) + +#define MPERROR_SAFE_BOOT_REG_IDX (0) + + +void mperror_init0 (void) { + // Enable SYS GPIOs peripheral clocks + MAP_PRCMPeripheralClkEnable(MICROPY_SYS_LED_PRCM, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); +#ifdef BOOTLOADER + MAP_PRCMPeripheralClkEnable(MICROPY_SAFE_BOOT_PRCM, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); +#endif + + // Configure the bld + MAP_PinTypeGPIO(MICROPY_SYS_LED_PIN_NUM, PIN_MODE_0, false); + MAP_PinConfigSet(MICROPY_SYS_LED_PIN_NUM, PIN_STRENGTH_6MA, PIN_TYPE_STD); + MAP_GPIODirModeSet(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, GPIO_DIR_MODE_OUT); + +#ifdef BOOTLOADER + // Configure the safe boot pin + MAP_PinTypeGPIO(MICROPY_SAFE_BOOT_PIN_NUM, PIN_MODE_0, false); + MAP_PinConfigSet(MICROPY_SAFE_BOOT_PIN_NUM, PIN_STRENGTH_4MA, PIN_TYPE_STD_PD); + MAP_GPIODirModeSet(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN, GPIO_DIR_MODE_IN); +#endif +} + +void mperror_deinit_sfe_pin (void) { + // disable the pull-down + MAP_PinConfigSet(MICROPY_SAFE_BOOT_PIN_NUM, PIN_STRENGTH_4MA, PIN_TYPE_STD); +} + +void mperror_signal_error (void) { + uint32_t count = 0; + while ((MPERROR_TOOGLE_MS * count++) > MPERROR_SIGNAL_ERROR_MS) { + // toogle the led + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN)); + UtilsDelay(UTILS_DELAY_US_TO_COUNT(MPERROR_TOOGLE_MS * 1000)); + } +} + +void mperror_request_safe_boot (void) { + MAP_PRCMOCRRegisterWrite(MPERROR_SAFE_BOOT_REG_IDX, 1); +} + +void mperror_clear_safe_boot (void) { + MAP_PRCMOCRRegisterWrite(MPERROR_SAFE_BOOT_REG_IDX, 0); +} + +// returns the last state of the safe boot request and clears the register +bool mperror_safe_boot_requested (void) { + bool ret = MAP_PRCMOCRRegisterRead(MPERROR_SAFE_BOOT_REG_IDX); + mperror_clear_safe_boot(); + return ret; +} + void NORETURN __fatal_error(const char *msg) { +#ifdef DEBUG if (msg != NULL) { // wait for 20ms UtilsDelay(UTILS_DELAY_US_TO_COUNT(20000)); @@ -45,6 +111,9 @@ void NORETURN __fatal_error(const char *msg) { mp_hal_stdout_tx_str(msg); mp_hal_stdout_tx_str("\r\n"); } +#endif + // signal the crash with the system led + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN); for ( ;; ) {__WFI();} } @@ -63,4 +132,3 @@ void nlr_jump_fail(void *val) { __fatal_error(NULL); #endif } - diff --git a/cc3200/misc/mperror.h b/cc3200/misc/mperror.h index 89a2abe8ef..827d00a9f0 100644 --- a/cc3200/misc/mperror.h +++ b/cc3200/misc/mperror.h @@ -25,8 +25,16 @@ * THE SOFTWARE. */ -#ifdef DEBUG +#ifndef MPERROR_H_ +#define MPERROR_H_ + extern void NORETURN __fatal_error(const char *msg); -#else -#define __fatal_error(...) for ( ;; ) {__WFI();} -#endif + +void mperror_init0 (void); +void mperror_deinit_sfe_pin (void); +void mperror_signal_error (void); +void mperror_request_safe_boot (void); +void mperror_clear_safe_boot (void); +bool mperror_safe_boot_requested (void); + +#endif // MPERROR_H_ diff --git a/cc3200/mods/pybextint.c b/cc3200/mods/pybextint.c index a98dbdba78..c135c4f560 100644 --- a/cc3200/mods/pybextint.c +++ b/cc3200/mods/pybextint.c @@ -46,6 +46,7 @@ #include "mpexception.h" #include "interrupt.h" #include "cc3200_asm.h" +#include "mperror.h" /// \moduleref pyb /// \class ExtInt - configure I/O pins to interrupt on external events @@ -218,8 +219,8 @@ STATIC void ExecuteIntCallback (extint_obj_t *self) { extint_disable(self); // printing an exception here will cause a stack overflow that ends up in a // hard fault so, is better to signal the uncaught (probably non-recoverable) - // exception by blinkg the BLD - // TODO: Blink the BLD + // exception by blinkg the system led + mperror_signal_error(); } gc_unlock(); enable_irq(primsk); diff --git a/cc3200/mptask.c b/cc3200/mptask.c index 90bb7e9a29..733191969c 100644 --- a/cc3200/mptask.c +++ b/cc3200/mptask.c @@ -96,12 +96,20 @@ void TASK_Micropython (void *pvParameters) { // Initialize the garbage collector with the top of our stack uint32_t sp = gc_helper_get_sp(); gc_collect_init (sp); + bool safeboot; FRESULT res; #if MICROPY_HW_ENABLE_RTC pybrtc_init(); #endif +#ifdef DEBUG + mperror_init0(); + safeboot = false; +#else + safeboot = mperror_safe_boot_requested(); +#endif + // Create the simple link spawn task ASSERT (OSI_OK == VStartSimpleLinkSpawnTask(SIMPLELINK_SPAWN_TASK_PRIORITY)); @@ -170,16 +178,19 @@ soft_reset: // reset config variables; they should be set by boot.py MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL; - // run boot.py, if it exists - const char *boot_py = "BOOT.PY"; - res = f_stat(boot_py, NULL); - if (res == FR_OK) { - int ret = pyexec_file(boot_py); - if (ret & PYEXEC_FORCED_EXIT) { - goto soft_reset_exit; - } - if (!ret) { - // TODO: Flash some LEDs + if (!safeboot) { + // run boot.py, if it exists + const char *boot_py = "BOOT.PY"; + res = f_stat(boot_py, NULL); + if (res == FR_OK) { + int ret = pyexec_file(boot_py); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } + if (!ret) { + // flash the system led + mperror_signal_error(); + } } } @@ -189,22 +200,25 @@ soft_reset: // At this point everything is fully configured and initialised. - // Run the main script from the current directory. - if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { - const char *main_py; - if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) { - main_py = "MAIN.PY"; - } else { - main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main)); - } - res = f_stat(main_py, NULL); - if (res == FR_OK) { - int ret = pyexec_file(main_py); - if (ret & PYEXEC_FORCED_EXIT) { - goto soft_reset_exit; + if (!safeboot) { + // Run the main script from the current directory. + if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { + const char *main_py; + if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) { + main_py = "MAIN.PY"; + } else { + main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main)); } - if (!ret) { - // TODO: Flash some LEDs + res = f_stat(main_py, NULL); + if (res == FR_OK) { + int ret = pyexec_file(main_py); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } + if (!ret) { + // flash the system led + mperror_signal_error(); + } } } } diff --git a/cc3200/telnet/telnet.c b/cc3200/telnet/telnet.c index 7d11df913b..31037aed2b 100644 --- a/cc3200/telnet/telnet.c +++ b/cc3200/telnet/telnet.c @@ -36,6 +36,7 @@ #include "debug.h" #include "mpexception.h" #include "serverstask.h" +#include "mperror.h" #include "genhdr/py-version.h" @@ -461,7 +462,8 @@ static bool telnet_send_with_retries (int16_t sd, const void *pBuf, int16_t len) } while (++retries <= TELNET_TX_RETRIES_MAX); } else { - // TODO: blink the BLD + // blink the system led + mperror_signal_error(); } return false;