NorFlash的硬件接線:
首先,如果做過sdram實驗的朋友應該知道,NorFlash與sdram很相似,只不過sdram位寬為32,NOR為16。在硬件連接上,Nor的地址線與cpu的地址線錯開1位,sdram錯開2位。簡單分析一下:
32位的CPU地址線為32位,每一個地址對應1個byte,地址的步長為1byte
0x0000 0000 對應第1個地址空間 大小為1bytes
0x0000 0001 對應 2 大小為1bytes
依次類推。。.
可以理解為cpu的地址類型 為 u8 * addraddr+1 移動1個字節
32位的sdram,每一個地址對應于4個byte,地址步長為4byte
0x0000 0000 對應第1個地址空間 大小為4bytes
0x0000 0001 對應 2 大小為4bytes
依次類推。。.
可以理解為sdram的地址類型 為 u32 * addraddr+1 移動4個字節
16位的nor,每一個地址對應于2個byte,地址步長為2byte
0x0000 0000 對應第1個地址空間 大小為2bytes
0x0000 0001 對應 2 大小為2bytes
依次類推。。.
可以理解為nor的地址類型 為 u16 * addraddr+1 移動2個字節
因此,CPU的地址與它們的地址是錯位的。
CPU的4個連續地址 如 0 1 2 3 均對應于sdram的 0地址
CPU的2個連續地址 如 0 1 均對應于nor 的 0地址
假如我想取sdram 0地址的 第二個byte 地址如何寫?對于sdram和nor具體的每一個byte是無法尋址的呀,但是arm有一個叫存儲管理器的東西,它大概會幫我們實現單字節的讀寫,至于sdram和nor支不支持單字節讀寫,我們后邊在分析。
NorFlash的軟件設置:
需要像初始化sdram一樣,設置Bank寄存器,主要是一些時序圖的時間大小。
位寬在BWSCON寄存器中設置,不過它是由硬件決定的,bank0的位寬,我們撥動開關選擇nor啟動還是nand啟動的時候,它就已經確定了。
NorFlash信息:
我這款Nor大小為2M,32個Block,每個block分為16個sector,一個sector為4K,具體信息如下圖。
NorFlash寫、擦除、讀芯片ID:
Nor可以像sdram一樣直接讀取,對于其它的操作,例如寫、擦除、讀信息等需要寫特定的Date到特定的Addr。
這里尤其需要注意的是,Addr指的是nor地址線上看到的地址,相對于cpu也就是我們寫程序的時候,需要將addr《《1,這樣cpu錯位的地址線發出的地址正好對上nor需求的地址。
對于擦除操作,nor支持按block、sector或者整片的擦除,整個擦除需要6個周期,以按sector擦除為例,前五個周期為往XXX里寫XXX,最后一個周期將0X30寫入要擦除的sector對應的首地址即可。
對于寫操作,需要4個周期,前3個周期往XXX里寫XXX,最后一個周期將Data寫入addr,這里需要注意的是addr必須是半字對齊,data也要求為16bit。
對于讀取信息的操作,主要是讀ID的操作,前3個周期往XXX里寫XXX,第四個周期去讀特定的地址,對于DeviceID來說,A1-A19=0,A0=1,對于CPU來說就是0x1《《1.
NorFlash的等待:
NorFlash有三種方式,1中讀硬件引腳,另外兩種讀地址線,主要用讀地址線的兩種方式。
1、Toggle
連續讀兩次相同地址的數據,看DQ6是否相等,相等則擦除或寫完成
2、polling
讀數據,看DQ7是否正確,正確則擦除完成。如果擦除的話DQ7應該等于1,寫操作的話,對比數據的第7位。
還有,很重要的一點:
經過我的測試,sdram的單字節讀取沒有問題,但是Nor單字節讀取的時候,讀出的數據并不正確。比如我在0x00地址處寫入了0xff11,單字節讀取0x0理論上應該得到0x11,而我在實際實驗的時候得到的卻是0xff。也就是說nor在存儲半字數據的時候高8位于低8位互換了。
[cpp] view plain copy
#include “uart.h”
#define MAIN_SECT_SIZE (4*1024) /* 4 KB */
#define CMD_UNLOCK1 0x000000AA
#define CMD_UNLOCK2 0x00000055
#define CMD_ERASE_SETUP 0x00000080
#define CMD_ERASE_CONFIRM 0x00000030
#define CMD_PROGRAM 0x000000A0
#define MEM_FLASH_ADDR1 (*(volatile U16 *)(0x000005555 《《 1))
#define MEM_FLASH_ADDR2 (*(volatile U16 *)(0x000002AAA 《《 1))
#define U16 unsigned short
#define U32 unsigned long
#define U8 unsigned char
int write_hword (U32 dest, U16 data);
typedef struct {
U32 size; /* total bank size in bytes */
U16 sector_count; /* number of erase units */
U32 flash_id; /* combined device & manufacturer code */
U32 start[512]; /* physical sector start addresses */
} flash_info_t;
/*-----------------------------------------------------------------------*/
void flash_id(){
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
MEM_FLASH_ADDR1 = 0x00000090;
print(“Manufacturer ID :%x\r\n”,*((U16 *)0x00));
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
MEM_FLASH_ADDR1 = 0x00000090;
print(“Device ID :%x\r\n”,*((U16 *)(0x01《《1)));
}
void flash_init () //計算總大小,每個sector的起始地址
{
flash_id();
//print(“flash init OK\r\n”);
print(“*((U32 *)0x32000000) = 0x00001100\r\n”);
*((U32 *)0x32000000) = 0x00001100;
print(“U8 0x32000001 == %x\r\n”,*((U8 *)0x32000001));
*((U8 *)0x32000003) = 0xff;
print(“*((U8 *)0x32000003) = 0xff\r\n”);
print(“now the U32 0x32000000 should be 0xff001100\r\n”);
print(“U32 0x32000000 = %x\r\n”,*((U32 *)0x32000000));
print(“U8 0x32000000 = %x\r\n”,*((U8 *)0x32000000));
print(“U8 0x32000001 = %x\r\n”,*((U8 *)0x32000001));
print(“U8 0x32000002 = %x\r\n”,*((U8 *)0x32000002));
print(“U8 0x32000003 = %x\r\n”,*((U8 *)0x32000003));
if(flash_erase(0,1) == 0)
print(“erase OK\r\n”);
U32 a = 0x00001c15;
U16 b = 0x11ff;
write_hword(a,b);
print(“*(U32 *0x00001c15) == 0x11ff\r\n”);
print(“U8 0x1c15 = %x\r\n”,*((U8 *)0x1c15));
print(“U8 0x1c16 = %x\r\n”,*((U8 *)0x1c16));
print(“U16 0x1c15 = %x\r\n”,*((U16 *)0x1c15));
if(write_buff((1024*20),0,(7*1024)) == 0)
print(“write OK\r\n”);
}
int flash_erase (int s_first, int s_last)
{
int i,j;
U32 size = 0;
flash_info_t flash_info;
for (i = 0; i 《 1; i++) {
U32 flashbase = 0;
flash_info.size = 2*1024*1024;
flash_info.sector_count = 512;
flashbase = 0;
for (j = 0; j 《 flash_info.sector_count; j++) {
flash_info.start[j] =
flashbase + (j) * MAIN_SECT_SIZE;
//print(“%d \t:%d\r\n”,j,flash_info.start[j]);
}
}
int sect;
unsigned short temp;
/* Start erase on unprotected sectors */
for (sect = s_first; sect 《= s_last; sect++) {
print (“Erasing sector %d 。。. \r\n”, sect+1);
volatile U16 * addr = (volatile U16 *)(flash_info.start[sect]);
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
*addr = CMD_ERASE_CONFIRM;
print(“wait\r\n”);
while(1){
temp = (*addr) & 0x40; // 0100 0000 DQ6
if(temp != (*addr) & 0x40) //DQ6
continue;
if(*addr & 0x80) //dq7 ==1
break;
}
}
return 0;
}
//寫16位數據,地址應該是16位對齊的。
int write_hword (U32 dest, U16 data)
{
//print(“now to write %d\r\n”,dest);
int rc;
volatile U16 *addr = (volatile U16 *)dest;
U16 result;
//Check if Flash is (sufficiently) erased
result = *addr;
if ((result & data) != data)
return 1;
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
MEM_FLASH_ADDR1 = CMD_PROGRAM;
*addr = data;
while(1){
unsigned short i = *addr & 0x40;
if(i != (*addr & 0x40)) //D6 == D6
continue;
if((*addr & 0x80) == (data & 0x80)){
rc = 0;
break; //D7 == D7
}
}
//print(“write %d OK\r\n”,dest);
return rc;
}
int write_buff (U32 src, U32 addr, U32 len)
{
int rc;
U16 data; //16Bit?
if(addr % 2){
print(“addr is not for 16bit align\n”);
return 1;
}
while (len 》= 2) {
data = *((volatile U16 *) src);
if ((rc = write_hword (addr, data)) != 0) {
return (rc);
}
src += 2;
addr += 2;
len -= 2;
}
return 0;
}
-
FlaSh
+關注
關注
10文章
1623瀏覽量
147785 -
存儲器
+關注
關注
38文章
7455瀏覽量
163623
發布評論請先 登錄
相關推薦
評論