本文主要是關于NOR flash的相關介紹,并著重對NOR flash的識別及其工作原理進行了詳盡的闡述。
NOR flash工作原理
Nor Flash 具有像內存一樣的接口,它可以像內存一樣讀,卻不可以像內存一樣寫,Nor Flash 的寫、擦除都需要發出特定的命令。談到 Nor Flash 通常就會涉及到 CFI ([Common Flash Interface) 接口,一般 Nor Flash 都支持發命令來讀取廠家 ID 和 設備 ID 等基本信息,但并不是所有的 Nor
Flash 都支持發命令來獲取和芯片本身容量大小、扇區數、擦除塊大小等信息。為了讓將來的 Nor Flash 兼容性更好,引進了 CFI 接口,將芯片有關的信息都寫入芯片內部,通過 CFI 命令就可以獲取這些信息。
Linux 內核中對各種型號的 Nor Flash 都有很好的支持 ,但是其組織復雜,不利于分析。這里選用 u-boot 里面的 Nor Flash 代碼來分析。代碼位于:u-boot-2010.06/board/samsung/smdk2410/flash.c 。
通常內核里面要識別一個 Nor Flash 有兩種方法:一種是 jedec 探測,就是在內核里面事先定義一個數組,該數組里面放有不同廠家各個芯片的一些參數,探測的時候將 flash 的 ID 和數組里面的 ID 一一比較,如果發現相同的,就使用該數組的參數。另一種是 cfi 探測,就是直接發各種命令來讀取芯片的信息,比如 ID、容量等。jedec 探測的優點就是簡單,缺點是如果內核要支持的 flash 種類很多,這個數組就會很龐大。。。/samsung/smdk2410/flash.c 文件采用的是第一種方法,但是還是有些區別的,內核里面用
jedec 探測一個芯片時,是先通過發命令來獲取 flash 的 ID,然后和數組比較,但是 flash.c 中連 ID 都是自己通過宏配置的。
unsigned long flash_init (void)
{
for (i = 0; i 《 CONFIG_SYS_MAX_FLASH_BANKS; i++)
{
ulong flashbase = 0;
//設置 flash_id ,這個標志保存廠家 ID 和 設備 ID
flash_info[i].flash_id =
#if defined(CONFIG_AMD_LV400)
(AMD_MANUFACT & FLASH_VENDMASK) | (AMD_ID_LV400B & FLASH_TYPEMASK);
#elif defined(CONFIG_AMD_LV800)
(AMD_MANUFACT & FLASH_VENDMASK) | (AMD_ID_LV800B & FLASH_TYPEMASK);
#else
#error “Unknown flash configured”
#endif
//設置 flash 大小和扇區數
flash_info[i].size = FLASH_BANK_SIZE;
flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;
//對于 flash 的每個扇區,都需要保存扇區的首地址
for (j = 0; j 《 flash_info[i].sector_count; j++)
{
。。.。。.
flash_info[i].start[j] = flashbase + (j - 3) * MAIN_SECT_SIZE;
}
size += flash_info[i].size; //片外所有flash 的總大小
}
//對代碼區的扇區設置寫保護,這里只是軟件的一種設定
flash_protect (FLAG_PROTECT_SET, CONFIG_SYS_FLASH_BASE,
CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
&flash_info[0]);
//如果環境變量保存在 nor 里面,還需對這些扇區設置寫保護
flash_protect (FLAG_PROTECT_SET, CONFIG_ENV_ADDR,
CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
return size; //返回 flash 大小
}
flash_init() 函數主要是做一些 flash 的初始化,比如設置 flash 的 ID、大小、扇區數等來構造flash_info_t 結構體,但是從上面的代碼可以看出,在該初始化函數中并沒有做任何與硬件有關的初始化,所有的值都是通過外部賦值,也就是說我們可以給這些成員變量賦任何我們想要的值,哪怕這些值并不是
flash 真正的參數,雖然這些值并不影響本函數的調用,但是和下面這些函數就有密切關系。
int flash_erase (flash_info_t * info, int s_first, int s_last)
{
//參看是否有寫保護扇區,有直接返回錯誤
prot = 0;
for (sect = s_first; sect 《= s_last; ++sect)
{
if (info-》protect[sect])
prot++;
}
if (prot)
return ERR_PROTECTED;
//關閉中斷等,防止擦除過程被中斷
icache_disable ();
iflag = disable_interrupts ();
/* Start erase on unprotected sectors */
for (sect = s_first; sect 《= s_last && !ctrlc (); sect++)
{
printf (“Erasing sector %2d 。。. ”, sect);
/* arm simple, non interrupt dependent timer */
reset_timer_masked ();
if (info-》protect[sect] == 0) //此處的判斷有點多余
{ /* not protected */
//取扇區的首地址
vu_short *addr = (vu_short *) (info-》start[sect]);
//發解鎖和擦除扇區命令
MEM_FLASH_ADDR1 = CMD_UNLOCK1; //往地址 0x555《《1 寫入 0xAA
MEM_FLASH_ADDR2 = CMD_UNLOCK2; //往地址 0x2AA《《1 寫入 0x55
MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;//往地址 0x555《《1 寫入 0x80
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
*addr = CMD_ERASE_CONFIRM; //往地址 0x555《《1 寫入 0x30
/* wait until flash is ready */
chip = 0;
do
{
result = *addr; //讀取該扇區首地址里面的值
/* check timeout */
if (get_timer_masked () 》 CONFIG_SYS_FLASH_ERASE_TOUT)
{
MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
chip = TMO;
break;
}
//BIT_ERASE_DONE = 0x80,即判斷 DQ7 是否為 1
if (!chip && (result & 0xFFFF) & BIT_ERASE_DONE)
chip = READY;
//BIT_PROGRAM_ERROR = 0x20,即判斷 DQ5 是否為 1
if (!chip && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
chip = ERR;
} while (!chip);
MEM_FLASH_ADDR1 = CMD_READ_ARRAY; //往地址 0x555《《1 寫入 0xF0
。。.。。.
printf (“ok.n”);
}
else
{ /* it was protected */
printf (“protected!n”);
}
}
。。.。。.
/* allow flash to settle - wait 10 ms */
udelay_masked (10000);
return rc;
}
如何自動識別是NOR flash
Norflash啟動時:
4K的內部SRAM都被映射到了0x40000000-0x40001000
Nandflash啟動時:
4K的內部SRAM都被映射到了0x40000000,同時還被映射到了0x00000000-0x00001000
所有,我們可以通過判斷0x0000003c處的數據是否和0x4000003c處的數據相等來判斷是哪種啟動方式。選擇這個地址是因為這個地址處的值固定是0xdeadbeef
3c = 60 = 4*15
.globl _start_start: b start_code ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq _undefined_instruction: .word undefined_instruction_software_interrupt: .word software_interrupt_prefetch_abort: .word prefetch_abort_data_abort: .word data_abort_not_used: .word not_used_irq: .word irq_fiq: .word fiq .balignl 16,0xdeadbeef
在start.S里的代碼如下
/***************** CHECK_BOOT_FLASH ******************************************/ ldr r1, =( (4《《28)|(3《《4)|(3《《2) ) /* address of Internal SRAM 0x4000003C*/ mov r0, #0 /* r0 = 0 */ str r0, [r1] mov r1, #0x3c /* address of men 0x0000003C*/ ldr r0, [r1] cmp r0, #0 bne relocate /* recovery */ ldr r0, =(0xdeadbeef) ldr r1, =( (4《《28)|(3《《4)|(3《《2) ) str r0, [r1]/***************** CHECK_BOOT_FLASH ******************************************/
Uboot里的流程:啟動時先將0x4000003C處的數據清零,再讀出0x0000003C處地址的數據,如果為0就意味著,這個地址是同時映射在0x4000003C處和0x0000003C處即為nandflash啟動,不相等則為norflash啟動。
但是最后有一點很重要:如果是Nand flash啟動,必須要復原清零的數據。原因是:在nand boot過后,會核對內部SRAM中的4K程序,和從Nand中拷貝到SDRAM的前4K程序是否一致,如果不一致會進入死循環。
nor flash是如何讀寫數據的
(1) Nor Flash工作模式
Nor Flash上電后處于數據讀取狀態(Reading Array Data)。此狀態可以進行正常的讀。這和讀取SDRAM/SRAM/ROM一樣。(要是不一樣的話,芯片上電后如何從Nor Flash中讀取啟動代碼。~)
一般再對Flash進行操作前都要讀取芯片信息比如設備ID號。這樣做的主要目的是為了判斷自己寫的程序是否支持該設備。 Nor Flash支持2種方式獲取ID號。一種是編程器所用的方法需要高電壓(11.5V-12.5V)。另一種方法就是所謂的in-system方法,就是在系統中通過Nor Flash的命令寄存器來完成。本文中只對in-system方法進行說明。此時需要切換到自動選擇(Autoselect Command),這要通過發送命令來完成。命令類型見下圖。注意:
進入自動選擇(Autoselect Command)模式后需要發送復位命令才能回到數據讀取狀態(Reading Array Data)。
在完成信息獲取后一般就要擦除數據。 Nor Flash支持扇區擦(Sector Erase)除和整片擦除(Chip Erase)。這2種模式都有對應的命令序列。在完成擦除命令后會自動返回到數據讀取(Reading Array Data)狀態。在返回前可查詢編程的狀態。
完成擦除后就需要對芯片進行寫入操作也就是編程。這就需要進入編程(Program)狀態。在完成編程命令后會自動返回到數據讀取(Reading Array Data)狀態。在返回前可查詢編程的狀態。注意:編程前一定要先擦除。因為編程只能將’1’改寫為’0’,通過擦寫可以將數據全部擦寫為‘1’。
(2)Nor Flash 硬件連接
1. 引腳47 為BYTE# :當其為高電平時數據輸出為16bit模式(此時地址線為A19:A0)。低電平為8bit模式。 (此時地址線為A19:A1)上圖中Pin47加VCC選用的是16bit模式有效地址線為A19:A0.
2. 對于16bit模式要16bit對齊因此S3C2440A的LADDR1要與A0連接。此時要注意的是NorFlash片內地址0x555對應S3C2440A的地址為baseaddr+0x555*2;其中baseaddr與NorFlash映射的地址有關。一般NorFlash放在Bank0.所以baseaddr=0,但是開啟mmu后baseaddr=地址0映射到的新地址。0x555*2的原因是LADDR1與A0連接。也就是0x555表示片內第0x555個word(16bit)。
3. 引腳15為RYBY#輸出引腳。用于輸出Ready與Busy信號。實際用時可以不接。可用命令查詢NorFlash狀態代替。
( 3) Nor Flash 模式編程
1. 讀ID
2. 扇區擦除(Sector Erase)
扇區擦除命令序列的每個周期均為寫周期。
3. 編程(Program)
4. 寫操作狀態(WRITE OPERATION STATUS)
Nor Flash 提供幾個數據位來確定一個寫操作的狀態,它們分別是: DQ2, DQ3, DQ5, DQ6,DQ7, and RY/BY#. 如上圖所示。其中DQ7, RY/BY#引腳, 和 DQ6 中的每一個都提供了一種方法來判斷一個編程或者擦除操作是否已經完成或正在進行中。實際編程中只需要使用其中的一種。
DQ7:Data# Polling bit,DQ7在編程時的狀態變化。
在編程過程中從正在編程的地址中讀出的數據的DQ7為要寫入數據的補碼。比如寫入的數據為0x0000,及輸入的DQ7為‘0’,則在編程中讀出的數據為‘1’;當編程完成時讀出的數據又變回輸入的數據即’0’。在擦除過程中DQ7輸出為’0’;擦除完成后輸出為’1’;注意讀取的地址必須是擦除范圍內的地RY/BY#:高電平表示‘就緒’,低電平表示‘忙’。
DQ6:輪轉位1(Toggle Bit 1)。
編程和擦除期間,讀任意地址都會導致DQ6的輪轉(0,1間相互變換)。。當操作完成后,DQ6停止轉換。
DQ2:輪轉位2(Toggle Bit 2)。當某個扇區被選中擦除時,讀有效地址(地址都在擦除的扇區范圍內)會導致DQ2的輪轉。
注意:DQ2只能判斷一個特定的扇區是否被選中擦除。但不能區分這個快是否正在擦除中或者正處于擦除暫停狀態。相比之下,DQ6可以區分NorFlash是否處于擦除中或者擦除狀態,但不能區分哪個快被選中擦除。因此需要這2個位來確定扇區和模式狀態信息。
DQ5: 超時位(Exceeded Timing Limits),當編程或擦除操作超過了一個特定內部脈沖計數是DQ5=1;這表明操作失敗。當編程時把’0’改為’1’就會導致DQ5=1,因為只有擦除擦做才能把’0’改為’1’。當錯誤發生后需要執行復位命令(見圖1-1)才能返回到讀數據狀態。
DQ3: (扇區擦除計時位)Sector Erase Timer,只在扇區擦除指令時起作用。當擦除指令真正開始工作是DQ3=1,此時輸入的命令(除擦除暫停命令外)都被忽略。DQ3=0,是可以添加附加的扇區用于多扇區擦除
結語
關于NOR flash的相關介紹就到這了,如有不足之處歡迎指正。
-
存儲器
+關注
關注
38文章
7528瀏覽量
164176 -
NOR flash
+關注
關注
2文章
91瀏覽量
23061
發布評論請先 登錄
相關推薦
評論