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

 

Flash Driver

1 Introduction

 

Almost every embedded system needs a non-volatile memory to store the application code; flash device is the most common one nowadays because it can be erased and programmed electronically. Most embedded development IDE comes with a flash programming utility to facilitate the programming of the application code into a flash device. However, if your application requires in-field updates of the code or non-volatile data storage, you’ll need a flash driver yourself for the upper layer application code to call to reprogram your code or write data into the flash.

While most flash devices are similar, they vary in structure and commands. Reading data from flash is easy, but writing data and erasing memory are done through a series of commands. Therefore, the key code is a function of writing one byte completely. Once you have that function working correctly, you can write as many bytes as you want. Some flash devices support multiple writes in one command. Here is an example of flash driver for Atmel AT49BV040B. That flash is a 512k x 8, parallel interface device. A typical hardware interface is shown in Figure 1.

 

2 Hardware Interface

 

                                                                                      
Figure 1 AT49BV040B flash interfacing with a DSP chip

 

3 Programming


Reading data from flash is straightforward usually, while writing to flash requires specific attention. As long as you know how to write one byte into flash, you can write any number of data. So let’s focus on how to write one byte to flash and make sure it is written completely. This function shall include two parts; one is to write the byte into a memory, the other is to check when the write is completed. To detect the completion of a byte write, the device has two methods, data polling and toggle bit. We used the toggle bit method in the example shown below.

/*******************************************************************************************
* Function: SendByte
*
* Desc: This function writes a byte to an address in flash and wait for completion.
*
* Params:
* long lAddr - address to write to
* char value - value to write
*
* Returns: true if data is written to the address successfully, false otherwise
*
* Notes:
* 1 - None
*
*******************************************************************************************/

bool SendByte( const long lAddr, const char value )
{
    bool result;
    // set the address
    long *pFlashAddr = (long *)(FLASH_BASE_ADDR + lAddr);

    //write commands
    *pFlashAddr = value;

    // make sure the write was successful
    result = PollToggleBit(lAddr, value);

    return result;
}


/*******************************************************************************************
* Function: PollToggleBit
*
* Desc: This function polls the toggle bit I/O6 to see when the operation is complete
*
* Params:
* long lOffset - address offset
*
* Returns: true if data is written to the address successfully, false otherwise
*
* Notes:
* 1 - None
*
*******************************************************************************************/
bool PollToggleBit( const long lOffset )
{
    char val1, val2;    // 2 consecutive values read from flash
    char toggleBit;      // used to see if I/O6 is toggling
    long timeout = FLASH_POLL_TIMEOUT;    // timeout value

    while(timeout--)
    {
        // read the same location 2 times
        ReadByte(lOffset, &val1);
        ReadByte(lOffset, &val2);

        // check to see if bit 6 is toggling
        toggleBit = val1 ^ val2;

        // if bit 6 stops toggling and the data matches what it should be
        // the write or erase is complete

        if( !(toggleBit & 0x40) )
            break;
    }

    // check to see if there was a timeout
    return (timeout > 0);
 }

With the above function, now we can write data and erase the chip. Note that each of those actions requires a series of commands, as shown in Table 1.


Table 1 AT49BV040B Command Table


FLASH_BASE_ADDR is a base address macro determined by the chip select signal.

 

3.1 Write Data


/*******************************************************************************************
* Function: WriteByte
*
* Desc: This function write one byte to an address in flash.
*
* Params:
* long lAddr - address to write to
* long value - value to write
*
* Returns: true if data is written to the address successfully, false otherwise
*
* Notes: None
* Addr Data Addr Data Addr Data Addr Data
* 555  AA   AAA  55    555 A0     Addr Data
*******************************************************************************************/
bool WriteByte( const long ulAddr, const char value )
{
    //write commands
    if (SendByte(0x555, 0xaa))
    {
        if (SendByte(0xaaa, 0x55))
        {
            if (SendByte(0x555, 0xa0))
            {
                if (SendByte(lAddr, value))
                {
                    return true;
                }
            }
        }
    }

    return false;
}

The write wave form (wrting data 0xA to address 0x0) is shown in Figure 1.

 

 

3.2 Chip Erase


/*******************************************************************************************
* Function: Flash_EraseChip
*
* Desc: This function sends an "erase all" command to the flash
*
* Params: none
*
* Returns: true - if erase is successful, false otherwise
*
* Notes: Erase command:
* Addr Data Addr Data Addr Data Addr Data Addr Data Addr Data
* 555  AA   AAA  55    555   80    555  AA   AAA  55    555  10
*
*******************************************************************************************/
bool Flash_EraseChip(void)
{
    bool result;     // flag to indicate error

    //write commands
    result = SendByte(0x555, 0xaa);
    if (result)
    {
        result = SendByte(0xaaa, 0x55);
        if (result)
        {
            result = SendByte(0x555, 0x80);
            if (result)
            {
                result = SendByte(0x555, 0xaa);
                if (result)
                {
                    result = SendByte(0xaaa, 0x55);
                    if (result)
                    {
                        result = SendByte(0x555, 0x10);
                    }
                }
            }
        }
    }

    return result;
}

 

3.3 Sector Erase

 

/*******************************************************************************************
* Function: Flash_EraseSector
*
* Desc: This function sends an "erase sector" command to the flash
*
* Params: long nSector - the sector number to be erased
*
* Returns: true - if erase is successful, false otherwise
*
* Notes: Erase command:
* Addr Data Addr Data Addr Data Addr Data Addr Data Addr Data
* 555 AA AAA 55 555 80 555 AA AAA 55 addr 30
* where: addr - any address within the sector
*******************************************************************************************/
bool Flash_EraseSector(long nSector)
{
    bool result;       // flag to indicate error
    long lStartAddr, lEndAddr;

    //get the start address of the sector
    Flash_GetSectorStartEnd(nSector, &lStartAddr, &lEndAddr);

    //write commands
    result = SendByte(0x555, 0xaa);
    if (result)
    {
        result = SendByte(0xaaa, 0x55);
        if (result)
        {
            result = SendByte(0x555, 0x80);
            if (result)
            {
                result = SendByte(0x555, 0xaa);
                if (result)
                {
                    result = SendByte(0xaaa, 0x55);
                    if (result)
                    {
                        result = SendByte(lStartAddr, 0x30);
                    }
                }
            }
        }
    }

    return result;
}

 

3.4 Read Data


/*******************************************************************************************
* Function: ReadByte
*
* Desc: This function reads one byte from an address in flash.
*
* Params:
*     long lAddr - the address to read from
*     char pValue - pointer to store the value read from flash
*
* Returns: void
*
* Notes: None
*
*******************************************************************************************/
void ReadByte( const long lAddr, char *pValue )
{
    // set flash address to where we want to read
    long *pFlashAddr = (long *)(FLASH_BASE_ADDR + lAddr);

    // read the value
    *pValue = *pFlashAddr;
}

The read wave form (reading data from address 0 to 9) is shown in Figure 2.

 

 

 4 Source Code

 

The complete driver source code is available for download.

 

    ES_AT49BV040B.c

    ES_AT49BV040B.h