我所知道的EC====>Uart
来源:互联网 发布:小学英语单词速记软件 编辑:程序博客网 时间:2024/05/16 00:39
我所知道的EC====>Uart
1. Introduction
“没有输出之前调试是一门艺术,有了输出以后调试就是一门技术!”这句话准确的道出了调试程序时能够查看运行状况和环境信息的重要性;尤其在FW环境下debug手段非常有限,uart是几乎所有FW都会采用的debug方式。Uart全称是 Universal Asynchronous Receiver/Transmitter即通用异步收发器(异步串行通信口)它包括了RS232、RS485等接口和总线标准规范, 它作为一种低速通信协议广泛应用于通信领域。
2. Hardware Interface
Uart spec定义了非常多的信号,但debug过程中通常只需要接三根信号RX、TX、GND就可以了,故常见串口debug线路如下图1所示:
串口读写数据时数据送往内部的fifo,如果fifo满了数据就会按照顺讯逐个bit送往总线。数据读写的时序和格式如下图2所示:
串口通信常见的波特率有19200,115200,9600,4800,2400,1200 Bps,波特率可以通过寄存器配置。
3. How to Implement
前一段时间有同事问我一个问题:”为什么我们EC之中使用printf、puts、 putchar这些函数输出字符,字符会送给串口呢?以前写的DOS下的程序是输出到终端的呀。”,他的困惑不无道理,为什么呢?不要着急,让我来告诉你其中的奥秘。若干年以前,我曾经在arm9上面portting过bootloader(u-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的实现吧,下面的代码是vsprintf的code。
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这里就已经很明了了,反正一不做二不休,我们一追到底看个明白(我参考的是s3c24x0的code):
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将数据抛出去的。经这一追printf、puts、putchar都解决了看完上面的分析之后,大家应该不会再困惑了吧!
That’s all!
Peter
- 我所知道的EC====>Uart
- 我所知道的EC====>Preface
- 我所知道的EC====>PowerSequence
- 我所知道的EC====>Battery
- 我所知道的EC====>Thermal
- 我所知道的EC====>Brightness
- 我所知道的EC====>LID
- 我所知道的EC====>Keyboard
- 我所知道的EC====>SMBUS
- 我所知道的EC====>SPI
- 我所知道的EC====>System Architecture
- 我所知道的EC====>Deep Sleep Mode
- 我所知道的EC====>Auto Detect
- 我所知道的EC====>IDLE &RESET MODE
- 我所知道的EC====>KBSMI&KBSCI
- 我所知道的Eclipse
- 我所知道的幸福
- 我所知道的《魔兽世界》
- vmware tools之文件共享
- 深切认识.NET接口
- linux的自动任务创建
- XPCOM--跨平台的组件开发技术
- linux下根据日期创建文件或者文件夹
- 我所知道的EC====>Uart
- 在VS 2008下成功编译Chrome
- 大量小文件的实时同步方案
- VC++ & MFC实现的优秀的开源项目
- boost库在uClibc里的链接错误
- 调用flash时覆盖html标签的决方法
- 组织结构图
- 数论的欧拉定理证明 & 欧拉函数公式
- WAP MMS