This post is part of my Roadtest Review of Cypress PSoC 62S2 Wi-Fi & BT5.0 Pioneer Dev Kit - Review. My review is splitted into multiple reviews and tutorials. Main page of review contains brief description of every chapter. Some projects are implemented in multiple variants. Main page of review contains brief description about every chapter, project and variants and contains some reccomendations for reading.

 

Table of Contents

 

Project 3 – FRAM

In this project I will make application that uses onboard FRAM (it is external memory from the perspective of main MCU). Application example will show program that print numbered messages over UART in infinite loop. When power loss (and then restore) occur application will continue with numbering messages at the same number as it was when power loss occurred. Code of this sample is quite easy in when implemented using both libraries. More detailed overview of FRAM’s details is presented in chapter Review of onboard peripherals.

 

This is first variant of project. It uses serial-flash library provided by Cypress. Second variant is based on HAL library.

At the beginning create project based on Empty PSoC6 App template and integrate retarget-io and serial-flash libraries. Picture based tutorial you can find in Project 1 – low level variant. At the beginning lets configure memories used on board using QSPI Configurator which is available in Quick Panel window in Tools section. The first memory is preconfigured but we need to configure FRAM which is connected in slot 2 (not 1) and it is CY15B104QSN. The configuration file has no configuration for QPI mode. We can define it yourself or just use less efficient DPI mode instead. Because in this example I do not need ultra high performance I will use DPI mode instead. In Data Select select the wires that contain 0 in name. Enable memory mapped, start address set immediately after range where the Flash is mapped. It is 0x1C000000. Then enable Write Enable and Config Data in Flash. It should look like on the following image.

 

Then save changes using Save button in toolbar. It will automatically generate source files which include our setting. Now we can simply use memory using serial-flash library.

At beginning after initialization of board features add initialization of retarget-io library which enables printf function in the way that it will forward all output to UART. This could be done using cy_retarget_io_init function.

 

result = cy_retarget_io_init(CYBSP_DEBUG_UART_TX, CYBSP_DEBUG_UART_RX, 115200);
if (result != CY_RSLT_SUCCESS) {
    CY_ASSERT(0);
}

 

Now we will initialize serial-flash library and initialize SMIF module. We use FRAM which is second configured memory (first is flash). Configuration for memory is available in array smifMemConfigs. Initialization function requires definition of data, clock and slave select ports. I mentioned them directly, but you can use predefined constants instead. Last parameter is frequency of clock. I will use 50 MHz. Because I am using DPI mode only I can run safely at this frequency without configuring wait states.

 

result = cy_serial_flash_qspi_init(smifMemConfigs[1], P11_6, P11_5, P11_4, P11_3, NC, NC, NC, NC, P11_7, P11_0, 50000000);
if (result != CY_RSLT_SUCCESS) {
    CY_ASSERT(0);
}

 

Now I declare variable which will be used as counter for messages.

 

uint32_t i;

 

Now I define macro which will contains address of memory in FRAM that is used to store nonvolatile backup of I variable. This should be any number in range 0 to (512 KiB – 4 Bytes). I am using for example address 16.

 

#define FRAM_I 0x10

 

I will initialize it with value read from FRAM. For reading from FRAM I will use RFRAM function which I will write later. This is last stored value which was stored before power loss occurs. If the value from fram is out of range (0 to 500) I will reinitialize it to 0. This normally happens only at first start of application or in time when some another application which I developed earlier overwrote FRAM with some other data. In case of first start value would be 0xFFFFFFFF (it is 4294967295 in decimal).

 

uint32_t initialValue = RFRAM(FRAM_I);
if (initialValue > 500) {
      initialValue = 0;
}
i = initialValue;

 

Now I print the value loaded from SRAM and wait for a while after it.

 

printf("Restored value counter value to: %lu\r\n", initialValue);
cyhal_system_delay_ms(2000);

 

And now I will write an infinite loop which will print numbered messages and backup variable I to FRAM.

 

while (1) {
      for (; i <= 500; i++, WFRAM(FRAM_I, i)) {
            printf("Hello RoadTest! Message no. %lu\r\n", i);
            cyhal_system_delay_ms(100);
      }
      i = 0;
}

 

Now lets write RFRAM function. It will call cy_serial_flash_qspi_read function with address and buffer for data. It is simple with serial-flash library.

 

uint32_t RFRAM(uint32_t address) {
 uint32_t output;
 cy_rslt_t result;

    result = cy_serial_flash_qspi_read(address, sizeof(uint32_t), (uint8_t*)&output);
    if (result != CY_RSLT_SUCCESS) {
        CY_ASSERT(0);
    }

    return output;
}

 

WFRAM function is similar and easy with serial-flash library. While it looks like one operation. Library internally executes two transactions. First one is Write Enable and second one is write itself. FRAM (and other serial memories) always require enabling write before writing data.

 

void WFRAM(uint32_t address, uint32_t value) {
 cy_rslt_t result;

    result = cy_serial_flash_qspi_write(address, sizeof(uint32_t), (uint8_t*)&value);
    if (result != CY_RSLT_SUCCESS) {
        CY_ASSERT(0);
    }
}

 

Now you can run application. Power loss you can simulate using XRES button or you can disconnect MCU from power using Power button in Cypress Programmer utility. Following video shows how application works.

 

 

For the experiment I reconfigured application to using SPI mode and lowered frequency from 50 MHz to 1 MHz. Now let’s see what happens on the bus using Logic analyzer. I have connected logic analyzer to memory using following connection.

 

So now I can see what happened on the bus. If you look for overall view it looks as presented on following image. Every 100ms there are some SPI operation on the bus.

 

Now let’s look at the detail of one operation (others have the same format and differs only in number stored in data).

 

There are two operations. The first is command 0x06 which is Write Enable command. The second operations consist of transmitted bytes 0x02 0x00 0x00 0x10 0xA8 0x01 0x00 0x00. The operation code 0x02 means Write operation, then follows 3 bytes of address (0x000010) which is the same address as specified in FRAM_I macro, and then follows four bytes of data (0xA8 0x01 0x00 0x00). Because ARM of PSoC6 is little endian it is uint32_t of value 0x000001A8 (424 in decimal). It is the value of message which was printed at the time when this was sampled.

 

That’s all for now. You have seen that accessing memory is easy with serial-flash library. Provided tools simplify integration of external memory to minimum required work. If you are interesting about details of FRAM, I recommend reading chapter Review of onboard peripherals. In this chapter I describes FRAM’s in more details including details about lifespan of memory when application writes to memory very frequently (which our app created in this tutorial does) and why I used FRAM instead of normal FLASH.