UART driver debugging method

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

Guess you like

Origin blog.csdn.net/ch122633/article/details/130683475
Recommended