1:串口的数据发送的数据量较大时,使用fifo可以大大降低MCU的开销。(有点类似串入并出的cput处理模型,本质上还是串行收发)
2:在某些特殊场合,例如制定较复杂的协议时,可以使用fifo特性来做协议简化,比如一包
数据包含8个字节,(并且fifo设置的长度为8),这样相当于把uart转换为类似CAN/以太网模型,
这样信息可扩展性得到了质的提高,当然,这里需要同步协调。
fifo分析拓展:
1. 如果要用中断来处理接收到的数据,就是说,接收完数据然后产生中断,再于中断里处理接收的数据。如果要实现这个本意,要设置好触发点。
至于超时中断之类,那是另外一回事了。
2. 就UART的中断类型而言,还包括:RBR中断使能、THRE中断使能、RX线状态中断使能、自动波特率超时中断使能等。
3. FIFO定义说了,先入先出缓冲区,在UART中有什么用呢。我们可以用它来批量发送 数据(而非FIFO模式,只能一字节一字节的发,而且发每个字节都需要等待缓冲区变空才能发送下一字节),这样能在一定程度上提高数据发送速度。还有就是 避免数据包的的丢失(这个问题,目前还没体会)。
需要了解的相关知识:
HCLK主要为S3C2440 AHB总线(Advanced High performance Bus)上挂接硬件提供工作频率,AHB总线主要挂接有内存,NAND,LCD控制器等硬件
FCLK主要为ARM920T内核提供工作频率;
PCLK主要为APB总线提供工作频率,APB总线主要挂接UART串口,Watchdog等硬件控制器。【所以在这里我们用PCLK作为UART的时钟源】
外接设备 |
起始地址 |
结束地址 |
存储控制器 |
0x48000000 |
0x48000030 |
USB Host控制器 |
0x49000000 |
0x49000058 |
中断控制器 |
0x4A000000 |
0x4A00001C |
DMA |
0x4B000000 |
0x4B0000E0 |
时钟和电源管理 |
0x4C000000 |
0x4C000014 |
LCD控制器 |
0x4D000000 |
0x4D000060 |
NAND FLASH控制器 |
0x4E000000 |
0x4E000014 |
摄像头接口 |
0x4F000000 |
0x4F0000A0 |
UART |
0x50000000 |
0x50008028 |
脉宽调制计时器 |
0x51000000 |
0x51000040 |
USB设备 |
0x52000140 |
0x5200026F |
WATCHDOG计时器 |
0x53000000 |
0x53000008 |
IIC控制器 |
0x54000000 |
0x5400000C |
IIS控制器 |
0x55000000 |
0x55000012 |
I/O端口 |
0x56000000 |
0x560000B0 |
实时时钟RTC |
0x57000040 |
0x5700008B |
A/D转换器 |
0x58000000 |
0x58000010 |
SPI |
0x59000000 |
0x59000034 |
SD接口 |
0x5A000000 |
0x5A000040 |
AC97音频编码接口 |
0x5B000000 |
0x5B00001C |
在start.s中完成对看门狗,内存等进行初始化:
GPBCON EQU 0x56000010
GPBDAT EQU 0x56000014
AREA Init,CODE,READONLY //声明一个只读性质的代码段Init.
ENTRY //入口
start
close watchdog
ldr r0,=0x53000000; //将看门狗控制寄存器地址放入r0
mov r1,#0
str r1,[r0]; //将r1的值0放到r0中,即设置看门/
狗控制寄存器的值为0
bl initmem; //跳转到initmem代码段,初始化内存
IMPORT main; //引入main.c中的main函数
ldr sp,=0x34000000; //调用c程序前先初始化桟指针
ldr lr,=loop; //设置main函数的返回地址
ldr pc,=main; //跳转到c程序的main函数的入口处执行
loop
b loop ; //死循环
initmen //内存初始化
ldr r0,=0x48000000; //加载内存相关寄存器首地址r0
ldr r1,=0x48000034; //加载内存相关寄存器尾地址到r1
adr r2,memdata; //将寄存器配置数据地址段首地址加载到r2
initmemloop
ldr r3,[r2],#4; //循环设置存寄存器
str r3,[r0],#4
teq r0,r1
bne initmemloop; //循环到最后一个寄存器时退出函数
mov pc,lr
memdata // 存放内存控制器设置数据
DCD 0x22000000 ;BWSCON
DCD 0x00000700 ;BANKCON0
DCD 0x00000700 ;BANKCON1
DCD 0x00000700 ;BANKCON2
DCD 0x00000700 ;BANKCON3
DCD 0x00000700 ;BANKCON4
DCD 0x00000700 ;BANKCON5
DCD 0x00018005 ;BANKCON6
DCD 0x00018005 ;BANKCON7
DCD 0x008e07a3 ;REFRESH
DCD 0x000000b1 ;BANKSIZE
DCD 0x00000030 ;MRSRB6
DCD 0x00000030 ;MRSRB7
END
在uart.c中:
#define GPHCON (*(volitile unsigned long *)0X56000070)
#define GPHDAT (*(volitile unsigned long *)0X56000074)
#define GPHUP (*(volitile unsigned long *)0X56000078)
#define UFCON0 (*(volitile unsigned long *)0x50000008)
#define UMCON0 (*(volitile unsigned long *)0X5000000C)
#define UCON0 (*(volitile unsigned long *)0X50000004)
#define ULCON0 (*(volitile unsigned long *)0X50000000)
#define UART_CLK PCKL //UART0的时钟源为PCLK
#define UART_BAUD_DATE 115200 //波特率
#define UART_BRD ((UART_CLK/(UART_BAUD_DATE*16))-1)
void uart_init(void)
{
UFCON0=0xbf; //使用fifo(发送fifo和接收fifo的触发深度都为32字节)【在中断模式下的fifo要设置触发方式(超时触发或字节触发)】
UMCON0=0x00; //不使用流控
UBRDIV0=UART_BRD; //波特率为115200
GPHCON |=0xa0; //GPH2,GPH3用作TXD0,RXD0
GPHUP=0x0c; //GPH2,GPH3内部上拉
UCON0=0X05 //时钟源为PCKL
ULCON0 &=0X03; //正常模式,数据格式:8个数据位,没有流控,1个数据位
}
当发送缓冲区里有数据需要传送时,我们就需要中断,来完成发送数据的任务。这个中断的产生,是由 s3c24xx_serial_start_tx()函数来完成的,具体来说,是它所调用的一个是中断使能的函数 enable_irq(TX_IRQ(port))来完成的。而此中断一旦使能,就会调用该中断的服务函数 s3c24xx_serial_tx_chars()去做后续的工作。