How to store stack info into flash for DA14585 when hard-fault or NMI happens?

Hello, is there a way to get contents in stack and store them into flash when Hard-fault or NMI happen? If it can't write flash in the situation, is there a mechanism to copy them into a block of SRAM which can be kept even when system has been re-started?

  • Hi Jerry,

    Thank you for posting your question on our Online Engineering Community.
    What data exactly are you interested in saving? In which scenario are you facing a Hard Fault or NMI? 
    The RAM cannot be retained if a power off has occurred. Only the data on the SPI Flash will be saved. 
    In order to save data in the SPI Flash please follow our Tutorial here:
    DA145XX Tutorial SDK6 Peripheral Drivers — DA145XX Tutorial SDK peripherals (renesas.com)
    Chapter 5. SPI Flash.

    Kind Regards,
    OV_Renesas

  • Hi OV_renesas,

    Thank you for your quick reply. I want to save stack info into flash when Hard Fault happens, so I can analyze the info to find out which function caused it.

    In function HardFault_HandlerC, I called the interfaces in spi_flash.c to do erase and write operations, but it didn't work, and nothing has been written into flash. These interfaces have already confirmed to work properly in normal process, so I doubt something needs to be taken care of before calling them in  HardFault_HandlerC. Could you please give me some instructions about it?

    Thanks,

    Jerry

  • Another question: is there a way to output some log from UART2 when Hard Fault happens?  I've tried to write some code like dbg_prod_output, but it seemed to not work.

  • Hi Jerry,

    Thank you for the reply.
    When you receive a Hard Fault error the device crashes and you are not going to be able to save the data into the Flash or print them via UART.
    Please refer on our SDK6 Debugging Tutorial: Tutorial Dialog SDK 6.0.x Debugging — SDK6 Debugging Tutorial (renesas.com)
    It shows the steps you have to make to understand the Hard Fault Error.
    If you want you can share your code implementation here, so we can take a look on why you are getting this Hard Fault Error.

    Kind Regards,
    OV_Renesas

  • Hi OV_Renesas,

    Thank you for your reply and info, but that can't solve my problem. The Hard Fault happened on my DA14585 device can't be reproduced easily. It needs lots of samples and several days, and then it has the chance to occur on only one device, so it's not easy to connect J-link to catch it. I'm sure DA14683 can have a mechanism to store stack info in a block of RAM, and the contents in the RAM can be kept unchanged during reset. Can DA14585 support the same mechanism as DA14683?

    Thanks,

    Jerry

  • Hi Jerry,

    Thank you for the reply and the clarifications.
    The SDK6 does not support the same mechanism as DA14683.
    However you can print out the Registers for HardFault Errors or NMI so you can see what caused the issue.
    In order to do that, you will have to do the following:
    On da1458x_config_advanced.h file:

    /****************************************************************************************************************/
    /* Output the Hardfault arguments to serial/UART interface.                                                     */
    /****************************************************************************************************************/
    #define CFG_PRODUCTION_DEBUG_OUTPUT

    On da1458x_config_basic.h file:

    #undef CFG_DEVELOPMENT_DEBUG
    
    #undef CFG_PRINTF
    
    #define CFG_UART1_SDK

    On user_periph_setup.h file add the following:
    /// Divider for 115200 bits/s
    #define UART_BAUDRATE_115K2         8
    #define UART_FRAC_BAUDRATE_115K2   11
    
    /// Character format
    enum
    {
        /// char format 5
        UART_CHARFORMAT_5 = 0,
        /// char format 6
        UART_CHARFORMAT_6 = 1,
        /// char format 7
        UART_CHARFORMAT_7 = 2,
        /// char format 8
        UART_CHARFORMAT_8 = 3
    };

    On hardfault_handler.c file you should change:
        // Switch to XTAL16 clock, if necessary
        if (GetBits16(CLK_CTRL_REG, RUNNING_AT_XTAL16M) == 0)
        {
            while ( !GetBits16(SYS_STAT_REG, XTAL16_SETTLED) ); // this takes some mili seconds
    
            SetBits16(CLK_CTRL_REG, SYS_CLK_SEL, 0);    // select XTAL 16MHz
        }

    into this:
    	if(GetBits16(CLK_CTRL_REG, RUNNING_AT_XTAL32M) == 0)
    		{
    			 while ( !GetBits16(SYS_STAT_REG, XTAL32M_SETTLED) ); // this takes some mili seconds
    		}

    Please also refer here, regarding the changes on hardfault_handler.c file: Build error with PRODUCTION_DEBUG_OUTPUT enabled — SDK6 Known Limitations List 0.1 documentation (renesas.com)
    Keep in mind, that for UART1 we are going to use the P2_5 pin which is declared on ueser_periph_setup.h file:
    /***************************************************************************************/
    /* Production debug output configuration                                               */
    /***************************************************************************************/
    #if PRODUCTION_DEBUG_OUTPUT
    #if defined (__DA14531__)
        #define PRODUCTION_DEBUG_PORT   GPIO_PORT_0
        #define PRODUCTION_DEBUG_PIN    GPIO_PIN_11
    #else
        #define PRODUCTION_DEBUG_PORT   GPIO_PORT_2
        #define PRODUCTION_DEBUG_PIN    GPIO_PIN_5
    #endif
    #endif

    You can change P2_5 to any pin that suits you.
    I worked on the ble_app_peripheral project, and in order to create a Hard Fault error I added the following line on the user_app_init custom callback function:
    		*(uint32_t*)0x07F00000 = 0x90;

    When I compile and run the project, I am able to see on my terminal:


    Unfortunately, there is not a mechanism to save this data into the SPI Flash. 

    Kind Regards,
    OV_Renesas

  • It's bad that there isn't a mechanism to save data into flash, but I'll try your demo to output some info from UART. Thank you for sharing the code. Can baudrate 921600 be used? It would be better to know divider values for 921600.

  • Hi Jerry,

    Thank you for the reply.
    Yes, baudrate 921600 can be used. 

    /// Divider for 921600 bits/s
    #define UART_BAUDRATE_921K6         1
    #define UART_FRAC_BAUDRATE_921K6    1

    For all the available baudrate options you can find the defines on the prod_test example on user_periph_setup.h file:
    /// Divider for 1000000 bits/s
    #define UART_BAUDRATE_1M            1
    #define UART_FRAC_BAUDRATE_1M       0
    
    /// Divider for 921600 bits/s
    #define UART_BAUDRATE_921K6         1
    #define UART_FRAC_BAUDRATE_921K6    1
    
    /// Divider for 500000 bits/s
    #define UART_BAUDRATE_500K          2
    #define UART_FRAC_BAUDRATE_500K     0
    
    /// Divider for 460800 bits/s
    #define UART_BAUDRATE_460K8         2
    #define UART_FRAC_BAUDRATE_460K8    3
    
    /// Divider for 230400 bits/s
    #define UART_BAUDRATE_230K4         4
    #define UART_FRAC_BAUDRATE_230K4    5
    
    /// Divider for 115200 bits/s
    #define UART_BAUDRATE_115K2         8
    #define UART_FRAC_BAUDRATE_115K2   11
    
    /// Divider for 57600 bits/s
    #define UART_BAUDRATE_57K6          17
    #define UART_FRAC_BAUDRATE_57K6     6
    
    /// Divider for 38400 bits/s
    #define UART_BAUDRATE_38K4          26
    #define UART_FRAC_BAUDRATE_38K4     1
    
    /// Divider for 28800 bits/s
    #define UART_BAUDRATE_28K8          34
    #define UART_FRAC_BAUDRATE_28K8     12
    
    /// Divider for 19200 bits/s
    #define UART_BAUDRATE_19K2          52
    #define UART_FRAC_BAUDRATE_19K2     1
    
    /// Divider for 14400 bits/s
    #define UART_BAUDRATE_14K4          69
    #define UART_FRAC_BAUDRATE_14K4     7
    
    /// Divider for 9600 bits/s
    #define UART_BAUDRATE_9K6           104
    #define UART_FRAC_BAUDRATE_9K6      3
    
    /// Divider for 2400 bits/s
    #define UART_BAUDRATE_2K4           416
    #define UART_FRAC_BAUDRATE_2K4      11
    
    /// Character format
    enum
    {
        /// char format 5
        UART_CHARFORMAT_5 = 0,
        /// char format 6
        UART_CHARFORMAT_6 = 1,
        /// char format 7
        UART_CHARFORMAT_7 = 2,
        /// char format 8
        UART_CHARFORMAT_8 = 3
    };
    


    Kind Regards,
    OV_Renesas