Add support for a new flash device

To support a new flash device, a configuration file must be written that describes the device characteristics, such as page size, number of pages and commands for reading, writing and erasing data. This information can be found in the datasheet for the flash device. Many devices available in the market can be described using these configuration parameters; those that cannot are unsupported.

The configuration file for the Numonyx M25P10-A is shown below. The device is described as an initializer for a C structure, the values of which are described in the following sections.

10,                     /* 1.  libflash device ID */
256,                    /* 2.  Page size */
512,                    /* 3.  Number of pages */
3,                      /* 4.  Address size */
4,                      /* 5.  Clock divider */
0x9f,                   /* 6.  RDID cmd */
0,                      /* 7.  RDID dummy bytes */
3,                      /* 8.  RDID data size in bytes */
0x202011,               /* 9.  RDID manufacturer ID */
0xD8,                   /* 10. SE cmd */
0,                      /* 11. SE full sector erase */
0x06,                   /* 12. WREN cmd */
0x04,                   /* 13. WRDI cmd */
PROT_TYPE_SR,           /* 14. Protection type */
{{0x0c,0x0},{0,0}},     /* 15. SR protect and unprotect cmds */
0x02,                   /* 16. PP cmd */
0x0b,                   /* 17. READ cmd */
1,                      /* 18. READ dummy bytes*/
SECTOR_LAYOUT_REGULAR,  /* 19. Sector layout */
{32768,{0,{0}}},        /* 20. Sector sizes */
0x05,                   /* 21. RDSR cmd*/
0x01,                   /* 22. WRSR cmd */
0x01,                   /* 23. WIP bit mask */

Libflash Device ID

10, /* 1. libflash device ID */

This value is returned by libflash on a call to the function fl_getFlashType so that the application can identify the connected flash device.

Page Size and Number of Pages

10,                     /* 1.  libflash device ID */
256,                    /* 2.  Page size */

These values specify the size of each page in bytes and the total number of pages across all available sectors. On the M25P10-A datasheet, these can be found from the following paragraph on page 6:

The memory is organized as 4 sectors, each containing 128 pages. Each page is 256 bytes wide. Thus, the whole memory can be viewed as consisting of 512 pages, or 131,072 bytes.

Address Size

3,                      /* 4.  Address size */

This value specifies the number of bytes used to represent an address. the table below reproduces the part of the M25P10-A datasheet that provides this information. In the table, all instructions that require an address take three bytes.

Table 4 on page 17 of M25P10-A datasheet

Instruction

Description

One-byte instruction code

Address byte

Dummy bytes

Data bytes

WREN

Write Enable

0000 0110

06h

0

0

0

WRDI

Write Disable

0000 0100

04h

0

0

0

RDID

Read

1001 1111

9Fh

0

0

1 to 3

RDSR

Read Status Register

0000 0101

05h

0

0

1 to ∞

WRSR

Write Status Register

0000 0001

01h

0

0

1

READ

Read Data Bytes

0000 0011

03h

3

0

1 to ∞

FAST_READ

Read Data Bytes at Higher Speed

0000 1011

0Bh

3

1

1 to ∞

PP

Page Program

0000 0010

02h

3

0

1 to 256

SE

Sector Erase

1101 1000

D8h

3

0

0

BE

Bulk Erase

1100 0111

C7h

0

0

0

DP

Deep Power-down

1011 1001

B9h

0

0

0

RES

Release from Deep Power-down, and Read Electronic Signature

1010 1011

ABh

0

3

1 to ∞

Release from Deep Power-down

0

0

0

Clock Rate

4,                      /* 5.  Clock divider */

This value is used to determine the clock rate for interfacing with the SPI device. For a value of n, the SPI clock rate used is 100/2*n MHz. libflash supports a maximum of 12.5MHz.

The table below reproduces the part of the M25P10-A datasheet that provides this information. The AC characteristics table shows that all instructions used in the configuration file, as discussed throughout this document, can operate at up to 25MHz. This is faster than libflash can support, so the value 4 is provided to generate a 12.5MHz clock.

Table 18 on page 40 of M25P10-A datasheet (first four entries only).

Symbol

Alt.

Parameter

Min

Typ

Max

Unit

fC

fC

Clock frequency for the following instructions: FAST_READ, PP, SE, BE, DP, RES, WREN, WRDI, RDSR, WRSR

D.C.

 

25

MHz

fR

 

Clock frequency for READ instructions

D.C.

 

20

MHz

tCH

tCLH

Clock High time

18

   

ns

tCL

tCLL

Clock Low time

18

   

ns

In general, if the SPI device supports different clock rates for different commands used by libflash, the lowest value must be specified.

Read Device ID

0x9f,                   /* 6.  RDID cmd */
0,                      /* 7.  RDID dummy bytes */
3,                      /* 8.  RDID data size in bytes */
0x202011,               /* 9.  RDID manufacturer ID */

Most flash devices have a hardware identifier that can be used to identify the device. This is used by libflash when one or more flash devices are supported by the application to determine which type of device is connected. The sequence for reading a device ID is typically to issue an RDID (read ID) command, wait for zero or more dummy bytes, and then read one or more bytes of data.

Table 4 on page 17 of M25P10-A datasheet reproduces the part of the M25P10-A datasheet that provides this information. The row for the instruction RDID shows that the command value is 0x9f, that there are no dummy bytes, and one to three data bytes. As shown in Table 5 on page 19 of M25P10-A datasheet and Figure 9 on page 19 of M25P10-A datasheet, the amount of data read depends on whether just the manufacturer ID (first byte) is required, or whether both the manufacturer ID and the device ID (second and third bytes) are required. All three bytes are needed to uniquely identify the device, so the manufacturer ID is specified as the three-byte value 0x202011.

Table 5 on page 19 of M25P10-A datasheet

Manufacturer identification

Device identification

Memory type

Memory capacity

20h

20h

11h

Figure 9 on page 19 of M25P10-A datasheet
images/fl-m25p10a-fig9.png

In general, if there is a choice of RDID commands then the JEDEC compliant one should be preferred. Otherwise, the one returning the longest ID should be used.

Sector Erase

0xD8,                   /* 10. SE cmd */
0,                      /* 11. SE full sector erase */

Most flash devices provide an instruction to erase all or part of a sector.

Table 4 on page 17 of M25P10-A datasheet reproduces the part of the M25P10-A datasheet that provides this information. The row for the instruction SE shows that the command value is 0xd8. On the M25P10-A datasheet, the amount of data erased can be found from the first paragraph on page 28:

The Sector Erase (SE) instruction sets to ‘1’ (FFh) all bits inside the chosen sector.

In this example the SE command erases all of the sector, so the SE data value is set to 0. If the number of bytes erased is less than a full sector, this value should be set to the number of bytes erased.

Write Enable/Disable

0x06,                   /* 12. WREN cmd */
0x04,                   /* 13. WRDI cmd */

Most flash devices provide instructions to enable and disable writes to memory. Table 4 on page 17 of M25P10-A datasheet reproduces the part of the M25P10-A datasheet that provides this information. The row for the instruction WREN shows that the command value is 0x06, and the row for the instruction WRDI shows that the command value is 0x04.

Memory Protection

PROT_TYPE_SR,           /* 14. Protection type */
{{0x0c,0x0},{0,0}},     /* 15. SR protect and unprotect cmds */

Some flash devices provide additional protection of sectors when writes are enabled. For devices that support this capability, libflash attempts to protect the flash image from being accidentally corrupted by the application. The supported values for protection type are:

PROT_TYPE_NONE

The device does not provide protection

PROT_TYPE_SR

The device provides protection by writing the status register

PROT_TYPE_SECS

The device provides commands to protect individual sectors

The protection details are specified as part of a construction of the form:

{{a,b},{c,d}}

If the device does not provide protection, all values should be set to 0. If the device provides SR protection, a and b should be set to the values to write to the SR to protect and unprotect the device, and c and d to 0. Otherwise, c and d should be set to the values to write to commands to protect and unprotect the device, and a and b to 0.

Table 2 on page 13 of M25P10-A datasheet and Table 6 on page 20 of M25P10-A datasheet reproduce the parts of the M25P10-A datasheet that provide this information. The first table shows that BP0 and BP1 of the status register should be set to 1 to protect all sectors, and both to 0 to disable protection. The second table shows that these are bits 2 and 3 of the SR.

Table 2 on page 13 of M25P10-A datasheet

Status Register Content BP1 bit

Memory content BP0 bit

0

0

none

All sectors (four sectors: 0, 1, 2 and 3)

0

1

Upper quarter (sector 3)

Lower three-quarters (three sectors: 0 to 2)

1

0

Upper half (two sectors: 2 and 3)

Lower half (sectors 0 and 1)

1

1

All sectors (four sectors: 0, 1, 2 and 3)

none

Table 6 on page 20 of M25P10-A datasheet
images/fl-m25p10a-tab6.png

Programming Command

0x02,                   /* 16. PP cmd */

Devices are programmed either a page at a time or a small number of bytes at a time. If page programming is available it should be used, as it minimizes the amount of data transmitted over the SPI interface.

Table 4 on page 17 of M25P10-A datasheet reproduces the part of the M25P10-A datasheet that provides this information. In the table, a page program command is provided and has the value 0x02.

If page programming is not supported, this value is a concatenation of three separate values. Bits 0..7 must be set to 0. Bits 8..15 should contain the program command. Bits 16..23 should contain the number of bytes per command. The libflash library requires that the first program command accepts a three byte address but subsequent program command use auto address increment (AAI).

An example of a device without a PP command is the ESMT F25L004A. the table below reproduces the part of the F25L004A datasheet that provides this information. In the timing diagram, the AAI command has a value 0xad, followed by a three-byte address and two bytes of data.

Table 7 on page 12 of F25L004A datasheet.

Symbol

Parameter

Minimum

Units

TPU-READ

VDD Min to Read Operation

10

µ s

TPU-WRITE

VDD Min to Write Operation

10

µ s

The corresponding entry in the specification file is:

0x00|(0xad<<8)|(2<<16), /* No PP, have AAI for 2 bytes */

Read Data

0x0b,                   /* 17. READ cmd */
1,                      /* 18. READ dummy bytes*/

The sequence for reading data from a device is typically to issue a READ command, wait for zero or more dummy bytes, and then read one or more bytes of data.

Table 4 on page 17 of M25P10-A datasheet reproduces the part of the M25P10-A datasheet that provides this information. There are two commands that can be used to read data: READ and FAST_READ. The row for the instruction FAST_READ shows that the command value is 0x0b, followed by one dummy byte.

Sector Information

SECTOR_LAYOUT_REGULAR,  /* 19. Sector layout */
{32768,{0,{0}}},        /* 20. Sector sizes */

The first value specifies whether all sectors are the same size. The supported values are:

SECTOR_LAYOUT_REGULAR

The sectors all have the same size

SECTOR_LAYOUT_IRREGULAR

The sectors have different sizes

On the M25P10-A datasheet, this can be found from the following paragraph on page 15:

The memory is organized as:

  • 131,072 bytes (8 bits each)
  • 4 sectors (256 Kbits, 32768 bytes each)
  • 512 pages (256 bytes each).

The sector sizes is specified as part of a construction: {a, {b, {c}}}. For regular sector sizes, the size is specified in a. The values of b and c should be 0.

For irregular sector sizes, the size number of sectors is specified in b. The log base 2 of the number of pages in each sector is specified in c. The value of a should be 0. An example of a device with irregular sectors is the AMIC A25L80P. Table 2 on page 7 of A25L80P datasheet reproduces the part of this datasheet that provides the sector information.

Table 2 on page 7 of A25L80P datasheet

Sector

Sector Size (Kb)

Address Range

15

64

F0000h

FFFFFh

14

64

E0000h

EFFFFh

13

64

D0000h

DFFFFh

12

64

C0000h

CFFFFh

11

64

B0000h

BFFFFh

10

64

A0000h

AFFFFh

9

64

90000h

9FFFFh

8

64

80000h

8FFFFh

7

64

70000h

7FFFFh

6

64

60000h

6FFFFh

5

64

50000h

5FFFFh

4

64

40000h

4FFFFh

3

64

30000h

3FFFFh

2

64

20000h

2FFFFh

1

64

10000h

1FFFFh

0-4

32

08000h

0FFFFh

0-3

16

04000h

07FFFh

0-2

8

02000h

03FFFh

0-1

4

01000h

01FFFh

0-0

4

00000h

00FFFh

The corresponding entry in the specification file is:

SECTOR_LAYOUT_IRREGULAR,
    {0,{20,{4,4,5,6,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8}}},

Status Register Bits

0x05,                   /* 21. RDSR cmd*/
0x01,                   /* 22. WRSR cmd */
0x01,                   /* 23. WIP bit mask */

Most flash devices provide instructions to read and write a status register, including a write-in-progress bit mask.

Table 4 on page 17 of M25P10-A datasheet reproduces the part of the M25P10-A datasheet that documents the RDSR and WRSR commands. The diagram in Table 6 on page 20 of M25P10-A datasheet shows that the WIP bit is in bit position 0 of the SR, resulting in a bit mask of 0x01.

Add Support to xTimeComposer

A configuration file can be used with libflash or xflash. The example program below uses libflash to connect to a M25P10-A device, the configuration parameters which are specified in m25p10a.

#include "platform.h"
#include "flash.h"
#include "flashlib.h"
#include "stdio.h"
#include "stdlib.h"

fl_PortHolderStruct SPI = {PORT_SPI_MISO,
                           PORT_SPI_SS,
                           PORT_SPI_CLK,
                           PORT_SPI_MOSI,
                           XS1_CLKBLK_1};

fl_DeviceSpec myFlashDevices[] = {
 {
   #include "m25p10a"
 }
};

int flash_access() {
  if (fl_connectToDevice(SPI, myFlashDevices,
      sizeof(myFlashDevices)/sizeof(fl_DeviceSpec)) != 0) {
    printf("No supported flash devices found.\n"); exit(1);
  } else {
  printf("Found custom flash device m25p10a.\n"); exit(0);
  }
  return 0;
}

int main() {
  // multicore main is required for xscope
  par {
    on stdcore[0] : flash_access();
  }
}

The custom flash device must be specified in the XN file as follows:

<ExternalDevices>
  <Device NodeId="0" Tile="0" Name="bootFlash"
          Class="SPIFlash" Type="M25P10A">
    <Attribute Name="PORT_SPI_MISO" Value="PORT_SPI_MISO" />
    <Attribute Name="PORT_SPI_SS" Value="PORT_SPI_SS" />
    <Attribute Name="PORT_SPI_CLK" Value="PORT_SPI_CLK" />
    <Attribute Name="PORT_SPI_MOSI" Value="PORT_SPI_MOSI" />
  </Device>
</ExternalDevices>

To compile an image file that links to the lib flash library, start the command-line tools and enter the following command:

xcc main.xc -o prog.xe -target=target_with_custom_flash.xn -lflash

To generate an image file in the xCORE flash format, which can be subsequently programmed into the above flash device, enter the following command:

xflash prog.xe -o imgfile –spi-spec m25p10a

XFLASH generates an image for the custom flash device, which it writes to the specified image file.

Select a Flash Device

When selecting a flash device for use with an xCORE device, the following guidelines are recommended:

  • If access to the data partition is required, select a device with fine-grained erase granularity, as this will minimize the gaps between the factory and upgrade images, and will also minimize the amount of data that libflash needs to buffer when writing data.
  • Select a device with sector protection if possible, to ensure that the bootloader and factory image are protected from accidental corruption post-deployment.
  • Select a flash speed grade suitable for the application. Boot times are minimal even at low speeds.