📄 flash_nvram56xx.c
字号:
/*
$Workfile: flash_nvram56xx.c $
$Revision: 1.22 $
$Date: Aug 23 2006 23:25:24 $
*/
//******************************************************************
//
// Copyright (C) 2001. GENESIS MICROCHIP INC.
// All rights reserved. No part of this program may be reproduced.
//
// Genesis Microchip Inc., 165 Commerce Valley Dr. West
// Thornhill, Ontario, Canada, L3T 7V8
// Genesis Microchip Corp., 2150 Gold Street
// Alviso, CA 95002 USA
//
//================================================================
//
// MODULE: flash_nvram.c
//
// USAGE : This module maintains NVRAM block data in FLASH rather than
// EEPROM based NVRAM. The main difference being that FLASH can
// only be erased a minimum of 1 sector (typically 4KB) were EEPROM
// based NVRAM can be byte erasable, allowing for a more random access
// approach to memory management.
// The FLASH approach to memory management is to never erase a sector
// until it becomes full. If a block is saved, it is simply appended
// to the end, and when it is to be accessed, it's the last copy that
// is the most recent. When the sector becomes full, a prune operation
// takes place where a second sector is erased, and only the most
// recent block data is copied into the new sector. The new sector// becomes the "working" sector, and will be pruned when it becomes full.
//
//******************************************************************
//******************************************************************
// I N C L U D E F I L E S
//******************************************************************
#include "..\inc\all.h"
#if USE_FLASHSPEED_AUTODETECT || NVRAM_USE_FLASH
#include "flash_hex56xx.h"
#include "mem.h"
#include "dos.h"
#include ".\system\Mcu186.h"
//******************************************************************
// L O C A L D E F I N I T I O N S
//******************************************************************
#define DEBUG_FLASH_NV 0
#define DEBUG_FLASH_NV_EXTENDED 0
#define DEBUG_FLASH_INP 0
#if DEBUG_FLASH_NV && DEBUG_MSG
#define msg(a,b) gm_Print((const char far *)a,b)
#else
#define msg(a,b)
#endif
#if DEBUG_FLASH_NV_EXTENDED && DEBUG_MSG
#define msgx(a,b) gm_Print((const char far *)a,b)
#else
#define msgx(a,b)
#endif
#if DEBUG_FLASH_INP && DEBUG_MSG
#define inp_msg(a,b) gm_Print((const char far *)a,b)
#else
#define inp_msg(a,b)
#endif
#define LAST_BLOCK_ID gmv_Size_RomDirectory //used to speed up prune routine, don't
// bother searching for all 0x00 -> 0xff block types if they're not used.
/******** NOTE **************************************************************
The #defines below for sector size and start must be in 'HUGE' format, or
normalized 'far' format. Examples of far pointers and their normalized
equivalents:
far normalized
--------- -----------
0000:0123牋牋0012:0003
0040:0056牋牋0045:0006
500D:9407牋牋594D:0007
7418:D03F牋牋811B:000F
0000:1000 0100:0000 <- Example of 4KB sector size that's normalized
******************************************************************************/
#ifdef PHOENIX
#if FLASH_TYPE == PM39F010
#define FLASHUserPrefSectorStartD 0x9D000000UL // use last two banks (normalized)
#define FLASHUserPrefSectorSizeD 0x01000000UL // 4KB sector size. (normalized)
#elif FLASH_TYPE == PM39F020
#define FLASHUserPrefSectorStartD 0xB5000000UL // use last two banks (normalized)
#define FLASHUserPrefSectorSizeD 0x01000000UL // 4KB sector size. (normalized)
#elif FLASH_TYPE == SPI_FLASH
#define FLASHUserPrefSectorStartS128 0x9D000000UL // use last two banks (normalized) for size = 128K
#define FLASHUserPrefSectorStartS256 0xBD000000UL // use last two banks (normalized) for size = 256K
#define FLASHUserPrefSectorStartS512 0xED000000UL // use last two banks (normalized) for size = 512K
#define FLASHUserPrefSectorSizeS4 0x01000000UL // 4KB sector size. (normalized)
// #define FLASHUserPrefSectorStartST 0xA0000000UL // use last two banks (normalized) for ST (size 256K)
// #define FLASHUserPrefSectorSizeST 0x10000000UL // 64KB sector size. (normalized) for ST
// #define FLASHUserPrefSectorStartS1 0x80400000UL // use two 1K sectors in sector0, start from 2nd sector
// #define FLASHUserPrefSectorSizeS1 0x00400000UL // 1KB sector size. (normalized)
#else
#error "FLASH_TYPE Uknown!"
#endif
#else // PHOENIX
#if FLASH_TYPE == PM39F010
#define FLASHUserPrefSectorStartD 0x9E000000UL // use last two banks (normalized)
#define FLASHUserPrefSectorSizeD 0x01000000UL // 4KB sector size. (normalized)
#elif FLASH_TYPE == PM39F020
#define FLASHUserPrefSectorStartD 0xB6000000UL // use last two banks (normalized)
#define FLASHUserPrefSectorSizeD 0x01000000UL // 4KB sector size. (normalized)
#elif FLASH_TYPE == SPI_FLASH
#define FLASHUserPrefSectorStartS128 0x9E000000UL // use last two banks (normalized) for size = 128K
#define FLASHUserPrefSectorStartS256 0xBE000000UL // use last two banks (normalized) for size = 256K
#define FLASHUserPrefSectorStartS512 0xEE000000UL // use last two banks (normalized) for size = 512K
#define FLASHUserPrefSectorSizeS4 0x01000000UL // 4KB sector size. (normalized)
// #define FLASHUserPrefSectorStartST 0xA0000000UL // use last two banks (normalized) for ST (size 256K)
// #define FLASHUserPrefSectorSizeST 0x10000000UL // 64KB sector size. (normalized) for ST
#else
#error "FLASH_TYPE Uknown!"
#endif
#endif // PHOENIX
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//NOTE: Macor HUGE_OFF and HUGE assumes normalized 32-bit address as an input;
// Otherwise, the macros will give wrong results! Only when computing Size, Room
// or comparing address, converting the normalized 32-bit adddress to 20-bit address
// first by using HUGE; In all other cases, keep normalized 32-bit address!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#define HUGE_OFF(a) (WORD)(((((a)>>12)&0xfff0) + FP_OFF(a)))
#define HUGE(a) (DWORD)( (((DWORD)(a)>>12)&0xffff0UL) + (((DWORD)(a))&0xFFFFUL))
typedef enum {
FLASH_NV_WRITE,
FLASH_NV_SECTOR_ERASE,
FLASH_NV_AUTODETECT,
FLASH_NV_PROTECT,
FLASH_NV_UNPROTECT
} flash_nv_cmd;
// Moved to Nvram_def.h file
#if 0
typedef struct block_hdr_struct
{
BYTE Type; // Block_ID
BYTE Index; // Block_Index
WORD Size; // Size of Block including header
BYTE Checksum; // Checksum.
}block_hdr_type;
#endif
#define BLOCK_TYPE_OFFSET 0
#define BLOCK_INDEX_OFFSET 1
#define BLOCK_SIZE_OFFSET 2
#define BLOCK_CHECKSUM_OFFSET 4
#define BLOCK_DATA_OFFSET 5
extern BYTE DecompBuf[768];
BYTE B_FlashChipID; // flash chip type
DWORD FLASHUserPrefSectorStart;
DWORD FLASHUserPrefSectorSize;
typedef union
{
DWORD DW_Addr;
BYTE B_A[4];
} ADDRESS;
typedef union
{
WORD W_Word;
BYTE B_A[2];
} WORDTOBYTE;
typedef void far(*RamResidentEntry)(BYTE cmd, BYTE far *WrAddr, WORD length, BYTE far *buff);
#if NVRAM_USE_FLASH
#if FAST_FLASH_PAGE_UPDATE
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//NOTE: To optimize memory usage and speed up searching,
// MAX_BLOCK_ENTRIES and MAX_TOTAL_INDICES has to be manually derived from nvtable.c file,
// make: MAX_BLOCK_ENTRIES = gmv_Size_RomDirectory, and
// MAX_TOTAL_INDICES = # of total entries in gmc_RomDirectory[] array
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#define MAX_BLOCK_ENTRIES 20 //maximum # of nvram blockType
#define MAX_TOTAL_INDICES 100 //maximum # of total individual nvram blocks (different index count as 1)
//local
static BYTE B_CountTable[MAX_BLOCK_ENTRIES];
static WORD W_AddrTable[MAX_TOTAL_INDICES];
//extern variables
extern gmt_BLOCKINFO ROM gmc_RomDirectory[];
extern BYTE ROM gmv_Size_RomDirectory;
static gmt_RET_STAT MakeCountTable(void);
#endif
static WORD getLength(BYTE far *addr);
static BYTE far *findBlockType(BYTE blockType, BYTE blockIndex, BYTE *version);
void prune(void);
static void findWorkingSector(void);
static BYTE checkChecksum(BYTE far * blockAddr);
#endif //!NVRAM_USE_FLASH
gmt_BLOCKINFO block_info; // WORD address, WORD length
BYTE far *workingSector; // current FLASH sector in use.
//******************************************************************
// C O D E
//******************************************************************
static void executeRamResidentCmd(flash_nv_cmd cmd, BYTE far *WrAddr, WORD length, BYTE far *buff);
//Added function to set optimal SPI clock based on flash type after AutoDetect or know which flash type
//*********************************************************************************************
// FUNCTION : SetOptimizedSPIClock(void)
// DESCRIPTION : to set optimal SPI clock based on flash type
// INPUT : B_FlashChipID
//
// OUTPUT : None
// USED_REGS : None
//*********************************************************************************************
//Note: only call this function or after flash type is known, and there is a limitation for
//speed setting according to flash chipID since some flash with the same chipID may have different
//speed. System maker has to check whether this mechanism can be used or not before enable this option
#if (DISABLE_AUTODETECT == 0) && (USE_FLASHSPEED_AUTODETECT==1)
gmt_RET_STAT SetOptimalSPIClock(void)
{
BYTE B_FlashClockInMHz; // flash clock;
BYTE B_tmpDivisor;
switch(B_FlashChipID)
{
case SST25VF010_ID:
msgx("SST",0);
B_FlashClockInMHz = 20;
break;
case PM25LV010_ID:
msgx("PMC",0);
B_FlashClockInMHz = 25;
break;
case WB25X00_ID:
msgx("WB",0);
B_FlashClockInMHz = 25;
break;
case STM25PExx_ID:
msgx("ST_PE",0);
B_FlashClockInMHz = 20;
break;
case ST0000000_ID:
msgx("ST",0);
B_FlashClockInMHz = 20;
break;
default:
msg("Error - B_FlashChipID is wrong !",B_FlashChipID);
// B_FlashClockInMHz = 20;
return gmd_FALSE;
};
//reset gmc_SPI_Clock_Sel based on flash clock
if( (CPU_CLK_MHZ / B_FlashClockInMHz) > 2)
{
B_tmpDivisor = (BYTE)( (10*CPU_CLK_MHZ+9*B_FlashClockInMHz)/(10UL*B_FlashClockInMHz) - 2);
gmc_SPI_Clock_Sel = (B_tmpDivisor<<4);
}
else
{
gmc_SPI_Clock_Sel = 0;
}
gm_ClearAndSetBitsByte(SPI_CONTROL, SPI_CLK_SEL ,gmc_SPI_Clock_Sel);
msg("Detect and Set SPI Clock = %d Mhz-----", B_FlashClockInMHz);
return gmd_TRUE;
}
gmt_RET_STAT AutoDetectAndSetSpiClock(void)
{
BYTE far *Bp_Buff = &B_FlashChipID;
executeRamResidentCmd(FLASH_NV_AUTODETECT, NULL_PTR, 0, Bp_Buff);
B_FlashChipID = ( B_FlashChipID & 0x0F );
msg("B_FlashChipID = %x",B_FlashChipID);
//set optimal clock based on flash type
return SetOptimalSPIClock();
}
#endif //(DISABLE_AUTODETECT == 0)
//***************************************************************
// FUNCTION : executeRamResidentCmd
// DESCRIPTION : copies RAM resident code to RAM buffer and executes code.
// FLASH_NV_WRITE -> write contents of buffer to flash WrAddr
// FLASH_NV_SECTOR_ERASE -> erases sector at addres WrAddr.
// INPUT : cmd, WrAddr, Length, buffer.
// OUTPUT : gmt_RET_STAT
// USED_REGS : None
//***************************************************************
#if( FLASH_TYPE == SPI_FLASH )
#define ENABLE_INT() asm{ STI } // Enable all interrupts
static void executeRamResidentCmd(flash_nv_cmd cmd, BYTE far *WrAddr, WORD length, BYTE far *buff)
{
DWORD DW_WrAddr = ((DWORD) WrAddr) & 0xFF000000UL;
RamResidentEntry RamEntry = (RamResidentEntry)&DecompBuf[0];
BYTE B_CacheCtrl;
WORD far *pW_Cache = (WORD far *) 0x0000A800UL;
WORD W_DummyCount;
DWORD DW_tmpAddr;
//Stop vblank ISR to avoid horizontal bar garbage during saving data to flash
StopADCCalibrationISR();
DW_tmpAddr = HUGE(WrAddr);
if( (DW_tmpAddr < HUGE(FLASHUserPrefSectorStart)) || ((DW_tmpAddr + length) > HUGE(FLASHUserPrefSectorStart + 2 * FLASHUserPrefSectorSize) ) )
{
if(cmd < FLASH_NV_AUTODETECT)
{
inp_msg("ERROR: Attempt of write to the wrong address in the flash (ignored)",0);
inp_msg("Address High = %x", (WORD)(((unsigned long)WrAddr) >> 16));
inp_msg("Address Low = %x", (WORD)WrAddr);
return;
}
}
if(FLASH_NV_AUTODETECT == cmd)
{
msg("AUTODETECT",0);
#if(DISABLE_AUTODETECT == 0)
_fmemcpy(&DecompBuf[0],&RamResidentCode_AutoDetect[0],sizeof(RamResidentCode_AutoDetect));
#else
msg("Error - AUTODETECT is disabled !",0);
return;
#endif
}
#if NVRAM_USE_FLASH
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -