arm 通讯接口


串行通讯
- 单线
- 双线 uart (全双工 异步)
- 双线 i2c (半双工 同步)
- 三线 spi (全双宫 同步)
并行通讯
- 多跟数据线,地址线,如内存
查引脚

我们使用串口II,中间的这个
我们接下来看cpu哪个引脚连着串口II


搜索
查询cpu的引脚

这个引脚不一定只能做串口
这个除了输入输出,还能做串口
做串口发送输出
看手册
这颗板子支持4个UART,但是我们只使用了三个

这个引脚叫GPA1_0和GPA1_1
搜一下GPA1
配置寄存器
配置到串口模式
1_1在手册里面是
GPA1CON[1]
之前控制灯我们设置为输出模式
现在我们设置为串口模式
0x2 = UART_2_TXD
同理,我们接受也是一样的
模板
main.c
/*
功能: 实现通过串口com2 输出字符显示
1. 看电路图找到CPU对应的控制管脚 GPA1_1 GPA1_0
2. 看芯片手册,找到对应寄存器
a. 配置管脚为串口模式
b. 功能块设置
3. 编程
*/
int main(void)
{
return 0;
}
Makefile:
all:
arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o start.o start.S
arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o main.o main.c
arm-none-linux-gnueabi-ld start.o main.o -Tmap.lds -o uart.elf
arm-none-linux-gnueabi-objcopy -O binary uart.elf uart.bin
arm-none-linux-gnueabi-objdump -D uart.elf > uart.dis
clean:
rm -rf *.bak start.o main.o uart.elf uart.bin uart.dis
start.s
.global delay1s
.text
.global _start
_start:
b reset @0x00
ldr pc,_undefined_instruction @0x04
ldr pc,_software_interrupt
ldr pc,_prefetch_abort
ldr pc,_data_abort
ldr pc,_not_used
ldr pc,_irq
ldr pc,_fiq
_undefined_instruction: .word _undefined_instruction
_software_interrupt: .word _software_interrupt
_prefetch_abort: .word _prefetch_abort
_data_abort: .word _data_abort
_not_used: .word _not_used
_irq: .word _irq
_fiq: .word _fiq
reset:
ldr r0,=0x40008000 @设置异常向量表的启始地址为 0x40008000
mcr p15,0,r0,c12,c0,0 @ Vector Base Address Register
init_stack:
ldr r0,stacktop /*get stack top pointer*/
/********svc mode stack********/
mov sp,r0
sub r0,#128*4 /*512 byte for irq mode of stack*/
/****irq mode stack**/
msr cpsr,#0xd2
mov sp,r0
sub r0,#128*4 /*512 byte for irq mode of stack*/
/***fiq mode stack***/
msr cpsr,#0xd1
mov sp,r0
sub r0,#0
/***abort mode stack***/
msr cpsr,#0xd7
mov sp,r0
sub r0,#0
/***undefine mode stack***/
msr cpsr,#0xdb
mov sp,r0
sub r0,#0
/*** sys mode and usr mode stack ***/
msr cpsr,#0x10
mov sp,r0 /*1024 byte for user mode of stack*/
b main
delay1s:
ldr r4,=0x1ffffff
delay1s_loop:
sub r4,r4,#1
cmp r4,#0
bne delay1s_loop
mov pc,lr
.align 4
/**** swi_interrupt handler ****/
stacktop: .word stack+4*512
.data
stack:
.space 4*512
.end
map.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x40008000; /*指定链接的起始地址 */
. = ALIGN(4);
.text :
{
start.o(.text)
*(.text)
}
. = ALIGN(4);
.data :
{ *(.data) }
. = ALIGN(4);
.bss :
{ *(.bss) }
}
实现
#define GPA1CON (*(volatile unsigned int *)*0x11400020)
void uart_init(void)
{
//1. 配置pin GPA1_1 和 GPA1_0 为串口模式
//*0x11400020 = 0x22
GPA1CON = 0x22;
}设置串口相关功能



Transmit Shifter 移位寄存器
Buad-rate Generator 波特率

为什么这里有这么多基地址,因我我们有0-3个com口
ULCONn 线控
28.6.1.1 ULCONn (n = 0 to 4)
Base Address: 0x1380_0000, 0x1381_0000, 0x1382_0000, 0x1383_0000, 0x1384_0000
Address = Base Address + 0x0000, Reset Value = 0x0000_0000
Word Length 字长
表示每一帧发送的位数
Indicates the number of data bits UART transmits or receives
per frame.
00 = 5 bits
01 = 6 bits
10 = 7 bits
11 = 8 bits
Number of Stop Bit 停止位
Specifies how many stop bits UART uses to signal end-offrame signal.
0 = One stop bit per frame
1 = Two stop bit per frame
Parity Mode 校验位
Specifies the type of parity that UART generates and checks
during UART transmit and receive operation.
0xx = No parity
100 = Odd parity
101 = Even parity
110 = Parity forced/ checked as 1
111 = Parity forced/ checked as 0
UCONn 串口控制寄存器
28.6.1.2 UCONn (n = 0 to 4)
Base Address: 0x1380_0000, 0x1381_0000, 0x1382_0000, 0x1383_0000, 0x1384_0000
Address = Base Address + 0x0004, Reset Value = 0x0000_0000



Receive Mode 采用什么方式读取
Determines which function is able to Read data from UART
receive buffer.
00 = Disables
01 = Interrupt request or polling mode
10 = DMA mode
11 = Reserved
这里使用 polling mode
Transmit Mode
传输模式
Determines which function is able to Write Tx data to the
UART transmit buffer.
00 = Disables
01 = Interrupt request or polling mode
10 = DMA mode
11 = Reserved
这里也选择 polling mode
register map summary
ULCONn 线控
UCONn 接受模式
UBRDIVn 设置速率 设置波特率
UFRACVALn 设置速率 波特率的分频值
UBRDIVn
28.6.1.11 UBRDIVn (n = 0 to 4)
Base Address: 0x1380_0000, 0x1381_0000, 0x1382_0000, 0x1383_0000, 0x1384_0000
Address = Base Address + 0x0028, Reset Value = 0x0000_0000

28.6.1.12 UFRACVALn (n = 0 to 4)
Base Address: 0x1380_0000, 0x1381_0000, 0x1382_0000, 0x1383_0000, 0x1384_0000
Address = Base Address + 0x002C, Reset Value = 0x0000_0000

1. UART Baud-Rate Configuration
You can use the value stored in the Baud-rate divisor (UBRDIVn) and divisor fractional value (UFRACVALn)
to determine the serial Tx/Rx clock rate (Baud rate) as:
DIV_VAL = UBRDIVn + UFRACVALn/16
or
DIV_VAL = (SCLK_UART/(bps 16)) 1
Where, the divisor should be from 1 to (216 – 1).
By using UFRACVALn, you can generate the Baud rate more accurately.
For example, if the Baud rate is 115200 bps and SCLK_UART is 40 MHz, UBRDIVn and UFRACVALn are:
DIV_VAL = (40000000/(115200 * 16)) – 1
= 21.7 – 1
= 20.7
UBRDIVn = 20 (integer part of DIV_VAL)
UFRACVALn/16 = 0.7
Therefore, UFRACVALn = 11
2. Baud-Rate Error Tolerance
UART Frame error should be less than 1.87 % (3/160)
tUPCLK = (UBRDIVn + 1 + UFRACVAL/16) 16 1Frame/SCLK_UART
tUPCLK = Real UART Clock
tEXTUARTCLK = 1Frame/baud-rate
tEXTUARTCLK = Ideal UART Clock
UART error = (tUPCLK tEXTUARTCLK)/tEXTUARTCLK 100 %
* 1Frame = start bit + data bit + parity bit + stop bit.
3. UART Clock and PCLK Relation
There is a constraint on the ratio of clock frequencies for PCLK to UARTCLK.
The frequency of UARTCLK must be no more than 5.5/3 times faster than the frequency of PCLK:
FUARTCLK 5.5/3 FPCLK
FUARTCLK = baudrate 16这样就有足够的时间将接收到的数据写入接收FIFO。时钟框图:

PERI-L 左外设
UTXHn 指定传输缓冲区
28.6.1.9 UTXHn (n = 0 to 4)
Base Address: 0x1380_0000, 0x1381_0000, 0x1382_0000, 0x1383_0000, 0x1384_0000
Address = Base Address + 0x0020, Reset Value = 0x0000_0000
UTRSTATn 指定缓冲区状态
28.6.1.5 UTRSTATn (n = 0 to 4)
Base Address: 0x1380_0000, 0x1381_0000, 0x1382_0000, 0x1383_0000, 0x1384_0000
Address = Base Address + 0x0010, Reset Value = 0x0000_0000
检测状态是否为空
设置不同模式
#define GPA1CON (*(volatile unsigned int *)*0x11400020)
#define ULCON2 (*(volatile unsigned int *)*0x13820000)
#define UCON2 (*(volatile unsigned int *)*0x13820004)
#define UBRDIV2 (*(volatile unsigned int *)*0x13820028)
#define UFRACVAL2 (*(volatile unsigned int *)*0x1382002C)
#define UTXH2 (*(volatile unsigned int *)0x13820020)
#define UTRSTAT2 (*(volatile unsigned int *)0x13820010)
void uart_init(void)
{
//1. 配置pin GPA1_1 和 GPA1_0 为串口模式
//*0x11400020 = 0x22
GPA1CON = 0x22;
//2. 设置窗口控制块
//set data bit = 8, parity = none, stop = 1
ULCON2 = 0x03;
//3. set polling mode
UCON2 = 0x05;
/*
设置波特率 = 115200
DIV_VAL = (40000000/(115200 16)) – 1
= 53.253
UBRDIV2 = 50;
UFRACVAL2 = 0.253 * 16 = 4
*/
UBRDIV2 = 53;
UFRACVAL2
}模拟输出
void putc(char c)
{
while(1)
{
//只判断1号位是否为1
if( UTRSTAT2&0x02)
break;
}
UTXH2 = c;
}
int main(void)
{
uart_init()
while(1)
{
putc('a');
delay1s();
}
return 0;
}Makefile
all:
arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o start.o start.S
arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o main.o main.c
arm-none-linux-gnueabi-ld start.o main.o -Tmap.lds -o uart.elf
arm-none-linux-gnueabi-objcopy -O binary uart.elf uart.bin
arm-none-linux-gnueabi-objdump -D uart.elf > uart.dis
clean:
rm -rf *.bak start.o main.o uart.elf uart.bin uart.dis
先将两个文件编译
arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o start.o start.S
arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o main.o main.c指定链接脚本链接并转成二进制
arm-none-linux-gnueabi-ld start.o main.o -Tmap.lds -o uart.elfmap.lds
链接脚本指定最终目标文件地址
指定代码段地址
指定输出的格式
elf32文件格式以小端输出
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")最终输出的是arm系列cpu
OUTPUT_ARCH(arm)ENTRY(_start) //链接后的第一条指令所在的地址*(.text) //系统自动安排下面的地址点表示当前位置
. = 0x40008000; /*指定链接的起始地址 */. = ALIGN(4); 表示对齐
.text 表示代码段开始
.data 表示数据段开始
程序入口在start.s
中断异常向量表
ldr pc,_undefined_instruction @0x04
ldr pc,_software_interrupt
ldr pc,_prefetch_abort
ldr pc,_data_abort
ldr pc,_not_used
ldr pc,_irq
ldr pc,_fiq
_undefined_instruction: .word _undefined_instruction
_software_interrupt: .word _software_interrupt
_prefetch_abort: .word _prefetch_abort
_data_abort: .word _data_abort
_not_used: .word _not_used
_irq: .word _irq
_fiq: .word _fiq

通过b指令跳转到c文件
c程序想要调用,需要声明全局
.global delay1s 和普通函数用法一样