⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 norflash_rw.txt

📁 flash read and write
💻 TXT
📖 第 1 页 / 共 4 页
字号:
2月29日
如何读写NOR FLASH,今天我下午的研究

//////note that SOFTWARE COMMAND SEQUENCE   reference to flash_datasheet

#define write(addr,data) *((volatile unsigned short *)(addr<<1))=(unsigned short)data
#define read(addr) (*((volatile unsigned short *)(addr<<1)))
#define reset() write(0x0,0xf0f0)

unsigned int SST39VF160_CheckID(void)
{
unsigned short ManID,DevID;
reset();
write(0x5555,0xaa);
write(0x2aaa,0x55);
write(0x5555,0x90);
ManID=read(0x0000);
DevID=read(0x0001);
reset();
return ((ManID<<16)+DevID);
}

unsigned char SST39VF160_Erase(void)
{  //擦除FLASH
write(0x5555,0xaa);
write(0x2aaa,0x55);
write(0x5555,0x80);
write(0x5555,0xaa);
write(0x2aaa,0x55);
write(0x5555,0x10);
return 1;
}

unsigned char SST39VF160_WordPro(unsigned int addr,unsigned short data)
{  //写入两个字节,一个SHORT字
write(0x5555,0xaa);
write(0x2aaa,0x55);
write(0x5555,0xa0);
write(addr,data);
return wait();
}

unsigned char wait(void)
{
volatile unsigned short flashstatus,old;
old=*((volatile unsigned short *)0x0);
while(1)
flashstatus=*((volatile unsigned short *)0x0);
if((old&0x1000)==(flashstatus&0x1000))
break;
old=flashstatus;
}
return 1;
}

以上是一些功能函数,若你想实现FLASH的烧写,还得组合这些函数,设置一些标志,当擦除完成,烧写完成时,以便实时监控哦!
















//**************************************************************************************************
//*** norflash操作原理:假设现在讨论的norflash连接在cpu的地址空间的0x0C000000位置的intel L18F256 32MB norflash(块大小为128KB)
/*
intel E28F128J3A150 16MB 16bit norflash 和bf561相连的接法为 :
bf561 <=> E28F128J3A150

A[23:1] => A[23:1] //bf561给norflash的地址信号
D[15:0] => D[15:0] //bf561给norflash的数据信号
/AMS0 => /CE //bf561给norflash的片选信号
/AOE => /OE //bf561给norflash的读信号
/AWE => /WE //bf561给norflash的写信号

/BYTE //上拉为高
VPEN //上拉为高
/RP //上拉为高

*/

1.norflash读取生产ID和设备ID的步骤:
1)执行相应的命令序列:=>向norflash的基地址发送命
*(0x0C000000 + 0x5555) = 0x00AA;
*(0x0C000000 + 0x2AAA) = 0x0055;
*(0x0C000000 + 0x5555) = 0x0090;
2)开始读取生产ID:
(u16)mnfID=*(0x0C000000+0x0);
3)开始读取设备ID:
(u16)devID=*(0x0C000000+0x2);
2.以块为单位擦除norflash的步骤:(假设擦除uboot所在分区:0x0C100000)
1)禁止flash的写保护: //设置EMIFS_CONFIG寄存器的最低位为1(即让wp引脚输出为高)
2)Block unlock
*((short*)0x0C100000) = 0x0060; //块对齐地址
*((short*)0x0C100000) = 0x00D0; //块对齐地址
while(!(*((short*)0x0C100000) & 0x0080)); //块对齐地址
*((short*)0x0C100000) = 0x00FF; //设置norflash为read array模式
3)执行擦除命令序列:=>向要操作的块地址发送命令
*((short*)0x0C100000) = 0x0020; //块对齐地址,INTEL_ERASE_CMD0
*((short*)0x0C100000) = 0x00D0; //块对齐地址,INTEL_ERASE_CMD1
while (!(*((short*)0x0C100000) & 0x0080)); //块对齐地址,等待直到擦除结束
5)设置norflash为read array模式
*((short*)0x0C100000) = 0x00FF; //让norflash重新进入read array模式
6)使能flash的写保护://设置EMIFS_CONFIG寄存器的最低位为0(即让wp引脚输出为低)
3.以块为单位写norflash的步骤:(假设写uboot所在分区:0x0C100000)
/*
发送写命令(0xE8)->发送数据->发送确认写命令(0xD0)->确认状态寄存器命令(0x70)->清掉状态寄存器命令(0x50)
块对齐 字对齐 块对齐 字对齐 字对齐
*/
1)禁止flash的写保护://设置EMIFS_CONFIG寄存器的最低位为1(即让wp引脚输出为高)
2)发送写命令: //块对齐地址
*((short*)0x0C100000)=0x00E8; //块对齐地址,program setup command
while(!(*0x0C100000 & 0x0080)); //块对齐地址
3)开始发送要写到flash的数据 =>(这些数据会在norflash芯片内部的buffer中锁存起来) =>每次2个字节,因为数据总线宽度为16位
(short *)ulData = 0x10010000 =>SDRAM的地址
(long *)psAddress = 0x0C000000 =>Norflash的地址
for(i=0; i<15; i++)
{
*psAddress = ulData;
psAddress++;
}
4)通知norflash将存在自己buffer中的数据写到norflash的介质上:
*((short*)0x0C100000)=0x00D0; //块对齐地址
5)读状态寄存器,确保步骤4)已经完成
*0x0C100000 = 0x0070; //Check Status Register ,这里是字对齐的地址
while(!(*0x0C100000 & BIT7)); //字对齐地址
6)// Check program status.
if ( *0x0C100000 & 0x0010 ) //字对齐地址
{
*0x0C100000 = 0x0050; //字对齐地址, Clear Status
*((short*)0x0C100000) = 0x00FF; //块对齐地址 Put chip back into read array mode.
return 1;
}
7)使能flash的写保护://设置EMIFS_CONFIG寄存器的最低位为0(即让wp引脚输出为低)
//**************************************************************************************************
//*** norflash操作原理:假设现在讨论的norflash连接在cpu的地址空间的0x0C000000位置的st stm29w640d 8MB norflash(块大小为64KB,16位宽度)
//=> 注意ST和intel norflash是有区别的 :
// ST的norflash A0可用, 故对16bit的接法为A1接A0,后面引脚类推
//intel的norflash A0不可用,故对16bit的接法为A1接A1,后面引脚类推
//
/*
1).st stm29w640d 8MB 16bit norflash 和bf561相连的接法为 :
bf561 <=> stm29w640d

/ABE3 => A0 //注意ABE[3]在这里被当成A1来使用:
A[22:2] => A[21:1] //bf561给norflash的地址信号
D[15:0] => D[15:0] //bf561给norflash的数据信号
/AMS0 => /CE //bf561给norflash的片选信号
/AOE => /OE //bf561给norflash的读信号
/AWE => /WE //bf561给norflash的写信号

RDY //上拉为高
/BYTE //上拉为高
WP_/VPP //上拉为高
/RP //上拉为高
2).注意ABE[3]在这里被当成A1来使用:
The ABE[3] pin of bf561 has two different functions. When the AMC is configured
to do 16-bit data packing via the Asynchronous Memory Global Control
Register,the ABE[3] pin of bf561 functions as the least significant bit of the address bus (ABE[3] = A1).
*/
1.norflash读取生产ID和设备ID的步骤:
1)执行相应的命令序列:=>向norflash的基地址发送命
*(0x0C000000 + 0x5555) = 0x00AA;
*(0x0C000000 + 0x2AAA) = 0x0055;
*(0x0C000000 + 0x5555) = 0x0090;

2)开始读取生产ID:
(u16)mnfID=*(0x0C000000+0x0);

3)开始读取设备ID:
(u16)devID=*(0x0C000000+0x2);

2.以块为单位擦除norflash的步骤:(假设擦除uboot所在分区:0x0C100000)
1)禁止flash的写保护: //设置EMIFS_CONFIG寄存器的最低位为1(即让wp引脚输出为高)
2)Block unlock //无
3)执行擦除命令序列:=>向要操作的块地址发送命令
*((short*)0x0C100000 + 0x555) = 0x00AA;
*((short*)0x0C100000 + 0x2AA) = 0x0055;
*((short*)0x0C100000 + 0x555) = 0x0080;
*((short*)0x0C100000 + 0x555) = 0x00AA;
*((short*)0x0C100000 + 0x2AA) = 0x0055;
*((short*)0x0C100000) = 0x0030; //块对齐地址
while (!(*((short*)0x0C100000) & 0x0080)); //块对齐地址,等待直到擦除结束

5)设置norflash为read array模式
*((short*)0x0C100000) = 0x00FF; //让norflash重新进入read array模式
6)使能flash的写保护://设置EMIFS_CONFIG寄存器的最低位为0(即让wp引脚输出为低)

3.以块为单位写norflash的步骤:(假设写uboot所在分区:0x0C100000)
/*
*/
1)禁止flash的写保护: //设置EMIFS_CONFIG寄存器的最低位为1(即让wp引脚输出为高)
2)发送写命令: //块对齐地址
*((short*)0x0C100000 + 0x555) = 0x00AA;
*((short*)0x0C100000 + 0x2AA) = 0x0055;
*((short*)0x0C100000 + 0x555) = 0x00A0;

3)开始发送要写到flash的数据 =>(这些数据会在norflash芯片内部的buffer中锁存起来) =>每次2个字节,因为数据总线宽度为16位
*(volatile U16 *)0x0C100000 = j;

4)通知norflash将存在自己buffer中的数据写到norflash的介质上:

5)读状态寄存器,确保步骤4)已经完成
while(!(*0x0C100000 & 0x80)); //字对齐地址

6)// Check program status.

7)使能flash的写保护://设置EMIFS_CONFIG寄存器的最低位为0(即让wp引脚输出为低)

4.读norflash的步骤:(假设写uboot所在分区:0x0C100000)
1)方法一:
*((short*)0x0C100000 + 0x555) = 0x00AA;
*((short*)0x0C100000 + 0x2AA) = 0x0055;

(short)data = *((short *)0x0C100000+);
2)方法二:直接读
(short)data = *((short *)0x0C100000+);



/// @ingroup AMD_BOOTLOADER
/// @file progflash.c
/// @brief Program functions for AMD Flash
///
/// @li FlashWrite
/// @li FlashRead
/// @li FlashChipErase
/// @li FlashSectorErase
/// @li FlashVerify
///
/// @author Louis Lai
/// @bug
/// @version $Version$
//
//<<<<<Include
#include "../Include/tht_memory_map_defines.h"
#include "../Include/type.h"
//>>>>>Include

//<<<<<< Private Macro
#ifndef TRUE
#define TRUE (1 == 1)
#endif
#ifndef FALSE
#define FALSE (1 == 2)
#endif

#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))

#define FLASH_DQ7_2X16 ((1 << (7 + 16)) | (1 << 7))
#define FLASH_DQ5_2X16 ((1 << (5 + 16)) | (1 << 5))
#define TACC 55 // Asyn. Access Time
#define TIACC 87 // Syn. Access Time#define HCLK 66 // EIM CLK
#define FCLK 54 // Flash Burst CLK
#define HCLK 66

#define MX21_MEM_ADDR_CS0 0xC8000000
#define MX21_MEM_ADDR_CS1 0xCC000000
#define MX21_MEM_ADDR_CS2 0xD0000000
#define MX21_MEM_ADDR_CS3 0xD1000000
#define MX21_MEM_ADDR_CS4 0xD2000000
#define MX21_MEM_ADDR_CS5 0xD3000000
//>>>>>> Private Macro
//<<<<<< Private Structure

//>>>>>> Private Structure

//<<<<<< Global Variable

//>>>>>> Global Variable

//<<<<<rivate Function Declearation
extern void EUARTputString(U8 *line);
extern void EUARTputHex(U8 data);
//>>>>>rivate Function Declearation

//<<<<<Body


///@brief This function configures the flash burst mode parameters.
///
///@param bBurstMode burst mode on/off
///@param bRisingClock use rising CLK edge?
///@param bEarlyReady RDY one CLK before data?
///@param nClk wait states (2..7)
///@param sAddress base Address of the Flash
///
///@return void
void FlashConfigBurst(BOOL bBurstMode,
BOOL bRisingClock,
BOOL bEarlyReady,
U32 nClk,
U32 sAddress)
{
volatile U32* pBase;
U32 nAddr;
U32 fWsc;
U32 nTiacc = TIACC;
int dividend;


// Calculate Configuration Register address based on mode
// ******************************************************
if (bBurstMode)
{

#if 0
fWsc = (((TIACC +10) * nClk + 999) / 1000);
#else
fWsc = ((TIACC +10) * nClk + 999);
//fWsc = fWsc/1000;
dividend = fWsc;
fWsc = dividend >> 10;
dividend -= fWsc * 1000;
while(dividend>=1000)
{
dividend -= 1000;
fWsc++;
}
#endif

nAddr = (0 << 19) | // synchronous mode
((bEarlyReady ? 0 : 1) << 18) | // RDY one CLK before?
((bRisingClock ? 1 : 0) << 17) | // CLK edge
(0 << 15) | // continuous mode
((fWsc - 2) << 12); // wait state bits
}
else
{
nAddr = (1 << 19) | // asynchronous mode
0x555; // fixed
}


// Reset flash devices before writing configuration sequence
// *********************************************************
pBase = (volatile U32*) sAddress;
*(pBase + 0x000) = 0x00f000f0;
*(pBase + 0x555) = 0x00aa00aa;
*(pBase + 0x2aa) = 0x00550055;
*(pBase + nAddr) = 0x00c000c0;

}

///@brief This function enabled or disables burst mode with the
/// MX21 processor and with the memory.
///
///@param bOnOff burst mode on/off
///@param sAddress Base Address of the Flash
///
///@return BOOL TRUE if successful, FALSE on error
BOOL BoardControlBurstMode(BOOL bOnOff, U32 sAddress)
{

//BOOL bResult;
U32 nWait;
U32 nCsHi;
U32 nCsLo;
U32 nWsc;
U32 nBcd = 0;
U32 nOea;
U32 nClk = 0;




if (bOnOff)
{
// Calculate MX1 burst clock divisor based on HCLK frequency and
// input memory clock frequency parameter. Adjust used memory clock.
// *************************************************************
nBcd = (HCLK + (FCLK - 1)) / FCLK;
//nClk = (HCLK / nBcd);
nClk = (HCLK / ((HCLK + (FCLK - 1)) / FCLK));

// Calculate number of CLK cycles required for delaying by Tacc
// in Tclk increments.
// ************************************************************
nWsc = (((TIACC + 10) * HCLK + 999) / 1000);
nWait = MAX(MIN(((TIACC * FCLK + 999) / 1000), 7), 2);

// Enable OE only one half-clock before sampling data (one half
// clock plus first CLK plus wait states minus one half clock)
// ************************************************************
nOea = MIN((nWait + 1) * 2, 0x0f);
}
else
{

nWsc = ((TACC * HCLK + 999) / 1000) + 40;
nWait = 0;
}


// Configure burst mode with flash memory. Use the number of wait
// states calculated above. For this board, we use the rising CLK
// edge and configure the RDY pin to become active with the data.
// **************************************************************
FlashConfigBurst(bOnOff,TRUE,FALSE,nClk,sAddress);


// Configure burst mode with MX1 (chip select registers)
// *****************************************************
if (bOnOff)
{
// Chip select control register for synchronous mode
// *************************************************
nCsHi = (0 << (63 - 32)) | // DTACK_SEL
((nBcd - 1) << (60 - 32)) | // BCD
(0 << (56 - 32)) | // BCS
(0 << (54 - 32)) | // PSZ
(0 << (53 - 32)) | // PME
(1 << (52 - 32)) | // SYNC
(1 << (48 - 32)) | // DOL
(0 << (46 - 32)) | // CNC
((nWsc - 1) << (40 - 32)) | // WSC
(0 << (36 - 32)) | // WWS
(1 << (32 - 32)); // EDC

nCsLo = (nOea << 28) | // OEA
(0 << 24) | // OEN
(0 << 20) | // WEA
(0 << 16) | // WEN
(0 << 12) | // CSA
(1 << 11) | // EBC
(6 << 8) | // DSZ
(0 << 6) | // SP
(0 << 4) | // WP
(0 << 1) | // PA
(1 << 0); // CSEN
}
else
{
// Chip select control register for asynchronous mode
// **************************************************
nCsHi = (0 << (63 - 32)) | // DTACK_SEL
(0 << (60 - 32)) | // BCD
(0 << (56 - 32)) | // BCS
(0 << (54 - 32)) | // PSZ
(0 << (53 - 32)) | // PME
(0 << (52 - 32)) | // SYNC
(0 << (48 - 32)) | // DOL
(0 << (46 - 32)) | // CNC
((62) << (40 - 32)) | // WSC
//((nWsc - 1) << (40 - 32)) | // WSC
(0 << (36 - 32)) | // WWS
(0 << (32 - 32)); // EDC
//(1 << (32 - 32)); // EDC

nCsLo = (0 << 28) | // OEA
(0 << 24) | // OEN
(0 << 20) | // WEA
(0 << 16) | // WEN
(0 << 12) | // CSA
(0 << 11) | // EBC
// (1 << 11) | // EBC
(6 << 8) | // DSZ
(0 << 6) | // SP
(0 << 4) | // WP
(0 << 1) | // PA
(1 << 0); // CSEN
}

*(volatile U32*)WEIM_CS0U = nCsHi;
*(volatile U32*)WEIM_CS0L = nCsLo;

return bOnOff;
}




///@brief This function programs data into flash memory. It is
/// assumed that the memory has been erased before calling
/// this function.
///
///@param sAddress start address for write
///@param pData data to write
///@param nData number of words to write
///
///@return void
void FlashWrite(U32 sAddress,
U32* pData,
U32 nData)
{


volatile U32* pBase; // base address of the selected memory bank
volatile U32* pWalk; // flash programming pointer
U32* pWalkSrc; // ram source pointer
BOOL bFailTotal;
BOOL bDone;
BOOL bFail;
U32 nWalk;
U32 nPoll;
U32 nDone;
U32 nAddress;
U32 i=0;

// Check the Flash Starting Address
pBase = (volatile U32*)(sAddress & 0xFE000000);

// Reset flash devices before starting programming sequence
// ********************************************************
*(pBase + 0x000) = 0x00f000f0;


// execute unlock bypass sequence
// ******************************************
*(pBase + 0x555) = 0x00aa00aa;
*(pBase + 0x2aa) = 0x00550055;
*(pBase + 0x555) = 0x00200020;


// start the flash programming algorithm
// **********************************************
nWalk = sAddress;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -