ARM9的系統(tǒng)時(shí)鐘和串口(非流控 + 非FIFO + 查詢(xún)方式)
實(shí)驗(yàn)的目的:
設(shè)置系統(tǒng)時(shí)鐘,并在串口上輸入一個(gè)字符,單板接收后將它的ASCII值加1后,從串口輸出。
實(shí)驗(yàn)的源程序:
/*************************************************************************
s3c24xx.h
*************************************************************************/
/* WOTCH DOG register */
#define WTCON (*(volatile unsigned long *)0x53000000)
/* SDRAM regisers */
#define MEM_CTL_BASE 0x48000000
#define SDRAM_BASE 0x30000000
/* NAND Flash registers */
#define NFCONF (*(volatile unsigned int *)0x4e000000)
#define NFCMD (*(volatile unsigned char *)0x4e000004)
#define NFADDR (*(volatile unsigned char *)0x4e000008)
#define NFDATA (*(volatile unsigned char *)0x4e00000c)
#define NFSTAT (*(volatile unsigned char *)0x4e000010)
/*GPIO registers*/
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPFUP (*(volatile unsigned long *)0x56000058)
#define GPGCON (*(volatile unsigned long *)0x56000060)
#define GPGDAT (*(volatile unsigned long *)0x56000064)
#define GPGUP (*(volatile unsigned long *)0x56000068)
#define GPHCON (*(volatile unsigned long *)0x56000070)
#define GPHDAT (*(volatile unsigned long *)0x56000074)
#define GPHUP (*(volatile unsigned long *)0x56000078)
/*UART registers*/
#define ULCON0 (*(volatile unsigned long *)0x50000000)
#define UCON0 (*(volatile unsigned long *)0x50000004)
#define UFCON0 (*(volatile unsigned long *)0x50000008)
#define UMCON0 (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
#define UTXH0 (*(volatile unsigned char *)0x50000020)
#define URXH0 (*(volatile unsigned char *)0x50000024)
#define UBRDIV0 (*(volatile unsigned long *)0x50000028)
/*interrupt registes*/
#define SRCPND (*(volatile unsigned long *)0x4A000000)
#define INTMOD (*(volatile unsigned long *)0x4A000004)
#define INTMSK (*(volatile unsigned long *)0x4A000008)
#define PRIORITY (*(volatile unsigned long *)0x4A00000c)
#define INTPND (*(volatile unsigned long *)0x4A000010)
#define INTOFFSET (*(volatile unsigned long *)0x4A000014)
#define SUBSRCPND (*(volatile unsigned long *)0x4A000018)
#define INTSUBMSK (*(volatile unsigned long *)0x4A00001c)
/*external interrupt registers*/
#define EINTMASK (*(volatile unsigned long *)0x560000a4)
#define EINTPEND (*(volatile unsigned long *)0x560000a8)
/*clock registers*/
#define LOCKTIME (*(volatile unsigned long *)0x4c000000)
#define MPLLCON (*(volatile unsigned long *)0x4c000004)
#define UPLLCON (*(volatile unsigned long *)0x4c000008)
#define CLKCON (*(volatile unsigned long *)0x4c00000c)
#define CLKSLOW (*(volatile unsigned long *)0x4c000010)
#define CLKDIVN (*(volatile unsigned long *)0x4c000014)
/*PWM & Timer registers*/
#define TCFG0 (*(volatile unsigned long *)0x51000000)
#define TCFG1 (*(volatile unsigned long *)0x51000004)
#define TCON (*(volatile unsigned long *)0x51000008)
#define TCNTB0 (*(volatile unsigned long *)0x5100000c)
#define TCMPB0 (*(volatile unsigned long *)0x51000010)
#define TCNTO0 (*(volatile unsigned long *)0x51000014)
#define GSTATUS1 (*(volatile unsigned long *)0x560000B0)
/********************************************************************************
serial.c
********************************************************************************/
#include "s3c24xx.h"
#include "serial.h"
#define TXD0READY (1<<2)
#define RXD0READY (1)
#define PCLK 50000000 // init.c中的clock_init函數(shù)設(shè)置PCLK為50MHz
#define UART_CLK PCLK // UART0的時(shí)鐘源設(shè)為PCLK
#define UART_BAUD_RATE 115200 // 波特率
#define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1)
/*
* 初始化UART0
* 115200,8N1,無(wú)流控
*/
void uart0_init(void)
{
GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0
GPHUP = 0x0c; // GPH2,GPH3內(nèi)部上拉
ULCON0 = 0x03; // 8N1(8個(gè)數(shù)據(jù)位,無(wú)較驗(yàn),1個(gè)停止位)
UCON0 = 0x05; // 查詢(xún)方式,UART時(shí)鐘源為PCLK
UFCON0 = 0x00; // 不使用FIFO
UMCON0 = 0x00; // 不使用流控
UBRDIV0 = UART_BRD; // 波特率為115200
}
/*
* 發(fā)送一個(gè)字符
*/
void putc(unsigned char c)
{
/* 等待,直到發(fā)送緩沖區(qū)中的數(shù)據(jù)已經(jīng)全部發(fā)送出去 */
while (!(UTRSTAT0 & TXD0READY));
/* 向UTXH0寄存器中寫(xiě)入數(shù)據(jù),UART即自動(dòng)將它發(fā)送出去 */
UTXH0 = c;
}
/*
* 接收字符
*/
unsigned char getc(void)
{
/* 等待,直到接收緩沖區(qū)中的有數(shù)據(jù) */
while (!(UTRSTAT0 & RXD0READY));
/* 直接讀取URXH0寄存器,即可獲得接收到的數(shù)據(jù) */
return URXH0;
}
/*
* 判斷一個(gè)字符是否數(shù)字
*/
int isDigit(unsigned char c)
{
if (c >= '0' && c <= '9')
return 1;
else
return 0;
}
/*
* 判斷一個(gè)字符是否英文字母
*/
int isLetter(unsigned char c)
{
if (c >= 'a' && c <= 'z')
return 1;
else if (c >= 'A' && c <= 'Z')
return 1;
else
return 0;
}
/************************************************************************************
serial.h
************************************************************************************/
void uart0_init(void);
void putc(unsigned char c);
unsigned char getc(void);
int isDigit(unsigned char c);
int isLetter(unsigned char c);
/***********************************************************************************
init.c
***********************************************************************************/
/*
* init.c: 進(jìn)行一些初始化
*/
#include "s3c24xx.h"
void disable_watch_dog(void);
void clock_init(void);
void memsetup(void);
void copy_steppingstone_to_sdram(void);
/*
* 關(guān)閉WATCHDOG,否則CPU會(huì)不斷重啟
*/
void disable_watch_dog(void)
{
WTCON = 0; // 關(guān)閉WATCHDOG很簡(jiǎn)單,往這個(gè)寄存器寫(xiě)0即可
}
#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
/*
* 對(duì)于MPLLCON寄存器,[19:12]為MDIV,[9:4]為PDIV,[1:0]為SDIV
* 有如下計(jì)算公式:
* 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
* 對(duì)于本開(kāi)發(fā)板,F(xiàn)in = 12MHz
* 設(shè)置CLKDIVN,令分頻比為:FCLK:HCLK:PCLK=1:2:4,
* FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
*/
void clock_init(void)
{
// LOCKTIME = 0x00ffffff; // 使用默認(rèn)值即可
CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
/* 如果HDIVN非0,CPU的總線模式應(yīng)該從“fast bus mode”變?yōu)椤癮synchronous bus mode” */
__asm__(
"mrc p15, 0, r1, c1, c0, 0n" /* 讀出控制寄存器 */
"orr r1, r1, #0xc0000000n" /* 設(shè)置為“asynchronous bus mode” */
"mcr p15, 0, r1, c1, c0, 0n" /* 寫(xiě)入控制寄存器 */
);
/* 判斷是S3C2410還是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
MPLLCON = S3C2410_MPLL_200MHZ; /* 現(xiàn)在,F(xiàn)CLK=200MHz,HCLK=100MHz,PCLK=50MHz */
}
else
{
MPLLCON = S3C2440_MPLL_200MHZ; /* 現(xiàn)在,F(xiàn)CLK=200MHz,HCLK=100MHz,PCLK=50MHz */
}
}
/*
* 設(shè)置存儲(chǔ)控制器以使用SDRAM
*/
void memsetup(void)
{
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
/* 這個(gè)函數(shù)之所以這樣賦值,而不是像前面的實(shí)驗(yàn)(比如mmu實(shí)驗(yàn))那樣將配置值
* 寫(xiě)在數(shù)組中,是因?yàn)橐伞蔽恢脽o(wú)關(guān)的代碼”,使得這個(gè)函數(shù)可以在被復(fù)制到
* SDRAM之前就可以在steppingstone中運(yùn)行
*/
/* 存儲(chǔ)控制器13個(gè)寄存器的值 */
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++;
}
}
/**********************************************************************************
head.S
**********************************************************************************/
@******************************************************************************
@ File:head.S
@ 功能:設(shè)置SDRAM,將程序復(fù)制到SDRAM,然后跳到SDRAM繼續(xù)執(zhí)行
@******************************************************************************
.extern main
.text
.global _start
_start:
Reset:
ldr sp, =4096 @ 設(shè)置棧指針,以下都是C函數(shù),調(diào)用前需要設(shè)好棧
bl disable_watch_dog @ 關(guān)閉WATCHDOG,否則CPU會(huì)不斷重啟
// bl是位置無(wú)關(guān)碼,相當(dāng)于:PCnew = PC + 偏移
// PCnew = (4+8) + 0x28 = 0x34
//ldr pc, =disable_watch_dog /* 這樣寫(xiě)將出錯(cuò) */
bl clock_init @ 設(shè)置MPLL,改變FCLK、HCLK、PCLK
bl memsetup @ 設(shè)置存儲(chǔ)控制器以使用SDRAM
bl copy_steppingstone_to_sdram @ 復(fù)制代碼到SDRAM中
ldr pc, =on_sdram @ 跳到SDRAM中繼續(xù)執(zhí)行
on_sdram:
ldr sp, =0x34000000 @ 設(shè)置棧指針
ldr lr, =halt_loop @ 設(shè)置返回地址
ldr pc, =main @ 調(diào)用main函數(shù)
halt_loop:
b halt_loop
/**************************************************************************
main.c
**************************************************************************/
#include "serial.h"
int main()
{
unsigned char c;
uart0_init(); // 波特率115200,8N1(8個(gè)數(shù)據(jù)位,無(wú)校驗(yàn)位,1個(gè)停止位)
putc('T');
putc('e');
putc('s');
putc('t');
putc(':');
putc('n');
putc('r');
while(1)
{
// 從串口接收數(shù)據(jù)后,判斷其是否數(shù)字或字母,若是則加1后輸出
c = getc();
if (isDigit(c) || isLetter(c))
putc(c+1);
}
return 0;
}
/***********************************************************************
uart.lds
************************************************************************/
SECTIONS {
. = 0x30000000;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
/********************************************************************************
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 $@
arm-linux-objdump -D -m arm uart_elf > uart.dis
%.o:%.c
arm-linux-gcc -Wall -O2 -c -o $@ $<
%.o:%.S
arm-linux-gcc -Wall -O2 -c -o $@ $<
clean:
rm -f uart.bin uart_elf uart.dis *.o
實(shí)驗(yàn)的問(wèn)題總結(jié):
I.關(guān)于系統(tǒng)時(shí)鐘的設(shè)置,我們主要看clock_init()函數(shù)。
1>
/* 如果HDIVN非0,CPU的總線模式應(yīng)該從“fast bus mode”變?yōu)椤癮synchronous bus mode” */
__asm__( //C語(yǔ)言?xún)?nèi)嵌匯編,這段話(huà)是根據(jù)s3c2440用戶(hù)手冊(cè)上的說(shuō)明來(lái)寫(xiě)的
"mrc p15, 0, r1, c1, c0, 0n" /* 讀出控制寄存器 */
"orr r1, r1, #0xc0000000n" /* 設(shè)置為“asynchronous bus mode” */
"mcr p15, 0, r1, c1, c0, 0n" /* 寫(xiě)入控制寄存器 */
);
2>
GSTATUS1寄存器為芯片序列信號(hào),可查看s3c2440用戶(hù)手冊(cè)
3>
MPLLCON的目的是設(shè)置FCLK和Fin的倍數(shù),關(guān)于其值的設(shè)置,可以參考s3c2440用戶(hù)手冊(cè)關(guān)于PLL值選擇表
II.關(guān)于UART,我們主要分析如下:
我們主要分析serial.c文件,我們主要使用的方式是:非流控 + 非FIFO + 查詢(xún)方式。
在uart0_init()函數(shù)中,關(guān)于這幾個(gè)寄存器的配置,你可以對(duì)照s3c2440手冊(cè)進(jìn)行一一配置即可
其中,UTRSTAT0寄存器是判斷發(fā)送緩沖器或接收緩沖器中是否有數(shù)據(jù)
UTXH0為發(fā)送緩沖寄存器,我們?nèi)粝氚l(fā)送數(shù)據(jù),直接往UTXH0寄存器里邊賦值即可。