Line 15... |
Line 15... |
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this program; if not, see http://www.gnu.org/licenses/.
|
along with this program; if not, see http://www.gnu.org/licenses/.
|
!*/
|
!*/
|
|
|
/*
|
/*
|
supports AT45D* Flash on Port E
|
SPI mode of MMC / *SD Cards
|
*/
|
*/
|
|
|
#ifndef[ZTEX_FLASH_H]
|
#ifeq[MMC_PORT][E]
|
#define[ZTEX_FLASH_H]
|
#define[MMC_bmMODE]
|
|
#elifeq[MMC_PORT][A]
|
|
#elifeq[MMC_PORT][B]
|
|
#elifeq[MMC_PORT][C]
|
|
#elifneq[MMC_PORT][D]
|
|
#error[Macro `MMC_PORT' is not defined correctly. Valid values are: `A', `B', `C', `D' and `E'.]
|
|
#endif
|
|
|
|
#ifndef[ZTEX_FLASH1_H]
|
|
#define[ZTEX_FLASH1_H]
|
|
|
|
#define[@CAPABILITY_FLASH;]
|
|
|
|
#ifndef[MMC_PORT]
|
|
#error[MMC_PORT not defined]
|
|
#endif
|
|
|
|
#ifndef[MMC_BIT_CS]
|
|
#error[MMC_BIT_CS not defined]
|
|
#endif
|
|
|
|
#ifndef[MMC_BIT_DI]
|
|
#error[MMC_BIT_DI not defined]
|
|
#endif
|
|
|
|
#ifndef[MMC_BIT_DO]
|
|
#error[MMC_BIT_DO not defined]
|
|
#endif
|
|
|
|
#ifndef[MMC_BIT_CLK]
|
|
#error[MMC_BIT_CLK not defined]
|
|
#endif
|
|
|
|
#define[MMC_bmCS][bmBITMMC_BIT_CS]
|
|
#define[MMC_bmDI][bmBITMMC_BIT_DI]
|
|
#define[MMC_bmDO][bmBITMMC_BIT_DO]
|
|
#define[MMC_bmCLK][bmBITMMC_BIT_CLK]
|
|
|
#define[FLASH_SI_BIT][6]
|
#define[MMC_IO][IOMMC_PORT]
|
#define[FLASH_SO_BIT][4]
|
|
#define[FLASH_CLK_BIT][5]
|
#ifndef[MMC_bmMODE]
|
#ifeq[PRODUCT_IS][UFM-1_1]
|
#define[MMC_CS][IOMMC_PORTMMC_BIT_CS]
|
#define[FLASH_CS_BIT][3]
|
#define[MMC_CLK][IOMMC_PORTMMC_BIT_CLK]
|
//#warning[FLASH_CS_BIT=3]
|
#define[MMC_DI][IOMMC_PORTMMC_BIT_DI]
|
|
#define[MMC_DO][IOMMC_PORTMMC_BIT_DO]
|
|
#endif
|
|
|
|
// 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
|
|
xdata DWORD flash_sectors; // 3 number of sectors
|
|
xdata BYTE flash_ec; // 7 error code
|
|
|
|
xdata BYTE mmc_last_cmd; // 0
|
|
xdata BYTE mmc_response; // 1
|
|
xdata BYTE mmc_buffer[16]; // 2
|
|
|
|
#define[FLASH_EC_CMD_ERROR][1]
|
|
#define[FLASH_EC_TIMEOUT][2]
|
|
#define[FLASH_EC_BUSY][3]
|
|
#define[FLASH_EC_PENDING][4]
|
|
#define[FLASH_EC_READ_ERROR][5]
|
|
#define[FLASH_EC_WRITE_ERROR][6]
|
|
|
|
/* *********************************************************************
|
|
***** mmc_clocks ****************************************************
|
|
********************************************************************* */
|
|
// perform c (256 if c=0) clocks
|
|
void mmc_clocks (BYTE c) {
|
|
c; // this avoids stupid warnings
|
|
_asm
|
|
mov r2,dpl
|
|
#ifdef[MMC_bmMODE]
|
|
mov a,_MMC_IO
|
|
anl a, #(~MMC_bmCLK)
|
|
mov r3, a
|
|
orl a, #(MMC_bmCLK)
|
|
mov r4, a
|
|
010014$:
|
|
mov _MMC_IO,r4
|
|
nop
|
|
mov _MMC_IO,r3
|
#else
|
#else
|
#define[FLASH_CS_BIT][7]
|
010014$:
|
//#warning[FLASH_CS_BIT=7]
|
setb _MMC_CLK
|
|
nop
|
|
clr _MMC_CLK
|
#endif
|
#endif
|
|
djnz r2,010014$
|
|
_endasm;
|
|
}
|
|
|
xdata BYTE flash_buffer = 1; // current buffer 1
|
|
xdata BYTE flash_bufferModified = 0; // 1 indicates that the current flash page needs to be reprogrammeded
|
|
xdata WORD flash_page = 0xffff; // current flash page
|
|
xdata WORD flash_nextPage = 0xffff; // next flash page (usually flashPage+1)
|
|
xdata WORD flash_maxPage = 0; // next flash page (usually flashPage+1)
|
|
xdata WORD flash_pageSize = 528; // page size (512 or 528)
|
|
xdata BYTE flash_register[4]; // used to store register content
|
|
|
|
/* *********************************************************************
|
/* *********************************************************************
|
***** flash_setPage *************************************************
|
***** flash_read_byte ***********************************************
|
********************************************************************* */
|
********************************************************************* */
|
/* set the current page, i.e. executes the following steps
|
// read a single byte from the flash
|
1. wait if busy
|
BYTE flash_read_byte() { // uses r2,r3,r4
|
2. read the desired page from the falsh array into the new buffer
|
_asm
|
3. write the old buffer to the flash array (if modified)
|
#ifdef[MMC_bmMODE]
|
*/
|
// 8 - 1 + 8*13 + 1 + 6 = 118 clocks
|
static void flash_setPage(WORD page)
|
mov a,_MMC_IO
|
{
|
anl a, #(~MMC_bmCLK)
|
flash_nextPage = page + 1;
|
mov r2, a
|
|
orl a, #(MMC_bmCLK)
|
|
mov r3, a
|
|
|
|
mov a,_MMC_IO // 7
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r2
|
|
|
|
mov a,_MMC_IO // 6
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r2
|
|
|
|
mov a,_MMC_IO // 5
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r2
|
|
|
|
mov a,_MMC_IO // 4
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r2
|
|
|
|
mov a,_MMC_IO // 3
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r2
|
|
|
|
mov a,_MMC_IO // 2
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r2
|
|
|
|
mov a,_MMC_IO // 1
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r2
|
|
|
|
mov a,_MMC_IO // 0
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
xrl a,#255
|
|
mov _MMC_IO, r2
|
|
|
|
#else
|
|
// 8*7 + 6 = 62 clocks
|
|
mov c,_MMC_DO // 7
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 6
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 5
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 4
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 3
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 2
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 1
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 0
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
#endif
|
|
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
|
|
#ifdef[MMC_bmMODE]
|
|
mov a,_MMC_IO
|
|
anl a, #(~MMC_bmCLK)
|
|
mov r5, a
|
|
orl a, #(MMC_bmCLK)
|
|
mov r3, a
|
|
|
|
010012$:
|
|
// 8 + len*(-1 + 8*13 - 1 + 2 + 9) + 4 = 12 + len*113 clocks
|
|
mov a,_MMC_IO // 7
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r5
|
|
|
|
mov a,_MMC_IO // 6
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r5
|
|
|
|
mov a,_MMC_IO // 5
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r5
|
|
|
|
mov a,_MMC_IO // 4
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r5
|
|
|
|
mov a,_MMC_IO // 3
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r5
|
|
|
|
mov a,_MMC_IO // 2
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r5
|
|
|
|
mov a,_MMC_IO // 1
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
mov r4,a
|
|
mov _MMC_IO, r5
|
|
|
|
mov a,_MMC_IO // 0
|
|
anl a,#(MMC_bmDO)
|
|
mov _MMC_IO, r3
|
|
subb a,#1
|
|
mov a,r4
|
|
rlc a
|
|
xrl a,#255
|
|
mov _MMC_IO, r5
|
|
#else
|
|
010012$:
|
|
// 2 + len*(8*7 + 9) + 4 = 6 + len*65 clocks
|
|
mov c,_MMC_DO // 7
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 6
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 5
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 4
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 3
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 2
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 1
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
|
|
mov c,_MMC_DO // 0
|
|
setb _MMC_CLK
|
|
rlc a
|
|
clr _MMC_CLK
|
|
#endif
|
|
movx @dptr,a
|
|
inc dptr
|
|
djnz r2,010012$
|
|
_endasm;
|
|
}
|
|
|
|
/* *********************************************************************
|
|
***** flash_write_byte **********************************************
|
|
********************************************************************* */
|
|
// send one bytes from buffer buf to the card
|
|
void flash_write_byte (BYTE b) { // b is in dpl
|
|
b; // this avoids stupid warnings
|
|
_asm
|
|
#ifdef[MMC_bmMODE]
|
|
// up to 7 + 8*12 + 6 = 109 clocks
|
|
mov a,_MMC_IO
|
|
anl a, #(255 - MMC_bmCLK - MMC_bmDI )
|
|
mov r3, a
|
|
mov a,dpl
|
|
|
|
rlc a // 7
|
|
mov _MMC_IO,r3
|
|
jnc 0100157$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100157$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 6
|
|
mov _MMC_IO,r3
|
|
jnc 0100156$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100156$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 5
|
|
mov _MMC_IO,r3
|
|
jnc 0100155$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100155$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 4
|
|
mov _MMC_IO,r3
|
|
jnc 0100154$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100154$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 3
|
|
mov _MMC_IO,r3
|
|
jnc 0100153$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100153$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 2
|
|
mov _MMC_IO,r3
|
|
jnc 0100152$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100152$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 1
|
|
mov _MMC_IO,r3
|
|
jnc 0100151$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100151$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 0
|
|
mov _MMC_IO,r3
|
|
jnc 0100150$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100150$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
mov _MMC_IO,r3
|
|
#else
|
|
// 3 + 8*7 + 4 = 63 clocks
|
|
mov a,dpl
|
|
rlc a // 7
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 6
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 5
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 4
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 3
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 2
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 1
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 0
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
nop
|
|
clr _MMC_CLK
|
|
#endif
|
|
_endasm;
|
}
|
}
|
|
|
/* *********************************************************************
|
/* *********************************************************************
|
***** flash_write ***************************************************
|
***** flash_write ***************************************************
|
********************************************************************* */
|
********************************************************************* */
|
/* writes <bytes> bytes at address <addr> to the current buffer starting at <offs>.
|
// write len (256 id len=0) bytes from the buffer to the flash
|
If <setNextPage> = 1 the next page (defined by <flash_nextPage> is set automatically
|
void flash_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
|
|
#ifdef[MMC_bmMODE]
|
|
// 7 + len*(2 + 8*12 + 7 ) + 6 = 13 + len*105 clocks
|
|
mov a,_MMC_IO
|
|
anl a, #(255 - MMC_bmCLK - MMC_bmDI )
|
|
mov r3, a
|
|
010013$:
|
|
movx a,@dptr
|
|
|
|
rlc a // 7
|
|
mov _MMC_IO,r3
|
|
jnc 0100167$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100167$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 6
|
|
mov _MMC_IO,r3
|
|
jnc 0100166$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100166$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 5
|
|
mov _MMC_IO,r3
|
|
jnc 0100165$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100165$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 4
|
|
mov _MMC_IO,r3
|
|
jnc 0100164$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100164$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 3
|
|
mov _MMC_IO,r3
|
|
jnc 0100163$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100163$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 2
|
|
mov _MMC_IO,r3
|
|
jnc 0100162$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100162$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 1
|
|
mov _MMC_IO,r3
|
|
jnc 0100161$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100161$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
rlc a // 0
|
|
mov _MMC_IO,r3
|
|
jnc 0100160$
|
|
orl _MMC_IO, #(MMC_bmDI)
|
|
0100160$:
|
|
orl _MMC_IO, #(MMC_bmCLK)
|
|
|
|
inc dptr
|
|
djnz r2,010013$
|
|
|
|
mov _MMC_IO,r3
|
|
#else
|
|
010013$:
|
|
// 2 + len*(3 + 8*7 - 1 + 7 ) + 4 = 6 + len*65 clocks
|
|
movx a,@dptr
|
|
rlc a // 7
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 6
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 5
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 4
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 3
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 2
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 1
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
rlc a // 0
|
|
clr _MMC_CLK
|
|
|
|
mov _MMC_DI,c
|
|
setb _MMC_CLK
|
|
inc dptr
|
|
clr _MMC_CLK
|
|
|
|
djnz r2,010013$
|
|
#endif
|
|
_endasm;
|
|
}
|
|
|
|
/* *********************************************************************
|
|
***** mmc_wait_busy *************************************************
|
|
********************************************************************* */
|
|
BYTE mmc_wait_busy () {
|
|
WORD i;
|
|
flash_ec = FLASH_EC_BUSY;
|
|
MMC_IO |= MMC_bmDI; // avoids that in-data is interpreted as command
|
|
for (i=0; (flash_read_byte()!=255) && i<65535; i++ ) ;
|
|
if ( MMC_IO & MMC_bmDO ) {
|
|
flash_ec = 0;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* *********************************************************************
|
|
***** mmc_select ****************************************************
|
|
********************************************************************* */
|
|
/*
|
|
select the card (CS) and waits if busy
|
|
returns 1 if busy
|
*/
|
*/
|
static void flash_write(WORD addr, WORD bytes, WORD offs, BYTE setNextPage)
|
BYTE mmc_select() {
|
{
|
MMC_IO |= MMC_bmCS; // CS = 1
|
addr = 0;
|
mmc_clocks(8); // 8 dummy clocks to finish a previous command
|
bytes = 0;
|
MMC_IO &= ~MMC_bmCS; // CS = 0
|
offs = 0;
|
|
setNextPage = 0;
|
return mmc_wait_busy();
|
}
|
}
|
|
|
/* *********************************************************************
|
/* *********************************************************************
|
***** flash_write ***************************************************
|
***** mmc_deselect **************************************************
|
|
********************************************************************* */
|
|
// de-select the card (CS) and waits if busy
|
|
void mmc_deselect() {
|
|
MMC_IO |= MMC_bmDI; // CS = 1
|
|
mmc_clocks(8); // 8 dummy clocks to finish a previous command
|
|
MMC_IO |= MMC_bmCS; // CS = 1
|
|
mmc_clocks(8); // 8 more dummy clocks
|
|
}
|
|
|
|
/* *********************************************************************
|
|
***** mmc_read_response *********************************************
|
|
********************************************************************* */
|
|
// read the first response byte
|
|
BYTE mmc_read_response() {
|
|
MMC_IO |= MMC_bmDI; // avoids that in-data is interpreted as command
|
|
_asm
|
|
mov r2,#0x255
|
|
010010$:
|
|
lcall _flash_read_byte
|
|
mov a,dpl
|
|
jnb acc.7,010011$
|
|
djnz r2, 010010$
|
|
|
|
010011$:
|
|
mov dptr,#_mmc_response
|
|
movx @dptr,a
|
|
mov dpl,a
|
|
ret
|
|
_endasm;
|
|
return 0; // never ever called, just to avoid stupid warnings
|
|
}
|
|
|
|
/* *********************************************************************
|
|
***** mmc_wait_start ************************************************
|
|
********************************************************************* */
|
|
/*
|
|
wait for the start byte
|
|
returns 1 on error
|
|
*/
|
|
BYTE mmc_wait_start() {
|
|
WORD to;
|
|
to=0;
|
|
MMC_IO |= MMC_bmDI; // avoids that in-data is interpreted as command
|
|
while ( flash_read_byte() != 0xfe ) { // wait for the start byte
|
|
if ( ++to == 0 ) // 65536 * 8 clocks
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* *********************************************************************
|
|
***** flash_read_init ***********************************************
|
|
********************************************************************* */
|
|
/*
|
|
Start the initialization sequence for reading sector s-
|
|
The whole sector must be read.
|
|
returns an error code (FLASH_EC_*). 0 means no error.
|
|
*/
|
|
BYTE flash_read_init(DWORD s) {
|
|
if ( (MMC_IO & MMC_bmCS) == 0 ) {
|
|
return FLASH_EC_PENDING; // we interrupted a pending Flash operation
|
|
}
|
|
if ( mmc_select() ) { // select the card
|
|
mmc_deselect();
|
|
return FLASH_EC_BUSY;
|
|
}
|
|
mmc_last_cmd = 17;
|
|
mmc_buffer[0] = 17 | 64;
|
|
s = s << 1;
|
|
mmc_buffer[1] = s >> 16;
|
|
mmc_buffer[2] = s >> 8;
|
|
mmc_buffer[3] = s;
|
|
mmc_buffer[4] = 0;
|
|
mmc_buffer[5] = 1;
|
|
flash_write(mmc_buffer,6);
|
|
mmc_read_response();
|
|
if ( mmc_response != 0 ) {
|
|
mmc_deselect();
|
|
return FLASH_EC_CMD_ERROR;
|
|
}
|
|
|
|
if ( mmc_wait_start() ) { // wait for the start byte
|
|
mmc_deselect();
|
|
return FLASH_EC_TIMEOUT;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* *********************************************************************
|
|
***** flash_read_finish *********************************************
|
|
********************************************************************* */
|
|
/*
|
|
Reads n dummy bytes (the whole sector has to be read out)
|
|
and runs the finalization sequence for a sector read.
|
|
*/
|
|
void flash_read_finish(WORD n) {
|
|
while ( n > 32 ) {
|
|
mmc_clocks(0); // 256 clocks = 32 dummy bytes
|
|
n-=32;
|
|
}
|
|
mmc_clocks(n << 3);
|
|
mmc_clocks(24); // 16 CRC + 8 dummy clocks
|
|
mmc_deselect();
|
|
}
|
|
|
|
|
|
/* *********************************************************************
|
|
***** flash_write_init **********************************************
|
|
********************************************************************* */
|
|
/*
|
|
Start the initialization sequence for writing sector s
|
|
The whole sectir must be written.
|
|
returns an error code (FLASH_EC_*). 0 means no error.
|
|
*/
|
|
BYTE flash_write_init(DWORD s) {
|
|
if ( (MMC_IO & MMC_bmCS) == 0 ) {
|
|
return FLASH_EC_PENDING; // we interrupted a pending Flash operation
|
|
}
|
|
if ( mmc_select() ) { // select the card
|
|
mmc_deselect();
|
|
return FLASH_EC_BUSY;
|
|
}
|
|
mmc_clocks(8);
|
|
mmc_last_cmd = 24;
|
|
mmc_buffer[0] = 24 | 64;
|
|
s = s << 1;
|
|
mmc_buffer[1] = s >> 16;
|
|
mmc_buffer[2] = s >> 8;
|
|
mmc_buffer[3] = s;
|
|
mmc_buffer[4] = 0;
|
|
mmc_buffer[5] = 1;
|
|
flash_write(mmc_buffer,6);
|
|
mmc_read_response();
|
|
if ( mmc_response != 0 ) {
|
|
mmc_deselect();
|
|
return FLASH_EC_CMD_ERROR;
|
|
}
|
|
|
|
MMC_IO |= MMC_bmDI; // send one dummy byte plus the start byte 0xfe
|
|
mmc_clocks(15);
|
|
MMC_IO &= ~MMC_bmDI;
|
|
MMC_IO |= MMC_bmCLK;
|
|
MMC_IO &= ~MMC_bmCLK;
|
|
return 0;
|
|
}
|
|
|
|
/* *********************************************************************
|
|
***** flash_write_finish ********************************************
|
|
********************************************************************* */
|
|
/*
|
|
Writes n dummy bytes (the whole sector has to be written)
|
|
and runs the finalization sequence for a sector write
|
|
returns an error code (FLASH_EC_*). 0 means no error.
|
|
*/
|
|
BYTE flash_write_finish(WORD n) {
|
|
BYTE b;
|
|
MMC_IO &= ~MMC_bmDI; // value of the dummy data is 0
|
|
while ( n > 32 ) {
|
|
mmc_clocks(0); // 256 clocks = 32 dummy bytes
|
|
n-=32;
|
|
}
|
|
mmc_clocks(n << 3);
|
|
|
|
MMC_IO |= MMC_bmDI;
|
|
mmc_clocks(16); // 16 CRC clocks
|
|
b = flash_read_byte() & 7;
|
|
// mmc_wait_busy(); // not required here, programming continues if card is deslected
|
|
mmc_deselect();
|
|
if ( b != 5 ) { // data response, last three bits must be 5
|
|
return FLASH_EC_WRITE_ERROR;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* *********************************************************************
|
|
***** mmc_send_cmd **************************************************
|
|
********************************************************************* */
|
|
// send a command
|
|
#define[mmc_send_cmd(][,$1);][{ // send a command, argument=0
|
|
mmc_last_cmd = $0;
|
|
mmc_buffer[0] = 64 | ($0 & 127);
|
|
mmc_buffer[1] = 0;
|
|
mmc_buffer[2] = 0;
|
|
mmc_buffer[3] = 0;
|
|
mmc_buffer[4] = 0;
|
|
mmc_buffer[5] = $1 | 1;
|
|
flash_write(mmc_buffer,6);
|
|
mmc_read_response();
|
|
}]
|
|
|
|
/* *********************************************************************
|
|
***** flash_init ****************************************************
|
********************************************************************* */
|
********************************************************************* */
|
static void flash_readRegister(BYTE cmd)
|
// init the card
|
{
|
void flash_init() {
|
BYTE oe,b,i,j;
|
BYTE i;
|
|
|
b = OEE & ( ~( (1 << FLASH_SO_BIT) | (1 << FLASH_SI_BIT) | (1 << FLASH_CLK_BIT) | (1 << FLASH_CS_BIT) ) );
|
flash_enabled = 1;
|
oe = IOE & b;
|
flash_sector_size = 512;
|
IOE = oe | (1 << FLASH_CS_BIT); // CS = 1
|
|
OEE = b | (1 << FLASH_SI_BIT) | (1 << FLASH_CLK_BIT) | (1 << FLASH_CS_BIT);
|
OEMMC_PORT = (OEMMC_PORT & ~MMC_bmDO) | ( MMC_bmCS | MMC_bmDI | MMC_bmCLK );
|
IOE = oe; // CS = 0
|
MMC_IO |= MMC_bmDI;
|
|
MMC_IO |= MMC_bmCS;
|
// CLK=0
|
mmc_clocks(0); // 256 clocks
|
for ( i=0; i<8; i++ ) {
|
|
IOE = b = oe | ((cmd & 128) >> (7-FLASH_SI_BIT)); // CLK = 0, SI=x
|
mmc_select(); // select te card
|
IOE = b | (1 << FLASH_CLK_BIT); // CLK = 1, SI=x
|
flash_ec = FLASH_EC_BUSY;
|
cmd <<= 1;
|
|
}
|
mmc_send_cmd(0, 0x95); // send reset command
|
|
if ( mmc_response & ~1 ) { // check for errors
|
for ( j=0; j<4; j++ ) {
|
goto mmc_init_cmd_err;
|
// CLK = 1
|
}
|
b = 0;
|
|
for ( i=0; i<8; i++ ) {
|
for ( i=0; mmc_response != 0 && i<255; i++ ) { // send the init command and wait wait (up to 1s) until ready
|
IOE = oe; // CLK = 0, SO=x
|
wait(4);
|
b = (b << 1) | ((IOE >> FLASH_SO_BIT) & 1);
|
mmc_send_cmd(1, 0xff);
|
IOE = oe | (1 << FLASH_CLK_BIT); // CLK = 1
|
|
}
|
}
|
flash_register[j]=b;
|
if ( mmc_response != 0 ) { // check for errors
|
|
goto mmc_init_cmd_err;
|
}
|
}
|
|
|
IOE = oe | (1 << FLASH_CS_BIT); // CS = 1
|
mmc_send_cmd(9, 0); // read the CSD
|
|
if ( mmc_wait_start() ) {
|
|
flash_ec = FLASH_EC_TIMEOUT;
|
|
goto mmc_init_err;
|
|
}
|
|
flash_read(mmc_buffer,16);
|
|
mmc_clocks(16); // CRC is clocked out to nirvana
|
|
|
|
i = (mmc_buffer[5] & 15) + ((mmc_buffer[10] >> 7) | ((mmc_buffer[9] & 3) << 1)) - 7;
|
|
flash_sectors = ((mmc_buffer[8] >> 6) | (mmc_buffer[7] << 2) | ((mmc_buffer[6] & 3) << 10)) + 1;
|
|
flash_sectors = flash_sectors << i;
|
|
|
|
flash_ec = 0;
|
|
mmc_deselect();
|
|
|
|
return;
|
|
|
|
mmc_init_cmd_err:
|
|
flash_ec = FLASH_EC_CMD_ERROR;
|
|
mmc_init_err:
|
|
flash_enabled = 0;
|
|
mmc_deselect();
|
}
|
}
|
|
|
|
|
/* *********************************************************************
|
/* *********************************************************************
|
***** EP0 vendor request 0x40 ***************************************
|
***** EP0 vendor request 0x40 ***************************************
|
********************************************************************* */
|
********************************************************************* */
|
|
// send mmc information structure (card size, error status, ...) to the host
|
ADD_EP0_VENDOR_REQUEST((0x40,,
|
ADD_EP0_VENDOR_REQUEST((0x40,,
|
flash_readRegister(SETUPDAT[2]);
|
MEM_COPY1(flash_enabled,EP0BUF,8);
|
EP0BUF[0] = flash_register[0];
|
EP0BCH = 0;
|
EP0BUF[1] = flash_register[1];
|
EP0BCL = 8;
|
EP0BUF[2] = flash_register[2];
|
,,
|
EP0BUF[3] = flash_register[3];
|
));;
|
|
|
|
/* *********************************************************************
|
|
***** EP0 vendor request 0x41 ***************************************
|
|
********************************************************************* */
|
|
void mmc_read_ep0 () {
|
|
flash_read(EP0BUF, ep0_payload_transfer);
|
|
if ( ep0_payload_remaining == 0 ) {
|
|
mmc_clocks(24); // 16 CRC + 8 dummy clocks
|
|
mmc_deselect();
|
|
}
|
|
}
|
|
|
|
ADD_EP0_VENDOR_REQUEST((0x41,, // read (exactly) one sector
|
|
if ( (MMC_IO & MMC_bmCS) == 0 ) {
|
|
flash_ec = FLASH_EC_PENDING; // we interrupted a pending Flash operation
|
|
EP0_STALL;
|
|
}
|
|
if ( mmc_select() ) { // select the card
|
|
mmc_deselect();
|
|
EP0_STALL;
|
|
}
|
|
mmc_last_cmd = 17;
|
|
mmc_buffer[0] = 17 | 64;
|
|
_asm
|
|
clr c
|
|
mov dptr,#(_SETUPDAT + 2)
|
|
movx a,@dptr
|
|
mov dptr,#(_mmc_buffer + 3)
|
|
rlc a
|
|
movx @dptr,a
|
|
|
|
mov dptr,#(_SETUPDAT + 3)
|
|
movx a,@dptr
|
|
mov dptr,#(_mmc_buffer + 2)
|
|
rlc a
|
|
movx @dptr,a
|
|
|
|
mov dptr,#(_SETUPDAT + 4)
|
|
movx a,@dptr
|
|
mov dptr,#(_mmc_buffer + 1)
|
|
rlc a
|
|
movx @dptr,a
|
|
_endasm;
|
|
mmc_buffer[4] = 0;
|
|
mmc_buffer[5] = 1;
|
|
flash_write(mmc_buffer,6);
|
|
mmc_read_response();
|
|
if ( mmc_response != 0 ) {
|
|
flash_ec = FLASH_EC_CMD_ERROR;
|
|
mmc_deselect();
|
|
EP0_STALL;
|
|
}
|
|
|
|
if ( mmc_wait_start() ) { // wait for the start byte
|
|
flash_ec = FLASH_EC_TIMEOUT;
|
|
mmc_deselect();
|
|
EP0_STALL;
|
|
}
|
|
|
|
mmc_read_ep0();
|
|
EP0BCH = 0;
|
|
EP0BCL = ep0_payload_transfer;
|
|
,,
|
|
if ( ep0_payload_transfer != 0 ) {
|
|
mmc_read_ep0();
|
|
}
|
|
EP0BCH = 0;
|
|
EP0BCL = ep0_payload_transfer;
|
|
));;
|
|
|
|
/* *********************************************************************
|
|
***** EP0 vendor command 0x42 ***************************************
|
|
********************************************************************* */
|
|
void mmc_send_ep0 () {
|
|
flash_write(EP0BUF, ep0_payload_transfer);
|
|
if ( ep0_payload_remaining == 0 ) {
|
|
MMC_IO |= MMC_bmDI;
|
|
mmc_clocks(16); // 16 CRC clocks
|
|
if ( (flash_read_byte() & 7) != 5 ) { // data response, last three bits must be 5
|
|
flash_ec = FLASH_EC_WRITE_ERROR;
|
|
}
|
|
// mmc_wait_busy(); // not required here, programming continues if card is deselected
|
|
mmc_deselect();
|
|
}
|
|
}
|
|
|
|
ADD_EP0_VENDOR_COMMAND((0x42,, // write (exactly!) one sector
|
|
if ( (MMC_IO & MMC_bmCS) == 0 ) {
|
|
flash_ec = FLASH_EC_PENDING; // we interrupted a pending Flash operation
|
|
EP0_STALL;
|
|
}
|
|
if ( mmc_select() ) { // select the card
|
|
mmc_deselect();
|
|
EP0_STALL;
|
|
}
|
|
mmc_last_cmd = 24;
|
|
mmc_buffer[0] = 24 | 64;
|
|
_asm
|
|
clr c
|
|
mov dptr,#(_SETUPDAT + 2)
|
|
movx a,@dptr
|
|
mov dptr,#(_mmc_buffer + 3)
|
|
rlc a
|
|
movx @dptr,a
|
|
|
|
mov dptr,#(_SETUPDAT + 3)
|
|
movx a,@dptr
|
|
mov dptr,#(_mmc_buffer + 2)
|
|
rlc a
|
|
movx @dptr,a
|
|
|
|
mov dptr,#(_SETUPDAT + 4)
|
|
movx a,@dptr
|
|
mov dptr,#(_mmc_buffer + 1)
|
|
rlc a
|
|
movx @dptr,a
|
|
_endasm;
|
|
mmc_buffer[4] = 0;
|
|
mmc_buffer[5] = 1;
|
|
flash_write(mmc_buffer,6);
|
|
mmc_read_response();
|
|
if ( mmc_response != 0 ) {
|
|
flash_ec = FLASH_EC_CMD_ERROR;
|
|
mmc_deselect();
|
|
EP0_STALL;
|
|
}
|
|
|
|
MMC_IO |= MMC_bmDI; // send one dummy byte plus the start byte 0xfe
|
|
mmc_clocks(15);
|
|
MMC_IO &= ~MMC_bmDI;
|
|
MMC_IO |= MMC_bmCLK;
|
|
MMC_IO &= ~MMC_bmCLK;
|
|
,,
|
|
if ( ep0_payload_transfer != 0 ) {
|
|
flash_ec = 0;
|
|
mmc_send_ep0();
|
|
if ( flash_ec != 0 ) {
|
|
EP0_STALL;
|
|
}
|
|
}
|
|
));;
|
|
|
|
/* *********************************************************************
|
|
***** EP0 vendor request 0x43 ***************************************
|
|
********************************************************************* */
|
|
// send detailed MMC status plus debug information
|
|
ADD_EP0_VENDOR_REQUEST((0x43,, // this may interrupt a pending operation
|
|
MEM_COPY1(flash_ec,EP0BUF+2,19);
|
|
EP0BUF[21] = (MMC_IO & MMC_bmDO) == 0;
|
|
mmc_select();
|
|
mmc_send_cmd(13, 0);
|
|
EP0BUF[0] = mmc_response;
|
|
EP0BUF[1] = flash_read_byte();
|
|
mmc_deselect();
|
EP0BCH = 0;
|
EP0BCH = 0;
|
EP0BCL = 4;
|
EP0BCL = 22;
|
,,));;
|
,,
|
|
));;
|
|
|
#endif /*ZTEX_DESCRIPTORS_H*/
|
#endif /*ZTEX_FLASH1_H*/
|
|
|
No newline at end of file
|
No newline at end of file
|