• Tiny6410之UART裸机驱动


    UART简介:

      UART(Universal Asynchronous Receiver and Transmitter)通用异步收发器(异步串行通信口),是一种通用的数据通信协议,它包括了RS232、RS499、RS423、RS422和RS485等接口标准规范和总线标准规范,即UART是异步串行通信口的总称。而RS232、RS499、RS423、RS422和RS485等,是对应各种异步串行通信口的接口标准和总线标准,它规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容,这些东东都是物理层的概念。通信协议,是属于通信网络中的数据链路层的概念。
    一、数据传输流程:
      1)平时数据线处于“空闲”状态(1状态)
      2)当腰发送数据时,UART改变TxD数据线状态(0状态)并维持一位的时间,这样接收方检测到开始位后。再等1.5位的时间就开始一位一位的检测数据线状态得到所传输的数据。
      3)UART一帧中可以有5,6,7,或8位的数据,发送方一位一位的改变数据线的状态,将他们发送出去,首先发送最低位。
      4)如果使用校验功能UART在发送完数据后还要发送一校验位,有两种校验方式,奇校验和偶校--数据位连同校验位中,“1”的数目等于奇数或偶数
      5)最后发送停止位,数据线状态恢复到“空闲”状态(1状态)停止位的状态有三种1位,1.5位,2位。

        起始位:先发出一个逻辑”0”信号,表示传输字符的开始。
        数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。小端传输
        校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验)
        停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
        空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。
        
    二、操作步骤:
      第一步:配置引脚


      通过硬件原理图可以知道使用的是MAX3232SOP芯片 使用的是TX0 和RXD0 对应的配置寄存器是GPA通过数据手册可知GPA的地址及每位所代表的意义。通过数据手册可以知道通过配置GPACON的相应管脚就可以将其设置为UART功能。


      Register       Address
        GPACON   0x7F008000   

    GPA0  [3:0]        0000 = Input              0001 = Output
                             0010 = UART RXD[0]  0011 = Reserved
                             0100 = Reserved        0101 = Reserved
                             0110 = Reserved        0111 = External Interrupt Group 1 [0]
                                
    GPA1  [7:4]        0000 = Input              0001 = Output
                             0010 = UART TXD[0]  0011 = Reserved
                             0100 = Reserved        0101 = Reserved
                             0110 = Reserved        0111 = External Interrupt Group 1 [1]

    故只需要将GPACON的第八位赋值成 0x00100010即可将GPA配置成UART

    第二步:设置数据格式
      由数据手册可知uart数据帧发送是可编程的。它由一个起始位,5~8 个数据位,一个可选的奇偶位和 1~2 个可由行控制寄存器(ULCONn )指定的停止位组成。发送器也可以产生中断条件,在传输过程中,它通过置位逻辑状态 0 来强制串行输出。当目前的发送完全传输完成后,发送中断信号。然后不断传送数据到发送 FIFO 寄存器(在非 FIFO 的模式下,发送保存寄存器。)

    word length = 11,8bit的数据

    Number of Stop Bit = 0;1bit的停止位

    Parity Mode = 000;无校验位

    Intfrared Mode =0;使用普通模式

    所以ULCON0 = 0x3;

    第三步:UART配置

     

    Receive Mode = 01;使用中断模式或轮询模式、

    Transmit Mode = 01;使用中断模式或轮询模式

    Send Break Signal = 0;普通传输

    loop-back Mode = 0;使用回环方式

    Clock Selection = 0;使用PCLK作为UART的工作时钟

    所以UCON =0x5;UFCON0 用来使能FIFO,UMCON0用来设置无留控

    第三步:设置波特率
      波特率即每秒传输的数据位数,涉及两个寄存器UBRDIV0和UDIVSLOT0

    波特率设置相关公式:DIV_VAL = UBRDIVn + (num of 1’s in UDIVSLOTn)/16. Refer to UART Baud Rate Configure Registers.

    PCLK = 66.5MHZ 波特率bps设置为115200。所以(66.5MHZ、(115200*16))-1 =35.08 =UBRDIVn + (num of 1’s in UDIVSLOTn)/16。故设置UBRDIV0 = 35,UDIVSLOT0 = 0x1;

     第四步:编码

      1 //start.S
      2 // 启动代码
      3 .global _start
      4 
      5 _start:
      6 
      7     // 把外设的基地址告诉CPU
      8     ldr r0, =0x70000000                     
      9     orr r0, r0, #0x13                    
     10     mcr p15,0,r0,c15,c2,4                
     11     
     12     // 关看门狗
     13     ldr r0, =0x7E004000
     14     mov r1, #0
     15     str r1, [r0] 
     16     
     17     // 设置栈
     18     ldr sp, =0x0C002000
     19     
     20     // 开启icaches
     21 #ifdef  CONFIG_SYS_ICACHE_OFF
     22     bic r0, r0, #0x00001000                 @ clear bit 12 (I) I-cache
     23 #else
     24     orr r0, r0, #0x00001000                 @ set bit 12 (I) I-cache
     25 #endif
     26     mcr p15, 0, r0, c1, c0, 0
     27 
     28     // 设置时钟
     29     bl clock_init
     30     
     31     // 调用C函数点灯
     32     bl main
     33     
     34 halt:
     35     b halt    
     36 //Tiny6410Addr.h
     37 #ifndef _Tiny6410Addr_H
     38 #define _Tiny6410Addr_H
     39 //GPK 
     40 #define GPKIO_BASE (0x7F008800)
     41 #define rGPKCON0 (*((volatile unsigned long *)(GPKIO_BASE+0x00)))
     42 #define rGPKDAT  (*((volatile unsigned long *)(GPKIO_BASE+0x08)))
     43 
     44 //CLOCK
     45 #define APLL_LOCK (*((volatile unsigned long *)0x7E00F000))
     46 #define MPLL_LOCK (*((volatile unsigned long *)0x7E00F004))
     47 #define EPLL_LOCK (*((volatile unsigned long *)0x7E00F008))
     48 #define OTHERS     (*((volatile unsigned long *)0x7E00F900))
     49 #define CLK_DIV0  (*((volatile unsigned long *)0x7E00F020))
     50 #define APLL_CON  (*((volatile unsigned long *)0x7E00F00C))
     51 #define MPLL_CON  (*((volatile unsigned long *)0x7F00F010))
     52 #define CLK_SRC   (*((volatile unsigned long *)0x7E00F01C))
     53 
     54 //GPA /uart
     55 #define ULCON0     (*((volatile unsigned long *)0x7F005000))
     56 #define UCON0      (*((volatile unsigned long *)0x7F005004))
     57 #define UFCON0     (*((volatile unsigned long *)0x7F005008))
     58 #define UMCON0     (*((volatile unsigned long *)0x7F00500C))
     59 #define UTRSTAT0   (*((volatile unsigned long *)0x7F005010))
     60 #define UFSTAT0    (*((volatile unsigned long *)0x7F005018))
     61 #define UTXH0      (*((volatile unsigned char *)0x7F005020))
     62 #define URXH0      (*((volatile unsigned char *)0x7F005024))
     63 #define UBRDIV0    (*((volatile unsigned short *)0x7F005028))
     64 #define UDIVSLOT0  (*((volatile unsigned short *)0x7F00502C))
     65 #define GPACON     (*((volatile unsigned long *)0x7F008000))
     66 
     67 
     68 
     69 #endif
     70 
     71 
     72 
     73 //uart.c
     74 // 功能:初始化串口
     75 #include "uart.h" 
     76 #include "Tiny6410Addr.h"
     77 
     78 
     79 void uart_init(void)
     80 {
     81     /* 1. 配置引脚 */
     82     GPACON &= ~0xff;
     83     GPACON |= 0x22;
     84     
     85     /* 2. 设置数据格式等 */
     86     ULCON0 = 0x3;                      // 数据位:8, 无校验, 停止位: 1, 8n1 
     87     UCON0  = 0x5;                      // 时钟:PCLK,禁止中断,使能UART发送、接收 
     88     UFCON0 = 0x01;                     // FIFO ENABLE
     89     UMCON0 = 0;                        // 无流控
     90     
     91     /* 3. 设置波特率 */
     92     // DIV_VAL = (PCLK / (bps x 16 ) ) - 1 = (66500000/(115200x16))-1 = 35.08
     93     // DIV_VAL = 35.08 = UBRDIVn + (num of 1’s in UDIVSLOTn)/16 
     94     UBRDIV0   = 35;
     95     UDIVSLOT0 = 0x1;
     96     
     97 }
     98 
     99 /* 接收一个字符 */
    100 char get_char(void)
    101 {
    102     while ((UFSTAT0 & 0x7f) == 0);  // 如果RX FIFO空,等待 
    103     return URXH0;                   // 取数据 
    104 }
    105 
    106 /* 发送一个字符 */
    107 void put_char(char c)
    108 {
    109     while (UFSTAT0 & (1<<14));         // 如果TX FIFO满,等待 
    110     UTXH0 = c;                      // 写数据 
    111 }
    112 
    113 
    114 //uart.h
    115 char get_char(void);
    116 void put_char(char c);
    117 void init_uart(void);
    118 
    119 //clock.c
    120 #include "Tiny6410Addr.h"
    121 // 功能:c语言初始化时钟
    122  
    123 
    124 #define ARM_RATIO    0                           // ARMCLK     = DOUTAPLL / (ARM_RATIO + 1)      = 532/(0+1) = 532  MHz
    125 #define MPLL_RATIO   0                           // DOUTMPLL = MOUTMPLL / (MPLL_RATIO + 1)   = 532/(0+1) = 532  MHz
    126 #define HCLKX2_RATIO 1                           // HCLKX2     = HCLKX2IN / (HCLKX2_RATIO + 1) = 532/(1+1) = 266  MHz
    127 #define HCLK_RATIO   1                           // HCLK     = HCLKX2   / (HCLK_RATIO + 1)   = 266/(1+1) = 133  MHz
    128 #define PCLK_RATIO   3                           // PCLK       = HCLKX2   / (PCLK_RATIO + 1)   = 266/(3+1) = 66.5 MHz
    129 
    130 
    131  
    132 #define APLL_CON_VAL  ((1<<31) | (266 << 16) | (3 << 8) | (1))
    133 
    134  
    135 #define MPLL_CON_VAL  ((1<<31) | (266 << 16) | (3 << 8) | (1))
    136 
    137  
    138 
    139 void clock_init(void)
    140 {    
    141     /* 1. 设置各PLL的LOCK_TIME,使用默认值 */
    142     APLL_LOCK = 0xffff;                            // APLL_LOCK,供cpu使用 
    143     MPLL_LOCK = 0xffff;                            // MPLL_LOCK,供AHB(存储/中断/lcd等控制器)/APB(看门狗,定时器,SD等)总线上的设备使用
    144     EPLL_LOCK = 0xffff;                            // EPLL_LOCK,供UART,IIS,IIC使用 
    145 
    146     /* 2. 设置为异步模式(Asynchronous mode) */
    147     OTHERS &= ~0xc0;                            //《linux installation for u-boot》3.7中:用MPLL作为HCLK和PCLK的Source是异步(ASYNC)模式,用APLL是同步(SYNC)模式
    148     while ((OTHERS & 0xf00) != 0);
    149 
    150     /* 3. 设置分频系数 */
    151     CLK_DIV0 = (ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_RATIO << 12);
    152 
    153     /* 4. 设置PLL,放大时钟 */    
    154     APLL_CON = APLL_CON_VAL;  
    155     MPLL_CON = MPLL_CON_VAL;  
    156 
    157     /* 5. 选择PLL的输出作为时钟源 */
    158     CLK_SRC = 0x03;
    159 }
    160 
    161 //main.c
    162 #include "uart.h"
    163 int main()
    164 {
    165     char c;
    166     uart_init();
    167     while(1)
    168     {
    169         c= get_char();
    170         put_char(c+1);
    171     }
    172     
    173     return 0;
    174     }
    175 
    176 //Makefile
    177 uart.bin : start.o clock.o main.o uart.o
    178     arm-linux-ld -Ttext 0x50000000 -o uart.elf start.o clock.o main.o uart.o
    179     arm-linux-objcopy -O binary uart.elf uart.bin
    180     arm-linux-objdump -D uart.elf > uart.dis
    181     
    182 %.o : %.S
    183     arm-linux-gcc -g -c -O2 -o $@ $^
    184     
    185 %.o : %.c
    186     arm-linux-gcc -g -c -O2 -o $@ $^
    187 .PHONY:clean
    188 clean:
    189     rm *.o *.elf *.bin *.dis
    View Code


        

    海阔凭鱼跃,天高任鸟飞。
  • 相关阅读:
    shell 案例
    linux 软链接和硬链接区别
    mac安装使用nginx
    Leetcode SQL_#176_第二高的薪水
    南邮ctf web题记录(上)
    CTFHub Web技能树
    XCTF web 新手练习区
    诊断工具--arthas使用教程
    prometheus--监控工具
    无状态状态机--cola stateMachine
  • 原文地址:https://www.cnblogs.com/chenshikun/p/5840106.html
Copyright © 2020-2023  润新知