s3c2440串口
一、简介
通用异步收发器(Universal Asynchronous Receiver Transmitter),简称“串口”,它可以工作在中断模式或者DMA模式。用系统时钟它可以产生高达
921.6Kbps的波特率。s3c2440共有3个串口,每个串口都2个64位的FIFO用于接收与发送数据。串口之间采用全双工的模式发送数据,最简单的接线方式就是串口1的tx接串口2的rx,串口1的rx接串口2的tx,两个串口在共地即可。2440的串口用的TTL电平(0~3.3V),而我们的计算机采用的是RS232电平(逻辑0:
3~15v 逻辑1:-3~-15v),两者通信需要电平转换。传输过程如下(8位数据位,1位停止位,无校验位):
LSB MSB
(1)平时处于高电平,空闲状态
(2)数据发送时变成低电平发送一位起始位,之后数据从高到低位依次发送
(3)数据位发送完毕若有需要会发送校验位(本图无校验位),最后发送一位停止位,接着返回步骤一
二、内部工作原理
每个串口有波特率发生器、传输器、接收器和控制单元组成,波特率发生器的时钟可由PCLK、FCLK/n和外部时钟提供,发送数据时数据首先被放到FIFO中,然后数据被复制到移位器中,移位器一位位的发送到tx引脚,接收数据时数据从rx引脚被移位器接收,然后复制到FIFO中。
page333
三、串口寄存器的使用
(1)
page341
数据长度:我们选择11,即8位 停止位:我们选0,即每帧1位停止位 校验模式:0xx,无校验 红外模式:0 选择普通模式
(2)串口控制寄存器
接收模式:01 中断请求或轮询模式 传输模式:01 中断请求或轮询模式 发送break信号: 0 不发送,普通模式 回环模式:0 普通模式
接收错误中断:0 不产生 接收超时中断:0 不产生 接收中断类型:我们不使用中断,默认 发送中断类型:不使用,默认
时钟源选择:00或者10 PCLK FCLK 分频:未使用0000
如果使用一些特殊的波特率,可以尝试使用FCLK或者外部时钟
(3)UART FIFO control registers与UART FIFO status registers,这里没有使用FIFO
(4)UART MODEM control registers与UART modem status registers,这里也没有使用
(5)串口接收发送状态寄存器
page347
接收buffer状态:0 空,即没有数据 1接收到了数据
传输buffer状态: 0 数据正在传输 1空,数据传输完毕
传输空: 0 传输数据buffer或移位数据buffer不为空 1传输数据buffer和移位数据buffer都为空
(6)UART error status registers
page348
0~4位表示溢出错误、校验错误、帧错误、break信号检测,读取后相应的位自动清零
如果接收数据使用了FIFO,则会有一个“错误FIFO”表明接收到的错误,cpu只有在读出这个错误数据时才会发现错误。要想清除“错误FIFO”,则必须读出错误数据,,并读出UART error status registers相应的位。
(7)
将数据写到寄存器,启动数据传输。注意数据的大小端分别对应不同地址
(8)
当接收到数据时,读这个寄存器会得到数据,也要注意数据的大小端分别对应不同地址
(9)
波特率计算:UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
当使用外部时钟时UBRDIVn被设置为0.
例如:UBRDIVn=(int)(50000000/(115200x16))-1=26
四、实验代码
目的:输入一个字符把这个字符的值加一输出,采用轮询方式
head.S
.text
.global _start
_start:
mov sp, #4096
bl disable_watch_dog
bl clock_init
bl set_up_mem_ctl
bl copy_steppingstone_to_sdram
ldr sp, =0x34000000
ldr pc, =on_sdram
on_sdram:
bl init_uart0
bl main
halt_loop:
b halt_loop
init.c
#include "s3c2440.h"
void disable_watch_dog(void)
{
WTCON = 0X00;
}
void clock_init(void)
{
CLKDIVN = 0x03; //应先设置分频值,在设定MPLLCON
__asm__(
"mrc p15,0,r1,c1,c0,0\n"
"orr r1, r1, #0xc0000000\n"
"mcr p15,0,r1,c1,c0,0\n");
MPLLCON = (0x2a << 12) | (0x01 << 4) | 0x01; //MPLL为200MHz
}
void set_up_mem_ctl(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)
{
volatile unsigned int *source_addr = (volatile unsigned int *)0x00;
volatile unsigned *dest_addr = (volatile unsigned int *)0x30000000;
unsigned int length = 4096;
while(length--)
*dest_addr++ = *source_addr++;
}
void init_uart0(void)
{
GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0
GPHUP = 0x0c; // GPH2,GPH3内部上拉
ULCON0 = 0x03; //8位数据位,1位停止位,无校验位,普通模式(非红外模式)
UCON0 = 0X05;
UBRDIV0 = 26; //波特率115200bps
}
main.c
#include "s3c2440.h"
#include "uart.h"
int main(void)
{
char c;
while(1){
c = uart0_get_char();
uart0_put_char(c + 1);
}
return 0;
}
Makefile
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
s3c2440.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)
uart.c
#include "s3c2440.h"
char uart0_get_char(void)
{
char ret_char;
while(!(UTRSTAT0 & 0x01));
ret_char = URXH0;
return ret_char;
}
void uart0_put_char(char c)
{
while(!((UTRSTAT0>>2) & 0x01 ));
UTXH0 = c;
}
uart.h
char uart0_get_char(void);
void uart0_put_char(char c);
uart.lds
SECTIONS {
. = 0x30000000;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}