4. Reboot Analysis - BOD

This section provides a brief description of the Brown-out Detection (BOD) mechanism as implemented in the DA1468x family of devices. It describes the tools that can be used to deal with BOD events, and demonstrates a real use case of a BOD event, including all the steps that need to be followed for coping with the issue.

4.1. Introduction

Typically, an MCU includes a built-in Brown-out Detection (BOD) circuit, which monitors supply voltage levels during operation. Usually, BOD circuitry consists of comparators which constantly compare voltage levels against fixed trigger levels. As soon as a voltage level drops below a pre-defined threshold, a Power-on Reset (POR) may take place in order for the system to recover from power failure.

The DA1468x family of devices incorporates a BOD circuit which can be used for monitoring voltage levels derived from various power rails as illustrated in Table 1. Typically, from a software point of view, BOD functionality involves enabling the BOD mechanism and then monitoring a dedicated BOD status register.

Table 1 Power Rails of the SoC Monitored by the BOD Circuitry
Power Rail Description
1V8 power rail This powers the externally connected Flash memory. The BOD mechanism for the rail is enabled by default. As soon as the voltage level drops below the predefined threshold, and given that BOD is enabled for the specific rail, a POR is issued.
1V8P power rail This is intended for powering external devices even when the system is in sleep mode. This power rail is disabled by default. When enabled, the BOD protection for the rail is also enabled by the SDK. As soon as the voltage level drops below a predefined threshold, and given that BOD is enabled for the specific rail, a POR is issued.
VDD power rail This powers the core itself. The BOD protection for the rail is disabled by default. The SDK does not have a macro to enable it. As soon as the voltage level drops below a predefined threshold, and given that BOD is enabled for the specific rail, a POR is issued.
Vsys power rail This powers almost the whole system. The BOD protection for the rail is disabled by default. The SDK does not have a macro to enable it. As soon as the voltage level drops below a predefined threshold, and given that BOD is enabled for the specific rail, a POR is issued.
VBAT power rail This is powered by the battery port. The BOD protection for the rail is enabled by default. As soon as the voltage level drops below a predefined threshold, a system interrupt is issued. This notifies the application that from this point and below, the DC-DC converter is not providing better efficiency than the LDOs. The application should switch the Power Management Unit (PMU) operation to the LDOs.

Note

The BOD status register, that is BOD_STATUS_REG, does not contain valid information for the power rails in which BOD protection is disabled. Also, the contents stored in this register are kept intact during a POR cycle.

4.2. Manually Triggering a BOD

The following real use case demonstrates triggering a BOD event on the 1V8P power rail and identifying that a reset was caused by that BOD event.

  1. Make a copy of the freertos_retarget sample code found in the SDK of the DA1468x family of devices. For information on how to create a new project, see Create a New Project in the Starting a Project tutorial.
  1. Enable the BOD mechanism by setting the following macro in the config/custom_config_qspi.h configuration file:
/* Enable WDOG */
#define dg_configUSE_WDOG                       (1)
  1. Enable the 1V8P power rail by setting the following macro in config/custom_config_qspi.h configuration file. After enabling it, its BOD protection is enabled by the SDK.
/* Power the 1V8P power rail */
#define dg_configPOWER_1V8P                     (1)
  1. The key goal of this exercise is for the developer to determine whether or not a reset was caused by a BOD event. This means that the BOD status should be monitored before the execution of the main application tasks. To do this, follow the steps below:
    1. In startup/system_ARMCM0.c, declare a variable to hold the contents of the BOD_STATUS_REG register.
__RETAINED_UNINIT uint32_t bod_status_reg_val;

  1. In the SystemInit function in startup/system_ARMCM0.c, get the contents of the BOD_STATUS_REG register just before enabling the BOD protection mechanism. After initializing the BOD mechanism, any previously stored information in the status register is invalidated.
/*
 * Initialize UNINIT variables.
 */
sys_tcs_init();

/*
 * Get the BOD status register before enabling the BOD protection
 */
bod_status_reg_val = CRG_TOP->BOD_STATUS_REG & 0x1F;

/*
 * BOD protection
 */
if (dg_configUSE_BOD == 1) {
        /* BOD has already been enabled at this point but it must be reconfigured */
        hw_cpm_configure_bod_protection();
} else {
        hw_cpm_deactivate_bod_protection();
}

  1. In main.c, add the following variables:
/* This is an external variable declared in system_ARMCM0.c source file */
extern uint32_t bod_status_reg_val;

/*
 * This variable should be of type [volatile] since it will be reassigned
 * during the debugging session.
 */
static volatile bool bod_1v8p_flag = true;

  1. In the system_init function in main.c, add the code that checks whether or not the system recovers from a BOD event on the 1V8P power rail:
/* Set the desired sleep mode. */
pm_set_sleep_mode(pm_mode_extended_sleep);

/*
 * Check whether or not the system recovers after a BOD event
 */
if (!(bod_status_reg_val & REG_MSK(CRG_TOP, BOD_STATUS_REG, BOD_1V8_PA_LOW))) {
        /*
         * If yes, print a message on the serial console and then add an infinite
         * loop so that the debugger can catch it! Then manually unblock!
         */
        printf("\n\n\rSystem has just recovered from a POR due to voltage drop on 1V8P power rail\n\n\r");
        while(bod_1v8p_flag) {

                ;
        }
}

/* Start main task here (text menu available via UART1 to control application) */
OS_TASK_CREATE( "Template",            /* The text name assigned to the task, for
  1. Increase the stack size reserved for the system_init initialization function by at least 100 bytes.
/* Start the two tasks as described in the comments at the top of this file. */
status = OS_TASK_CREATE("SysInit",              /* The text name assigned to the task, for
                                                   debug only; not used by the kernel. */
                system_init,                    /* The System Initialization task. */
                ( void * ) 0,                   /* The parameter passed to the task. */
                (configMINIMAL_STACK_SIZE * OS_STACK_WORD_SIZE + 100),
                                                /* The number of bytes to allocate to the
                                                   stack of the task. */
                OS_TASK_PRIORITY_HIGHEST,       /* The priority assigned to the task. */
                xHandle );                      /* The task handle */
OS_ASSERT(status == OS_TASK_CREATE_SUCCESS);
  1. Build the project either in Debug or Release mode and burn the generated image in the chip.
  2. Press the K2 button on Pro DevKit. This step starts the chip executing its firmware.
  3. Before triggering a voltage drop on 1V8P power rail, monitor the status of the BOD mechanism. To do this:
    1. Start a debugging session by selecting the ATTACH mode and then selecting Suspend to halt MCU operation.
    2. Select the EmbSys Registers window and navigate to BOD_CTRL2_REG and BOD_STATUS_REG registers under the CRG_TOP folder. Double-click on each register name to display the contents.
'Inspecting BOD related registers'

Fig. 18 Inspecting BOD Related Registers

  1. Select Terminate to terminate the current debugging session.
  2. Open a serial terminal. For more information on configuring a serial terminal, see Prepare the System in the Starting a Project tutorial.
  1. Shortcut the 1V8P power rail using a low value resistor (for example, 100 Ohm). The shortcut can also be done without using a resistor but it is not recommended as this may damage the chip.
'DA1468x Pro DevKit'

Fig. 19 DA1468x Pro DevKit

4.3. Dealing with a BOD Event

  1. Following the shortcut on the 1V8P power rail, the code should be in an infinite loop. To verify this, a new debugging session should be performed by selecting ATTACH mode and then Suspend to halt the MCU operation.
'Dealing With a BOD Event'

Fig. 20 Dealing with a BOD Event

  1. Verify that the BOD_1V8_PA_LOW bit in the BOD_STATUS_REG register was set to zero by monitoring the bod_status_reg_val variable. To do this, in the Expressions window (1), click Add new expression (2) and write the variable name of interest (3).
'Inspecting Variables and Expressions using the Expressions window'

Fig. 21 Inspecting Variables and Expressions using the Expressions Window

Note

A voltage drop on a power line may also affect other power rails of the system.

  1. The default presentation format for all variables is decimal. To change it, right-click on the variable name in the Expressions window (1), select Number Format (2), and then select the preferred format (3).
'Changing Number Presentation Formats'

Fig. 22 Changing Number Presentation Formats

  1. A debugging message, indicating that BOD mechanism trigged a POR cycle, should also be displayed on the serial console. This message could also be sent through BLE functionality using a custom BLE Profile.
'Printing Debugging Messages on the Serial Console Upon a BOD Event'

Fig. 23 Printing Debugging Messages on the Serial Console upon a BOD Event

  1. Normally, code execution will not stick in infinite loops, we only do this to verify various parameters related to a BOD event. To resume code execution the bod_1v8p_flag variable should be set to false. To do this, in the Expressions window (1), click on Add new expression (2) and enter the variable name of interest (3).
'Inspecting Variables and Expressions Using the Expressions Window'

Fig. 24 Inspecting Variables and Expressions using the Expressions window

  1. Click on the Value cell, in our case that is true (4) and change the value to false. The variable shoud now contain the newly declared value.
'Modifying Variable Contents While in Debugging Session'

Fig. 25 Modifying Variable Contents while in Debugging Session

Note

The volatile keyword indicates that a value may change between different accesses, even if it does not appear to be modified. In other words, it tells the compiler that the value of the variable may change at any time thus, not performing optimizations for that object. The system always reads the current value of a volatile object from the memory location rather than keeping its value in temporary core registers at the point it requested, even if a previous instruction asked for a value from the same object.

  1. Select Terminate to terminate the current debugging session. The code should resume its execution. To verify this, monitor the serial console. The # character should be printed out every 1 second.