JZ2440 串口分析

裸机系列代码地址:链接: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)





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值