PDA

View Full Version : Spi flash chip example - 8mb flash



longpole001
- 16th June 2014, 11:11
Hi guys ,

I had a need to add a flash chip to a project

I could not find any sample of code on the site or elsewhere for Flash routines and use , and i hate having to redo the wheel if i dont have to

so now you dont have to - as much

This code works and is designed for 8mb Flash - M25P80 chip , at 75mhz

the code runs on a 64mhz 18F cpu , and software SPI ( for the Moment )
spi pins, chip select are done else where but it easy to add to this section
this code is used as an include to another core program .

The code will change to suite the duel /quad spi chip range 25Q80 series some time
No use of the "HOLD" PIN is supported at this time

the W and Hold Pins are tied High , but allows for the W pin to be tied low to lock sectors

it use the same name variables from the SDFS3 , so take care to consider the issues when using both., but double use of the defined buffers on both programs works

this code will change as other chips are used

hope it helps someone else avoid the days it took me

regards

Sheldon



'* Notes : writen for M25P80 8Mbit or simular *
'* : support of duel / quad options not as yet *
'* :3.3v - NOT 5V input tollerant *
'* : Code supports Software Protection of data , hardware WP and Hold pins high *
'************************************************* ****************************************
'* Revision: *
'* *
'* *
'* *
'* *
'* *
'************************************************* ****************************************
' *
'----------------------------------------------------------------------------------------*
' *
' Operational Notes on Timing Max and Min times *
' ============================================= *
' *
' 1. powerup delay to CE & WR = 10ms max -1ms min *
' 2. 256 bytes max per read / write *
' 3. spi bus and flash CE configures in main program *
' 4. avg is 15ma during write /erase, 8ma for read *
' 5. min 100ns on CE deselect *
' 6. SPI chip interface timing has min of 10ns requirements , so no timing issues *
' for picbasic which has a min of 2us using shiftout cmd *
' *
'----------------------------------------------------------------------------------------*


'----------SPI FLASH (M25P80) commands---------------------------------------------------

' SDC_cmd, SDC_CmdCode
' command 1-7 use the Write enable command ---
Flash_Wr_reg con 1 ' $01 'def write the Status Register
Flash_WR con 2 ' $02 'def Page Program mode command 1- 256 bytes
Flash_Sec_Ers con 3 ' $D8 'def Sector Erase command
Flash_Bulk_Ers con 4 ' $C7 'def Bulk Erase command
Flash_PWR_Dwn con 5 ' $B9 'def Deep Power Down command
Flash_Rd_Sign con 6 ' $9E 'def read device signature - 1 byte RES COMMAND (13h)

Flash_RD con 7 ' $03 'def read data at normal speed
Flash_Rd_HS con 8 ' $0B 'def read data at High speed
Flash_Rd_ID con 9 ' $9F 'def Read manufacture/ device/UID codes upto 20 bytes
Flash_PWR_Up con 10' $AB 'def Release From Deep Power Down command
'---- not in command lookup table - used directly -----
Flash_Wr_dis CON $04 'def write disable command
Flash_Rd_reg con $05 'def read the Status Register
Flash_Wr_en con $06 'def write Enable command


' ---------- 8mb FLASH varables -------------------------


Data_Length var byte ' table of data length
SDC_buffer Var Byte[256] ' indexed data - max 256 bytes - 8mb FLASH has a 256 Limit from page Writes - Note 512 used in SD routines
SDC_data_in Var Byte ' Data in byte from flash
SDC_data_out Var Byte ' Data out byte from Flash -
SDC_address Var Long ' address sent to FLASH - may use page and sector varables to form address ?
SDC_index Var Word ' Loop index counter
SDC_CmdCode Var Byte ' used here as Sector protect value for the Write Status register
SDC_cmd Var Byte ' command code for selected operation
SDC_Sector var byte ' Sector address
SDC_Page var byte ' Page Address
SDC_Byte Var byte ' Bytes Address
Flash_RD_Fast var bit ' Flag for High speed read 1 = Highspeed read speed 0= normal read speed

Flash_Manf_id var byte ' manufacture id code
Flash_Manf_type var byte ' device type code
Flash_Manf_cap var byte ' device capacity code
Flash_tmp var byte ' used as a temp varable

goto JumpOverSPIFLASH ' Jump to end of this include file for Correct compile

'-----------------------------------------------------------------------------------------
Flash_Init:
' do a read register command to clear the Flash register after power up
' bug seems to return $FF in status register on first write access otherwise ???

FLASH_CE = 0 ' Bring the FLASH chip select line low
SDC_data_out = Flash_Rd_reg ' Send the read status register command byte
Gosub Flash_spiw ' Write Byte SDC_data_out. , subroutine writes a byte on the SPI bus
FLASH_CE = 1 ' Bring the FLASH chip select line low
return

Flash_Format:
'Note wont work if any sectors are protected
' can take upto 20sec on 8mbit chip
sdc_cmd = Flash_Bulk_ers ' excutes as it sounds
gosub Flash_Comand
return



Flash_Sec_Erase:
' assumes sector address only
' erases 1 sector at a time address
' Erases wont work on sectors that are write protected
' sector erase take 600ms per instruction
sdc_cmd = Flash_Sec_Ers ' Erases sector ( 256 pages x 256 bytes )
SDC_address.byte2 = SDC_Sector ' set sector Address 0 to 15 for 8mb chip
SDC_address.byte1 = 0 ' set page start address 0 to 255
SDC_address.byte0 = 0 ' set byte start address 0 to 255
gosub Flash_Comand ' Do the command
return


Flash_Write:
' assumes data length , address and upto 256 bytes in SDC_buffer[] to send
' writes bytes from SDC_buffer[] into flash , Sector/page/byte loction must be "FF" at start
' write wont work on sectors that are write protected

sdc_cmd = Flash_WR ' excutes as it sounds - max of 256 bytes
SDC_address.byte2 = SDC_Sector ' set sector Address 0 to 15 for 8mb chip
SDC_address.byte1 = SDC_Page ' set page start address 0 to 255
SDC_address.byte0 = SDC_byte ' set byte start address 0 to 255
gosub Flash_Comand
return



Flash_Read:
' assumes data length input
' gets upto bytes data into SDC_buffer[] from flash
' uses normal read speed
if Flash_RD_Fast = 1 then
sdc_cmd = Flash_Rd_HS ' excutes fast read - max of 256 bytes
else
sdc_cmd = Flash_RD ' excutes normal read - max of 256 bytes cos of buffers size/ page size
endif
SDC_address.byte2 = SDC_Sector ' set sector Address 0 to 15 for 8mb chip
SDC_address.byte1 = SDC_Page ' set page start address 0 to 255
SDC_address.byte0 = SDC_byte ' set byte start address 0 to 255
gosub Flash_Comand
return


Flash_WR_protect:
' assumes sector protect block value - input sector block to protect
' Sets Hardware protect bit 7 = 1 at same time , so HW protect can be used
' bits7 = 1 HW protect enable ,bit6,5 = n/a bit4-2 = sector protect select , bit1,0 = n/a

sdc_cmd = Flash_Wr_reg ' write register
data_length = 0 ' set 0 = 1 byte
if SDC_Sector = 0 then SDC_buffer[0] = $80 ' proctects no sectors bit 7 = 1 ,bits4-2= 000
if SDC_Sector = 15 then SDC_buffer[0] = $84 ' protect sector 15 bit 7 = 1 ,bits4-2= 001
if SDC_Sector = 14 then SDC_buffer[0] = $88 ' protects sector 14-15 bit 7 = 1 ,bits4-2= 010
if SDC_Sector = 12 then SDC_buffer[0] = $8C ' protects sector 12-15 bit 7 = 1 ,bits4-2= 011
if SDC_Sector = 8 then SDC_buffer[0] = $90 ' protects sector 8 -15 bit 7 = 1 ,bits4-2= 100
if SDC_Sector >0 and SDC_Sector < 8 then SDC_buffer[0] = $94 ' protects All sectors bit 7 = 1 ,bits4-2= 101
gosub Flash_Comand
return

Flash_WR_Disable:
' reset the write enable latch
FLASH_CE = 0 ' Bring the FLASH chip select line low
SDC_data_out = Flash_Rd_reg ' Send the read status register command byte
Gosub Flash_spiw ' Write Byte SDC_data_out. , subroutine writes a byte on the SPI bus
FLASH_CE = 1 ' Bring the FLASH chip select line high
return

Flash_Read_ID:
' returns manufacture ID- 1byte,memory type 1 byte, memcapacity 1 byte , CFD length 1 byte , CFD bytes 16 bytes
' need only first 3 bytes for size calaculation of other devices later maybe
sdc_cmd = Flash_Rd_ID ' read id register
data_length = 2 ' 2 = 3 bytes
gosub Flash_Comand
Flash_Manf_id = SDC_buffer[0]
Flash_Manf_type = SDC_buffer[1]
Flash_Manf_cap = SDC_buffer[2]
HSEROUT ["Flash_Manf_id = ",hex Flash_Manf_id,"Flash_Manf_type = ",hex Flash_Manf_type,"Flash_Manf_cap = ",hex Flash_Manf_cap,13,10] ' debug
return

Flash_Power_Down:
' sEt Flash chip to low power mode from standby mode - no command other tha powerup will wake the device
sdc_cmd = Flash_PWR_Dwn ' send the powerdown command
gosub Flash_Comand
return

Flash_Power_Up:
' sEt Flash chip to standby mode - no command other tha powerup will wake the device
sdc_cmd = Flash_PWR_Up ' send the powerUp command
gosub Flash_Comand
return



' -----------------------------

Flash_Comand:
' assumes SDC_address long
' assumbe data_Length = Lookup table to fill
' max 256 bytes per write
' erase of the sector by byte / bulk is needed prior to write , as a write only changes a 1 to 0 , and the erase chanse the 0 to 1
if SDC_cmd = 0 then return ' invalid command if value =0

Lookup SDC_cmd,[$00,$01,$02,$D8,$C7,$B9,$9E,$03,$0B,$9F,$AB],SDC_CmdCode ' asignes command code to flash chip

Flash_tmp = 0 ' ensure 0 - counter for busychk loop
if SDC_cmd <=6 then gosub BSY_chk ' do for writes, byte erase, sector erase,bulk erase , write reg protect , deep power down , signature read
' test if Chip is busy writing

if SDC_cmd <=4 then ' do for writes, sector erase,bulk erase , write reg protect
FLASH_CE = 0 ' Bring the FLASH chip select line low.
SDC_data_out = Flash_Wr_en ' Send command byte that requires a write
Gosub Flash_spiw ' Write Byte SDC_data_out. , subroutine writes a byte on the SPI bus
FLASH_CE = 1 ' Bring the FLASH chip select line high to complete the write command
pauseus 1 ' pause between prev command - may not need
endif

FLASH_CE = 0 ' Bring the FLASH chip select line high to complete the write command
SDC_data_out = SDC_CmdCode ' Send the command byte,
Gosub Flash_spiw ' Write Byte SDC_data_out. , subroutine writes a byte on the SPI bus

if SDC_cmd =>2 and SDC_cmd <=3 or _ ' if commands 2= Page write 3= Sector Erase,
SDC_cmd =>6 and SDC_cmd <=7 then ' or 7= read data normalspeed or 8 read data at Highspeed then set given address
SDC_data_out = SDC_address.Byte2 ' set sector Address 0 to 15 for 8mb chip
Gosub Flash_spiw ' Write Byte SDC_data_out.
SDC_data_out = SDC_address.Byte1 ' set page address 0 to 255
Gosub Flash_spiw ' Write Byte SDC_data_out.
SDC_data_out = SDC_address.Byte0 ' set byte address 0 to 255
Gosub Flash_spiw ' Write Byte SDC_data_out.
if SDC_cmd = 7 then ' read High speed mode
SDC_data_out = SDC_address.Byte0 ' used as dummy byte for read High speed mode
Gosub Flash_spiw ' Write Byte SDC_data_out.
endif
endif

if SDC_cmd <=2 or _ ' if commands 1= write Register , 2= Page write ,3= byte erase
SDC_cmd >=6 and SDC_cmd <= 9 then ' or 6= read signature byte, 7=read data normalspeed, 8= read data at Highspeed , 9=read ID
' allow for data in/out buffer use
For SDC_index = 0 To Data_Length
if SDC_cmd <= 2 then ' if write or Write register then
SDC_data_out = SDC_buffer[SDC_index] ' send contents of indexed SDC_buffer
gosub Flash_SPIw ' write byte SDC_data_in from SPI bus. Returns SDC_data_in.
endif

if SDC_cmd =>6 and SDC_cmd <=9 then ' if 6= read signature byte, 7=read data normalspeed, 8= read data at Highspeed , 9=read ID
gosub Flash_SPIR ' Read Byte SDC_data_in from SPI bus. Returns SDC_data_in.
SDC_buffer[SDC_index] = SDC_data_in
endif
Next SDC_index
endif

FLASH_CE = 1 ' Bring the FLASH chip select line high.

return
'----------------------------------------------------
Bsy_chk:
FLASH_CE = 0 ' Bring the FLASH chip select line low
SDC_data_out = Flash_Rd_reg ' Send the read status register command byte
Gosub Flash_spiw ' Write Byte SDC_data_out. , subroutine writes a byte on the SPI bus

while Flash_tmp <150 ' loop test read
gosub Flash_SPIR ' Read Byte SDC_data_in from SPI bus. Returns SDC_data_in.
HSEROUT ["BSY-CHK = ",hex SDC_data_in,13,10] ' debug
HSEROUT ["Flash_tmp = ",dec2 Flash_tmp,13,10] ' debug
Flash_tmp = Flash_tmp + 1
SDC_data_in = SDC_data_in & $01
if SDC_data_in = 0 then Flash_tmp = 151 ' Test bit 1 if write not busy,force exit of loop
wend
Flash_tmp = 0 ' clear counter
FLASH_CE = 1 ' Bring the FLASH chip select line high
return
'-------------------------------
Flash_SPIR:
SO = 1 ' Shift out high bits while shifing in data.
Shiftin SO, SCK, 6,[SDC_data_in] ' MSb first, clock idle high.

Return
'-------------------------------

Flash_SPIW:
Shiftout SI,SCK, 5,[SDC_data_out] ' MSb first, clock idle high.

return

JumpOverSPIFLASH:

longpole001
- 16th June 2014, 11:16
an example of how to use the routines





lash_Test:
gosub Bsy_chk ' just get the status reg value for ref


for SDC_Page= 0 to 5
' routinE to write / read test data back form flaSH chip
SDC_Sector = 15 ' set sector Address 0 to 15 for 8mb chip
' SDC_Page = 0 ' set page start address 0 to 255
SDC_byte = 0 ' set byte start address 0 to 255
Data_Length = 255

For SDC_index = 0 to Data_Length
SDC_buffer[SDC_index] = SDC_index ' fill the data buffer with 0 - 255 values
next SDC_index
gosub Flash_Format
' gosub Flash_Sec_Erase
' gosub Flash_Write
' gosub Flash_Byte_Modify
' gosub Flash_Byte_Erase
next SDC_Page



Flash_Test_RD:
gosub Bsy_chk ' just get the status reg value for ref
for SDC_Page = 0 to 5
' use prev values for sector, page address and length to do a read
SDC_Sector = 15 ' set sector Address 0 to 15 for 8mb chip
' SDC_Page = 0 ' set page start address 0 to 255
SDC_byte = 0 ' set byte start address 0 to 255
Data_Length = 255
gosub Flash_Read
HSEROUT [13,10,"SDC_buffer PAGE ",dec SDC_Page, 13,10]
For SDC_index = 0 To Data_Length
HSEROUT [",",Dec3 SDC_buffer[SDC_index] ]
next SDC_index
next SDC_Page

return

Flash_protect_test:
SDC_Sector = 0
gosub Flash_WR_protect
gosub Bsy_chk
gosub Flash_Read_ID
return

longpole001
- 16th June 2014, 11:21
data sheet on M25P80 chip used

http://www.farnell.com/datasheets/1737025.pdf

longpole001
- 18th June 2014, 05:36
found a error in the read/fast read option, where dummy byte was offseting the read address by 1 in flash_comand routine

- heres the updated area




if SDC_cmd =>2 and SDC_cmd <=3 or _ ' if commands 2= Page write 3= Sector Erase,
SDC_cmd =>6 and SDC_cmd <=8 then ' or 6=Signature read( 3 dummybytes) 7= read data normalspeed or 8 read data at Highspeed then set given address
SDC_data_out = SDC_address.Byte2 ' set sector Address 0 to 15 for 8mb chip
Gosub Flash_spiw ' Write Byte SDC_data_out.
SDC_data_out = SDC_address.Byte1 ' set page address 0 to 255
Gosub Flash_spiw ' Write Byte SDC_data_out.
SDC_data_out = SDC_address.Byte0 ' set byte address 0 to 255
Gosub Flash_spiw ' Write Byte SDC_data_out.
if SDC_cmd = 8 then ' read High speed mode
SDC_data_out = $FF ' used as dummy byte for read High speed mode
Gosub Flash_spiw ' Write Byte SDC_data_out.
endif
endif

longpole001
- 23rd June 2014, 07:33
further testing showed that when sequences of commands to do read and writes over multi sectors , the the busy_chk routine requires to be checked not just for writes , but also for reads

if a read is done during a cycle of a sector erase,write , the read is not done at all

as such the code changed to





Flash_Comand:
' assumes SDC_address long
' assumbe data_Length = Lookup table to fill
' max 256 bytes per write
' erase of the sector by byte / bulk is needed prior to write , as a write only changes a 1 to 0 , and the erase chanse the 0 to 1
if SDC_cmd = 0 then return ' invalid command if value =0

Lookup SDC_cmd,[$00,$01,$02,$D8,$C7,$B9,$9E,$03,$0B,$9F,$AB],SDC_CmdCode ' asignes command code to flash chip

Flash_tmp = 0 ' ensure 0 - counter for busychk loop
gosub BSY_chk ' do for all commands

if SDC_cmd <=4 then ' do for writes, sector erase,bulk erase , write reg protect
FLASH_CE = 0 ' Bring the FLASH chip select line low.
SDC_data_out = Flash_Wr_en ' Send command byte that requires a write
Gosub Flash_spiw ' Write Byte SDC_data_out. , subroutine writes a byte on the SPI bus
FLASH_CE = 1 ' Bring the FLASH chip select line high to complete the write command
pauseus 1 ' pause between prev command - may not need
endif

FLASH_CE = 0 ' Bring the FLASH chip select line high to complete the write command
SDC_data_out = SDC_CmdCode ' Send the command byte,
Gosub Flash_spiw ' Write Byte SDC_data_out. , subroutine writes a byte on the SPI bus

if SDC_cmd =>2 and SDC_cmd <=3 or _ ' if commands 2= Page write 3= Sector Erase,
SDC_cmd =>6 and SDC_cmd <=8 then ' or 6=Signature read( 3 dummybytes) 7= read data normalspeed or 8 read data at Highspeed then set given address
SDC_data_out = SDC_address.Byte2 ' set sector Address 0 to 15 for 8mb chip
Gosub Flash_spiw ' Write Byte SDC_data_out.
SDC_data_out = SDC_address.Byte1 ' set page address 0 to 255
Gosub Flash_spiw ' Write Byte SDC_data_out.
SDC_data_out = SDC_address.Byte0 ' set byte address 0 to 255
Gosub Flash_spiw ' Write Byte SDC_data_out.
if SDC_cmd = 8 then ' read High speed mode
SDC_data_out = $FF ' used as dummy byte for read High speed mode
Gosub Flash_spiw ' Write Byte SDC_data_out.
endif
endif

if SDC_cmd <=2 or _ ' if commands 1= write Register , 2= Page write ,
SDC_cmd >=6 and SDC_cmd <= 9 then ' or 6= read signature byte, 7=read data normalspeed, 8= read data at Highspeed , 9=read ID

For SDC_index = 0 To Data_Length
if SDC_cmd <= 2 then ' if write or Write register then
SDC_data_out = SDC_buffer[SDC_index] ' send contents of indexed SDC_buffer
gosub Flash_SPIw ' write byte SDC_data_in from SPI bus. Returns SDC_data_in.
endif

if SDC_cmd =>6 and SDC_cmd <=9 then ' if 6= read signature byte, 7=read data normalspeed, 8= read data at Highspeed , 9=read ID
gosub Flash_SPIR ' Read Byte SDC_data_in from SPI bus. Returns SDC_data_in.
SDC_buffer[SDC_index] = SDC_data_in
endif
Next SDC_index
endif

FLASH_CE = 1 ' Bring the FLASH chip select line high.

return
'----------------------------------------------------
Bsy_chk:
FLASH_CE = 0 ' Bring the FLASH chip select line low
SDC_data_out = Flash_Rd_reg ' Send the read status register command byte
Gosub Flash_spiw ' Write Byte SDC_data_out. , subroutine writes a byte on the SPI bus
Flash_tmp = 0 ' clear counter
while Flash_tmp <150 ' loop test read
gosub Flash_SPIR ' Read Byte SDC_data_in from SPI bus. Returns SDC_data_in.
IF FLASH_Install = 1 then
Flash_Reg_val = SDC_data_in ' get value of read status reg value for use in flash install program checks for protection
HSEROUT ["STATUS REG = ",hex Flash_Reg_val,13,10] ' show on terminal when doing flash install
HSEROUT ["Flash_tmp = ",dec2 Flash_tmp,13,10]
endif
Flash_tmp = Flash_tmp + 1
SDC_data_in = SDC_data_in & $01
if SDC_data_in = 0 then Flash_tmp = 151 ' Test bit 1 if write not busy,force exit of loop
wend

FLASH_CE = 1 ' Bring the FLASH chip select line high
return

longpole001
- 24th June 2014, 07:27
refer to other posts that have usefull copy sector , copy page , byte modify routines with this code example

http://www.picbasic.co.uk/forum/showthread.php?t=19286

longpole001
- 1st August 2014, 12:00
Hi guys , when using the routines , i found that i often use "data_length" varable to reflect the TOTAL amount of bytes used in the buffer , eg datalength = 32 , thus the data buffer should have 32 bytes ,

but the Flash_comand routine code uses " for 0 to Data_length , thus the buffer need to have 33 bytes of valid data , in this example

As a result the code changes to

" for 0 to Data_length-1"

ammed to




For SDC_index = 0 To Data_Length-1 ' DATA LENGTH -1 COS 0 USED
if SDC_cmd <= 2 then ' if write or Write register then
SDC_data_out = SDC_buffer[SDC_index] ' send contents of indexed SDC_buffer
gosub Flash_SPIw ' write byte SDC_data_in from SPI bus. Returns SDC_data_in.
endif

if SDC_cmd =>6 and SDC_cmd <=9 then ' if 6= read signature byte, 7=read data normalspeed, 8= read data at Highspeed , 9=read ID
gosub Flash_SPIR ' Read Byte SDC_data_in from SPI bus. Returns SDC_data_in.
SDC_buffer[SDC_index] = SDC_data_in
endif
Next SDC_index



"