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

Intermittent device reset in modified ble_app_beacon example

This project is a stripped down version of a product under development. It depends upon being able to change the contents of the advertising data whenever the board (a sensor) detects a new state.  The code as shown generally works but eventually the device resets. This could happen after running for a few minutes or a few days or anywhere in between.

The ADV data is updated by a 1 second timer. I've tried many variations but in the one included here, the time sets a flag, the main loop looks for the flag and then stops advertising, reinits the advertising and starts it back up.

Scouring the forums led me to this patch: app timer expires immediately which also cause spurious resets. But applying it did not change the reset behavior.

I started with this problem in v14.2.0 and upgraded to v15.2.0 in hopes that would help but it did not.

I'm not sure what to try next and am running up against a deadline. Any and all help is appreciated.

The complete project is at the link above. Here is main.c:

#include <stdbool.h>
#include <stdint.h>
#include "nordic_common.h"
#include "bsp.h"
#include "nrf_soc.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "ble_advdata.h"
#include "app_timer.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#define S_PER_DAY  86400	// # of seconds in a day
#define SKY_TX_PIN		14
#define SKY_RX_PIN		15
#define APP_BLE_CONN_CFG_TAG            1                                  /**< A tag identifying the SoftDevice BLE configuration. */

#define NON_CONNECTABLE_ADV_INTERVAL    MSEC_TO_UNITS(100, UNIT_0_625_MS)  /**< The advertising interval for non-connectable advertisement (100 ms). This value can vary between 100ms to 10.24s). */

#define APP_BEACON_INFO_LENGTH          0x17                               /**< Total length of information advertised by the Beacon. */
#define APP_ADV_DATA_LENGTH             0x15                               /**< Length of manufacturer specific data in the advertisement. */
#define APP_DEVICE_TYPE                 0x02                               /**< 0x02 refers to Beacon. */
#define APP_MEASURED_RSSI               0xC3                               /**< The Beacon's measured RSSI at 1 meter distance in dBm. */
#define APP_COMPANY_IDENTIFIER          0x0059                             /**< Company identifier for Nordic Semiconductor ASA. as per www.bluetooth.org. */
#define APP_MAJOR_VALUE                 0x01, 0x02                         /**< Major value used to identify Beacons. */
#define APP_MINOR_VALUE                 0x03, 0x04                         /**< Minor value used to identify Beacons. */
#define APP_BEACON_UUID                 0x01, 0x12, 0x23, 0x34, \
                                        0x45, 0x56, 0x67, 0x78, \
                                        0x89, 0x9a, 0xab, 0xbc, \
                                        0xcd, 0xde, 0xef, 0xf0            /**< Proprietary UUID for Beacon. */

#define DEAD_BEEF                       0xDEADBEEF                         /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */

#define USE_UICR_FOR_MAJ_MIN_VALUES
#if defined(USE_UICR_FOR_MAJ_MIN_VALUES)
#define MAJ_VAL_OFFSET_IN_BEACON_INFO   18                                 /**< Position of the MSB of the Major Value in m_beacon_info array. */
#define UICR_ADDRESS                    0x10001080                         /**< Address of the UICR register used by this example. The major and minor versions to be encoded into the advertising data will be picked up from this location. */
#endif

// Struct representing the data put in the ADV packet
typedef __packed struct {
	uint8_t devType;	    // pos 2 **fixed pos
	uint8_t pktLen;	        // pos 3 **fixed pos
	uint8_t d;			    // pos 4
	uint8_t d0;			    // pos 5
	uint16_t d1;			// pos 6-7 
	uint16_t d2;			// pos 8-9
	uint32_t d3;  			// pos 10-11 

	// internal day clock   17 bits - secs max 86400
	//						pos 14 - 16 bits 0-16
	// time in service		15 bits - hours max 32767
	//						pos 16 - 17 bits 17-31
	uint32_t clock:17;
	uint32_t serviceHours:15;

	uint8_t  macAddress[6];	// pos 18-23 Note: iPhone app does not have access to MAC so we have to put here as user data
	uint8_t  d4;	   		// pos 24  
} payload_t;
payload_t payload;
payload_t* p = &payload;

static ble_gap_adv_params_t m_adv_params;                                  /**< Parameters to be passed to the stack when starting advertising. */
static uint8_t              m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; /**< Advertising handle used to identify an advertising set. */
static uint8_t              m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX];  /**< Buffer for storing an encoded advertising set. */
APP_TIMER_DEF(rtc_tick_timer);
uint32_t secondsOfDay = 0;
bool updateNeeded = false;

/**@brief Struct that contains pointers to the encoded advertising data. */
static ble_gap_adv_data_t m_adv_data =
{
    .adv_data =
    {
        .p_data = m_enc_advdata,
        .len    = BLE_GAP_ADV_SET_DATA_SIZE_MAX
    },
    .scan_rsp_data =
    {
        .p_data = NULL,
        .len    = 0

    }
};

static uint8_t m_beacon_info[APP_BEACON_INFO_LENGTH] =                    /**< Information advertised by the Beacon. */
{
    APP_DEVICE_TYPE,     // Manufacturer specific information. Specifies the device type in this
                         // implementation.
    APP_ADV_DATA_LENGTH, // Manufacturer specific information. Specifies the length of the
                         // manufacturer specific data in this implementation.
    APP_BEACON_UUID,     // 128 bit UUID value.
    APP_MAJOR_VALUE,     // Major arbitrary value that can be used to distinguish between Beacons.
    APP_MINOR_VALUE,     // Minor arbitrary value that can be used to distinguish between Beacons.
    APP_MEASURED_RSSI    // Manufacturer specific information. The Beacon's measured TX power in
                         // this implementation.
};

/**@brief Callback function for asserts in the SoftDevice. */
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
{
    app_error_handler(DEAD_BEEF, line_num, p_file_name);
}

// set up the initial ADV data
void payload_init()
{
	p->devType = 0x02;
	p->pktLen = APP_ADV_DATA_LENGTH;
	p->d = 0;
	p->d0 = 0;
	p->d1 = 0;
	p->d2 = 0;
	p->d3 = 0;
	p->serviceHours = 0;
	p->d4 = 0;

	secondsOfDay = (*(uint32_t *)UICR_ADDRESS);
	p->clock = 0x0001FFFF & secondsOfDay;
	
	ble_gap_addr_t address;
	sd_ble_gap_addr_get( &address);
	
	for( int i = 0; i < 6; i++)
	{
		p->macAddress[i] =  address.addr[i];
	}
}

/**@brief Function for initializing the Advertising functionality.*/
static void advertising_init(void)
{
    uint32_t      err_code;
    ble_advdata_t advdata;
    uint8_t       flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;

    ble_advdata_manuf_data_t manuf_specific_data;

    manuf_specific_data.company_identifier = APP_COMPANY_IDENTIFIER;

#if 0 //defined(USE_UICR_FOR_MAJ_MIN_VALUES)
    uint16_t major_value = ((*(uint32_t *)UICR_ADDRESS) & 0xFFFF0000) >> 16;
    uint16_t minor_value = ((*(uint32_t *)UICR_ADDRESS) & 0x0000FFFF);

    uint8_t index = MAJ_VAL_OFFSET_IN_BEACON_INFO;

    m_beacon_info[index++] = MSB_16(major_value);
    m_beacon_info[index++] = LSB_16(major_value);

    m_beacon_info[index++] = MSB_16(minor_value);
    m_beacon_info[index++] = LSB_16(minor_value);
#endif

	// ignore code above copy payload instead
	memcpy( m_beacon_info, p, sizeof(payload_t));

    manuf_specific_data.data.p_data = (uint8_t *) m_beacon_info;
    manuf_specific_data.data.size   = APP_BEACON_INFO_LENGTH;

    // Build and set advertising data.
    memset(&advdata, 0, sizeof(advdata));

    advdata.name_type             = BLE_ADVDATA_NO_NAME;
    advdata.flags                 = flags;
    advdata.p_manuf_specific_data = &manuf_specific_data;

    // Initialize advertising parameters (used when starting advertising).
    memset(&m_adv_params, 0, sizeof(m_adv_params));

    m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
    m_adv_params.p_peer_addr     = NULL;    // Undirected advertisement.
    m_adv_params.filter_policy   = BLE_GAP_ADV_FP_ANY;
    m_adv_params.interval        = NON_CONNECTABLE_ADV_INTERVAL;
    m_adv_params.duration        = 0;       // Never time out.

    err_code = ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);
    APP_ERROR_CHECK(err_code);

    err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for starting advertising. */
static void advertising_start(void)
{
    ret_code_t err_code;

    err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
    APP_ERROR_CHECK(err_code);

	// this board has no buttons
    //err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
    //APP_ERROR_CHECK(err_code);
}

/**@brief Function for initializing the BLE stack. */
static void ble_stack_init(void)
{
    ret_code_t err_code;

    err_code = nrf_sdh_enable_request();
    APP_ERROR_CHECK(err_code);

    // Configure the BLE stack using the default settings.
    // Fetch the start address of the application RAM.
    uint32_t ram_start = 0;
    err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
    APP_ERROR_CHECK(err_code);

    // Enable BLE stack.
    err_code = nrf_sdh_ble_enable(&ram_start);
    APP_ERROR_CHECK(err_code);
}

/**@brief Function for initializing logging. 
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}
*/
/**@brief Function for initializing LEDs. 
static void leds_init(void)
{
    ret_code_t err_code = bsp_init(BSP_INIT_LEDS, NULL);
    APP_ERROR_CHECK(err_code);
}
*/

/**@brief Function for initializing timers. */
static void timers_init(void)
{
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing power management. */
static void power_management_init(void)
{
    ret_code_t err_code;
    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
}

/**@brief Function for handling the idle state (main loop). */
static void idle_state_handle(void)
{
    if (NRF_LOG_PROCESS() == false)
    {
        nrf_pwr_mgmt_run();
    }
}

// This board has a Power Amplifier - set up radio notification to turn amp on/off
uint32_t radio_notification_init(uint32_t irq_priority, uint8_t notification_type, uint8_t notification_distance)
{
    uint32_t err_code;

	nrf_gpio_cfg_output(SKY_TX_PIN);
	nrf_gpio_cfg_output(SKY_RX_PIN);
	
	// PA sleep mode
	nrf_gpio_pin_clear( SKY_TX_PIN);
	nrf_gpio_pin_clear( SKY_RX_PIN);

	nrf_gpio_cfg_output(11);
	nrf_gpio_pin_clear( 11);  // DBG
	
    err_code = sd_nvic_ClearPendingIRQ(SWI1_IRQn);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    err_code = sd_nvic_SetPriority(SWI1_IRQn, irq_priority);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    err_code = sd_nvic_EnableIRQ(SWI1_IRQn);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    // Configure the event
    return sd_radio_notification_cfg_set(notification_type, notification_distance);
}

/**@brief Software interrupt 1 IRQ Handler, handles radio notification interrupts. */
void SWI1_IRQHandler(bool radio_evt)
{
    if (radio_evt)
    {
		nrf_gpio_pin_toggle( SKY_TX_PIN);  
		nrf_gpio_pin_toggle( 11);  // DBG
   }
}

// Timeout handler for the repeated 1 second timer
static void on_rtc_tick(void * p_context)
{ 
	secondsOfDay++;
	
	if( secondsOfDay >= S_PER_DAY)
	{
		secondsOfDay = 0; // new day
	}
	
	p->clock = 0x0001FFFF & secondsOfDay;

	//nrf_gpio_pin_toggle( 11);  // DBG
	
	// signal main loop to update the ADV data
	updateNeeded = true;
}

/** Function for application main entry. */
int main(void)
{
    // Initialize.
    //log_init();
    timers_init();
    //leds_init();
    power_management_init();
 	app_timer_create(&rtc_tick_timer, APP_TIMER_MODE_REPEATED, on_rtc_tick);
	ble_stack_init();
	radio_notification_init(3, NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, NRF_RADIO_NOTIFICATION_DISTANCE_800US);
	payload_init();
    advertising_init();

    app_timer_start(rtc_tick_timer, APP_TIMER_TICKS(1000), NULL);

    // Start execution.
    //NRF_LOG_INFO("Beacon example started.");
    advertising_start();

    // Enter main loop.
    for (;; )
    {
        idle_state_handle();
		
		if( updateNeeded)
		{
			uint32_t err_code;
			err_code = sd_ble_gap_adv_stop(m_adv_handle);
			APP_ERROR_CHECK(err_code);

			advertising_init();
			
			err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
			APP_ERROR_CHECK(err_code);
			
			updateNeeded = false;
		}
    }
}

Parents Reply Children
  • I monitor the clock value in the broadcast. I have a phone app that monitors several devices and displays  the clock value.  When I program the devices I use the UICR_ADDRESS to set the current time.  If a reset occurs then the time will be incorrect because it gets reinitialized to the programmed value. Here is the state of the current test. If a device is working properly the last contact time will within a minute of the sensor time:

Related