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

Write to Flash during App timer_handler

I am using SDK15.0 and added the functionality of nrf_storage into the ble_app_uart in order to store the results of scan (which are kept during run time in an array in RAM).

I want to write the array to flash every 24 hours.

The command nrf_fstorage_write is working OK if it is in the main or in the uart_event_handle

But it doesn't work (Error) if it is inside the App timer handler (which is counting for 24h)

I cannot put a flag in the timer_handler and poll the flag in the main (as it was suggested before) since the polling is power consuming.

How can I do it?

Parents
  • Have you considered using the app scheduler library? You would “schedule” a call to nrf_fstorage_write in your app timer handler and it would be executed in main. 

  • I must keep my solution low power.

    Will scheduler running at main enable low power (ie sleep current between advertisement) till 24h timer reached?

    How does it work correctly if it is inside the uart_event?

    Will I be able to operate the flash storage inside the gpiote event (assuming I will use external low power RTC)?

    One more option:

    Is it possible to use the array in the RAM after soft reset  (nvic_systemreset()) and put the flash storage as part of the initialization? i.e. every 24 hours, the chip will reset, and store into the flash the content of the RAM array. In the RAM I can use a counter that will be used as a counter to write to different portion of the flash each day

    Will it work?

  • Hello,

     

    Avi said:
    Is it possible to use the array in the RAM after soft reset  (nvic_systemreset()) and put the flash storage as part of the initialization? i.e. every 24 hours, the chip will reset, and store into the flash the content of the RAM array.

     I doubt that a reset every 24 hours will cost less power consumption than polling a flag before sd_app_evt_wait(), or the similar sleep function that you use in your main loop.

    As I see it, you have 3 options:

    1: Use a scheduler, as  suggested.

    2: Set a flag in the timer interrupt, and poll it in your main loop.

    3: Use PPI to link the timer interrupt with a custom event handler (using the EGU), and write to flash in this interrupt.

    General question: 

    But it doesn't work (Error) if it is inside the App timer handler (which is counting for 24h)

     What sort of error do you encounter? Is it one of the function calls that return an err_code != 0, or are you missing a callback, or what error is it?

    Out of curiosity, what timer do you use? App_timer? RTC? TIMER? And what interrupt priority does your timer have?

    Best regards,

    Edvin

  • Hi,

    I will probably use the flag option, I check the current increment and it goes up to 20-30uA instead of 1uA (sleep). 

    Regarding the timer, I used App_timer and for testing I set it to 3 min long. I don't know which error it is, the code is stuck during the printf statement.

    The priority of the App_TImer is 7. I tried to raise it to 3 and it didn't help.

    Avi 

  • Hi,

     

    Avi said:
    I will probably use the flag option, I check the current increment and it goes up to 20-30uA instead of 1uA (sleep). 

     Is the only difference the flag poll between 20-30µA and 1µA? Do you run the app_timer in the 1µA scenario?

    You can leave the app_timer priority at 7. What I wanted to check was whether the issue was that you called the fstorage calls from a higher priority than what fstorage was running on, blocking the execution.

    Can you please specify what sort of error you encountered when you called the fstorage directly from the app_timer?

    BR,

    Edvin

  • The code is attached below

    How can I check which Error I get?

    ////////////////////////////////////////////////////////////////////////

    /// Main //////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////

    /**
    * Copyright (c) 2016 - 2018, 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.
    *
    */
    #include <stdio.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include "nordic_common.h"
    #include "app_error.h"
    #include "app_uart.h"
    #include "ble_db_discovery.h"
    #include "app_timer.h"
    #include "bsp.h"
    #include "app_util.h"
    #include "bsp_btn_ble.h"
    #include "ble.h"
    #include "nrf_soc.h"
    #include "ble_gap.h"
    #include "ble_hci.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_sdh_soc.h"
    #include "ble_advdata.h"
    #include "ble_nus_c.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_pwr_mgmt.h"
    #include "nrf_gpio.h"
    #include "nrf_delay.h"

    #include "nrf_nvic.h"
    #include "nrf_fstorage_sd.h"

    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"


    #define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */

    #define NON_CONNECTABLE_ADV_INTERVAL MSEC_TO_UNITS(500, 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 0x00, 0x01 /**< 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. */

    APP_TIMER_DEF(bas_timer);

    #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

    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. */


    #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 APP_BLE_OBSERVER_PRIO 3 /**< Application's BLE observer priority. You shoulnd't need to modify this value. */

    #define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */
    #define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */

    #define NUS_SERVICE_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN /**< UUID type for the Nordic UART Service (vendor specific). */

    #define SCAN_INTERVAL 0xBB80 /**< Determines scan interval in units of 0.625 millisecond. */
    #define SCAN_WINDOW 0x0640 /**< Determines scan window in units of 0.625 millisecond. */
    #define SCAN_DURATION 0x0000 /**< Timout when scanning. 0x0000 disables timeout. */

    #define MIN_CONNECTION_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS) /**< Determines minimum connection interval in millisecond. */
    #define MAX_CONNECTION_INTERVAL MSEC_TO_UNITS(75, UNIT_1_25_MS) /**< Determines maximum connection interval in millisecond. */
    #define SLAVE_LATENCY 0 /**< Determines slave latency in counts of connection events. */
    #define SUPERVISION_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Determines supervision time-out in units of 10 millisecond. */

    #define ECHOBACK_BLE_UART_DATA 1 /**< Echo the UART data that is received over the Nordic UART Service back to the sender. */

    BLE_NUS_C_DEF(m_ble_nus_c); /**< BLE NUS service client instance. */
    NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */
    BLE_DB_DISCOVERY_DEF(m_db_disc); /**< DB discovery module instance. */

    bool uart_on= false;

    uint32_t mac_arr[0xFF]; //Major index,hour_count

    static uint32_t flash_value;
    static uint32_t min_timer=0;
    static uint32_t pages_to_erase = 1;
    bool flash_done=false;


    static void fs_event_handler(nrf_fstorage_evt_t * evt){
    if (evt->result != NRF_SUCCESS){
    NRF_LOG_ERROR("Flash error");

    } else {
    NRF_LOG_INFO("Flash event success");
    }
    }

    NRF_FSTORAGE_DEF(nrf_fstorage_t m_fs1) =
    {
    .evt_handler = fs_event_handler,
    .start_addr = 0x0007C000,
    .end_addr = 0x0007FFFF,
    };
    NRF_FSTORAGE_DEF(nrf_fstorage_t m_fs2) =
    {
    .evt_handler = fs_event_handler,
    .start_addr = 0x0007D000,
    .end_addr = 0x0007FFFF,
    };

    NRF_FSTORAGE_DEF(nrf_fstorage_t m_fs3) =
    {
    .evt_handler = fs_event_handler,
    .start_addr = 0x0007E000,
    .end_addr = 0x0007FFFF,
    };
    NRF_FSTORAGE_DEF(nrf_fstorage_t m_fs4) =
    {
    .evt_handler = fs_event_handler,
    .start_addr = 0x0007F000,
    .end_addr = 0x0007FFFF,
    };


    void erase_flash(nrf_fstorage_t m_fs)
    {

    ret_code_t rc = nrf_fstorage_erase(
    &m_fs, /* The instance to use. */
    m_fs.start_addr, /* The address of the flash pages to erase. */
    pages_to_erase, /* The number of pages to erase. */
    NULL); /* Optional parameter, backend-dependent. */

    if (rc == NRF_SUCCESS)
    {
    /* The operation was accepted.
    Upon completion, the NRF_FSTORAGE_ERASE_RESULT event
    is sent to the callback function registered by the instance. */

    if(uart_on) printf("ERASE SUCCESSFUL");
    }
    else
    {
    if(uart_on) printf("ERASE UNSUCCESFUL ");
    /* Handle error.*/
    }
    }

    void write_to_flash(nrf_fstorage_t m_fs,int add_offset)
    {
    ret_code_t rc;

    rc = nrf_fstorage_write(&m_fs, m_fs.start_addr+add_offset, &flash_value, 4, NULL); //Write data to memory address. Check it with command: nrfjprog --memrd addr --n 32
    if (rc == NRF_SUCCESS)
    {

    if(uart_on) printf("WRITE SUCCESSFUL");
    }
    else
    {
    if(uart_on) printf("WRITE UNSUCCESFUL ");
    /* Handle error.*/
    }


    }


    static uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
    /**@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 Connection parameters requested for connection. */
    static ble_gap_conn_params_t const m_connection_param =
    {
    (uint16_t)MIN_CONNECTION_INTERVAL, // Minimum connection
    (uint16_t)MAX_CONNECTION_INTERVAL, // Maximum connection
    (uint16_t)SLAVE_LATENCY, // Slave latency
    (uint16_t)SUPERVISION_TIMEOUT // Supervision time-out
    };

    static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_MIN]; /**< buffer where advertising reports will be stored by the SoftDevice. */

    /**@brief Pointer to the buffer where advertising reports will be stored by the SoftDevice. */
    static ble_data_t m_scan_buffer =
    {
    m_scan_buffer_data,
    BLE_GAP_SCAN_BUFFER_MIN
    };

    /** @brief Parameters used when scanning. */
    static ble_gap_scan_params_t const m_scan_params =
    {
    .active = 1,
    .interval = SCAN_INTERVAL,
    .window = SCAN_WINDOW,
    .timeout = SCAN_DURATION,
    .scan_phys = BLE_GAP_PHY_1MBPS,
    .filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL,
    };

    /**@brief NUS uuid. */
    static ble_uuid_t const m_nus_uuid =
    {
    .uuid = BLE_UUID_NUS_SERVICE,
    .type = NUS_SERVICE_UUID_TYPE
    };


    /**@brief 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] p_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(0xDEADBEEF, line_num, p_file_name);
    }


    /**@brief Function to start scanning. */
    static void scan_start(void)
    {
    ret_code_t ret;

    ret = sd_ble_gap_scan_start(&m_scan_params, &m_scan_buffer);
    APP_ERROR_CHECK(ret);

    ret = bsp_indication_set(BSP_INDICATE_SCANNING);
    APP_ERROR_CHECK(ret);
    }


    /**@brief Function for handling database discovery events.
    *
    * @details This function is callback function to handle events from the database discovery module.
    * Depending on the UUIDs that are discovered, this function should forward the events
    * to their respective services.
    *
    * @param[in] p_event Pointer to the database discovery event.
    */
    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
    ble_nus_c_on_db_disc_evt(&m_ble_nus_c, p_evt);
    }


    /**@brief Function for handling characters received by the Nordic UART Service.
    *
    * @details This function takes a list of characters of length data_len and prints the characters out on UART.
    * If @ref ECHOBACK_BLE_UART_DATA is set, the data is sent back to sender.
    */
    static void ble_nus_chars_received_uart_print(uint8_t * p_data, uint16_t data_len)
    {
    ret_code_t ret_val;

    NRF_LOG_DEBUG("Receiving data.");
    NRF_LOG_HEXDUMP_DEBUG(p_data, data_len);

    for (uint32_t i = 0; i < data_len; i++)
    {
    do
    {
    ret_val = app_uart_put(p_data[i]);
    if ((ret_val != NRF_SUCCESS) && (ret_val != NRF_ERROR_BUSY))
    {
    NRF_LOG_ERROR("app_uart_put failed for index 0x%04x.", i);
    APP_ERROR_CHECK(ret_val);
    }
    } while (ret_val == NRF_ERROR_BUSY);
    }
    if (p_data[data_len-1] == '\r')
    {
    while (app_uart_put('\n') == NRF_ERROR_BUSY);
    }
    if (ECHOBACK_BLE_UART_DATA)
    {
    // Send data back to peripheral.
    do
    {
    ret_val = ble_nus_c_string_send(&m_ble_nus_c, p_data, data_len);
    if ((ret_val != NRF_SUCCESS) && (ret_val != NRF_ERROR_BUSY))
    {
    NRF_LOG_ERROR("Failed sending NUS message. Error 0x%x. ", ret_val);
    APP_ERROR_CHECK(ret_val);
    }
    } while (ret_val == NRF_ERROR_BUSY);
    }
    }
    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 defined(USE_UICR_FOR_MAJ_MIN_VALUES)
    // If USE_UICR_FOR_MAJ_MIN_VALUES is defined, the major and minor values will be read from the
    // UICR instead of using the default values. The major and minor values obtained from the UICR
    // are encoded into advertising data in big endian order (MSB First).
    // To set the UICR used by this example to a desired value, write to the address 0x10001080
    // using the nrfjprog tool. The command to be used is as follows.
    // nrfjprog --snr <Segger-chip-Serial-Number> --memwr 0x10001080 --val <your major/minor value>
    // For example, for a major value and minor value of 0xabcd and 0x0102 respectively, the
    // the following command should be used.
    // nrfjprog --snr <Segger-chip-Serial-Number> --memwr 0x10001080 --val 0xabcd0102
    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

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


    #ifdef BOARD_PCA10056
    m_adv_params.primary_phy = BLE_GAP_PHY_CODED;
    m_adv_params.secondary_phy = BLE_GAP_PHY_CODED;
    m_adv_params.scan_req_notification = 0;

    m_adv_params.properties.type = BLE_GAP_ADV_TYPE_EXTENDED_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);
    err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, m_adv_handle, 8); //+8dBm
    APP_ERROR_CHECK(err_code);}
    #endif

    #ifdef BOARD_PCA10040
    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);
    err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, m_adv_handle, -4); //-4dBm
    APP_ERROR_CHECK(err_code);
    }
    #endif
    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);

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

    /**@brief Function for handling app_uart events.
    *
    * @details This function will receive a single character from the app_uart module and append it to
    * a string. The string will be be sent over BLE when the last character received was a
    * 'new line' '\n' (hex 0x0A) or if the string has reached the maximum data length.
    */
    void uart_event_handle(app_uart_evt_t * p_event)
    {
    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    static uint16_t index = 0;

    switch (p_event->evt_type)
    {
    /**@snippet [Handling data from UART] */
    case APP_UART_DATA_READY:
    UNUSED_VARIABLE(app_uart_get(&data_array[index]));
    index++;

    if ((data_array[index - 1] == '\n') || (index >= (m_ble_nus_max_data_len)))
    {
    NRF_LOG_DEBUG("Ready to send data over BLE NUS");
    NRF_LOG_HEXDUMP_DEBUG(data_array, index);

    if (data_array[0]=='E' && data_array[1]=='R' && data_array[2]=='F')
    {
    sd_ble_gap_adv_stop(m_adv_handle);
    sd_ble_gap_scan_stop();

    if (data_array[3]=='1') erase_flash(m_fs1);
    else if (data_array[3]=='2') erase_flash(m_fs2);
    else if (data_array[3]=='3') erase_flash(m_fs3);
    else if (data_array[3]=='4') erase_flash(m_fs4);

    advertising_init();
    advertising_start();
    scan_start();
    }

    else if (data_array[0]=='R' && data_array[1]=='D' && data_array[2]=='F')
    {
    int *mem;
    if (data_array[3]=='1') mem = (int *)(0x0007C000+(data_array[4]-'0')*100+(data_array[5]-'0')*10+(data_array[6]-'0'));
    else if (data_array[3]=='2') mem = (int *)(0x0007D000+(data_array[4]-'0')*100+(data_array[5]-'0')*10+(data_array[6]-'0'));
    else if (data_array[3]=='3') mem = (int *)(0x0007E000+(data_array[4]-'0')*100+(data_array[5]-'0')*10+(data_array[6]-'0'));
    else if (data_array[3]=='4') mem = (int *)(0x0007F000+(data_array[4]-'0')*100+(data_array[5]-'0')*10+(data_array[6]-'0'));
    int temp = *mem;
    if (uart_on) printf("tag found:%x",temp);
    }

    else if (data_array[0]=='R' && data_array[1]=='D' && data_array[2]=='M')
    {
    if (uart_on) printf("Mac_array[%d]:%x",(data_array[3]-'0')*100+(data_array[4]-'0')*10+data_array[5]-'0',
    mac_arr[(data_array[3]-'0')*100+(data_array[4]-'0')*10+data_array[5]-'0']);
    }

    else if (data_array[0]=='W' && data_array[1]=='R' && data_array[2]=='F')
    {
    sd_ble_gap_adv_stop(m_adv_handle);
    sd_ble_gap_scan_stop();
    flash_value = data_array[7];
    if (data_array[3]=='1') write_to_flash(m_fs1,(data_array[4]-'0')*100+(data_array[5]-'0')*10+(data_array[6]-'0'));
    else if (data_array[3]=='2') write_to_flash(m_fs2,(data_array[4]-'0')*100+(data_array[5]-'0')*10+(data_array[6]-'0'));
    else if (data_array[3]=='3') write_to_flash(m_fs3,(data_array[4]-'0')*100+(data_array[5]-'0')*10+(data_array[6]-'0'));
    else if (data_array[3]=='4') write_to_flash(m_fs4,(data_array[4]-'0')*100+(data_array[5]-'0')*10+(data_array[6]-'0'));
    advertising_init();
    advertising_start();
    scan_start();
    }

    index = 0;
    }
    break;

    /**@snippet [Handling data from UART] */
    case APP_UART_COMMUNICATION_ERROR:
    NRF_LOG_ERROR("Communication error occurred while handling UART.");
    APP_ERROR_HANDLER(p_event->data.error_communication);
    break;

    case APP_UART_FIFO_ERROR:
    NRF_LOG_ERROR("Error occurred in FIFO module used by UART.");
    APP_ERROR_HANDLER(p_event->data.error_code);
    break;

    default:
    break;
    }
    }


    /**@brief Callback handling NUS Client events.
    *
    * @details This function is called to notify the application of NUS client events.
    *
    * @param[in] p_ble_nus_c NUS Client Handle. This identifies the NUS client
    * @param[in] p_ble_nus_evt Pointer to the NUS Client event.
    */

    /**@snippet [Handling events from the ble_nus_c module] */
    static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
    {
    ret_code_t err_code;

    switch (p_ble_nus_evt->evt_type)
    {
    case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
    NRF_LOG_INFO("Discovery complete.");
    err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
    APP_ERROR_CHECK(err_code);

    err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_INFO("Connected to device with Nordic UART Service.");
    break;

    case BLE_NUS_C_EVT_NUS_TX_EVT:
    ble_nus_chars_received_uart_print(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len);
    break;

    case BLE_NUS_C_EVT_DISCONNECTED:
    NRF_LOG_INFO("Disconnected.");
    scan_start();
    break;
    }
    }
    /**@snippet [Handling events from the ble_nus_c module] */


    /**
    * @brief Function for shutdown events.
    *
    * @param[in] event Shutdown type.
    */
    static bool shutdown_handler(nrf_pwr_mgmt_evt_t event)
    {
    ret_code_t err_code;

    err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    APP_ERROR_CHECK(err_code);

    switch (event)
    {
    case NRF_PWR_MGMT_EVT_PREPARE_WAKEUP:
    // Prepare wakeup buttons.
    err_code = bsp_btn_ble_sleep_mode_prepare();
    APP_ERROR_CHECK(err_code);
    break;

    default:
    break;
    }

    return true;
    }

    NRF_PWR_MGMT_HANDLER_REGISTER(shutdown_handler, APP_SHUTDOWN_HANDLER_PRIORITY);


    /**@brief Function for handling the advertising report BLE event.
    *
    * @param[in] p_adv_report Advertising report from the SoftDevice.
    */
    static void on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report)
    {
    ret_code_t err_code;
    uint8_t uuid[30];
    memmove(uuid, p_adv_report->data.p_data, p_adv_report->data.len);
    if (uuid[9]==0x01 && uuid[10]==0x12 && uuid[11]==0x23 && uuid[12]==0x34)
    {
    if(uart_on) printf("MAC: %x%x%x%x%x%x ",p_adv_report->peer_addr.addr[0], p_adv_report->peer_addr.addr[1],
    p_adv_report->peer_addr.addr[2],p_adv_report->peer_addr.addr[3],p_adv_report->peer_addr.addr[4],
    p_adv_report->peer_addr.addr[5]);
    if(uart_on) printf("MAJOR: %x%x\n", uuid[25], uuid[26]);
    mac_arr[uuid[25]*10+uuid[26]] = (p_adv_report->rssi)*256+min_timer;
    }

    mac_arr[p_adv_report->peer_addr.addr[0]] = 1;

    if (ble_advdata_uuid_find(p_adv_report->data.p_data, p_adv_report->data.len, &m_nus_uuid))
    {
    err_code = sd_ble_gap_connect(&p_adv_report->peer_addr,
    &m_scan_params,
    &m_connection_param,
    APP_BLE_CONN_CFG_TAG);

    if (err_code == NRF_SUCCESS)
    {
    // scan is automatically stopped by the connect
    err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_INFO("Connecting to target %02x%02x%02x%02x%02x%02x",
    p_adv_report->peer_addr.addr[0],
    p_adv_report->peer_addr.addr[1],
    p_adv_report->peer_addr.addr[2],
    p_adv_report->peer_addr.addr[3],
    p_adv_report->peer_addr.addr[4],
    p_adv_report->peer_addr.addr[5]
    );
    }
    }
    else
    {
    err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer);
    APP_ERROR_CHECK(err_code);
    }
    }


    /**@brief Function for handling BLE events.
    *
    * @param[in] p_ble_evt Bluetooth stack event.
    * @param[in] p_context Unused.
    */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
    ret_code_t err_code;
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;

    switch (p_ble_evt->header.evt_id)
    {
    case BLE_GAP_EVT_ADV_REPORT:
    on_adv_report(&p_gap_evt->params.adv_report);
    break; // BLE_GAP_EVT_ADV_REPORT

    case BLE_GAP_EVT_CONNECTED:
    NRF_LOG_INFO("Connected to target");
    err_code = ble_nus_c_handles_assign(&m_ble_nus_c, p_ble_evt->evt.gap_evt.conn_handle, NULL);
    APP_ERROR_CHECK(err_code);

    err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
    APP_ERROR_CHECK(err_code);

    // start discovery of services. The NUS Client waits for a discovery result
    err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);
    APP_ERROR_CHECK(err_code);
    break;

    case BLE_GAP_EVT_TIMEOUT:
    if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN)
    {
    NRF_LOG_INFO("Scan timed out.");
    scan_start();
    }
    else if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
    {
    NRF_LOG_INFO("Connection Request timed out.");
    }
    break;

    case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
    // Pairing not supported
    err_code = sd_ble_gap_sec_params_reply(p_ble_evt->evt.gap_evt.conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
    APP_ERROR_CHECK(err_code);
    break;

    case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
    // Accepting parameters requested by peer.
    err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle,
    &p_gap_evt->params.conn_param_update_request.conn_params);
    APP_ERROR_CHECK(err_code);
    break;

    case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
    {
    NRF_LOG_DEBUG("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;

    case BLE_GATTC_EVT_TIMEOUT:
    // Disconnect on GATT Client timeout event.
    NRF_LOG_DEBUG("GATT Client Timeout.");
    err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
    BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    APP_ERROR_CHECK(err_code);
    break;

    case BLE_GATTS_EVT_TIMEOUT:
    // Disconnect on GATT Server timeout event.
    NRF_LOG_DEBUG("GATT Server Timeout.");
    err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
    BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    APP_ERROR_CHECK(err_code);
    break;

    default:
    break;
    }
    }


    /**@brief Function for initializing the BLE stack.
    *
    * @details Initializes the SoftDevice and the BLE event interrupt.
    */
    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);

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


    /**@brief Function for handling events from the GATT library. */
    void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
    {
    if (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)
    {
    NRF_LOG_INFO("ATT MTU exchange completed.");

    m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
    NRF_LOG_INFO("Ble NUS max data length set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
    }
    }


    /**@brief Function for initializing the GATT library. */
    void gatt_init(void)
    {
    ret_code_t err_code;

    err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_ble_gatt_att_mtu_central_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
    APP_ERROR_CHECK(err_code);
    }


    /**@brief Function for handling events from the BSP module.
    *
    * @param[in] event Event generated by button press.
    */
    void bsp_event_handler(bsp_event_t event)
    {
    ret_code_t err_code;

    switch (event)
    {
    case BSP_EVENT_SLEEP:
    nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
    break;

    case BSP_EVENT_DISCONNECT:
    err_code = sd_ble_gap_disconnect(m_ble_nus_c.conn_handle,
    BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    if (err_code != NRF_ERROR_INVALID_STATE)
    {
    APP_ERROR_CHECK(err_code);
    }
    break;

    default:
    break;
    }
    }

    /**@brief Function for initializing the UART. */
    static void uart_init(void)
    {
    ret_code_t err_code;

    app_uart_comm_params_t const comm_params =
    {
    .rx_pin_no = RX_PIN_NUMBER,
    .tx_pin_no = TX_PIN_NUMBER,
    .rts_pin_no = RTS_PIN_NUMBER,
    .cts_pin_no = CTS_PIN_NUMBER,
    .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
    .use_parity = false,
    .baud_rate = UART_BAUDRATE_BAUDRATE_Baud115200
    };

    APP_UART_FIFO_INIT(&comm_params,
    UART_RX_BUF_SIZE,
    UART_TX_BUF_SIZE,
    uart_event_handle,
    APP_IRQ_PRIORITY_LOWEST,
    err_code);

    APP_ERROR_CHECK(err_code);
    }

    /**@brief Function for initializing the NUS Client. */
    static void nus_c_init(void)
    {
    ret_code_t err_code;
    ble_nus_c_init_t init;

    init.evt_handler = ble_nus_c_evt_handler;

    err_code = ble_nus_c_init(&m_ble_nus_c, &init);
    APP_ERROR_CHECK(err_code);
    }


    /**@brief Function for initializing buttons and leds. */
    static void buttons_leds_init(void)
    {
    ret_code_t err_code;
    bsp_event_t startup_event;

    err_code = bsp_init(BSP_INIT_LEDS, bsp_event_handler);
    APP_ERROR_CHECK(err_code);

    err_code = bsp_btn_ble_init(NULL, &startup_event);
    APP_ERROR_CHECK(err_code);
    }


    void bas_timer_handler(void * p_context)
    {
    min_timer = min_timer+1;
    }

    /**@brief Function for initializing the timer. */
    static void timer_init(void)
    {
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);
    err_code = app_timer_create(&bas_timer,APP_TIMER_MODE_REPEATED,bas_timer_handler);
    APP_ERROR_CHECK(err_code);
    }


    /**@brief Function for initializing the nrf log module. */
    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 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 initializing the Database Discovery Module. */
    static void db_discovery_init(void)
    {
    ret_code_t err_code = ble_db_discovery_init(db_disc_handler);
    APP_ERROR_CHECK(err_code);
    }


    /**@brief Function for handling the idle state (main loop).
    *
    * @details Handle any pending log operation(s), then sleep until the next event occurs.
    */
    static void idle_state_handle(void)
    {
    if (NRF_LOG_PROCESS() == false)
    {
    nrf_pwr_mgmt_run();
    }
    }



    int main(void)
    {

    uint32_t err_code;
    // Initialize.
    log_init();
    timer_init();
    for (int i=0;i<100;i++)
    mac_arr[i]=0;
    err_code = nrf_fstorage_init(&m_fs1, &nrf_fstorage_sd, NULL);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_fstorage_init(&m_fs2, &nrf_fstorage_sd, NULL);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_fstorage_init(&m_fs3, &nrf_fstorage_sd, NULL);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_fstorage_init(&m_fs4, &nrf_fstorage_sd, NULL);
    APP_ERROR_CHECK(err_code);


    app_timer_start(bas_timer, APP_TIMER_TICKS((60*1000)), NULL);
    nrf_gpio_cfg_input(11,NRF_GPIO_PIN_PULLUP);
    nrf_delay_ms(1000);
    if(!nrf_gpio_pin_read(11)) uart_on = true;
    nrf_gpio_cfg_input(11,NRF_GPIO_PIN_NOPULL);
    if(uart_on) uart_init();
    buttons_leds_init();
    db_discovery_init();
    power_management_init();

    ble_stack_init();
    gatt_init();
    nus_c_init();
    advertising_init();
    advertising_start();

    // Start execution.
    if(uart_on) printf("BLE UART central example started.\r\n");

    NRF_LOG_INFO("BLE UART central example started.");
    scan_start();

    // Enter main loop.
    for (;;)
    {
    if ((min_timer % 3)==1 && !flash_done)
    {
    flash_done = true;
    sd_ble_gap_adv_stop(m_adv_handle);
    sd_ble_gap_scan_stop();
    int i=1;
    for (int i=0;i<100;i++)
    {
    if (mac_arr[i]!=0)
    {
    flash_value = mac_arr[i];
    if(uart_on) printf("Write to Flash %d", mac_arr[i]);
    write_to_flash(m_fs1,(min_timer/3)*100+i*4);
    nrf_delay_ms(100);
    }

    }
    advertising_init();
    advertising_start();
    scan_start();
    }
    else if ((min_timer % 3)==2) flash_done=false;
    idle_state_handle();

    }
    }

  • If you are going to include code, please use the "insert"->"code" functionality.

    I don't know what error you encountered. You said that you had an error: "But it doesn't work (Error) if it is inside the App timer handler (which is counting for 24h)". What does that mean? Is it because you see the "WRITE UNSUCCESFUL" in the log?

Reply Children
Related