Home
General Guide
Register File
Boot Sequence
BLDC Motor FOC
Serial Comm Driver
Flash Driver
NVRAM Driver
RVDT Driver
Renesas
Microchip
Texas Instruments
Analog Devices
Mobile Devices
.NET Tips
Miscellaneous
Contact Us
Forum

 

Non-Volatile Memory Driver

1 Introduction


Non-volatile memory is often used in embedded applications for non-volatile data storage. EEPROM and FRAM are commonly used for that purpose because they are easy to read and write in comparison with flash devices. EEPROM and FRAM are small in size, and usually in serial interface. Some devices provide SPI (Serial Peripheral Interface) in addition to I/O interface. Therefore, data are clocked in or out serially. FRAM has advantages over EEPROM, because it features rapid writes and much higher write cycles. Here is an example how to write a SPI driver for Ramtron FM25CL64.


2 Hardware Interface


FM25CL64 supports two types of hardware interface, SPI interface and I/O interface. The former consists of four wires; the latter consists of four or three wires in which SI and SO are combined. Four signals for SPI are SPICS, SPICLK, MOSI, and MISO. Figure 1 demonstrates that FM25CL64 interfaces with Analog Device ADSP-21369 via SPI.



Figure 1
FM25CL64 interfaces with Analog Device ADSP-21369 via SPI

Figure 2 demonstrates that FM25CL64 interfaces with a microcontroller via three I/O pins. It is pretty simple to emulate the serial interface using I/O pins. Note that in this interface, the SI and SO can be multiplexed into one bi-directional I/O pin to save the number of pins.



Figure 2
FM25CL64 interfaces with a microcontroller via three I/O pins


3 Chip Select Signal Selection


Any flag signal FLAG14-0 of ADSP-21369 could be used for SPICS, however, only FLAG3-0 can be controlled by SPICTL register, which means that toggling of flags can be done automatically when SPICTL. CPHASE = 0, or manually (by your code) when SPICTL. CPHASE = 1. If you use any one of FLAG14-3, you must toggle it through software. By default, MOSI, MISO, and SPICLK are multiplexed with other functions on pin DPI_01, DPI_02, and DPI_03 respectively, while FLAG3-0 used as SPIFLG3-0 are routed to DPI_08 - _05 respectively. However, those SPI signals can be routed to other DPI pins, in which case, toggling flags must be done by software.

In the following example, signals are routed as shown in figure 1, i.e.,
MOSI -> DPI_01
MISO -> DPI_02
SPICLK -> DPI_03
SPICS -> DPI_04


4 Driver Programming


Driver programming includes FRAM_Open(), FRAM_Write(), FRAM_Read(), and FRAM_Close() functions.


4.1 FRAM_Open


FRAM_Open() function includes signal routing, the configuration of SPI control register, baud rate register.


4.1.1 Signal Routing


Routing a signal of peripheral module to an external pin can be done easily with SRU routing macros. Please note that the output pin buffer shall be enabled, while input pin buffer shall be disabled.

/*********************************************************************************
* Function: DSP_SRU_SPI
*
* Desc: This function configures SRU for SPI interface
*
* Params: None
*
* Returns: boolean
*
* Notes:
*
*********************************************************************************/
bool DSP_SRU_SPI(void)
{
    //set DPI_01 as SPI MOSI
    SRU2(SPI_MOSI_O, DPI_PB01_I);
    SRU2(HIGH, DPI_PBEN01_I);

    //set DPI_02 as SPI MISO
    SRU2(DPI_PB02_O, SPI_MISO_I);
    SRU2(LOW, DPI_PBEN02_I);

    //set DPI_03 as SPI CLK
    SRU2(SPI_CLK_O, DPI_PB03_I);
    SRU2(HIGH, DPI_PBEN03_I);

    //set DPI_04 and FLAG0 as SPI CS
    SRU2(SPI_FLG0_O, DPI_PB04_I);
    SRU2(HIGH, DPI_PBEN04_I);

    return true;
}


4.1.2 SPI Control and Baud Rate Register Configuration


SPI Baud rate is configured by setting a divisor value to SPIBAUD register.
Baud rate = fpclk / (4 x divisor)


Where
        fpclk – peripheral clock which is ½ of core clock

In our example, fpclk = 160 MHz, and the FRAM can run at 20 MHz, so we have divisor value 2. Please note that the bit[15:1] of SPIBAUD register are used for the divisor value, which means that the register value is twice as much as the divisor value when you look at the register value from the IDE.

Write word length, transfer format, and so on appropriately to the control register. To control Ramtron FRAM, the clock polarity shall be set to active low. In order to read and to write any number of bytes, the chip select signal shall be active during the entire buffer transmission, it is easier to use core driven approach to control the chip select signal, so we set SPICTL.CPHASE = 1.


4.1.3 Source Code

/*******************************************************************************************
* Function: FRAM_Open
*
* Desc: This function sets up hardware SPI interface and configures control registers
*
* Params: None
*
* Returns: true if opening the port successfully, false otherwise
*
* Notes: None
*
*******************************************************************************************/
bool FRAM_Open(void)
{
    int temp;

    ST_SPICTL spictl;

    //set up hardware interface
    DSP_SRU_SPI();

    //SPI DMA is not used
    SPIDMAC.ALL = 0;

    //set SPI baud rate
    SPIBAUD.BIT.BAUD_DIVISOR = FRAM_BAUD_RATE_DIVISOR;

    //configure flag0 as chip select
    SPIFLG.BIT.DS0EN = 1;

    //configure SPI control register
    spictl.ALL = 0;
    spictl.BIT.TIMOD = 1;     //mode 1
    spictl.BIT.GM = 1;          //new data overwrites previous one
    spictl.BIT.ISSEN = 0;    
//disable SPIDS to free that pin for chip select
    spictl.BIT.SPIEN = 1;     //SPI enable
    spictl.BIT.SPIMS = 1;    //master
    spictl.BIT.OPD = 0;       //open drain mode disabled as we use 1 (master) - 1 (slave) connection
    spictl.BIT.SENDZ = 1;   //send zeros
    spictl.BIT.WL = 0;         //word width 8
    spictl.BIT.MSBF = 1;     //MSB first
    spictl.BIT.CLKPL = 1;    //clock polarity active low
    spictl.BIT.CPHASE = 1; //control chip select manually
    spictl.BIT.ILPBK = 0;     //internal loop back disabled
    SPICTL.ALL = spictl.ALL;

    //write status register to disable write protection
    WriteFramStatusRegister(FARM_INIT_STATUS);

    //read status register
    temp = ReadFramStatusRegister();

    if (temp == FARM_INIT_STATUS)
    {
        return true;
    }
    else
    {
        return false;
    }
}


4.2 FRAM_Write


FRAM_Write() function writes a number of words to FRAM memory. The sequence of writing a word is write enable first, followed by write command, two bytes address, and the data to be written. There are two notes worth mentioning.


4.2.1 Write Enable


Write Enable command must be sent as a separate command from other writing or reading command, which means that the chip select signal must be in separate cycle. It won’t work if the Write Enable command is followed by a writing command in one chip select signal.


4.2.2 SPISTAT.RXS


In master mode, the SPI generates clock signals on SPICLK pin during a transmission, in which data is shifted out of MOSI and shifted in from MISO simultaneously, no matter whether a slave device is sending out data. During a transmission, SPIRX is loaded with whatever on MISO; SPISTAT.RXS is set after the transmission is complete. So SPIRX must be read or flushed to clear the RXS bit. If the data is what you wait for, get the data; if not, discard the data.


4.2.3 Write Wave Form


In the wave form, signal 0 is the /CS, signal 1 is SPICLK, signal 2 is MOSI, and signal 4 is MISO.



4.2.4 Source Code


/*******************************************************************************************
* Function: FRAM_Write
*
* Desc: This function writes a buffer to FRAM device
*
* Params:
* int startAddr - address in FRAM to start the writes at
* int length - number of elements to write, in this case bytes
* int *pData - pointer to data buffer
*
* Returns: bool - true if writing is successful, false otherwise
*
* Notes: None
*
*******************************************************************************************/
bool FRAM_Write( int startAddr, int length, int *pData )
{
    int i;
    int absAddr;

    absAddr = FRAM_START_ADDR + startAddr;

    //write enable command
    EnableFramWrite();

    //assert CS
    AssertSPI_CS();

    //write command
    WriteWordToSPI(FRAM_WRITE);

    //high byte address
    WriteWordToSPI(absAddr >> 8);

    //low byte address
    WriteWordToSPI(absAddr);

    //write data to FRAM sequentially
    for (i = 0; i < length; i++)
    {
        WriteWordToSPI(*pData++);
    }

   
//de-assert CS
    DeassertSPI_CS();

    return true;
}


4.3 FRAM_Read


FRAM_Read() function read a number of data from FRAM memory. The sequence of reading a word is read command first, followed by two bytes of address, then a dummy write to generate 8 clocks to clock out data bits, which are shifted to RXSPI register.


4.3.1 Read Wave Form


 


4.3.2 Source Code


/*******************************************************************************************
* Function: FRAM_Read
*
* Desc: This function reads data from FRAM device to a buffer
*
* Params:
* int startAddr - address in FRAM to start the reading at
* int length - number of bytes to read
* int *pData - pointer to data buffer
*
* Returns: bool - true if reading is successful, false otherwise
*
* Notes: None
*
*******************************************************************************************/
bool FRAM_Read( int startAddr, int length, int *pData )
{
    int i;
    int absAddr;

    absAddr = FRAM_START_ADDR + startAddr;

    //assert CS
    AssertSPI_CS();

    //read command
    WriteWordToSPI(FRAM_READ);

    //high byte address
    WriteWordToSPI(absAddr >> 8);

    //low byte address
    WriteWordToSPI(absAddr);

    //read the buffer up to NVM_BUFFER_SIZE items
    for (i = 0; i < length; i++)
    {
        //dummy write to generate 8 clks to clock data into SPIRX
        *pData++ = WriteWordToSPI(0);
    }

    //de-assert CS
    DeassertSPI_CS();

    return true;
}


4.4 FRAM_Close


FRAM_Close() function disables the SPI module to close the driver.


4.4.1 Source Code


/*******************************************************************************************
* Function: FRAM_Close
*
* Desc: This function closes FRAM device driver.
*
* Params: None
*
* Returns: bool - true if successful, false otherwise
*
* Notes: None
*
*******************************************************************************************/
bool FRAM_Close(void)
{
    SPICTL.BIT.SPIEN = 0;

    return true;
}


4.5 Write/Read Status Register


Before wring to FRAM memory, an appropriate Write Protection command shall be written to the Status register to set up the protection area.
According to the tables above, write 0x80 to the status register if you chose no protection. You shall read back the status register and get the same value 0x80 if the /WP pin is at high level. Here is the code to write/read the status register.

 

4.5.1 Write Status Register


/*******************************************************************************************
* Function: WriteFramStatusRegister
*
* Desc: This function writes a word to the 8-bit status register of the FRAM
*
* Params: int status - status value
*
* Returns: bool - true if successful, false otherwise
*
* Notes: None
*
*******************************************************************************************/
bool WriteFramStatusRegister(int status)
{
    //write enable command
    EnableFramWrite();

    //assert CS
    AssertSPI_CS();

    //write status register
    WriteWordToSPI(FRAM_WRSR);

   
//write status register
    WriteWordToSPI(status);

   
//de-assert CS
    DeassertSPI_CS();

    return true;
}

 

4.5.2 Read Status Register


/*******************************************************************************************
* Function: ReadFramStatusRegister
*
* Desc: This function reads the 8-bit status register from the FRAM
*
* Params: None
*
* Returns: Status of the register
*
* Notes: None
*
*******************************************************************************************/

int ReadFramStatusRegister(void)
{
    int status;

    //assert CS
    AssertSPI_CS();

   
//read status register
    WriteWordToSPI(FRAM_RDSR);

    //write status register with dummy word
    status = WriteWordToSPI(0);

    //de-assert CS
    DeassertSPI_CS();

    return status;
}


4.6 Complete Source Code Download


The complete source code of the driver can be downloaded here.


ES_FRAM.c
ES_FRAM.h