?? DM365的視頻處理涉及到三個相關處理器,分別是視頻采集芯片、ARM處理器和視頻圖像協處理器(VICP),整個處理流程由ARM核協調。視頻處理主要涉及三個處理流程,分別是視頻采集、視頻編碼和對編碼后的視頻的處理,為了提高性能,通常為每個處理流程提供一個處理線程。
視頻采集
? TVP5146將采集到的視頻數據轉化為數字信號,并將這些數據送入DM365的BT656接口,然后通過Resize得到所需要的分辨率,然后將這些數據寫入到指定的內存中,這些內存空間由cmem模塊分配。cmem模塊用于分配連續的存儲空間,連續的存儲空間可以提高數據的讀寫效率。
視頻編碼
?? VICP從指定的存儲空間中讀入視頻數據,并將這些數據編碼為指定的視頻/圖像格式,然后將編碼后的數據寫入到指定的存儲空間,這些存儲空間通常也是由cmem模塊分配。
編碼數據處理
? ARM從指定的內存空間中獲取編碼后的視頻數據,可以將這些編碼后的數據保存到本地或遠端,也可以使用RTP協議發送到網絡。
整個過程由ARM核協調,為了提高效率,大量使用DMA操作和cmem模塊分配的連續存儲空間。
?
? |
作者:德州儀器現場技術支持工程師 孟海燕
概要:
本文介紹了DM368 NAND Flash啟動的原理,并且以DM368 IPNC參考設計軟件為例,介紹軟件是如何配合硬件實現啟動的。
關鍵字:NAND Flash啟動,RBL,UBL
芯片上電后是如何啟動實現應用功能的?這是許多工程師在看到處理器運行的時候,通常都會問的一個問題。下面我們就以德州儀器的多媒體處理芯片TMS320DM368為例,介紹它的NAND Flash啟動原理以及實現。
一.NAND Flash啟動原理
德州儀器的多媒體處理芯片TMS320DM368可以實現1080P30 h264的編碼,已經廣泛的使用在了網絡攝像機的應用中。DM368可以支持NOR Flash, NAND Flash, UART, SD Card啟動等多種啟動方式。對于NAND啟動,DM365支持的特性如下:
1.?? 不支持一次性全部固件下載啟動。相反的,需要使用從NAND flash把第二級啟動代碼(UBL)復制到ARM的內存(AIM),將控制轉交給用戶定義的UBL。
2.?? 支持最大4KB頁大小的NAND。
3.?? 支持特殊數字標志的錯誤檢測,在加載UBL的時候會嘗試最多24次。例如在NAND的第1個block沒有找到特殊數字標志,會到下一個block繼續查找,一直到查找到第24個block。
4.?? 支持30KB大小的UBL(DM365有32KB的內存,其中2KB用作了RBL的堆棧,剩下的空間可以放UBL)
5.?? 用戶可以選擇在RBL執行的時候是否需要支持DMA,I-cache(例如,加載UBL的時候)
6.?? 使用并且需要4位硬件ECC(支持每512字節需要ECC位數小于或等于4位的NAND Flash)。
7.?? 支持需要片選信號在Tr讀時間為低電平的NAND Flash。
在網絡網絡攝像機的應用中為了節約成本,有一些用戶使用了NAND Flash啟動方式。圖1 就是從上電到Linux啟動的一個概要的流程圖。首先RBL(ROM boot loader)從NAND上讀取UBL(user boot loader)并且復制到ARM的內存里面。UBL運行在ARM的內存里,初始化系統,例如初始化DDR。然后UBL從NAND Flash里面讀取U-Boot的內容并且復制到DDR里運行。DDR里面運行的U-Boot又從NAND Flash里面讀取Linux內核代碼,并且復制到DDR上,然后啟動內核。這樣DM365的系統就從上電到完成Linux內核啟動,然后就可以運行相應的應用程序了。
圖1 NAND Flash啟動流程
下面我們會一步一步的介紹從上電到Linux啟動是如何實現的。
首先我們需要提到的一個概念是RBL,也就是ROM Boot Loader (ROM啟動代碼)。在DM368芯片上有一塊ROM的區域(地址從0x00008000到 0x0000 BFFF),這塊區域就是存放RBL代碼的地方。ROM上的代碼是在芯片出廠前就燒寫好的,用戶是不能修改的。在DM368上,除了AEMIF (Nor Flash)啟動,其他的啟動方式都需要運行RBL。
無論是上電復位,熱復位,還是看門狗復位,在復位信號由低到高的時候,DM368芯片會檢測BTSEL[2:0]引腳(啟動選擇引腳)。只要檢測到電平不是001,也就是不是AEMIF (NOR Flash)啟動,ARM程序就會從ARM的ROM的地址0x00008000地址開始執行。
RBL首先會讀取BOOTCFG寄存器里面的BTSEL信息,如果發現BTSEL的狀態是000,就會得知配置的是NAND Flash啟動,NAND啟動模式開始執行。注意:為了保證NAND啟動正常運行,需要保證在復位的時候DEEPSLEEPZ/GIO0引腳拉高。在確認啟動是NAND后,首先RBL會初始化最高2KB的內存為堆棧并且關閉所以中斷。然后RBL會讀取NAND的ID信息,然后在RBL的代碼里面的NAND ID 列表,從而得知更詳細的NAND Flash的信息,例如頁(page)大小等,對EMIF做好相應的配置。DM368支持啟動的NAND的ID信息可以在參考文檔1(ARM子系統用戶手冊)里面找到。硬件選型時,請務必選擇在NAND ID列表里面支持的NAND芯片。
接下來,RBL會在NAND Flash的第1塊的第0個頁開始查找UBL的描述符。如果沒有找一個合法的UBL的特殊數字標志,RBL會繼續到下一個塊的第0個頁查找描述符,最多第24個塊。RBL會到多個塊里面查找描述符是根據NAND Flash本身容易與壞塊的特點而設計的。24塊應該足以避免NAND Flash壞塊的影響。
如RBL在某塊里面找到了合法的UBL描述符,這個塊號(block number)就會寫到ARM內存最后的32位(0x7FFC~0x8000)用于調試時候使用,然后UBL描述符的具體內容將被讀取并且處理。UBL描述符告訴RBL關于下載和將控制權交給UBL所需要的信息,具體見表1.
第0頁地址 | 32位 | 描述 |
0 | 0xA1AC Edxx | 特殊數字標志 |
4 | UBL入口地址 | 用戶啟動代碼的入口地址(絕對地址) |
8 | UBL使用的頁數 | 頁數(用戶啟動diamond的大小) |
12 | UBL開始的塊號 | 開始存放用戶啟動代碼的塊號(block number) |
16 | UBL開始的頁數 | 開始存放用戶啟動代碼的頁數 |
20 | PLL設置-M | PLL設置- 倍率(僅在特殊數字標準表示PLL使能的時候有效) |
24 | PLL設置-N | PLL設置- 分率(僅在特殊數字標準表示PLL使能的時候有效 |
28 | 快速EMIF設置 | 快速EMIF設置(僅在特殊數字標準表示快速EMIF啟動的時候有效) |
表1 NAND UBL描述符
一旦用戶需要的啟動設置配置好,RBL就會從0x0020第地址開始把UBL搬移到ARM內存。在從NAND讀取UBL的過程中中,RBL會使用4位的硬件ECC對NAND Flash上的數據進行檢錯和糾錯。如果因為其他原因讀失敗,復制會立即停止,RBL會在下個塊里面繼續尋找特殊數字標志。
對于UBL的描述符有幾點注意事項:
1.?? 入口地址必須在0x0020到0x781C之間
2.?? 存放UBL的頁必須是連續的頁,可以分布在多個塊內,總共大小必須小于30KB。
3.?? UBL的起始塊號(block number)可以是和存放UBL描述符的塊號一樣。
4.?? 如果UBL的起始塊號是和存放UBL描述符的塊號一樣, 那UBL的起始頁數一定不可以和UBL描述符存放的頁數一樣。
但RBL根據UBL描述符里提供的UBL大小信息將UBL全部成功復制到ARM內存后,RBL會跳到UBL起始地址,這樣芯片的控制權就交給了UBL,UBL開始在ARM內存里運行了。
也許你會問,既然RBL可以把NAND Flash上的內容復制到ARM內存里運行,為什么我們不直接把U-Boot復制到內存運行?原因是ARM內存太小。一般的U-Boot都是大于100KB,而DM365上可以用于啟動的內存只有30KB。也許你又要問了,那為什么不把U-Boot直接復制到DDR上運行,DDR有足夠大的空間?這個原因是,芯片上電后并無法知道用戶在DM365的DDR2接口上接的DDR信息,RBL也就無法初始化DDR,在RBL運行的階段DDR是不可用的。這也是為什么UBL里面初始化DDR是它的一項重要任務。
當NAND啟動失敗的時候,RBL會繼續嘗試MMC/SD啟動方式。如果你系統使用NAND啟動,但NAND上的內容損壞了,如果你的板子上有SD卡接口,也可以改變啟動方式,那你可以用SD卡先把系統啟動起來,然后重新燒寫NAND Flash上的內容。這可以作為產品失效后在客戶側的一個補救方法。
二.NAND Flash啟動的軟件配合實現
現在我們知道了DM368 NAND Flash啟動的原理,下面我們來看看軟件是如何根據并配合硬件的要求實現啟動的。在DM368 IPNC的軟件包里面有一個工具的目錄,里面有預先編譯好的燒寫NAND的CCS的可執行文件, UBL的二進制文件以及相關源碼。
剛才在介紹NAND Flash啟動原理的時候,我們提到了RBL需要到NAND Flash上面搜索特殊數字標志。這個特殊數字標志就是由燒寫NAND的CCS的工程寫到Flash上的。在flash_utils_dm36x_1.0.0\flash_utils_dm36x\DM36x\CCS\NANDWriter\src\nandwriter.c里面的LOCAL_writeHeaderAndData()函數就是用來寫描述符的。
// Setup header to be written
headerPtr = (Uint32 *) gNandTx;
headerPtr[0] = nandBoot->magicNum; //Magic Number
headerPtr[1] = nandBoot->entryPoint; //Entry Point
headerPtr[2] = nandBoot->numPage; //Number of Pages
#if defined(IPNC_DM365) || defined(IPNC_DM368)
headerPtr[3] = blockNum+3; //Starting Block Number
headerPtr[4] = 0; //Starting Page Number - always start data in page 1 (this header goes in page 0)
對比表1,你可看到headerPtr[3]的內容是用來存放UBL代碼的起始塊號。這里+3的意思就是UBL是存放在UBL描述符所放塊號后面的第三塊里面。headerPtr[4] = 0表示是從第0頁開始存放。當然這個值用戶是可以修改的。只要你燒寫UBL代碼的位置和描述符里面的起始塊/頁數一致就可以了。
在IPNC的代碼里面UBL的描述符是會從NAND Flash的第1個塊開始寫,如果塊是好的,就放在第1塊的第0頁。如果第1塊是壞的,就會把UBL的描述符寫入到下一個塊的第0頁。IPNC的代碼里面沒有將UBL描述符可能有的塊號從1到24塊(這是RBL搜索的范圍),它只是從第1塊到第3塊。如果UBL描述符放在第1塊,那如果第4塊是好的話,UBL的代碼就從第4塊的第0頁開始放。
#elif defined(IPNC_DM368)
// Defines which NAND blocks the RBL will search in for a UBL image
#define DEVICE_NAND_RBL_SEARCH_START_BLOCK (1)
#define DEVICE_NAND_RBL_SEARCH_END_BLOCK (3)
在nandwriter.c里面你還可以看到UBL的入口地址是固定的0x100。
gNandBoot.entryPoint = 0x0100; // This fixed entry point will work with the UBLs
要了解為什么是0x100,你就必須要看一下UBL的源碼。在UBL源碼的UBL.cmd文件里面,你可以看到下面的定義,將入口地址放在boot的地方,而boot的運行地址就是0x100。
-e boot //指定入口地址為boot
...
MEMORY
{
...
UBL_I_TEXT (RX) : origin = 0x00000100 length = 0x00004300
...
UBL_F_TEXT (R) : origin = 0x020000E0 length = 0x00004300
...
}
SECTIONS
{
...
.text : load = UBL_F_TEXT, run = UBL_I_TEXT, LOAD_START(FLASHTEXTStart), LOAD_SIZE(FLASHTEXTSize)
{
*(.boot)
. = align(4);
*(.text)
. = align(4);
}
....
}
在UBL的源碼boot.c里面有強制把啟動的最初代碼放在了boot的section里面。
#if defined(__TMS470__)
...
#pragma CODE_SECTION(boot,".boot");
#endif
void boot(void)
{
...
}
這樣從cmd的配置以及代碼指定代碼段,UBL的程序就能確保是從0x100的地址開始運行。
UBL啟動U-Boot的過程,借鑒了RBL啟動UBL的原理。燒寫描述符也是用同樣的LOCAL_writeHeaderAndData()函數。在nandwriter.c里面,我們把U-Boot的代碼叫做應用代碼(APP)。
// Defines which NAND blocks are valid for writing the APP data
#define DEVICE_NAND_UBL_SEARCH_START_BLOCK (8)
#define DEVICE_NAND_UBL_SEARCH_END_BLOCK (10)
下面是IPNC啟動后串口最初的打印。
Valid magicnum, 0xA1ACED66, found in block 0x00000008.
DONE
Jumping to entry point at 0x81080000.
我們可以看到UBL是指第8塊的地方找到了U-Boot的描述符,這個DEVICE_NAND_UBL_SEARCH_START_BLOCK的定義是一致的。
IPNC代碼支持在U-Boot里面更新UBL或者U-Boot自己。下面是燒寫ubl和U-Boot在U-Boot下的命令。
燒寫ubl:
nand write 0x80700000 0x080000 0x08000
燒寫U-Boot:
nand write 0x80700000 0x160000 0x28000
要了解為什么NAND Flash的燒寫地址是0x80000和0x160000,這還是需要了解nandwriter.c里面的燒寫流程。從前面的內容我們可以得知,nandwriter.c燒寫UBL是從1+3=4塊開始的,而燒寫U-Boot是從8+3=11塊。在IPNC上使用的NAND Flash是2K一個頁,每個塊128KB。所以UBL燒寫的地址是128KBx4=0x80000,而燒寫U-Boot的地址是128Kx11=0x160000。
所以如果在沒有NAND Flash壞塊的情況下,nandwriter.c會把UBL的描述符燒寫在第1塊第0頁上,把UBL的代碼燒寫在第4塊第0頁上,把U-Boot(APP)的描述符燒寫在第8塊第0頁上,把U-Boot的代碼燒寫在第11塊第0頁上。這樣芯片在上電確認是NAND Flash啟動后,RBL在執行的時候就會找到UBL相應的描述符,把UBL加載的ARM內存里運行。而UBL又找到了U-Boot的描述符,把U-Boot加載到DDR上運行。最后U-Boot加載uImage并啟動了Linux,完成了從上電到Linux啟動的整個過程。
三.結束語
每個芯片一般都有多種啟動方式,各個芯片的啟動方式都有所不同,但又有類似的地方。上面的介紹也可以作為學習其他芯片其他啟動方式的一個參考。
最后感謝李斌在本文整理過程中的幫助!
參考文獻
1. TMS320DM36x Digital Media System-on-Chip (DMSoC) ARM Subsystem User's Guide Literature Number: SPRUFG5A
2. TMS320DM368 datasheet Literature Number: SPRS668C