我所知道的EC====>Uart

来源:互联网 发布:小学英语单词速记软件 编辑:程序博客网 时间:2024/05/16 00:39

我所知道的EC====>Uart

 

1. Introduction

 

     “没有输出之前调试是一门艺术,有了输出以后调试就是一门技术!”这句话准确的道出了调试程序时能够查看运行状况和环境信息的重要性;尤其在FW环境下debug手段非常有限,uart是几乎所有FW都会采用的debug方式。Uart全称是 Universal Asynchronous Receiver/Transmitter通用异步收发器(异步串行通信口)它包括了RS232RS485等接口和总线标准规范, 它作为一种低速通信协议广泛应用于通信领域。

 

2. Hardware Interface

 

   Uart spec定义了非常多的信号,但debug过程中通常只需要接三根信号RXTXGND就可以了,故常见串口debug线路如下图1所示:

 

 

串口读写数据时数据送往内部的fifo,如果fifo满了数据就会按照顺讯逐个bit送往总线。数据读写的时序和格式如下图2所示:

 

串口通信常见的波特率有192001152009600480024001200 Bps,波特率可以通过寄存器配置。

 

3. How to Implement

 

     前一段时间有同事问我一个问题:”为什么我们EC之中使用printfputs putchar这些函数输出字符,字符会送给串口呢?以前写的DOS下的程序是输出到终端的呀。,他的困惑不无道理,为什么呢?不要着急,让我来告诉你其中的奥秘。若干年以前,我曾经在arm9上面porttingbootloaderu-boot,u-boot也有一个串口debug的部分,所以我就碰巧大致翻了翻这部分的代码,关注过这个问题J.先来看看printf的实现吧,下述代码是u-boot 中的printf code

 

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

    {

            va_list args;

            uint i;

            char printbuffer[CFG_PBSIZE];

 

            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);

 

            /* Print the string */

            puts (printbuffer);

}

 

注意看红色部分的代码,printf先使用vsprintf处理输入的参数,并将处理后的结果存入printbuffer,随后调用puts输出。那么我们看一下vsprintf的实现吧,下面的代码是vsprintfcode

  

   int vsprintf(char *buf, const char *fmt, va_list args)

   {

            int len;

            unsigned long num;

            int i, base;

            char * str;

            const char *s;

 

            int flags;                       /* flags to number() */

 

            int field_width;  /* width of output field */

            int precision;                  /* min. # of digits for integers; max

                                                   number of chars for from string */

            int qualifier;                  /* 'h', 'l', or 'q' for integer fields */

 

            for (str=buf ; *fmt ; ++fmt) {

                        if (*fmt != '%') {

                                    *str++ = *fmt;

                                    continue;

                        }

 

                        /* process flags */

                        flags = 0;

                        repeat:

                                    ++fmt;               /* this also skips first '%' */

                                    switch (*fmt) {

                                                case '-': flags |= LEFT; goto repeat;

                                                case '+': flags |= PLUS; goto repeat;

                                                case ' ': flags |= SPACE; goto repeat;

                                                case '#': flags |= SPECIAL; goto repeat;

                                                case '0': flags |= ZEROPAD; goto repeat;

                                                }

 

                        /* get field width */

                        field_width = -1;

                        if (is_digit(*fmt))

                                    field_width = skip_atoi(&fmt);

                        else if (*fmt == '*') {

                                    ++fmt;

                                    /* it's the next argument */

                                    field_width = va_arg(args, int);

                                    if (field_width < 0) {

                                                field_width = -field_width;

                                                flags |= LEFT;

                                    }

                        }

 

                        /* get the precision */

                        precision = -1;

                        if (*fmt == '.') {

                                    ++fmt;

                                    if (is_digit(*fmt))

                                                precision = skip_atoi(&fmt);

                                    else if (*fmt == '*') {

                                                ++fmt;

                                                /* it's the next argument */

                                                precision = va_arg(args, int);

                                    }

                                    if (precision < 0)

                                                precision = 0;

                        }

 

                        /* get the conversion qualifier */

                        qualifier = -1;

                        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||

                            *fmt == 'Z' || *fmt == 'z' || *fmt == 't' ||

                            *fmt == 'q' ) {

                                    qualifier = *fmt;

                                    if (qualifier == 'l' && *(fmt+1) == 'l') {

                                                qualifier = 'q';

                                                ++fmt;

                                    }

                                    ++fmt;

                        }

 

                        /* default base */

                        base = 10;

 

                        switch (*fmt) {

                        case 'c':

                                    if (!(flags & LEFT))

                                                while (--field_width > 0)

                                                            *str++ = ' ';

                                    *str++ = (unsigned char) va_arg(args, int);

                                    while (--field_width > 0)

                                                *str++ = ' ';

                                    continue;

 

                        case 's':

                                    s = va_arg(args, char *);

                                    if (!s)

                                                s = "<NULL>";

 

                                    len = strnlen(s, precision);

 

                                    if (!(flags & LEFT))

                                                while (len < field_width--)

                                                            *str++ = ' ';

                                    for (i = 0; i < len; ++i)

                                                *str++ = *s++;

                                    while (len < field_width--)

                                                *str++ = ' ';

                                    continue;

 

                        case 'p':

                                    if (field_width == -1) {

                                                field_width = 2*sizeof(void *);

                                                flags |= ZEROPAD;

                                    }

                                    str = number(str,

                                                (unsigned long) va_arg(args, void *), 16,

                                                field_width, precision, flags);

                                    continue;

 

 

                        case 'n':

                                    if (qualifier == 'l') {

                                                long * ip = va_arg(args, long *);

                                                *ip = (str - buf);

                                    } else {

                                                int * ip = va_arg(args, int *);

                                                *ip = (str - buf);

                                    }

                                    continue;

 

                        case '%':

                                    *str++ = '%';

                                    continue;

 

                        /* integer number formats - set up the flags and "break" */

                        case 'o':

                                    base = 8;

                                    break;

 

                        case 'X':

                                    flags |= LARGE;

                        case 'x':

                                    base = 16;

                                    break;

 

                        case 'd':

                        case 'i':

                                    flags |= SIGN;

                        case 'u':

                                    break;

 

                        default:

                                    *str++ = '%';

                                    if (*fmt)

                                                *str++ = *fmt;

                                    else

                                                --fmt;

                                    continue;

                        }

                        if (qualifier == 'l') {

                                    num = va_arg(args, unsigned long);

                        } else if (qualifier == 'Z' || qualifier == 'z') {

                                    num = va_arg(args, size_t);

                        } else if (qualifier == 't') {

                                    num = va_arg(args, ptrdiff_t);

                        } else if (qualifier == 'h') {

                                    num = (unsigned short) va_arg(args, int);

                                    if (flags & SIGN)

                                                num = (short) num;

                        } else if (flags & SIGN)

                                    num = va_arg(args, int);

                        else

                                    num = va_arg(args, unsigned int);

                        str = number(str, num, base, field_width, precision, flags);

            }

            *str = '/0';

            return str-buf;

}

 

上述代码大致的意思就是解析fmt字符串,并据此分析计算args,最后将结果写入buf之中,有兴趣可以自己单步debug玩一玩。下面我们来看一看puts的实现代码:

      

       void puts (const char *s)

     {

#ifdef CONFIG_SILENT_CONSOLE

            if (gd->flags & GD_FLG_SILENT)

                        return;

#endif

            if (gd->flags & GD_FLG_DEVINIT)

            {

                        /* Send to the standard output */

                        fputs (stdout, s);

            }

            else

            {

                        /* Send directly to the handler */

                        serial_puts (s);

            }

}

 

这段code一出问题就明了了J,puts函数会先检查GD_FLG_SILENT flag如置起就什么都不干直接返回,silent就是安静的意思嘛J,而后会看GD_FLG_DEVINIT flag如置起,那么输出到stdout(也就是通常所说的终端),否则就是红色部分的代码了,这里就是问题的关键,它会调用serial_puts输出到串口了,到serial_puts这里就已经很明了了,反正一不做二不休,我们一追到底看个明白(我参考的是s3c24x0code):

 

void serial_puts (const char *s)

{

            _serial_puts(s, UART_NR);

}

 

void _serial_puts(const char *s, const int dev_index)

{

            while (*s)

            {

                        _serial_putc (*s++, dev_index);

            }

}

 

/*

 * Output a single byte to the serial port.

 */

void _serial_putc (const char c, const int dev_index)

{

            S3C24X0_UART * const uart = S3C24X0_GetBase_UART(dev_index);

#ifdef CONFIG_MODEM_SUPPORT

            if (be_quiet)

                        return;

#endif

 

            /* wait for room in the tx FIFO */

            while (!(uart->UTRSTAT & 0x2));

 

#ifdef CONFIG_HWFLOW

            /* Wait for CTS up */

            while(hwflow && !(uart->UMSTAT & 0x1))

                        ;

#endif

 

            uart->UTXH = c;

 

            /* If /n, also do /r */

            if (c == '/n')

                        serial_putc ('/r');

}

 

 

图穷匕见,秘密终于揭开,红色部分的code已经说明一切了最终是通过操纵s3c24x0 uart register将数据抛出去的。经这一追printfputsputchar都解决了看完上面的分析之后,大家应该不会再困惑了吧!

 

 

That’s all!

 

Peter

原创粉丝点击