1. NOR FLASH 的簡單介紹
NOR FLASH 是很常見的一種存儲芯片,數據掉電不會丟失.NOR FLASH支持Execute On Chip,即程序可以直接在FLASH片內執行(這意味著存儲在NOR FLASH上的程序不需要復制到RAM就可以直接運行)。這點和NAND FLASH不一樣。因此,在嵌入式系統中,NOR FLASH很適合作為啟動程序的存儲介質.NOR FLASH的讀取和RAM很類似(只要能夠提供數據的地址,數據總線就能夠正確的給出數據),但不可以直接進行寫操作。對NOR FLASH的寫操作需要遵循特定的命令序列,最終由芯片內部的控制單元完成寫操作。
從支持的最小訪問單元來看,NOR FLASH一般分為 8 位的和16位的(當然,也有很多NOR FLASH芯片同時支持8位模式和是16 位模式,具體的工作模式通過特定的管腳進行選擇)。
對8位的 NOR FLASH芯片,或是工作在8-BIT模式的芯片來說,一個地址對應一個BYTE(8-BIT)的數據。例如一塊8-BIT的NOR FLASH,假設容量為4個BYTE.那芯片應該有8個數據信號D7-D0 和2個地址信號,A1-A0.地址0x0對應第0個 BYTE,地址0x1對應于1BYTE,地址0x2對應于第2個BYTE,而地址0x3則對應于第3 個BYTE.對16位的 NOR FLASH芯片,或是工作在16-BIT模式的芯片來說,一個地址對應于一個HALF-WORD(16-BIT)的數據。例如,一塊16-BIT的 NOR FLASH,假設其容量為4個BYTE.那芯片應該有16 個數據信號線D15-D0 和1個地址信號A0.地址 0x0對應于芯片內部的第0個HALF-WORD,地址0x1對應于芯片內部的第1個 HALF-WORD
FLASH一般都分為很多個SECTOR,每個SECTOR包括一定數量的存儲單元。對有些大容量的FLASH,還分為不同的BANK,每個BANK包括一定數目的SECTOR.FLASH的擦除操作一般都是以SECTOR,BANK或是整片FLASH為單位的。
在對FLASH進行寫操作的時候,每個BIT可以通過編程由1變為0,但不可以有0修改為1.為了保證寫操作的正確性,在執行寫操作前,都要執行擦除操作。擦除操作會把FLASH的一個SECTOR,一個BANK或是整片FLASH的值全修改為0xFF.這樣,寫操作就可以正確完成了。
由于NOR FLASH沒有本地壞區管理,所以一旦存儲區塊發生毀損,軟件或驅動程序必須接手這個問題,否則可能會導致設備發生異常。 在解鎖、抹除或寫入NOR FLASH區塊時,特殊的指令會先寫入已繪測的記憶區的第一頁(Page)。接著快閃記憶芯片會提供可用的指令清單給實體驅動程序,而這些指令是由一般性閃存接口(CommON FLASH memory Interface, CFI)所界定的。 與用于隨機存取的ROM不同,NOR FLASH也可以用在存儲設備上;不過與NAND FLASH相比,NOR FLASH的寫入速度一般來說會慢很多。
2. NOR Flash的燒寫方式
以下內容,如無特別說明,處理器指的是 ARM 處理器,FLASH 指的都是 NOR FLASH.另外,BYTE指的是8-BIT的數據單元,HALF-WORD代表的是16-BIT的數據單元,而WORD 則代表了32-BIT的數據單元。
2.1 處理器尋址
ARM 可以說是目前最流行的32位嵌進式處理器。在這里只提一下ARM處理器的尋址,為后面做個展墊。從處理器的角度來看,系統中每個地址對應的是一個BYTE的數據單元。這和很多別的處理器都是一樣的。
2.2 處理器和NOR FLASH的硬件連接
從前面的先容,我們知道從處理器的角度來看,每個地址對應的是一個 BYTE 的數據單元。而,NOR FLASH 的每個地址有可能對應的是一個BYTE的數據單元,也有可能對應的是一個HALF-WORD的數據單元。所以在硬件設計中,連接ARM處理器和 NOR FLASH時,必須根據實際情況對地址信號做特別的處理。
假如ARM處理器外部擴展的是8-BIT的NOR FLASH, 數據線和地址線的連接應該如圖1所示。 從圖中我們可以看到,處理器的數據信號D0-D7和 FLASH的數據信號D0-D7是逐一對應連接的,處理器的地址信號A0-An和NOR FLASH的地址信號A0-An 也是逐一對應連接的。
假如ARM處理器外部擴展的是16-BIT的NOR FLASH, 地址線必須要錯位連接。 圖2給了一個ARM處理器和16-BIT NOR FLASH的連接示意圖。如圖2所示,ARM處理器的數據信號D0-D15和FLASH 的數據信號D0-D15是逐一對應的。而ARM處理器的地址信號和NOR FLASH 的地址信號是錯位連接的,ARM的A0懸空,ARM 的A1 連接FLASH 的A0,ARM 的A2連接FLASH的A1,依次類推。需要錯位連接的原因是:ARM處理器的每個地址對應的是一個BYTE 的數據單元,而 16-BIT 的 FLASH 的每個地址對應的是一個HALF-WORD(16-BIT)的數據單元。為了保持匹配,所以必須錯位連接。這樣,從ARM處理器發送出來的地址信號的最低位A0對16-BIT FLASH來說就被屏蔽掉了。
補充說明:
一般來說,ARM處理器內部要設置相應的寄存器,告訴處理器外部擴展的FLASH的位寬(8-BIT/16-BIT/32-BIT) 。這樣,處理器才知道在訪問的時候如何從FLASH正確的讀取數據;
有些ARM處理器內部可以設置地址的錯位。對于支持軟件選擇地址錯位的處理器,在連接16-BIT FLASH的時候,硬件上可以不需要把地址線錯位。讀者設計的時候,請參考MCU的數據手冊,以手冊為準,以免造成不必要的麻煩;
假如處理器支持內部設置地址錯位,在實際訪問的時候,送出的地址實際上是在MCU內部做了錯位處理,其作用是等效于硬件連接上的錯位的。
上面的描述可能比較抽象,下面讓我們來看2個ARM處理器訪問16-BIT FLASH的例子:
例子 1:ARM處理器需要從地址0x0讀取一個BYTE
ARM處理器在地址線An-A0上送出信號0x0;
16-BIT FLASH在自己的地址信號An-A0上看到的地址是0x0,然后將地址0x0對應的16-BIT數據單元輸出到D15-D0上;
ARM處理器知道訪問的是16-BIT的FLASH,從D7-D0上讀取所需要的一個BYTE的數據。
例子 2:ARM處理器需要從地址0x1讀取一個BYTE
ARM處理器在地址線An-A0上送出信號0x1;
16-BIT FLASH在自己的地址信號An-A0上看到的地址依然是0x0, 然后將地址0x0對應的16-BIT數據單元輸出到D15-D0上;
ARM處理器知道訪問的是16-BIT的FLASH,從D15-D8 上讀取所需要的一個BYTE 的數據。
2.3 從軟件角度來看 ARM 處理器和 NOR FLASH 的連接
從軟件的角度來理解ARM處理器和 FLASH的連接。對于8-BIT的FLASH的連接,很好理解,由于ARM處理器和8-BIT FLASH的每個地址對應的都是一個 BYTE 的數據單元。所以地址連接毫無疑問是逐一對應的。假如 ARM 處理器連接的是 16-BIT 的處理器,由于 ARM 處理器的每個地址對應的是一個 BYTE 的數據單元,而 16-BIT FLASH 的每個地址對應的是一個 HALF-WORD 的16-BIT的數據單元。所以,也毫無疑問,ARM處理器訪問16-BIT處理器的時候,地址肯定是要錯開一位的。在寫FLASH驅動的時候,我們不需要知道地址錯位是由硬件實現的,還是是通過設置ARM處理器內部的寄存器來實現的,只需要記住2點:
ARM處理器訪問8-BIT FLASH的時候,地址是逐一對應的;
ARM處理器訪問16-BIT FLASH的時候,地址肯定是錯位的。
2.4 8-BIT FLASH 燒寫驅動實例 - HY29F040
HY29F040是現代公司的一款8-BIT的NOR FLASH.在這個小節里,我們以這個芯片為例子,講述如何對8-BIT NOR FLASH進行操作。
HY29F040的容量為512K-BYTE,總共包括8 個SECTOR,每個SECTOR 的容量是64K-BYTE.該芯片支持SECTOR擦除,整片擦除和以BYTE 為基本單位的寫操縱.HY29F040的命令定義如表-1所示。
下面,我們來看看如何實現基本的擦除和編程操作。在本節后面的描述中,我們使用了下面的2 個定義:
U32 sysbase; //該變量用來表示 FLASH 的起始地址
#define SysAddr8(sysbase, offset) ((volatile U8*)(sysbase)+(offset)) //用來方便對指定的 FALSH 地址進行操作
宏SysAddr8定義了一個 BYTE(8-BIT)指針,其地址為(sysbase + offset)。假設FLASH的起始地址為0x10000000,假如要將0xAB寫到FLASH的第一個BYTE中往,可以用下面的代碼:
*SysAddr8(0x10000000, 0x1) = 0xAB;
注意:
在本節后面的描述中,sysbase代表的是FLASH的起始地址,而SysAddr8中的offset則代表了相對于FLASH起始地址的BYTE偏移量.offset也是8-BIT FLASH在自己的地址信號An-A0上看到的地址。
a. 整片擦除操作
整片擦除操縱共需要6個周期的總線寫操作:
將 0xAA寫到 FLASH 地址 0x5555;
將 0x55 寫到 FLASH 地址 0x2AAA;
將 0x80 寫到 FLASH 地址 0x5555;
將 0xAA寫到 FLASH 地址 0x5555;
將 0x55 寫到 FLASH 地址 0x2AAA;
將 0x10 寫到 FLASH 地址 0x5555.
對應的代碼:
*SysAddr8(sysbase, 0x5555) = 0xAA; //將值 0xAA寫到 FLASH 地址 0x5555
*SysAddr8(sysbase, 0x2AAA) = 0x55; //將值 0x55 寫到 FLASH 地址 0x2AAA
*SysAddr8(sysbase, 0x5555) = 0x80; //將值 0x80 寫到 FLASH 地址 0x5555
*SysAddr8(sysbase, 0x5555) = 0xAA; //將值 0xAA寫到 FLASH 地址 0x5555
*SysAddr8(sysbase, 0x2AAA) = 0x55; //將值 0x55 寫到 FLASH 地址 0x2AAA
*SysAddr8(sysbase, 0x5555) = 0x10; //將值 0x10 寫到 FLASH 地址 0x5555
b. SECTOR擦除操作
SECTOR的擦除操縱共需要6個周期的總線寫操作:
將 0xAA寫到 FLASH 地址 0x5555;
將 0x55 寫到 FLASH 地址 0x2AAA;
將 0x80 寫到 FLASH 地址 0x5555;
將 0xAA寫到 FLASH 地址 0x5555;
將 0x55 寫到 FLASH 地址 0x2AAA;
將 0x30 寫到要擦除的 SECTOR 對應的地址。
對應的代碼:
*SysAddr8(sysbase, 0x5555) = 0xAA; //將值 0xAA寫到 FLASH 地址 0x5555
*SysAddr8(sysbase, 0x2AAA) = 0x55; //將值 0x55 寫到 FLASH 地址 0x2AAA
*SysAddr8(sysbase, 0x5555) = 0x80; //將值 0x80 寫到 FLASH 地址 0x5555
*SysAddr8(sysbase, 0x5555) = 0xAA; //將值 0xAA寫到 FLASH 地址 0x5555
*SysAddr8(sysbase, 0x2AAA) = 0x55; //將值 0x55 寫到 FLASH 地址 0x2AAA
*SysAddr8(sysbase, addr) = 0x30; //將值 0x30 寫到要擦除的 SECTOR 對應的地址
c. BYTE擦除操作
寫一個BYTE 的數據到FLASH中往,需要 4個周期的總線寫操作:
將 0xAA寫到 FLASH 地址 0x5555;
將 0x55 寫到 FLASH 地址 0x2AAA;
將 0xA0 寫到 FLASH 地址 0x5555;
將編程數據(BYTE)寫到對應的編程地址上。
對應的代碼:
*SysAddr8(sysbase, 0x5555) = 0xAA; //將值 0xAA寫到 FLASH 地址 0x5555
*SysAddr8(sysbase, 0x2AAA) = 0x55; //將值 0x55 寫到 FLASH 地址 0x2AAA
*SysAddr8(sysbase, 0x5555) = 0xA0; //將值 0xA0 寫到 FLASH 地址 0x5555
*SysAddr8(sysbase, addr) = data; //將一個 BYTE的數據寫到期看的地址
2.5 16-BIT FLASH 燒寫驅動實例 - SST39VF160
SST39VF160是SST公司的一款16-BIT的NOR FLASH. 在這個小節里, 我們以SST39VF160為例子, 講述如何對16-BIT NOR FLASH進行操作。對8-BIT FLASH的操作很好理解,但對16-BIT FLASH的操作理解起來要晦澀很多。我盡力描述得清楚些。
SST39VF160的容量為2M-BYTE , 總共包括512個SECTOR, 每個SECTOR 的容量是4K-BYTE. 該芯片支持SECTOR擦除,整片擦除和以 HALF-WORD 為基本單位的寫操縱.SST39VF160 的命令定義如表-2 所示。在表 2 中,由于所有命令都是從FLASH的角度來定義的。 所以, 所有的地址都是HALF-WORD地址, 指的是16-BIT FLASH在自己的地址信號An-A0上看到的地址。
在本節后面的描述中,我們使用了下面的2個定義:
U32 sysbase; //該變量用來表示 FLASH 的起始地址
#define SysAddr16(sysbase, offset) ((volatile U16*)(sysbase)+(offset)) //用來方便對指定的 FALSH 地址進行操作
SysAddr16(sysbase, offset)首先定義了一個16-BIT HALF-WORD的指針,指針的地址為sysbase,然后根據offset做個偏移操縱。 由于HALF-WORD指針的地址是2個BYTE對齊的, 所以每個偏移操縱會使得地址加2. 終極, SysAddr16 (sysbase, offset)相當于定義了一個HALF-WORD的指針,其終極地址為(sysbase + 2offset) 。在使用SysAddr16的時候,將sysbase設置成 FLASH 的起始地址,offset 則可以理解為相對于 FLASH 起始地址的HALF-WORD 偏移量或是偏移地址。假設FLASH 的起始地址為 0x10000000,SysAddr16(0x10000000, 0)指向 16-BIT FLASH 的第 0 個HALF-WORD, SysAddr16(0x10000000, 1指向16-BIT FLASH的第1個HALF-WORD.依次類推。假如要將0xABCD分別寫到FLASH 的第0個和第 1個HALF-WORD 中往,可以用下面的代碼:
*SysAddr16(0x10000000, 0x0) = 0xABCD;
*SysAddr16(0x10000000, 0x1) = 0xABCD;
接下來,我們分別從ARM處理器的角度和FLASH的角度來具體分析一下。
從 ARM 的角度來看:
假設 FLASH 的起始地址為 0x10000000,由于 ARM 處理器知道 FLASH 的地址空間為 0x10000000 ~ (0x10000000 +FLASH容量 – 1),所以在對這個地址空間進行訪問的時候,會設置好FLASH的片選信號,并將低位的地址輸出到 地址信號上。以*SysAddr16(0x10000000, 0x1) = 0xABCD 為例。從ARM 處理器的角度來看,該操縱是把0xABCD寫到地址0x10000002上往。所以ARM處理器終極會在它的地址信號An-A0輸出地址0x2,同時會在D15-D0 上輸出0xABCD.
從 FLASH 的角度來看:
還是以 *SysAddr16(0x10000000, 0x1) = 0xABCD 為例,FLASH看到的地址是多少呢?接著分析.ARM 處理器在執行操縱的時候,會設置好相應的FLASH片選使能信號,并在ARM的地址信號An-A0上輸出 0x2.由于 ARM和 16-BIT FLASH的地址信號的連接是錯開一位的, 所以, FLASH終極在自己的地址An-A0上看到的信號是0x1, 相當于將ARM處理器輸出的地址往右做了一個移位操縱,恰好對應的是FLASH的第1 個HALF-WORD.同時,FLASH會在自己的D15-D0上看到數據0xABCD.
通過上面的分析,我們知道 SysAddr16 中指定的 offset 的值就是 16-BIT FLASH 在自己的地址 An-A0 上看到的值。所以,我們可以很方便的通過 SysAddr16(sysbase, offset) 對 FLASH 進行操縱,其中 sysbase 代表 FLASH 起始地址,offset 則代表了FLASH 的第幾個HALF-WORD(HALF-WORD偏移量或偏移地址)
注意:
在本節后面的描述中,SysAddr16中的 SYSBASE代表的是FLASH的起始地址,而SysAddr16中的 OFFSET則代表了相對于FLASH起始地址的 HALF-WORD 偏移量或偏移地址.OFFSET 的值也是16-BIT FLASH在自己的地址信號An-A0上看到的值;
在SST39VF160的命令定義中,所有的地址都是針對FLASH的HALF-WORD地址,指的是在FLASH自己的地址信號An-A0上看到的地址。
整片擦除操作
整片擦除操縱共需要6個周期的總線寫操作:
將 0x00AA寫到 FLASH HALF-WORD 地址 0x5555;
將 0x0055 寫到 FLASH HALF-WORD地址 0x2AAA;
將 0x0080 寫到 FLASH HALF-WORD地址 0x5555;
將 0x00AA寫到 FLASH HALF-WORD 地址 0x5555;
將 0x0055 寫到 FLASH HALF-WORD地址 0x2AAA;
將 0x0010 寫到 FLASH HALF-WORD地址 0x5555.
對應的代碼:
*SysAddr16(sysbase, 0x5555) = 0x00AA; //將值 0x00AA 寫到 FLASH HALF-WORD地址 0x5555
*SysAddr16(sysbase, 0x2AAA) = 0x0055; //將值 0x0055 寫到 FLASH HALF-WORD地址 0x2AAA
*SysAddr16(sysbase, 0x5555) = 0x0080; //將值 0x0080 寫到 FLASH HALF-WORD地址 0x5555
*SysAddr16(sysbase, 0x5555) = 0x00AA; //將值 0x00AA 寫到 FLASH HALF-WORD地址 0x5555
*SysAddr16(sysbase, 0x2AAA) = 0x0055; //將值 0x0055 寫到 FLASH HALF-WORD地址 0x2AAA
*SysAddr16(sysbase, 0x5555) = 0x0010; //將值 0x0010 寫到 FLASH HALF-WORD地址 0x5555
SECTOR擦除操作
SECTOR的擦除操縱共需要6個周期的總線寫操作:
將 0x00AA寫到 FLASH HALF-WORD 地址 0x5555;
將 0x0055 寫到 FLASH HALF-WORD地址 0x2AAA;
將 0x0080 寫到 FLASH HALF-WORD地址 0x5555;
將 0x00AA寫到 FLASH HALF-WORD 地址 0x5555;
將 0x0055 寫到 FLASH HALF-WORD地址 0x2AAA;
將 0x0030 寫到要擦除的 SECTOR 對應的 HALF-WORD地址。
對應的代碼:
*SysAddr16(sysbase, 0x5555) = 0x00AA; //將值 0x00AA 寫到 FLASH HALF-WORD地址 0x5555
*SysAddr16(sysbase, 0x2AAA) = 0x0055; //將值 0x0055 寫到 FLASH HALF-WORD地址 0x2AAA
*SysAddr16(sysbase, 0x5555) = 0x0080; //將值 0x0080 寫到 FLASH HALF-WORD地址 0x5555
*SysAddr16(sysbase, 0x5555) = 0x00AA; //將值 0x00AA 寫到 FLASH HALF-WORD地址 0x5555
*SysAddr16(sysbase, 0x2AAA) = 0x0055; //將值 0x0055 寫到 FLASH HALF-WORD地址 0x2AAA
*SysAddr16(sysbase, addr 》》 1) = 0x0030; //將值 0x0030 寫到要擦除的 SECTOR 對應的HALF-WORD地址
注意:
上面的代碼中第6個操縱周期中的ADDR 是從ARM處理器的角度來看的BYTE地址,由于在擦除的時候,用戶希看指定的是從 ARM 的角度看到的地址,這樣更方便和更直觀。而在 SysAddr16 的宏定義中,OFFSET 表示的是相對于FLASH起始地址的 HALF-WORD 偏移量,或是FLASH在自己的地址信號An-A0上看到的地址。所以需要執行一個右移操作,把ADDR轉換成 HALF-WORD 地址。
舉例說明,SST39VF160 每個 SECTOR 的大小是 4K-BYTE.從 ARM 處器的角度和用戶的角度來看,SECTOR-0 相對于FLASH起始地址的BYTE地址是0x0;從FLASH來看SECTOR-0 的HALF-WORD地址是0x0.從ARM處理器的角度和用戶的角度來看, FLASH SECTOR-1相對于FLASH起始地址的BYTE地址0x1000; 從FLASH來看, SECTOR-1的HALF-WORD地址應該是(0x1000 》》 1) = 0x800.
假如要擦除SECTOR-0,上面代碼的第6條指令應該是:
*SysAddr16(sysbase, 0x0 》》 1) = 0x0030;
假如要擦除SECTOR-1,上面代碼的第6條指令應該是:
*SysAddr16(sysbase, 0x1000 》》 1) = 0x0030;
HALF-WORD 編程操作
寫一個HALF-WORD的數據到FLASH中往,需要4個周期的總線寫操作:
將 0x00AA寫到 FLASH HALF-WORD 地址 0x5555;
將 0x0055 寫到 FLASH HALF-WORD地址 0x2AAA;
將 0x00A0 寫到 FLASH HALF-WORD 地址 0x5555;
將編程數據(HALF-WORD)寫到對應的 HALF-WORD地址。
對應的代碼:
*SysAddr16(sysbase, 0x5555) = 0x00AA; //將值 0x00AA 寫到 FLASH 地址 0x5555
*SysAddr16(sysbase, 0x2AAA) = 0x0055; //將值 0x0055 寫到 FLASH 地址 0x2AAA
*SysAddr16(sysbase, 0x5555) = 0x00A0; //將值 0x00A0 寫到 FLASH 地址 0x5555
*SysAddr16(sysbase, addr 》》 1) = data; //將數據寫到對應的 HALF-WORD 地址
注意:
上面的代碼中第4個操作周期中的ADDR是從ARM處理器的角度來看的BYTE地址, 由于在執行寫操作的時候,用戶希看指定的是從 ARM 的角度看到的地址,這樣會更方便和更直觀。而在 SysAddr16 的宏定義中,OFFSET表示的是相對于FLASH起始地址的HALF-WORD偏移量。 所以需要執行一個右移操縱, 把它轉換成HALF-WORD地址。
例如要將數據 0x0123 寫到地址 0x0處,對應的是 FLASH 的第 0 個 HAFL-WORD,對應的 HALF-WORD 地址應該是0x0,上面代碼的第4條指令應該是:
*SysAddr16(sysbase, 0x0 》》 1) = 0x0123;
又如要將數據0x4567寫到地址0x2處, 對應的是FLASH的第1個 HALF-WORD, 對應的HALF-WORD地址應該是0x1, 上面代碼的第4條指令應該是:
*SysAddr16(sysbase, 0x2 》》 1) = 0x4567;
再如要將數據0x89AB寫到地址0x4處, 對應的是FLASH的第2個HALF-WORD, 對應的HALF-WORD地址應該是0x2,上面代碼的第4條指令應該是:
*SysAddr16(sysbase, 0x4 》》 1) = 0x89AB;
還如要將數據0xCDEF 寫到地址 0x6處,對應的是 FLASH 的第 3 個 HALF-WORD,對應的 HALF-WORD 地址應該是0x3,上面代碼的第4條指令應該是:
*SysAddr16(sysbase, 0x6 》》 1) = 0xCDEF;
2.6 結束語
以上簡單介紹了NOR FLASH原理,以及如何對NOR FLASH進行操作, 但沒有包括狀態查詢, 保護等其他操縱。 對于更復雜的多片FLASH并聯的情況也沒有討論,如有需要者,可自行分析.
-
FlaSh
+關注
關注
10文章
1660瀏覽量
150917 -
存儲器
+關注
關注
38文章
7625瀏覽量
166255
發布評論請先 登錄
什么是串行Nor Flash?串行Nor Flash的結構和參數特性

NAND Flash和NOR Flash的差別

NAND FLASH與NOR FLASH的技術對比

關于Nor Flash的各種挑戰
NAND Flash與NOR Flash的區別
關于NOR Flash的幾大應用領域淺析
單片機內部Flash是Nor 還是Nand Flash
NOR Flash和NAND FLASH的區別是什么

NAND Flash和NOR Flash的區別

Flash存儲芯片:NOR Flash、NAND Flash、UFS和eMMC的比較與解析

評論