stmhal: Add pyb.fault_debug() function, to control hard-fault behaviour.

This new function controls what happens on a hard-fault:
- debugging disabled: board will do a reset
- debugging enabled: board will print registers and stack and flash LEDs

The default is disabled, ie to do a reset.  This is different to previous
behaviour which flashed the LEDs and waited indefinitely.
This commit is contained in:
Damien George 2017-02-06 13:19:52 +11:00
parent bffda45154
commit 27c149efe0
5 changed files with 34 additions and 13 deletions

View File

@ -80,6 +80,19 @@ Reset related functions
Activate the bootloader without BOOT\* pins. 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 Interrupt related functions
--------------------------- ---------------------------

View File

@ -38,6 +38,7 @@
#include "lib/oofatfs/ff.h" #include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h" #include "lib/oofatfs/diskio.h"
#include "gccollect.h" #include "gccollect.h"
#include "stm32_it.h"
#include "irq.h" #include "irq.h"
#include "systick.h" #include "systick.h"
#include "led.h" #include "led.h"
@ -64,6 +65,12 @@
#include "extmod/vfs.h" #include "extmod/vfs.h"
#include "extmod/utime_mphal.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() /// \function millis()
/// Returns the number of milliseconds since the board was last reset. /// 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[] = { 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___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_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_hard_reset), (mp_obj_t)&machine_reset_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&machine_info_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&machine_info_obj },

View File

@ -71,6 +71,7 @@
#include STM32_HAL_H #include STM32_HAL_H
#include "py/obj.h" #include "py/obj.h"
#include "py/mphal.h"
#include "pendsv.h" #include "pendsv.h"
#include "irq.h" #include "irq.h"
#include "pybthread.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 // 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: // 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 // 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) { STATIC char *fmt_hex(uint32_t val, char *buf) {
const char *hexDig = "0123456789abcdef"; const char *hexDig = "0123456789abcdef";
@ -142,7 +138,13 @@ typedef struct {
uint32_t r0, r1, r2, r3, r12, lr, pc, xpsr; uint32_t r0, r1, r2, r3, r12, lr, pc, xpsr;
} ExceptionRegisters_t; } ExceptionRegisters_t;
int pyb_hard_fault_debug = 0;
void HardFault_C_Handler(ExceptionRegisters_t *regs) { 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 // 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. // the VCP and then block indefinitely waiting for the buffer to drain.
pyb_usb_flags = 0; pyb_usb_flags = 0;
@ -209,14 +211,6 @@ void HardFault_Handler(void) {
" b HardFault_C_Handler \n" // Off to C land " 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. * @brief This function handles NMI exception.

View File

@ -63,6 +63,8 @@
****************************************************************************** ******************************************************************************
*/ */
extern int pyb_hard_fault_debug;
void NMI_Handler(void); void NMI_Handler(void);
void HardFault_Handler(void); void HardFault_Handler(void);
void MemManage_Handler(void); void MemManage_Handler(void);

View File

@ -40,3 +40,6 @@ pyb.sync()
print(len(pyb.unique_id())) print(len(pyb.unique_id()))
pyb.wfi() pyb.wfi()
pyb.fault_debug(True)
pyb.fault_debug(False)