📄 flash.c
字号:
static byte *selp;
static byte sechigh;
static byte *flashptr; /* flash window (64K bytes) */
static int oldsector = -1;
word i;
int retry;
/**************************************************************/
/* IMPORTANT: Note that flashptr is defined as a WORD pointer */
/* If BYTE pointers are used, the command tables will have to */
/* be remapped */
/* Note 1: flashptr is declared far - if system does not */
/* support far pointers, this will have to be changed */
/* Note 2: flashptr is declared static to avoid calling */
/* get_flash_memptr() on successive sector accesses */
/**************************************************************/
/******************************************************************/
/* On systems where bus glitching is prevalent, some long command */
/* strings may be interrupted and cause the command to fail (this */
/* is most probable on six cycle commands such as chip erase). In */
/* order to ensure that flash_command executes the command */
/* properly, it may be necessary to issue the command more than */
/* once in order for it to be accepted by the flash device. In */
/* these cases it is recommended that the retry number be made */
/* positive (such as 1 or 2), so that flash_command will try */
/* to issue the command more than once. Keep in mind that this */
/* will only be attempted if the command fails in the first */
/* attempt. */
/******************************************************************/
static int retrycount[] = {0,0,0,0,0,0,0,0,0,0};
retry = retrycount[command];
if(sector != oldsector) {
flashptr = (byte *) get_flash_memptr(sector);
}
again:
if (command == FLASH_SELECT) {
return;
} else if (command == FLASH_RESET || command > FLASH_LASTCMD) {
flashptr[0] = 0xF0; /* assume reset device to read mode */
} else if (command == FLASH_ESUSPEND) {
flashptr[0] = 0xB0; /* suspend sector erase */
} else if (command == FLASH_ERESUME) {
flashptr[0] = 0x30; /* resume suspended sector erase */
} else if (command == FLASH_UBPROG) {
flashptr[0] = 0xA0;
flashptr[sector*0x10000+offset] = data;
} else if (command == FLASH_UBRESET) {
flashptr[0] = 0x90;
flashptr[0] = 0x00;
}
else {
flashptr[0x555] = 0xAA; /* unlock 1 */
flashptr[0x2AA] = 0x55; /* unlock 2 */
switch (command) {
case FLASH_AUTOSEL:
flashptr[0x555] = 0x90;
break;
case FLASH_PROG:
flashptr[0x555] = 0xA0;
flashptr[0x10000*sector+offset] = data;
break;
case FLASH_CERASE:
flashptr[0x555] = 0x80;
flashptr[0x555] = 0xAA;
flashptr[0x2AA] = 0x55;
flashptr[0x555] = 0x10;
break;
case FLASH_SERASE:
flashptr[0x555] = 0x80;
flashptr[0x555] = 0xAA;
flashptr[0x2AA] = 0x55;
flashptr[sector*0x10000+offset] = 0x30;
break;
case FLASH_UB:
flashptr[0x555] = 0x20;
break;
}
}
if (retry-- > 0 && flash_status(flashptr) == STATUS_READY) {
goto again;
}
}
/*********************************************************************/
/* Flash_write extends the functionality of flash_program() by */
/* providing an faster way to program multiple data words, without */
/* needing the function overhead of looping algorithms which */
/* program word by word. This function utilizes fast pointers */
/* to quickly loop through bulk data. */
/*********************************************************************/
int flash_write(int sector, unsigned offset, byte *buf,
int nbytes, int ub)
{
byte *flashptr; /* flash window */
byte *src, *dst;
word i;
int stat;
int retry = 0, retried = 0;
flashptr = (byte *)get_flash_memptr(sector);
dst = flashptr + offset/2; /* (byte offset) */
src = (byte *)buf;
if ((nbytes | offset) & 1) {
return -1;
}
again:
/* Check to see if we're in unlock bypass mode */
if (ub == FALSE)
flashptr[0] = 0xF0; /* reset device to read mode */
while ((stat = flash_status(flashptr)) == STATUS_BUSY) {}
if (stat != STATUS_READY) {
return (byte *)src - buf;
}
while (nbytes > 0) {
if (ub == FALSE){
flashptr[0x555] = 0xAA; /* unlock 1 */
flashptr[0x2AA] = 0x55; /* unlock 2 */
}
flashptr[0x555] = 0xA0;
*dst++ = *src++;
for(i=0;i<0x50;i++)
i=i;
while ((stat = flash_status(flashptr)) == STATUS_BUSY) {}
if (stat != STATUS_READY) break;
nbytes -= 2;
}
if (stat != STATUS_READY || nbytes != 0) {
if (retry-- > 0) {
++retried;
--dst, --src; /* back up */
goto again; /* and retry the last word */
}
if (ub == FALSE)
flash_command(FLASH_RESET,sector,0,0);
}
return ((byte *)src - buf);
}
/*********************************************************************/
/* Flash_status utilizes the DQ6, DQ5, and DQ3 polling algorithms */
/* described in the flash data book. It can quickly ascertain the */
/* operational status of the flash device, and return an */
/* appropriate status code (defined in flash.h) */
/*********************************************************************/
int flash_status(word *fp)
{
unsigned char d, t;
int retry = 1;
again:
d = *fp; /* read data */
t = d ^ *fp; /* read it again and see what toggled */
if (t == 0) { /* no toggles, nothing's happening */
return STATUS_READY;
}
else if (t == 0x04) { /* erase-suspend */
if (retry--) goto again; /* may have been write completion */
return STATUS_ERSUSP;
}
else if (t & 0x40) {
if (d & 0x20) { /* timeout */
return STATUS_TIMEOUT;
}
else {
return STATUS_BUSY;
}
}
if (retry--) goto again; /* may have been write completion */
return STATUS_ERROR;
}
/*********************************************************************/
/* BEGIN API WRAPPER FUNCTIONS */
/*********************************************************************/
/* Flash_sector_erase() will erase a single sector dictated by the */
/* sector parameter. */
/* Note: this function will merely BEGIN the erase program. Code */
/* execution will immediately return to the calling function */
/*********************************************************************/
byte flash_sector_erase(byte sector)
{
flash_command(FLASH_SERASE,sector,0,0);
return(1);
}
/*********************************************************************/
/* Flash_sector_erase_int() is identical to flash_sector_erase(), */
/* except it will wait until the erase is completed before returning */
/* control to the calling function. This can be used in cases which */
/* require the program to hold until a sector is erased, without */
/* adding the wait check external to this function. */
/*********************************************************************/
byte flash_sector_erase_int(byte sector)
{
flash_command(FLASH_SERASE,sector,0,0);
while (flash_status((byte *)get_flash_memptr(sector))
== STATUS_BUSY) { }
return(1);
}
/*********************************************************************/
/* flash_reset() will reset the flash device to reading array data. */
/* It is good practice to call this function after autoselect */
/* sequences had been performed. */
/*********************************************************************/
byte flash_reset(void)
{
flash_command(FLASH_RESET,1,0,0);
return(1);
}
/*********************************************************************/
/* flash_get_device_id() will perform an autoselect sequence on the */
/* flash device, and return the device id of the component. */
/* This function automatically resets to read mode. */
/*********************************************************************/
byte flash_get_device_id(byte sector)
{
byte *fwp; /* flash window */
byte answer;
fwp = (byte *)get_flash_memptr(sector);
flash_command(FLASH_AUTOSEL,sector,0,0);
answer = *((fwp+1));
flash_command(FLASH_RESET,sector,0,0); /* just to be safe */
return( (byte) answer );
}
/*********************************************************************/
/* flash_get_manuf_code() will perform an autoselect sequence on the */
/* flash device, and return the manufacturer code of the component. */
/* This function automatically resets to read mode. */
/*********************************************************************/
byte flash_get_manuf_code(byte sector)
{
byte *fwp; /* flash window */
byte answer;
word i;
fwp = (byte *)get_flash_memptr(sector);
flash_command(FLASH_AUTOSEL,sector,0,0);
answer = *fwp;
flash_command(FLASH_RESET,sector,0,0); /* just to be safe */
return( (byte) (answer & 0x00FF) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -