1-14 串口在S3C2440上的原理、配置与驱动实现

来源:互联网 发布:the zen of python 编辑:程序博客网 时间:2024/05/17 23:31

(本节笔记的具体实验代码,在这里:https://github.com/elvinsys/arm_tq2440/tree/master/1_uboot/1-14.serial)


一、  基本概念

    1.  作用:作为数据传输的途径,或者作为控制台来提供用户对设备的控制方式

    2.  通讯格式的几个概念

        2.1  波特率:每秒传输bit的个数,常用的波特率有38400/115200

        2.2  常用的参数:

            起始位:当线路空闲时,电平为高,一旦检测到一个下降沿,则视为一个起始位

            数据位:一帧中实际有效的数据的位数

            校验位:用于检测数据传输的正确性

            停止位:表示这帧数据的结束

    3.  引脚:

        RS232——9针引脚串口

        2 : RXD : 接收脚

        3 : TXD  : 发送脚

        5 : GND : 接地脚


二、  串口驱动程序设计

    1.  串口初始化——    void uart_init()

        (先touch uart.c,把uart.o加入到Makefile中)

        查看底板原理图和核心板原理图可得知:

        TXD0 : TXD0 / GPH2

        RXD0: RXD0 / GPH3

        1.1  配置引脚功能:GPHCON  0x5600 0070

                GPH2    [5:4]    10    :    TXD[0]

                GPH3    [7:6]    10    :    RXD[0]

        1.2  设置串口数据格式:ULCON0  0x5000 0000

Word Length[1:0]11设定为8bitNumber of stop[2]0one stop bit 1位停止位Parity Mode[5:3]0XXNo Parity 无校验

        1.3  设置串口工作模式:UCON0  0x5000 0004

        (若在操作系统的支持下,可选择使用中断或DMA模式,但在bootloader中,一般采用轮询的工作模式)

Receive Mode[3:2]01polling modeTransmit Mode[1:0]01polling mode        1.4  设置UART波特率(UART BAUD RATE DIVISOR REGISTER)

            公式是:UBRDIVn = (int)(UART clock / (buad rate x 16) -1)

            UBRDIV0  R/W  0x5000 0028

            UART clock = PCLK = 50MHZ

            (#define PCLK 500 0000)

            (#define BAUD 115200)

            UBRDIV0 = (int)(PCLK / (BAUD X 16)-1);


    2.  发送数据——void putc (unsigned char ch)

        2.1  检查UTRSTAT0  R  0x5000 0010

Transmitter empty[2]0Not empty  等待同上同上1empty  发送        2.2  发送到UTXH0  W  0x5000 0020                 (UART TRANSMIT BUFFER REGISTER)

              UTXH0 = ch;

    3.  接收数据——unsigned char getc(void)

        3.1  检查UTRSTAT0  R  0x5000 0010

Receive buffer data ready[0]0Empty   等待  1has data  接收   
        3.2  从URXH0  R  0x5000 0024    (UART RECEIVE BUFF REGISTER)

               return URXH0;

    4.  把uart_init()加入到main.c中,并加入如下代码进行测试:

        /*  加入回车换行符的ASCII码  */

            putc(0x0d);

            putc(0x0a);
        /*  加入输出一个大写字母“H”  */

            putc('H');

    5.  添加控制台回显功能

        5.1  在main.c中删除以上三行测试代码,在while(1)中加入getc(),让程序不断检测自PC断输入的字符。

        5.2  修改usrt.c中的接受收据的函数,代码如下:

unsigned char getc(void)
{
unsigned char ret;
while(!(UTRSTAT0 & (1<<0)));
ret = URXH0;
if((ret == 0x0d) || (ret == 0x0a))
{
putc(0x0d);
putc(0x0a);
}
else
{
putc(ret);
}
return ret;
}

    6.  发送一个字符串的函数,在uart.c中加入如下代码:

void uart_send_string(char * str)

{

    while(*str)

    {

        putc(&str++);

    }

    putc(0x0d);

    putc(0x0a);

}


    7.  整个uart.c的实验代码如下:

#define ULCON0   (*(volatile unsigned char *)0x50000000)
#define UCON0    (*(volatile unsigned char *)0x50000004)
#define UTRSTAT0 (*(volatile unsigned char *)0x50000010)
#define UTXH0    (*(volatile unsigned char *)0x50000020)
#define URXH0    (*(volatile unsigned char *)0x50000024)
#define UBRDIV0  (*(volatile unsigned long *)0x50000028)
#define GPHCON   (*(volatile unsigned long *)0x56000070)


#define PCLK 50000000
#define BUAD 115200


void uart_init(void)    /*  初始化串口  */
{
//配置GPIO口,查表得TXD0=GPH2,RXD0=GPH3
    GPHCON &= ~((0x3<<4)|(0x3<<6));
    GPHCON |= ((0x2<<4)|(0x2<<6));

//配置ULCON0
    ULCON0 = 0x03;

//配置UCON0
    UCON0 = 0x09;   /*  这里必须设置为0x09,也就是0b1001,否则后面DMA实验会出错  */

//设置波特率
    UBRDIV0 = (int)(PCLK/(BUAD*16)-1);
}


void putc(unsigned char ch)  /*  发送一个字符  */
{
    while(!(UTRSTAT0 & (1<<2)));
    UTXH0 = ch;
}


unsigned char getc(void)    /*  回显功能  */
{
    unsigned char ret;
    while(!(UTRSTAT0 & (1<<0)));
    ret = URXH0;
    if((ret == 0x0d) || (ret == 0x0a))
    {
        putc(0x0d);
        putc(0x0a);
    }
    else
    {
        putc(ret);
    }
    return ret;
}

void uart_send_string(char * str)  /*  发送一个字符串用作测试  */

{

    while(*str)

    {

        putc(&str++);

    }

    putc(0x0d);

    putc(0x0a);

}


三、  建立S3C2440开发板基于串口的控制台

    1.  大建控制台框架,在main.c中加入如下while(1)代码:

while(1)
{
printf("\n****************************************\n\r");
printf("\n*****************GBOOT******************\n\r");
printf("1:Download Linux Kernel from TFTP Server!\n\r");
printf("2:Boot Linux from RAM !\n\r");
printf("3:Boot Linux from Nand Flash !\n\r");
printf("\nPlease Select : ");

scanf("%d", &num);

switch (num)
{
case 1:
printf("selected 1 !\n\r");
break;
case 2:
printf("selected 2 !\n\r");
break;
case 3:
printf("selected 3 !\n\r");
break;
default:
printf("Error : This is a wrong slection !\n\r");
break;
}
}

    2.  printf / scanf 函数的移植和实现

        2.1  touch printf.c ,并把printf.o丢到Makefile里

            2.1.1  unsigned char outbuf[1024];

            2.1.2  man 3 printf,函数原型为 int printf(const char * fmt, ...),讲变参转化为字符串,

                va_list args;                                          /*  变参列表  */

                va_start(args, fmt);                              /*  把原型中的fmt格式传递给变量列表  */

                vsprint( (char *)outbuf, fmt, args );    /*  把变参转化字符串放进outbuf中  */

                va_end();

            2.1.3  打印字符串到串口

                for ( i = 0; i < strlen( (char *) outbuf); i++)

                {

                    putc(outbuf[i]);

                }

                return i;


        2.2  然而,va_start, vsprintf, va_end 在gboot并木有定义,必须先从Lib中移植

            2.2.1  修改顶层Makefile

OBJS := start.o main.o dev/dev.o lib/lib.o

            2.2.2  编译后,出现错误,ctype.c 符号没定义,分析其原因为:ctype.h 没被预编译时包含,arm-linux-gcc路径应包含本地include文件夹,于是在顶层Makefile中添加如下代码:

CFLAGS := -I$(shell pwd)/include
export CFLAGS

                       编译后,报错,va_list'没声明,解决方法为,在printf.c中添加:#include “vsprintf.h”

                       编译后,报错,main.c中的“puts”没定义,原因为,出现了内联函数(inline funtion),解决办法未,修改顶层Makefile中的CFLAGS

CFLAGS := -fno-builtin -I$(shell pwd)/include
export CFLAGS

......

%.o : %.c
arm-linux-gcc $(CFLAGS) -c $^


    2.3  移植scanf

        2.3.1  unsigned char inbuf[1024];

        2.3.2  man 3 scanf, 原型为:int scanf (const char * fmt, ....);

        2.3.3  在printf.c中加入如下代码:

int scanf(const char *fmt, ...)
{
int i = 0;
unsigned char ch;
va_list args;
while(1)
{    /*  获取输入的字符串  */
ch = getc();
if((ch==0x0d) || (ch==0x0a))
{
putc('\n');
break;
}
else
{
inbuf[i++] = ch;
}
} /*  格式转换  */

va_start(args, fmt);
vsscanf((char *)inbuf, fmt, args);  /*  此处和vsprintf不大一样  */
va_end();
return i;
}


    3.  程序代码结构优化

        3.1  建立dev文件夹,把button.c    interrupt.c    led.c    mmu.c    uart.c  等文件丢进去

        3.2  在dev中,复制lib中的makefile进行修改

objs := mmu.o led.o button.o interrupt.o nandflash.o uart.o dma.o

        3.3  xiugai dingceng Makefile

OBJS := start.o main.o dev/dev.o lib/lib.o





0 0