SPI DataFlash Library

Aus ProjectWiki
Wechseln zu:Navigation, Suche


This library reads/writes Atmel AT25DF-compatible SPI DataFlash ICs (ex. Spansion S25FL) through either a SW or HW SPI interface. The sample serves also as Firmware for the DataFlash Programmer application to write data to the memory. It uploads a list of any type of files, image files are converted on the fly to the uncompressed 16-Bit color BIN format. To access the stored information, an include file with all the neccessary constants (memory position, size, image width & height) is generated.

The library has been developed and tested using an XMega-A1 Xplained board with a Spansion S25FL032P (32Mbit) dataflash mounted on it.

Forum thread

How to use

Include the library. Set the options above the $include statement, needs the new Submode.

Config Submode = New

Const Flash_port_spi = PORTC
$include "SpiFlash.inc"

Init the DataFlash SPI interface

Sub Flash_init()

Read the 81 Bytes JEDEC RDID information

Sub Flash_get_info(byref Spiflashbuffer() As Byte)

Disable the SPI interface

Sub Flash_stop()

Erase a sector (64Kb block, upper 8 Bit of 24 Bit byte adress). The memory has to be erased (set to &HFF) before writing data.

Sub Flash_sector_erase(byval Sector As Byte)

Erase the whole memory

Sub Flash_bulk_erase()

Writes a page to the memory (256 Bytes) to a specified page adress (upper 16 Bit of 24 Bit byte adress).

Sub Flash_write_page(byval Address As Word , Byref Pagedata() As Byte)

Reads a block of data starting from the 24 Bit adress

Sub Flash_read(byval Address As Dword , Byref Spiflashbuffer() As Byte , Byval Length As Word)

Reads a block of data from the flash memory to an SRAM adress

Sub Flash_readto(byval Sourceaddress As Dword , Byval Destinationaddress As Dword , Byval Length As Dword)

Start an asynchronous read sequence. Data can be read byte-wise from the 24 Bit start adress until Flash_endread() is called.

Sub Flash_beginread(byval Address As Dword)

Reads a Byte (needs Flash_beginread() first)

Function Flash_readbyte() As Byte

Stop a read sequence

Sub Flash_endread()


Options and settings need to be set before the $include-statement, every setting has a default value that will be used if not specified otherwise. (in the list below the default values for the ATXMega are shown, values for ATMega are written in brackets () if applicable).

Set to true to use software SPI instead of hardware modules, any GPIOs will work.

Const Flash_use_soft_spi = False

False only configures the SS pin, does not enable and configure the SPI interface, this needs to be done manually (useful if the memory shares the SPI interface with other hardware).

Const Flash_init_spi = True

Sets the port of the SPI interface.

Const Flash_port_spi = Portc (Portb)

Set the SPI pins (CS, CLK, SDO and SDI are set to the hardware SPI pins by default)

Const Flash_pin_cs = 4 (0)
Const Flash_pin_clk = 7 (1)
Const Flash_pin_sdo = 5 (2)
Const Flash_pin_sdi = 6 (3)

(HW SPI) If the memory's SS signal is not connected to the HW SPI CS pin, the correct pin needs to be set:

Const Flash_port_ss = Flash_port_spi
Const Flash_pin_ss = Flash_pin_cs

Enable the status LED. Active during ongoing transmissions.

Const Flash_enable_statusled = False

Invert the status LED (active low)

Const Flash_invert_statusled = False

Set the pin of the status LED

Flash_statusled Alias Porte.0 (Porta.0)

Electrical connection

SPI DataFlash connection schematic

Only a handful small components are needed to connect the memory. The status LED is optional.


This sample also serves as firmware to program the memory with the DataFlash Programmer application, works for both ATMega and ATXmega devices.

$regfile = "xm128a1def.dat"
'$regfile = "m128def.dat"
$crystal = 32000000
$hwstack = 64
$swstack = 64
$framesize = 64

Config Submode = New
Const False = 0
Const True = 1

' XMega settings
#if _xmega = True
   ' sets the clock frequency using the PLL with the internal 2MHz oscillator
   $include "XMegaPll.inc"

   ' Host communication
   Config Com1 = 115200 , Mode = Asynchroneous , Parity = None , Stopbits = 1 , Databits = 8

   ' use the watchdog for communication timeouts
   Config Watchdog = 1000

   ' Xplained DataFlash SS
   Const Flash_port_ss = Portq
   Const Flash_pin_ss = 2

' ATMega settings
   ' Host communication
   $baud = 115200
   Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0

   ' use the watchdog for communication timeouts
   Config Watchdog = 1024

Open "COM1:" For Binary As #1

Const Flash_enable_statusled = True                                             '
$include "SPI-Flash.inc"

Dim Flashbuffer(256) As Byte
Dim Shakedhands As Boolean
Dim Sector As Byte , Page As Word , Address As Dword


   ' wait for command
   Inputbin #1 , Sector
   Select Case Sector

   ' Handshake/Exit
   Case &HAA:
      Shakedhands = Not Shakedhands                                             ' some kind of accidental write protection
      Printbin #1 , &HF0                                                        ' ack

   ' erase a sector (address bits 23..16)
   Case &H01:
      Reset Watchdog
      Start Watchdog
      Inputbin #1 , Sector                                                    ' read sector address
      Stop Watchdog
      If Shakedhands = True Then Flash_sector_erase Sector
      Printbin #1 , &HF0                                                        ' ack

   ' erase whole memory
   Case &H02:
      If Shakedhands = True Then Flash_bulk_erase
      Printbin #1 , &HF0                                                        ' ack

   ' write a page (256 Bytes, address bits 23..8)
   Case &H03:
      Reset Watchdog
      Start Watchdog
      Inputbin #1 , Page                                                    ' read page address
      Inputbin #1 , Flashbuffer(1) ; 256                                        ' read 256 bytes page data
      Stop Watchdog
      Swap Page
      If Shakedhands = True Then Flash_write_page Page , Flashbuffer(1)
      Printbin #1 , &HF0                                                        ' ack

   ' read a page (256 Bytes, address bits 23..8)
   Case &H04:
      Reset Watchdog
      Start Watchdog
      Inputbin #1 , Page                                                    ' read page address
      Stop Watchdog
      Swap Page
      Address = Page
      Shift Address , Left , 8
      If Shakedhands = True Then Flash_read Address , Flashbuffer(1) , 256
      Printbin #1 , Flashbuffer(1) ; 256                                        ' write page data

   ' read the device ID data (81 Bytes)
   Case &H05:
      If Shakedhands = True Then Flash_get_info Flashbuffer(1)
      Printbin #1 , Flashbuffer(1) ; 81

   End Select

Application example (XMega-A1 Xplained)

Load all data from flash memory to the extended SRAM memory for faster access:

$regfile = "xm128a1def.dat"
$crystal = 32000000
$hwstack = 64
$swstack = 64
$framesize = 64
Config Submode = New

Const False = 0
Const True = 1

' use the XMega PLL clock system to set the desired system clock frequency
$include "XMegaPll.inc"

'the XPLAIN has a 64 MBit SDRAM which is 8 MByte, it is connected in 3 port, 4 bit databus mode
'in the PDF of the SDRAM you can see it is connected as 16 Meg x 4. Refreshcount is 4K and the row address is A0-A11, column addressing is A0-A9
$xramsize = 8388608                                                             ' 8 MByte
Config Xram = 3port , Sdbus = 4 , Sdcol = 10 , Sdcas = 3 , Sdrow = 12 , Refresh = 500 , Initdelay = 3200 , Modedelay = 2 , Rowcycledelay = 7 , Rowprechargedelay = 7 , Wrdelay = 1 , Esrdelay = 7 , Rowcoldelay = 7 , Modesel3 = Sdram , Adrsize3 = 8m , Baseadr3 = &H0000
'the config above will set the port registers correct. it will also wait for Ebi_cs3_ctrlb.7
Const Xramstart = _hwstackstart + 1                                             ' the address where XRAM data space starts
Const Xramend = Xramstart + _xramsize                                           ' end address

'Const Flash_use_soft_spi = True                                                  ' uncomment to use SW SPI (works on any GPIO)
Const Flash_port_ss = Portq                                                     ' set to select a different pin as SS instead of the dedicated HW SPI module's
Const Flash_pin_ss = 2
$include "SPI-Flash.inc"                                                        ' include the library
$include "DataFlashFiles.inc"                                                   ' include the file info constants written by the DataFlash Programmer application
Const Xramdataend = Xramstart + Flash_totalsize                                 ' calculate the start of free SRAM memory after loading the data from the flash memory

Dim Sram_file_address As Dword

' load all the data stored in the flash memory into the extended SRAM memory for faster access
Flash_init                                                                      ' init the SPI interface
Flash_readto 0 , Xramstart , Flash_totalsize                                    ' load all data at once into the SRAM
Flash_stop                                                                      ' stop the SPI interface

' the file addresses are now calculated as follows:
Sram_file_address = Xramstart + Flash_myfile_bin

DataFlash Programmer

The SPI DataFlash Programmer application allows in-circuit programming of the memory over a serial connection. It uploads any types of files, images files (BMP, JPG, PNG, TIFF) can be converted to the uncompressed 16 Bit color BIN format on the fly when writing the data (standard). SPI DataFlash Programmer application

To use this application, the sample from above has to be programmed in the microcontroller, set up the SPI and the USART interface correctly. On the left side, choose the files to upload, rearrange them as you need and choose whether to convert image files to BIN by checking the box (initially checked for images) or upload them as they are by unchecking (does not affect other file types). Select the correct port and baudrate for the communication to the device, the "R" button refreshes the available serial port list. During the programming process, the File addresses include file is written, which contains information about the stored files (start address, size, width & height for images) as constants. Because page writes can't change 0's to 1's, the memory needs to be erased (sets everything to 1) before writing data to it. Erasing is done sector-wise, which are 64Kb blocks. This is done automatically during programming process for each sector containing pages to write. You can skip this sector-erasing by ticking the checkbox, only page writes are executed. Bulk erase could be used instead, this erases the whole memory at once (takes a while). If the DataFlash device supports the JEDEC RDID command (likely), "Read Flash Info" displays these informations. "Write to file..." writes the resulting data stream into a binary file instead of programming a memory. At least, a file list in .txt format (one file path per line), containing the files to write, can be saved or loaded.