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

Problems with flash erase/write while using SD S340

Hi,

I'm trying to write/read from flash in my app. Reading/writing works until I either:

a) run ant_hrm_rx_start() - then after the call to nrf_fstorage_erase I get "00> <info> app: --> Event received: ERROR while executing an fstorage operation." in the log, or

b) connect to my device via bluetooth and try to write some data via service - then the application hangs on wait_for_flash_ready(&fstorage);

Before any of these two, I can read/write/erase without problems, even after I initiate my softdevice.

This is how I init my flash: 

nrf_fstorage_api_t* p_fs_api;
p_fs_api = &nrf_fstorage_sd;
err_code = nrf_fstorage_init(&fstorage, p_fs_api, NULL);
APP_ERROR_CHECK(err_code);

I also have FDS_ENABLED 1 and  #define FDS_BACKEND 2.

Below is my messy main.c file. From BLE service I'm calling the function write_config_ble (see main below for declaration)

/**
 * Copyright (c) 2013 - 2020, Nordic Semiconductor ASA
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
/** @file
 *
 * @defgroup ble_sdk_app_ant_hrs_main main.c
 * @{
 * @ingroup ble_sdk_app_ant_hrs
 * @brief HRM sample application using both BLE and ANT.
 *
 * The application uses the BLE Heart Rate Service (and also the Device Information
 * services), and the ANT HRM RX profile.
 *
 * It will open a receive channel which will connect to an ANT HRM TX profile device when the
 * application starts. The received data will be propagated to a BLE central through the
 * BLE Heart Rate Service.
 *
 * The ANT HRM TX profile device simulator SDK application
 * (Board\pca10003\ant\ant_hrm\hrm_tx_buttons) can be used as a peer ANT device. By changing
 * ANT_HRMRX_NETWORK_KEY to the ANT+ Network Key, the application will instead be able to connect to
 * an ANT heart rate belt.
 *
 * @note The ANT+ Network Key is available for ANT+ Adopters. Please refer to
 *       http://thisisant.com to become an ANT+ Adopter and access the key.
 *
 * @note This application is based on the BLE Heart Rate Service Sample Application
 *       (Board\nrf6310\ble\ble_app_hrs). Please refer to this application for additional
 *       documentation.
 */

#include <stdint.h>
#include <string.h>
#include "nordic_common.h"
#include "app_error.h"
#include "app_timer.h"
#include "ble.h"
#include "ble_hci.h"
#include "ble_conn_state.h"
#include "ble_conn_params.h"
#include "ble_srv_common.h"
#include "ble_advdata.h"
#include "ble_hrs.h"
#include "nrf_drv_timer.h"
#include "bsp.h"
#include "fds.h"
#include "peer_manager.h"
#include "peer_manager_handler.h"
#include "sensorsim.h"
#include "nrf_ble_gatt.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_sdh_ant.h"
#include "nrf_sdh_soc.h"
#include "nrf_ble_qwr.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_fstorage_sd.h"

#include "ant_error.h"
#include "ant_key_manager.h"
#include "ant_hrm.h"
#include "ant_parameters.h"
#include "ant_interface.h"
#include "nrf_delay.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_drv_gpiote.h"
#include "my_common.h"
#include "math.h"

// ######################################################################################################
// ################### parameters dependent on the user device and user HR/preference ###################
// ######################################################################################################
uint8_t fan_hi = 0; // in new approach we store the index of array corresponding to the delay above
										// fan_hi is the index for high speed of the fan (for upper_hr)
uint8_t fan_lo = 159; // this variable is the index of the "segments" array with delays corresponding to the low speed (for lower_hr)
uint8_t lower_hr = 70; // this value of HR will be used as a value above which we will start the fan
uint8_t upper_hr = 200; // this is the value of HR above which we will set the delay to minimum = give max power to fan
uint16_t ant_id = 0; // this ant id of hrm should be used; if zero -> find the nearest hr belt instead (default)
// ######################################################################################################

const nrf_drv_timer_t TRIAC_TIMER = NRF_DRV_TIMER_INSTANCE(1);
uint32_t flash_addr;
uint8_t global_hr = 50;
#define PIN_IN BSP_BUTTON_0 // 15 on nrf51 // pin for zero crossing detection
#define PIN_OUT BSP_LED_0 // 20 on nrf51 // pin for contronling the triac
#define uS_IN_PI 10000
#define M_PI 3.14159265358979323846
#define MULTIPLIER uS_IN_PI/M_PI
double segments[SEGMENTS_NO];
double scale;
bool triac_on;
bool turn_off;
uint32_t global_delay = 0; // how long shall we wait till firing the triac
bool test;
uint32_t test_delay;
ret_code_t ant_reinit(ant_channel_config_t const * p_config);

#define WAKEUP_BUTTON_ID                0                                            /**< Button used to wake up the application. */
#define BOND_DELETE_ALL_BUTTON_ID       1                                            /**< Button used for deleting all bonded centrals during startup. */

#define DEVICE_NAME                     "HRM Fan #3"                                 /**< Name of device. Will be included in the advertising data. */
//#define MANUFACTURER_NAME               "NordicSemiconductor"                        /**< Manufacturer. Will be passed to Device Information Service. */
#define APP_ADV_INTERVAL                40                                           /**< The advertising interval (in units of 0.625 ms. This value corresponds to 25 ms). */
#define APP_ADV_DURATION                18000                                        /**< The advertising duration in units of seconds. */

#define APP_BLE_CONN_CFG_TAG            1                                            /**< A tag that refers to the BLE stack configuration we set with @ref sd_ble_cfg_set. Default tag is @ref BLE_CONN_CFG_TAG_DEFAULT. */

#define IS_SRVC_CHANGED_CHARACT_PRESENT 0                                            /**< Whether or not to include the service_changed characteristic. If not enabled, the server's database cannot be changed for the lifetime of the device */

#define SECOND_1_25_MS_UNITS            800                                          /**< Definition of 1 second, when 1 unit is 1.25 ms. */
#define SECOND_10_MS_UNITS              100                                          /**< Definition of 1 second, when 1 unit is 10 ms. */
#define MIN_CONN_INTERVAL               (SECOND_1_25_MS_UNITS / 10)                  /**< Minimum acceptable connection interval (0.5 seconds), Connection interval uses 1.25 ms units. */
#define MAX_CONN_INTERVAL               (SECOND_1_25_MS_UNITS / 5)                       /**< Maximum acceptable connection interval (1 second), Connection interval uses 1.25 ms units. */
#define SLAVE_LATENCY                   0                                            /**< Slave latency. */
#define CONN_SUP_TIMEOUT                (4 * SECOND_10_MS_UNITS)                     /**< Connection supervisory timeout (4 seconds), Supervision Timeout uses 10 ms units. */

#define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(5000)                        /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
#define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000)                       /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
#define MAX_CONN_PARAMS_UPDATE_COUNT    3                                            /**< Number of attempts before giving up the connection parameter negotiation. */

#define SEC_PARAM_TIMEOUT               30                                           /**< Timeout for Pairing Request or Security Request (in seconds). */
#define SEC_PARAM_BOND                  1                                            /**< Perform bonding. */
#define SEC_PARAM_MITM                  0                                            /**< Man In The Middle protection not required. */
#define SEC_PARAM_IO_CAPABILITIES       BLE_GAP_IO_CAPS_NONE                         /**< No I/O capabilities. */
#define SEC_PARAM_OOB                   0                                            /**< Out Of Band data not available. */
#define SEC_PARAM_MIN_KEY_SIZE          7                                            /**< Minimum encryption key size. */
#define SEC_PARAM_MAX_KEY_SIZE          16                                           /**< Maximum encryption key size. */

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

#define ANT_HRMRX_ANT_CHANNEL           0                                            /**< Default ANT Channel. */
#define ANT_HRMRX_DEVICE_NUMBER         0                                            /**< Device Number. */
#define ANT_HRMRX_TRANS_TYPE            0                                            /**< Transmission Type. */
#define ANTPLUS_NETWORK_NUMBER          0                                            /**< Network number. */

static volatile uint16_t                m_conn_handle = BLE_CONN_HANDLE_INVALID;     /**< Handle of the current connection. */
static uint8_t                          m_adv_handle;                                /**< Advertising handle. */
BLE_HRS_DEF(m_hrs);                                                                  /**< Heart rate service instance. */
NRF_BLE_QWR_DEF(m_qwr);                                                              /**< Context for the Queued Write module.*/
NRF_BLE_GATT_DEF(m_gatt);                                                            /**< GATT module instance. */

ant_hrm_profile_t m_ant_hrm;                                                         /**< ANT HRM profile instance. */
HRM_DISP_CHANNEL_CONFIG_DEF(m_ant_hrm,
                            ANT_HRMRX_ANT_CHANNEL,
                            ANT_HRMRX_TRANS_TYPE,
                            ANT_HRMRX_DEVICE_NUMBER,
                            ANTPLUS_NETWORK_NUMBER,
                            HRM_MSG_PERIOD_4Hz);
NRF_SDH_ANT_OBSERVER(m_ant_hrm_observer, ANT_HRM_ANT_OBSERVER_PRIO, ant_hrm_disp_evt_handler, &m_ant_hrm);

static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt);
NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) =
{
    /* Set a handler for fstorage events. */
    .evt_handler = fstorage_evt_handler,

    /* These below are the boundaries of the flash space assigned to this instance of fstorage.
     * You must set these manually, even at runtime, before nrf_fstorage_init() is called.
     * The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the
     * last page of flash available to write data. */
    .start_addr = 0x0FF000,//0x3e000,
    .end_addr   = 0x100000,//0x3ffff,
};

void divide_sinewave(int pieces)
{
		double u;
		float area;
		double offset;
		float two = 2.0;
		// area of the whole half-sine = 2, so area of each piece = 2/pieces 
		area = two / (float)pieces;
	
		//NRF_LOG_INFO("area:" NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(area));
		u = area;
		for(int t = 0; t < pieces; t ++)
		{
				segments[t] = acos(1 - u) * MULTIPLIER; // multipy value in radians to match the range of 0-10ms (10k us)
				
				// next 2 lines - shift values to the 0 offset - minimum delay works, maximum won't due to timer inacuracies and incudctive load influence
				if(t == 0) offset = segments[t];
				segments[t] -=  offset;
				
				u += area;
				//if(t<10 || t>190) app_trace_log("segments[%i]=%lf\n", t, segments[t]);
		}		
}

void calculate_scale(int pieces)
{
		// we store the index of "segments" array instead of delay in ms
		scale = (float)(fan_lo - fan_hi) / (float)(upper_hr - lower_hr);
}
void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
		//NRF_LOG_INFO("button pressed\n");
    if(triac_on) 
		{
				if(global_delay > 0) 
				{
						turn_off = false;
						nrf_drv_gpiote_out_clear(PIN_OUT);
						nrf_drv_timer_extended_compare(&TRIAC_TIMER, NRF_TIMER_CC_CHANNEL1, global_delay, NRF_TIMER_SHORT_COMPARE1_STOP_MASK, true);
						nrf_drv_timer_enable(&TRIAC_TIMER);
				}
				else
				{
						nrf_drv_gpiote_out_set(PIN_OUT);
				}
		} 
		else 
		{ 
				nrf_drv_gpiote_out_clear(PIN_OUT);
		}
}
/**@brief Callback function for asserts in the SoftDevice.
 *
 * @details This function will be called in case of an assert in the SoftDevice.
 *
 * @warning This handler is an example only and does not fit a final product. You need to analyze
 *          how your product is supposed to react in case of Assert.
 * @warning On assert from the SoftDevice, the system can only recover on reset.
 *
 * @param[in]   line_num   Line number of the failing ASSERT call.
 * @param[in]   file_name  File name of the failing ASSERT call.
 */
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
{
    app_error_handler(DEAD_BEEF, line_num, p_file_name);
}

void init_flash(void)
{
	  uint32_t err_code;
	
	  uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
    uint32_t pg_num  = NRF_FICR->CODESIZE - 1;  // Use last page in flash
		//app_trace_log("page_size=%zu, code_size=%zu\n", NRF_FICR->CODEPAGESIZE, NRF_FICR->CODESIZE);
		flash_addr = (uint32_t)(pg_size * pg_num);
	
    nrf_fstorage_api_t* p_fs_api;
    p_fs_api = &nrf_fstorage_sd;
    err_code = nrf_fstorage_init(&fstorage, p_fs_api, NULL);
    APP_ERROR_CHECK(err_code);
}

void wait_for_flash_ready(nrf_fstorage_t const * p_fstorage);
void write_data_to_flash(uint32_t m_address, uint32_t m_data)
{
		uint32_t err_code;
	
		// erase first
		NRF_LOG_INFO("erasing flash @%x", m_address);
		err_code = nrf_fstorage_erase(&fstorage, m_address, 1, NULL);
		APP_ERROR_CHECK(err_code);
	
		NRF_LOG_INFO("waiting after erase ... ");
    wait_for_flash_ready(&fstorage);
    NRF_LOG_INFO("done");
		
    // write to flash
    NRF_LOG_INFO("writing %x to flash @%x", m_data, m_address);
    err_code = nrf_fstorage_write(&fstorage, m_address, &m_data, sizeof(m_data), NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_INFO("waiting after write ... ");
    wait_for_flash_ready(&fstorage);
		NRF_LOG_INFO("done");
}
uint32_t read_data_from_flash(uint32_t m_address)
{
		uint32_t err_code;
		uint32_t read_data = 0;	
		NRF_LOG_INFO("reading data @%x", m_address);
		err_code = nrf_fstorage_read(&fstorage, m_address, &read_data, sizeof(read_data));
		APP_ERROR_CHECK(err_code);
		NRF_LOG_INFO("read data: %x ", read_data);
		return read_data;
}
void read_config(void)
{
		uint32_t read_data;

		// read first word from flash
		//read_data = (uint32_t) *(flash_addr);			
		//app_trace_log("data read: %zu\n", read_data);	
	
		read_data = read_data_from_flash(flash_addr);
    NRF_LOG_INFO("waiting after read? ... ");
    wait_for_flash_ready(&fstorage);
		NRF_LOG_INFO("done, now converting ...");	
	
		fan_lo = (uint8_t)((read_data & 0xFF000000) >> 24);
		fan_hi = (uint8_t)((read_data & 0x00FF0000) >> 16);
		lower_hr = (uint8_t)((read_data & 0x0000FF00) >> 8);
		upper_hr = (uint8_t)(read_data & 0x000000FF);

    NRF_LOG_INFO("done, now reading again ... ");
		// read second word - ant_id
		read_data = read_data_from_flash(flash_addr + 100);
		ant_id = (uint16_t)(read_data & 0x0000FFFF);
		
		NRF_LOG_INFO("FLASH read: fan_lo=%u, fan_hi=%u, lower_hr=%u, upper_hr=%u, ant_id=%u\n", \
									fan_lo, fan_hi, lower_hr, upper_hr, ant_id);
}
void write_config_ble(void)
{
		const uint32_t data_to_write = fan_lo << 24 | fan_hi << 16 | lower_hr << 8 | upper_hr; 
		uint32_t ant_id_32 = (uint32_t) ant_id;
		write_data_to_flash(flash_addr, data_to_write);
		write_data_to_flash(flash_addr + 100, ant_id_32);
}


/**@brief Start advertising.
 */
static void advertising_start(void)
{
    uint32_t err_code;

    err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
    if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE)
    {
        APP_ERROR_HANDLER(err_code);
    }

    err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
    APP_ERROR_CHECK(err_code);
}


/**@brief Start receiving the ANT HRM data.
 */
static void ant_hrm_rx_start(void)
{
    uint32_t err_code = ant_hrm_disp_open(&m_ant_hrm);
    APP_ERROR_CHECK(err_code);
}


/**@brief Attempt to both open the ant channel and start ble advertising.
*/
static void ant_and_adv_start(void)
{
    advertising_start();
    ant_hrm_rx_start();
}


/**@brief Timer initialization.
 *
 * @details Initializes the timer module. This creates and starts application timers.
 */
static void peripherals_init(void)
{
    // Initialize timer module
    uint32_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing the GATT module.
 */
static void gatt_init(void)
{
    ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
    APP_ERROR_CHECK(err_code);
}


/**@brief GAP initialization.
 *
 * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
 *          device including the device name, appearance, and the preferred connection parameters.
 */
static void gap_params_init(void)
{
    uint32_t                err_code;
    ble_gap_conn_params_t   gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);

    err_code = sd_ble_gap_device_name_set(&sec_mode,
                                          (const uint8_t *)DEVICE_NAME,
                                          strlen(DEVICE_NAME));
    APP_ERROR_CHECK(err_code);

    err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT);
    APP_ERROR_CHECK(err_code);

    memset(&gap_conn_params, 0, sizeof(gap_conn_params));

    gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
    gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
    gap_conn_params.slave_latency     = SLAVE_LATENCY;
    gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;

    err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
    APP_ERROR_CHECK(err_code);
}


/**@brief Advertising functionality initialization.
 *
 * @details Encodes the required advertising data and passes it to the stack.
 *          Also builds a structure to be passed to the stack when starting advertising.
 */
static void advertising_init(void)
{
    uint32_t             err_code;
    ble_advdata_t        advdata;
		ble_advdata_t				 scanrsp;
    ble_gap_adv_data_t   advdata_enc;
    ble_gap_adv_params_t adv_params;
    static uint8_t       advdata_buff[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
    uint16_t             advdata_buff_len = BLE_GAP_ADV_SET_DATA_SIZE_MAX;
    uint8_t              flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
	
		static uint8_t			srdata_buff[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
		uint16_t						srdata_buff_len = BLE_GAP_ADV_SET_DATA_SIZE_MAX;

		ble_uuid_t ble_uuid;
		ble_uuid128_t base_uuid = {LBS_UUID_BASE};
    err_code = sd_ble_uuid_vs_add(&base_uuid, &ble_uuid.type);
		APP_ERROR_CHECK(err_code);
		ble_uuid_t adv_uuids[] = {{LBS_UUID_SERVICE, ble_uuid.type}};		
		
		// Build and set advertising data.
    memset(&advdata, 0, sizeof(advdata));

    advdata.name_type               = BLE_ADVDATA_FULL_NAME;
    advdata.include_appearance      = true;
    advdata.flags                   = flags;
    //advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
    //advdata.uuids_complete.p_uuids  = adv_uuids;		
		
    err_code = ble_advdata_encode(&advdata, advdata_buff, &advdata_buff_len);
    APP_ERROR_CHECK(err_code);

    m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;

    memset(&advdata_enc, 0, sizeof(advdata_enc));

		// SCAN RESPONSE DATA (vendor id does not fit in standard advertising data)
		memset(&scanrsp, 0, sizeof(scanrsp));
    scanrsp.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
    scanrsp.uuids_complete.p_uuids  = adv_uuids;
		err_code = ble_advdata_encode(&scanrsp, srdata_buff, &srdata_buff_len);
    APP_ERROR_CHECK(err_code);
		
    advdata_enc.adv_data.p_data = advdata_buff;
    advdata_enc.adv_data.len    = advdata_buff_len;
		advdata_enc.scan_rsp_data.p_data = srdata_buff;
		advdata_enc.scan_rsp_data.len = srdata_buff_len;

    // Initialise advertising parameters (used when starting advertising).
    memset(&adv_params, 0, sizeof(adv_params));

    adv_params.primary_phy     = BLE_GAP_PHY_1MBPS;
    adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
    adv_params.filter_policy   = BLE_GAP_ADV_FP_ANY;
    adv_params.interval        = APP_ADV_INTERVAL;
    adv_params.duration        = APP_ADV_DURATION;

    err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &advdata_enc, &adv_params);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling Queued Write Module errors.
 *
 * @details A pointer to this function will be passed to each service which may need to inform the
 *          application about an error.
 *
 * @param[in]   nrf_error   Error code containing information about what went wrong.
 */
static void nrf_qwr_error_handler(uint32_t nrf_error)
{
    APP_ERROR_HANDLER(nrf_error);
}

static void config_write_handler(ble_hrs_t* p_lbs, const uint8_t config[]) 
{
		uint16_t prev_ant_id = ant_id;

	NRF_LOG_INFO("config [%i %i %i %i %i %i]\n", config[0], config[1], config[2], config[3], config[4], config[5]);

		fan_lo = SEGMENTS_NO - config[0];
		fan_hi = SEGMENTS_NO - config[1];
		lower_hr = config[2];
		upper_hr = config[3];
		ant_id = config[4] << 8 | config[5];

		NRF_LOG_INFO("incoming conf: fan_lo=%i, fan_hi=%i, lower_hr=%i, upper_hr=%i, ant_id=%i\n", \
				fan_lo, fan_hi, lower_hr, upper_hr, ant_id);

		write_config_ble();	
	
		// reinitialize the ant connection if ant_id has changed
		if(prev_ant_id != ant_id) 
		{
				uint32_t err_code;
				//app_trace_log("new ant_id - reconnect\n");
				err_code = ant_reinit(HRM_DISP_CHANNEL_CONFIG(m_ant_hrm));
				APP_ERROR_CHECK(err_code);
				nrf_delay_ms(30);
				triac_on = false;
		}
}
static void test_write_handler(ble_hrs_t* p_lbs, const uint8_t newState[])
{
		uint8_t testState = newState[0];

		//app_trace_log("incoming test %i\n", testState);
		if(testState > 0) {
				uint32_t time_delay;
				int index = SEGMENTS_NO - testState; // incoming value should be between 1 and 201
				if(index < 0) 
				{
						global_delay = 0;
						nrf_drv_gpiote_out_set(PIN_OUT);
				}
				else 
				{
						time_delay = segments[index];
						global_delay = nrf_drv_timer_us_to_ticks(&TRIAC_TIMER, time_delay); 			
				}

				//app_trace_log("index=%i, testState=%i, time_delay=%i, global_delay=%i\n", index, testState, time_delay, global_delay);
				test = true;
				triac_on = true;
		}
		else
		{
				triac_on = false;
				test = false;
		}
}
/**@brief Initialize services that will be used by the application.
 *
 * @details Initialize the Heart Rate and Device Information services.
 */
static void services_init(void)
{
    uint32_t           err_code;
    ble_hrs_init_t     hrs_init;
    nrf_ble_qwr_init_t qwr_init = {0};

    // Initialize the Queued Write module.
    qwr_init.error_handler = nrf_qwr_error_handler;

    err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
    APP_ERROR_CHECK(err_code);

    // Initialize Heart Rate Service.
    memset(&hrs_init, 0, sizeof(hrs_init));
    hrs_init.evt_handler                 = NULL;

    // Here the sec level for the Heart Rate Service can be changed/increased.
    hrs_init.wr_sec = SEC_OPEN;
    hrs_init.rd_sec      = SEC_OPEN;
    hrs_init.test_write_handler = test_write_handler;
		hrs_init.config_write_handler = config_write_handler;

    err_code = ble_hrs_init(&m_hrs, &hrs_init);
    APP_ERROR_CHECK(err_code);
}


/**@brief Connection Parameters Module handler.
 *
 * @details This function will be called for all events in the Connection Parameters Module which
 *          are passed to the application.
 *          @note All this function does is to disconnect. This could have been done by simply
 *                setting the disconnect_on_fail config parameter, but instead we use the event
 *                handler mechanism to demonstrate its use.
 *
 * @param[in]   p_evt   Event received from the Connection Parameters Module.
 */
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
{
    uint32_t err_code;

    switch (p_evt->evt_type)
    {
        case BLE_CONN_PARAMS_EVT_FAILED:
            err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
            APP_ERROR_CHECK(err_code);
            break;

        default:
            // No implementation needed.
            break;
    }
}


/**@brief Connection Parameters module error handler.
 *
 * @param[in]   nrf_error   Error code containing information about what went wrong.
 */
static void conn_params_error_handler(uint32_t nrf_error)
{
    APP_ERROR_HANDLER(nrf_error);
}


/**@brief Initialize the Connection Parameters module.
 */
static void conn_params_init(void)
{
    uint32_t               err_code;
    ble_conn_params_init_t cp_init;

    memset(&cp_init, 0, sizeof(cp_init));

    cp_init.p_conn_params                  = NULL;
    cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
    cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
    cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
    //cp_init.start_on_notify_cccd_handle    = m_hrs.hrm_handles.cccd_handle;
    cp_init.disconnect_on_fail             = false;
    cp_init.evt_handler                    = on_conn_params_evt;
    cp_init.error_handler                  = conn_params_error_handler;

    err_code = ble_conn_params_init(&cp_init);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling a ANT stack event.
 *
 * @param[in] p_ant_evt  ANT stack event.
 * @param[in] p_context  Context.
 */
void ant_evt_handler(ant_evt_t * p_ant_evt, void * p_context)
{
    if (p_ant_evt->event != EVENT_CHANNEL_CLOSED)
    {
        return;
    }
    if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
    {
        ant_hrm_rx_start();
    }
    else
    {
        ant_and_adv_start();
    }
}


/**@brief Handle received ANT+ HRM data.
 *
 * @param[in]   p_profile       Pointer to the ANT+ HRM profile instance.
 * @param[in]   event           Event related with ANT+ HRM Display profile.
 */
static void ant_hrm_evt_handler(ant_hrm_profile_t * p_profile, ant_hrm_evt_t event)
{

}

/**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler.
 *
 * @param[in] p_ble_evt  Bluetooth stack event.
 * @param[in] p_context  Context.
 */
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    ret_code_t err_code = NRF_SUCCESS;

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
            APP_ERROR_CHECK(err_code);
            m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
            APP_ERROR_CHECK(err_code);
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            err_code = bsp_indication_set(BSP_INDICATE_IDLE);
            APP_ERROR_CHECK(err_code);
            m_conn_handle = BLE_CONN_HANDLE_INVALID;

            // Need to close the ANT channel to make it safe to write bonding information to flash
            err_code = sd_ant_channel_close(ANT_HRMRX_ANT_CHANNEL);
            APP_ERROR_CHECK(err_code);

            // Note: Bonding information will be stored, advertising will be restarted and the
            //       ANT channel will be reopened when ANT event CHANNEL_CLOSED is received.
            break;

#ifndef S140
        case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
        {
            ble_gap_phys_t const phys =
            {
                .rx_phys = BLE_GAP_PHY_AUTO,
                .tx_phys = BLE_GAP_PHY_AUTO,
            };

            err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
            APP_ERROR_CHECK(err_code);
        } break;
#endif

#ifndef BONDING_ENABLE
        case BLE_GAP_EVT_SEC_INFO_REQUEST:
            err_code = sd_ble_gap_sec_info_reply(m_conn_handle, NULL, NULL, NULL);
            APP_ERROR_CHECK(err_code);
            break;

        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
            err_code = sd_ble_gap_sec_params_reply(m_conn_handle,
                                                   BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP,
                                                   NULL,
                                                   NULL);
            APP_ERROR_CHECK(err_code);
            break;
#endif // BONDING_ENABLE

        case BLE_GAP_EVT_ADV_SET_TERMINATED:
            if (p_ble_evt->evt.gap_evt.params.adv_set_terminated.reason ==
                BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT)
            {
                err_code = bsp_indication_set(BSP_INDICATE_IDLE);
                APP_ERROR_CHECK(err_code);
                // Go to system-off mode (this function will not return; wakeup will cause a reset)
                //err_code = sd_power_system_off();
                //APP_ERROR_CHECK(err_code);
            }
            break;

#ifndef BONDING_ENABLE
            case BLE_GATTS_EVT_SYS_ATTR_MISSING:
                err_code = sd_ble_gatts_sys_attr_set(m_conn_handle,
                                                     NULL,
                                                     0,
                                                     BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS);
                APP_ERROR_CHECK(err_code);
                break;
#endif // BONDING_ENABLE

        default:
            // No implementation needed.
            break;
    }
}

#ifdef BONDING_ENABLE
/**@brief Function for handling Peer Manager events.
 *
 * @param[in] p_evt  Peer Manager event.
 */
static void pm_evt_handler(pm_evt_t const * p_evt)
{
    pm_handler_on_pm_evt(p_evt);
    pm_handler_flash_clean(p_evt);

    switch (p_evt->evt_id)
    {
        case PM_EVT_PEERS_DELETE_SUCCEEDED:
            advertising_start();
            break;

        default:
            break;
    }
}


/**@brief Function for the Peer Manager initialization.
 *
 * @param[in] erase_bonds  Indicates whether bonding information should be cleared from
 *                         persistent storage during initialization of the Peer Manager.
 */
static void peer_manager_init(bool erase_bonds)
{
    ble_gap_sec_params_t sec_param;
    ret_code_t           err_code;

    err_code = pm_init();
    APP_ERROR_CHECK(err_code);

    if (erase_bonds)
    {
        err_code = pm_peers_delete();
        APP_ERROR_CHECK(err_code);
    }

    memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));

    // Security parameters to be used for all security procedures.
    sec_param.bond           = SEC_PARAM_BOND;
    sec_param.mitm           = SEC_PARAM_MITM;
    sec_param.io_caps        = SEC_PARAM_IO_CAPABILITIES;
    sec_param.oob            = SEC_PARAM_OOB;
    sec_param.min_key_size   = SEC_PARAM_MIN_KEY_SIZE;
    sec_param.max_key_size   = SEC_PARAM_MAX_KEY_SIZE;
    sec_param.kdist_own.enc  = 1;
    sec_param.kdist_own.id   = 1;
    sec_param.kdist_peer.enc = 1;
    sec_param.kdist_peer.id  = 1;

    err_code = pm_sec_params_set(&sec_param);
    APP_ERROR_CHECK(err_code);

    err_code = pm_register(pm_evt_handler);
    APP_ERROR_CHECK(err_code);
}
#endif // BONDING_ENABLE


/**@brief BLE + ANT stack initialization.
 *
 * @details Initializes the SoftDevice and the stack event interrupt.
 */
static void softdevice_setup(void)
{
    ret_code_t err_code = nrf_sdh_enable_request();
    APP_ERROR_CHECK(err_code);

    ASSERT(nrf_sdh_is_enabled());

    // 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);

    err_code = nrf_sdh_ant_enable();
    APP_ERROR_CHECK(err_code);

    err_code = ant_plus_key_set(ANTPLUS_NETWORK_NUMBER);
    APP_ERROR_CHECK(err_code);

    // Register a handler for BLE events.
    NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    NRF_SDH_ANT_OBSERVER(m_ant_observer, APP_ANT_OBSERVER_PRIO, ant_evt_handler, NULL);
}

void TRIAC_TIMER_event_handler(nrf_timer_event_t event_type, void* p_context)
{
		nrf_drv_timer_clear(&TRIAC_TIMER);	
		if(!turn_off)
		{
				nrf_drv_gpiote_out_set(PIN_OUT);    

				turn_off = true;
				nrf_drv_timer_extended_compare(&TRIAC_TIMER, NRF_TIMER_CC_CHANNEL1, 3, NRF_TIMER_SHORT_COMPARE1_STOP_MASK, true);
				nrf_drv_timer_enable(&TRIAC_TIMER);
		}
		else
		{
				nrf_drv_gpiote_out_clear(PIN_OUT);
		}	
}

void nrf_timer_init(void)
{
		uint32_t err_code;
    //uint32_t time_ms = 500; //Time(in miliseconds) between consecutive compare events.
    //uint32_t time_ticks;
		//Configure all leds on board.
    bsp_board_init(BSP_INIT_LEDS);

    //Configure TRIAC_TIMER for generating simple light effect - leds on board will invert his state one after the other.
    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
		timer_cfg.frequency = NRF_TIMER_FREQ_31250Hz;
    err_code = nrf_drv_timer_init(&TRIAC_TIMER, &timer_cfg, TRIAC_TIMER_event_handler);
    APP_ERROR_CHECK(err_code);

    //time_ticks = nrf_drv_timer_ms_to_ticks(&TRIAC_TIMER, time_ms);
    //nrf_drv_timer_extended_compare(
    //     &TRIAC_TIMER, NRF_TIMER_CC_CHANNEL1, time_ticks, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true);
    //nrf_drv_timer_enable(&TRIAC_TIMER);
}
void gpiote_init(void)
{
		uint32_t err_code;  
		err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);

    err_code = nrf_drv_gpiote_out_init(PIN_OUT, &out_config);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
    in_config.pull = NRF_GPIO_PIN_NOPULL;

    err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(PIN_IN, true);
}

/**@brief Application main function.
 */

//#################################################################################################################################################################################
//#################################################################################################################################################################################
//#################################################################################################################################################################################

/**@brief   Sleep until an event is received. */
static void power_manage(void)
{
    (void) sd_app_evt_wait();
}

static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt)
{
    if (p_evt->result != NRF_SUCCESS)
    {
        NRF_LOG_INFO("--> Event received: ERROR while executing an fstorage operation.");
        return;
    }

    switch (p_evt->id)
    {
        case NRF_FSTORAGE_EVT_WRITE_RESULT:
        {
            NRF_LOG_INFO("--> Event received: wrote %d bytes at address 0x%x.",
                         p_evt->len, p_evt->addr);
        } break;

        case NRF_FSTORAGE_EVT_ERASE_RESULT:
        {
            NRF_LOG_INFO("--> Event received: erased %d page from address 0x%x.",
                         p_evt->len, p_evt->addr);
        } break;

        default:
            break;
    }
}

void wait_for_flash_ready(nrf_fstorage_t const * p_fstorage)
{
    /* While fstorage is busy, sleep and wait for an event. */
    while (nrf_fstorage_is_busy(p_fstorage))
    {
				power_manage();
    }
}

//#################################################################################################################################################################################
//#################################################################################################################################################################################
//#################################################################################################################################################################################

int main(void)
{
    uint32_t err_code;

    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);
		global_hr = lower_hr - 1;
	
		NRF_LOG_DEFAULT_BACKENDS_INIT();
	
		// FLASH Stuff
		init_flash();
	
		// Uncomment next line only to reset config to predefined values, then compile, run, and comment again
		//write_config_ble();
		//read_config();
	
		// divide sinewave into SEGMENT_NO pieecs, each with equal area
		divide_sinewave(SEGMENTS_NO);
	
    // Initialize peripherals
    peripherals_init();

    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);

    softdevice_setup();
				
    // Initialize Bluetooth stack parameters.
    gatt_init();
    gap_params_init();
    advertising_init();
    services_init();
    conn_params_init();

    // Initialize ANT+ HRM receive channel.
    err_code = ant_hrm_disp_init(&m_ant_hrm,
                                 HRM_DISP_CHANNEL_CONFIG(m_ant_hrm),
                                 ant_hrm_evt_handler);
    APP_ERROR_CHECK(err_code);

		nrf_timer_init();
		triac_on = false;	
		gpiote_init();

#ifdef BONDING_ENABLE
    bool erase_bonds = bsp_button_is_pressed(BOND_DELETE_ALL_BUTTON_ID);

    peer_manager_init(erase_bonds);
    if (erase_bonds == true)
    {
        NRF_LOG_INFO("Bonds erased!");
    }
#endif // BONDING_ENABLE

    NRF_LOG_INFO("ANT and BLE Heart Rate Monitor Relay example started.");

		advertising_start();
	
		// FLASH TEST - HERE IT WORKS!!!
		uint32_t m_data = 0x22334455;
		uint32_t r_data = 0;
		write_data_to_flash(flash_addr, m_data);
		r_data = read_data_from_flash(flash_addr);
		NRF_LOG_INFO("r_data = %x", r_data);
		// END TEST		

		ant_hrm_rx_start();
		
		// FLASH TEST - HERE IT DOESN't WORK!!! - Event received: ERROR while executing an fstorage operation.
		write_data_to_flash(flash_addr, m_data);
		r_data = read_data_from_flash(flash_addr);
		NRF_LOG_INFO("r_data = %x", r_data);
		// END TEST		

		// Enter main loop.
    for (;;)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
}

/**
 * @}
 */

What can be wrong?

PLEASE HELP

Parents
  • Digging deeper it seems that there is a general conflict with SDH and FDS. When I initialize the flash (my flash_init function in main.c) and then start ble and and Ant, the bluetooth works only until I connect an ANT hear rate monitor. Once the HRM is connected the BT stops advertising.

    If on the other hand I comment out the flash_init call then BT works all the way, even when I connect the HR. 

    No wonder the flash has problems. Any ideas how to solve this? Please

  • What have you set NRF_SDH_DISPATCH_MODEL to? Can it be related to:
    https://devzone.nordicsemi.com/f/nordic-q-a/42474/problem-with-fstorage-and-ble-init/165704#165704

    What have you set NRF_FSTORAGE_SD_MAX_RETRIES to? Try to increase it for instance to 1000.

    Since flash operation have very low priority compared to radio events, you may consider calling nrf_fstorage_is_busy(NULL); and wait for all operations to complete before starting BLE or ANT operations.

    Kenneth

  • Hi,Thanks for the answer.

    MAX_RETRIES don't fix the problem. I've laready tried that (see 3 posts above - I just have to wait longer for an error). 

    Dispatch model is NRF_SDH_DISPATCH_MODEL_INTERRUPT. It doesn't even start to work on the other two.

    I also do wait_for_flash_ready(&fstorage); after each nrf_fstorage_erase and nrf_fstorage_write.

    void wait_for_flash_ready(nrf_fstorage_t const * p_fstorage)
    {
        /* While fstorage is busy, sleep and wait for an event. */
        while (nrf_fstorage_is_busy(p_fstorage))
        {
    				(void) sd_app_evt_wait();
        }
    }

    As I am using the INTERRUP model then I guess addding app_sched_execute to wait_for_flash_ready doesn't make much sense? Anyway I checked all options I could think of already, including changing the model to scheduler and adding this option, but the results seem even worse. 

    Anywyay, my application is based on the ble_ant_app_hrm example. I added flash and GPIOTE to it.

Reply
  • Hi,Thanks for the answer.

    MAX_RETRIES don't fix the problem. I've laready tried that (see 3 posts above - I just have to wait longer for an error). 

    Dispatch model is NRF_SDH_DISPATCH_MODEL_INTERRUPT. It doesn't even start to work on the other two.

    I also do wait_for_flash_ready(&fstorage); after each nrf_fstorage_erase and nrf_fstorage_write.

    void wait_for_flash_ready(nrf_fstorage_t const * p_fstorage)
    {
        /* While fstorage is busy, sleep and wait for an event. */
        while (nrf_fstorage_is_busy(p_fstorage))
        {
    				(void) sd_app_evt_wait();
        }
    }

    As I am using the INTERRUP model then I guess addding app_sched_execute to wait_for_flash_ready doesn't make much sense? Anyway I checked all options I could think of already, including changing the model to scheduler and adding this option, but the results seem even worse. 

    Anywyay, my application is based on the ble_ant_app_hrm example. I added flash and GPIOTE to it.

Children
  • It looks to me that the problem here are softdevice priorities. In this case are doing flash operations while both BLE and ANT is active, typically the softdevice will be able to schedule flash operations between these events, however, especially erase operations take a long time, and it's not given that it will be able to schedule the flash erase operation due to this. My recommendation is that you don't schedule flash operations while both BLE and ANT is active. Flash operations will always have lowest priority:

    https://infocenter.nordicsemi.com/topic/sds_s140/SDS/s1xx/multilink_scheduling/priorities_and_events_intro.html 

  • And there really is no way to change the priorities somehow for a short while?

    The wtire operation is initiated from an android application communicating to my devive via BLE. Is there a way to somehow freeze / hibernate BT for the time of the erase/write operation? Something that would store current state, turn off BT, erase/write and then bring the BT back and restore previous state?  I need the connection to my phone to be preserved. If not maybe something similar for the ANT? A short pause in working of ANT wouldn't kill me (my application would still be good enough).

    Please advise.

  • Also, to be clear, my application isn't doint that much yet. It's just 1 bluetooth connection (to the phone app) and ant scanning. Would this be enough to take all proecssor time? I seriously doubt it.

    I have a sibling app which I build for NRF51 with SDK10 and it has, in addition to the ANT/BLE stuuf a 50hz interrupt going on and everything is working fine there. The proessor has enough time for everything. 

    To be honest I just to the sime 

    sd_flash_page_erase(page_to_erase);
    nrf_delay_ms(30);

    and hope for the best there, but it is working 100% of times and I had no problems with this implenentation. I wanted to do the same function here, but the proper way :) 

  • dragilla said:
    Dispatch model is NRF_SDH_DISPATCH_MODEL_INTERRUPT. It doesn't even start to work on the other two.

    The other two can't use your current implementation of wait_for_flash_ready(), for instance if you were to use NRF_SDH_DISPATCH_MODEL_APPSH you would need to use app_sched_execute(). 

    When using NRF_SDH_DISPATCH_MODEL_INTERRUPT there is no requirement to have a  wait_for_flash_ready() between calling flash operations, the intention of having NRF_FSTORAGE_SD_QUEUE_SIZE is to handle this for you so you avoid using wait_for_flash_ready(). 

    If you choose to keep wait_for_flash_ready(), then you may consider to remove the sd_app_evt_wait()/power_manage() in the loop, I am sligthly worried there may be a race condition where the flag is checked, cleared, and then the chip go to idle. If you choose to keep it, you may also want to add it before calling erase flash operations, in case there is already one pending. I suggest to use nrf_fstorage_is_busy(NULL); to check for all flash operations.

    dragilla said:
    Also, to be clear, my application isn't doint that much yet. It's just 1 bluetooth connection (to the phone app) and ant scanning. Would this be enough to take all proecssor time? I seriously doubt it.

    A flash erase operation take 100ms (this will halt the chip for 100ms), this needs to be scheduled by the softdevice internal scheduler, if there is ANT or BLE activity occurring every <100ms, then the softdevice may not be able to schedule the flash operation between those events, even if the CPU is not used more than 1%. 

    I suspect that ant_hrm_rx_start() will require heavy duty cycle of the radio until channel is synchronized to the peer, this will prevent the softdevice to be able to execute the flash erase opeation. So either do the flash erase operation before calling ant_hrm_rx_start(), or wait until channel is synchronized with the peer. If you want to call it while searching for peer, then I recommend to set NRF_FSTORAGE_SD_MAX_RETRIES to a very high value (e.g. 1000), to ensure it can handle the long period that the softdevice will search for the peer.

    Best regards,
    Kenneth

  • Ok. Now, after I've removed the wait_for_flash_ready calls I've reached a situation, where simingly my application works (as I operate purly on memory and need to save data only for between restarts) but the data is never saved to flash. The calls are queued and after the set number of reties they all fail. If I click save multiple times not waiting for the calls to fail then I quickly get NRF_ERROR_NO_MEM as the queue get overfilled. Well, at least it is working stable now and I know what is happening.

    Now, to the solution. I cannot do do write prior to the start of ant. My save function needs to work while connected to both ble and ant. I need to somehow freeze either ant and bt, for the time of erase/write. Can you elaborate shortyly how this could be done? 

    PS: my ble on dongle is a central/server based on the ble_blinky demo - the mobile app is also based on that demo - I just modified the services. The ANT application is the ant_hrm_rx demo, sligtly modifeid - I only use page0 for HR reading.

    Please advice, 

    Best regards,

    Lukasz

Related