文章目录

  • 一、linux下的UART驱动框架
    • 1. uart_driver 注册与注销
    • 2. uart_port 的添加与移除
    • 3. uart_ops 实现
  • 二、6u UART驱动分析
    • 1. UART 的 的 platform 驱动框架
    • 2. uart_driver 初始化
    • 3. uart_port 初始化与添加
    • 4. imx_pops 结构体变量
  • 三、原理图分析
  • 四、RS232驱动编写
    • 1. UART3 IO 节点创建
    • 2. 添加 uart3 节点
  • 五、移植minicom
    • 1. 移植ncurses
    • 2. 移植 minicom
  • 六、RS232驱动测试
    • 1. RS232连接设置
    • 2. minicom设置
    • 3. RS232收发测试
      • 1. 发送测试
      • 2. 接收测试

串口是很常用的一个外设,在 Linux 下通常通过串口和其他设备或传感器进行通信,根据电平的不同,串口分为 TTL 和 RS232。不管是什么样的接口电平,其驱动程序都是一样的,通过外接 RS485 这样的芯片就可以将串口转换为 RS485 信号,正点原子的 I.MX6U-ALPHA 开发板就是这么做的。

对于正点原子的 I.MX6U-ALPHA 开发板而言, RS232、RS485 以及 GPS 模块接口通通连接到了 I.MX6U 的 UART3 接口上,因此这些外设最终都归结为 UART3 的串口驱动。

本章我们就来学习一下如何驱动 I.MX6U-ALPHA 开发板上的 UART3 串口,进而实现 RS232驱动。

一、linux下的UART驱动框架

1. uart_driver 注册与注销

同 I2C、SPI 一样,Linux 也提供了串口驱动框架,我们只需要按照相应的串口框架编写驱动程序即可。串口驱动没有什么主机端和设备端之分,就只有一个串口驱动,而且这个驱动也已经由 NXP 官方已经编写好了,我们真正要做的就是在设备树中添加所要使用的串口节点信息。

当系统启动以后串口驱动和设备匹配成功,相应的串口就会被驱动起来,生成/dev/ttymxcX(X=0….n)文件。

虽然串口驱动不需要我们去写,但是串口驱动框架我们还是需要了解的,uart_driver 结构体表示 UART 驱动,uart_driver 定义在 include/linux/serial_core.h 文件中,内容如下:

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 };

每个串口驱动都需要定义一个 uart_driver,加载驱动的时候通过 uart_register_driver 函数向系统注册这个 uart_driver,此函数原型如下:

int uart_register_driver(struct uart_driver *drv)

函数参数和返回值含义如下:

drv :要注册的 uart_driver。
返回值:0,成功;负值,失败。

注销驱动的时候也需要注销掉前面注册的 uart_driver,需要用到 uart_unregister_driver 函数,函数原型如下:

void uart_unregister_driver(struct uart_driver *drv)

函数参数和返回值含义如下:

drv :要注销的 uart_driver。
返回值:无。

2. uart_port 的添加与移除

uart_port 表示一个具体的 port,uart_port 定义在 include/linux/serial_core.h 文件,内容如下(有省略):

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 };

uart_port 中最主要的就是第 235 行的 ops,ops 包含了串口的具体驱动函数,这个我们稍后再看。每个 UART 都有一个 uart_port,那么 uart_port 是怎么和 uart_driver 结合起来的呢?这里要用到 uart_add_one_port 函数,函数原型如下:

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

函数参数和返回值含义如下:

drv:此 port 对应的 uart_driver。
uport :要添加到 uart_driver 中的 port。
返回值:0,成功;负值,失败。

卸载 UART 驱动的时候也需要将 uart_port 从相应的 uart_driver 中移除,需要用到uart_remove_one_port 函数,函数原型如下:

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

函数参数和返回值含义如下:

drv:要卸载的 port 所对应的 uart_driver。
uport :要卸载的 uart_port。
返回值:0,成功;负值,失败。

3. uart_ops 实现

在上面讲解 uart_port 的时候说过,uart_port 中的 ops 成员变量很重要,因为 ops 包含了针对 UART 具体的驱动函数,Linux 系统收发数据最终调用的都是 ops 中的函数。ops 是 uart_ops类型的结构体指针变量,uart_ops 定义在 include/linux/serial_core.h 文件中,内容如下

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 驱动编写人员需要实现 uart_ops,因为 uart_ops 是最底层的 UART 驱动接口,是实实在在的和 UART 寄存器打交道的。

关于 uart_ops 结构体中的这些函数的具体含义请参考
Documentation/serial/driver 这个文档。

UART 驱动框架大概就是这些,接下来我们理论联系实际,看一下 NXP 官方的 UART 驱动文件是如何编写的。

二、6u UART驱动分析

1. UART 的 的 platform 驱动框架

打开 imx6ull.dtsi 文件,找到 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 };

重点看一下第 2,3 行的 compatible 属性,这里一共有三个值:“fsl,imx6ul-uart”、“fsl,imx6q-uar”和“fsl,imx21-uart”。在 linux 源码中搜索这三个值即可找到对应的 UART 驱动文件,此文件为 drivers/tty/serial/imx.c,在此文件中可以找到如下内容:

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);

可以看出 I.MX6U 的 UART 本质上是一个 platform 驱动,
第 267~280 行,imx_uart_devtype为传统匹配表。
第 283~288 行,设备树所使用的匹配表,第 284 行的 compatible 属性值为“fsl,imx6q-uart”。
第 2071~2082 行,platform 驱动框架结构体 serial_imx_driver。
第 2084~2096 行,驱动入口函数,第 2086 行调用uart_register_driver 函数向 Linux 内核注册 uart_driver,在这里就是 imx_reg。
第 2098~2102 行,驱动出口函数,第 2101 行调用 uart_unregister_driver 函数注销掉前面注册的 uart_driver,也就是 imx_reg。

2. uart_driver 初始化

在 imx_serial_init 函数中向 Linux 内核注册了 imx_reg,imx_reg 就是 uart_driver 类型的结构体变量,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. uart_port 初始化与添加

当 UART 设备和驱动匹配成功以后 serial_imx_probe 函数就会执行,此函数的重点工作就是初始化 uart_port,然后将其添加到对应的 uart_driver 中。在看 serial_imx_probe 函数之前先来看一下 imx_port 结构体,imx_port 是 NXP 为 I.MX 系列 SOC 定义的一个设备结构体,此结构体内部就包含了 uart_port 成员变量,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 };

第 217 行,uart_port 成员变量 port。

接下来看一下 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 }

第 1971 行,定义一个 imx_port 类型的结构体指针变量 sport。
第 1977 行,为 sport 申请内存。
第 1987~1988 行,从设备树中获取 I.MX 系列 SOC UART 外设寄存器首地址,对于I.MX6ULL 的 UART3 来说就是 0X021EC000。得到寄存器首地址以后对其进行内存映射,得到对应的虚拟地址。
第 1992~1994 行,获取中断信息。
第 1996~2034 行,初始化 sport,
第 2003 行初始化 sport 的 port 成员变量,也就是设置 uart_ops 为 imx_pops,imx_pops 就是 I.MX6ULL 最底层的驱动函数集合,稍后再来看。
第 2040~2055 行,申请中断。
第 2061 行,使用 uart_add_one_port 向 uart_driver 添加 uart_port,在这里就是向 imx_reg 添加 sport->port。

4. imx_pops 结构体变量

imx_pops 就是 uart_ops 类型的结构体变量,保存了 I.MX6ULL 串口最底层的操作函数,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 };

imx_pops 中的函数基本都是和 I.MX6ULL 的 UART 寄存器打交道的,这里就不去详细的分析了。简单的了解了 I.MX6U 的 UART 驱动以后我们再来学习一下,如何驱动正点原子I.MX6U-ALPHA 开发板上的 UART3 接口。

三、原理图分析

本实验要用到的 I.MX6U 的 UART3 接口,I.MX6U-ALPHA 开发板上 RS232、这个接口都连接到了 UART3 上,我们依次来看一下这三个模块的原理图。

可以看出,RS232 电平通过 SP3232 这个芯片来实现,RS232 连接到了 I.MX6U的 UART3 接口上,但是要通过 JP1 这个跳线帽设置。把 JP1 的 1-3 和 2-4 连接起来以后 SP3232就和 UART3 连接到了一起。

四、RS232驱动编写

我们要做的就是在设备树中添加 UART3 对应的设备节点即可。打开 imx6ull-luatao-emmc.dts文件,在此文件中只有 UART1 对应的 uart1 节点,并没有 UART3 对应的节点,因此我们可以参考 uart1 节点创建 uart3 节点。

1. UART3 IO 节点创建

UART3用到了UART3_TXD和UART3_RXD这两个IO,因此要先在iomuxc中创建UART3对应的 pinctrl 子节点,在 iomuxc 中添加如下内容:

 pinctrl_uart3: uart3grp {fsl,pins = <MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0X1b0b14MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0X1b0b1>;};


最后检查一下 UART3_TX 和 UART3_RX 这两个引脚有没有被用作其他功能,如果有的话要将其屏蔽掉,保证这两个 IO 只用作 UART3,切记!!!

2. 添加 uart3 节点

默认情况下 imx6ull-luatao-emmc.dts 中只有 uart1 和 uart2 这两个节点,如图所示:

uart1 是UART1的,在正点原子的 I.MX6U-ALPHA 开发板上没有用到UART2,而且UART2默认用到了 UART3 的 IO,因此需要将 uart2 这个节点删除掉,然后加上 UART3 对应的 uart3,uart3 节点内容如下:

&uart3 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart3>;status = "okay";
};

完成以后重新编译设备树并使用新的设备树启动 Linux,如果设备树修改成功的话,系统启动以后就会生成一个名为“/dev/ttymxc2”的设备文件,ttymxc2 就是 UART3 对应的设备文件,应用程序可以通过访问 ttymxc2 来实现对 UART3 的操作。

五、移植minicom

minicom 类似我们常用的串口调试助手,是 Linux 下很常用的一个串口工具,将 minicom移植到我们的开发板中,这样我们就可以借助 minicom 对串口进行读写操作。

1. 移植ncurses

minicom 需要用到 ncurses,依次需要先移植 ncurses,如果前面已经移植好了 ncurses,那么这里就不需要再次移植了,只需要在编译 minicom 的时候指定 ncurses 库和头文件目录 即可。

首 先 在 ubuntu 中 创 建 一 个 目 录 来 存 放 我 们 要 移 植 的 文 件 , 比 如 我在/home/luatao/linux/目录下创建了一个名为“tool”的目录来存放所有的移植文件。

然后下载 ncurses 源码,我们已经将 ncurses 源码放到了开发板光盘中,路径为:1、例程源码-》7、第三方库源码-》ncurses-6.0.tar.gz,

将 ncurses-6.0.tar.gz 拷贝到 Ubuntu 中创建的 tool 目录下,然后进行解压,解压命令如下:

tar -vxzf ncurses-6.0.tar.gz


解压完成以后就会生成一个名为“ncurses-6.0”的文件夹,此文件夹就是 ncurese 的源码文件夹。在 tool 目录下新建名为“ncurses”目录,用于保存 ncurses 编译结果,一切准备就绪以后就可以编译 ncureses 库了。

进入到 ncureses 源码目录下,也就是刚刚解压出来的 ncurses-6.0 目录中,首先是配置 ncureses,输入如下命令:

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

configure 就是配置脚本,–prefix 用于指定编译结果的保存目录,这里肯定将编译结果保存到我们前面创建的“ncurses”目录中。–host 用于指定编译器前缀,这里设置为 “arm-linux-gnueabihf”,–target 用于指定目标,这里也设置为“arm-linux-gnueabihf”。

配置命令写好以后点击回车键,等待配置完成,配置成功以后如图所示:

配置成功以后输入“make”命令开始编译,编译成功以后如图所示

编译成功以后输入“make install”命令安装,安装的意思就是将编译出来的结果拷贝到–pfefix 指定的目录里面去。安装成功以后如图所示:


安装成功以后查看一下前面创建的“ncurses”文件夹,会发现里面多了一些东西,如图所示

我们需要将图中 include、lib 和 share 这三个目录中存放的文件分别拷贝到开发板根文件系统中的/usr/include、/usr/lib 和/usr/share 这三个目录中,如果哪个目录不存在的话请自行创建!!拷贝命令如下:

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

然后在开发板根目录的/etc/profile(没有的话自己创建一个)文件中添加如下所示内容:

vi ../../nfs/rootfs/etc/profile1 #!/bin/sh2 LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH3 export LD_LIBRARY_PATH4 5 export TERM=vt1006 export TERMINFO=/usr/share/terminfo

2. 移植 minicom

继续移植 minicom,获取 minicom 源码,我们已经放到了开发板光盘中了,路径为:1、例程源码-》7、第三方库源码-》minicom-2.7.1.tar.gz。

将 minicom-2.7.1.tar.gz 拷贝到 ubuntu 中的/home/luatao/linux/tool 目录下,然后在 tool 目录下新建一个名为“minicom”的子目录,用于存放minicom编译结果。一切准备好以后就可以编译minicom了,先解压minicom,命令如下:

tar -vxzf minicom-2.7.1.tar.gz

解压完成以后会生成一个叫做 minicom-2.7.1 的文件夹,这个就是 minicom 的源码,进入到此目录中,然后配置 minicom,配置命令如下:

./configure CC=arm-linux-gnueabihf-gcc --prefix=/home/luatao/linux/tool/minicom --host=arm-linux-gnueabihf CPPFLAGS=-I/home/luatao/linux/tool/ncurses/include LDFLAGS=-L/home/luatao/linux/tool/ncurses/lib -enable-cfg-dir=/etc/minicom

CC 表示要使用的 gcc 交叉编译器,–prefix 指定编译出来的文件存放目录,肯定要存放到我们前面创建的 minicom 目录中。–host 指定交叉编译器前缀,CPPFLAGS 指定 ncurses 的头文件路径
LDFLAGS 指定 ncurses 的库路径。

配置成功的话如图

配置成功以后执行如下命令编译并安装:

make
make install

编译安装完成以后,前面创建的 minicom 目录内容如图

将 minicom 目录中 bin 子目录下的所有文件拷贝到开发板根目录中的/usr/bin 目录下,命令如下:

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

完成以后在开发板中输入“minicom -v”来查看 minicom 工作是否正常,结果如图所示:

可以看出,此时 minicom 版本号为 2.7.1,minicom 版本号查看正常。输入如下命令打开 minicom 配置界面:

minicom -s

结果是打不开 minicom 配置界面,提示如图

可以看出,minicom 异常嚣张,竟然让我们“Go away”,这能容忍?!必须要治一下。

解决方法很简单,新建/etc/passwd 文件,然后在 passwd 文件里面输入如下所示内容:

root:x:0:0:root:/root:/bin/sh


开发板重启以后再执行“minicom -s”命令,此时 minicom 配置界面就可以打开了,如图

mincom 工作正常了

六、RS232驱动测试

1. RS232连接设置

在测试之前要先将 I.MX6U-ALPHA 开发板的 RS232 与电脑连接起来,首先设置 JP1 跳线帽,如图所示:

跳线帽设置好以后使用 RS232 线将开发板与电脑连接起来,这里建议使用 USB 转DB9(RS232)数据线,比如正点原子售卖的 CH340 方案的 USB 转公头 DB9 数据线,如图 所示:

2. minicom设置

在开发板中输入“minicom -s”,打开 minicom 配置界面,然后选中“Serial port setup”,如图

选中“Serial port setup”以后点击回车,进入设置菜单,如图

有 7 个设置项目,分别对应 A、B……G,比如第一个是选中串口,UART3 的串口文件为/dev/ttymxc2,因此串口设置要设置为/dev/ttymxc2。设置方法就是按下键盘上的‘A’,然后输入“/dev/ttymxc2”即可,如图所示

设置完以后按下回车键确认,确认完以后就可以设置其他的配置项。比如 E 设置波特率、数据位和停止位的、F 设置硬件流控的,设置方法都一样,设置完以后如图

都设置完成以后按下回车键确认并退出,这时候会退回到如图所示的界面,按下ESC 键退出图所示的配置界面,退出以后如图

就是我们的串口调试界面,可以看出当前的串口文为/dev/ttymxc2,按下CTRL-A,然后再按下 Z 就可以打开 minicom 帮助信息界面,如图

可以看出,minicom 有很多快捷键,本实验我们打开 minicom 的回显功能,回显功能配置项为“local Echo on/off…E”,因此按下 E 即可打开/关闭回显功能。

3. RS232收发测试

1. 发送测试

首先测试开发板通过 UART3 向电脑发送数据的功能,需要打开 minicom 的回显功能(不打开也可以,但是在 minicom 中看不到自己输入的内容),回显功能打开以后输入“AAAA”,如图

图中的“AAAA”相当于开发板通过 UART3 向电脑发送“AAAA”,那么 COM9就会接收到“AAAA”,SecureCRT 中 COM9 收到的数据如图所示:

可以看出,开发板通过 UART3 向电脑发送数据正常,那么接下来就测试开发板数据接收功能。

2. 接收测试

接下来测试开发板的 UART3 接收功能,同样的,要先打开 SecureCRT 上 COM9 的本地回显,否则的话你在 COM9 上输出的内容会看不到,但是实际上是已经发送给了开发板。

选中SecureCRT 的 Options->Session Options->Adavnced,打开回话配置界面,然后选中“Local echo”,如图所示:

SecureCRT设置好以后向开发板发送一个“BBBB”,在SecureCRT的COM9上输入“BBBB”,如图

此时开发板的 minicom 就会接收到发送过来的“BBBB”,如图

UART3 收发测试都没有问题,说明我们的 UART3 驱动工作正常。如果要退出 minicom 的话,在 minicom 通信界面按下 CRTL+A,然后按下 X 来关闭 minicom。关于 minicom 的使用我们这里讲的很简单,大家可以在网上查找更加详细的 minicom 使用教程。

linux UART(RS232/485)驱动实验相关推荐

  1. i.MX6ULL终结者Linux RS232/485驱动实验i.MX6UL UART驱动分析

    文章目录 1 uart的platform驱动框架 2 uart_driver初始化 3 uart_port初始化和注册 4 imx_pops结构体 1 uart的platform驱动框架 首先看一下在 ...

  2. 迅为linux下串口,迅为IMX6ULL开发板Linux RS232/485驱动实验(上)

    在 arm 设备中串口是很常用的一个外设,不仅可以用来打印信息,还可以用于外接设备和其他传感器通信.根据不同的电平,串口分为 TTL 和 RS232,但是在Linux内核中的驱动程序是一样的,在串口上 ...

  3. linux 串口驱动 atmel_set_mctrl何时调用,linux uart serial使用驱动分析

    uart tty serial 驱动分析 内核版本3.14.23 以atmel为例: 起点: static int __init atmel_serial_init(void) { int ret; ...

  4. linux+fc+网卡驱动,Linux下DM9000网卡驱动实验〈三〉

    驱动程序共包含三个文件dm9000x.c,dm9000.c和dm9000.h,都存放在drivers/net/目录下,其中dm9000x.c主要包括以下函数: 底层硬件操作函数:这些函数与硬件相关,与 ...

  5. UART RS-232 485通信 串口通信传输时间计算 波特率计算

    波特率:是指串行端口每秒内可以传输的波特位数. 有一些初学的朋友认为波特率是指每秒传输的字节数,如标准9600会被误认为每秒种可以传送9600个字节,而实际上它是指每秒可以传送9600个二进位,而一个 ...

  6. Linux RS232/485/GPS 驱动实验(2)-UART 驱动分析

    1.UART 的 platform 驱动框架 打开 imx6ull.dtsi 文件,找到 UART3 对应的子节点,子节点内容如下所示: 1 uart3: serial@021ec000 { 2 co ...

  7. 正点原子linux串口驱动下载,「正点原子Linux连载」第六十三章Linux RS232/485/GPS驱动实验...

    1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南>关注官方微信号公众号,获取更多资料:正点原子 第六十三章Linux RS232/485/ ...

  8. 【正点原子Linux连载】第六十三章 Linux RS232/485/GPS驱动实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  9. STM32MP157驱动开发——Linux RS232/485/GPS 驱动

    STM32MP157驱动开发--Linux RS232/485/GPS 驱动 一.简介 二.STM32MP1 UART 驱动分析 1.UART 的 platform 驱动框架 2.uart_drive ...

  10. linux uart寄存器 代替 printk,Linux驱动学习之设备树(设备树下的LED驱动实验),...

    Linux驱动学习之设备树(设备树下的LED驱动实验), 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.相当于从驱动代码分离出来的配置文件,比如串口的波特率通过设 ...

最新文章

  1. 梦想的地方!地球上最值得去的20个地方【组图】
  2. 2021腾讯数字生态大会:腾讯安全聚焦安全共建,护航数字经济发展
  3. Python 网易新闻热点新闻爬虫
  4. request如何setParamter
  5. python2.7+opencv3.1人脸识别
  6. SAP CRM系统里Opportunity预期销售金额和货币相关的自动转换
  7. jmeter测试java服务_Jmeter 测试 JMS (Java Message Service)/ActiveMQ 性能
  8. 【FICO 汇率】汇率
  9. win10系统预览体验计划错误代码0x800bfa19怎么办
  10. decimal(10,2) 的含义
  11. Apache Dubbo是一款高性能Java RPC框架。
  12. [转]MySQL修改root密码的多种方法
  13. 【ROS学习】ROS中四元数与欧拉角的转换
  14. C++之 Eigen-3.4.0 全方位教程:Chapter02-矩阵篇
  15. 无人机航摄地面站航线设计主要参数
  16. 拉姆达Lambda表达式对list分页,获取list总页数
  17. CentOS yum方式升级内核kernel
  18. 汪延谈王志东离职问题 (转)
  19. Codeforces Round #827 (Div. 4) D - F
  20. ubuntu系统vim常用命令学习以及ubuntu软件下载安装

热门文章

  1. 文件加密系统,随时保护终端数据安全
  2. denseNet 详解
  3. 基于matlab的信号与系统课程设计,信号与系统课程设计基于 MATLAB 完成信号与系统综合设计实验...
  4. stm32获取绝对值编码器值(SSI,串行通讯)
  5. 小程序商城源码,小程序源码带前端+后台+数据库 ,免费分享
  6. redis基础知识——菜鸟教程
  7. android 扇形统计动画,Android自定义View——扇形统计图的实现代码
  8. lopatkin俄大神精简中文系统Windows 10 Pro 18898.1000 20H1 PreRelease x86-x64 ZH-CN DREY
  9. 《推荐系统实践》算法纯享(附代码链接)(三)—— 冷启动篇
  10. 中石油企业微信私有版设置服务器,企业微信授权配置教程