1.head.s
@******************************************************************************
@ File:head.S
@ 功能:設定SDRAM,将程式複制到SDRAM,然後跳到SDRAM繼續執行
@******************************************************************************
.extern main
.text
.global _start
_start:
Reset:
ldr sp, =4096 @ 設定棧指針,以下都是C函數,調用前需要設好棧
bl disable_watch_dog @ 關閉WATCHDOG,否則CPU會不斷重新開機
// bl是位置無關碼,相當于:PCnew = PC + 偏移
// PCnew = (4+8) + 0x28 = 0x34
ldr pc, =disable_watch_dog
bl clock_init @ 設定MPLL,改變FCLK、HCLK、PCLK
bl memsetup @ 設定存儲控制器以使用SDRAM
bl copy_steppingstone_to_sdram @ 複制代碼到SDRAM中
ldr pc, =on_sdram @ 跳到SDRAM中繼續執行
on_sdram:
ldr sp, =0x34000000 @ 設定棧指針
ldr lr, =halt_loop @ 設定傳回位址
ldr pc, =main @ 調用main函數
halt_loop:
b halt_loop
2.init.c
/*
* init.c: 進行一些初始化
*/
#include "s3c24xx.h"
void disable_watch_dog(void);
void clock_init(void);
void memsetup(void);
void copy_steppingstone_to_sdram(void);
/*
* 關閉WATCHDOG,否則CPU會不斷重新開機
*/
void disable_watch_dog(void)
{
WTCON = 0; // 關閉WATCHDOG很簡單,往這個寄存器寫0即可
}
#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
/*
* 對于MPLLCON寄存器,[19:12]為MDIV,[9:4]為PDIV,[1:0]為SDIV
* 有如下計算公式:
* S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s)
* S3C2440: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
* 其中: m = MDIV + 8, p = PDIV + 2, s = SDIV
* 對于本開發闆,Fin = 12MHz
* 設定CLKDIVN,令分頻比為:FCLK:HCLK:PCLK=1:2:4,
* FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
*/
void clock_init(void)
{
// LOCKTIME = 0x00ffffff; // 使用預設值即可
CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
/* 如果HDIVN非0,CPU的總線模式應該從“fast bus mode”變為“asynchronous bus mode” */
__asm__(
"mrc p15, 0, r1, c1, c0, 0\n" /* 讀出控制寄存器 */
"orr r1, r1, #0xc0000000\n" /* 設定為“asynchronous bus mode” */
"mcr p15, 0, r1, c1, c0, 0\n" /* 寫入控制寄存器 */
);
/* 判斷是S3C2410還是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
MPLLCON = S3C2410_MPLL_200MHZ; /* 現在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
}
else
{
MPLLCON = S3C2440_MPLL_200MHZ; /* 現在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
}
}
/*
* 設定存儲控制器以使用SDRAM
*/
void memsetup(void)
{
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
/* 這個函數之是以這樣指派,而不是像前面的實驗(比如mmu實驗)那樣将配置值
* 寫在數組中,是因為要生成”位置無關的代碼”,使得這個函數可以在被複制到
* SDRAM之前就可以在steppingstone中運作
*/
/* 存儲控制器13個寄存器的值 */
p[0] = 0x22011110; //BWSCON
p[1] = 0x00000700; //BANKCON0
p[2] = 0x00000700; //BANKCON1
p[3] = 0x00000700; //BANKCON2
p[4] = 0x00000700; //BANKCON3
p[5] = 0x00000700; //BANKCON4
p[6] = 0x00000700; //BANKCON5
p[7] = 0x00018005; //BANKCON6
p[8] = 0x00018005; //BANKCON7
/* REFRESH,
* HCLK=12MHz: 0x008C07A3,
* HCLK=100MHz: 0x008C04F4
*/
p[9] = 0x008C04F4;
p[10] = 0x000000B1; //BANKSIZE
p[11] = 0x00000030; //MRSRB6
p[12] = 0x00000030; //MRSRB7
}
void copy_steppingstone_to_sdram(void)
{
unsigned int *pdwSrc = (unsigned int *)0;
unsigned int *pdwDest = (unsigned int *)0x30000000;
while (pdwSrc < (unsigned int *)4096)
{
*pdwDest = *pdwSrc;
pdwDest++;
pdwSrc++;
}
}
3.uart.c
#include "s3c24xx.h"
#include "serial.h"
#define TXD0READY (1<<2)
#define RXD0READY (1)
#define PCLK 50000000 // init.c中的clock_init函數設定PCLK為50MHz
#define UART_CLK PCLK // UART0的時鐘源設為PCLK
#define UART_BAUD_RATE 115200 // 波特率
#define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1)
/*
* 初始化UART0
* 115200,8N1,無流控
*/
void uart0_init(void)
{
GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0
GPHUP = 0x0c; // GPH2,GPH3内部上拉
ULCON0 = 0x03; // 8N1(8個資料位,無較驗,1個停止位)
UCON0 = 0x05; // 查詢方式,UART時鐘源為PCLK
UFCON0 = 0x00; // 不使用FIFO
UMCON0 = 0x00; // 不使用流控
UBRDIV0 = UART_BRD; // 波特率為115200
}
/*
* 發送一個字元
*/
void putc(unsigned char c)
{
/* 等待,直到發送緩沖區中的資料已經全部發送出去 */
while (!(UTRSTAT0 & TXD0READY));
/* 向UTXH0寄存器中寫入資料,UART即自動将它發送出去 */
UTXH0 = c;
}
/*
* 接收字元
*/
unsigned char getc(void)
{
/* 等待,直到接收緩沖區中的有資料 */
while (!(UTRSTAT0 & RXD0READY));
/* 直接讀取URXH0寄存器,即可獲得接收到的資料 */
return URXH0;
}
/*
* 判斷一個字元是否數字
*/
int isDigit(unsigned char c)
{
if (c >= '0' && c <= '9')
return 1;
else
return 0;
}
/*
* 判斷一個字元是否英文字母
*/
int isLetter(unsigned char c)
{
if (c >= 'a' && c <= 'z')
return 1;
else if (c >= 'A' && c <= 'Z')
return 1;
else
return 0;
}
4.uart.lds
SECTIONS {
. = 0x30000000;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
5.main.c
#include "serial.h"
int main()
{
unsigned char c;
uart0_init(); // 波特率115200,8N1(8個資料位,無校驗位,1個停止位)
while(1)
{
// 從序列槽接收資料後,判斷其是否數字或子母,若是則加1後輸出
c = getc();
if (isDigit(c) || isLetter(c))
putc(c+1);
}
return 0;
}
6.Makefile
objs := head.o init.o serial.o main.o
uart.bin: $(objs)
arm-linux-ld -Tuart.lds -o uart_elf $^
arm-linux-objcopy -O binary -S uart_elf [email protected]
arm-linux-objdump -D -m arm uart_elf > uart.dis
%.o:%.c
arm-linux-gcc -Wall -O2 -c -o [email protected] $<
%.o:%.S
arm-linux-gcc -Wall -O2 -c -o [email protected] $<
clean:
rm -f uart.bin uart_elf uart.dis *.o