SPI DataFlash Library
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.
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
Read the 81 Bytes JEDEC RDID information
Sub Flash_get_info(byref Spiflashbuffer() As Byte)
Disable the SPI interface
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
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
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)
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 #else ' 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 #endif 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 Flash_init Do ' 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 Loop
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
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).
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.