diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 910b2f45b4..9c4933808a 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -80,6 +80,19 @@ Reset related functions Activate the bootloader without BOOT\* pins. +.. function:: fault_debug(value) + + Enable or disable hard-fault debugging. A hard-fault is when there is a fatal + error in the underlying system, like an invalid memory access. + + If the `value` argument is `False` then the board will automatically reset if + there is a hard fault. + + If `value` is `True` then, when the board has a hard fault, it will print the + registers and the stack trace, and then cycle the LEDs indefinitely. + + The default value is disabled, i.e. to automatically reset. + Interrupt related functions --------------------------- diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index 53b4335e79..93ae5d40ba 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -38,6 +38,7 @@ #include "lib/oofatfs/ff.h" #include "lib/oofatfs/diskio.h" #include "gccollect.h" +#include "stm32_it.h" #include "irq.h" #include "systick.h" #include "led.h" @@ -64,6 +65,12 @@ #include "extmod/vfs.h" #include "extmod/utime_mphal.h" +STATIC mp_obj_t pyb_fault_debug(mp_obj_t value) { + pyb_hard_fault_debug = mp_obj_is_true(value); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_fault_debug_obj, pyb_fault_debug); + /// \function millis() /// Returns the number of milliseconds since the board was last reset. /// @@ -131,6 +138,8 @@ MP_DECLARE_CONST_FUN_OBJ_KW(pyb_main_obj); // defined in main.c STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_fault_debug), (mp_obj_t)&pyb_fault_debug_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_bootloader), (mp_obj_t)&machine_bootloader_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_hard_reset), (mp_obj_t)&machine_reset_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&machine_info_obj }, diff --git a/stmhal/stm32_it.c b/stmhal/stm32_it.c index 245b2ade4b..4152050a99 100644 --- a/stmhal/stm32_it.c +++ b/stmhal/stm32_it.c @@ -71,6 +71,7 @@ #include STM32_HAL_H #include "py/obj.h" +#include "py/mphal.h" #include "pendsv.h" #include "irq.h" #include "pybthread.h" @@ -95,11 +96,6 @@ extern PCD_HandleTypeDef pcd_hs_handle; // Set the following to 1 to get some more information on the Hard Fault // More information about decoding the fault registers can be found here: // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0646a/Cihdjcfc.html -#define REPORT_HARD_FAULT_REGS 0 - -#if REPORT_HARD_FAULT_REGS - -#include "py/mphal.h" STATIC char *fmt_hex(uint32_t val, char *buf) { const char *hexDig = "0123456789abcdef"; @@ -142,7 +138,13 @@ typedef struct { uint32_t r0, r1, r2, r3, r12, lr, pc, xpsr; } ExceptionRegisters_t; +int pyb_hard_fault_debug = 0; + void HardFault_C_Handler(ExceptionRegisters_t *regs) { + if (!pyb_hard_fault_debug) { + NVIC_SystemReset(); + } + // We need to disable the USB so it doesn't try to write data out on // the VCP and then block indefinitely waiting for the buffer to drain. pyb_usb_flags = 0; @@ -209,14 +211,6 @@ void HardFault_Handler(void) { " b HardFault_C_Handler \n" // Off to C land ); } -#else -void HardFault_Handler(void) { - /* Go to infinite loop when Hard Fault exception occurs */ - while (1) { - __fatal_error("HardFault"); - } -} -#endif // REPORT_HARD_FAULT_REGS /** * @brief This function handles NMI exception. diff --git a/stmhal/stm32_it.h b/stmhal/stm32_it.h index fc61d57be1..a168cda838 100644 --- a/stmhal/stm32_it.h +++ b/stmhal/stm32_it.h @@ -63,6 +63,8 @@ ****************************************************************************** */ +extern int pyb_hard_fault_debug; + void NMI_Handler(void); void HardFault_Handler(void); void MemManage_Handler(void); diff --git a/tests/pyb/pyb1.py b/tests/pyb/pyb1.py index 0087ec0507..00adc85533 100644 --- a/tests/pyb/pyb1.py +++ b/tests/pyb/pyb1.py @@ -40,3 +40,6 @@ pyb.sync() print(len(pyb.unique_id())) pyb.wfi() + +pyb.fault_debug(True) +pyb.fault_debug(False)