OpenCores
URL https://opencores.org/ocsvn/usb_fpga_1_15/usb_fpga_1_15/trunk

Subversion Repositories usb_fpga_1_15

[/] [usb_fpga_1_15/] [trunk/] [include/] [ztex-flash2.h] - Rev 4

Compare with Previous | Blame | View Log

/*!
   ZTEX Firmware Kit for EZ-USB FX2 Microcontrollers
   Copyright (C) 2009-2014 ZTEX GmbH.
   http://www.ztex.de
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 3 as
   published by the Free Software Foundation.
 
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   General Public License for more details.
 
   You should have received a copy of the GNU General Public License
   along with this program; if not, see http://www.gnu.org/licenses/.
!*/
 
/*
    Support for standard SPI flash. 
*/    
 
#ifeq[SPI_PORT][A]
#elifeq[SPI_PORT][B]
#elifeq[SPI_PORT][C]
#elifneq[SPI_PORT][D]
#error[Macro `SPI_PORT' is not defined correctly. Valid values are: `A', `B', `C' and `D'.]
#endif
 
#ifndef[ZTEX_FLASH1_H]
#define[ZTEX_FLASH1_H]
 
#define[@CAPABILITY_FLASH;]
 
#ifndef[SPI_PORT]
#error[SPI_PORT not defined]
#endif
 
#ifndef[SPI_BIT_CS]
#error[SPI_BIT_CS not defined]
#endif
 
#ifndef[SPI_BIT_DI]
#error[SPI_BIT_DI not defined]
#endif
 
#ifndef[SPI_BIT_DO]
#error[SPI_BIT_DO not defined]
#endif
 
#ifndef[SPI_BIT_CLK]
#error[SPI_BIT_CLK not defined]
#endif
 
#ifndef[SPI_OPORT]
#define[SPI_OPORT][SPI_PORT]
#endif
 
#define[SPI_IO@][IOSPI_PORT]
#define[SPI_OIO@][IOSPI_OPORT]
 
#define[SPI_CS][SPI_IO@SPI_BIT_CS]
#define[SPI_CLK][SPI_IO@SPI_BIT_CLK]
#define[SPI_DI][SPI_IO@SPI_BIT_DI]
#define[SPI_DO][SPI_OIO@SPI_BIT_DO]
 
// may be redefined if the first sectors are reserved (e.g. for a FPGA bitstream)
#define[FLASH_FIRST_FREE_SECTOR][0]
 
__xdata BYTE flash_enabled;	// 0	1: enabled, 0:disabled
__xdata WORD flash_sector_size; // 1    sector size <sector size> = MSB==0 : flash_sector_size and 0x7fff ? 1<<(flash_sector_size and 0x7fff)
__xdata DWORD flash_sectors;	// 3	number of sectors
__xdata BYTE flash_ec; 	        // 7	error code
 
__xdata BYTE spi_vendor;	// 0
__xdata BYTE spi_device;	// 1
__xdata BYTE spi_memtype;	// 2
__xdata BYTE spi_erase_cmd;	// 3
__xdata BYTE spi_last_cmd;	// 4
__xdata BYTE spi_buffer[4];	// 5
 
__xdata WORD spi_write_addr_hi;
__xdata BYTE spi_write_addr_lo;
__xdata BYTE spi_need_pp;
__xdata WORD spi_write_sector;
__xdata BYTE ep0_read_mode;
__xdata BYTE ep0_write_mode;
 
#define[FLASH_EC_TIMEOUT][2]
#define[FLASH_EC_BUSY][3]
#define[FLASH_EC_PENDING][4]
#define[FLASH_EC_NOTSUPPORTED][7]
 
/* *********************************************************************
   ***** spi_clocks ****************************************************
   ********************************************************************* */
// perform c (256 if c=0) clocks
void spi_clocks (BYTE c) {
	c;					// this avoids stupid warnings
__asm
	mov 	r2,dpl
010014$:
        setb	_SPI_CLK	// 1
        nop			// 1
        nop			// 1
        nop			// 1
        clr	_SPI_CLK	// 1
	djnz 	r2,010014$	// 3
__endasm;    
}
 
 
/* *********************************************************************
   ***** flash_read_byte ***********************************************
   ********************************************************************* */
// read a single byte from the flash
BYTE flash_read_byte() { // uses r2,r3,r4
__asm  
	// 8*7 + 6 = 62 clocks 
	mov	c,_SPI_DO	// 7
        setb	_SPI_CLK
        rlc 	a		
        clr	_SPI_CLK
 
        mov	c,_SPI_DO	// 6
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 5
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 4
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 3
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 2
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 1
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 0
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
        mov	dpl,a
        ret
__endasm;
	return 0;		// never ever called (just to avoid warnings)
} 
 
/* *********************************************************************
   ***** flash_read ****************************************************
   ********************************************************************* */
// read len (256 if len=0) bytes from the flash to the buffer
void flash_read(__xdata BYTE *buf, BYTE len) {
	*buf;					// this avoids stupid warnings
	len;					// this too
__asm						// *buf is in dptr, len is in _flash_read_PARM_2
	mov	r2,_flash_read_PARM_2
010012$:
	// 2 + len*(8*7 + 9) + 4 = 6 + len*65 clocks
	mov	c,_SPI_DO	// 7
        setb	_SPI_CLK
        rlc 	a		
        clr	_SPI_CLK
 
        mov	c,_SPI_DO	// 6
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 5
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 4
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 3
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 2
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 1
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
        mov	c,_SPI_DO	// 0
        setb 	_SPI_CLK
        rlc 	a		
        clr 	_SPI_CLK
 
	movx	@dptr,a
	inc	dptr
	djnz 	r2,010012$
__endasm;
} 
 
/* *********************************************************************
   ***** spi_write_byte ************************************************
   ********************************************************************* */
// send one bytes from buffer buf to the card
void spi_write_byte (BYTE b) {	// b is in dpl
	b;				// this avoids stupid warnings
__asm
        // 3 + 8*7 + 4 = 63 clocks 
	mov 	a,dpl
	rlc	a		// 7
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 6
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 5
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 4
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 3
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 2
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 1
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 0
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	nop
        clr	_SPI_CLK
__endasm;
}  
 
/* *********************************************************************
   ***** spi_write *****************************************************
   ********************************************************************* */
// write len (256 if len=0) bytes from the buffer to the flash
void spi_write(__xdata BYTE *buf, BYTE len) {
	*buf;					// this avoids stupid warnings
	len;					// this too
__asm						// *buf is in dptr, len is in _flash_read_PARM_2
	mov	r2,_flash_read_PARM_2
010013$:
	// 2 + len*(3 + 8*7 - 1 + 7 ) + 4 = 6 + len*65 clocks
	movx	a,@dptr
	rlc	a		// 7
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 6
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 5
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 4
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 3
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 2
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 1
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	rlc	a		// 0
        clr	_SPI_CLK
 
	mov	_SPI_DI,c
        setb	_SPI_CLK
	inc	dptr
        clr	_SPI_CLK 
 
	djnz 	r2,010013$ 
__endasm;
} 
 
/* *********************************************************************
   ***** spi_select ****************************************************
   ********************************************************************* */
/* 
   select the flash (CS)
*/
void spi_select() {
    SPI_CS = 1;					// CS = 1;
    spi_clocks(8);				// 8 dummy clocks to finish a previous command
    SPI_CS = 0;
}
 
/* *********************************************************************
   ***** spi_deselect **************************************************
   ********************************************************************* */
// de-select the flash (CS)
void spi_deselect() {
    SPI_CS = 1;					// CS = 1;
    spi_clocks(8);				// 8 dummy clocks to finish a previous command
}
 
/* *********************************************************************
   ***** spi_start_cmd *************************************************
   ********************************************************************* */
// send a command   
#define[spi_start_cmd(][);][{			// send a command, argument=0
    spi_last_cmd = $0;
    spi_select();				// select
    spi_write_byte($0);				// CMD 90h
}]    
 
/* *********************************************************************
   ***** spi_wait ******************************************************
   ********************************************************************* */
/* 
   wait if prvious read/write command is still prcessed
   result is flash_ec (FLASH_EC_TIMEOUT or 0)
*/
BYTE spi_wait() {
    WORD i;
    // wait up to 11s
    spi_start_cmd(0x05);
    for (i=0; (flash_read_byte() & bmBIT0) && i<65535; i++ ) { 
	spi_clocks(0);				// 256 dummy clocks
//	uwait(20);
    }
    flash_ec = flash_read_byte() & bmBIT0 ? FLASH_EC_TIMEOUT : 0;
    spi_deselect();
    return flash_ec;
}
 
/* *********************************************************************
   ***** flash_read_init ***********************************************
   ********************************************************************* */
/*
   Start the initialization sequence for reading sector s.
   returns an error code (FLASH_EC_*). 0 means no error.
*/   
BYTE flash_read_init(WORD s) {
    if ( (SPI_CS) == 0 ) {
	flash_ec = FLASH_EC_PENDING;
	return FLASH_EC_PENDING;		// we interrupted a pending Flash operation
    }  
    OESPI_OPORT &= ~bmBITSPI_BIT_DO;
    OESPI_PORT |= bmBITSPI_BIT_CS | bmBITSPI_BIT_DI | bmBITSPI_BIT_CLK;
    if ( spi_wait() ) {
	return flash_ec;
    }
 
    s = s << ((BYTE)flash_sector_size - 8);     
    spi_start_cmd(0x0b);			// read command
    spi_write_byte(s >> 8);			// 24 byte address
    spi_write_byte(s & 255);
    spi_write_byte(0);
    spi_clocks(8);				// 8 dummy clocks
    return 0;
} 
 
/* *********************************************************************
   ***** flash_read_next ***********************************************
   ********************************************************************* */
/*
   dummy function for compatibilty
*/   
BYTE flash_read_next() {
    return 0;
} 
 
 
/* *********************************************************************
   ***** flash_read_finish *********************************************
   ********************************************************************* */
/*
    Runs the finalization sequence for the read operation.
*/   
void flash_read_finish(WORD n) {
   n;					// avoids warnings
   spi_deselect();
}
 
 
/* *********************************************************************
   ***** spi_pp ********************************************************
   ********************************************************************* */
BYTE spi_pp () {	
    spi_deselect();				// finish previous write cmd
 
    spi_need_pp = 0;
 
    if ( spi_wait() ) {
	return flash_ec;
    }
    spi_start_cmd(0x06);			// write enable command
    spi_deselect();
 
    spi_start_cmd(0x02);			// page write
    spi_write_byte(spi_write_addr_hi >> 8);	// 24 byte address
    spi_write_byte(spi_write_addr_hi & 255);
    spi_write_byte(0);
    return 0;
}
 
 
/* *********************************************************************
   ***** flash_write_byte **********************************************
   ********************************************************************* */
BYTE flash_write_byte (BYTE b) {
    if ( spi_need_pp && spi_pp() ) return flash_ec;
    spi_write_byte(b);
    spi_write_addr_lo++;
    if ( spi_write_addr_lo == 0 ) {
	spi_write_addr_hi++;
	spi_deselect();				// finish write cmd
	spi_need_pp = 1;
    }
    return 0;
}
 
 
/* *********************************************************************
   ***** flash_write ***************************************************
   ********************************************************************* */
// write len (256 if len=0) bytes from the buffer to the flash
BYTE flash_write(__xdata BYTE *buf, BYTE len) {
    BYTE b;
    if ( spi_need_pp && spi_pp() ) return flash_ec;
 
    if ( spi_write_addr_lo == 0 ) {
	spi_write(buf,len);
    }
    else {
	b = (~spi_write_addr_lo) + 1;
	if ( len==0 || len>b ) {
	    spi_write(buf,b);
	    len-=b;
	    spi_write_addr_hi++;
	    spi_write_addr_lo=0;
	    buf+=b;
	    if ( spi_pp() ) return flash_ec;
	}
	spi_write(buf,len);
    }
 
    spi_write_addr_lo+=len;
 
    if ( spi_write_addr_lo == 0 ) {
	spi_write_addr_hi++;
	spi_deselect();				// finish write cmd
	spi_need_pp = 1;
    }
 
    return 0;
}
 
 
/* *********************************************************************
   ***** flash_write_init **********************************************
   ********************************************************************* */
/*
   Start the initialization sequence for writing sector s
   The whole sector will be modified
   returns an error code (FLASH_EC_*). 0 means no error.
*/
BYTE flash_write_init(WORD s) {
    if ( !SPI_CS ) {
	flash_ec = FLASH_EC_PENDING;
	return FLASH_EC_PENDING;		// we interrupted a pending Flash operation
    }  
    OESPI_OPORT &= ~bmBITSPI_BIT_DO;
    OESPI_PORT |= bmBITSPI_BIT_CS | bmBITSPI_BIT_DI | bmBITSPI_BIT_CLK;
    if ( spi_wait() ) {
	return flash_ec;
    }
    spi_write_sector = s;
    s = s << ((BYTE)flash_sector_size - 8);     
    spi_write_addr_hi = s;
    spi_write_addr_lo = 0;
 
    spi_start_cmd(0x06);			// write enable command
    spi_deselect();
 
    spi_start_cmd(spi_erase_cmd);		// erase command
    spi_write_byte(s >> 8);			// 24 byte address
    spi_write_byte(s & 255);
    spi_write_byte(0);
    spi_deselect();
 
    spi_need_pp = 1;
    return 0;
}
 
 
/* *********************************************************************
   ***** flash_write_finish_sector *************************************
   ********************************************************************* */
/*
   Dummy function for compatibilty.
*/
BYTE flash_write_finish_sector (WORD n) {
    n;
    spi_deselect();
    return 0;
}
 
 
/* *********************************************************************
   ***** flash_write_finish ********************************************
   ********************************************************************* */
/*
   Dummy function for compatibilty.
*/
void flash_write_finish () {
    spi_deselect();
}
 
 
/* *********************************************************************
   ***** flash_write_next **********************************************
   ********************************************************************* */
/*
   Prepare the next sector for writing, see flash_write_finish1.
*/
BYTE flash_write_next () {
    spi_deselect();
    return flash_write_init(spi_write_sector+1);
}
 
 
/* *********************************************************************
   ***** flash_init ****************************************************
   ********************************************************************* */
// init the flash
void flash_init() {
    BYTE i;
 
    PORTCCFG = 0;
 
    flash_enabled = 1;
    flash_ec = 0;
    flash_sector_size = 0x8010;  // 64 KByte
    spi_erase_cmd = 0xd8;
 
    OESPI_OPORT &= ~bmBITSPI_BIT_DO;
    OESPI_PORT |= bmBITSPI_BIT_CS | bmBITSPI_BIT_DI | bmBITSPI_BIT_CLK;
    SPI_CS = 1;
    spi_clocks(0);				// 256 clocks
 
    spi_start_cmd(0x90);			// CMD 90h, not supported by all chips
    spi_clocks(24);				// ADDR=0
    spi_device = flash_read_byte();			
    spi_deselect();				// deselect
 
    spi_start_cmd(0x9F);			// CMD 9Fh
    flash_read(spi_buffer,3);			// read data
    spi_deselect();				// deselect
    if ( spi_buffer[2]<16 || spi_buffer[2]>24 ) {
	goto  disable;
    }
    spi_vendor = spi_buffer[0];
    spi_memtype = spi_buffer[1];
 
#ifeq[USE_4KSECTORS_ENABLED][1]
    if ( ( spi_vendor==1 && spi_memtype == 0x40 ) ||
	 ( spi_vendor==0x20 && spi_memtype == 0xba )
       ) {
	// support of uniform 4 kbyte (logical) sectors
        flash_sector_size = 0x800C;  // 4 KByte
	spi_erase_cmd = 0x20;
	i=spi_buffer[2]-12;
    }
    else {
	// support of uniform 64 kbyte (logical) sectors
	i=spi_buffer[2]-16;
    }
#else    
    i=spi_buffer[2]-16;
#endif    
    flash_sectors = 1 << i;
 
    return;
 
disable:
    flash_enabled = 0;
    flash_ec = FLASH_EC_NOTSUPPORTED;
    OESPI_PORT &= ~( bmBITSPI_BIT_CS | bmBITSPI_BIT_DI | bmBITSPI_BIT_CLK );
}
 
 
/* *********************************************************************
   ***** EP0 vendor request 0x40 ***************************************
   ********************************************************************* */
// send flash information structure (card size, error status,  ...) to the host
ADD_EP0_VENDOR_REQUEST((0x40,,
    if ( flash_ec == 0 && SPI_CS == 0 ) {
	flash_ec = FLASH_EC_PENDING;
    }
    MEM_COPY1(flash_enabled,EP0BUF,8);
    EP0BCH = 0;
    EP0BCL = 8;
,,
));;
 
/* *********************************************************************
   ***** EP0 vendor request 0x41 ***************************************
   ********************************************************************* */
/* read modes (ep0_read_mode)
	0: start read
	1: continue read
	2: finish read
*/
void spi_read_ep0 () { 
    flash_read(EP0BUF, ep0_payload_transfer);
    if ( ep0_read_mode==2 && ep0_payload_remaining==0 ) {
	spi_deselect();
    } 
}
 
ADD_EP0_VENDOR_REQUEST((0x41,,			// read data
    ep0_read_mode = SETUPDAT[5];
    if ( (ep0_read_mode==0) && flash_read_init((SETUPDAT[3] << 8) | SETUPDAT[2]) ) {
	EP0_STALL;
    }  
    spi_read_ep0();  
    EP0BCH = 0;
    EP0BCL = ep0_payload_transfer; 
,,
    if ( ep0_payload_transfer != 0 ) {
	flash_ec = 0;
        spi_read_ep0(); 
    } 
    EP0BCH = 0;
    EP0BCL = ep0_payload_transfer;
));;
 
/* *********************************************************************
   ***** EP0 vendor command 0x42 ***************************************
   ********************************************************************* */
void spi_send_ep0 () { 
    flash_write(EP0BUF, ep0_payload_transfer);
    if ( ep0_write_mode==2 && ep0_payload_remaining==0 ) {
	spi_deselect();
    } 
}
 
ADD_EP0_VENDOR_COMMAND((0x42,,			// write integer number of sectors
    ep0_write_mode = SETUPDAT[5];
    if ( (ep0_write_mode == 0) && flash_write_init((SETUPDAT[3] << 8) | SETUPDAT[2]) ) {
	EP0_STALL;
    }
,,
    if ( ep0_payload_transfer != 0 ) {
	flash_ec = 0;
	spi_send_ep0();
        if ( flash_ec != 0 ) {
    	    spi_deselect();
	    EP0_STALL;
	} 
    } 
));;
 
/* *********************************************************************
   ***** EP0 vendor request 0x43 ***************************************
   ********************************************************************* */
// send detailed SPI status plus debug information
ADD_EP0_VENDOR_REQUEST((0x43,,
    MEM_COPY1(flash_ec,EP0BUF,10);	
    EP0BCH = 0;
    EP0BCL = 10;
,,
));;
 
#endif  /*ZTEX_FLASH1_H*/

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.