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.
This commit is contained in:
danicampora 2015-02-25 22:38:33 +01:00
parent 8a5aee103d
commit 7a074a14ce
10 changed files with 172 additions and 75 deletions

View File

@ -37,3 +37,12 @@
#define MICROPY_STDIO_UART PYB_UART_0 #define MICROPY_STDIO_UART PYB_UART_0
#define MICROPY_STDIO_UART_BAUD 115200 #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

View File

@ -5,6 +5,7 @@ BOOT_INC += -Ibootmgr/sl
BOOT_INC += -Ihal BOOT_INC += -Ihal
BOOT_INC += -Ihal/inc BOOT_INC += -Ihal/inc
BOOT_INC += -I../drivers/cc3100/inc BOOT_INC += -I../drivers/cc3100/inc
BOOT_INC += -Imisc
BOOT_INC += -Imods BOOT_INC += -Imods
BOOT_INC += -Isimplelink BOOT_INC += -Isimplelink
BOOT_INC += -Isimplelink/oslib BOOT_INC += -Isimplelink/oslib
@ -39,6 +40,10 @@ BOOT_CC3100_SRC_C = $(addprefix drivers/cc3100/,\
src/wlan.c \ src/wlan.c \
) )
BOOT_MISC_SRC_C = $(addprefix misc/,\
mperror.c \
)
BOOT_MODS_SRC_C = $(addprefix mods/,\ BOOT_MODS_SRC_C = $(addprefix mods/,\
pybwdt.c \ 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_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 # Add the linker script
LINKER_SCRIPT = bootmgr/bootmgr.lds LINKER_SCRIPT = bootmgr/bootmgr.lds
@ -90,6 +95,7 @@ ifeq ($(BTYPE), debug)
CFLAGS += -DDEBUG=DEBUG CFLAGS += -DDEBUG=DEBUG
# Optimize the stable sources only # Optimize the stable sources only
$(BUILD)/hal/%.o: CFLAGS += -Os $(BUILD)/hal/%.o: CFLAGS += -Os
$(BUILD)/misc/%.o: CFLAGS += -Os
$(BUILD)/simplelink/%.o: CFLAGS += -Os $(BUILD)/simplelink/%.o: CFLAGS += -Os
$(BUILD)/drivers/cc3100/%.o: CFLAGS += -Os $(BUILD)/drivers/cc3100/%.o: CFLAGS += -Os
$(BUILD)/py/%.o: CFLAGS += -Os $(BUILD)/py/%.o: CFLAGS += -Os

View File

@ -26,8 +26,10 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <std.h> #include <std.h>
#include "py/mpconfig.h"
#include MICROPY_HAL_H
#include "hw_ints.h" #include "hw_ints.h"
#include "hw_types.h" #include "hw_types.h"
#include "hw_gpio.h" #include "hw_gpio.h"
@ -50,6 +52,7 @@
#include "cc3200_hal.h" #include "cc3200_hal.h"
#include "debug.h" #include "debug.h"
#include "pybwdt.h" #include "pybwdt.h"
#include "mperror.h"
//***************************************************************************** //*****************************************************************************
@ -60,19 +63,11 @@
#define BOOTMGR_HASH_SIZE 32 #define BOOTMGR_HASH_SIZE 32
#define BOOTMGR_BUFF_SIZE 512 #define BOOTMGR_BUFF_SIZE 512
#define BOOTMGR_WAIT_SAFE_MODE_MS 2000 #define BOOTMGR_WAIT_SAFE_MODE_MS 1600
#define BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS 250 #define BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS 200
#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_SAFE_MODE_ENTER_MS 700
#define BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS 70
//***************************************************************************** //*****************************************************************************
// Exported functions declarations // Exported functions declarations
@ -159,18 +154,12 @@ static void bootmgr_board_init(void) {
// Enable the Data Hashing Engine // Enable the Data Hashing Engine
HASH_Init(); HASH_Init();
// Enable GPIOA3 Peripheral Clock // Init the system led and the system switch
MAP_PRCMPeripheralClkEnable(BOOTMGR_PINS_PRCM, PRCM_RUN_MODE_CLK); mperror_init0();
// Configure the bld // clear the safe boot request, since we should not trust
MAP_PinTypeGPIO(BOOTMGR_LED_PIN_NUM, PIN_MODE_0, false); // the register's state after reset
MAP_PinConfigSet(BOOTMGR_LED_PIN_NUM, PIN_STRENGTH_6MA, PIN_TYPE_STD); mperror_clear_safe_boot();
MAP_GPIODirModeSet(BOOTMGR_PINS_PORT, BOOTMGR_LED_PORT_PIN, GPIO_DIR_MODE_OUT);
// 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);
} }
//***************************************************************************** //*****************************************************************************
@ -252,13 +241,14 @@ static void bootmgr_load_and_execute (_u8 *image) {
//***************************************************************************** //*****************************************************************************
static bool safe_mode_boot (void) { static bool safe_mode_boot (void) {
_u32 count = 0; _u32 count = 0;
while (!MAP_GPIOPinRead(BOOTMGR_PINS_PORT, BOOTMGR_SFE_PORT_PIN) && while (MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) &&
((BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS * count++) < BOOTMGR_WAIT_SAFE_MODE_MS)) { ((BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS * count++) < BOOTMGR_WAIT_SAFE_MODE_MS)) {
// toogle the led // 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)); 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; _i32 fhandle;
if (safe_mode_boot()) { if (safe_mode_boot()) {
_u32 count = 0; _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 // 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)); UtilsDelay(UTILS_DELAY_US_TO_COUNT(BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS * 1000));
} }
psBootInfo->ActiveImg = IMG_ACT_FACTORY; psBootInfo->ActiveImg = IMG_ACT_FACTORY;
// turn the led off // 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? // do we have a new update image that needs to be verified?
else if ((psBootInfo->ActiveImg == IMG_ACT_UPDATE) && (psBootInfo->Status == IMG_STATUS_CHECK)) { 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 // could not be loaded, so, loop forever and signal the crash to the user
while (true) { while (true) {
// keep the bld on // 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" __asm volatile(" dsb \n"
" isb \n" " isb \n"
" wfi \n"); " wfi \n");

View File

@ -63,7 +63,7 @@ int main (void) {
// Initialize the clocks and the interrupt system // Initialize the clocks and the interrupt system
HAL_SystemInit(); HAL_SystemInit();
// Start the watchdog // Init the watchdog
pybwdt_init0(); pybwdt_init0();
#ifdef DEBUG #ifdef DEBUG

View File

@ -35,6 +35,7 @@
#include "pybuart.h" #include "pybuart.h"
#include "osi.h" #include "osi.h"
#include "pybwdt.h" #include "pybwdt.h"
#include "mperror.h"
//***************************************************************************** //*****************************************************************************
@ -66,15 +67,13 @@ void vApplicationIdleHook (void)
void vApplicationMallocFailedHook (void) void vApplicationMallocFailedHook (void)
{ {
#ifdef DEBUG #ifdef DEBUG
// Break into the debugger // break into the debugger
__asm volatile ("bkpt #0 \n"); __asm volatile ("bkpt #0 \n");
printf("\nFATAL ERROR: FreeRTOS malloc failed!\n");
#endif #endif
for ( ; ; ) for ( ; ; )
{ {
// TODO: Blink the BLD __fatal_error("FreeRTOS malloc failed!");
} }
} }
@ -92,13 +91,11 @@ void vApplicationStackOverflowHook (OsiTaskHandle *pxTask, signed char *pcTaskNa
#ifdef DEBUG #ifdef DEBUG
// Break into the debugger // Break into the debugger
__asm volatile ("bkpt #0 \n"); __asm volatile ("bkpt #0 \n");
printf("\nFATAL ERROR: Application: %s stack overflow!\n", pcTaskName);
#endif #endif
for ( ; ; ) for ( ; ; )
{ {
// TODO: Blink the BLD __fatal_error("Stack overflow!");
} }
} }

View File

@ -32,12 +32,78 @@
#include "py/mpconfig.h" #include "py/mpconfig.h"
#include MICROPY_HAL_H #include MICROPY_HAL_H
#include "py/obj.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 "pybuart.h"
#include "utils.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) { void NORETURN __fatal_error(const char *msg) {
#ifdef DEBUG
if (msg != NULL) { if (msg != NULL) {
// wait for 20ms // wait for 20ms
UtilsDelay(UTILS_DELAY_US_TO_COUNT(20000)); 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(msg);
mp_hal_stdout_tx_str("\r\n"); 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();} for ( ;; ) {__WFI();}
} }
@ -63,4 +132,3 @@ void nlr_jump_fail(void *val) {
__fatal_error(NULL); __fatal_error(NULL);
#endif #endif
} }

View File

@ -25,8 +25,16 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifdef DEBUG #ifndef MPERROR_H_
#define MPERROR_H_
extern void NORETURN __fatal_error(const char *msg); extern void NORETURN __fatal_error(const char *msg);
#else
#define __fatal_error(...) for ( ;; ) {__WFI();} void mperror_init0 (void);
#endif 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_

View File

@ -46,6 +46,7 @@
#include "mpexception.h" #include "mpexception.h"
#include "interrupt.h" #include "interrupt.h"
#include "cc3200_asm.h" #include "cc3200_asm.h"
#include "mperror.h"
/// \moduleref pyb /// \moduleref pyb
/// \class ExtInt - configure I/O pins to interrupt on external events /// \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); extint_disable(self);
// printing an exception here will cause a stack overflow that ends up in a // 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) // hard fault so, is better to signal the uncaught (probably non-recoverable)
// exception by blinkg the BLD // exception by blinkg the system led
// TODO: Blink the BLD mperror_signal_error();
} }
gc_unlock(); gc_unlock();
enable_irq(primsk); enable_irq(primsk);

View File

@ -96,12 +96,20 @@ void TASK_Micropython (void *pvParameters) {
// Initialize the garbage collector with the top of our stack // Initialize the garbage collector with the top of our stack
uint32_t sp = gc_helper_get_sp(); uint32_t sp = gc_helper_get_sp();
gc_collect_init (sp); gc_collect_init (sp);
bool safeboot;
FRESULT res; FRESULT res;
#if MICROPY_HW_ENABLE_RTC #if MICROPY_HW_ENABLE_RTC
pybrtc_init(); pybrtc_init();
#endif #endif
#ifdef DEBUG
mperror_init0();
safeboot = false;
#else
safeboot = mperror_safe_boot_requested();
#endif
// Create the simple link spawn task // Create the simple link spawn task
ASSERT (OSI_OK == VStartSimpleLinkSpawnTask(SIMPLELINK_SPAWN_TASK_PRIORITY)); ASSERT (OSI_OK == VStartSimpleLinkSpawnTask(SIMPLELINK_SPAWN_TASK_PRIORITY));
@ -170,6 +178,7 @@ soft_reset:
// reset config variables; they should be set by boot.py // reset config variables; they should be set by boot.py
MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL; MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL;
if (!safeboot) {
// run boot.py, if it exists // run boot.py, if it exists
const char *boot_py = "BOOT.PY"; const char *boot_py = "BOOT.PY";
res = f_stat(boot_py, NULL); res = f_stat(boot_py, NULL);
@ -179,7 +188,9 @@ soft_reset:
goto soft_reset_exit; goto soft_reset_exit;
} }
if (!ret) { if (!ret) {
// TODO: Flash some LEDs // flash the system led
mperror_signal_error();
}
} }
} }
@ -189,6 +200,7 @@ soft_reset:
// At this point everything is fully configured and initialised. // At this point everything is fully configured and initialised.
if (!safeboot) {
// Run the main script from the current directory. // Run the main script from the current directory.
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
const char *main_py; const char *main_py;
@ -204,7 +216,9 @@ soft_reset:
goto soft_reset_exit; goto soft_reset_exit;
} }
if (!ret) { if (!ret) {
// TODO: Flash some LEDs // flash the system led
mperror_signal_error();
}
} }
} }
} }

View File

@ -36,6 +36,7 @@
#include "debug.h" #include "debug.h"
#include "mpexception.h" #include "mpexception.h"
#include "serverstask.h" #include "serverstask.h"
#include "mperror.h"
#include "genhdr/py-version.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); } while (++retries <= TELNET_TX_RETRIES_MAX);
} }
else { else {
// TODO: blink the BLD // blink the system led
mperror_signal_error();
} }
return false; return false;