嵌入式入門4(內存控制器和SDRAM)

通常ARM芯片,都包含如下幾類接口:html

一、GPIO、門電路前端

這類接口經過操做某些寄存器,來設置對應引腳爲輸入、輸出引腳,以及其引腳的電平。linux

二、協議類接口編程

CPU將數據寫入某些地址和寄存器,對應引腳就會發出特定的波形。如:UART、I2C、I2S、SPI等。markdown

三、內存接口app

CPU經過地址能夠直接訪問這類設備,由於它們都參與CPU的統一編址。如:Nor、SDRAM、DM9000(網卡芯片)等,dom

注意:Nand Flash不參與CPU的統一編址,由於它是直接鏈接到Nand Flash控制器上的。異步

未命名文件.png

1、內存控制器

S3C2440A芯片內部集成了內存控制器,幾乎全部的外設和寄存器都與它相連。CPU只負責發出命令,其他都交給了內存管理器處理。那麼內存管理器是如何來管理這些外設的呢?測試

咱們能夠查看s3c2440的地址空間分佈ui

image.png

  • 一、地址空間被分爲8個bank(bank0-bank7),每一個bank對應128M地址空間。
  • 二、每一個bank擁有對應的片選引腳(nGCS0-nGCS7),當引腳爲低電平時表示該bank被選通。
  • 三、內存控制器根據不一樣的地址範圍,發出不一樣的片選信號,只有被選中的芯片纔會工做,沒被選中的芯片就像不存在同樣。

一個bank對應128M地址空間,須要27根地址線來表示。

128 M B = 128 1 M B = 2 7 2 20 = 2 27 128MB = 128 * 1MB = 2^7 * 2^{20} = 2^{27}

那麼8個bank,意味着外接內存類芯片可訪問地址範圍最多爲1GB(128M*8)。

咱們看到地址空間是0-0x40000000,總共是1G。而s3c2440的cpu是32位的,它理論上可使用的地址能夠達到4G,除了用於鏈接外設的1G地址空間以外,還有一部分是cpu內部寄存器的地址(0x48000000-0x5fffffff),其他的地址沒有使用。

2、外接芯片的地址線接法

外接芯片的位寬不一樣,則地址線的接法也會不一樣。能夠參考S3C2440A的第5章 Memory Controller中的ROM Memory Interface Examples。例如:

image.png

ROM/bit CPU發出地址 ROM收到地址 ROM返回的數據 內存控制器返回給CPU的數據
8bit(ROM) 000011 000011 編號3的存儲單元中的8數據 編號3的存儲單元中的8bit數據
16bit(ROM) 000011 000001 編號1的存儲單元中的16數據 根據A0=1,挑出低8bit數據
32bit(ROM) 000011 000000 編號0的存儲單元中的32數據 根據A0A1=11,挑出最低8bit數據

3、時序圖分析

查看s3c2440的PROGRAMMABLE ACCESS CYCLE

image.png

時序圖流程以下:

  • 一、CPU先發出地址信號。
  • 二、通過Tacs時間後再發出片選信號。
  • 三、通過Tcos時間後發出讀信號。
  • 四、發出讀信號後,數據纔有效。
  • 五、讀出數據後,再移除釋放讀信號、片選信號、地址信號。

由咱們的JZ2440電路圖可知,Nor Flash爲MX29LV160DBTI-70G,而後查看其芯片手冊。其交流特性以下:

image.png

image.png

參數 含義
Taa 發出地址數據後多久數據纔有效
Tce 發出片選信號後多久數據纔有效
Toe 發出讀信號後多久數據纔有效

4、開始編程

爲了簡單起見,咱們設置片選信號、讀信號、地址信號同時發出,而後保持70ns,再讀取數據,這樣就知足Nor Flash的時序要求了。

4.一、設置位寬

首先,設置BWSCON[2:1],用於設置bank0的位寬。

image.png

而DW0是隻讀的,它是經過OM[1:0]引腳來決定的

image.png

查看硬件電路圖:

image.png

image.png

發現OM[1]直接接地,而OM[0]的電平,由Nor boot switch決定。咱們經過開關,決定了S3C2440A的啓動方式:32bit Nor FlashNand-boot

4.二、配置BANKCON0

咱們Nor Flash接到Bank0,因此須要配置BANKCON0。

image.png

設備上電時,採用晶振作爲時鐘源,12MHz,Tacc=0x111,14個週期。

14個週期=14/12MHz秒 = 14/12_000_000秒 = 14000/12納秒 = 1166.6納秒,遠大於Nor Flash要求的70ns。因此當咱們上電時,即便不設置時鐘,設備也能正常運行。

而咱們如今HCLK=100MHz:1個週期=10納秒,Tacc只需設置爲0x101,即8個時鐘週期,就能知足Nor Flash大於70納秒的時序要求。

4.三、全部源代碼

init.c

#include "s3c2440_soc.h"

void bank0_tacc_set(int val) {
    BANKCON0 = val << 8;
}
複製代碼

init.h

#ifndef _INIT_H
#define _INIT_H

void bank0_tacc_set(int val);

#endif
複製代碼

led.c

#include "s3c2440_soc.h"

void delay(volatile int d) {
    while (d--);
}

int led_test(void) {
    /* 設置GPFCON讓GPF4/5/6配置爲輸出引腳 */
    GPFCON &= ~((3<<8) | (3<<10) | (3<<12));
    GPFCON |=  ((1<<8) | (1<<10) | (1<<12));

    /* 循環點亮 */
    int i = 4;
    while (1) {
        for(i=4; i<=6; i++) {
            //對數據寄存器4~6位取反
            GPFDAT ^= (1<<i);
            delay(30000);
        }
    }

    return 0;
}
複製代碼

main.c

#include "s3c2440_soc.h"
#include "uart.h"
#include "init.h"

int main(void) {
    unsigned char c;

    uart0_init();
    puts("Enter the Tacc val: \n\r");

    while(1)
    {
        c = getchar();
        putchar(c);
        if (c >= '0' && c <= '7')
        {
            bank0_tacc_set(c - '0');
            led_test();
        }
        else
        {
            puts("Error, val should between 0~7\n\r");
            puts("Enter the Tacc val: \n\r");
        }
    }
    return 0;
}
複製代碼

start.S

.text
.global _start

_start:

    /* 關閉看門狗 */
    ldr r0, =0x53000000
    ldr r1, =0
    str r1, [r0]

    /* 設置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
    /* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
    ldr r0, =0x4C000000
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */
    ldr r0, =0x4C000014
    ldr r1, =0x5
    str r1, [r0]

    /* 設置CPU工做於異步模式 */
    mrc p15,0,r0,c1,c0,0
    orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA
    mcr p15,0,r0,c1,c0,0

    /* 設置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 
     *  m = MDIV+8 = 92+8=100
     *  p = PDIV+2 = 1+2 = 3
     *  s = SDIV = 1
     *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
     */
    ldr r0, =0x4C000004
    ldr r1, =(92<<12)|(1<<4)|(1<<0)
    str r1, [r0]
    /* 一旦設置PLL, 就會鎖定lock time直到PLL輸出穩定
     * 而後CPU工做於新的頻率FCLK
     */

    /* nor啓動 */
    ldr sp, =0x40000000+4096 

    bl main

halt:
    b halt
複製代碼

uart.c

#include "s3c2440_soc.h"


/* 115200,8n1 */
void uart0_init() {
    /* 設置引腳用於串口 */
    /* GPH2,3用於TxD0, RxD0 */
    GPHCON &= ~((3<<4) | (3<<6));
    GPHCON |=  ((2<<4) | (2<<6));

    GPHUP &= ~((1<<2) | (1<<3));  /* 使能內部上拉 */


    /* 設置波特率 */
    /* UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1 * UART clock = 50M * UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1 = 26 */
    UCON0 = 0x00000005; /* PCLK,中斷/查詢模式 */
    UBRDIV0 = 26;

    /* 設置數據格式 */
    ULCON0 = 0x00000003; /* 8n1: 8個數據位, 無較驗位, 1箇中止位 */
}

int putchar(int c) {
    /* UTRSTAT0 */
    while (!(UTRSTAT0 & (1<<2)));
    /* UTXH0 */
    UTXH0 = (unsigned char)c;
}

int getchar(void) {
    while (!(UTRSTAT0 & (1<<0)));
    return URXH0;
}

int puts(const char *s) {
    while (*s)
    {
        putchar(*s);
        s++;
    }
}
複製代碼

uart.h

#ifndef _UART_H
#define _UART_H

void uart0_init();
int putchar(int c);
int getchar(void);
int puts(const char *s);

#endif
複製代碼

Markfile

all:
	arm-linux-gcc -c -o led.o led.c
	arm-linux-gcc -c -o uart.o uart.c
	arm-linux-gcc -c -o init.o init.c
	arm-linux-gcc -c -o main.o main.c
	arm-linux-gcc -c -o start.o start.S
	arm-linux-ld -Ttext 0 start.o led.o uart.o init.o main.o -o nor.elf
	arm-linux-objcopy -O binary -S nor.elf nor.bin
	arm-linux-objdump -D nor.elf > nor.dis
clean:
	rm *.bin *.o *.elf *.dis
複製代碼

編譯燒寫後,串口輸入0~7,其中0~4,因爲Tacc小於70ns,因此燈不會閃爍,只有5~7纔會閃爍。

5、SDRAM

SDRAM:Synchronous Dynamic Random Access Memory,同步動態隨機存儲器。同步是指其時鐘頻率和CPU前端總線的系統時鐘相同,而且內部命令的發送與數據的傳輸都以它爲基準;動態是指存儲陣列須要不斷的刷新來保證數據不丟失;隨機是指數據不是線性依次存儲,而是自由指定地址進行數據的讀寫。

通常SDRAM的存儲結構以下:

image.png

它由多個表格(Bank)組成,並經過行地址和列地址來進行訪問,每一個小格子表示一個存儲單元,單元的大小等於SDRAM的位寬。

  • 一、CPU先發出片選信號,選中整個芯片。
  • 二、發出Bank地址,選擇哪一個表格(Bank)。
  • 三、而後依次發出行地址和列地址,才能定位到具體的存儲單元。

5.一、JZ2440的SDRAM接法

查看JZ2440的SDRAM電路圖:

image.png

能夠發現:

  • 一、JZ2440外接2片SDRAM,每片提供16位的數據,容量爲32M,共計64M,32位。
  • 二、SDRAM接在JZ2440的片選6引腳,也就是說SDRMAM在第六個Bank地址空間中。
  • 三、BA[0:1]分別接在ADDR[25:24]上,用於選中SDRAM裏的哪一個Bank。

JZ2440的SDRAM芯片型號是K4S561632N-LC75,查看其芯片手冊(K4S561632E):

image.png

發現如下有用信息:

  • 一、每片SDRAM組織形式:4M * 16bit * 4Bank = 32M
  • 二、行地址13條,列地址9條。

參考SDRAM BANK ADDRESS PIN CONNECTION EXAMPLE,能夠知道Bank Address爲A[25:24],對比JZ2440的SDRAM電路圖,確實是BA[0:1]分別接在ADDR[25:24]上。

image.png

如今能夠配置SDRAM,來測試SDRAM的讀寫操做。

5.二、設置BANK6爲SDRAM

首先咱們須要設置內存控制器,讓Bank6設置爲SDRAM,這樣內存控制器在發送地址時,纔會將其拆分爲Bank地址、行地址和列地址。

image.png

BANKCON6[16:15]決定Bank6接入的是哪一種類型的內存芯片,這裏咱們設置爲SDRAM,即BANKCON6[16:15]=0x11

image.png

因爲外接的SDRAM列地址有9條,因此BANKCON6[1:0]=0x01

Trcd,表示內存控制器發出行地址多久後,才能發出列地址。

查看SDRAM芯片手冊的交流特性圖:

image.png

知道Trcd最小取20ns,用於HLCK=100MHZ,即一個週期須要10ns,使用Trcd至少須要2個週期,即BANKCON6[3:2]=0x00

BANKCON6 = 0x00018001
複製代碼

5.三、設置BANK6位寬

image.png

  • 設置BWSCON[25:24]爲10,由於JZ2440是由2個16爲SDRAM芯片組成的32位SDRAM。
  • BWSCON[26],是否使用WAIT信號,它是內存芯片向CPU發出來的。假設內存芯片很是慢,當CPU發出讀寫命令後,內存控制器開始驅動引腳,在這些時間裏,內存芯片還沒準備好數據,此時它能夠向CPU發出nWAIT信號,請求CPU再寬限一點時間。
  • BWSCON[27],設置SDRAM是否使用UB/LB引腳,UB/LB分別是存儲器高8位,低8位的數據線使能信號。

nBE:Byte Enable,表示讀或者寫的時候,是否能夠經過操做這個引腳,來操做這個Byte。
nWBE:Write Byte Enable,表示寫某個字節的時候,是否真正的寫進去。

因爲咱們內存是32位(4字節)的,若是咱們只想修改某個字節,此時就須要經過nWEB引腳,來決定某個字節會被寫入。而讀的時候,咱們老是讀出4字節數據,而後內存控制器從中挑選出咱們所感興趣的數據。

BWSCON = 0x02000000
複製代碼

5.四、設置SDRAM刷新寄存器

SDRAM不像靜態SRAM那麼可靠,在使用過程當中,必須不斷刷新它,否則數據會丟失。

image.png

  • 設置REFEN = 1,表示開啓SDRAM刷新。
  • 設置TREFMD = 0,設置爲自動刷新模式。
  • Refresh Counter,刷新週期,查看SDRAM芯片手冊,自動其刷新爲64ms refresh period (8K Cycle),即刷新週期爲:

64 1000 u s 8 1024 = 7.8125 u s \frac{64*1000us}{8*1024} = 7.8125us

而咱們HCLK=100MHz,恰好與實例一致,因此Refresh Count = 1269 = 0x4F5

  • Trp,行地址的充電時間。由SDRAM芯片手冊的交流特性圖可知,Trp最小爲20ns,因此REFERSH[21:20]=0x00
  • Tsrc,Trc = Tsrc + Trp。Trc爲65ns,因此Tsrc=65-20=45ns。設置去0x01,即5個週期。

image.png

REFERSH = 0x008404f5
複製代碼

5.五、設置Bank寄存器

image.png

  • 設置BANKSIZE[2:0]=001,由於SDRAM是由兩個16位的32M芯片組成的32位64M芯片。
  • 設置BANKSIZE[7]=1,容許突發訪問,即同時能夠連續一次訪問多個字節。
  • 設置BANKSIZE[5]=1,可使用SCKE來使能休眠模式。
  • 設置BANKSIZE[4]=1,推薦值。
BANKSIZE= 0x000000b1
複製代碼

5.六、設置SDRAM模式寄存器

image.png

除了CL,其他都是固定的。

CAS latency:內存控制器讀SDRAM時,先發出Bank地址,再發出行地址,最後發出列地址。還要等一會,數據纔好。

SDRAM芯片手冊在FEATURES中告訴咱們:CAS latency(2 & 3)。當咱們設置CL後,CPU會發送給SDRAM,SDRAM會將其保存在自身的寄存器中,當SDRAM收到列地址後,等待一段時間後,纔會返回數據。

MRSRB6 = 0x00000020
複製代碼

5.七、全部代碼

init.h

#ifndef _INIT_H
#define _INIT_H

void sdram_init();
int sdram_test();

#endif
複製代碼

init.c

#include "s3c2440_soc.h"

void sdram_init() {
    BWSCON = 0x02000000;
    BANKCON6 = 0x00018001;
    REFRESH = 0x008404f5;
    BANKSIZE = 0x000000b1;
    MRSRB6 = 0x00000020;
}

int sdram_test() {
    volatile unsigned char* p = (volatile unsigned char*)0x30000000;
    int i;

    for(i=0; i<1000; i++){
        p[i] = 'A';
    }

    for(i=0; i<1000; i++){
        if(p[i] != 'A'){
            return -1;
        }
    }
    return 0;
}
複製代碼

main.c

#include "s3c2440_soc.h"
#include "uart.h"
#include "init.h"

int main(void) {
    uart0_init();
    sdram_init();
    if(sdram_test()==0)
    {
        puts("ok\n\r");
        led_test();
    } else {
        puts("error\n\r");
    }
    return 0;
}
複製代碼
相關文章
相關標籤/搜索