210串口控制台-210移植printf不好使
生活随笔
收集整理的這篇文章主要介紹了
210串口控制台-210移植printf不好使
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
210串口控制臺-問題描述
當210做到串口控制臺發現按照視頻及210故障分析之后卻發現仍然不好使,
這個是因為視頻中老師的代碼中去除了一部分之前課程中與串口控制臺無關部分的代碼,
這邊正常大家應該會發現,移植內核中printf函數還是會不好使,但是基本的串口打印是正常的,
首先我們先得分析一下這邊主要的原因,如果細心的同學應該會發現,
當我們加入內核printf的代碼之后,編譯出來的檔案會大于16K,
我們查找?S5PV210_iROM_ApplicationNote_Preliminary.pdf 這份文件,
?
可以發現手冊中有這個部分的操作順序,上電之后首先會運行在iROM中BL0里廠商固化好的代碼,
并且把用戶的BL1部分(只有16K)復制到了SRAM中(起始地址是0xD0020010,其中0xD0020000~0xD0020010是210加頭的部份),
按照圖中順序用戶應該要在BL1中將BL2(超過16K的部份),自己復制到SRAM中,
整個SRAM中有96K,如果整個Bootloader還超過就要在BL2中將剩馀代碼復制到內存SDRAM中,
因此我們發現最大的問題應該就出在BL0只復制16K上,按手冊要求,也為了之后的實驗,
我們在這里需要把我們的裸機代碼分成BL1跟BL2兩個部分,這樣才能解決不好使的問題
210串口控制臺-BL0廠商固化代碼
如果你看過答疑助手-許老師的BL1部分代碼,你會發現許老師在BL1中根本沒有做內存初始化,
直接就使用C語言,我們都知道C語言必須先要設置堆棧指針,而且堆棧指針會指向內存,
但是這個時候我們內存初始化都還沒做呢,怎么可能會把指針指向內存,
其實答案就出在BL0廠商固化代碼中,210跟2440、6410的啟動流程最大不一樣的地方,
就在這個BL0廠商固化代碼中,首先從手冊可以找到這個BL0干了什么
?
1.關閉看門狗計時器
2.初始化 iCache
3.初始化棧
4.初始化堆
5.初始化塊設備復制函數
6.初始化鎖相環并且設定系統時鐘
7.復制用戶代碼BL1到SRAM中
8.檢查BL1的校驗值
9.檢查是否為安全啟動模式
10.跳轉到用戶的BL1繼續執行
也就是說BL0中其實已經為我們初始化好堆棧了并且可以參考下面的內存地址分布來看一下
?
210串口控制臺-BL1、BL2分別需要完成的代碼
知道了BL0都干了什么之后,我們就知道其實BL1中最重要就是把BL2的代碼復制到SRAM或者是內存
因為我們的uboot很容易就超過80K所以我們就乾脆不復制到SRAM而直接復制到內存了,
復制到內存之后當然還必須跳轉到內存去執行,而BL2就是我們正常的uboot或者是裸機了,
而在BL1中的復制代碼首先要考慮的就是從哪里復制、復制到哪里、怎么復制,
下面整理了BL1的這幾個問題
1.從哪里復制:我們的代碼是下載到nand中的所以當然是從nand復制這個肯定是沒問題的,
當然使用nand之前當然得初始化nand
2.復制到哪:這個剛剛已經知道了我們直接復制到內存(SDRAM)中,這個也應該沒問題
3.怎么復制:
(a)首先按照課程自己初始化nand自己寫的復制函數,當然沒有問題,但是要注意的是nand的地址,
老師視頻中的nand地址的寫法是針對塊來寫的,建議大家可以參考yang的代碼按手冊按不同的nand,
寫成標準的列+行地址的方式
?
(b)前面我們說到了BL0初始化了一個塊設備復制函數,我們可不可以使用呢?當然是可以使用
手冊提到了下面的說明
?
怎么使用呢可以先定義
#define NF8_ReadPage_Adv(a,b,c) (((int(*)(unsigned int, unsigned int, unsigned char*))(*((unsigned int *)0xD0037F90)))(a,b,c))
然后復制的時候
?
需要注意的是這個函數的輸入部分是數據所在的塊跟所在的頁,而不是頁偏移,因為是塊設備復制
(c)另外值得注意的是我們自己寫的nand復制函數其實沒有考慮過ecc,因為nand存儲的數據很容易會出錯,
所以nand有個ecc的校驗機制,其實我們在看nand的手冊仔細點就可以看出端倪,
?
也就是這個部分,多出的這些字節其實就是存放ecc校驗碼的,至于算法有興趣的可以參考yang的代碼
最后就是從nand的哪個地址開始復制,首先分為SLC跟MLC兩種flash
正常大家應該使用的都是SLC的版本,下一節會提到BL1跟BL2的分割方式,
假設BL1加頭之后填充到4K,并且把BL2附加在后面那么實際上就是從nand4K的位置開始復制,
如果BL1加頭之后填充到16K,并且把BL2附加在后面那么實際上就是從nand16K的位置開始復制
另外提一下在210手冊523頁有一個OM腳的變量可以用來判斷是怎么啟動的
?
固化代碼中還有從SD卡復制代碼的函數有興趣的可以參考yang的代碼判斷OM假設從SD卡啟動,
就從SD卡復制剩下的代碼BL2到內存。
210串口控制臺-鏈接地址與BL1、BL2的分割方式
首先我們知道BL1是復制到SRAM中去執行的,在BL1中我們基本上只有在跳轉BL2的時候使用絕對跳轉,
剩下的地方都不會使用絕對跳轉,所以BL1的鏈接地址實際上沒有多大的作用,
而BL2的鏈接地址因為是跳轉到內存中的,并且是我們主要的程序部分,
加上需要處理中段向量,因此這個鏈接地址就非常重要了,
如果我們的代碼最終是復制到0x20008000這個地址并且跳轉到這個地址的,
那我們的鏈接地址就必須是0x20008000,也就是說鏈接地址與代碼實際的地址必須保持一致
?
至于怎么把代碼分割成BL1跟BL2實際上的作法是做兩個代碼分別編譯,
并且保證BL1小于16K,把BL1加頭之后擴展到一定的大小,再把BL2附加在BL1后面
?
BL1的Makefile先把BL1編譯之后加頭
?
頂層的Makefile實際上就是把已經加完頭的spl_210.bin 擴展成16K,然后再把編譯完的BL2,
連接,實際上因為在210的頭中有BL1的實際大小,因此如果你的BL1不到16K也就不需要一定得擴展到16K
當210做到串口控制臺發現按照視頻及210故障分析之后卻發現仍然不好使,
這個是因為視頻中老師的代碼中去除了一部分之前課程中與串口控制臺無關部分的代碼,
這邊正常大家應該會發現,移植內核中printf函數還是會不好使,但是基本的串口打印是正常的,
首先我們先得分析一下這邊主要的原因,如果細心的同學應該會發現,
當我們加入內核printf的代碼之后,編譯出來的檔案會大于16K,
我們查找?S5PV210_iROM_ApplicationNote_Preliminary.pdf 這份文件,
?
可以發現手冊中有這個部分的操作順序,上電之后首先會運行在iROM中BL0里廠商固化好的代碼,
并且把用戶的BL1部分(只有16K)復制到了SRAM中(起始地址是0xD0020010,其中0xD0020000~0xD0020010是210加頭的部份),
按照圖中順序用戶應該要在BL1中將BL2(超過16K的部份),自己復制到SRAM中,
整個SRAM中有96K,如果整個Bootloader還超過就要在BL2中將剩馀代碼復制到內存SDRAM中,
因此我們發現最大的問題應該就出在BL0只復制16K上,按手冊要求,也為了之后的實驗,
我們在這里需要把我們的裸機代碼分成BL1跟BL2兩個部分,這樣才能解決不好使的問題
210串口控制臺-BL0廠商固化代碼
如果你看過答疑助手-許老師的BL1部分代碼,你會發現許老師在BL1中根本沒有做內存初始化,
直接就使用C語言,我們都知道C語言必須先要設置堆棧指針,而且堆棧指針會指向內存,
但是這個時候我們內存初始化都還沒做呢,怎么可能會把指針指向內存,
其實答案就出在BL0廠商固化代碼中,210跟2440、6410的啟動流程最大不一樣的地方,
就在這個BL0廠商固化代碼中,首先從手冊可以找到這個BL0干了什么
?
1.關閉看門狗計時器
2.初始化 iCache
3.初始化棧
4.初始化堆
5.初始化塊設備復制函數
6.初始化鎖相環并且設定系統時鐘
7.復制用戶代碼BL1到SRAM中
8.檢查BL1的校驗值
9.檢查是否為安全啟動模式
10.跳轉到用戶的BL1繼續執行
也就是說BL0中其實已經為我們初始化好堆棧了并且可以參考下面的內存地址分布來看一下
?
210串口控制臺-BL1、BL2分別需要完成的代碼
知道了BL0都干了什么之后,我們就知道其實BL1中最重要就是把BL2的代碼復制到SRAM或者是內存
因為我們的uboot很容易就超過80K所以我們就乾脆不復制到SRAM而直接復制到內存了,
復制到內存之后當然還必須跳轉到內存去執行,而BL2就是我們正常的uboot或者是裸機了,
而在BL1中的復制代碼首先要考慮的就是從哪里復制、復制到哪里、怎么復制,
下面整理了BL1的這幾個問題
1.從哪里復制:我們的代碼是下載到nand中的所以當然是從nand復制這個肯定是沒問題的,
當然使用nand之前當然得初始化nand
2.復制到哪:這個剛剛已經知道了我們直接復制到內存(SDRAM)中,這個也應該沒問題
3.怎么復制:
(a)首先按照課程自己初始化nand自己寫的復制函數,當然沒有問題,但是要注意的是nand的地址,
老師視頻中的nand地址的寫法是針對塊來寫的,建議大家可以參考yang的代碼按手冊按不同的nand,
寫成標準的列+行地址的方式
?
(b)前面我們說到了BL0初始化了一個塊設備復制函數,我們可不可以使用呢?當然是可以使用
手冊提到了下面的說明
?
怎么使用呢可以先定義
#define NF8_ReadPage_Adv(a,b,c) (((int(*)(unsigned int, unsigned int, unsigned char*))(*((unsigned int *)0xD0037F90)))(a,b,c))
然后復制的時候
?
需要注意的是這個函數的輸入部分是數據所在的塊跟所在的頁,而不是頁偏移,因為是塊設備復制
(c)另外值得注意的是我們自己寫的nand復制函數其實沒有考慮過ecc,因為nand存儲的數據很容易會出錯,
所以nand有個ecc的校驗機制,其實我們在看nand的手冊仔細點就可以看出端倪,
?
也就是這個部分,多出的這些字節其實就是存放ecc校驗碼的,至于算法有興趣的可以參考yang的代碼
最后就是從nand的哪個地址開始復制,首先分為SLC跟MLC兩種flash
正常大家應該使用的都是SLC的版本,下一節會提到BL1跟BL2的分割方式,
假設BL1加頭之后填充到4K,并且把BL2附加在后面那么實際上就是從nand4K的位置開始復制,
如果BL1加頭之后填充到16K,并且把BL2附加在后面那么實際上就是從nand16K的位置開始復制
另外提一下在210手冊523頁有一個OM腳的變量可以用來判斷是怎么啟動的
?
固化代碼中還有從SD卡復制代碼的函數有興趣的可以參考yang的代碼判斷OM假設從SD卡啟動,
就從SD卡復制剩下的代碼BL2到內存。
210串口控制臺-鏈接地址與BL1、BL2的分割方式
首先我們知道BL1是復制到SRAM中去執行的,在BL1中我們基本上只有在跳轉BL2的時候使用絕對跳轉,
剩下的地方都不會使用絕對跳轉,所以BL1的鏈接地址實際上沒有多大的作用,
而BL2的鏈接地址因為是跳轉到內存中的,并且是我們主要的程序部分,
加上需要處理中段向量,因此這個鏈接地址就非常重要了,
如果我們的代碼最終是復制到0x20008000這個地址并且跳轉到這個地址的,
那我們的鏈接地址就必須是0x20008000,也就是說鏈接地址與代碼實際的地址必須保持一致
?
至于怎么把代碼分割成BL1跟BL2實際上的作法是做兩個代碼分別編譯,
并且保證BL1小于16K,把BL1加頭之后擴展到一定的大小,再把BL2附加在BL1后面
?
BL1的Makefile先把BL1編譯之后加頭
?
11.png?
下載附件??保存到相冊
頂層的Makefile實際上就是把已經加完頭的spl_210.bin 擴展成16K,然后再把編譯完的BL2,
連接,實際上因為在210的頭中有BL1的實際大小,因此如果你的BL1不到16K也就不需要一定得擴展到16K
總結
以上是生活随笔為你收集整理的210串口控制台-210移植printf不好使的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于IO模式(浮空、推挽、开漏...)描
- 下一篇: FreeRtos osMessageP