从收发方向调试,数据从App -> 行规程 -> serial_core -> 硬件驱动 -> TXD
行规程和serial_core是linux提供的代码,基本很少出错。这样就就可以比较开始和结束的数据,判断驱动是否正确。
从接收方向,RX -> 触发中断,驱动读取数据 -> 把数据读取到行规程 -> App
对于读取的数据,行规程需要设置成RAW模式。
一、怎么得到UART硬件上手法的数据
1.1 接收到的原始数据
可以在接收中断函数里把它打印出来,这些数据也会存入UART对应的tty_port的buffer里:
static inline int tty_insert_flip_char(struct tty_port *port,
unsigned char ch, char flag)
{
struct tty_buffer *tb = port->buf.tail; //这个buf是接收到的数据
int change;
change = (tb->flags & TTYB_NORMAL) && (flag != TTY_NORMAL);
if (!change && tb->used < tb->size) {
if (~tb->flags & TTYB_NORMAL)
*flag_buf_ptr(tb, tb->used) = flag;
*char_buf_ptr(tb, tb->used++) = ch;
return 1;
}
return __tty_insert_flip_char(port, ch, flag);
}
1.2 发送出去的数据
所有要发送出去的串口数据,都会通过uart_write函数发送,所有可以在uart_write中把她们打印出来:
static int uart_write(struct tty_struct *tty,
const unsigned char *buf, int count) //这个buf是发送前的buf
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
struct circ_buf *circ;
unsigned long flags;
int c, ret = 0;
/*
* This means you called this function _after_ the port was
* closed. No cookie for you.
*/
if (!state) {
WARN_ON(1);
return -EL3HLT;
}
port = uart_port_lock(state, flags);
circ = &state->xmit;
if (!circ->buf) {
uart_port_unlock(port, flags);
return 0;
}
while (port) {
c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
if (count < c)
c = count;
if (c <= 0)
break;
memcpy(circ->buf + circ->head, buf, c);
circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
buf += c;
count -= c;
ret += c;
}
__uart_start(tty);
uart_port_unlock(port, flags);
return ret;
}
二、proc文件
2.1 /proc/interrupts
查看中断次数
cat /proc/interrupts
CPU0
16: 2017356 GPC 55 Level i.MX Timer Tick
18: 2486 GPC 26 Level 2020000.serial
19: 0 GPC 98 Level sai
20: 0 GPC 50 Level 2034000.asrc
35: 0 GPC 4 Level 20cc000.snvs:snvs-powerkey
36: 55327 GPC 120 Level 20b4000.ethernet
37: 0 GPC 121 Level 20b4000.ethernet
38: 0 GPC 80 Level 20bc000.wdog
44: 0 GPC 19 Level rtc alarm
50: 1556 GPC 2 Level sdma
55: 57709 GPC 43 Level 2184000.usb
56: 0 GPC 42 Level 2184200.usb
57: 309252 GPC 118 Level 2188000.ethernet
58: 0 GPC 119 Level 2188000.ethernet
59: 19073 GPC 22 Level mmc0
60: 32527 GPC 23 Level mmc1
61: 1 GPC 100 Level 2198000.adc
62: 626 GPC 36 Level 21a0000.i2c
63: 124 GPC 37 Level 21a4000.i2c
65: 52 GPC 5 Level 21c8000.lcdif
66: 0 GPC 8 Level pxp-dmaengine-legacy
67: 0 GPC 18 Level pxp-dmaengine-std
68: 0 GPC 27 Level 21e8000.serial
69: 0 GPC 28 Level 21ec000.serial
70: 0 GPC 46 Level dcp-vmi-irq
71: 0 GPC 47 Level dcp-irq
73: 2 GPC 6 Level imx-rng
211: 7 gpio-mxc 9 Level gt9xx
IPI0: 0 CPU wakeup interrupts
IPI1: 0 Timer broadcast interrupts
IPI2: 0 Rescheduling interrupts
IPI3: 0 Function call interrupts
IPI4: 0 CPU stop interrupts
IPI5: 0 IRQ work interrupts
IPI6: 0 completion interrupts
Err: 0
2.2 /proc/tty/drivers
依次是:driver_name、设备节点前缀、主设备号、次设备号范围、类型
root@npi:~# cat /proc/tty/drivers
/dev/tty /dev/tty 5 0 system:/dev/tty
/dev/console /dev/console 5 1 system:console
/dev/ptmx /dev/ptmx 5 2 system
/dev/vc/0 /dev/vc/0 4 0 system:vtmaster
rfcomm /dev/rfcomm 216 0-255 serial
g_serial /dev/ttyGS 246 0-3 serial
usbserial /dev/ttyUSB 188 0-511 serial
fsl-lpuart /dev/ttyLP 247 0-5 serial
IMX-uart /dev/ttymxc 207 16-23 serial
pty_slave /dev/pts 136 0-1048575 pty:slave
pty_master /dev/ptm 128 0-1048575 pty:master
unknown /dev/tty 4 1-63 console
2.3 /proc/tty/driver(没有s)
root@npi:~# ls /proc/tty/driver
fsl-lpuart IMX-uart usbserial #所有的tty_driver
root@npi:~# cat /proc/tty/driver
driver/ drivers
root@npi:~# cat /proc/tty/driver/IMX-uart #查看数据收发统计信息
serinfo:1.0 driver revision:
0: uart:IMX mmio:0x02020000 irq:18 tx:69907 rx:127 brk:1 RTS|DTR|DSR|CD #发送字符数、接收字符数
1: uart:IMX mmio:0x021E8000 irq:68 tx:0 rx:0 DSR|CD
2: uart:IMX mmio:0x021EC000 irq:69 tx:6248 rx:25167 DSR|CD
2.4 /proc/tty/ldiscs
root@npi:~# cat /proc/tty/ldiscs #有哪些行规程
n_tty 0
ppp 3
pppsync 14
n_hci 15
n_null 27
三、sys文件
在drivers\tty\serial\serial_core.c中,有如下代码:
static DEVICE_ATTR(type, S_IRUSR | S_IRGRP, uart_get_attr_type, NULL);
static DEVICE_ATTR(line, S_IRUSR | S_IRGRP, uart_get_attr_line, NULL);
static DEVICE_ATTR(port, S_IRUSR | S_IRGRP, uart_get_attr_port, NULL);
static DEVICE_ATTR(irq, S_IRUSR | S_IRGRP, uart_get_attr_irq, NULL);
static DEVICE_ATTR(flags, S_IRUSR | S_IRGRP, uart_get_attr_flags, NULL);
static DEVICE_ATTR(xmit_fifo_size, S_IRUSR | S_IRGRP, uart_get_attr_xmit_fifo_size, NULL);
static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL);
static DEVICE_ATTR(close_delay, S_IRUSR | S_IRGRP, uart_get_attr_close_delay, NULL);
static DEVICE_ATTR(closing_wait, S_IRUSR | S_IRGRP, uart_get_attr_closing_wait, NULL);
static DEVICE_ATTR(custom_divisor, S_IRUSR | S_IRGRP, uart_get_attr_custom_divisor, NULL);
static DEVICE_ATTR(io_type, S_IRUSR | S_IRGRP, uart_get_attr_io_type, NULL);
static DEVICE_ATTR(iomem_base, S_IRUSR | S_IRGRP, uart_get_attr_iomem_base, NULL);
static DEVICE_ATTR(iomem_reg_shift, S_IRUSR | S_IRGRP, uart_get_attr_iomem_reg_shift, NULL);
这些代码会在/sys目录中创建串口的对应文件,查看这些文件可以得到串口的很多参数
寻找这些文件的方法:
cd /sys
find -name uartclk