; Orange programmer module v2.2 FASTSPI
; (c) 2013-2014 CnCLab
; SPI FLASH
; 4 BYTE Address! 3 status registers!


; GROUP=Winbond
;CHIP=W25Q256,32768K(256),W25Q256.HPL
;AREA=FLASH,32768K(256)
;AREA=SECURITY,768
;AREA=SFDP,256
;VCC=3250


;bits                7   6   5   4   3   2   1   0
;Status Register1: SRP0 TB  BP3 BP2 BP1 BP0 WEL BUSY
;		 		            r/o r/o
;Status Register2:  SUS CMP LB3 LB2 LB1  R  QE SRP1
;		    r/o		            r/o r/o
;Status Register3:  HOLD DRV1 DRV0 (R) (R) WPS ADP ADS


; Tested W25Q256 Orange5


SOCKET=4 ;"SPI"
OPTIONS=f,,w

PINO=SCK,0
PINO=SI,1
PINO=CS,2
PINO=WP,3
PINO=HOLD,4
PINI=SO,1

BUSO=SPIOUT,0xD4
;BUSO=SPIOUT24,0xD6
BUSO=SPIOUT32,0xD7
BUSI=SPIIN,0xD4


CDELAY=0.1 ; one set delay

R9=STATUS1,C8,SRP0,TB,BP3,BP2,BP1,BP0,WEL,BUSY
R10=STATUS2,C8,SUS,CMP,LB3,LB2,LB1,x,QE,SRP1
R11=STATUS3,C8,HOLD,DRV1,DRV0,x,x,WPS,ADP,ADS
R12=UID,E8
;R9=STATUS,B8
@UID=8


[_SENDBYTE]
;LOOP=(7,0){SI=R0[I],SCK=P}
;speed-up
SPIOUT=R0

[_RX]
SI=1
R1=0
LOOP=(7,0){R1[I]=SO,SCK=P}
;PRINT=L("%02X\n",R1)

;4 bytes
[_SENDADR]
LOOP=(31,0){SI=R0[I],SCK=P}


;Security Register address
;Security Register 1: A23-16 = 00h; A15-8 = 10h; A7-0 = byte address
;Security Register 2: A23-16 = 00h; A15-8 = 20h; A7-0 = byte address
;Security Register 3: A23-16 = 00h; A15-8 = 30h; A7-0 = byte address
[_SENDADR_S]
SI=0,SCK=P16
R0=ADR,R0=/256,R0=+1,R0=<<4
;PRINT=L("RH=%04X\n",R0)
LOOP=(7,0){SI=R0[I],SCK=P}
LOOP=(7,0){SI=ADR[I],SCK=P}  ;A7-0


[_RDID]
CS=0
R0=0
_SENDBYTE(0x9F)  ;JEDEC Read ID
SI=1
LOOP=(23,0){SCK=1,R0[I]=SO,SCK=0}
CS=1


[INIT]
HOLD=1
WP=0
CS=1
SCK=0

_RDID
R0?0xFFFFFF{
PRINT=A("Chip not respond, continue?")
RA?0{EXIT}
}

R0?0x0{
PRINT=A("Chip not respond (SO=0), continue?")
RA?0{EXIT}
}


;Enter 4-Byte Mode (B7h)
CS=0
_SENDBYTE(0xB7)
CS=1


[READ]
$AREA?1{  ;SECURITY
CS=0
_SENDBYTE(0x48)     ;Read
_SENDADR_S
SI=1
SCK=P8 ;Dummy
LOOP=(7,0){SCK=1,DATA[I]=SO,SCK=0}
CS=1
RETURN
}

$AREA?2{  ;SFDP
CS=0
_SENDBYTE(0x5A)     ;Read SFDP Register 
LOOP=(23,0){SI=ADR[I],SCK=P}
SI=1
SCK=P8 ;Dummy
LOOP=(7,0){SCK=1,DATA[I]=SO,SCK=0}
CS=1
RETURN
}

CS=0
_SENDBYTE(0x03)     ;Read main flash
LOOP=(31,0){SI=ADR[I],SCK=P}
SI=1
;LOOP=(7,0){SCK=1,DATA[I]=SO,SCK=0}
DATA=SPIIN
CS=1


;Only for FLASH
[READBLOCK]
CS=0
SPIOUT=0x03 ;_SENDBYTE(0x03)     ;Read
;LOOP=(31,0){SI=ADR[I],SCK=P}
SPIOUT32=ADR
SI=1
LOOP=($BLOCKSIZE){
;LOOP=(7,0){SCK=1,DATA[I]=SO,SCK=0}
DATA=SPIIN
ADR=+1
}
CS=1


[_RDSTAT]
CS=0
_SENDBYTE(00000101b)     ;RDSR
SI=1
R9=0
;LOOP=(7,0){SCK=1,R9[I]=SO,SCK=0}
R9=SPIIN
CS=1


[_WAITWR]	;Wait for end write memory...
SCK=0
LOOP=(0,500){
_RDSTAT
R9[0]?0{BREAK}   ;WIP bit
P=10
}


[_WREN]
SCK=0
CS=0
_SENDBYTE(00000110b)   ; Write enable
CS=1


[WRITEINIT]
HOLD=1
WP=1
CS=1
P=5000
_WREN

CS=0
_SENDBYTE(00000001b)    ;WRSR
_SENDBYTE(00000000b)    ;Status Register
CS=1
P=50000	;!
_WAITWR

[_WRSEC]
_WREN
CS=0
_SENDBYTE(0x42)   ; Program Security Registers (42h)
_SENDADR_S
R0=DATA,_SENDBYTE
CS=1
_WAITWR


[WRITE]
;R0=DATA,R0?0xFF{RETURN}
$AREA?1{_WRSEC,RETURN}

SCK=0
_WREN
CS=0
R0=00000010b   ; Write
_SENDBYTE
LOOP=(31,0){SI=ADR[I],SCK=P}
LOOP=(7,0){SI=DATA[I],SCK=P}
SI=1,CS=1
;P=5000
_WAITWR


; page program time - max 3ms
[WRITEBLOCK]
;R2=ADR	;check empty (0xFF) block
;LOOP=($BLOCKSIZE){
;R1=DATA
;R1?!0xFF{BREAK}
;ADR=+1
;}
;R1?0xFF{RETURN}
;ADR=R2


SCK=0
_WREN
CS=0
_SENDBYTE(00000010b)   ; Write CMD
;LOOP=(31,0){SI=ADR[I],SCK=P}
SPIOUT32=ADR
LOOP=($BLOCKSIZE){
;LOOP=(7,0){SI=DATA[I],SCK=P}
SPIOUT=DATA
ADR=+1
}
CS=1
_WAITWR


[READID]
WP=1
SCK=0
CS=1
_RDID
PRINT=S("ID value = %04lXH",R0)



[ReadStatus]
;HOLD=1
WP=1
SCK=0
CS=1
CS=0
R9=0
_SENDBYTE(0x05)     ;RDSR
SI=1
LOOP=(7,0){SCK=1,R9[I]=SO,SCK=0}
CS=1
P=10
R10=0
CS=0
_SENDBYTE(0x35)     ;RDSR2
SI=1
LOOP=(7,0){SCK=1,R10[I]=SO,SCK=0}
CS=1

R11=0
CS=0
_SENDBYTE(0x15)     ;RDSR3
SI=1
LOOP=(7,0){SCK=1,R11[I]=SO,SCK=0}
CS=1


P=10000
GET=("Status",R9,R10,R11)

[WriteStatus]
GET=("Write Status",R9,R10,R11)
RA?0{EXIT}
WP=1
CS=1
SCK=0
;PRINT=("value %02lX",R9)

_WREN
CS=0
_SENDBYTE(0x01)       ;WRSR
_SENDBYTE(R9)	      ;Status Register
CS=1
P=200000 ;Write Status Register Time 67... 150 ms

_WREN
CS=0
_SENDBYTE(0x31)    ;WRSR2
_SENDBYTE(R10)
CS=1
P=200000 ;Write Status Register Time 67... 150 ms

_WREN
CS=0
_SENDBYTE(0x11)   ;WRSR3
_SENDBYTE(R11)
CS=1
P=200000 ;Write Status Register Time 67... 150 ms



;Read Unique ID Number - factory-set read-only 64-bit number
;Run on PC
[#ReadUniqueID]
WP=0

CS=0
_SENDBYTE(0x4B)  ;Read Unique ID Number (4Bh)
SI=0,SCK=P32 ;Dummy Byte 1-4
SI=1
LOOP(0,7){
_RX
@UID[I]=R1
}
CS=1
R12=0 ;Array 0
GET=("UniqueID",R12)


;erase one Security Register #1
[_ERASESEC1]
R2=R0    ;push
PRINT=S("Erase sec...")
CS=1

_WREN

CS=0
_SENDBYTE(0x44)      ;WRSR
_SENDADR(R2)
CS=1

P=200000 ;Write Status Register Time 67... 150 ms!
_WAITWR



[Erase]
HOLD=1
WP=1
SCK=0

$AREA?1{
PRINT=S("Erase sec...")
CS=1
_WREN
CS=0
_SENDBYTE(00000001b)      ;WRSR
_SENDBYTE(0)	 ;Status Register
CS=1
P=200000 ;Write Status Register Time 67... 150 ms!
_WAITWR
_WREN
CS=0

_ERASESEC1(0x1000)
_ERASESEC1(0x2000)
_ERASESEC1(0x3000)
RETURN}

$AREA?2{
PRINT=E("This area is read-only!")
EXIT}

PRINT=S("Erase flash...")
CS=1
_WREN
CS=0
_SENDBYTE(00000001b)      ;WRSR
_SENDBYTE(0)	 ;Status Register
CS=1
P=200000 ;Write Status Register Time 67... 150 ms!
_WREN
CS=0
_SENDBYTE(11000111b)	;BE Bulk Erase 0xC7
CS=1

; Full erase time:
; Winbond   25..80 sec

SCK=0
R3=0
PRINT=P(0,22000)
LOOP=(22000){ ;110 sec
_RDSTAT
R9[0]?0{BREAK}   ;BUSY bit
P=5000
R3=+1
PRINT=P(R3)
}

PRINT=S("Erase status %02X",R9)
P=400000
R9?!0{
P=600000
PRINT=L("Erase error. Status %02X\n",R9)
}