串口设备的裸机驱动开发
{
1、明确需求: 谁(com2) 做什么(发送'S')
2、看原理图:
1)原理: XuTXD2 ---> 数据发送
2)控制芯片: XuTXD2 ---》 GPA1_1------》uart(串口)控制器
|
|------> GPIO控制器(设置成串口发送的专用脚)
3、芯片手册(寄存器)
【GPIO】
GPA1CON 0x11400020 [7:4] 0x2 = UART_2_TXD
GPA1CON 0x11400020 [3:0] 0x2 = UART_2_RXD
【uart】
1)通过目录找到控制器章节
28章节
2)看看子章节和需求相关的部分
概述看,需求功能相关看。
a)串口有5路,4路是标准的串口(com2)。每个串口发送和接收buf。
b)串口包含的内容: 波特率发生器, 发送接收单元, 停止位,校验位,数据位c)发送流程: data-->fifo --> shifter --> txpin
|----人-||-------uart控制器-----|
d)fifo: fifo:all bytes no fifo:1 byte (选择)
e)ULCONn: 设置数据位、校验位、停止位
f)clk:UBRDIVn UFRACVALn3)看寄存器
a)筛选寄存器(ctrl和config要,功能相关要,不确定的要)
ULCON: 设置停止位、数据位、校验位
UCON:全局控制
UTXH:发送的fifo
UBRDIV:波特率分频
UFRACVAL:分频???b)细看寄存器,怎么实现需求
ULCONn = 0x3;
UCONn [3:2] 01 tx poll mode [1:0] 01 rx poll mode
UTXHn: 把数据写入,就发送, 最多只能8位的数据
URXHn: 从里面读数据 ok 最多只能读8位数据
40MHZ = 40000000 40MHZ/(115200*16)-1 115200:波特率的位/秒
UBRDIVn: 整数
UFRACVALn: 小数*16}
all: arm-linux-gcc myadd.S -o start.o -c -g arm-linux-gcc main.c -o main.o -c -g arm-linux-ld start.o main.o -o start.elf -Ttest.lds arm-linux-objcopy start.elf start.bin -O binary
汇编通用脚本 myadd.S:
.globl _start _start: b reset ldr pc, _undefined_instruction 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: /* 设置cpu模式为SVC模式 */ mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr,r0 /* 设置异常向量表起始地址 */ ldr r0, =0x41000000 mcr p15, 0, r0, c12, c0, 0 @Set VBAR /*用户需要设置的初始化*/ ldr sp, stacktop /*设置svc sp*/ sub r6, sp , #64 /*计算user需要指向的栈顶地址*/ /*切换到用户模式*/ mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0x10 msr cpsr,r0 mov sp, r6 /*设置user sp*/ /*跳转到应用程序*/ bl main stack: .space 64*8 stacktop: .word stack+64*8
连接汇编和c的脚本 test.lds:
ENTRY(_start) SECTIONS{ . = 0x41000000; .text : { start.o(.text) *(.text) } .data : { *(.data) } .bss : { *(.bss) } }
main.c:
#define GPA1CON *(unsigned int volatile*)0x11400020 #define ULCON2 *(unsigned int volatile*)0x13820000 #define UCON2 *(unsigned int volatile*)0x13820004 #define UTXH2 *(unsigned int volatile*)0x13820020 #define URXH2 *(unsigned int volatile*)0x13820024 #define UBRDIV2 *(unsigned int volatile*)0x13820028 #define UFRACVAL2 *(unsigned int volatile*)0x1382002c #define UTRSTAT2 *(unsigned int volatile*)0x13820010 //自定义睡眠函数 void delay(){ int t = 0xfffff; while(t--); } void uart_init(){ //波特率发生器 //GPA1CON 0x11400020 [7:4] 0x2 = UART_2_TXD 发送 GPA1CON = GPA1CON & ~(0xf<<4) | (0x2<<4); //GPA1CON 0x11400020 [3:0] 0x2 = UART_2_RXD 接收 GPA1CON = GPA1CON & ~(0xf<<0) | (0x2<<0); //指定数据位有几位,这里是8位 ULCON2 = 0x3; //全局控制,清除0-5位待用,0x1<<2:轮询发送 <<0:轮询接收 UCON2 = UCON2 & ~0x3f | (0x1<<2) | (0x1<<0); //100MHZ = 100000000 100MHZ/(115200*16)-1 115200:波特率的位/秒 UBRDIV2 = 53; UFRACVAL2 = 4; } void uart_send(char c){ //检测有效数据,防止无效数据的发送 //当传输buf无有效数据传输,且传输移位为空时,该位自动设置为1 while( !(UTRSTAT2&(0x1<<2)) ); UTXH2 = c; } void uart_str(char *s){ while(*s!='\0'){ uart_send(*s); s++; } } char uart_recv(){ //检测有效数据 //当接收buf含通过RXDn端口接收的有效数据时,自动将该位设置为1 while( !(UTRSTAT2&0x1) ); //接收数据位为8位 return (URXH2 & 0xff); } void main() { #if 0 char c = 'S'; uart_init(); uart_send(c); #endif #if 1 char *s = "hello"; uart_init(); uart_str(s); //引入按键输入的字符 while(1){ char c = uart_recv(); uart_send(c); } #endif while(1); }