This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Error Handling for Soft Device and Application

Hello:

I am looking for the best way to capture the SD and application error/fault(s) so that when the device is restarted, the data can be transmitted to the central device upon request. I am currently using the FDS module in my app where I save device configurations but I am pretty sure the FDS will not be accessible in the app_error_fault_handler function at the time of the error. any code example would be greatly appreciated. I am using SDK 16.0.0 and SD S132 version 7.0.1 with the nRF52832. Your help will be greatly appreciated.

Regards,

  • Hello,

    I think the most reliable way may be to first store the error information to a non-initialized section of RAM and reset the device.  Then on subsequent startup when everything is back to a good state, you load the info from RAM to flash. I actually used this approach in a SES project I had based on SDK 14.2.0 and have included some relevant code snippets from that below. I hope it gives you a better idea of where to start. Also, maybe not relevant for this case, but another advantage worth mentioning is that writing to RAM is fast enough to let you log debug information related to WD timeouts as well.

    /*
        Place variables in non-initialized section of RAM to prevent
        overwrite by startupcode. 
        
        Note: If a bootloader is present - ensure it does not have other
        RAM sections overlapping with ".non_init" 
        
    */
    
    static char error_info[128] __attribute__((section(".non_init")));
    static uint16_t crc __attribute__((section(".non_init")));
    
    /* Should be replaced with SDK hardfault handler library or at least
       be expanded to include psr register */
    
    void process_stack(stack_t * p_stack)
    {
        snprintf(error_info,
                 sizeof(error_info),
                 "HARDFAULT. PC: 0x%x", // Stacked PC from previous frame.
                 p_stack->pc);
    
        crc = crc16_compute(error_info, sizeof(error_info), NULL);
        NVIC_SystemReset();
    }
    
    void HardFault_Handler()
    {
        __ASM volatile("mrs r0, msp                 \n"
                       "ldr r3, =process_stack      \n"
                       "bx r3                       \n");
       
    }
    
    /* Re-declarion of weak handler */
    
    void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
    {
        
        memset(error_info, 0, sizeof(error_info));
        
        switch (id)
        {
            case NRF_FAULT_ID_SD_ASSERT:
                snprintf(error_info,
                         sizeof(error_info),
                         "SD_ASSERT. PC: 0x%x",
                         pc);
                break;
            case NRF_FAULT_ID_APP_MEMACC:
                snprintf(error_info,
                         sizeof(error_info),
                         "APP_MEMACC. 0x%x",
                         pc);
                break;
           
            case NRF_FAULT_ID_SDK_ASSERT:
            {
                assert_info_t * p_info = (assert_info_t *)info;
                snprintf(error_info, 
                         sizeof(error_info), 
                         "SDK_ASSERT, line: %d, file: %s",
                         p_info->line_num,
                         p_info->p_file_name);
                break;
            }
            case NRF_FAULT_ID_SDK_ERROR:
            {
                error_info_t * p_info = (error_info_t *)info;
                snprintf(error_info, 
                         sizeof(error_info), 
                         "SDK_ERROR, line: %d, file: %s, err_code: %d",
                         p_info->line_num,
                         p_info->p_file_name,
                         p_info->err_code);
                break;
            }
        }
    
        crc = crc16_compute(error_info, sizeof(error_info), NULL);
        NVIC_SystemReset();
    }
    
    /* To be called on startup. Checks if new error information is available
       and store it to flash */
       
    void check_error_info()
    {
        uint32_t len;
        
        if ( crc == crc16_compute(error_info, sizeof(error_info), NULL))
        {
            crc = 0;
            len = strlen(error_info);
            if (len > sizeof(error_info)) len = sizeof(error_info);
            //store error information to flash
            persistent_storage_update_error_info(error_info, len);
            NRF_LOG_INFO("%s", error_info);
        }
    }
    
    /* Function to retreive error information from flash */
    void get_error_info(uint32_t * p_data)
    {  
        *p_data = (uint32_t) error_info;
        memset(error_info, 0, sizeof(error_info));
        persistent_storage_get_error_info(error_info, sizeof(error_info));
    }

    Let me know if anything is unclear.

    Regards,

    Vidar

  • Hi Vidar,

    Thank you for taking the time to suggest this. unfortunately, I do not believe this would be a viable option for our device since the device is powered on using a magnetic reed switch. when this switch is enabled, it allows power to flow to the MCU and the MCU enables GPIO pin after 3 seconds to drive a FET to permanently keep the MCU ON. therefore, after a power on reset, the GPIO pin is no longer driving the FET and the MCU and the rest of the device is powered OFF. Unless I can keep this pin enabled; post reset, the MCU has no way to maintain power. please let me know if I may have missed something that would otherwise still enable me to implement your suggestion. If not, is there anything else I can do? Again, your time and effort will be greatly appreciated.

    Regards,

      

  • Ok, I see. Pin configurations are only retained through Wakeup from System OFF resets. So my previous suggestion will not work in your case unless you can use system OFF reset with your current setup.

    Here's a way to access the NVMC peripheral even if the Softdevice is enabled:

    https://devzone.nordicsemi.com/f/nordic-q-a/53248/disable-softdevice-sandboxing-in-fault-handler  

    I've not tried it, but I think you may be able to use fds from your fault handler if you disable the memory protection and swap the fstorage backend to 'nrf_fstorage_nvmc'

Related