侵权投诉
搜索
更多>> 热门搜索:
订阅
纠错
加入自媒体

UART的原理以及驱动程序如何编写?

2020-12-30 15:21
一口Linux
关注

该寄存器通用配置为:

UCON2 = 0x5;  //Interrupt request or polling mode

一般裸机情况下,采用轮询模式。

UTRSTATn

UTRSTAT n寄存器用来表明数据是否已经发送完毕、是否已经接收到数据,格式如下图所示,上面说的“缓冲区”,其实就是下图中的 FIFO ,不使用 FIFO 功能时可以认为其深度为 1。

当我们读取数据时,就轮询检查bit[0]置1之后,然后再从URXHn寄存器读取数据;当我们读取数据时,就轮询检查bit[1]置1之后,然后再向UTXHn寄存器写入数据来发送数据;

UTXHn寄存器(UART TRANSMIT BUFFER REGISTER)   CPU 将数据写入这个寄存器, UART即会将它保存到缓冲区中,并自动发送出去。
URXHn寄存器(UART RECEIVE BUFFER REGISTER)  当 UART 接收到数据时,读取这个寄存器,即可获得数据。
UFRACVALn 计算波特率

根据给定的波特率、所选择时钟源频率,可以通过以下公式计算 UBRDIVn 寄存器 (n 为 0~4,对应 5个 UART 通道 )的值。

  UBRDIVn = (int)( UART clock / ( buad rate x 16) ) – 1

上式计算出来的 UBRDIVn 寄存器值不一定是整数, UBRDIVn 寄存器取其整数部分,小部分由 UFRACVALn 寄存器设置, UFRACVALn 寄存器的引入,使产生波特率更加精确。「【举例】」当UART clock为100MHz时,要求波特率为115200 bps,则:

  100000000/(115200 x 16) – 1 = 54.25 – 1 = 53.25
      UBRDIVn = 整数部分 = 53              
      UFRACVALn/16 = 小数部分 = 0.25
      UFRACVALn = 4

5)电路图

外设电路图:

SP3232EEA 用来将TTL电平转换成RS232电平。我们使用的是COM2。

外设与核心板连接电路图

可见UART的收发引脚连接到了GPA上,打开exynos4412芯片手册:

我们只需要将GPA1 的低8位设置为0x22。

6.实例代码

裸机代码,主要实现uart_init()、putc()、getc()这三个函数。

uart_init()

该函数主要配置UART的,波特率115200,数据位:8,奇偶校验位:0,终止位:1,不设置流控。

如下图:是运行在windows下常用的串口工具配置信息,配置信息必须完全一致。

putc()

该函数是向串口发送一个数据data,他的实现逻辑就是轮询检查寄存器UART2.UTRSTAT2 ,判断其bite【1】是否置1,如果置1,则向UART2.UTXH2存入要发送的数据即可。

getc()

该函数是从串口接收一个数据data,他的实现逻辑就是轮询检查寄存器UART2.UTRSTAT2 ,判断其bite【0】是否置1,如果置1,说明数据准备好,则可以从寄存器UART2.URXH2取出数据。

代码
* UART2

typedef struct {
   unsigned int ULCON2;
   unsigned int UCON2;
   unsigned int UFCON2;
   unsigned int UMCON2;
   unsigned int UTRSTAT2;
   unsigned int UERSTAT2;
   unsigned int UFSTAT2;
   unsigned int UMSTAT2;
   unsigned int UTXH2;
   unsigned int URXH2;
   unsigned int UBRDIV2;
   unsigned int UFRACVAL2;
   unsigned int UINTP2;
   unsigned int UINTSP2;
   unsigned int UINTM2;
}uart2;
#define UART2 ( * (volatile uart2 *)0x13820000 )
GPA1
typedef struct {
   unsigned int CON;
   unsigned int DAT;
   unsigned int PUD;
   unsigned int DRV;
   unsigned int CONPDN;
   unsigned int PUDPDN;
}gpa1;
#define GPA1 (* (volatile gpa1 *)0x11400020)
void uart_init()
{ UART2 initialize
GPA1.CON = (GPA1.CON & ~0xFF ) | (0x22); //GPA1_0:RX;GPA1_1:TX
UART2.ULCON2 = 0x3; //Normal mode, No parity,One stop bit,8 data bits
UART2.UCON2 = 0x5;  //Interrupt request or polling mode
//Baud-rate : src_clock:100Mhz
UART2.UBRDIV2 = 0x35;
UART2.UFRACVAL2 = 0x4;

void putc(const char data)
{ while(!(UART2.UTRSTAT2 & 0X2));
UART2.UTXH2 = data;
if (data == '')
  putc('');

char getc(void)
{ char data;
while(!(UART2.UTRSTAT2 & 0x1));
data = UART2.URXH2;
if ((data == '')||(data == ''))

  putc('');
  putc('');
}else
  putc(data);
return data;

puts/getsvoid puts(const  char  *pstr)
{ while(*pstr != '')
 putc(*pstr++);

void gets(char *p)
{ char data;
while((data = getc())!= '')
{  if(data == '')
 {p--;
 }
 *p++ = data;

if(data == '')
*p++ = '';
*p = '';

7.如何裸机程序可以支持printf函数

首先看下文件的目录结构:

代码架构

老规矩,关注,后台回复【armprintf】,就可以得到代码。

这里我们只贴出部分文件的代码。

「cpu/start.s」改文件主要是实现异常向量表,实现各个模式的栈初始化

.text
.global _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_handler
 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_handler
_fiq:     .word  _fiq
reset:
ldr r0,=0x40008000
mcr p15,0,r0,c12,c0,0  @ 协处理器指令设置异常向量表地址
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 @跳转到c语言的main函数
.align 4
***  swi_interrupt handler  ***
***  irq_handler  ***
irq_handler:
sub  lr,lr,#4
stmfd sp!,{r0-r12,lr}
.weak do_irq   @该函数可以没有定义
bl do_irq  @跳转到中断入口
ldmfd sp!,{r0-r12,pc}^
stacktop:    .word   stack+4*512 @定义栈顶
.data
stack:  .space  4*512  @分配一块栈空间

「lib/printf.c」

该文件主要实现打印函数printf一些格式控制,一些字符串转换算数运算需要借助头文件ctype.h、stdarg.h中一些宏。其中vsprintf 具体的实现我们就不再详解,有兴趣读者自行研究。

……
void printf (const char *fmt, ...)

va_list args;
unsigned int i;
char printbuffer[100];
va_start (args, fmt);
 For this to work, printbuffer must be larger than
 * anything we ever want to print.
 
i = vsprintf (printbuffer, fmt, args);//对输入的参数进行格式整理
va_end (args);
puts (printbuffer); //调用上一章我们封装的puts函数实现向串口打印书字符串

「main.c」该文件可以直接调用printf()函数来打印信息了。

void  delay_ms(unsigned int num)

   int i,j;
   for(i=num; i>0;i--)
for(j=1000;j>0;j--)
 ;

*  裸机代码,不同于LINUX 应用层, 一定加循环控制

int main (void)

int i = 0;
while (1) {
 printf("aaaaaaaaaaaaa");
 delay_ms(500);

  return 0;

「Makefile」

CROSS_COMPILE = arm-none-eabi-
NAME =gcd
CFLAGS=-mfloat-abi=softfp -mfpu=vfpv3 -mabi=apcs-gnu -fno-builtin  -fno-builtin-function -g -O0 -c  -I ./include -I ./lib                                                  
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
OBJS=./cpu/start.o ./driver/uart.o  
       ./driver/_udivsi3.o ./driver/_divsi3.o ./driver/_umodsi3.o main.o ./lib/printf.o
#=============================================================================#
all:  $(OBJS)
$(LD)  $(OBJS) -T map.lds -o $(NAME).elf
$(OBJCOPY)  -O binary  $(NAME).elf $(NAME).bin
$(OBJDUMP) -D $(NAME).elf > $(NAME).dis
%.o: %.S
$(CC) $(CFLAGS) -c -o  $@ $<
%.o: %.s
$(CC) $(CFLAGS) -c -o  $@ $<
%.o: %.c
$(CC) $(CFLAGS) -c -o  $@ $<
clean:
rm -rf $(OBJS) *.elf *.bin *.dis *.o

Makefile、map.lds 参考《7. 从0开始学ARM-GNU伪指令、代码编译,lds使用》

后续我们都会在这个模板上来编写其他硬件的驱动代码。

<上一页  1  2  3  
声明: 本文由入驻维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。

发表评论

0条评论,0人参与

请输入评论内容...

请输入评论/评论长度6~500个字

您提交的评论过于频繁,请输入验证码继续

暂无评论

暂无评论

工控 猎头职位 更多
文章纠错
x
*文字标题:
*纠错内容:
联系邮箱:
*验 证 码:

粤公网安备 44030502002758号