Remote Monitoring & Control

Enter Your Electronics & Design Project for a chance to win up to a $200 Shopping Cart of Product!

Back to The Project14 homepage

Project14 Home
Monthly Themes
Monthly Theme Poll

 

When you want to store information in any embedded project then you can either use external storage devices or internal storage of embedded controller. The internal storage space (SRAM or EEPROM) is usually very small with limited number of erase/write cycles. Therefore external storage devices are better choice especially due to their low cost, easy replacement and high number of erase/write cycles.

PSoC6 (CY8CKIT-062-WiFi-BT) kit has onboard 3V 512 Mbit (64 Mbyte) QSPI Flash Memory (S25FL512S). Cypress has also provided an example to read and this external flash memory (CE220823) but these examples are for PSoC Creator and ModusTool Box IDEs. So these examples cannot be used any application with WICED-Studio. Also the PSoC6 SDK in WICED studio does not provide all the functionality. Another problem with Wireless application is that it store some data on this flash and only 16MB is accessible. If you will write any data at the start of this external flash then it might stop working unlike other two IDE.

In this project we will write an external flash test code which will write data at those locations which are not erased during reprogramming and not used by filesystem.bin. After writing some data at these locations we will use slightly modified Cypress example to read that data. and verified that reprogramming didn't erase that data.

I have also modified the wiced SDK (wiced_platform.h) and platform files (CY8CKIT_062=> platform.c & platform.h) to add support of all the onboard LED lights. In this WICED project I will be using these newly added LED lights just to indicate the completion of FLASH operation. These modified files are attached below.

 

WICED Studio Code:

In WICED Studio we easily access the external flash by using the SDK function that automatically initialize all the QSPI settings and configure the GPIO accordingly.

Function to initialize external flash is;

int init_sflash( /*@out@*/ sflash_handle_t* const handle, /*@shared@*/ void* peripheral_id, sflash_write_allowed_t write_allowed_in );

 

The above mentioned function is available at WICED=>platform=>MCU=>PSoC6=>peripheral =>spi_flash folder.

If we analyze this function we found that WICED studio is only using 16MB of external memory and then dividing that memory into normal and backup sectors.

In this example we use the FLASH address of inside the backup sector. Choose the external memory address of

uint32_t extMemAddress = 16000000 ;

 

Caution! do not  use the sflash_chip_erase.

 

We can erase the flash sector of our extMemAddress by using the function shown below;

int sflash_sector_erase ( const sflash_handle_t* handle, unsigned long device_address )

 

After erasing the desired sector we can write data at that location by using this function.

int sflash_write( const sflash_handle_t* const handle, unsigned long device_address, /*@observer@*/ const void* const data_addr, unsigned int size )

 

After writing any data to external memory we read that data to verify the success of our earlier operations.

int sflash_read( const sflash_handle_t* const handle, unsigned long device_address, /*@out@*/ /*@dependent@*/ void* const data_addr, unsigned int size )

The final code to test the external flash will look like this,

/******************************************************************************
* File Name: main.c
*
* Version 2.0
*
* Description:
*     Demonstrates interfacing with an external memory by using the Serial Memory
*     Interface (SMIF) hardware block in Quad Serial Peripheral Interface (QSPI)
*     mode.
*
* Related Document: CE220823_PSoC6_SMIFMemWriteAndRead.pdf
*
*******************************************************************************
* Copyright (2018-2019), Cypress Semiconductor Corporation. All rights reserved.
*******************************************************************************
* This software, including source code, documentation and related materials
* ("Software"), is owned by Cypress Semiconductor Corporation or one of its
* subsidiaries ("Cypress") and is protected by and subject to worldwide patent
* protection (United States and foreign), United States copyright laws and
* international treaty provisions.  Therefore, you may use this Software only as
* provided in the license agreement accompanying the software package from which
* you obtained this Software ("EULA").
*
* If no EULA applies, Cypress hereby grants you a personal, non-exclusive,
* non-transferable license to copy, modify, and compile the Software source code
* solely for use in connection with Cypress’s integrated circuit products.  Any
* reproduction, modification, translation, compilation, or representation of
* this Software except as specified above is prohibited without the express
* written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress
* reserves the right to make changes to the Software without notice. Cypress
* does not assume any liability arising out of the application or use of the
* Software or any product or circuit described in the Software. Cypress does not
* authorize its products for use in any products where a malfunction or failure
* of the Cypress product may reasonably be expected to result in significant
* property damage, injury or death ("High Risk Product"). By including Cypress's
* product in a High Risk Product, the manufacturer of such system or application
* assumes all risk of such use and in doing so agrees to indemnify Cypress
* against all liability.
*******************************************************************************/
#include "wiced.h"
#include "spi_flash.h"
#include "stdio.h"
#include "string.h"

#define PACKET_SIZE             (64u)     /* Memory Read/Write size */
#define MAX_ADDRESS_SIZE        (3u)      /* Memory address size */
//#define NUM_BYTES_PER_LINE      (16u)     /* Used when array of data is printed on the console */
//#define LED_TOGGLE_DELAY_MSEC   (1000u)   /* LED blink delay */

void CheckStatus(char *message, uint32_t status)
{
    if(0u != status)
    {
        printf("\n================================================================================\n");
        printf("\nFAIL: %s\n", message);
        printf("Error Code: 0x%08lX\n", status);
        printf("\n================================================================================\n");
        while(true) /* Wait forever here when error occurs. */
        {
            wiced_led_set_state(WICED_LED_INDEX_3,WICED_LED_ON);
            wiced_rtos_delay_milliseconds( 500 );
            wiced_led_set_state(WICED_LED_INDEX_3,WICED_LED_OFF);
            wiced_rtos_delay_milliseconds( 500 );
        }
    }
}

void application_start(){

    int ret=-1;


    wiced_init();

    sflash_handle_t qspi_flash_handle;
    sflash_write_allowed_t qspi_flash_allowed_write_in = SFLASH_WRITE_ALLOWED;
    void* qspi_flash_peripheral_id=0;

    unsigned long flash_size=0;


    ret = init_sflash(&qspi_flash_handle, qspi_flash_peripheral_id, qspi_flash_allowed_write_in);
    sflash_get_size(&qspi_flash_handle, &flash_size);
    WPRINT_APP_INFO(("Memory Size: %lu | status: %d\r\n", flash_size, ret));

    /* Initialize the transfer buffers */
    uint8_t txBuffer[PACKET_SIZE];
    uint8_t rxBuffer[PACKET_SIZE];

    /* Initialize tx buffer and rx buffer */
    for(uint32_t index = 0; index < PACKET_SIZE; index++)
    {
        txBuffer[index] = (uint8_t) (index & 0xFF);
        rxBuffer[index] = 0;
    }

//    uint32_t extMemAddress = 260000 ;
    uint32_t extMemAddress = 16000000 ;

    ret = -1;
    ret = sflash_sector_erase(&qspi_flash_handle, extMemAddress);
    WPRINT_APP_INFO(("Erase Sector | status: %d\r\n", ret));

    ret = -1;
    ret = sflash_write(&qspi_flash_handle, extMemAddress, txBuffer, PACKET_SIZE);
    WPRINT_APP_INFO(("Write Data: %d | status: %d\r\n", PACKET_SIZE, ret));


    ret = -1;
    ret = sflash_read(&qspi_flash_handle, extMemAddress, rxBuffer, PACKET_SIZE);
    WPRINT_APP_INFO(("Read Data: %d | status: %d\r\n", PACKET_SIZE, ret));

    for (int i=0; i<PACKET_SIZE; i++)
        WPRINT_APP_INFO(("txBuffer[%d] = %d | rxBuffer[%d] = %d\n", i, txBuffer[i], i, rxBuffer[i]));

    CheckStatus("Read data does not match with written data. Read/Write operation failed.", memcmp(txBuffer, rxBuffer, PACKET_SIZE));

    WPRINT_APP_INFO(("\n================================================================================\n"));
    WPRINT_APP_INFO(("\nSUCCESS: Read data matches with written data!\n"));
    WPRINT_APP_INFO(("\n================================================================================\n"));

    while(1){
        wiced_led_set_state(WICED_LED_INDEX_4,WICED_LED_ON);
        wiced_led_set_state(WICED_LED_INDEX_5,WICED_LED_OFF);
        wiced_rtos_delay_milliseconds( 1000 );
        wiced_led_set_state(WICED_LED_INDEX_4,WICED_LED_OFF);
        wiced_led_set_state(WICED_LED_INDEX_5,WICED_LED_ON);
        wiced_rtos_delay_milliseconds( 1000 );
    }
}

 

Code from Cypress example:

We will use the CheckStatus() function as it is.

 

void CheckStatus(char *message, uint32_t status)
{
    if(0u != status)
    {
        printf("\n================================================================================\n");
        printf("\nFAIL: %s\n", message);
        printf("Error Code: 0x%08lX\n", status);
        printf("\n================================================================================\n");
        while(true) /* Wait forever here when error occurs. */
        {
            wiced_led_set_state(WICED_LED_INDEX_3,WICED_LED_ON);
            wiced_rtos_delay_milliseconds( 500 );
            wiced_led_set_state(WICED_LED_INDEX_3,WICED_LED_OFF);
            wiced_rtos_delay_milliseconds( 500 );
        }
    }
}

 

Copy these two from PSoC example but modify the MAX_ADDRESS_SIZE to 3 to meet the WICED SMIF driver library.

 

#define PACKET_SIZE (64u)    /* Memory Read/Write size */
#define MAX_ADDRESS_SIZE (3u)    /* Memory address size */

 

Also the code lines of comparing the write and read data will be the same.

 

CheckStatus("Read data does not match with written data. Read/Write operation failed.", memcmp(txBuffer, rxBuffer, PACKET_SIZE));
WPRINT_APP_INFO(("\n================================================================================\n"));
WPRINT_APP_INFO(("\nSUCCESS: Read data matches with written data!\n"));
WPRINT_APP_INFO(("\n================================================================================\n"));

 

Modified Modus Toolbox Code:

Download the External flash example for modus toolbox from link given at the END. Open the project in modustool box and modify few code lines as shown below.

External Flash testing

Modify the address as shown below;

uint8_t extMemAddress[MAX_ADDRESS_SIZE] = {0xF4, 0x24, 0x00, 0x00};

 

This code will be used to verify the earlier stored data. This address is choosen to make sure that reprogramming using WICED Studio does not effect it.

After running the Flash testing code created in WICED Studio, we will reprogram the PSoC6 device with some other program and then use this code to read the earlier saved flash data.

Flash Testing:

 

ModusTool Box and PSoC Creator Example: CE220823: PSoC6 - SMIF memory write and read operation

 

PART 1: Micro Monster - Succulent Plants Monitoring System

PART 2: Establishing and Testing the Secure Connection

PART 3: Remote Device Restart, Factory Reset and Data storage on External Flash

PART 4: Remote Firmware Download and Update

PART 5: Sensors Interfacing

PART 6: Final Testing and Demo