Debug from the sending and receiving direction, and the data is from App -> line procedure -> serial_core -> hardware driver -> TXD
line procedure and serial_core are codes provided by linux, and there are basically few errors. In this way, the data at the beginning and end can be compared to determine whether the driver is correct.
From the receiving direction, RX -> Trigger an interrupt, the driver reads data -> reads the data to the row procedure -> App
For the read data, the row procedure needs to be set to RAW mode.
1. How to get the data of the method on the UART hardware
1.1 Raw data received
It can be printed out in the receiving interrupt function, and these data will also be stored in the buffer of the tty_port corresponding to the UART:
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 Data sent out
All the serial port data to be sent will be sent through the uart_write function, and all of them can be printed out in 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;
}
Two, proc file
2.1 /proc/interrupts
View interruptions
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
In order: driver_name, device node prefix, major device number, minor device number range, type
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 (no 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
Three, sys file
In drivers\tty\serial\serial_core.c, there is the following code:
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);
These codes will create the corresponding files of the serial port in the /sys directory, and you can get many parameters of the serial port by viewing these files
Ways to find these files:
cd /sys
find -name uartclk