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

Code:
'*  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: