本文主要探讨210串口相关知识。
同步通信和异步通信
发送和接收方同时钟工作叫同步,否则叫异步
同步通信频率固定,双方通信频率不固定,,接收方收到起始信号开始接收信息
电平信号和差分信号
电平信号和差分信号是描述通信线路传输方式
电平信号传输线中有参考电平线(GND),信号值由信号线电平和参考电平电压差决定
差分信号传输线中没有参考电平,只有信号线,1和0由信号线之间电压差决定
电平信号通信线间电平差异易受干扰,传输易失败
差分信号不易受干扰,传输稳定(常用)发送快
并行接口和串行接口
电平信号:电平线+信号线可传递1位二进制(常用)
差分信号:2信号线(彼此差分)发送1位二进制(8位需16线)
异步串行差分接口常用(USB)
串口通信
串口通信特点:异步、电平信号、串行
异步:发送方和接收方之间没有统一时钟信号
电平信号:电平信号传输
串行通信:每次同时传输1位二进制位
RS232电平和TTL电平
电平信号是信号线电平与考线电平压差值区别1,0
RS232中-3V~-15V表示1;+3~+15V表示0
TTL电平+5V表示1,0V表示0
RS232电平定义大,接收干扰大、距离远,TTL相反
RS232接口传输距离小于15米,TTL用在芯片之间
波特率、起始位、数据位、奇偶校验位、停止位
波特率是串口通信速率,每秒钟传输二进制位。(B = 9600,t = 1/9600 = 104us)
通信双方设定相同波特率才能通信,否则接收信息解析会出错
串口通信收发是周期性的,由起始位+数据位+奇偶校验位+停止位组成
起始位表示发送方开始;数据位是有效信息位;奇偶校验位是校验数据位;停止位表示结束标志
起始位是串口通信标准指定,由通信线电平变反映(内置)
数据位是发送的有效数据(8)
奇偶校验位是据位进行奇偶校验(1)
停止位是串口通信标准指定,由通信线电平变化反映(1)
串口通信是异步通信,通信双方约定好通信参数,参数包括:波特率、数据位、奇偶校验位、停止位
串口通信原理
单工就是单方向,双工是双方同时收发,同时只能单方向收发是半双工
通信线:Rx,Tx,GND
SoC内串口引脚输出TTL电平(X210未使用),每个串口有3线(Tx、Rx、GND)可提供外设使用
串口通信发送方隔一段时间(波特率)将信息(1,0)放到通信线上,逐二进制位发送
接收方定时读取通信线上电平高低来区分1,0依次读取数据位、奇偶校验位、停止位,停止位
DB9接口中有9通信线,3线为GND、Tx、Rx其余6和流控(不使用)有关
210串口
串口包含发送器和接收器,串口控制器接在APB总线上
发送器由发送缓冲区和发送移位器构成,发送信息时将二进制信息流一帧帧(8位)写入发送缓冲区,发送移位器自动读取一帧数据发送到Tx通信线上
接收器由接收缓冲区和接收移位器构成,接收信息时,Rx通信线上的信息通过接收移位器将该二进制信息流保存到接收缓冲区,缓冲区满时产生中断给CPU,CPU读取数据
FIFO模式和DMA模式和IrDA模式(210)
典型串口发送和接收缓冲区大小为1字节,发送和接收只能处理1帧数据,中断信号太多,影响CPU的处理其他事务
FIFO扩展发送或接收缓冲区(轻量级)
DMA是DSP的一种技术,交换数据时不需要CPU参与,模块独立完成,大量数据发送或接收
IrDA是发送方固定间隔时间向接收方发送红外信号,接收方每隔固定时间去判断有无红外线信号来接收
210串口相关
时钟:PCLK_PSYS,66MHz
Tx和Rx的GPIO,Rx为GPA0_1,Rx为GPA0_0,GPA0CON(0xE0200000)bit[3:0] = 0b0010 bit[7:4] = 0b0010
关键寄存器UCON0 ULCON0 UMCON0 UFCON0
ULCON0 = 0x3 // 0校验位、8数据位、1停止位
UCON0 = 0x5 // 发送和接收都是polling mode
UMCON0 = 0x0 // 禁止modem、afc
UFCON0 = 0x0 // 禁止FIFO模式
波特率
寄存器: UBRDIV0 UDIVSLOT0
UBRDIVn设置波特率,UDIVSLOTn校准波特率
DIV_VAL: DIV_VAL = (PCLK / (bps x 16)) - 1
UBRDIV0为DIV_VAL整数
小数*161并查表得uBDIVSLOT0值
demo1:
编写210串口
start.S
#define WTCON 0xE2700000
#define SVC_STACK 0xd0037d80
.global _start
_start:
//关看门狗
ldr r0, =WTCON
ldr r1, =0x0
str r1, [r0]
//设置SVC栈
ldr sp, =SVC_STACK
//开/关icache
mrc p15,0,r0,c1,c0,0; // 读出cp15的c1到r0中
orr r0, r0, #(1<<12) // bit12 置1 开icache
mcr p15,0,r0,c1,c0,0;
bl main
b .
mian.c
void delay_time()
{
volatile unsigned int i = 900000;
while (i--);
}
int main()
{
//init uart
init_uart();
//send data
while(1)
{
send_data('w');
delay_time();
}
return 0;
}
uart.c
#define GPA0CON0 0xE0200000
#define UCON0 0xE2900004
#define ULCON0 0xE2900000
#define UMCON0 0xE290000C
#define UFCON0 0xE2900008
#define UBRDIV0 0xE2900028
#define UDIVSLOT0 0xE290002C
#define UTRSTAT0 0xE2900010
#define UTXH0 0xE2900020
#define URXH0 0xE2900024
#define rGPA0CON0 (*(volatile unsigned int *)GPA0CON0)
#define rUCON0 (*(volatile unsigned int *)UCON0)
#define rULCON0 (*(volatile unsigned int *)ULCON0)
#define rUMCON0 (*(volatile unsigned int *)UMCON0)
#define rUFCON0 (*(volatile unsigned int *)UFCON0)
#define rUBRDIV0 (*(volatile unsigned int *)UBRDIV0)
#define rUDIVSLOT0 (*(volatile unsigned int *)UDIVSLOT0)
#define rUTRSTAT0 (*(volatile unsigned int *)UTRSTAT0)
#define rUTXH0 (*(volatile unsigned int *)UTXH0)
#define rURXH0 (*(volatile unsigned int *)URXH0)
void init_uart()
{
//set GPIO uart mode(TX,RX)
rGPA0CON0 &= ~(0xff);
rGPA0CON0 |= ((1 << 2) | (1<< 6));
//set uart polling mode
rUCON0 = 0x5;
//set uart,prohibit afc
rUMCON0 = 0x0;
//set uart,prohibit fifo
rUFCON0 = 0x0;
//set clock device frequence
//DIV_VAL = (PCLK / (bps x 16)) -1
//DIV_VAL = (66000000 / (115200*16)) -1 = 34.8
rUBRDIV0 = 34;
//0.8 * 16 = 13,check 210 table
rUDIVSLOT0 = 0xdfdd;
}
void send_data(char cdata)
{
//judge send buff is'not or is empty,then send data
while (!(rUTRSTAT0 & (1 << 1)));
rUTXH0 = cdata;
}
char get_data()
{
//judge get buff is'not or is empty,then get data
while (!(rUTRSTAT0 & 1));
return (rURXH0 & 0x0f);
}
Makefile
uart.bin: start.o uart.o main.o
arm-linux-ld -Ttext 0x0 -o uart.elf $^
arm-linux-objcopy -O binary uart.elf uart.bin
arm-linux-objdump -D uart.elf > uart_elf.dis
gcc mkv210_image.c -o mkx210
./mkx210 uart.bin 210.bin
%.o : %.S
arm-linux-gcc -o $@ $< -c -nostdlib
%.o : %.c
arm-linux-gcc -o $@ $< -c -nostdlib
clean:
rm *.o *.elf *.bin *.dis mkx210 -f
demo2:
串口移植printf
start.S
#define WTCON 0xE2700000
#define SVC_STACK 0xd0037d80
.global _start
_start:
//关看门狗
ldr r0, =WTCON
ldr r1, =0x0
str r1, [r0]
//设置SVC栈
ldr sp, =SVC_STACK
//开/关icache
mrc p15,0,r0,c1,c0,0; // 读出cp15的c1到r0中
orr r0, r0, #(1<<12) // bit12 置1 开icache
mcr p15,0,r0,c1,c0,0;
bl main
b .
main.c
#include "stdio.h"
void delay_time()
{
volatile unsigned int i = 900000;
while (i--);
}
int main(void)
{
uart_init();
int num = 18;
putc('h');
putc('e');
putc('l');
putc('l');
putc('o');
while (1)
{
printf("test for printf, a = %d.\n", a);
delay_time();
}
return 0;
}
uart.c
#define GPA0CON0 0xE0200000
#define UCON0 0xE2900004
#define ULCON0 0xE2900000
#define UMCON0 0xE290000C
#define UFCON0 0xE2900008
#define UBRDIV0 0xE2900028
#define UDIVSLOT0 0xE290002C
#define UTRSTAT0 0xE2900010
#define UTXH0 0xE2900020
#define URXH0 0xE2900024
#define rGPA0CON0 (*(volatile unsigned int *)GPA0CON0)
#define rUCON0 (*(volatile unsigned int *)UCON0)
#define rULCON0 (*(volatile unsigned int *)ULCON0)
#define rUMCON0 (*(volatile unsigned int *)UMCON0)
#define rUFCON0 (*(volatile unsigned int *)UFCON0)
#define rUBRDIV0 (*(volatile unsigned int *)UBRDIV0)
#define rUDIVSLOT0 (*(volatile unsigned int *)UDIVSLOT0)
#define rUTRSTAT0 (*(volatile unsigned int *)UTRSTAT0)
#define rUTXH0 (*(volatile unsigned int *)UTXH0)
#define rURXH0 (*(volatile unsigned int *)URXH0)
void init_uart()
{
//set GPIO uart mode(TX,RX)
rGPA0CON0 &= ~(0xff);
rGPA0CON0 |= ((1 << 2) | (1<< 6));
//set uart polling mode
rUCON0 = 0x5;
//set uart,prohibit afc
rUMCON0 = 0x0;
//set uart,prohibit fifo
rUFCON0 = 0x0;
//set clock device frequence
//DIV_VAL = (PCLK / (bps x 16)) -1
//DIV_VAL = (66000000 / (115200*16)) -1 = 34.8
rUBRDIV0 = 34;
//0.8](//0.8) * 16 = 13,check 210 table
rUDIVSLOT0 = 0xdfdd;
}
void putc(char cdata)
{
//judge send buff is'not or is empty,then send data
while (!(rUTRSTAT0 & (1 << 1)));
rUTXH0 = cdata;
}
char getc()
{
//judge get buff is'not or is empty,then get data
while (!(rUTRSTAT0 & 1));
return (rURXH0 & 0x0f);
}
Makefile
CC = arm-linux-gcc
LD = arm-linux-ld
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump
AR = arm-linux-ar
INCDIR := $(shell pwd)
#C预处理器的flag,flag就是编译器可选的选项
CPPFLAGS := -nostdlib -nostdinc -I$(INCDIR)/include
#C编译器的flag
CFLAGS := -Wall -O2 -fno-builtin
#导出变量到全局,提供子给Makefile使用
export CC LD OBJCOPY OBJDUMP AR CPPFLAGS CFLAGS
objs := start.o uart.o main.o
objs += lib/libc.a
uart.bin: $(objs)
$(LD) -Ttext 0x0 -o uart.elf $^
$(OBJCOPY) -O binary uart.elf uart.bin
$(OBJDUMP) -D uart.elf > uart_elf.dis
gcc mkv210_image.c -o mkx210
./mkx210 uart.bin 210.bin
lib/libc.a:
cd lib; make; cd ..
%.o : %.S
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
%.o : %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
clean:
rm *.o *.elf *.bin *.dis mkx210 -f
cd lib; make clean; cd ..
printf