Linux 串口RS232/485/GPS 驱动实验(移植minicom)

您所在的位置:网站首页 rfa是什么文件 Linux 串口RS232/485/GPS 驱动实验(移植minicom)

Linux 串口RS232/485/GPS 驱动实验(移植minicom)

#Linux 串口RS232/485/GPS 驱动实验(移植minicom)| 来源: 网络整理| 查看: 265

目录 Linux 下UART 驱动框架I.MX6U UART 驱动分析硬件原理图分析RS232 驱动编写移植minicomRS232 驱动测试RS232 连接设置minicom 设置RS232 收发测试 RS485 测试RS485 连接设置RS485 收发测试 GPS 测试GPS 连接设置GPS 数据接收测试

串口是很常用的一个外设,在Linux 下通常通过串口和其他设备或传感器进行通信,根据 电平的不同,串口分为TTL 和RS232。不管是什么样的接口电平,其驱动程序都是一样的,通 过外接RS485 这样的芯片就可以将串口转换为RS485 信号,正点原子的I.MX6U-ALPHA 开发 板就是这么做的。对于正点原子的I.MX6U-ALPHA 开发板而言,RS232、RS485 以及GPS 模 块接口通通连接到了I.MX6U 的UART3 接口上,因此这些外设最终都归结为UART3 的串口驱 动。本章我们就来学习一下如何驱动I.MX6U-ALPHA 开发板上的UART3 串口,进而实现RS232、 RS485 以及GSP 驱动。

Linux 下UART 驱动框架

1、uart_driver 注册与注销 同I2C、SPI 一样,Linux 也提供了串口驱动框架,我们只需要按照相应的串口框架编写驱 动程序即可。串口驱动没有什么主机端和设备端之分,就只有一个串口驱动,而且这个驱动也 已经由NXP 官方已经编写好了,我们真正要做的就是在设备树中添加所要使用的串口节点信 息。当系统启动以后串口驱动和设备匹配成功,相应的串口就会被驱动起来,生成 /dev/ttymxcX(X=0….n)文件。 虽然串口驱动不需要我们去写,但是串口驱动框架我们还是需要了解的,uart_driver 结构 体表示UART 驱动,uart_driver 定义在include/linux/serial_core.h 文件中,内容如下:

示例代码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 };

每个串口驱动都需要定义一个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 文件,内容如下 (有省略):

示例代码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 };

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 文件中,内容如下:

示例代码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 驱动编写人员需要实现uart_ops,因为uart_ops 是最底层的UART 驱动接口,是实 实在在的和UART 寄存器打交道的。关于uart_ops 结构体中的这些函数的具体含义请参考 Documentation/serial/driver 这个文档。 UART 驱动框架大概就是这些,接下来我们理论联系实际,看一下NXP 官方的UART 驱动文件是如何编写的。

I.MX6U UART 驱动分析

1、UART 的platform 驱动框架 打开imx6ull.dtsi 文件,找到UART3 对应的子节点,子节点内容如下所示:

示例代码63.2.1 uart3 设备节点 1 uart3: serial@021ec000 { 2 compatible = "fsl,imx6ul-uart", 3 "fsl,imx6q-uart", "fsl,imx21-uart"; 4 reg = ; 5 interrupts = ; 6 clocks = , 7 ; 8 clock-names = "ipg", "per"; 9 dmas = , ; 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,在此文件中可以找到如下内容:

示例代码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);

可以看出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 定义如下:

示例代码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、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 结构体内容如下所示(有缩减):

示例代码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 };

第217 行,uart_port 成员变量port。 接下来看一下serial_imx_probe 函数,函数内容如下:

示例代码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 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->pormbase = 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 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 定义如下:

示例代码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 };

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

硬件原理图分析

本实验要用到的I.MX6U 的UART3 接口,I.MX6U-ALPHA 开发板上RS232、RS485 和GPS 这三个接口都连接到了UART3 上,我们依次来看一下这三个模块的原理图。 1、RS232 原理图 RS232 原理图如图63.3.1 所示: 在这里插入图片描述 从图63.3.1 可以看出,RS232 电平通过SP3232 这个芯片来实现,RS232 连接到了I.MX6U 的UART3 接口上,但是要通过JP1 这个跳线帽设置。把JP1 的1-3 和2-4 连接起来以后SP3232 就和UART3 连接到了一起。 2、RS485 原理图 RS485 原理图如图63.3.2 所示: 在这里插入图片描述 RS485 采用SP3485 这颗芯片来实现,RO 为数据输出端,RI 为数据输入端,RE 是接收使 能信号(低电平有效),DE 是发送使能信号(高电平有效)。在图63.3.2 中RE 和DE 经过一系列 的电路,最终通过RS485_RX 来控制,这样我们可以省掉一个RS485 收发控制IO,将RS485 完全当作一个串口来使用,方便我们写驱动。 3、GPS 原理图 正点原子有一款GPS+北斗定位模块,型号为ATK1218-BD,I.MX6U-ALPHA 开发板留出 了这款GPS 定位模块的接口,接口原理图如图63.3.3 所示: 在这里插入图片描述 从图63.3.3 可以看出,GPS 模块用的也是UART3,因此UART3 驱动成功以后就可以直接 读取GPS 模块数据了。

RS232 驱动编写

前面我们已经说过了,I.MX6U 的UART 驱动NXP 已经编写好了,所以不需要我们编写。 我们要做的就是在设备树中添加UART3 对应的设备节点即可。打开imx6ull-alientek-emmc.dts 文件,在此文件中只有UART1 对应的uart1 节点,并没有UART3 对应的节点,因此我们可以 参考uart1 节点创建uart3 节点。 1、UART3 IO 节点创建 UART3 用到了UART3_TXD 和UART3_RXD 这两个IO,因此要先在iomuxc 中创建UART3 对应的pinctrl 子节点,在iomuxc 中添加如下内容:

示例代码63.4.1 UART3 引脚pinctrl 节点 1 pinctrl_uart3: uart3grp { 2 fsl,pins = ; 6 };

最后检查一下UART3_TX 和UART3_RX 这两个引脚有没有被用作其他功能,如果有的话 要将其屏蔽掉,保证这两个IO 只用作UART3,切记!!! 2、添加uart3 节点 默认情况下imx6ull-alientek-emmc.dts 中只有uart1 和uart2 这两个节点,如图63.4.1 所示: 在这里插入图片描述 uart1 是UART1 的,在正点原子的I.MX6U-ALPHA 开发板上没有用到UART2,而且UART2 默认用到了UART3 的IO,因此需要将uart2 这个节点删除掉,然后加上UART3 对应的uart3, uart3 节点内容如下:

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

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

移植minicom

minicom 类似我们常用的串口调试助手,是Linux 下很常用的一个串口工具,将minicom 移植到我们的开发板中,这样我们就可以借助minicom 对串口进行读写操作。 1、移植ncurses minicom 需要用到ncurses,因此需要先移植ncurses,如果前面已经移植好了ncurses,那么 这里就不需要再次移植了,只需要在编译minicom 的时候指定ncurses 库和头文件目录即可。 首先在ubuntu 中创建一个目录来存放我们要移植的文件,比如我在 /home/zuozhongkai/linux/IMX6ULL 目录下创建了一个名为“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/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 就是配置脚本,–prefix 用于指定编译结果的保存目录,这里肯定将编译结果保存 到我们前面创建的“ncurses”目录中。–host 用于指定编译器前缀,这里设置为“arm-linux- gnueabihf”,–target 用于指定目标,这里也设置为“arm-linux-gnueabihf”。配置命令写好以后点 击回车键,等待配置完成,配置成功以后如图63.5.1 所示: 在这里插入图片描述 配置成功以后输入“make”命令开始编译,编译成功以后如图63.5.2 所示: 在这里插入图片描述 编译成功以后输入“make install”命令安装,安装的意思就是将编译出来的结果拷贝到–pfefix 指定的目录里面去。安装成功以后如图63.5.3 所示:

在这里插入图片描述 安装成功以后查看一下前面创建的“ncurses”文件夹,会发现里面多了一些东西,如图63.5.4 所示: 在这里插入图片描述 我们需要将图63.5.4 中include、lib 和share 这三个目录中存放的文件分别拷贝到开发板根 文件系统中的/usr/include、/usr/lib 和/usr/share 这三个目录中,如果哪个目录不存在的话请自行 创建!!拷贝命令如下:

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

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

示例代码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、移植minicom 继续移植minicom,获取minicom 源码,我们已经放到了开发板光盘中了,路径为:1、例 程源码-》7、第三方库源码-》minicom-2.7.1.tar.gz。将minicom-2.7.1.tar.gz 拷贝到ubuntu 中的 /home/zuozhongkai/linux/IMX6ULL/tool 目录下,然后在tool 目录下新建一个名为“minicom”的 子目录,用于存放minicom 编译结果。一切准备好以后就可以编译minicom 了,先解压minicom, 命令如下:

tar -vxzf minicom-2.7.1.tar.gz

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

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 表示要使用的gcc 交叉编译器,–prefix 指定编译出来的文件存放目录,肯定要存放到 我们前面创建的minicom 目录中。–host 指定交叉编译器前缀,CPPFLAGS 指定ncurses 的头文件路径,LDFLAGS 指定ncurses 的库路径。 配置成功的话如图63.5.5 所示:

在这里插入图片描述 配置成功以后执行如下命令编译并安装:

make make install

编译安装完成以后,前面创建的minicom 目录内容如图63.5.6 所示: 在这里插入图片描述 将minicom 目录中bin 子目录下的所有文件拷贝到开发板根目录中的/usr/bin 目录下,命令 如下:

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

完成以后在开发板中输入“minicom -v”来查看minicom 工作是否正常,结果如图63.5.7 所 示: 在这里插入图片描述 从图63.5.7 可以看出,此时minicom 版本号为2.7.1,minicom 版本号查看正常。输入如下 命令打开minicom 配置界面:

minicom -s

结果是打不开minicom 配置界面,提示如图63.5.8 所示信息: 在这里插入图片描述 从图63.5.8 可以看出,minicom 异常嚣张,竟然让我们“Go away”,这能容忍?!必须要 治一下。解决方法很简单,新建/etc/passwd 文件,然后在passwd 文件里面输入如下所示内容:

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

完成以后重启开发板! 完成以后重启开发板! 开发板重启以后再执行“minicom -s”命令,此时minicom 配置界面就可以打开了,如图 63.5.9 所示: 在这里插入图片描述 如果能出现图63.5.9 所示界面,那么就说明mincom 工作正常了。

RS232 驱动测试 RS232 连接设置

在测试之前要先将I.MX6U-ALPHA 开发板的RS232 与电脑连接起来,首先设置JP1 跳线 帽,如图63.6.1.1 所示: 在这里插入图片描述 跳线帽设置好以后使用RS232 线将开发板与电脑连接起来,这里建议使用USB 转 DB9(RS232)数据线,比如正点原子售卖的CH340 方案的USB 转公头DB9 数据线,如图63.6.1.2 所示: 在这里插入图片描述 图63.6.1.2 中所示的数据线是带有CH340 芯片的,因此当连接到电脑以后就会出现一个 COM 口,这个COM 口就是我们要使用的COM 口。比如在我的电脑上就是COM9,在SecureCRT 上新建一个连接,串口为COM9,波特率为115200。

minicom 设置

在开发板中输入“minicom -s”,打开minicom 配置界面,然后选中“Serial port setup”,如 图63.6.2.1 所示: 在这里插入图片描述 选中“Serial port setup”以后点击回车,进入设置菜单,如图63.6.2.2 所示: 在这里插入图片描述 图63.6.2.2 中有7 个设置项目,分别对应A、B……G,比如第一个是选中串口,UART3 的 串口文件为/dev/ttymxc2,因此串口设备要设置为/dev/ttymxc2。设置方法就是按下键盘上的‘A’, 然后输入“/dev/ttymxc2”即可,如图63.6.2.3 所示: 在这里插入图片描述 设置完以后按下回车键确认,确认完以后就可以设置其他的配置项。比如E 设置波特率、 数据位和停止位的、F 设置硬件流控的,设置方法都一样,设置完以后如图63.6.2.4 所示: 在这里插入图片描述 都设置完成以后按下回车键确认并退出,这时候会退回到如图63.6.2.1 所示的界面,按下 ESC 键退出图63.6.2.1 所示的配置界面,退出以后如图63.6.2.5 所示: 在这里插入图片描述 图63.6.2.2 就是我们的串口调试界面,可以看出当前的串口文件为/dev/ttymxc2,按下CTRL- A,然后再按下Z 就可以打开minicom 帮助信息界面,如图63.6.2.6 所示: 在这里插入图片描述 从图63.6.2.6 可以看出,minicom 有很多快捷键,本实验我们打开minicom 的回显功能, 回显功能配置项为“local Echo on/off…E”,因此按下E 即可打开/关闭回显功能。

RS232 收发测试

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

图63.6.3.1 中的“AAAA”相当于开发板通过UART3 向电脑发送“AAAA”,那么COM9 就会接收到“AAAA”,SecureCRT 中COM9 收到的数据如图63.6.3.2 所示: 在这里插入图片描述 可以看出,开发板通过UART3 向电脑发送数据正常,那么接下来就测试开发板数据接收 功能。 2、接收测试 接下来测试开发板的UART3 接收功能,同样的,要先打开SecureCRT 上COM9 的本地回 显,否则的话你在COM9 上输出的内容会看不到,但是实际上是已经发送给了开发板。选中 SecureCRT 的Options->Session Options->Adavnced,打开回话配置界面,然后选中“Local echo”, 如图63.6.3.3 所示: 在这里插入图片描述 SecureCRT设置好以后向开发板发送一个“BBBB”,在SecureCRT 的COM9 上输入“BBBB”, 如图63.6.3.3 所示: 在这里插入图片描述 此时开发板的minicom 就会接收到发送过来的“BBBB”,如图63.6.3.4 所示: 在这里插入图片描述 UART3 收发测试都没有问题,说明我们的UART3 驱动工作正常。如果要退出minicom 的 话,在minicom 通信界面按下CRTL+A,然后按下X 来关闭minicom。关于minicom 的使用我 们这里讲的很简单,大家可以在网上查找更加详细的minicom 使用教程。

RS485 测试

前面已经说过了,I.MX6U-ALPHA 开发板上的RS485 接口连接到了UART3 上,因此本质 上就是个串口。RS232 实验我们已经将UART3 的驱动编写好了,所以RS485 实验就不需要编 写任何驱动程序,可以直接使用minicom 来进行测试。

RS485 连接设置

首先是设置JP1 跳线帽,将3-5、4-6 连接起来,如图63.7.1.1 所示: 在这里插入图片描述 一个板子是不能进行RS485 通信测试的,还需要另一个RS485 设备,比如另外一块I.MX6U-ALPHA 开发板。这里推荐大家使用正点原子出品的USB 三合一串口转换器,支持USB 转TTL、 RS232 和RS485,如图63.7.1.2 所示: 在这里插入图片描述 使用杜邦线将USB 串口转换器的RS485 接口和I.MX6U-ALPHA 开发板的RS485 连接起 来,A 接A,B 接B,不能接错了!连接完成以后如图63.7.1.3 所示: 在这里插入图片描述 串口转换器通过USB 线连接到电脑上,我用的是CH340 版本的,因此就不需要安装驱动 的,如果使用的是FT232 版本的就需要安装相应的驱动。连接成功以后电脑就会有相应的COM 口,比如我的电脑上就是COM10,接下来就是测试。

RS485 收发测试

RS485 的测试和RS232 一模一样!USB 多合一转换器的COM 口为10,因此使用SecureCRT 创建一个COM10 的连接。开发板使用UART3,对应的串口设备文件为/dev/ttymxc2,因此开发 板使用minicom 创建一个/dev/ttymxc2 的串口连接。串口波特率都选择115200,8 位数据位,1 位停止位,关闭硬件和软件流控。 1、RS485 发送测试 首先测试开发板通过RS485 发送数据,设置好minicom 以后,同样输入“AAAA”,也就是 通过RS485 向电脑发送一串“AAAA”。如果RS485 驱动工作正常的话,那么电脑就会接收到 开发板发送过来的“AAAA”,如图63.7.2.1 所示: 在这里插入图片描述 从图63.7.2.1 可以看出开发板通过RS485 向电脑发送“AAAA”成功,说明RS485 数据数 据发送正常。 2、RS485 接收测试 接下来测试一下RS485 数据接收,电脑通过RS485 向开发板发送“BBBB”,然后观察 minicom 是否能接收到“BBBB”。结果如图63.7.2.2 所示: 在这里插入图片描述 从图63.7.2.1 可以看出开发板接收到电脑通过RS485 发送过来的“BBBB”,说明RS485 数 据接收也正常。

GPS 测试 GPS 连接设置

GPS 模块大部分都是串口输出的,这里以正点原子出品的ATK1218-BD 模块为例,这是 一款GSP+北斗的定位模块,模块如图63.8.1.1 所示: 在这里插入图片描述 首先要将I.MX6U-ALPHA 开发板上的JP1 跳线帽拔掉,不能连接RS232 或RS485,否则 会干扰到GSP 模块。UART3_TX 和UART3_RX 已经连接到了开发板上的ATK MODULE 上, 直接将ATK1218-BD 模块插到开发板上的ATK MODULE 接口即可,开发板上的ATK MODULE 接口是6 脚的,而ATK1218-BD 模块是5 脚的,因此需要靠左插!然后GPS 需要接上天线,天 线的接收头一定要放到户外,因此室内一般是没有GPS 信号的。连接完成以后如图63.8.1.2 所 示: 在这里插入图片描述

GPS 数据接收测试

GPS 我们都是被动接收定位数据的,因此打开minicom,设置/dev/ttymxc2,串口设置要求 如下: ①、波特率设置为38400,因为正点原子的ATK1218-BD 模块默认波特率就是38400。 ②、8 位数据位,1 位停止位。 ③、关闭硬件和软件流控。 设置好以后如图63.8.2.1 所示: 在这里插入图片描述 设置好以后就可以静静的等待GPS 数据输出,GPS 模块第一次启动可能需要几分钟搜星, 等搜到卫星以后才会有定位数据输出。搜到卫星以后GPS 模块输出的定位数据如图63.8.2.2 所 示: 在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3