Full Version : DataFlash SPI Interface (AVR ASM) from VFX
avr >>ASM PROGRAMMING (AVR) >>DataFlash SPI Interface (AVR ASM) from VFX


Argyle- 05-21-2006
DataFlash SPI Interface (AVR ASM) from VFX


CODE

;***************************************************************************
;
; File Name  :'DFlash.asm"
; Title   :SPI interface to Serial DataFlash
; Date   :2003.06.01.
; Version  :1.0.0
; Support telephone :+36-70-333-4034,  old: +36-30-9541-658 VFX
; Support fax  :
; Support Email  :info@vfx.hu
; Target MCU  :ATmega8
;
;***************************************************************************
;
; D E S C R I P T I O N
;
; SPI interface to AT45DBxxx Serial DataFlash
;
; Functions to access the Atmel AT45Dxxx dataflash series
;  Supports 1Mbit - 128Mbit
;
;***************************************************************************
;
; M O D I F I C A T I O N   H I S T O R Y
;
;
;       rev.      date      who   why
; ---- ----------  ---  ------------------------------------
; 0.01 2003.06.01  VFX  Creation
;
;***************************************************************************
;Hardware
;***************************************************************************
;*
;* SYSCLK: f=16.000 MHz (T= 62.5 ns)
;*
;***************************************************************************
;
; CS    - Chip Select
; SCK   - Serial Clock
; SI    - Serial Input
; SO    - Serial Output
; WP    - Hardware Page Write Protect Pin
; RESET - Chip Reset
; RDY/BUSY - Ready/Busy
;
; To provide optimal flexibility, the memory array of the AT45DB081B is
;divided into three levels of granularity comprising of sectors, blocks,
;and pages. All program operations to the DataFlash occur on a page-by-page
;basis; however, the optional erase operations can be performed at the block
;or page level.
;
;
;The device operation is controlled by instructions from the host processor.
;The list of instructions and their associated opcodes are contained in
;Tables 1 through 4. A valid instruction starts with the falling edge of CS
;followed by the appropriate 8-bit opcode and the desired buffer or main memory
;address location. While the CS pin is low, tog-gling the SCK pin controls the
;loading of the opcode and the desired buffer or main memory address location
;through the SI (serial input) pin. All instructions, addresses and data are
;transferred with the most significant bit (MSB) first.
;Buffer addressing is referenced in the datasheet using the terminology
;BFA8 - BFA0 to denote the nine address bits required to designate a byte address
;within a buffer. Main memory addressing is referenced using the terminology
;PA11 - PA0 and BA8 - BA0 where PA11 - PA0 denotes the 12 address bits required
;to designate a page address and BA8 - BA0 denotes the nine address bits
;required to designate a byte address within the page.
;
;
;Status Register Format
;Bit   7      6    5   4  3  2  1  0
;  RDY/BUSY COMP   1   0  0  1  X  X 45DB161
;***************************************************************************
;* Const Def
;

;Look-up table for these sizes ->  512k, 1M, 2M, 4M, 8M, 16M, 32M, 64M
;flash unsigned char DF_pagebits[]  ={  9,  9,  9,  9,  9,  10,  10,  11}; //index of internal page address bits



;Dataflash opcodes
.equ MainMemPageRead    =  0x52;Main Memory Page Read Inactive Clk Pol Low or High
.equ FlashPageRead = 0x52;Main memory page read
.equ FlashToBuf1Transfer= 0x53;Main memory page to buffer 1 transfer
.equ Buf1Read  = 0x54;Buffer 1 read
.equ FlashToBuf2Transfer= 0x55;Main memory page to buffer 2 transfer
.equ Buf2Read  = 0x56;Buffer 2 read
.equ StatusReg  = 0x57;Status register
.equ StatusRegMode3 = 0xD7;Status register read SPI Mode 0 or 3
.equ AutoPageReWrBuf1 = 0x58;Auto page rewrite through buffer 1
.equ AutoPageReWrBuf2 = 0x59;Auto page rewrite through buffer 2
.equ FlashToBuf1Compare = 0x60;Main memory page to buffer 1 compare
.equ FlashToBuf2Compare = 0x61;Main memory page to buffer 2 compare
.equ ContArrayRead = 0x68;Continuous Array Read (Note : Only A/B-parts supported)
.equ FlashProgBuf1 = 0x82;Main memory page program through buffer 1
.equ Buf1ToFlashWE = 0x83;Buffer 1 to main memory page program with built-in erase
.equ Buf1Write  = 0x84;Buffer 1 write
.equ FlashProgBuf2 = 0x85;Main memory page program through buffer 2
.equ Buf2ToFlashWE = 0x86;Buffer 2 to main memory page program with built-in erase
.equ Buf2Write  = 0x87;Buffer 2 write
.equ Buf1ToFlash = 0x88;Buffer 1 to main memory page program without built-in erase
.equ Buf2ToFlash = 0x89;Buffer 2 to main memory page program without built-in erase
.equ MainMemPageReadSPI = 0xD2;Main Memory Page Read SPI Mode 0 or 3
.equ ContArrayReadSPI   = 0xE8;Continuous Array Read SPI Mode 0 or 3


;Table 2. Program and Erase Commands
.equ Buffer1Write       = 0x84;Buffer 1 Write
.equ Buffer2Write       = 0x87;Buffer 2 Write
.equ Buffer1toMem       = 0x88;Buffer 1 to Main Memory Page Program without Built-in Erase
.equ Buffer2toMem       = 0x89;Buffer 2 to Main Memory Page Program without Built-in Erase
.equ DFPageErase        = 0x81;Page Erase
.equ DFBlockErase       = 0x50;Block Erase
.equ MemPageProgBuff1   = 0x82;Main Memory Page Program through Buffer 1
.equ MemPageProgBuff2   = 0x85;Main Memory Page Program through Buffer 2


;Table 3. Additional Commands
.equ MemPagetoBuff1     = 0x53;Main Memory Page to Buffer 1 Transfer
.equ MemPagetoBuff2     = 0x55;Main Memory Page to Buffer 2 Transfer
.equ MemPagetoBuff1Cmp  = 0x60;Main Memory Page to Buffer 1 Compare
.equ MemPagetoBuff2Cmp  = 0x61;Main Memory Page to Buffer 2 Compare
.equ PageRewriteBuff1   = 0x58;Auto Page Rewrite through Buffer 1
.equ PageRewriteBuff2   = 0x59;Auto Page Rewrite through Buffer 2



;**************************************************************************
;* Hardware Def.
;

; RDY/BUSY - Ready/Busy
.equ DFRDY_PORT = PORTD
.equ DFRDY_DIR = DDRD
.equ DFRDY_PIN = PIND
.equ DFRDY = 7

.equ DFRES_PORT = PORTD
.equ DFRES_DIR = DDRD
.equ DFRES = 5

.equ DFCS_PORT = PORTC
.equ DFCS_DIR = DDRC
.equ DFCs = 2



.equ MOSI_DIR = DDRB
.equ MOSI_PORT = PORTB
.equ MOSI = 3

.equ MISO_DIR = DDRB
.equ MISO_PORT = PORTB
.equ MISO_PIN = PINB
.equ MISO = 4

.equ SCLK_DIR = DDRB
.equ SCLK_PORT = PORTB
.equ SCLK = 5

.equ DFSS_DIR = DDRB
.equ DFSS_PORT = PORTB
.equ DFSS = 2



;***************************************************************************
;**** VARIABLES
.DSEG

DFSize:  .byte 1
DFPageSize: .byte 1
DFPageBits: .byte 1

.equ DFBuffer = AppData

;DFBuffer: .byte 128;Data buffer
; !!! use AppData buffer from user.asm --> save RAM Space !!!
; !!! Self update not supported in application !!!

;***************************************************************************
.ESEG


;***************************************************************************
;**** CODE SEG
;***************************************************************************
.CSEG

;p,x,y,z,0
;page bits = p
;page number = x * 256
;page size = y * 256 (264)
;type = z
;
AT45DBxxx: .db  9, 2,1,0b00001100;AT45DB011 1Mbit
 .db  9, 4,1,0b00010100;AT45DB021 2Mbit
 .db  9, 8,1,0b00011100;AT45DB041 4Mbit
 .db  9,16,1,0b00100100;AT45DB081 8Mbit
 .db 10,16,2,0b00101100;AT45DB161 16Mbit
 .db 10,32,2,0b00110100;AT45DB321 32Mbit
 .db 11,32,4,0b00111000;AT45DB642 64Mbit
               .db 11,64,4,0b00010000;AT45DB1282 128Mbit
 .dw 0,0


;****************************************************************************
;***           S P I    R U T I N S
;***
;****************************************************************************
;* SPI_init
;*
;* Initialize our port pins for use as SPI master.
;*
;***************************************************************************
;
SPI_init:
 sbi DFCS_PORT,DFCS;DFlash CE pin is output for ATmega
 sbi DFCS_DIR,DFCS;CS=1

 sbi DFRES_PORT,DFRES
 sbi DFRES_DIR,DFRES;DFlash Reset = H


 cbi DFRDY_DIR,DFRDY
 sbi DFRDY_PORT,DFRDY;DFlash R/B pullup input

 in R16,PORTB
 andi R16,0b11000011
 ori R16,0b00101100
 out PORTB,R16;SS, MOSI, SCK output; MISO input

 in R16,DDRB
 andi R16,0b11000011
 ori R16,0b00101100
 out DDRB,R16


 ldi R16,0b01011100
 out SPCR,R16;[7] - SPIE: SPI Interrupt Enable
  ;[6] - SPE: SPI Enable
  ;[5] - DORD: Data Order
  ;[4] - MSTR: Master/Slave Select
  ;[3] - CPOL: Clock Polarity
  ;[2] - CPHA: Clock Phase
  ;[1:0] - SPR1,SPR0: SPI Clock Rate Select
  ; SPI2X SPR1 SPR0 SCK Frequency
  ;   0    0    0      fosc/4
  ;   0    0    1      fosc/16
  ;   0    1    0      fosc/64
  ;   0    1    1      fosc/128
  ;   1    0    0      fosc/2
  ;   1    0    1      fosc/8
  ;   1    1    0      fosc/32
  ;   1    1    1      fosc/64

 ldi R16,0b00000001
 out SPSR,R16;[7] - SPIF: SPI Interrupt Flag
  ;[6] - WCOL: Write COLlision flag
  ;[5:1] - Res: Reserved Bits
  ;[0] - SPI2X: Double SPI Speed Bit
 in R16,SPSR
 in R16,SPDR;Clear SPIF & WCOL bits


 cbi DFRES_PORT,DFRES;DFlash Reset
   ;DFlash Reset>10us
 ldi ZL,low(SYSCLK/100000)
 ldi ZH,High(SYSCLK/100000)
W10us1:  sbiw ZL,1
 brne W10us1

 sbi DFRES_PORT,DFRES;DFlash Reset = 1

 ldi R16,50 ;Reset Recoveri time = 1 us
W10us2:  dec R16
 brne W10us2

 rcall DF_ReadStatus
 cbr R16,0b11000011
 ldi ZL,low(AT45DBxxx*2);ATmega128 -> set PAMPZ!!
 ldi ZH,high(AT45DBxxx*2)
SearchDF: lpm R17,Z+
 sts DFPageBits,R17
 lpm R18,Z+
 sts DFSize,R18
 lpm R18,Z+
 sts DFPageSize,R18
 lpm R2,Z+
 cp R16,R2
 breq DFHit
 tst R17
 brne SearchDF
DFHit:
 ret

;*****************************************************************************
;*DF_SPI_RW
;*
;* Read and writes one byte from/to SPI master
;*
;* In: R16 - Byte to be written to SPI data register
;*
;* Out: R16 - Byte read from SPI data register
;*
;******************************************************************************
;
DF_SPI_RW:
 out SPDR,R16
DF_SPI_RW0:
 sbis SPSR,spif
  rjmp DF_SPI_RW0;wait for transfer complete, poll SPIF-flag
 in R16,SPDR
 ret

;*****************************************************************************
;*Read_DF_status
;*
;* Status info concerning the Dataflash is busy or not.
;* Status info concerning compare between buffer and flash page
;* Status info concerning size of actual device
;*
;* In: -
;*
;* Out: R16 - status byte. Consult Dataflash datasheet for further decoding info
;*
;******************************************************************************
;
DF_ReadStatus:
 sbi DFCS_PORT,DFCS;DF CS inactive
 nop
 nop
 cbi DFCS_PORT,DFCS;DF CS Active!
   ;to reset dataflash command decoder
 ldi R16,StatusRegMode3
 rcall DF_SPI_RW;send status register read op-code
 clr R16
 rcall DF_SPI_RW;dummy write to get result
 ret


;*****************************************************************************
;* WaitToDF
;*
;* Wait for DataFlash to Ready
;*
;* In: -
;*
;* Out: -
;*
;******************************************************************************
;
WaitToDF:
       rcall DF_ReadStatus
        cbr R16,0x7F;Csak a Busy Flag marad meg
        breq WaitToDF;monitor the status register, wait until busy-flag is high
 sbi DFCS_PORT,DFCS ;DF CS inactive
 nop
 cbi DFCS_PORT,DFCS;DF CS Active! , reset dataflash command decoder
 ret

;*****************************************************************************
;Page_To_Buffer
;
; Transfers a page from flash to dataflash SRAM buffer
;
; In: R0 = BufferNo -> R0 = 0 usage Buffer 1
;            = non zero usage Buffer 2
;  R19:R18 = PageAdr  -> Address of page to be transferred to buffer
;
; Out: -
;*****************************************************************************
;
DF_PageToBuffer:
 rcall WaitToDF
 ldi R16,FlashToBuf1Transfer;transfer to buffer 1 op-code
 tst R0
 breq DF_PageToBuff01
 ldi R16,FlashToBuf2Transfer;transfer to buffer 2 op-code
DF_PageToBuff01:
 rcall DF_SPI_RW;send op-code
 lds R16,DFPageBits
 subi R16,8
DF_PageToBuff02:
 lsl R18
 rol R19
 dec R16
 brne DF_PageToBuff02

 mov R16,R19
 rcall DF_SPI_RW;upper part of page address
 mov R16,R18
 rcall DF_SPI_RW;lower part of page address
 clr R16
 rcall DF_SPI_RW

 sbi DFCS_PORT,DFCS;DF CS inactive
 ret


;*****************************************************************************
;DF_BufferReadByte
;
; Reads one byte from one of the dataflash internal SRAM buffers
;
; In: R0 = BufferNo -> R0 = 0 usage Buffer 1
;            = non zero usage Buffer 2
;  R19:R18 = IntPageAdr  -> Internal page address
;
; Out: R16 - One read byte (any value)
;
;*****************************************************************************
;
DF_BufferReadByte:
 rcall WaitToDF
 ldi R16,Buf1Read;read byte from buffer 1
 tst R0
 breq    BufferReadByte01
 ldi R16,Buf2Read;read byte from buffer 2
BufferReadByte01:
 rcall DF_SPI_RW;send op-code
 clr R16
 rcall DF_SPI_RW;don't cares
 mov R16,R19
 rcall DF_SPI_RW   ;upper part of page address
 mov R16,R18
 rcall DF_SPI_RW      ;lower part of page address
 clr R16
 rcall DF_SPI_RW;additional don't cares
 clr R16
 rcall DF_SPI_RW;read byte
 sbi DFCS_PORT,DFCS;DF CS inactive
 ret


;*****************************************************************************
;DF_BufferReadStr
;
; Reads one or more bytes from one of the dataflash internal SRAM buffers,
; and puts read bytes into buffer pointed to by X
; In: R0:  BufferNo -> R0 = 0 usage Buffer 1
;          = non zero usage Buffer 2
;      R19:R18  -> Internal page address
;      R21:R20  -> Number of bytes to be read
;      X    -> address of buffer to be used for read bytes
;
; Out: -
;
;*****************************************************************************
;
DF_BufferReadStr:
 rcall WaitToDF
 ldi R16,Buf1Read;read byte from buffer 1
 tst R0
 breq    DF_BufferReadStr01
 ldi R16,Buf2Read;read byte from buffer 2
DF_BufferReadStr01:
 rcall DF_SPI_RW;send op-code
 clr R16
 rcall DF_SPI_RW;don't cares
 mov R16,R19
 rcall DF_SPI_RW   ;upper part of page address
 mov R16,R18
 rcall DF_SPI_RW      ;lower part of page address
 clr R16
 rcall DF_SPI_RW;additional don't cares
 push YL
 push YH
 movw YL,R20 ;Internal page address + Number of bytes to be read <= Page Size!!!
DF_BufferReadStr02:
 clr R16
 rcall DF_SPI_RW
 st X+,R16 ;Store DF data byte
 sbiw YL,1
 brne DF_BufferReadStr02
 pop YH
 pop YL
 sbi DFCS_PORT,DFCS;DF CS inactive
 ret

;*****************************************************************************
; DF_BufferWriteEnable
;
; Enables continous write functionality to one of the dataflash buffers
; NOTE : User must ensure that CS goes high to terminate this mode
; before accessing other dataflash functionalities
;
; In: R0:  BufferNo -> R0 = 0 usage Buffer 1
;          = non zero usage Buffer 2
;      R19:R18  -> Internal page address to start writing from
;
; Out: None
;
;*****************************************************************************
;
DF_BufferWriteEnable:
 rcall WaitToDF
 ldi R16,Buf1Write;buffer 1 write op-code
 tst R0
 breq    DF_BufferWriteEnable01
 ldi R16,Buf2Write;buffer 2 write op-code
DF_BufferWriteEnable01:
 rcall DF_SPI_RW;send op-code
 clr R16
 rcall DF_SPI_RW;don't cares
 mov R16,R19
 rcall DF_SPI_RW   ;upper part of page address
 mov R16,R18
 rcall DF_SPI_RW      ;lower part of page address
 ret

;*****************************************************************************
; DF_BufferWriteByte:
;
; Writes one byte to one of the dataflash internal SRAM buffers
;
; In: R0:  BufferNo -> R0 = 0 usage Buffer 1
;          = non zero usage Buffer 2
;      R19:R18  -> Internal page address to write byte to
; R16  -> Data byte to be written
;
; Out: None
;
;*****************************************************************************
;
DF_BufferWriteByte:
 push R16
 rcall WaitToDF
 ldi R16,Buf1Write;buffer 1 write op-code
 tst R0
 breq    DF_BufferWriteByte01
 ldi R16,Buf2Write;buffer 2 write op-code
DF_BufferWriteByte01:
 rcall DF_SPI_RW;send op-code
 clr R16
 rcall DF_SPI_RW;don't cares
 mov R16,R19
 rcall DF_SPI_RW   ;upper part of page address
 mov R16,R18
 rcall DF_SPI_RW      ;lower part of page address
 pop R16
 rcall DF_SPI_RW;write data byte
DF_EndWrite:
 sbi DFCS_PORT,DFCS;DF CS inactive
 ret

;*****************************************************************************
; DF_BufferWriteStr
;
; Copies one or more bytes to one of the dataflash internal SRAM buffers
; from AVR SRAM buffer pointed to by X
;
; In: R0:  BufferNo -> R0 = 0 usage Buffer 1
;          = non zero usage Buffer 2
;      R19:R18  -> Internal page address
;      R21:R20  -> Number of bytes to be read
;      X    -> address of buffer to be used for write bytes
;
; Out: None
;
;*****************************************************************************
;
DF_BufferWriteStr:
 rcall WaitToDF
 ldi R16,Buf1Write;write byte to buffer 1
 tst R0
 breq    DF_BufferWriteStr01
 ldi R16,Buf2Write;write byte to buffer 2
DF_BufferWriteStr01:
 rcall DF_SPI_RW;send op-code
 clr R16
 rcall DF_SPI_RW;don't cares
 mov R16,R19
 rcall DF_SPI_RW   ;upper part of page address
 mov R16,R18
 rcall DF_SPI_RW      ;lower part of page address
 push YL
 push YH
 movw YL,R20 ;Internal page address + Number of bytes to be read <= Page Size!!!
DF_BufferWriteStr02:
 ld R16,X+ ;Store DF data byte
 rcall DF_SPI_RW
 sbiw YL,1
 brne DF_BufferWriteStr02
 pop YH
 pop YL
 ret

;*****************************************************************************
; DF_BufferToPage
; DF_BufferToPageWErase
;
; Transfers a page from dataflash SRAM buffer to flash
;
; In: R0 = BufferNo -> R0 = 0 usage Buffer 1
;            = non zero usage Buffer 2
;  R19:R18 = PageAdr  ->  Address of flash page to be programmed
;
; Out: None
;
;*****************************************************************************
;
DF_BufferToPage:
 rcall WaitToDF
 ldi R16,Buffer1toMem;buffer 1 to flash without erase
 tst R0
 breq    DF_BufferToPage01
 ldi R16,Buffer1toMem
 rjmp DF_BufferToPage01

DF_BufferToPageWErase:
 rcall WaitToDF
 ldi R16,Buf1ToFlashWE;buffer 1 to flash with erase op-code
 tst R0
 breq    DF_BufferToPage01
 ldi R16,Buf2ToFlashWE ;buffer 2 to flash with erase op-code
DF_BufferToPage01:
 rcall DF_SPI_RW;send op-code
 lds R16,DFPageBits
 subi R16,8
DF_BufferToPage02:
 lsl R18
 rol R19
 dec R16
 brne DF_BufferToPage02

 mov R16,R19
 rcall DF_SPI_RW;upper part of page address
 mov R16,R18
 rcall DF_SPI_RW;lower part of page address
 clr R16
 rcall DF_SPI_RW
 nop
 sbi DFCS_PORT,DFCS;DF CS inactive
 ret

;*****************************************************************************
; DF_PageErase
;
; Erase Flash Page
;
; In: R19:R18 = PageAdr  ->  Address of flash page to be erased
;
; Out: None
;
;*****************************************************************************
;
DF_PageErase:
 rcall WaitToDF
 ldi R16,DFPageErase
 rcall DF_SPI_RW;send op-code

 lds R16,DFPageBits
 subi R16,8
DF_PageErase01:
 lsl R18
 rol R19
 dec R16
 brne DF_PageErase01

 mov R16,R19
 rcall DF_SPI_RW;upper part of page address
 mov R16,R18
 rcall DF_SPI_RW;lower part of page address
 clr R16
 rcall DF_SPI_RW;dumpy part of address!!!
 nop
 sbi DFCS_PORT,DFCS;DF CS inactive
 ret



;*****************************************************************************
; DF_CheckErasedPage
;
; Test Erased Flash Page
;
; In: R19:R18 = PageAdr  ->  Address of flash page to be tested
; R0 = used buffer 0 = buffer0 other = buffer1
;
; Out: c=0 no error
; c=1 Bad Page! Dont use!!
;
;*****************************************************************************
;
DF_CheckErasedPage:
 rcall WaitToDF
 push R0
 rcall DF_PageToBuffer

               clr XL
 ldi R16,8
 lds XH,DFPageSize
 mul R16,XH
 add XL,R0
 adc XH,R1 ;X full lenght of page in byte
 pop R0
             
DF_Check00:
 push R0
 push XL
 push XH
 sbiw XL,1
 movw R18,XL
 rcall DF_BufferReadByte
 pop XH
 pop XL
 pop R0
 cpi R16,0xFF
 brne DF_BadPage
 sbiw XL,1
 brne DF_Check00
 clc
 ret  ;ok page cleared well
DF_BadPage:
 sec
 ret  ;Bad Page!


Link to Source: http://www.vfx.hu/avr/download/dflash.asm


Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.