Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

TWI HardFault_Handler fault on calling any function from TWI handler

I am using NRF52832, twi_sensor_pca10040 example with SHT3X sensor.

I changed slave address to 0X44 and SCL, SDA pin to 27 and 26. TWI TX transfer work fine, in response I am geeting 6 byte of data from SHT3X sensor ( TWI slave address 0x44 ).

In twi_sensor_pca10040 example, from twi_handler() hadler, read_data() function is called. For received data manupulation, I changed code logic in read_data() function, called from twi_handler(). Every time read_data() function called I get HardFault_Handler fault  and board hang.


For testing, I commented read_data() function; then after TWI RX data buffer updates fine with every TWI TX request. I checked it by placeing read buffer in keil debug mode watch window.

Why function call from twi_handler() is giving me HardFault_Handler fault? I am not getting how to debug it?

/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
 *
 * The information contained herein is property of Nordic Semiconductor ASA.
 * Terms and conditions of usage are described in detail in NORDIC
 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
 *
 * Licensees are granted free, non-transferable use of the information. NO
 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
 * the file.
 *
 */

/** @file
 * @defgroup tw_sensor_example main.c
 * @{
 * @ingroup nrf_twi_example
 * @brief TWI Sensor Example main file.
 *
 * This file contains the source code for a sample application using TWI.
 *
 */

#include <stdio.h>
#include "boards.h"
#include "app_util_platform.h"
#include "app_uart.h"
#include "app_error.h"
#include "nrf_drv_twi.h"
#include "nrf_delay.h"

/*Pins to connect shield. */
#define ARDUINO_I2C_SCL_PIN 27
#define ARDUINO_I2C_SDA_PIN 26

/*UART buffer size. */
#define UART_TX_BUF_SIZE 256
#define UART_RX_BUF_SIZE 1

/*Common addresses definition for accelereomter. */
#define MMA7660_ADDR        0x44 //(0x98U >> 1)

#define MMA7660_REG_XOUT    0x00U
#define MMA7660_REG_YOUT    0x01U
#define MMA7660_REG_ZOUT    0x02U
#define MMA7660_REG_TILT    0x03U
#define MMA7660_REG_SRST    0x04U
#define MMA7660_REG_SPCNT   0x05U
#define MMA7660_REG_INTSU   0x06U
#define MMA7660_REG_MODE    0x07U
#define MMA7660_REG_SR      0x08U
#define MMA7660_REG_PDET    0x09U
#define MMA7660_REG_PD      0x0AU

/* Mode for MMA7660. */
#define ACTIVE_MODE 1u

/*Failure flag for reading from accelerometer. */
#define MMA7660_FAILURE_FLAG (1u << 6)

/*Tilt specific bits*/
#define TILT_TAP_MASK (1U << 5)
#define TILT_SHAKE_MASK (1U << 7)

// [max 255, otherwise "int16_t" won't be sufficient to hold the sum
//  of accelerometer samples]
#define NUMBER_OF_SAMPLES 20

/* Define version of GCC. */
#define GCC_VERSION (__GNUC__ * 10000 \
                     + __GNUC_MINOR__ * 100 \
                     + __GNUC_PATCHLEVEL__)

/**
 * @brief Structure for holding sum of samples from accelerometer.
 */
typedef struct
{
    int16_t x;
    int16_t y;
    int16_t z;
} sum_t;
static sum_t m_sum = {0};

/**
 * @brief Union to keep raw and converted data from accelerometer samples at one memory space.
 */
typedef union{
    uint8_t raw;
    int8_t  conv;
}elem_t;

/**
 * @brief Enum for selecting accelerometer orientation.
 */
typedef enum{
    LEFT = 1,
    RIGHT = 2,
    DOWN = 5,
    UP = 6
}accelerometer_orientation_t;

/**
 * @brief Structure for holding samples from accelerometer.
 */
/*typedef struct
{
    elem_t  x;
    elem_t  y;
    elem_t  z;
    uint8_t tilt;
} sample_t;
*/

typedef struct
{
    elem_t  tmsb;
    elem_t  tlsb;
    elem_t  tcrc;
    elem_t  hmsb;
	  elem_t  hlsb;
		elem_t  hcrc;
} sample_t;

#ifdef __GNUC_PATCHLEVEL__
#if GCC_VERSION < 50505
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-braces"           // Hack to GCC 4.9.3 bug. Can be deleted after switch on using GCC 5.0.0
#endif
#endif
/* Buffer for samples. */
static sample_t m_sample_buffer[NUMBER_OF_SAMPLES] = {0};
#ifdef __GNUC_PATCHLEVEL__
#if GCC_VERSION < 50505
#pragma GCC diagnostic pop
#endif
#endif
/* Indicates if reading operation from accelerometer has ended. */
static volatile bool m_xfer_done = true;
/* Indicates if setting mode operation has ended. */
static volatile bool m_set_mode_done = false;
/* TWI instance. */
static const nrf_drv_twi_t m_twi_mma_7660 = NRF_DRV_TWI_INSTANCE(0);

/**
 * @brief Function for casting 6 bit uint to 6 bit int.
 *
 */
__STATIC_INLINE void int_to_uint(int8_t * put, uint8_t data)
{
    if (!(data & MMA7660_FAILURE_FLAG))     //6th bit is failure flag - we cannot read sample
    {
        *put = (int8_t)(data << 2) / 4;
    }
}

/**
 * @brief UART events handler.
 */
static void uart_events_handler(app_uart_evt_t * p_event)
{
    switch (p_event->evt_type)
    {
        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;

        default:
            break;
    }
}


/**
 * @brief UART initialization.
 */
static void uart_config(void)
{
    uint32_t                     err_code;
    const app_uart_comm_params_t comm_params =
    {
        RX_PIN_NUMBER,
        TX_PIN_NUMBER,
        RTS_PIN_NUMBER,
        CTS_PIN_NUMBER,
        APP_UART_FLOW_CONTROL_DISABLED,
        false,
        UART_BAUDRATE_BAUDRATE_Baud38400
    };

    APP_UART_FIFO_INIT(&comm_params,
                       UART_RX_BUF_SIZE,
                       UART_TX_BUF_SIZE,
                       uart_events_handler,
                       APP_IRQ_PRIORITY_LOW,
                       err_code);

    APP_ERROR_CHECK(err_code);
}


/**
 * @brief Function for setting active mode on MMA7660 accelerometer.
 */
void MMA7660_set_mode(void)
{
    ret_code_t err_code;
    /* Writing to MMA7660_REG_MODE "1" enables the accelerometer. */
    uint8_t reg[2] = {MMA7660_REG_MODE, ACTIVE_MODE};

    err_code = nrf_drv_twi_tx(&m_twi_mma_7660, MMA7660_ADDR, reg, sizeof(reg), false);  
    APP_ERROR_CHECK(err_code);
    
    while(m_set_mode_done == false);
}

/**
 * @brief Function for averaging samples from accelerometer.
 */
void read_data(sample_t * p_new_sample)
{
	static double temp, humd;
	static uint8_t sample_idx;
    
  sample_t * p_sample = &m_sample_buffer[sample_idx];
		
	int_to_uint(&p_sample->hmsb.conv, p_new_sample->hmsb.raw);
  int_to_uint(&p_sample->hlsb.conv, p_new_sample->hlsb.raw);
	
	temp = ( ( ( p_new_sample->hmsb.conv << 8 ) + ( p_new_sample->hlsb.conv <<0 ) ) * 0.00267033 )- 45.0;
}

/**
 * @brief TWI events handler.
 */
void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{   
    ret_code_t err_code;
    static sample_t m_sample;
    
    switch(p_event->type)
    {
        case NRF_DRV_TWI_EVT_DONE:
            if ((p_event->type == NRF_DRV_TWI_EVT_DONE) &&
                (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_TX))
            {
               /* if(m_set_mode_done != true)
                {
                    m_set_mode_done  = true;
                    return;
                }*/
                m_xfer_done = false;
                /* Read 4 bytes from the specified address. */
                err_code = nrf_drv_twi_rx(&m_twi_mma_7660, MMA7660_ADDR, (uint8_t*)&m_sample, sizeof(m_sample));
                APP_ERROR_CHECK(err_code);
            }
            else
            {
                read_data(&m_sample);
                m_xfer_done = true;
            }
            break;
        default:
            break;        
    }   
}

/**
 * @brief UART initialization.
 */
void twi_init (void)
{
    ret_code_t err_code;
    
    const nrf_drv_twi_config_t twi_mma_7660_config = {
       .scl                = ARDUINO_SCL_PIN,
       .sda                = ARDUINO_SDA_PIN,
       .frequency          = NRF_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH
    };
    
    err_code = nrf_drv_twi_init(&m_twi_mma_7660, &twi_mma_7660_config, twi_handler, NULL);
    APP_ERROR_CHECK(err_code);
    
    nrf_drv_twi_enable(&m_twi_mma_7660);
}

/**
 * @brief Function for main application entry.
 */
int main(void)
{
    //uart_config();
   // int a = __GNUC__, c = __GNUC_PATCHLEVEL__;
   // printf("\n\rTWI sensor example\r\n");
    twi_init();
    //MMA7660_set_mode(); 
    
    //uint8_t reg = 0;
    ret_code_t err_code;
		uint8_t reg[2] = {0x2C, 0x10};
    
    while(true)
    {
        nrf_delay_ms(100);
        /* Start transaction with a slave with the specified address. */
        do
        {
            __WFE();
        }while(m_xfer_done == false);
        err_code = nrf_drv_twi_tx(&m_twi_mma_7660, MMA7660_ADDR, reg, sizeof(reg), true);
        APP_ERROR_CHECK(err_code);
        m_xfer_done = false;
    }
}

/** @} */

Parents
  • Have you tried stepping through the read_data() function with the debugger to see exactly which lien causes the hard fault? 

    And I don't see that you initialize the sample_idx variable anywhere. It could be that it gets assigned a garbage value and when you try to read m_sample_buffer[sample_idx] it tries to access some part of memory way outside of the array. 

Reply
  • Have you tried stepping through the read_data() function with the debugger to see exactly which lien causes the hard fault? 

    And I don't see that you initialize the sample_idx variable anywhere. It could be that it gets assigned a garbage value and when you try to read m_sample_buffer[sample_idx] it tries to access some part of memory way outside of the array. 

Children
  • Hard fault occure at the point when first line of code of read_data() function is tried to execute. 

    sample_idx is local static variable, so I suppose it automatically will be intilized with 0.

  • I'm unable to reproduce this. I suggest that you implement the HardFault handling library and try to investigate what kind of hardfault you get. 

  • The hardware fault issue is because of the floating point multiplication inside read_data() function as shown in image. Either floating multiplication taking too much time and cause handler to timeout or I am wrongly doing floating point multiplication.  

    MartinBL,

    Can you please tell how should I handle(code) floating poing multiplication in handler function?

  • I don't see any reason why that calculation in it self would cause a hardfault. Can you please post the rest of your code?

  • /* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
     *
     * The information contained herein is property of Nordic Semiconductor ASA.
     * Terms and conditions of usage are described in detail in NORDIC
     * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
     *
     * Licensees are granted free, non-transferable use of the information. NO
     * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
     * the file.
     *
     */
    
    /** @file
     * @defgroup tw_sensor_example main.c
     * @{
     * @ingroup nrf_twi_example
     * @brief TWI Sensor Example main file.
     *
     * This file contains the source code for a sample application using TWI.
     *
     */
    
    #include <stdio.h>
    #include "boards.h"
    #include "app_util_platform.h"
    #include "app_uart.h"
    #include "app_error.h"
    #include "nrf_drv_twi.h"
    #include "nrf_delay.h"
    //#include "hardfault.h"
    #include "math.h"
    
    /*Pins to connect shield. */
    #define ARDUINO_I2C_SCL_PIN 27
    #define ARDUINO_I2C_SDA_PIN 26
    
    /*UART buffer size. */
    #define UART_TX_BUF_SIZE 256
    #define UART_RX_BUF_SIZE 1
    
    /*Common addresses definition for accelereomter. */
    #define SLAVE_ADDR        0x44 //(0x98U >> 1)
    
    // [max 255, otherwise "int16_t" won't be sufficient to hold the sum
    //  of accelerometer samples]
    #define NUMBER_OF_SAMPLES 20
    
    /* Define version of GCC. */
    #define GCC_VERSION (__GNUC__ * 10000 \
                         + __GNUC_MINOR__ * 100 \
                         + __GNUC_PATCHLEVEL__)
    
    typedef struct
    {
        float temp;
        float humd;
    } sensor_val_f;
    static sensor_val_f m_sensor_val_f = {0};
    
    typedef struct
    {
        uint16_t temp;
        uint16_t humd;
    } sensor_val;
    static sensor_val m_sensor_val = {0};
    
    /**
     * @brief Structure for holding sum of samples from accelerometer.
     */
    typedef struct
    {
        uint16_t tmsb;
        uint16_t tlsb;
        uint16_t hmsb;
    	  uint16_t hlsb;
    } sum_t;
    static sum_t m_sum = {0};
    //static sum_t m_sensor_raw_val = {0};
    
    /**
     * @brief Union to keep raw and converted data from accelerometer samples at one memory space.
     */
    typedef union{
        uint8_t raw;
        int8_t  conv;
    }elem_t;
    
    /**
     * @brief Enum for selecting accelerometer orientation.
     */
    typedef enum{
        LEFT = 1,
        RIGHT = 2,
        DOWN = 5,
        UP = 6
    }accelerometer_orientation_t;
    
    typedef struct
    {
        elem_t  tmsb;
        elem_t  tlsb;
        elem_t  tcrc;
        elem_t  hmsb;
    	  elem_t  hlsb;
    		elem_t  hcrc;
    } sample_t;
    
    #ifdef __GNUC_PATCHLEVEL__
    #if GCC_VERSION < 50505
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wmissing-braces"           // Hack to GCC 4.9.3 bug. Can be deleted after switch on using GCC 5.0.0
    #endif
    #endif
    /* Buffer for samples. */
    static sample_t m_sample_buffer[NUMBER_OF_SAMPLES] = {0};
    //static sample_t temp_sample_buffer;
    #ifdef __GNUC_PATCHLEVEL__
    #if GCC_VERSION < 50505
    #pragma GCC diagnostic pop
    #endif
    #endif
    
    /* Indicates if reading operation from accelerometer has ended. */
    static volatile bool m_xfer_done = true;
    /* Indicates if setting mode operation has ended. */
    static volatile bool m_set_mode_done = false;
    /* TWI instance. */
    static const nrf_drv_twi_t m_twi_slave = NRF_DRV_TWI_INSTANCE(0);
    
    void HardFault_Handler(void)
    {
        uint32_t *sp = (uint32_t *) __get_MSP(); // Get stack pointer
        uint32_t ia = sp[12]; // Get instruction address from stack
    
        printf("Hard Fault at address: 0x%08x\r\n", (unsigned int)ia);
        while(1)
            ;
    }
    
    /**
     * @brief Function for averaging samples from accelerometer.
     */
    void read_data(sample_t * p_new_sample)
    {
        /* Variable to count samples. */
        static uint8_t sample_idx;
        
        sample_t * p_sample = &m_sample_buffer[sample_idx];
    
    		m_sensor_val.temp = ( ( p_new_sample->tmsb.raw << 8 ) + ( p_new_sample->tlsb.raw <<0 ) );
    		m_sensor_val.humd = ( ( p_new_sample->tmsb.raw << 8 ) + ( p_new_sample->tlsb.raw <<0 ) );	
    
    		m_sensor_val_f.temp = (m_sensor_val.temp * 0.00267033)- 45;
    		m_sensor_val_f.humd = (m_sensor_val.humd * 0.0015259);
    
    /*    // Subtracting oldest sample
        m_sum.tmsb    -= p_sample->tmsb.raw;
        m_sum.tlsb    -= p_sample->tlsb.raw;
        m_sum.hmsb    -= p_sample->hmsb.raw;
    		m_sum.hlsb		-= p_sample->hlsb.raw;
        
    		p_sample->tmsb.raw = p_new_sample->tmsb.raw;
        p_sample->tlsb.raw = p_new_sample->tlsb.raw;
        p_sample->hmsb.raw = p_new_sample->hmsb.raw;
    		p_sample->hlsb.raw = p_new_sample->hlsb.raw;
    	
        // Adding new sample. This way we always have defined number of samples. 
        m_sum.tmsb    += p_sample->tmsb.raw;
        m_sum.tlsb    += p_sample->tlsb.raw;
        m_sum.hmsb    += p_sample->hmsb.raw;
    		m_sum.hlsb		+= p_sample->hlsb.raw;
    
        ++sample_idx;
        if (sample_idx > NUMBER_OF_SAMPLES)
        {
            sample_idx = 0;
        } else if (sample_idx == NUMBER_OF_SAMPLES) {
    				printf("tmsb: %3d, tlsb: %3d, hmsb: %3d hlsb: %3d \r\n",
                    m_sum.tmsb / NUMBER_OF_SAMPLES,
                    m_sum.tlsb / NUMBER_OF_SAMPLES,
                    m_sum.hmsb / NUMBER_OF_SAMPLES,
                    m_sum.hlsb / NUMBER_OF_SAMPLES);
    				sample_idx = 0;
    		}
    */
    }
    /**
     * @brief TWI events handler.
     */
    //static sample_t m_sample;
    void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
    {   
        ret_code_t err_code;
        static sample_t m_sample;
        
        switch(p_event->type)
        {
            case NRF_DRV_TWI_EVT_DONE:
                if ((p_event->type == NRF_DRV_TWI_EVT_DONE) &&
                    (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_TX))
                {
                   /* if(m_set_mode_done != true)
                    {
                        m_set_mode_done  = true;
                        return;
                    }*/
                    m_xfer_done = false;
                    /* Read 4 bytes from the specified address. */
    							  //nrf_delay_ms(2);
                    err_code = nrf_drv_twi_rx(&m_twi_slave, SLAVE_ADDR, (uint8_t*)&m_sample, sizeof(m_sample));
                    APP_ERROR_CHECK(err_code);
                }
                else
                {
    								read_data(&m_sample);
                    m_xfer_done = true;
                }
                break;
            default:
                break;        
        }   
    }
    
    /**
     * @brief UART initialization.
     */
    void twi_init (void)
    {
        ret_code_t err_code;
        
        const nrf_drv_twi_config_t twi_slave_config = {
           .scl                = ARDUINO_SCL_PIN,
           .sda                = ARDUINO_SDA_PIN,
           .frequency          = NRF_TWI_FREQ_100K,
           .interrupt_priority = APP_IRQ_PRIORITY_HIGH
        };
        
        err_code = nrf_drv_twi_init(&m_twi_slave, &twi_slave_config, twi_handler, NULL);
        APP_ERROR_CHECK(err_code);
        
        nrf_drv_twi_enable(&m_twi_slave);
    }
    
    /**
     * @brief Function for main application entry.
     */
    int main(void)
    {
    	  ret_code_t err_code;
    		uint8_t reg[2] = {0x2C, 0x06};
       // int a = __GNUC__, c = __GNUC_PATCHLEVEL__;
        twi_init();
    
        while(true)
        {
            nrf_delay_ms(100);
            /* Start transaction with a slave with the specified address. */
            do
            {
                __WFE();
            }while(m_xfer_done == false);
    
            err_code = nrf_drv_twi_tx(&m_twi_slave, SLAVE_ADDR, reg, sizeof(reg), true);
            APP_ERROR_CHECK(err_code);
            m_xfer_done = false;
        }
    }
    
    /** @} */
    

    Hardware_FaultHandler is also included in code. If you comment floating point multiplication code line in read_data() function, then there won't be any hardware fault.

    I am using sdk 11.0.0.

Related