NAV Navbar

CYW20819 SPI-Based Datalogger – CE226537

This code example includes two applications that demonstrate the operation of multiple Serial Peripheral Interface (SPI) interfaces using the CYW20819 Bluetooth SoC and ModusToolbox™ Integrated Development Environment (IDE). The first application demonstrates operation of two SPI masters – one for collecting sensor data and the other for logging the data to external flash. The second application demonstrates operation of an SPI slave which is used for providing sensor data to the first application.

Requirements

Tool: ModusToolbox IDE 1.1 or later version

Programming Language: C

Associated Parts: CYW20819

Related Hardware: CYW920819EVB-02 Evaluation Kit

Overview

The application "dual_spi_master" demonstrates two SPI master instances using multiple threads. The SPI1 instance is used to communicate with an external SPI sensor and the SPI2 instance is used to communicate with an SFLASH on the kit. The received sensor values are written to SFLASH by coupling with a timestamp of the temperature reading using the RTC. The user can initiate a read operation on the SFLASH by pressing user button (SW3) on the CYW920819EVB-02 kit to obtain and display the stored temperature records. A NVRAM module using internal flash is used to store the last temperature record number that was stored in SFLASH, so that the application resumes without overwriting the stored records during reset or power failure.

This application showcases usage of:

  1. Multiple threads communicating via an RTOS semaphore and message queue

  2. Two SPI instances available on the device in the same application

  3. SFLASH middleware library

  4. NVRAM middleware for application data

The application "spi_slave_sensor" demonstrates how to use the SPI Slave interface to send and receive bytes or a stream of bytes over the SPI hardware. This kit emulates a SPI-based temperature sensor by reading an onboard thermistor using the ADC on the device and sending it to the Master whenever a new value is requested. These two applications should be used in conjunction with each other.

Hardware Setup

Figure 1. Block Diagram

These applications run on two separate CYW920819EVB-02 kits. Both applications use the kit’s default configuration. Refer to the kit guide, if required, to ensure the kit is configured correctly. The block diagram depicting the connections between different blocks of two CYW920819EVB-02 kits is shown in Figure 1.

Make the connections as shown in Table 1.

Table 1. Hardware Connections

Function Master Master Master Slave Slave Slave
CLK WICED_P15 J3.8 D10 WICED_P09 J3.5 D13
MISO WICED_P14 J3.10 D8 WICED_P17 J3.6 D12
MOSI WICED_P13 J12.6 A05 WICED_P14 J3.10 D8
CS WICED_P12 J12.5 A04 WICED_P15 J3.8 D10
GND GND J11.6 GND GND J11.6 GND

Operation

Figure 2. Change Project Settings

Figure 3. Programming the CYW20819 Device from ModusToolbox

Figure 4. Serial terminal Output for SPI Slave

Figure 5. Serial Terminal Output of SPI Master

  1. Connect two kits to your PC using the provided USB cable. Note down the port enumerations for each device in Device Manager > Ports (COM & LPT) (Windows only). The enumeration with a smaller number is the HCI UART port and the other is Peripheral UART port.
  2. Import the two code examples into a workspace. See KBA225201.
  3. In the project explorer, right-click each [App Name]_mainapp project one at a time and select Change Application Settings in the drop-down menu. Configure the UART port to match the HCI UART port enumeration as shown in Figure 2 instead of using AUTO so that the master application is set for the HCI UART port of one of the kits and the slave application is set for the HCI UART of the other kit.
  4. Alternatively, instead of manually setting the UART port in the application settings, you can connect the kits one at a time to program the applications and then connect both kits once programming is done.
  5. Program the CYW20819 device on the kit with the application "dual_spi_master". In the project explorer, select the [App Name]_mainapp project for the master. In the Quick Panel, scroll to the Launches section, and click the Build + Program configuration as shown in Figure 3. Repeat this step to program the other kit with "spi_slave_sensor" and ensure that the UART port selected is for the other kit.
  6. Open a serial terminal application, such as Tera Term, and connect to the WICED Peripheral UART port of both the kits.
  7. Configure the terminal application to access the serial port using settings listed in Table 2.

Table 2. WICED Peripheral UART Settings

UART Serial Port Configuration Value
Baud rate 115200 bps
Data 8 bits
Parity None
Stop 1 bit
Flow control None
New-line for Receive data Line Feed or Auto setting
  1. The slave serial terminal window displays the SPI command received and the accompanying response on the terminal window, as shown in Figure 4.
  2. The master serial terminal window displays a message that prompts you to press the user button to view the temperature records. When you press the button, if there are no temperature records to be read from SFLASH, an appropriate message is displayed on the window. Otherwise, temperature records that you have not already read are displayed on the terminal window as shown in Figure 5.
  3. The master stores in the NVRAM the number of the record that was last stored in the SFLASH. This feature ensures that even when the Master is powered down or reset, prior temperature records are not lost by overwriting the previous data. You can test this feature by pressing the reset button (SW2) and then user button (SW3). The terminal displays all the stored temperature records from the beginning as shown in Figure 6. Note that the RTC timestamp value is reset for the new values that are stored, so there will not be continuity in the timestamp values between the stored records before reset and the stored records after reset.

Figure 6. Serial Terminal Output of SPI Master After Reset

Design and Implementation

SPI Master

This section describes the details of the implementation of the SPI Master.

On startup, the application sets up the UART and then starts the Bluetooth stack in application_start(). Once the stack is started (BTM_ENABLED_EVT), it calls the initialize_app() function which handles the remaining functionality. Note that the Bluetooth stack is running but we are not using Bluetooth in this application, so it doesn't do anything once the stack is started. The initialize_app() function initializes both the SPI interfaces, RTC, GPIO and two separate threads which handle the two different SPI transactions – one to read the SPI sensor and one to write the SFLASH. The two threads communicate with each other through a queue to transfer temperature records. A semaphore is used to signal the thread handling SFLASH when data of one page size is available in the queue for writing. In this implementation, the page size is 256 bytes and the size of each temperature record is 16 bytes, so records are written when 256/16 = 16 temperature values have been received.

Also, during initialization the number of the last record that was stored in NVRAM is obtained. The NVRAM read provides the number of temperature records that are present in SFLASH so that if the master is reset or powered down, the current address (i.e., where new temperature records will be written) is updated to address the next free location. This prevents overwriting over stored temperature records upon reset. When the application is running for the first time after download the NVRAM read fails since no write has been performed. Here, the record number read from NVRAM is re-assigned to 0 to prevent using an erroneous value for the record number.

The temperature readings are held in a structure called “temperature_record” which contains the following elements:

In the thread handling SPI communication with the slave (spi_sensor_thread), a finite state machine is used to determine the data that the master requests as shown in Figure 7.

Figure 7. FSM Adopted for Communicating with Slave

The finite state machine contains three states:

In each state, the slave is verified to be a known slave using a packet header before processing the data that is sent from the slave. If the master is not able to authenticate the slave, the master remains in the same state and retries. After five retries, the SPI interface is reset, and the master starts from the SENSOR_DETECT state.

In the SENSOR_DETECT state, the master requests the Manufacturer ID to verify that the slave’s manufacturer is Cypress. If the slave responds with an unknown Manufacturer ID, the master informs the user that the slave’s identity could not be authenticated. If the slave responds with the expected Manufacturer ID, the master enters the next state, READ_UNIT. A flowchart illustrating the operation is shown in Figure 8.

Figure 8. Flowchart of SENSOR_DETECT State

In the READ_UNIT state, the master requests the Unit ID to know the unit of temperature values provided by the slave. If the slave responds with an unknown Unit ID, the master informs the user that the unit of temperature is unknown and tries to obtain the unit again. If the number of retries exceeds 5, the master changes its state to SENSOR_DETECT. Otherwise, if the slave responds as expected, the master enters the next state, READ_TEMPERATURE. A flowchart illustrating the operation is shown in Figure 9.

Figure 9 Flowchart Showing READ_UNIT State

In the READ_TEMPERATURE state, the master requests the temperature from the slave. The temperature reading received comprises the decimal and fractional parts of the temperature. For instance, if the temperature reading is 24.44 C, the slave sends 2444 as the data. The Master then stores the quotient as the decimal part of temperature and remainder as the fractional part of temperature in the temperature record. The RTC is used to obtain the time when the temperature reading was received so that it can be included in the temperature record. The number of the temperature record is also updated and pushed to the queue. The queue occupancy is checked every time after a temperature record is pushed to the queue. Once the queue occupancy equals the size of a page in SFLASH, the thread sets a semaphore signaling the thread handling SFLASH to start popping data from queue to write to SFLASH. A flowchart illustrating the operation is shown in Figure 10.

Figure 10. Flowchart Showing READ_TEMPERATURE State

The thread handling SFLASH (sflash_thread) performs an erase if the current page being written to belongs to a new sector and waits for the semaphore to be set. Once the semaphore is set, it pops the data from the queue and writes it to SFLASH. The size of the data written is one page (256 bytes) which is 16 temperature records. The size of the data written is chosen as one page to maximize efficiency of the write operation. The record number of the last temperature record that was stored in SFLASH is written to NVRAM in this thread after every page write.

The application code and Bluetooth stack run on the Arm® Cortex®-M4 core of the CYW20819 SoC. The application level source files for dual_spi_master is listed in Table 3.

Table 3. Application Source Files

File Name Comments
dual_spi_master.c This file contains the application_start() function which is the entry point for execution of the user application code after device startup and the threads that handle SPI communication with sensor and SFLASH.
cycfg_pins.c, cycfg_pins.h These files reside in the GeneratedSource folder under the application folder. They contain the pin configuration information generated using the Device Configurator tool.

SPI Slave

This section describes the operation of the Slave. As with the master, application_start() sets up the UART and then starts the Bluetooth stack. Once the stack is started (BTM_ENABLED_EVT), it initializes the ADC and then calls the initialize_app() function which handles the remaining functionality. Note that again the Bluetooth stack is running but we are not using Bluetooth in this application, so it doesn't do anything once the stack is started. The initialize_app() function sets up the SPI interface and then waits for and responds to SPI master commands. There are three commands that the slave will respond to:

Figure 11. Flowchart Showing Slave Operation

The Slave reads from SPI Rx buffers only when its Tx buffers are empty. If the Slave is unable to empty the Tx buffers after several retries, the SPI interface is reset. A flowchart illustrating the operation of the slave is shown in Figure 11.

The application code and Bluetooth stack run on the Arm® Cortex®-M4 core of the CYW20819 SoC. The application-level source files for “spi_slave_sensor” are listed in Table 4.

Table 4. Application Source Files

File Name Comments
spi_slave_thermistor.c This file contains the application_start() function which is the entry point for execution of the user application code after device startup.
thermistor_temp_db.c, thermistor_temp_db.h These files contain the function to map resistance to temperature values of the thermistor using a lookup table (from the thermistor datasheet).
cycfg_pins.c, cycfg_pins.h These files reside in the GeneratedSource folder under the application folder. They contain the pin configuration information generated using the Device Configurator tool.

Resources and Settings

SPI Master

Figure 12. Device Configurator

Figure 13. SPI1 Configuration

Figure 14. SPI2 Configuration

Figure 15. PUART Configuration

This section explains the ModusToolbox resources and their configuration as used for SPI Master. Note that all the configuration explained in this section has already been done in the code example. The ModusToolbox IDE stores the configuration settings of the application in the design.modus file. This file is used by the graphical configurators, which generate the configuration firmware. This firmware is stored in the application’s GeneratedSource folder. For example, the Peripherals section of the design file allows you to select the peripherals needed for the application and to configure them as needed. For pin assignment and configuration, review the Pins section of the design file.

Figure 12 shows the Device Configurator settings for this code example. The Device Configurator is used to enable/configure the peripherals and the pins used in the application. To launch the Device Configurator, double-click the design.modus file or click Configure Device in the Quick Panel. Any time you make a change in the Device Configurator, click File > Save to save the updated configuration.

Peripherals: The design uses two SPI instances and one PUART which are enabled under the Peripherals section. The SPI1 instance communicates with the SPI sensor and its configuration details are provided in Figure 13. The SPI2 instance communicates with the SFLASH and its configuration details are provided in Figure 14. The PUART configuration details are provided in Figure 15.

Pins: The pins used in the application are enabled in the Pins section of the Device Configurator. Table 5 provides more information on these pins.

Table 5. Pin Mapping Details for Master

Pin Alias Purpose
P32 UART_TX Used for PUART transmit (Tx)
P37 UART_RX Used for PUART receive (Rx)
P12 SPI_1_CS Chip select for sensor
P13 SPI_1_MOSI MOSI pin to sensor
P14 SPI_1_MISO MISO pin to sensor
P15 SPI_1_CLK Clock
P11 SPI_2_CS Chip select for SFLASH
P06 SPI_2_MOSI MOSI pin to SFLASH
P17 SPI_2_MISO MISO pin to SFLASH
P09 SPI_2_CLK Clock
P00 BUTTON Button

SPI Slave

Figure 16. Device Configurator for Slave

Figure 17. SPI1 Configuration

Figure 18. PUART Configuration

This section explains the ModusToolbox resources and their configuration as used for the SPI Slave. Note that all the configuration explained in this section has already been done in the code example. Figure 16 shows the Device Configurator settings for this code example.

Peripherals: The example uses a SPI and PUART peripheral. The configuration details of the SPI used to communicate with the master are provided in Figure 17. The configuration details of the PUART are provided in Figure 18.

Pins: The pins used in the application are enabled in the Pins section of the Device Configurator. Table 6 provides more information on these pins.

Table 6. Pin Mapping Details for Slave

Pin Alias Purpose
P32 UART_TX Used for PUART transmit (Tx)
P37 UART_RX Used for PUART receive (Rx)
P15 SPI_1_CS Chip select for sensor
P14 SPI_1_MOSI MOSI pin to sensor
P17 SPI_1_MISO MISO pin to sensor
P09 SPI_1_CLK Clock

Code Example

This code example includes two applications that demonstrate the operation of multiple Serial Peripheral Interface (SPI) interfaces using the CYW20819. The first application demonstrates operation of two SPI masters – one for collecting sensor data and the other for logging the data to external Flash. The second application demonstrates operation of an SPI slave which is used for providing sensor data to the first application.

BLE Initialization (dual_spi_master.c)

if(WICED_SUCCESS != wiced_bt_stack_init( bt_cback, NULL, NULL ))
{
    WICED_BT_TRACE("BT stack initialization failed \n\r");
}

The function wiced_bt_stack_init() initializes the Bluetooth controller and stack, along with registering a callback for Bluetooth event notifications. The function return value is wiced_result_t which will return WICED_BT_SUCCESS on successful initialization of the BT stack and WICED_BT_FAILED if some error occurs. The callback bt_cback is called to handle the BLE stack events and process.

Main loop (dual_spi_master.c)

wiced_result_t bt_cback( wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data )
{
    switch( event )
    {
    /* BlueTooth stack enabled*/
    case BTM_ENABLED_EVT:
        initialize_app();
        break;

    default:
        break;
    }
    return result;
}

BTM_ENABLED_EVT event is triggered once BLE stack initialization is complete. After occurrence of this event, main application will start executing with calling function initialize_app().

Peripherals initialization (dual_spi_master.c)

void initialize_app( void )
{
wiced_hal_gpio_register_pin_for_interrupt( WICED_GPIO_PIN_BUTTON_1, button_cback, NULL );
wiced_hal_gpio_configure_pin( WICED_GPIO_PIN_BUTTON_1, ( GPIO_INPUT_ENABLE | GPIO_PULL_UP | GPIO_EN_INT_FALLING_EDGE ), GPIO_PIN_OUTPUT_HIGH );

    wiced_hal_sflash_init();
        WICED_BT_TRACE("Size of sflash %d bytes\r\n", wiced_hal_sflash_get_size());
readBytes =  wiced_hal_read_nvram( WICED_NVRAM_VSID_START, (record), uint8_t *)&record, &status);
        if(0 == readBytes)
        {
        WICED_BT_TRACE("Read from NVRAM failed\n\r",record);
        record = 0;
        }
        curr_addr = sizeof(temperature_record) * record;
        new_record = ++record;

       wiced_rtc_init();

wiced_hal_pspi_init(SPI1, SPI_MASTER, INPUT_PIN_PULL_UP, GPIO_CFG(CS_1,CLK_1,MOSI_1,MISO_1), DEFAULT_FREQUENCY, SPI_LSB_FIRST, SPI_SS_ACTIVE_LOW, SPI_MODE_0, CS_1);

        spi_1 = wiced_rtos_create_thread();
if ( WICED_SUCCESS == wiced_rtos_init_thread(spi_1, PRIORITY_MEDIUM, "SPI 1 instance", spi_sensor_thread, THREAD_STACK_MIN_SIZE, NULL ) )
        {
        WICED_BT_TRACE( "SPI Sensor thread created\n\r" );
        }
        else
        {
        WICED_BT_TRACE( "Failed to create SPI Sensor thread \n\r" );
        }

        spi_2 = wiced_rtos_create_thread();
if(WICED_SUCCESS == wiced_rtos_init_thread(spi_2, PRIORITY_MEDIUM, "SPI 2 instance", sflash_thread, THREAD_STACK_MIN_SIZE, NULL))
        {
        WICED_BT_TRACE( "SFLASH thread created\n\r" );
        }
        else
        {
        WICED_BT_TRACE( "Failed to create SFLASH thread \n\r" );
        }

        WICED_BT_TRACE( "Press SW3 to read temperature records\n\r" );
        msg_q = wiced_rtos_create_queue();
        if(NULL == msg_q)
        {
        WICED_BT_TRACE("Queue creation error\r\n");
        }

if(WICED_SUCCESS != wiced_rtos_init_queue(msg_q, "queue", MESSAGE_SIZE, QUEUE_LENGTH))
        {
        WICED_BT_TRACE("Queue initialization failed \r\n");
        }

        sem = wiced_rtos_create_semaphore();    
}

In initialize_app(), the 2 SPI Interfaces, SFLASH, threads, message queue, semaphore and GPIO are initialized and corresponding callbacks are registered.

wiced_hal_gpio_register_pin_for_interrupt() and wiced_hal_gpio_configure_pin() are called to configure interrupt button, registering callback button_cback().

SFLASH is initialized using wiced_hal_sflash_init() and the sflash size is read using wiced_hal_sflash_get_size().

A NVRAM module using internal flash is used to store the last temperature record number that was stored in SFLASH, so that the application resumes without overwriting the stored records during reset or power failure. NVRAM value is read using wiced_hal_read_nvram().

RTC is initialized using wiced_rtc_init().

SPI is initialized using wiced_hal_pspi_init() and two threads for SPI1 and SPI2 are created & initialized using wiced_rtos_create_thread() and wiced_rtos_init_thread(). Corresponding callbacks are also registered here.

A message queue is created and initialized using wiced_rtos_create_queue() and wiced_rtos_init_queue().

Button callback (dual_spi_master.c)

static void button_cback( void *data, uint8_t port_pin )
{
if(rd_addr >= curr_addr)
    {
        WICED_BT_TRACE("No temperature records to be read \n\r");
    }

    while(rd_addr < curr_addr)
    {
no_of_bytes_read = wiced_hal_sflash_read(rd_addr, sizeof(temperature_record), (uint8_t*)&stored_temperature);
        if(sizeof(stored_temperature) != no_of_bytes_read)
        {
            WICED_BT_TRACE("SFLASH read failed \n\r");
        }
        else
        {
            rd_addr += sizeof(temperature_record);
            wiced_rtc_ctime(&(stored_temperature.timestamp),record_temperature);
WICED_BT_TRACE("Record #: %d | " "Time stamp: %s | " "Temperature:%d.%02d \n\r", stored_temperature.record_no, record_temperature, stored_temperature.dec_temp, stored_temperature.frac_temp);
        }
    }
}

The user can initiate a read operation on the SFLASH by pressing user button (SW3) on the CYW920819EVB-02 kit to obtain and display the stored temperature records. After button is pressed, button_cback() is called. Sflash content is read using wiced_hal_sflash_read() and current date and time is also noted using wiced_rtc_ctime().

SPI sensor thread callback (dual_spi_master.c)

void spi_sensor_thread(uint32_t arg )
{
while(WICED_TRUE)
        {
        switch(curr_state)
        {
        case SENSOR_DETECT:

            send_data.data = GET_MANUFACTURER_ID;
            send_data.header = PACKET_HEADER;

            spi_sensor_utility(&send_data,&rec_data);
            if(PACKET_HEADER == rec_data.header)
            {
                if(MANUFACTURER_ID == rec_data.data)
                {
                    WICED_BT_TRACE("Manufacturer: Cypress Semiconductor\n\r");
                    curr_state = READ_UNIT;
                    num_retries = RESET_COUNT;
                }
                else
                {
                    num_retries++;
                    WICED_BT_TRACE("Unknown manufacturer \n\r");
                }
            }
            else
            {
                num_retries++;
            }
            break;

        case READ_UNIT:

            /* Configuring send_data data packet to contain command GET_UNIT*/
            send_data.data = GET_UNIT;
            send_data.header = PACKET_HEADER;
            spi_sensor_utility(&send_data,&rec_data);
            if(PACKET_HEADER == rec_data.header)
            {
                if(UNIT_ID == rec_data.data)
                {
                    WICED_BT_TRACE("Unit: Celsius \n\r");
                    curr_state = READ_TEMPERATURE;
                    num_retries = RESET_COUNT;
                }
                else
                {
                    num_retries++;
                    WICED_BT_TRACE("Unknown unit \n\r");
                }
            }
            else
            {
                num_retries++;
            }
            break;

        case READ_TEMPERATURE:
            send_data.data = MEASURE_TEMPERATURE;
            send_data.header = PACKET_HEADER;
            spi_sensor_utility(&send_data,&rec_data);
            if(PACKET_HEADER == rec_data.header)
            {
                num_retries = RESET_COUNT;

                sampled_temp.dec_temp = rec_data.data / NORM_FACTOR;
                sampled_temp.frac_temp = rec_data.data % NORM_FACTOR;
                wiced_rtc_get_time(&(sampled_temp.timestamp));
                sampled_temp.record_no = new_record++;
                result = wiced_rtos_push_to_queue(msg_q,
                        &sampled_temp,
                        WICED_NO_WAIT );
                if(WICED_SUCCESS != result)
                {
                    WICED_BT_TRACE("Push failed \n\r");
                }
                result = wiced_rtos_get_queue_occupancy(msg_q, &count);
                if(WICED_SUCCESS != result)
                {
                    WICED_BT_TRACE("Queue occupancy is unknown\n\r");
                }
                if( count >= WATERMARK)
                {
                    wiced_rtos_set_semaphore(sem);
                }
            }
            else
            {
                num_retries++;
            }
            break;

        default:
            break;
        }
        if(num_retries > MAX_RETRIES)
        {
            curr_state = SENSOR_DETECT;
            num_retries = RESET_COUNT;
            wiced_hal_pspi_reset(SPI1);
        }
        wiced_rtos_delay_milliseconds(SLEEP_TIMEOUT, ALLOW_THREAD_TO_SLEEP);
    }
}

SPI master states are defined in this function as follows: SENSOR_DETECT, READ_UNIT and READ_TEMPERATURE.

In SENSOR_DETECT state, SPI Master checks for presence of the SLAVE by comparing the received packet to the expected Manufacturer ID.

During READ_UNIT, Master reads the setting for the Units in which the temperature is measured by the sensor.

In READ_TEMPERATURE state, the Temperature value is read by the master.

In all three cases, spi_sensor_utility() function is called which performs all the SPI transactions with SPI sensor.

SFLASH thread callback (dual_spi_master.c)
Code Snippet:
void sflash_thread(uint32_t arg )
{
while(WICED_TRUE)
     {
        sect_id = curr_addr % SECTOR_SIZE;
        if(0 == sect_id)
        {
            wiced_hal_sflash_erase(curr_addr, SECTOR_SIZE );
        }

        wiced_rtos_get_semaphore(sem,  WICED_WAIT_FOREVER);

        for(loop_count = 0; loop_count < WATERMARK ; loop_count++)
        {
result = wiced_rtos_pop_from_queue(msg_q,  &(sampled_temperature[loop_count]), WICED_WAIT_FOREVER );
        }
        if(WICED_SUCCESS == result)
        {
  no_of_bytes_written = wiced_hal_sflash_write(curr_addr,  sizeof(sampled_temperature), (uint8_t *)sampled_temperature);
            if(sizeof(sampled_temperature) != no_of_bytes_written)
            {
                WICED_BT_TRACE("SFLASH write failed \n\r");
            }
            else
            {
                curr_addr += (sizeof(sampled_temperature));
            }
        }
        else
        {
            WICED_BT_TRACE("Failed to pop data from queue\n\r");
        }

        record = sampled_temperature[--loop_count].record_no;
        writeBytes = wiced_hal_write_nvram( WICED_NVRAM_VSID_START,
                                            sizeof(record),
                                            (uint8_t *)&record,
                                            &status);
        if(0 == writeBytes)
        {
            WICED_BT_TRACE("Write to NVRAM failed \n\r");
        }
    }
}

sflash_thread() callback is invoked when SPI2 thread is initialized. In this function, data is pooped from the queue and written to the sflash. Firstly, depending on the location where data needs to be written, wiced_hal_sflash_erase() is used to erase the previous data. When the semaphore is set by SPI sensor thread, temperature data is popped from queue using wiced_rtos_pop_from_queue(). Then the popped data is written to sflash using wiced_hal_sflash_write(). After Obtaining the record number of the last record that was written in SFLASH, this value is then stored in NVRAM using a write operation wiced_hal_write_nvram().