Linux serial port RS232/485/GPS driver experiment (transplant minicom)

The serial port is a very commonly used peripheral. Under Linux, it usually communicates with other devices or sensors through the serial port. According to the
different levels, the serial port is divided into TTL and RS232. No matter what the interface level is, the driver program is the same. The
serial port can be converted to RS485 signal by connecting an external chip such as RS485, which
is what the I.MX6U-ALPHA development board of punctual atom does. For the I.MX6U-ALPHA development board of Zhengdian Atom, the RS232, RS485 and GPS module
interfaces are all connected to the UART3 interface of I.MX6U, so these peripherals are ultimately attributed to the UART3 serial port driver
. In this chapter, we will learn how to drive the UART3 serial port on the I.MX6U-ALPHA development board, and then realize RS232,
RS485 and GSP drivers.

UART driver framework under Linux

1. Registration and deregistration of uart_driver
Like I2C and SPI, Linux also provides a serial port driver framework, we only need to write the driver
program according to the corresponding serial port framework. There is no distinction between the host end and the device end of the serial port driver, there is only one serial port driver, and this driver has been
officially written by NXP. What we really need to do is to add the serial port node information to be used in the device tree
. When the system is started, the serial port driver is successfully matched with the device, and the corresponding serial port will be driven to generate the
/dev/ttymxcX(X=0….n) file.
Although the serial port driver does not require us to write, we still need to understand the serial port driver framework. The uart_driver structure
represents the UART driver. The uart_driver is defined in the include/linux/serial_core.h file, and the content is as follows:

示例代码63.1.1 uart_driver 结构体
295 struct uart_driver {
    
    
296 struct module *owner; /* 模块所属者*/
297 const char *driver_name; /* 驱动名字*/
298 const char *dev_name; /* 设备名字*/
299 int major; /* 主设备号*/
300 int minor; /* 次设备号*/
301 int nr; /* 设备数*/
302 struct console *cons; /* 控制台*/
303
304 /*
305 * these are private; the low level driver should not
306 * touch these; they should be initialised to NULL
307 */
308 struct uart_state *state;
309 struct tty_driver *tty_driver;
310 };


Each serial port driver needs to define a uart_driver. When loading the driver , register this uart_driver with the system through the uart_register_driver function . The prototype of this function is as follows:

int uart_register_driver(struct uart_driver *drv)

The meanings of function parameters and return values ​​are as follows:
drv: uart_driver to be registered.
Return value: 0, success; negative value, failure.
When unregistering the driver, you also need to unregister the previously registered uart_driver. You need to use the uart_unregister_driver function.
The function prototype is as follows:

void uart_unregister_driver(struct uart_driver *drv)

The meanings of function parameters and return values ​​are as follows:
drv: uart_driver to be unregistered.
Return value: None.
2. Add and remove uart_port
uart_port represents a specific port, uart_port is defined in include/linux/serial_core.h file, the content is as follows
(some are omitted):

示例代码63.1.2 uart_port 结构体
117 struct uart_port {
    
    
118 spinlock_t lock; /* port lock */
119 unsigned long iobase; /* in/out[bwl] */
120 unsigned char __iomem *membase; /* read/write[bwl] */
......
235 const struct uart_ops *ops;
236 unsigned int custom_divisor;
237 unsigned int line; /* port index */
238 unsigned int minor;
239 resource_size_t mapbase; /* for ioremap */
240 resource_size_t mapsize;
241 struct device *dev; /* parent device */
......
250 };

The most important thing in uart_port is the ops in line 235. ops contains the specific driver functions of the serial port, which we
will look at later. Every UART has a uart_port, so how does uart_port combine with uart_driver?
The uart_add_one_port function is used here , and the function prototype is as follows:

int uart_add_one_port(struct uart_driver *drv,
struct uart_port *uport)

The meanings of function parameters and return values ​​are as follows:
drv: uart_driver corresponding to this port.
uport: the port to be added to uart_driver.
Return value: 0, success; negative value, failure.
When uninstalling the UART driver, you also need to remove the uart_port from the corresponding uart_driver. You need to use the
uart_remove_one_port function. The function prototype is as follows:

int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)

The meanings of function parameters and return values ​​are as follows:
drv: uart_driver corresponding to the port to be uninstalled.
uport: uart_port to uninstall.
Return value: 0, success; negative value, failure.
3. Implementation of uart_ops
As mentioned above when explaining uart_port, the ops member variable in uart_port is very important, because ops contains
specific driver functions for UART, and the functions in ops are finally called by the Linux system to send and receive data. ops is
a structure pointer variable of uart_ops type, uart_ops is defined in include/linux/serial_core.h file, the content is as follows:

示例代码63.1.3 uart_ops 结构体
49 struct uart_ops {
    
    
50 unsigned int (*tx_empty)(struct uart_port *);
51 void (*set_mctrl)(struct uart_port *, unsigned int mctrl);
52 unsigned int (*get_mctrl)(struct uart_port *);
53 void (*stop_tx)(struct uart_port *);
54 void (*start_tx)(struct uart_port *);
55 void (*throttle)(struct uart_port *);
56 void (*unthrottle)(struct uart_port *);
57 void (*send_xchar)(struct uart_port *, char ch);
58 void (*stop_rx)(struct uart_port *);
59 void (*enable_ms)(struct uart_port *);
60 void (*break_ctl)(struct uart_port *, int ctl);
61 int (*startup)(struct uart_port *);
62 void (*shutdown)(struct uart_port *);
63 void (*flush_buffer)(struct uart_port *);
64 void (*set_termios)(struct uart_port *, struct ktermios *new,
65 struct ktermios *old);
66 void (*set_ldisc)(struct uart_port *, struct ktermios *);
67 void (*pm)(struct uart_port *, unsigned int state,
68 unsigned int oldstate);
69
70 /*
71 * Return a string describing the type of the port
72 */
73 const char *(*type)(struct uart_port *);
74
75 /*
76 * Release IO and memory resources used by the port.
77 * This includes iounmap if necessary.
78 */
79 void (*release_port)(struct uart_port *);
80
81 /*
82 * Request IO and memory resources used by the port.
83 * This includes iomapping the port if necessary.
84 */
85 int (*request_port)(struct uart_port *);
86 void (*config_port)(struct uart_port *, int);
87 int (*verify_port)(struct uart_port *, struct serial_struct *);
88 int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
89 #ifdef CONFIG_CONSOLE_POLL
90 int (*poll_init)(struct uart_port *);
91 void (*poll_put_char)(struct uart_port *, unsigned char);
92 int (*poll_get_char)(struct uart_port *);
93 #endif
94 };

UART driver writers need to implement uart_ops, because uart_ops is the lowest-level UART driver interface, and actually
deals with UART registers. For the specific meaning of these functions in the uart_ops structure, please refer to
Documentation/serial/driver.
The UART driver framework is probably these. Next, we combine theory with practice to see how NXP's official UART driver file is written.

I.MX6U UART driver analysis

1. UART platform driver framework
Open the imx6ull.dtsi file and find the sub-node corresponding to UART3. The content of the sub-node is as follows:

示例代码63.2.1 uart3 设备节点
1 uart3: serial@021ec000 {
    
    
2 compatible = "fsl,imx6ul-uart",
3 "fsl,imx6q-uart", "fsl,imx21-uart";
4 reg = <0x021ec000 0x4000>;
5 interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
6 clocks = <&clks IMX6UL_CLK_UART3_IPG>,
7 <&clks IMX6UL_CLK_UART3_SERIAL>;
8 clock-names = "ipg", "per";
9 dmas = <&sdma 29 4 0>, <&sdma 30 4 0>;
10 dma-names = "rx", "tx";
11 status = "disabled";
12 };

Focus on the compatible attribute in lines 2 and 3. There are three values ​​here: "fsl,imx6ul-uart", "fsl,imx6q-uar"
and "fsl,imx21-uart". Search these three values ​​in the linux source code to find the corresponding UART driver file, this
file is drivers/tty/serial/imx.c, you can find the following content in this file:

示例代码63.2.2 UART platform 驱动框架
267 static struct platform_device_id imx_uart_devtype[] = {
    
    
268 {
    
    
269 .name = "imx1-uart",
270 .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART],
271 }, {
    
    
272 .name = "imx21-uart",
273 .driver_data = (kernel_ulong_t)
&imx_uart_devdata[IMX21_UART],
274 }, {
    
    
275 .name = "imx6q-uart",
276 .driver_data = (kernel_ulong_t)
&imx_uart_devdata[IMX6Q_UART],
277 }, {
    
    
278 /* sentinel */
279 }
280 };
281 MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
282
283 static const struct of_device_id imx_uart_dt_ids[] = {
    
    
284 {
    
     .compatible = "fsl,imx6q-uart", .data =
&imx_uart_devdata[IMX6Q_UART], },
285 {
    
     .compatible = "fsl,imx1-uart", .data =
&imx_uart_devdata[IMX1_UART], },
286 {
    
     .compatible = "fsl,imx21-uart", .data =
&imx_uart_devdata[IMX21_UART], },
287 {
    
     /* sentinel */ }
288 };
......
2071 static struct platform_driver serial_imx_driver = {
    
    
2072 .probe = serial_imx_probe,
2073 .remove = serial_imx_remove,
2074
2075 .suspend = serial_imx_suspend,
2076 .resume = serial_imx_resume,
2077 .id_table = imx_uart_devtype,
2078 .driver = {
    
    
2079 .name = "imx-uart",
2080 .of_match_table = imx_uart_dt_ids,
2081 },
2082 };
2083
2084 static int __init imx_serial_init(void)
2085 {
    
    
2086 int ret = uart_register_driver(&imx_reg);
2087
2088 if (ret)
2089 return ret;
2090
2091 ret = platform_driver_register(&serial_imx_driver);
2092 if (ret != 0)
2093 uart_unregister_driver(&imx_reg);
2094
2095 return ret;
2096 }
2097
2098 static void __exit imx_serial_exit(void)
2099 {
    
    
2100 platform_driver_unregister(&serial_imx_driver);
2101 uart_unregister_driver(&imx_reg);
2102 }
2103
2104 module_init(imx_serial_init);
2105 module_exit(imx_serial_exit);

It can be seen that the UART of I.MX6U is essentially a platform driver, lines 267~280, imx_uart_devtype
is the traditional matching table.
Lines 283~288, the matching table used by the device tree, the compatible attribute value of line 284 is "fsl,imx6q-uart".
Lines 2071~2082, platform driver frame structure serial_imx_driver.
Lines 2084~2096 are the driver entry functions. Line 2086 calls the uart_register_driver function to register
uart_driver with the Linux kernel, which is imx_reg here.
Lines 2098~2102 are the driver exit functions, and line 2101 calls the uart_unregister_driver function to unregister the previously registered
uart_driver, that is, imx_reg.
2. uart_driver initialization
In the imx_serial_init function, imx_reg is registered with the Linux kernel. imx_reg is a structure
variable of uart_driver type. imx_reg is defined as follows:

示例代码63.2.3 imx_reg 结构体变量
1836 static struct uart_driver imx_reg = {
    
    
1837 .owner = THIS_MODULE,
1838 .driver_name = DRIVER_NAME,
1839 .dev_name = DEV_NAME,
1840 .major = SERIAL_IMX_MAJOR,
1841 .minor = MINOR_START,
1842 .nr = ARRAY_SIZE(imx_ports),
1843 .cons = IMX_CONSOLE,
1844 };

3. Initialization and addition of uart_port
After the UART device and driver are successfully matched, the serial_imx_probe function will be executed. The key work of this function is to
initialize uart_port, and then add it to the corresponding uart_driver. Before looking at the serial_imx_probe function, let’s take a
look at the imx_port structure. imx_port is a device structure defined by NXP for the I.MX series SOC. This structure
contains the uart_port member variable. The content of the imx_port structure is as follows (with abbreviated ):

示例代码63.2.4 imx_port 结构体
216 struct imx_port {
    
    
217 struct uart_port port;
218 struct timer_list timer;
219 unsigned int old_status;
220 unsigned int have_rtscts:1;
221 unsigned int dte_mode:1;
222 unsigned int irda_inv_rx:1;
223 unsigned int irda_inv_tx:1;
224 unsigned short trcv_delay; /* transceiver delay */
......
243 unsigned long flags;
245 };

Line 217, uart_port member variable port.
Next, look at the serial_imx_probe function, the function content is as follows:

示例代码63.2.5 serial_imx_probe 函数
1969 static int serial_imx_probe(struct platform_device *pdev)
1970 {
    
    
1971 struct imx_port *sport;
1972 void __iomem *base;
1973 int ret = 0;
1974 struct resource *res;
1975 int txirq, rxirq, rtsirq;
1976
1977 sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
1978 if (!sport)
1979 return -ENOMEM;
1980
1981 ret = serial_imx_probe_dt(sport, pdev);
1982 if (ret > 0)
1983 serial_imx_probe_pdata(sport, pdev);
1984 else if (ret < 0)
1985 return ret;
1986
1987 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1988 base = devm_ioremap_resource(&pdev->dev, res);
1989 if (IS_ERR(base))
1990 return PTR_ERR(base);
1991
1992 rxirq = platform_get_irq(pdev, 0);
1993 txirq = platform_get_irq(pdev, 1);
1994 rtsirq = platform_get_irq(pdev, 2);
1995
1996 sport->port.dev = &pdev->dev;
1997 sport->port.mapbase = res->start;
1998 sport->port.membase = base;
1999 sport->port.type = PORT_IMX,
2000 sport->port.iotype = UPIO_MEM;
2001 sport->port.irq = rxirq;
2002 sport->port.fifosize = 32;
2003 sport->port.ops = &imx_pops;
2004 sport->port.rs485_config = imx_rs485_config;
2005 sport->port.rs485.flags =
2006 SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX;
2007 sport->port.flags = UPF_BOOT_AUTOCONF;
2008 init_timer(&sport->timer);
2009 sport->timer.function = imx_timeout;
2010 sport->timer.data = (unsigned long)sport;
2011
2012 sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
2013 if (IS_ERR(sport->clk_ipg)) {
    
    
2014 ret = PTR_ERR(sport->clk_ipg);
2015 dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
2016 return ret;
2017 }
2018
2019 sport->clk_per = devm_clk_get(&pdev->dev, "per");
2020 if (IS_ERR(sport->clk_per)) {
    
    
2021 ret = PTR_ERR(sport->clk_per);
2022 dev_err(&pdev->dev, "failed to get per clk: %d\n", ret);
2023 return ret;
2024 }
2025
2026 sport->port.uartclk = clk_get_rate(sport->clk_per);
2027 if (sport->port.uartclk > IMX_MODULE_MAX_CLK_RATE) {
    
    
2028 ret = clk_set_rate(sport->clk_per, IMX_MODULE_MAX_CLK_RATE);
2029 if (ret < 0) {
    
    
2030 dev_err(&pdev->dev, "clk_set_rate() failed\n");
2031 return ret;
2032 }
2033 }
2034 sport->port.uartclk = clk_get_rate(sport->clk_per);
2035
2036 /*
2037 * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
2038 * chips only have one interrupt.
2039 */
2040 if (txirq > 0) {
    
    
2041 ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0,
2042 dev_name(&pdev->dev), sport);
2043 if (ret)
2044 return ret;
2045
2046 ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0,
2047 dev_name(&pdev->dev), sport);
2048 if (ret)
2049 return ret;
2050 } else {
    
    
2051 ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0,
2052 dev_name(&pdev->dev), sport);
2053 if (ret)
2054 return ret;
2055 }
2056
2057 imx_ports[sport->port.line] = sport;
2058
2059 platform_set_drvdata(pdev, sport);
2060
2061 return uart_add_one_port(&imx_reg, &sport->port);
2062 }

Line 1971 defines a structure pointer variable sport of imx_port type.
Line 1977, apply for memory for sport.
Lines 1987~1988, get the first address of the I.MX series SOC UART peripheral register from the device tree, which
is 0X021EC000 for UART3 of I.MX6ULL. After the first address of the register is obtained, it is memory-mapped to obtain the
corresponding virtual address.
Lines 1992~1994, get interrupt information.
Lines 1996~2034, initialize sport, we focus on line 2003 to initialize the port member variable of sport
, that is, set uart_ops to imx_pops, imx_pops is the bottom-level driver function collection of I.MX6ULL,
see it later.
Lines 2040~2055, apply for interruption.
Line 2061, use uart_add_one_port to add uart_port to uart_driver, here is to add
sport->port to imx_reg.
4. imx_pops structure variable
imx_pops is a structure variable of uart_ops type, which saves the bottom-level operation function of the I.MX6ULL serial port.
The definition of imx_pops is as follows:

示例代码63.2.6 imx_pops 结构体
1611 static struct uart_ops imx_pops = {
    
    
1612 .tx_empty = imx_tx_empty,
1613 .set_mctrl = imx_set_mctrl,
1614 .get_mctrl = imx_get_mctrl,
1615 .stop_tx = imx_stop_tx,
1616 .start_tx = imx_start_tx,
1617 .stop_rx = imx_stop_rx,
1618 .enable_ms = imx_enable_ms,
1619 .break_ctl = imx_break_ctl,
1620 .startup = imx_startup,
1621 .shutdown = imx_shutdown,
1622 .flush_buffer = imx_flush_buffer,
1623 .set_termios = imx_set_termios,
1624 .type = imx_type,
1625 .config_port = imx_config_port,
1626 .verify_port = imx_verify_port,
1627 #if defined(CONFIG_CONSOLE_POLL)
1628 .poll_init = imx_poll_init,
1629 .poll_get_char = imx_poll_get_char,
1630 .poll_put_char = imx_poll_put_char,
1631 #endif
1632 };

The functions in imx_pops basically deal with the UART registers of I.MX6ULL, so I won't
analyze them in detail here. After a brief understanding of the UART driver of I.MX6U, let's learn how to drive the
UART3 interface on the punctual atom I.MX6U-ALPHA development board.

Hardware Schematic Analysis

The UART3 interface of I.MX6U used in this experiment, the
three interfaces of RS232, RS485 and GPS on the I.MX6U-ALPHA development board are all connected to UART3. Let’s take a look at the schematic diagrams of these three modules in turn.
1. RS232 schematic diagram
The schematic diagram of RS232 is shown in Figure 63.3.1:
insert image description here
From Figure 63.3.1, it can be seen that the RS232 level is realized through the chip SP3232, and RS232 is connected to the
UART3 interface of I.MX6U, but it needs to be connected through JP1 This jumper cap is set. After connecting 1-3 and 2-4 of JP1, SP3232
and UART3 are connected together.
2. Schematic diagram of RS485
The schematic diagram of RS485 is shown in Figure 63.3.2:
insert image description here
RS485 is realized by SP3485 chip, RO is the data output terminal, RI is the data input terminal, RE is the receiving enable
signal (active low), DE is the transmit enable signal (active high). In Figure 63.3.2, RE and DE go through a series
of circuits, and are finally controlled by RS485_RX, so that we can save an RS485 transceiver control IO, and
use RS485 as a serial port, which is convenient for us to write drivers.
3. GPS principle diagram
Zhengdian Atom has a GPS + Beidou positioning module, the model is ATK1218-BD, and the I.MX6U-ALPHA development board has reserved the
interface of this GPS positioning module. The interface principle diagram is shown in Figure 63.3.3:
insert image description here
from It can be seen from Figure 63.3.3 that the GPS module also uses UART3, so
the data of the GPS module can be read directly after UART3 is successfully driven.

RS232 driver writing

As we have said before, the UART driver of I.MX6U has been written by NXP, so we do not need to write it.
All we need to do is to add the device node corresponding to UART3 in the device tree. Open the imx6ull-alientek-emmc.dts
file, there is only the uart1 node corresponding to UART1 in this file, and there is no node corresponding to UART3, so we can
refer to the uart1 node to create the uart3 node.
1. UART3 IO node The creation of UART3 uses the two IOs UART3_TXD and UART3_RXD, so first create a pinctrl subnode corresponding to
UART3 in iomuxc , and add the following content in iomuxc:

示例代码63.4.1 UART3 引脚pinctrl 节点
1 pinctrl_uart3: uart3grp {
    
    
2 fsl,pins = <
3 MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0X1b0b1
4 MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0X1b0b1
5 >;
6 };

Finally, check whether the two pins UART3_TX and UART3_RX are used for other functions, and if so,
shield them to ensure that these two IOs are only used as UART3, remember! ! !
2. Add uart3 node
By default, there are only two nodes uart1 and uart2 in imx6ull-alientek-emmc.dts, as shown in Figure 63.4.1:
insert image description here
uart1 is UART1, on the I.MX6U-ALPHA development board of punctual atom UART2 is not used, and UART2
uses the IO of UART3 by default, so you need to delete the node uart2, and then add uart3 corresponding to UART3,
the content of the uart3 node is as follows:

示例代码63.4.2 UART3 对应的uart3 节点
1 &uart3 {
    
    
2 pinctrl-names = "default";
3 pinctrl-0 = <&pinctrl_uart3>;
4 status = "okay";
5 };

After the completion, recompile the device tree and use the new device tree to start Linux. If the device tree is modified successfully,
a device file named "/dev/ttymxc2" will be generated after the system starts. ttymxc2 is the device
file . The application program can realize the operation on UART3 by accessing ttymxc2.

Porting minicom

Minicom is similar to our commonly used serial port debugging assistant. It is a very commonly used serial port tool under Linux. We transplant minicom
into our development board, so that we can use minicom to read and write to the serial port.
1. Transplanting ncurses
minicom needs ncurses, so you need to transplant ncurses first. If ncurses has been transplanted before, then there is
no need to transplant again here. You only need to specify the ncurses library and header file directory when compiling minicom.
First create a directory in ubuntu to store the files we want to transplant. For example, I
created a directory named "tool" in the /home/zuozhongkai/linux/IMX6ULL directory to store all the transplanted files
. Then download the ncurses source code, we have put the ncurses source code into the development board CD, the path is: 1, the routine
source code- "7, the third-party library source code-"ncurses-6.0.tar.gz, ncurses-6.0.tar Copy the .gz file to the tool directory created in Ubuntu
, and then decompress it. The decompression command is as follows:

tar -vxzf ncurses-6.0.tar.gz

After the decompression is completed, a folder named "ncurses-6.0" will be generated, which is the source code folder of ncurse
. Create a new directory named "ncurses" under the tool directory to save the ncurses compilation results. After everything is ready, you
can compile the ncurses library. Enter the ncureses source code directory, that is, the ncurses-6.0 directory that has just been decompressed
, first configure ncureses, and enter the following command:

./configure --prefix=/home/zuozhongkai/linux/IMX6ULL/tool/ncurses --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf --with-shared --without-profile --disable-stripping --without-progs --with-manpages --without-tests

configure is the configuration script, and --prefix is ​​used to specify the saving directory of the compilation result, and the compilation result must be saved
in the "ncurses" directory we created earlier. –host is used to specify the compiler prefix, which is set to “arm-linux-
gnueabihf” here, and –target is used to specify the target, which is also set to “arm-linux-gnueabihf” here. After the configuration command is written, click
the Enter key and wait for the configuration to complete. After the configuration is successful, it is shown in Figure 63.5.1: After the configuration is successful,
insert image description here
enter the "make" command to start compiling. After the compilation is successful, it is shown in Figure 63.5.2:
insert image description here
Compilation is successful Then enter the "make install" command to install, the meaning of installation is to copy the compiled result to the directory specified by –pfefix. After the installation is successful, as shown in Figure 63.5.3:

insert image description here
After the installation is successful, check the "ncurses" folder created earlier, and you will find that there are some more things in it, as shown in Figure 63.5.4
:
insert image description here
we need to store the files in the three directories include, lib and share in Figure 63.5.4 Copy the files to
the three directories of /usr/include, /usr/lib and /usr/share in the root file system of the development board. If any directory does not exist, please create it yourself
! ! The copy command is as follows:

sudo cp lib/* /home/zuozhongkai/linux/nfs/rootfs/usr/lib/ -rfa
sudo cp share/* /home/zuozhongkai/linux/nfs/rootfs/usr/share/ -rfa
sudo cp include/* /home/zuozhongkai/linux/nfs/rootfs/usr/include/ -rfa

Then add the following content to the /etc/profile (create one yourself if you don't have one) file in the root directory of the development board:

示例代码63.5.1 /etc/profile 文件
1 #!/bin/sh
2 LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
3 export LD_LIBRARY_PATH
4
5 export TERM=vt100
6 export TERMINFO=/usr/share/terminfo

2. Transplant minicom
Continue to transplant minicom and obtain minicom source code, which we have put in the development board CD, the path is: 1. Routine
source code - "7. Third-party library source code - "minicom-2.7.1.tar.gz. Copy minicom-2.7.1.tar.gz to the
/home/zuozhongkai/linux/IMX6ULL/tool ​​directory in ubuntu, and then create a subdirectory named "minicom" under the tool directory
to store the minicom compilation results . After everything is ready, you can compile minicom, first unzip minicom,
the command is as follows:

tar -vxzf minicom-2.7.1.tar.gz

After the decompression is completed, a folder called minicom-2.7.1 will be generated. This is the source code of minicom. Enter
this directory, and then configure minicom. The configuration command is as follows:

cd minicom-2.7.1/ //进入minicom 源码目录
./configure CC=arm-linux-gnueabihf-gcc --prefix=/home/zuozhongkai/linux/IMX6ULL/tool/
minicom --host=arm-linux-gnueabihf CPPFLAGS=-I/home/zuozhongkai/linux/IMX6ULL/tool/
ncurses/include LDFLAGS=-L/home/zuozhongkai/linux/IMX6ULL/tool/ncurses/lib -enable-cfg-dir=/etc/minicom //配置

CC indicates the gcc cross-compiler to be used, and --prefix specifies the storage directory of the compiled files, which must be stored in the
minicom directory we created earlier. –host specifies the cross-compiler prefix, CPPFLAGS specifies the header file path of ncurses, and LDFLAGS specifies the library path of ncurses.
If the configuration is successful, as shown in Figure 63.5.5:

insert image description here
After the configuration is successful, execute the following command to compile and install:

make
make install

After compiling and installing, the content of the previously created minicom directory is shown in Figure 63.5.6:
insert image description here
copy all the files under the bin subdirectory in the minicom directory to the /usr/bin directory in the root directory of the development board, and the command is
as follows:

sudo cp bin/* /home/zuozhongkai/linux/nfs/rootfs/usr/bin/

After completion, enter "minicom -v" in the development board to check whether minicom works normally, the result is shown in Figure 63.5.7: From Figure 63.5.7, we
can
insert image description here
see that the version number of minicom is 2.7.1, and the version number of minicom is 2.7.1. View normal. Enter the following
command to open the minicom configuration interface:

minicom -s

The result is that the minicom configuration interface cannot be opened, and the information shown in Figure 63.5.8 is prompted:
insert image description here
From Figure 63.5.8, it can be seen that minicom is extremely arrogant and asks us to "Go away". Can this be tolerated? ! It must be
cured. The solution is very simple, create a new /etc/passwd file, and then enter the following content in the passwd file:

示例代码63.5.2 /etc/passwd 文件
1 root:x:0:0:root:/root:/bin/sh

Reboot the board when done!
Reboot the board when done!
After restarting the development board, execute the “minicom -s” command, then the minicom configuration interface can be opened, as
shown in Figure 63.5.9:
insert image description here
If the interface shown in Figure 63.5.9 appears, it means that mincom is working normally.

RS232 drive test

RS232 connection settings

Before the test, connect the RS232 of the I.MX6U-ALPHA development board to the computer, first set the JP1 jumper
cap, as shown in Figure 63.6.1.1:
insert image description here
After setting the jumper cap, use the RS232 line to connect the development board to the computer It is recommended to use a USB to
DB9 (RS232) data cable here , such as the USB to male DB9 data cable of the CH340 solution sold by Zhengdian Atom, as
shown in Figure 63.6.1.2:
insert image description here
The data cable shown in Figure 63.6.1.2 is with It has a CH340 chip, so when it is connected to a computer, a COM port will appear
, and this COM port is the COM port we want to use. For example, it is COM9 on my computer,
create a new connection on SecureCRT, the serial port is COM9, and the baud rate is 115200.

minicom-settings

Enter "minicom -s" in the development board to open the minicom configuration interface, and then select "Serial port setup", as shown in
Figure 63.6.2.1:
insert image description here
After selecting "Serial port setup", click Enter to enter the setup menu, as shown in Figure 63.6 As shown in .2.2:
insert image description here
There are 7 setting items in Figure 63.6.2.2, which correspond to A, B...G respectively. For example, the first one is to select the serial port, and the
serial port file of UART3 is /dev/ttymxc2, so the serial port device should be set to / dev/ttymxc2. The setting method is to press 'A' on the keyboard,
and then enter "/dev/ttymxc2", as shown in Figure 63.6.2.3:
insert image description here
After setting, press the Enter key to confirm, and then you can set other configurations item. For example, E sets the baud rate,
data bits and stop bits, and F sets the hardware flow control. The setting methods are the same. After setting, it is shown in Figure 63.6.2.4: After all settings are completed,
insert image description here
press the Enter key to confirm and exit. At this time, it will return to the interface shown in Figure 63.6.2.1, press
the ESC key to exit the configuration interface shown in Figure 63.6.2.1, after exiting, it will be shown in Figure 63.6.2.5: Figure 63.6.2.2
insert image description here
is our serial port debugging interface , it can be seen that the current serial port file is /dev/ttymxc2, press CTRL-
A, and then press Z to open the minicom help information interface, as shown in Figure 63.6.2.6:
insert image description here
From Figure 63.6.2.6 we can see that, There are many shortcut keys in minicom. In this experiment, we turn on the echo function of minicom. The
echo function configuration item is "local Echo on/off...E", so press E to turn on/off the echo function.

RS232 transceiver test

1. Sending test
First test the function of the development board to send data to the computer through UART3, you need to open the echo function of minicom (you can not
open it n’t see the content you input in minicom), after the echo function is turned on, enter "AAAA", as
shown in Figure 63.6.3.1:
insert image description here

"AAAA" in Figure 63.6.3.1 is equivalent to the development board sending "AAAA" to the computer through UART3, then COM9
will receive "AAAA". The data received by COM9 in SecureCRT is shown in Figure 63.6.3.2:
insert image description here
it can be seen , the development board sends data to the computer through UART3 normally, then test the data receiving
function of the development board.
2. Receiving test
Next, test the UART3 receiving function of the development board. Similarly, you must first enable the local echo of COM9 on the SecureCRT
, otherwise you will not see the output on COM9, but it has actually been sent to development board. Select
Options->Session Options->Adavnced of SecureCRT, open the session configuration interface, and then select "Local echo",
as shown in Figure 63.6.3.3:
insert image description here
After SecureCRT is set, send a "BBBB" to the development board, on COM9 of SecureCRT Input "BBBB",
as shown in Figure 63.6.3.3:
insert image description here
At this time, the minicom of the development board will receive the sent "BBBB", as shown in Figure 63.6.3.4:
insert image description here
There is no problem in the UART3 sending and receiving test, indicating that our UART3 driver works fine. If you want to exit minicom
, press CRTL+A on the minicom communication interface, and then press X to close minicom. The use of minicom
is very simple here, and you can find more detailed minicom tutorials on the Internet.

RS485 test

As mentioned above, the RS485 interface on the I.MX6U-ALPHA development board is connected to UART3, so
it is essentially a serial port. For the RS232 experiment, we have written the UART3 driver, so there is no need to write
any driver for the RS485 experiment, and we can directly use minicom to test.

RS485 connection settings

The first is to set the JP1 jumper cap and connect 3-5 and 4-6, as shown in Figure 63.7.1.1:
insert image description here
one board cannot perform RS485 communication test, and another RS485 device is needed, such as another I.MX6U -ALPHA development board. Here we recommend you to use the USB three-in-one serial converter produced by Zhengdian Atom, which supports USB to TTL,
RS232 and RS485, as shown in Figure 63.7.1.2:
insert image description here
use Dupont cable to connect the RS485 interface of the USB serial converter to the I.MX6U-ALPHA The RS485 of the development board is connected
, A connects A, B connects B, it cannot be wrongly connected! After the connection is completed, as shown in Figure 63.7.1.3:
insert image description here
the serial port converter is connected to the computer through the USB cable. I use the CH340 version, so there is no need to install the driver.
If you use the FT232 version, you need to install the corresponding drive. After the connection is successful, the computer will have a corresponding COM
port. For example, COM10 is on my computer, and the next step is to test.

RS485 transceiver test

The test of RS485 is exactly the same as that of RS232! The COM port of the USB all-in-one converter is 10, so use SecureCRT
to create a COM10 connection. The development board uses UART3, and the corresponding serial port device file is /dev/ttymxc2, so the development
board uses minicom to create a serial port connection of /dev/ttymxc2. The serial port baud rate is 115200, 8 data bits, 1
stop bit, and hardware and software flow control are turned off.
1. RS485 sending test
First test that the development board sends data through RS485, after setting minicom, also input "AAAA", that is,
send a string of "AAAA" to the computer through RS485. If the RS485 driver works normally, the computer will receive the
"AAAA" sent by the development board, as shown in Figure 63.7.2.1:
insert image description here
From Figure 63.7.2.1, it can be seen that the development board has successfully sent "AAAA" to the computer through RS485. It means that the RS485 data
is sent normally.
2. RS485 reception test
Next, test the RS485 data reception. The computer sends "BBBB" to the development board through RS485, and then observe
whether minicom can receive "BBBB". The result is shown in Figure 63.7.2.2:
insert image description here
From Figure 63.7.2.1, it can be seen that the development board receives the "BBBB" sent by the computer through RS485, indicating that the RS485 data
reception is also normal.

GPS test

GPS connection settings

Most of the GPS modules are output by serial ports. Here we take the ATK1218-BD module produced by Zhengdian Atom as an example. This is
a GSP+ Beidou positioning module. The module is shown in Figure 63.8.1.1
insert image description here
: Pull out the jumper cap of JP1 on the development board, do not connect RS232 or RS485, otherwise
it will interfere with the GSP module. UART3_TX and UART3_RX have been connected to the ATK MODULE on the development board.
Just plug the ATK1218-BD module directly into the ATK MODULE interface on the development board. The ATK MODULE interface on the development board
is 6-pin, while the ATK1218-BD module is 5-pin, so it needs to be inserted on the left! Then the GPS needs to be connected to an antenna, and
the receiving head of the antenna must be placed outdoors, so there is generally no GPS signal indoors. After the connection is completed, as shown in Figure 63.8.1.2
:
insert image description here

GPS data reception test

We all passively receive positioning data for GPS, so open minicom, set /dev/ttymxc2, and the serial port setting requirements are
as follows:
①. The baud rate is set to 38400, because the default baud rate of ATK1218-BD module of punctual atom is 38400.
②, 8 data bits, 1 stop bit.
③. Turn off hardware and software flow control.
After setting, as shown in Figure 63.8.2.1:
insert image description here
After setting, you can wait for the GPS data output quietly. It may take a few minutes for the GPS module to search for satellites for the first time, and the
positioning data will be output only after the satellites are found. After the satellite is found, the positioning data output by the GPS module is
shown in Figure 63.8.2.2:
insert image description here

Guess you like

Origin blog.csdn.net/zhuguanlin121/article/details/129894275