裸机系列代码地址:链接:http://pan.baidu.com/s/1pLHOd0v 密码:4x5s
UART:通用异步串行收发器
发送数据时:CPU将数据写入UART,UART按照一定的格式在一根线上串行发出接收数据时:UART检测另一根线上的信号,将串行收集放在缓冲区中,CPU即可读取UART获得的数据
在两个设备进行串行通讯前两者的UART要约定数据的传输速率(波特率),数据的传输格式(多少个数据位,是否使用校验位,是奇校验还是偶校验,有多少个停止位)
下图演示了UART使用7个数据位,偶校验,2个停止位的格式传输字符“A”
S3C2440 UART的特性
S3C2440有三路独立的UART通道,每个通道都可以工作于中断模式或MDA模式
S3C2440每个通道有16字节的发送FIFO和接收FIFO,发送数据时(中断模式),CPU先将数据写入发送FIFO中,FIFO中的数据到达FIFO阈值时
产生发送中断,UART会自动将FIFO中的数据复制到“发送移位器”中,发生移位器将数据一位一位的发送到TXD数据线上。接收数据时,“接收移位器”
将RXD中的数据一位一位的接收进来,然后复制到FIFO中,当接收FIFO中的数据达到FIFO阈值时,产生接收中断,CPU可以读取数据
S3C2440 UART结构图
S3C2440 UART的使用
(1)将所涉及的UART通道管脚设为UART功能
比如在UART0通道中,GPH2,GPH3分别用作TXD0,RXD0,要使用UART0通道时,需要设置GPHCON寄存器使得GPH2,GPH3引脚功能为TXD0,RXD0
(2)UBRDIVn寄存器:设置波特率
S3C2440 UART的时钟源有三种选择:PCLK,UEXTCLK,FCLK/n,其中n值通过UCON0,UCON1,UCON2联合设置。选定时钟源之后,设置波特率
UBRDIVn = (int)(UART_CLOCK/(buad_rate*16))-1
(3)ULCONn寄存器:设置传输格式
(4)UCONn寄存器:选择UART时钟源,设置UART中断方式
(5)UFCONn寄存器:设置是否使用FIFO,不使用的话可认为FIFO深度为1;设置FIFO的触发阈值
(6)UMCONn和UMSTATn:用于流量控制
(7)UTRSTATn寄存器:用来表明数据是否已经发送完毕,是否已经接收到数据
(8)UERSTATn寄存器:标示各种错误是否发生。溢出错误,校验错误,帧错误,break信号
(9)UTXHn寄存器:CPU将数据写入这个寄存器,UART即会将数据保存到缓冲区中,并自动发送
(10)URXHn寄存器:当UART接受到数据时,CPU读取这个寄存器,即可获得数据。
所以有两者方式检测读取数据和写数据的时机:
(1)UTRSTATn标示可读
(1)UTRSTATn标示可写(2)发送FIFO达到阈值,发数据中断产生
(2)接受FIFO达到阈值,读数据中断产生
下面是一个串口的实例
Makefile文件
objs:= head.o init.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_elf uart.dis uart.bin *.o
链接文件uart.lds
SECTIONS {
. = 0x30000000;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
head.s文件.text
.global _start
_start:
ldr sp,=4096 /*设置C函数使用的栈*/
bl disable_watch_dog
bl init_clock /*设置系统时钟,使得uart使用PCLK为50MHZ*/
bl memsetup /*初始化存储控制器使得SDRAM可用*/
bl copy_steppingstone_to_sdram /*将代码复制到SDRAM中*/
ldr pc,=on_sdram /*地址相关代码,从这里开始程序在SDRAM中运行*/
on_sdram:
ldr sp,=0x34000000 /*设置代码在SDRAM中运行时的栈*/
bl init_uart0 /*初始化串口0*/
bl main
bl halt_loop
halt_loop:
b halt_loop
init.c文件
#include "s3c2440.h"
void disable_watch_dog(void)
{
WTCON = 0x53000000;
}
/*注意这里必须用这种方式,用数组循环赋值的方式不可取*/
void memsetup(void)
{
volatile unsigned long *p = (volatile unsigned long *)0x48000000;
/* 这个函数之所以这样赋值,而不是像前面的实验(比如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 *pdest = (unsigned int *)0x30000000;
unsigned int *psrc = (unsigned int *)0x00000000;
while(psrc<(unsigned int *)4096)
{
*pdest = *psrc;
pdest++;
psrc++;
}
}
void init_clock(void)
{
#define MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
CLKDIVN = 0x03;
__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" /* 写入控制寄存器 */
);
MPLLCON = MPLL_200MHZ;
}
void init_uart0(void)
{
GPHCON = 0xa0; /*GPH2,GPH3用作TXD0,RXD0*/
GPHUP = 0x0c; /*GPH2,GPH3内部上拉*/
#define UART_PCLK 50000000
#define baurd 115200
#define UART_BRD ((UART_PCLK/(baurd*16)) -1 )
ULCON0 = 0x03; /*数据位数为8,一个停止位,无奇偶校验*/
UCON0 = 0x05; /*查询方式,UART时钟源为PCLK*/
UFCON0 = 0x00; /*不使用FIFO*/
UMCON0 = 0x00; /*不使用流控*/
UBRDIV0 = UART_BRD; /*波特率为115200*/
main.c文件
#include "s3c2440.h"
#define TXD0READY (1<<2)
#define RXD0READY (1)
void putcc(unsigned char c)
{
while( !(UTRSTAT0 & TXD0READY));
UTXH0 = c;
}
unsigned char getcc(void)
{
while( !(UTRSTAT0 & RXD0READY));
return URXH0;
}
int isdigitt(char c)
{
if ('0'<=c && c<='9')
return 1;
else
return 0;
}
int isletter(char c)
{
if ( ('a'<=c && c<='z') || (c>='A' && c<='Z') )
return 1;
else
return 0;
}
int main()
{
unsigned char c;
while(1)
{
c=getcc();
if(isdigitt(c) || isletter(c))
putcc(c+1);
}
return 0;
}
头文件s3c2440.h
/*GPIO*/
#define GPHCON (*(volatile unsigned long *)0x56000070)
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPHUP (*(volatile unsigned long *)0x56000078)
/*watch_dog*/
#define WTCON (*(volatile unsigned long *)0x53000000)
/*uart0*/
#define UBRDIV0 (*(volatile unsigned long *)0x50000028)
#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 UERSTAT0 (*(volatile unsigned long *)0x50000014)
#define UTXH0 (*(volatile unsigned long *)0x50000020)
#define URXH0 (*(volatile unsigned long *)0x50000024)
/*clock*/
#define MPLLCON (*(volatile unsigned long *)0x4C000004)
#define CLKDIVN (*(volatile unsigned long *)0x4C000014)