天天看點

s3c2440存儲控制器詳解

s3c2440存儲控制器詳解

從上圖可知,外部記憶體類的裝置與存儲管理器相連,那麼CPU是怎樣通路到記憶體的呢?通過存儲管理器。CPU比較單純,隻會按照指令執行,CPU隻負責發出位址,怎樣找到記憶體類裝置呢?這些都交給存儲管理器來管理。

s3c2440對外引出的27根位址線ADDR0-ADDR26的通路範圍隻有128M,那麼如何達到1G呢,CPU還對外引出了8條片選線nGCS0-nGCS7,對應于bank0-bank7,當通路BANKX的位址空間時,nGCSx輸出低電平選中外部晶片,這樣就能達到1G的位址空間。如下圖

s3c2440存儲控制器詳解

s3c2440作為32位的CPU,可以使用的位址理論上是4G,除了存儲器管理的1G,還有内部的寄存器占用位址外,其他的位址剩下沒用。s3c2440的内部寄存器位址範圍是0x48000000-0x5FFFFFFF,各功能部件的功能大體相同。

下圖是内部寄存器位址分布:

s3c2440存儲控制器詳解

SDRAM記憶體工作原理

SDRAM的内部是一個存儲陣列。陣列就如同表格一樣,将資料“填”進去。在資料讀寫時和表格的檢索原理一樣,先指定一個行(Row),再指定一個列(Column),我們就可以準确地找到所需要的單元格,這就是記憶體晶片尋址的基本原理,如圖所示。

s3c2440存儲控制器詳解

這個單元格(存儲陣列)就叫邏輯 Bank(Logical Bank,下文簡稱 L-Bank)。 由于技術、成本等原因,不可能隻做一個全容量的 L-Bank,而且最重要的是,由于SDRAM的工作原理限制,單一的 L-Ban k将會造成非常嚴重的尋址沖突,大幅降低記憶體效率。是以人們在 SDRAM内部分割成多個 L-Bank,目前基本都是 4個(這也是SDRAM規範中的最高L-Bank數量),由此可見,在進行尋址時就要先确定是哪個 L-Bank,然後在這個標明的 L-Bank中選擇相應的行與列進行尋址。是以對記憶體的通路,一次隻能是一個 L-Bank工作。

當對記憶體進行操作時,先要确定操作L-Bank,是以要對L-Bank進行選擇。在記憶體晶片的外部管腳上多出了兩個管腳BA0, BA1,用來片選4個L-Bank。如前所述, 32位的位址長度由于其存儲結構特點,分成了行位址和列位址。通過下面的記憶體結構圖可知,記憶體外接管腳位址線隻有13根位址線A0~A12,它最多隻能尋址8M記憶體空間,到底使用什麼機制來實作對64M記憶體空間進行尋址的呢?SDRAM的行位址線和列位址線是分時複用的,即位址要分兩次送出,先送出行位址(nSRAS行有效操作),再送出列位址(nSCAS列有效操作)。這樣,可以大幅度減少位址線的數目,提高器件的性能和制作工藝複雜度。但尋址過程也會是以而變得複雜。實際上,現在的SDRAM一般都以L-Bank為基本尋址對象的。由L-Bank位址線BAn控制L-Bank間的選擇,行位址線和列位址線貫穿連接配接所有的L-Bank,每個L-Bank的資料的寬度和整個存儲器的寬度相同,這樣,可以加快資料的存儲速度。同時,BAn還可以使未被選中的L-Bank工作于低功耗的模式下,進而降低器件的功耗。

這些都是記憶體的原理部分,其實作為工程師,能夠正确配置存儲管理器的相關的寄存器,就可以對記憶體進行初始化,可以使用了。

下面是配置存儲管理器的思路及方法:

以jz2440為例:

s3c2440存儲控制器詳解

1、确定BA0、BA1的接線

通過閱讀s3c2440手冊,可以看出CPU ADDR24和ADDR25

解釋一下名詞:

Bank Size: 外接記憶體容量大小(HY57561620是4Mbit*16bit*4Bank*2Chips/8=64MB)

Bus Width: 總線寬度 (兩片16位HY57561620,并聯成32位)

Base Component:單個晶片容量(bit)(256Mb)

Memory Configration:記憶體配置 ((4M*16*4banks)*2Chips )

使用A[25:24]兩根位址線作為Bank片選信号,正好兩根接線可以片選每個存儲單元的4個BANKS。

S3C2440提供的兩片16位晶片并聯連接配接示意圖,An是CPU位址總線,其中A2~A14為記憶體晶片尋址總線,之是以位址尋址總線從A2開始是因為記憶體位址都是按位元組對齊的,,A24,A25為L-Bank片選信号,Dn為CPU資料總線,其它為對應控制信号線。

S3C2440A為32位CPU,也就是說其資料總線和位址總線寬度都是32位(可以了解為32根線一端連接配接CPU内部,另外一端連接配接向記憶體控制器),那麼記憶體資料的輸入/輸出端也要保證是32位總線,jz2440上采用兩片16位寬總線記憶體晶片并聯構成32位總線。其中一個晶片連接配接到CPU資料總線的低16位,另外一個晶片連接配接到資料總線上的高16位,并聯成32位總線,是以兩個晶片的輸入/輸出總線連接配接到CPU總線上的不同管腳上。

一、SDRAM的讀操作

SDRAM進行讀操作時,先向位址線上送上要讀取資料的位址,通過前面的知識了解到,位址被分成3部分,行位址,列位址,L-Bank片選信号。片選(L-Bank的定址)操作和行有效操作可以同時進行。

在CS、L-Bank定址的同時,RAS(nSRAS行位址選通信号)也處于有效狀态。此時 An位址線則發送具體的行位址。A0~A12,共有13根位址線(可表示8192行),A0~A12的不同數值就确定了具體的行位址。由于行有效的同時也是相應 L-Bank有效,是以行有效也可稱為L-Bank有效。

行位址确定之後,就要對列位址進行尋址了。但是,位址線仍然是行位址所用的 A0~A12。沒錯,在SDRAM中,行位址與列位址線是複用的。列位址複用了A0~A8,共9根(可表示512列)。那麼,讀/寫的指令是怎麼發出的呢?其實沒有一個信号是發送讀或寫的明确指令的,而是通過晶片的可寫狀态的控制來達到讀/寫的目的。顯然WE信号(nWE)就是一個關鍵。WE無效時,當然就是讀取指令。有效時,就是寫指令。

SDRAM基本操作指令, 通過各種控制/位址信号的組合來完成(H代表高電平,L代表低電平,X表示高,低電平均沒有影響)。此表中,除了自重新整理指令外,所有指令都是預設CKE(SCKEl輸入時鐘頻率有效)有效。列尋址信号與讀寫指令是同時發出的。雖然位址線與行尋址共用,但CAS(nSCAS列位址選通信号)信号則可以區分開行與列尋址的不同,配合A0~A8,A9~A11來确定具體的列位址。

讀取指令與列位址一塊發出(當WE為低電平是即為寫指令)然而,在發送列讀寫指令時必須要與行有效指令有一個間隔,這個間隔被定義為 tRCD,即RAS to CAS Delay(RAS至 CAS延遲),這個很好了解,在位址線上送完行位址之後,要等到行位址穩定定位後再送出列位址,tRCD是SDRAM的一個重要時序參數,相關數值參看對應晶片硬體手冊。通常tRCD以時鐘周期(tCK,Clock Time)數為機關,比如筆者MINI2440所用記憶體晶片裡面寫到tRCD為20nst,如果将來記憶體工作在100MHz,那麼RCD至少要為2個時鐘周期, RCD=2。

SDRAM讀操作時序圖

s3c2440存儲控制器詳解

在標明列位址後,就已經确定了具體的存儲單元,剩下就是等待資料通過資料 I/O通道(DQ)輸出到記憶體資料總線上了。但是在列位址選通信号CAS 發出之後,仍要經過一定的時間才能有資料輸出,從CAS與讀取指令發出到第一筆資料輸出的這段時間,被定義為 CL(CAS Latency,CAS潛伏期)。由于CL隻在讀取時出現,是以CL又被稱為讀取潛伏期(RL,Read Latency)。CL的機關與tRCD一樣,也是時鐘周期數,具體耗時由時鐘頻率決定(筆者官方手冊CL=3)。不過,CAS并不是在經過CL周期之後才送達存儲單元。實際上CAS與RAS一樣是瞬間到達的。由于晶片體積的原因,存儲單元中的電容容量很小,是以信号要經過放大來保證其有效的識别性,這個放大/驅動工作由S-AMP負責。但它要有一個準備時間才能保證信号的發送強度,這段時間我們稱之為tAC(Access Time from CLK,時鐘觸發後的通路時間)。

 二、SDRAM預充電操作

原本邏輯狀态為1的電容在讀取操作後,會因放電而變為邏輯0。由于SDRAM的尋址具有獨占性,是以在進行完讀寫操作後,如果要對同一L-Bank的另一行進行尋址,就要将原先操作行關閉,重新發送行/列位址。在對原先操作行進行關閉時,DRAM為了在關閉目前行時保持資料,要對存儲體中原有的資訊進行重寫,這個充電重寫和關閉操作行過程叫做預充電,發送預充電信号時,意味着先執行存儲體充電,然後關閉目前L-Bank操作行。預充電中重寫的操作與重新整理操作(後面詳細介紹)一樣,隻不過預充電不是定期的,而隻是在讀操作以後執行的。

三、SDRAM突發操作

突發(Burst)是指在同一行中相鄰的存儲單元連續進行資料傳輸的方式,連續傳輸所涉及到存儲單元(列)數量就是突發長度(Burst Length,簡稱BL)。

在目前,由于記憶體控制器一次讀/寫P-Bank位寬的資料,也就是8個位元組,但是在現實中小于8個位元組的資料很少見,是以一般都要經過多個周期進行資料的傳輸,上文寫到的讀/寫操作,都是一次對一個存儲單元進行尋址,如果要連續讀/寫,還要對目前存儲單元的下一單元進行尋址,也就是要不斷的發送列位址與讀/寫指令(行位址不變,是以不用再對地尋址)。雖然由于讀/寫延遲相同可以讓資料傳輸在I/O端是連續的,但是它占用了大量的記憶體控制資源,在資料進行連續傳輸時無法輸入新的指令效率很低。為此,引入了突發傳輸機制,隻要指定起始列位址與突發長度,記憶體就會依次自動對後面相應長度資料的資料存儲單元進行讀/寫操作而不再需要控制器連續地提供列位址,這樣,除了第一筆資料的傳輸需要若幹個周期(主要是之間的延遲,一般的是tRCD + CL)外,其後每個資料隻需一個周期即可。

SDRAM寫操作

SDRAM的基本寫操作也需要控制線和位址線相配合地發出一系列指令來完成。先發出晶片有效指令,并鎖定相應的L-BANK位址(BA0、BA1給出)和行位址(A0~A12給出)。晶片有效指令發出後必須等待大于tRCD的時間後,發出寫指令資料,待寫入資料依次送到DQ(資料線)上。在最後一個資料寫入後,延遲tWR時間。發出預充電指令,關閉已經激活的頁。等待tRP時間後,可以展開下一次操作。寫操作可以有突發寫和非突發寫兩種。突發長度同讀操作。

寫操作時序如下圖:

s3c2440存儲控制器詳解

四、SDRAM的重新整理

SDRAM之是以成為DRAM就是因為它要不斷進行重新整理(Refresh)才能保留住資料,是以它是SDRAM最重要的操作。

重新整理操作與預充電中重寫的操作一樣,都是用S-AMP先讀再寫。但為什麼有預充電操作還要進行重新整理呢?因為預充電是對一個或所有 L-Bank中的工作行操作,并且是不定期的,而重新整理則是有固定的周期,依次對所有行進行操作,以保留那些很長時間沒經曆重寫的存儲體中的資料。但與所有L-Bank預充電不同的是,這裡的行是指所有L-Bank中位址相同的行,而預充電中各L-Bank中的工作行位址并不是一定是相同的。那麼要隔多長時間重複一次重新整理呢?目前公認的标準是,存儲體中電容的資料有效儲存期上限是64ms(毫秒,1/1000秒),也就是說每一行重新整理的循環周期是64ms。這樣重新整理時間間隔就是: 64m/行數s。我們在看記憶體規格時,經常會看到4096 Refresh Cycles/64ms或8192 Refresh Cycles/64ms的辨別,這裡的4096與8192就代表這個晶片中每個L-Bank的行數。重新整理指令一次對一行有效,重新整理間隔也是随總行數而變化,4096行時為 15.625μs(微秒,1/1000毫秒),8192行時就為 7.8125μs。重新整理操作分為兩種:Auto Refresh,簡稱AR與Self Refresh,簡稱SR。不論是何種重新整理方式,都不需要外部提供行位址資訊,因為這是一個内部的自動操作。對于 AR,SDRAM内部有一個行位址生成器(也稱重新整理計數器)用來自動的依次生成行位址。由于重新整理是針對一行中的所有存儲體進行,是以無需列尋址,或者說CAS在 RAS之前有效。是以,AR又稱CBR(CAS Before RAS,列提前于行定位)式重新整理。由于重新整理涉及到所有L-Bank,是以在重新整理過程中,所有 L-Bank都停止工作,而每次重新整理所占用的時間為9個時鐘周期(PC133标準),之後就可進入正常的工作狀态,也就是說在這9個時鐘期間内,所有工作指令隻能等待而無法執行。64ms之後則再次對同一行進行重新整理,如此周而複始進行循環重新整理。顯然,重新整理操作肯定會對SDRAM的性能造成影響,但這是沒辦法的事情,也是DRAM相對于 SRAM(靜态記憶體,無需重新整理仍能保留資料)取得成本優勢的同時所付出的代價。SR則主要用于休眠模式低功耗狀态下的資料儲存,這方面最著名的應用就是 STR(Suspend to RAM,休眠挂起于記憶體)。在發出AR指令時,将CKE置于無效狀态,就進入了SR模式,此時不再依靠系統時鐘工作,而是根據内部的時鐘進行重新整理操作。在SR期間除了CKE之外的所有外部信号都是無效的(無需外部提供重新整理指令),隻有重新使CKE有效才能退出自重新整理模式并進入正常操作狀态。

剩下的事情就是配置寄存器

(1)BWSCON寄存器(BUS WIDTH & WAIT CONTROL REGISTER)

s3c2440存儲控制器詳解

根據開發闆的存儲器配置和晶片型号,設定每個BANK焊接晶片的位寬和等待狀态,BWSCON,每4位對應一個BANK,這4位分别表示:

 STx:啟動/禁止SDRAM的資料掩碼引腳(UB/LB),SDRAM沒有高低位掩碼引腳,此位為0,SRAM連接配接有UB/LB管腳,設定為1

 注:UB/LB資料掩碼引腳用來控制晶片讀取/寫入的高位元組和低位元組(對比硬體手冊SDRAM和SRAM的接線圖)

 WSx:是否使用存儲器的WAIT信号,通常設為0

DWx:設定焊接存儲器晶片的位寬,筆者開發闆使用兩片容量為32M,位寬為16的SDRAM組成64M,32位存儲器,是以DW7,DW6位設定為0b10,其它BANK不用設定采用預設值即可。

BANK0對應的是系統引導BANK,這4位比較特殊,它的設定是由硬體跳線決定的,是以不用設定

BWSCON設定結果:0x22000000

2)BANKCON0~BANKCON5 (BANK CONTROL REGISTER)

s3c2440存儲控制器詳解

這6個寄存器用來設定對應BANK0~BANK5的通路時序,采用預設值0x700即可

(3)BANKCON6~BANKCON7 (BANK CONTROL REGISTER)

s3c2440存儲控制器詳解

由于記憶體都焊接在這兩個BANK上,是以記憶體驅動主要是對這兩個寄存器進行設定

MT:設定BANK6~BANK7的存儲器類型,

00=ROM or SRAM 01=保留

10=保留         11=SDRAM

記憶體為SDRAM,設定為0b11,對應的應該設定Trcd和SCAN位,其它位和SDRAM無關

Trcd:RAS to CAS Delay行位址選通到列位址選通延遲,這個參數請看後面的記憶體工作原理擴充部分解釋,筆者記憶體晶片為HY57V561620,由其晶片手冊可知其Trcd為最少 20ns,如果記憶體工作在100MHz,則該值至少要為2個時鐘周期,通常設定為3個時鐘周期,是以設定為0b01

SCAN:SDRAM Column Address Number SDRAM的列位址數,筆者記憶體晶片為HY57V561620,列位址數為9,設定為0b01

BANK6,BANK7設定結果為:0x18005

(4)REFRESH (REFRESH CONTROL REGISTER)

s3c2440存儲控制器詳解

重新整理頻率設定寄存器(REFRESH)

SDRAM的重新整理有效,重新整理頻率設定寄存器(重新整理)

REFEN:開啟/關閉重新整理功能,設定為1,開啟重新整理

TREFMD:SDRAM重新整理模式,0=CBR/AutoRefresh,  1=Self Refresh,設定為0,自動重新整理

Trp:行位址選通預充電時間,一般設定為0b00即可

Tsrc:單行重新整理時間,設定為0b11即可。

Refresh Counter:記憶體存儲單元重新整理數,它通過下面公式計算出:

Refresh Counter = 2^11 + 1 – SDRAM時鐘頻率(MHz)* SDRAM重新整理周期(uS)

SDRAM的重新整理周期,也就是記憶體存儲單元間隔需要多久進行一次重新整理,前面記憶體工作原理分析可知電容資料儲存上限為64ms,筆者使用記憶體晶片每個L-Bank共有8192行,是以每次重新整理最大間隔為:64ms/8192 = 7.8125uS,如果記憶體工作在外部晶振頻率12MHz下,Refresh Counter = 1955,如果記憶體工作在100MHz下,那麼Refresh Counter = 1269(取大整數)

 REFRESH寄存器設定為:

0x8e0000 + 1269 = 0x008e04f5(HCLK = 100MHz)

0x8e0000 + 1955 = 0x008e07a3(HCLK = 12MHz)

(5)BANKSIZE寄存器(BANKSIZE REGISTER)

s3c2440存儲控制器詳解

 BANKSIZE寄存器(BANKSIZE)

 設定記憶體的突發傳輸模式,省電模式和記憶體容量。

BURST_EN:是否開啟突發模式, 0 = ARM核心禁止突發傳輸 1 = 開啟突發傳輸,設定為1,開啟突發傳輸

SCKE_EN:是否使用SCKE信号作為省電模式控制信号, 0 = 不使用SCKE信号作為省電模式控制信号 1 = 使用SCKE信号作為省電模式控制信号,通常設定為1

SCLK_EN: 設定向存儲器輸入工作頻率,0 = 一直輸入SCLK頻率,即使沒有記憶體操作也會輸入, 1 = 僅當進行記憶體資料操作時才輸入SCLK頻率,通常設定為1

BK76MAP:設定Bank6/7的記憶體容量,筆者使用開發闆記憶體為兩片32M記憶體晶片并聯成64M,它們全部都外接到Bank6上,是以選擇0b001

BANKSIZE寄存器設定為:0xb1

(6)SDRAM模式設定寄存器MRSRx (SDRAM MODE REGISTER SET REGISTER)

s3c2440存儲控制器詳解

SDRAM模式設定寄存器(MRSRx)

該寄存器用于設定CAS潛伏周期,可以手動設定的位隻有CL[6:4]位,通過前面記憶體工作原理可知,筆者使用開發闆CL=3,即0b011

MRSR6,MRSR7設定為:0x00000030

記憶體實驗:

設定該工程加載時運作時位址為0x30000000

ctr.S

.equ    MEM_CTL_BASE,   0x48000000  
.equ    SDRAM_BASE,     0x30000000  
  
.text  
.global _start  
_start:  
        bl close_watchdog  
        bl memsetup  
        bl copy_steppingstone_to_sdram  
        ldr pc, =on_sdram  
on_sdram:  
        ldr sp,=0x34000000  
        bl main  
continue:  
        b continue  
  
close_watchdog:  
        mov r1,#0x53000000  
        mov r2,#0x0  
        str r2,[r1]  
        mov pc,lr  
          
copy_steppingstone_to_sdram:  
        mov r1,#0  
        ldr r2,=SDRAM_BASE  
        mov r3,#4*1024  
1:  
        ldr r4,[r1],#4  
        str r4,[r2],#4  
        cmp r1,r3  
        bne 1b  
        mov pc,lr  
  
memsetup:  
    mov r1,#MEM_CTL_BASE  
    adrl r2,mem_cfg_val  
    add r3,r1,#52  
1:  
    ldr r4,[r2],#4  
    str r4,[r1],#4  
    cmp r1,r3  
    bne 1b  
    mov pc,lr  
      
.align 4  
mem_cfg_val:  
    .long   0x22011110      @ BWSCON  
    .long   0x00000700      @ BANKCON0  
    .long   0x00000700      @ BANKCON1  
    .long   0x00000700      @ BANKCON2  
    .long   0x00000700      @ BANKCON3    
    .long   0x00000700      @ BANKCON4  
    .long   0x00000700      @ BANKCON5  
    .long   0x00018005      @ BANKCON6  
    .long   0x00018005      @ BANKCON7  
    .long   0x008C07A3      @ REFRESH  
    .long   0x000000B1      @ BANKSIZE  
    .long   0x00000030      @ MRSRB6  
    .long   0x00000030      @ MRSRB7        

main.c

#define GPFCON  (*(volatile unsigned long *)0x56000050)  
#define GPFDAT  (*(volatile unsigned long *)0x56000054)  
#define GPF4_out ( 1 << 4*2 )  
#define GPF5_out ( 1 << 5*2 )  
#define GPF6_out ( 1 << 6*2 )  
void   
delay(volatile unsigned long dly)  
{  
    for(;dly > 0;dly--);  
}  
int  
main()  
{  
    unsigned i = 1;  
      
    GPFCON = GPF4_out | GPF5_out | GPF6_out;  
    while(1)  
    {  
        GPFDAT = ( ~( i << 4 ) );  
        i *=2;  
        if( i == 8)  
        {  
            i = 1;  
        }  
        delay(30000);  
  
          
    }  
      
      
    return 0;  
}        

Makefile

CFLAGS := -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -ffreestanding  
led_on.bin:ctr.S main.c  
    arm-linux-gcc $(CFLAGS) -c -o ctr.o ctr.S  
    arm-linux-gcc $(CFLAGS) -c -o main.o main.c  
    arm-linux-ld -Ttext 0x30000000 ctr.o main.o -o led_on.elf  
    arm-linux-objcopy -O binary -S led_on.elf led_on.bin  
    arm-linux-objdump -D -m arm led_on.elf>led_on.dis  
clean:  
    rm -f led_on.bin led_on.elf *.o led_on.dis        

轉載于:https://www.cnblogs.com/Ye-Jason/p/7353783.html