您的位置:首页 > 编程语言

ARM:UART串口异步通信驱动编程

2017-02-06 22:50 701 查看
1. 串口的基本概念
1.1 UART - 串行异步收发器 Universal Asynchronous Receiver/Transmitter
串行/并行(课后补充)
异步/同步:'异步/同步通信两者之间的区别' (补充)
'单工/半双工/全双工:
单工:任何时候数据只能朝一个方向传输
半双工:数据可以向两个方向传输,任何同一时刻只能朝同一方向传输
全双工:数据可以同时向两个方向传输
1.2 串口通信标准
RS232 (电子工业协议EIA) - 目前最常用的'串行接口标准'
规定了'电气特性':
逻辑 0 ,+3 v ~ +15 v,SPACE
逻辑 1 ,- 3 v ~ - 15 v,MARK
规定了'机械特性':
传输距离 < 10 m
TTL电平,计算机内部电平(CPU):
逻辑 0 ,低电平 < 0.8 v
逻辑 1 ,高电平 > 2.4 v
串行异步通信的重要参数:
>>数据位个数: 5 ~ 8 bit  (开发板那端定好的是 8 bit / 帧数据)
>>验证方式:奇校验、偶校验、无校验
>>停止位宽度:1~2bit
>>通信的速率:bps (bit per second - 每秒传输bit位)'波特率单位'

2. 电路原理图
【底板】
             |---SP3232E电平转换芯片---|
PC_TXD1 ---> T2OUT ---> T2IN ---> UARTTXD0 ---> 'GPIOD18
PC_RXD1 ---> R2IN ---> R2OUT ---> UARTRXD0 ---> 'GPIOD14
完成串口通信有两种方式:
1) 一种方式:运行在arm core的程序和LED一样直接操作GPIO管脚,形成串行异步收发数据的时序。
2) 另一方式:S5P6818中集成了uart控制器,方式 1)纯软件实现通信的过程就可以使用软硬件结合的方式来实现通信时序,从而简化软件编程。

问题:
uart控制器可以完成哪些工作,还需软件做哪些工作,两者之间如何配合?
答案:CPU的数据手册中关于uart的相关章节

3. CPU datasheet
3.1 管脚的功能选择
--->P 71 - 2.3
GPIOD18 - Function1
GPIOD14 - Function1
--->P 757 - 16.5.1.8
GPIODALTFN0 - 0xc001d020 - [29:28] - 01=ALT Function1
GPIODALTFN1 - 0xc001d020 - [ 5 : 4 ] - 01=ALT Function1
3.2 uart 控制器
--->P 960 - 25.1
' S5P6818串行异步收发器 UART 单元特点:
1) 提供 6 个独立的uart控制器
2) 数据传输可以使用轮询、中断、DMA方式
3) 采用系统时钟时最大传输速率 4 Mbps   // 采用外部时钟时可以达更大速率
4) 每个UART通道有两个 64 bytes FIFO供发送和接收数据,以提供较高效率
5) 可编程波特率、红外发送接收、1~2个停止位、5~8位数据宽度、奇偶校验

问题:
COM1对应的是CPU内部的哪个uart控制器?
答案:
根据COM1使用的是CPU上的GPIOD14、GPIOD18,推断对应的是CPU内部的'UART0'。

知识点:
'CPU感知外接硬件变化通常有3种方式:
1> 轮询; 
// 定时对各种设备轮流询问一遍有无处理要求,有要求就处理,处理完回归CPU日常工作。- 适合硬件变化频繁的状况
2> 中断; 
// 当有硬件设备处理要求是,CPU启动输入输出设备存档准备数据,I/O完成发出中断信号,接收中断处理数据,随后某个时刻继续工作。 - 适合硬件变化不是特别频繁的状况
3>DMA;
// 直接内存存取,direct memory access,数据在内存与I/O设备间直接进行成块传输。

'【UART控制器重要参数】
non-FIFO - 115200 - 8 - None - 1 - 轮询mode

ULCON0 - 0xc00a1000 - R/W
- [ 1 : 0 ] - 11 , 8 bit - 数据宽word lenth
- [ 2 ] - 0 , 1 bit - 停止位number of stop bit
- [ 5 : 3 ] - 000 - 无校验
- [ 6 ] - 0 - 红外正常模式

UCON0 - 0xc00a1004 - R/W
- [ 1 : 0 ] - 01 - 轮询接收 Receive Mode(Polling mode)
- [ 3 : 2 ] - 01 - 轮询发送 Transmit Mode(Polling mode)
- [ 5 ] - 01 - 设置轮询模式 Setting Loop-back mode

UFCON0 - 0xc00a1008 - R/W
- [ 0 ] - 0 - 禁用FIFO(non-FIFO) FIFO Disables

UTRSTAT0 - 0xc00a1010 - R
- [ 0 ] - 1 - 代表收到了数据 Buffer has a received data
- [ 1 ] - 0 / 1 - 0 代表 transmit buffer 非空, 1 代表空

UTXH0 - 0xc00a1020 - W
- [ 7 : 0 ] - 写入要发送的数据 Transmit Data for UART0

URXH0 - 0xc00a1024 - R
- [ 7 : 0 ] - 读出接收到的数据 Receive Data for UART0

--->P 313 - 5.3.2.1.13 UARTCLKENB - '时钟源配置,地址数与UART对应
UARTCLKENB - 0xc00a9000 - R/W
- [ 2 ] - 1 - 使UART0时钟使能 Enable

 UARTCLKGEN0L - 0xc00a9004 - R/W
- [ 4 : 2 ] - 1 - 时钟源频率选择 PLL[1]==800MHz(uboot中调为该频率)
- [12: 5 ] - 1111 1111 - 分频系数,提供给UART0的时钟信号 50 MHz
// 1M==100万,800M==8亿,1111==0x0f,800MHz(0x0f+1)=50MHz

--->P 986 - 25.4.1.11/25.4.1.12 - '用于分频,将输入的50MHz分频成适合每秒钟发送115200个bit所需要的时钟信号
UBRDIV0 - 0xc00a1028 - R/W - 经计算取值为 26
UFRACVAL0 - 0xc00a102c - R/W - 经计算取值为 2

--->P 969 - For example // 设置方法示例
/* 手册定好的计算方式,不需要问为什么,直接套公式即可。
DIV_VAL = (40000000/(115200 x 16))  –  1
= 21.7 – 1
= 20.7
UBRDIVn = 20 (integer part of DIV_VAL)
UFRACVALn/16 = 0.7
So, UFRACVALn = 11
*/
50000000 / (115200 * 16) - 1 = 27.13 - 1 = 26.13 = 26 【==UBRDIV0】
0.13 * 16 = 2.08 = 2 【==UFRACVAL0】

【汇总】S5P6818UART相关寄存器
1) UART行控制器ULCONn - 设置数据格式
2) UART模式控制寄存器UCONn - 用来选择时钟源,发送/接收数据可选轮询
3) UART FIFO控制寄存器UFCONn
4) UART MODEM控制寄存器UMCONn
5) 发送寄存器UTXH、接收寄存器URXH
6) 波特率分频寄存器UBRDIV,UFRACVAL
7) GPIO相关寄存器
8) 中断相关寄存器
9) 时钟、电源控制寄存器

4. 编码
/** 代码演示 - main.c **/
#include "uart.h"
void main (void) {
// 8N1 115200 non-FIFO polling
uart_init ( );
while (1) {
uart_puts ("\n hello,world!");
}
}
/** 代码演示 - uart.c **/
#define UART0CLKENB     *((volatile unsigned int*)0xc00a9000)
#define UART0CLKGEN0L   *((volatile unsigned int*)0xc00a9004)

#define GPIOD_ALTFN0    *((volatile unsigned int*)0xc001d020)
#define GPIOD_ALTFN1    *((volatile unsigned int*)0xc001d024)
#define GPIOD_PULLENB   *((volatile unsigned int*)0xc001d060)

#define ULCON0          *((volatile unsigned int*)0xc00a1000)
#define UCON0           *((volatile unsigned int*)0xc00a1004)
#define UFCON0          *((volatile unsigned int*)0xc00a1008)
#define UTRSTAT0        *((volatile unsigned int*)0xc00a1010)
#define UTXH0           *((volatile unsigned int*)0xc00a1020)
#define URXH0           *((volatile unsigned int*)0xc00a1024)
#define UBRDIV0         *((volatile unsigned int*)0xc00a1028)
#define UFRACVAL0       *((volatile unsigned int*)0xc00a102c)
void uart_init (void) {
/* uart0 clk disable */
UART0CLKENB &= ~(1 << 2);
// GPIOD18(Tx 接收管脚) GPIOD14(Rx 发送管脚) 配置功能Function1
GPIOD_ALTFN0 &= ~(3 << 28); // GPIOD14
GPIOD_ALTFN0 |= (1 << 28);
GPIOD_ALTFN1 &= ~(3 << 4); // GPIOD18
GPIOD_ALTFN1 |= (1 << 4);
// 时钟配置:选择PLL[1] 800MHz
UART0CLKGEN0L &= ~(7 << 2);
UART0CLKGEN0L |= (1 << 2);
// 分频设置 800/(0x0f+1)=50MHz
UART0CLKGEN0L &= ~(0xff << 5); // [12:5] 8个位
UART0CLKGEN0L |= (0xf << 5); // [12:5] 4个位设置为1111
// UART控制器设置
ULCON0  = 0x03; // 8N1
UCON0   = 0x05; // 0101 == 0x05 polling
UFCON0 &= ~(1 << 0); // non-FIFO disable
UBRDIV0 = 26; // 50000000/(115200*16) - 1 == 26.13
UFRACVAL0 = 2; // 0.13*16 == 2.08
/* uart0 clk enable */
UART0CLKENB |= (1 << 2);
}
void uart_putc (char c) {
// UTRSTAT0 bit[1] == 1, 缓存寄存器为empty
// 轮询是否为空
while (! (UTRSTAT0 & 0x02)); // !(空) 什么都不干。
UTXH0 = c;
if (c == '\n')
uart_putc ('\r');
}
void uart_puts (char* str) {
if (! str)
return ;

while (*str) {
uart_putc (*str);
str++;
}
}
/** 代码演示 - uart.h **/
#ifndef _UART_H_
#define _UART_H_

extern void uart_init (void);
extern void uart_puts (char*);

#endif //_UART_H_

5. 编译

$:' arm-cortex_a9-linux-gnueabi-gcc -c -nostdlib main.c -o main.o
$:' arm-cortex_a9-linux-gnueabi-gcc -c -nostdlib uart.c -o uart.o
$:' arm-cortex_a9-linux-gnueabi-ld -nostdlib -nostartfiles -Ttext=48000000 -emain main.o uart.o -o uart      // 注意.o文件顺序
$:' arm-cortex_a9-linux-gnueabi-objcopy -O binary uart uart.bin
6. 运行
$:' sudo cp uart.bin /tftpboot/
X6818#:' tftp 48000000 uart.bin
X6818#:' go 48000000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  arm