文講的是s3c2440A芯片的存儲管理器,配套的開發板是友善之臂mini2440,首先貼出代碼
head.s的代碼:
.equ MEM_CTL_BASE, 0x48000000 @定義13個寄存器的首地址
.equ SDRAM_BASE, 0x30000000 @定義SDRAM的首地址
.text
.global _start
_start:
bl disable_watch_dog
bl memsetup
bl copy_steppingstone_to_sdram @把代碼從片內的SRAM復制到SDRAM里面
ldr pc, =on_sdram
on_sdram:
ldr sp, =0x34000000 @設置棧指針,用來調用C函數
bl main
halt_loop:
b halt_loop
disable_watch_dog:
ldr r0, =0x53000000
mov r1, #0x0
str r1, [r0]
mov pc, r14
copy_steppingstone_to_sdram:
mov r0, #0x0
mov r1, #SDRAM_BASE
mov r2, #4096
Loop: @用一個循環,從片內SRAM的0地址開始復制到SDRAM的0x30000000處
ldr r3, [r0], #4
str r3, [r1], #4
cmp r0, r2
bcc Loop
mov pc, r14
memsetup: @設置存儲管理器相關的13個寄存器
mov r0, #MEM_CTL_BASE
ldr r1, =0x22011110 @BWSCON
str r1, [r0], #4 @把r1寄存器里面的值放到r0所指的內存單元中,然后r0=r0+4
ldr r1, =0x00000700
str r1, [r0], #4 @BANKCON0
str r1, [r0], #4 @BANKCON1
str r1, [r0], #4 @BANKCON2
str r1, [r0], #4 @BANKCON3
str r1, [r0], #4 @BANKCON4
str r1, [r0], #4 @BANKCON5
ldr r1, =0x00018005
str r1, [r0], #4 @BANKCON6
str r1, [r0], #4 @BANKCON7
ldr r1, =0x008c07a3
str r1, [r0], #4 @REFRESH
ldr r1, =0x000000b1
str r1, [r0], #4 @BANKSIZE
ldr r1, =0x00000030
str r1, [r0], #4 @MRSRB6
str r1, [r0] @MRSRB7
mov pc, r14
led_key.c的代碼:
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
#define GPBUP (*(volatile unsigned long *)0x56000018)
#define GPGCON (*(volatile unsigned long *)0x56000060)
#define GPGDAT (*(volatile unsigned long *)0x56000064)
#define GPB5_out (1<<(5*2))
#define GPB6_out (1<<(6*2))
#define GPB7_out (1<<(7*2))
#define GPB8_out (1<<(8*2))
#define GPB0_out (1<<(0*2))
#define GPG0_in ~(3<<(0*2))
#define GPG3_in ~(3<<(3*2))
#define GPG5_in ~(3<<(5*2))
#define GPG6_in ~(3<<(6*2))
#define GPG7_in ~(3<<(7*2))
#define GPG11_in ~(3<<(11*2))
int main()
{
unsigned long read_value;
GPBCON |= (GPB5_out | GPB6_out | GPB7_out | GPB8_out | GPB0_out);
GPBUP &= 0x1e1;
GPBDAT |= 0x1e0;
GPGCON &= (GPG0_in & GPG3_in & GPG5_in & GPG6_in & GPG7_in );
while(1)
{
read_value = GPGDAT;
if(read_value & (1<<0))
{
GPBDAT |= (1<<5);
}
else
{
GPBDAT &= (~(1<<5));
}
if(read_value & (1<<3))
{
GPBDAT |= (1<<6);
}
else
{
GPBDAT &= (~(1<<6));
}
if(read_value & (1<<5))
{
GPBDAT |= (1<<7);
}
else
{
GPBDAT &= (~(1<<7));
}
if(read_value & (1<<6))
{
GPBDAT |= (1<<8);
}
else
{
GPBDAT &= (~(1<<8));
}
if(read_value & (1<<7))
{
GPBDAT &= (~(1<<0));
}
else
{
GPBDAT |= (1<<0);
}
}
return 0;
}
Makefile:
sdrampp1.bin : head.s led_key.c
arm-linux-gcc -g -c -o head.o head.s
arm-linux-gcc -g -c -o led_key.o led_key.c
arm-linux-ld -Ttext 0x30000000 -g head.o led_key.o -o sdrampp1_elf
arm-linux-objcopy -O binary -S sdrampp1_elf sdrampp1.bin
arm-linux-objdump -D -m arm sdrampp1_elf > sdrampp1.dis
clean:
rm -rf sdrampp1.* *.o
首先說明本程序主要實現的功能:本程序最終為了生成一個sdrampp1.bin的可執行文件下載到開發板的NandFlash的0地址處,一旦下載進去,s3c2440A這塊芯片就會自動地把NandFlash的前4K代碼復制到片內的steppingstone,也就是片內的SRAM里,如果不加處理,一般的程序就從SRAM的0地址處開始運行了,例如上一篇博客“arm裸機程序之LED燈”就是從SRAM的0地址處開始運行的,而本程序并非從SRAM的0地址開始執行,而是把片內的SRAM的4K代碼復制到SDRAM的0地址處,最后從SDRAM的0地址處開始執行,所以Makefile中的代碼段地址是0x30000000,并非上一篇博客里寫的0x00000000,從0x30000000處運行代碼,在SDRAM的0x34000000處設置了一個棧指針,至于為什么棧指針是這個,后面的內容會詳細解釋,最后調用C函數,這里的C函數實現的功能是按下開發板上的k1鍵,led1亮,松開led1就滅,k2,k3,k4同樣道理控制其他3個led,k5控制蜂鳴器的響與不響.
首先看Makefile,注意到Makefile的第4行,要求把代碼段放在0x3000000處,解釋如上。至于其他的內容和上一篇博客的Makefile沒什么不同,Makefile就分析到此。
下面看看head.s的代碼,程序一開始一個bl跳轉指令,實現關閉看門狗的程序就不解釋了。接著是一個Memory Controller(存儲管理器)初始化的工作,這里涉及到13個寄存器,分別是BWSCON寄存器,BANKCON0寄存器等等,如果一開始我解釋這些寄存器,你肯定不知道我要講會聽的云里霧里,所以我先講點原理,把握整體再深究細節。
我們先從開發板的硬件原理圖開始說起,因為是開發板的原理圖是最基本直觀的東西了,by the way,我用的開發板是mini2440,所以查看的是mini2440原理圖,先上張圖先:
臥槽,你TMD給我上張這個圖片,先別著急,我是想讓你看看著塊芯片有多少根地址總線和數據總線,正因為這張圖片長得是比較丑,所以我盡量把它講的生動,美化它,最終讓你愛上它。首先我們來明確兩個概念,什么是地址總線,什么是數據總線,顧名思義,地址總線是CPU發送一個地址,地址總線決定了CPU所能訪問的最大內存空間,這個CPU是中的地址總線是ADDR0~ADDR26,總用27條地址總線吧,所以s3c2440A最大訪問的內存地址為2^27=128M,但是如果想讓這個CPU實現最大能訪問的內存空間達到1GB的空間怎么辦呢,cpu還引出8根片選信號nGCS0~nGCS7,所以總的尋址空間就達到1GB了,雖然你在上面這張圖看不出來有多少個片選信號,你可以在原理圖上搜索一下即可。其實在這里,我就可以引出一張s3c2440 Memery Controller的地址空間分布圖了,在上圖之前,我講一句話解釋數據總線到底怎么回事:就是決定CPU每次傳送數據的大小,這里有DARA0~DATA31,,,每次發送32位的數據,每次發送32位數據,其實就可以引出SDRAM的原理圖了,暫且不說,先看Memery Controller的地址空間分布圖:
看到這么一張大圖,先別慌,我比你更慌,不知道怎么解釋,先驗證一下上面說的那段話,總共8個片選信號,為了滿足1GB的地址空間的尋址,其實在這里每個片選對應一個bank,nGCS0對應的是Bank0,nGCS7對應Bank7,依次類推,只要選擇了一個片選信號,例如我這里假設懸著nGCS6的片選信號,CPU的27根地址總線就能對0x30000000~0x38000000之間的地址進行尋址了,不過這里還要注意,并不是每個之間的每個地址都能進行存儲數據,尋址什么的,因為s3c2440的每個Bank其實都是外接設備的,例如Bank0外接NorFlash,Bank4外接網卡DM9000,Bank6和Bank7外接SDRAM等,至于其他的我們暫時不用管,還可以涉及到芯片的2中啟動方式我這里就不介紹了。這里Bank6和Bank7都外接SDRAM是怎么回事呢,這里就和上面的數據總線聯系在一起了,因為開發板外接了兩塊SDRAM,每個SDRAM有16根數據總線,為了和cup的數據總線的寬度保持一致,所以要接兩塊SDRAM,SDRAM的原理圖請看下圖:
要知道SDRAM的工作原理,首先看看下面幾個問題,下面是我其他博客上看到的:
(1) 地址線為什么從A2開始?
因為2440數據寬度為32位,按4字節對齊,即地址只會是0x...0,0x...4,0x..C,0x...E,每次地址增加都是四個字節,所以A0和A1沒什么用。
(2) SDRM BANK 選擇輸入BA0/BA1為什么連接的是A24,A25
因為系統內存容量為64M,32bit,由兩片64M 16bit的SDRM組成。表示64M的空間需要26根線,所以地址最高兩位為A25和A24。
(3) 64M需要26根線,為什么實際只用到了A2~A14,A24,A25?
理論上應該將A2~A25直接連接到SDRAM來尋址64M(之所以不是A0~A25,是因為每次訪問的是32bit),而實際上只把A2~A14這13根線連接到SDRAM的A0~A12,這是因為SDRAM訪問時地址是分兩次給的,即行地址和列地址,不需要一次輸入,行地址和列地址復用了A2~A14這13根線,這個SDRAM理論上可尋址的最大范圍為2^13 * 2^13。
(4)為什么板子上SDRAM的空間為0x30000000 ~ 0x34000000
根據2440 SPEC,SDRAM只能放在BANK6 或 BANK7 (nGCS6或nGCS7),起始地址分別為0x30000000和0x38000000,一個BANK的大小為128M,現在選擇BANK放SDRAM,而SDRAM的容量為64M(0x4000000),所以SDRAM的范圍就是0x30000000~0x34000000,為什么是0x3....呢?因為你把nGCS6片選接到SDRAM芯片上了;當然后你也可以接nGCS7,不過地址就要變了,[A29,A28,A27]=3,即從0x38000000開始.
看了上述的問題與回答,應該能大致理解SDRAM的工作原理吧。
最后我分析一下,Memery Controller的13個寄存器:
1.BWSCON寄存器:中文名字叫做位寬和等待控制器。
STx位:啟動或禁止SDRAM的數據掩碼引腳,對于SDRAM,此位為0,對于SRAM,此位為1;
WSx:是否使用存儲器的WAIT信號,通常設置為0.
DWx:用來設置相應的Bank數據總線的位寬。
所以這里設置BWSCON寄存器的設置的值為0x22011110,bank7和bank6的位寬都為32位,其他的為16位,因外接的外設不同。還要注意一點的是Bank0,沒有WS0和DW0
2.BANKCON0和BANKCON1,BANKCON2,BANKCON3,BANKCON4,BANKCON5屬于同一類,用于設置外接設備的訪問時序,具體要看芯片手冊上的時序圖,這里默認設置為0x0700即可。
3.BANKCON6和BANKCON7寄存器:因為Bank6和Bank7可以接SDRAM,還可以接SRAM,SROM等等,所以在這個寄存器里相應的位要指明接的是什么,可以根據MT([16:15])來控制,還有就是想BANKCON1等寄存器一樣要設置時序了。這里根據芯片手冊,設置為0x00018005即可。
4.REFRESH寄存器:中文名叫做刷新控制寄存器,可以設置SDRAM的刷新功能,要不要使能,刷新模式,刷新周期等等,這里可以設置0x008c007a3,具體對照芯片手冊。
5.BANKSIZE寄存器:記住一點就是當多個SDRAM一起工作的時候,設置SDRAM在內存中的映射圖
6.MRSRB6和MRSRB7寄存器,就是設置Bank6和Bank7的一些特征,知道一個設置值即可0x30,具體細節,我覺得沒有必要太深入了,暫時對SDRAM的研究不需要太深,畢竟最終目標是自己定制一個U-Boot。
請用批判的眼光看我的文章,組織上可能不怎么到位,自己看看總能看的明白,歡迎交流討論!
上一篇:ARM指令狀態切換到Thumb指令狀態
下一篇:ARM裸機程序之LED燈
推薦閱讀
史海拾趣
2001年,Desoutter公司與CP(Chicago Pneumatic)和GR(Grorges Renault)合并,成立了CPDI公司。這次合并使Desoutter公司獲得了更強大的技術實力和市場資源,進一步鞏固了其在氣動工具領域的領先地位。合并后,CPDI公司繼續致力于氣動工具的研發和生產,并推出了一系列創新產品,以滿足市場的不斷變化和升級需求。
在電子行業中,產品質量是企業生存和發展的關鍵。誠潤電子深知這一點,因此在生產過程中嚴格把控每一個環節,確保產品質量的穩定性和可靠性。這種對品質的執著追求,使得誠潤電子的產品在市場上贏得了廣泛的認可和信任。許多知名品牌都選擇了誠潤電子作為他們的合作伙伴,共同為消費者提供優質的電子產品。
進入21世紀,電子行業迎來了快速發展的黃金時期。為了適應市場需求的變化,Cableform Inc不斷加大研發投入,致力于技術創新。公司成功開發出了一系列具有自主知識產權的電磁控制產品,涵蓋了從直流電機控制到高精度磁鐵控制等多個領域。這些技術創新不僅提升了公司的核心競爭力,也為客戶提供了更加高效、可靠的解決方案。
1914年,Bussmann五兄弟以家族生意為起點,在自家的地下室里開始生產熔斷器。他們憑借對電路保護的深刻理解和對市場需求的敏銳洞察,不久便將業務從地下室擴展到了小型廠房,并專注于汽車熔斷器的生產。這一轉變不僅標志著Bussmann業務的飛速發展,也奠定了其在電路保護領域的基石。通過不斷的技術創新和市場拓展,Bussmann逐步在保險絲市場上取得了領先地位。
隨著市場的競爭加劇,ECI意識到只有不斷創新才能在行業中立足。在總經理張女士的領導下,公司投入大量資源進行研發,成功推出了一系列具有競爭力的新產品。其中,一款集成了先進算法的智能傳感器,因其高精度和低功耗特性,在市場上大受歡迎。這一創新不僅提升了ECI的品牌形象,也為公司帶來了豐厚的利潤。
Dino-Lite公司在發展過程中,始終注重市場拓展和合作伙伴關系的建立。公司與多家知名企業建立了長期穩定的合作關系,共同開拓市場、分享資源。通過與合作伙伴的緊密合作,Dino-Lite公司的產品得以快速進入各個行業領域,并獲得了良好的口碑和市場份額。
此外,Dino-Lite公司還積極參與國際展覽和交流活動,展示公司的最新技術和產品。這些活動不僅提高了公司的知名度,也為公司帶來了更多的商業機會和合作伙伴。
文 摘 提出一種高質量的低速率語言編碼算法MWI,該算法對傳統的波形插值算法WI進行了全面的改進。MWI采用了一種更加合理的插值模型,包括統一的清音和濁音分析合成模型、新的典型波形的提取和表示方法,并且采用動態規劃的算法增加基音周期估計的 ...… 查看全部問答∨ |
[Nios II 中Flash的使用].12864參考原代碼 本帖最后由 paulhyde 于 2014-9-15 09:18 編輯 [Nios II 中Flash的使用].12864參考原代碼 … 查看全部問答∨ |
前兩天已經問了大家有關USB盤符訪問的問題,在中文環境下也的確好了,但在英文情況下又出問題了。代碼如下: m_hUSBDevice = CreateFile(TEXT("\\\\硬盤\\\\1.txt"), ...… 查看全部問答∨ |
private string strConn = "Data Source = \\\\test.sdf"; private void button1_Click(object sender, EventArgs e) {   ...… 查看全部問答∨ |
兄弟姐妹們:我想搭一個檢測繼電器是否導通閉合的檢測電路,大家有沒有什么方法? PS:我想用光耦,如果導通無方波,如果斷開則產生50HZ的方波,大家覺得可行嗎?用單片機可以檢測嗎?… 查看全部問答∨ |
設計資源 培訓 開發板 精華推薦
- Linux系統編程篇丨迅為IMX6ULL-對應視頻講解
- 嵌入式學習丨4412開發板-uboot源碼-匯編-源碼分析(一)嵌入式學習丨4412開發板-uboot源碼-匯
- 迅為IMX6ULL開發板-主頻和時鐘配置例程(二)
- 迅為IMX6ULL開發板-主頻和時鐘配置例程
- 迅為IMX6ULL開發板安裝VMware Tool工具
- i.MX6ULL終結者Debian文件系統的構建i.MX6ULL 移植Debian文件系統
- 迅為i.MX6ULL開發板按鍵例程編譯及運行
- 迅為-i.MX6開發板手冊更新-非設備樹uboot-修改默認環境變量
- 迅為-IMX6ULL-QT應用_在開發板上移植ssh
- 迅為-i.MX6ULL開發板-QT實戰項目DHT11&網絡編程實戰練習(一)