RZ/G2L串口简介
瑞萨RZ/G2L的串口简称SCI,全称Serial Communication Interface。
RZ/G2L有两种串口,一种带FIFO叫SCIFA,另一种不带FIFO叫SCIg。
所以,RZ/G2L有5路SCIFA和2路SCIg总共7路的串口。
RZ/G2L串口驱动
包含驱动代码和设备树两部分:
内核中的驱动文件sh-sci.c
该源码文件路径:drivers/tty/serial/sh-sci.c,该驱动代码包含SCIFA和SCIg两种型号的完整驱动代码。
编译内核的时候需进行以下配置
egrep -rin "CONFIG_SERIAL_SH_SCI" .out/.config 2180:CONFIG_SERIAL_SH_SCI=y 2181:CONFIG_SERIAL_SH_SCI_NR_UARTS=18 2182:CONFIG_SERIAL_SH_SCI_CONSOLE=y 2183:CONFIG_SERIAL_SH_SCI_EARLYCON=y 2184:CONFIG_SERIAL_SH_SCI_DMA=y
该配置能够确保sh-sci.c的驱动代码能够被编译包含到Image中。
github上提供的内核源码的defconfig中默认已包含SCI驱动代码的编译。
SCI串口的设备树节点在r9a07g044.dtsi中定义,分别定义了scif0~4, sci0~1共7路。
scif0: serial@1004b800 { compatible = "renesas,scif-r9a07g044"; reg = <0 0x1004b800 0 0x400>; interrupts = <GIC_SPI 380 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 382 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 383 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 381 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 384 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 384 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "eri", "rxi", "txi", "bri", "dri", "tei"; clocks = <&cpg CPG_MOD R9A07G044_SCIF0_CLK_PCK>; clock-names = "fck"; dmas = <&dmac 0x4e79>, <&dmac 0x4e7a>; dma-names = "tx", "rx"; power-domains = <&cpg>; resets = <&cpg R9A07G044_SCIF0_RST_SYSTEM_N>; status = "disabled"; }; scif1: serial@1004bc00 { compatible = "renesas,scif-r9a07g044"; reg = <0 0x1004bc00 0 0x400>; interrupts = <GIC_SPI 385 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 387 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 388 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 386 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 389 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 389 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "eri", "rxi", "txi", "bri", "dri", "tei"; clocks = <&cpg CPG_MOD R9A07G044_SCIF1_CLK_PCK>; clock-names = "fck"; dmas = <&dmac 0x4e7d>, <&dmac 0x4e7e>; dma-names = "tx", "rx"; power-domains = <&cpg>; resets = <&cpg R9A07G044_SCIF1_RST_SYSTEM_N>; status = "disabled"; }; scif2: serial@1004c000 { compatible = "renesas,scif-r9a07g044"; reg = <0 0x1004c000 0 0x400>; interrupts = <GIC_SPI 390 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 392 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 391 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "eri", "rxi", "txi", "bri", "dri", "tei"; clocks = <&cpg CPG_MOD R9A07G044_SCIF2_CLK_PCK>; clock-names = "fck"; dmas = <&dmac 0x4e81>, <&dmac 0x4e82>; dma-names = "tx", "rx"; power-domains = <&cpg>; resets = <&cpg R9A07G044_SCIF2_RST_SYSTEM_N>; status = "disabled"; }; scif3: serial@1004c400 { compatible = "renesas,scif-r9a07g044"; reg = <0 0x1004c400 0 0x400>; interrupts = <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "eri", "rxi", "txi", "bri", "dri", "tei"; clocks = <&cpg CPG_MOD R9A07G044_SCIF3_CLK_PCK>; clock-names = "fck"; dmas = <&dmac 0x4e85>, <&dmac 0x4e86>; dma-names = "tx", "rx"; power-domains = <&cpg>; resets = <&cpg R9A07G044_SCIF3_RST_SYSTEM_N>; status = "disabled"; }; scif4: serial@1004c800 { compatible = "renesas,scif-r9a07g044"; reg = <0 0x1004c800 0 0x400>; interrupts = <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "eri", "rxi", "txi", "bri", "dri", "tei"; clocks = <&cpg CPG_MOD R9A07G044_SCIF4_CLK_PCK>; clock-names = "fck"; dmas = <&dmac 0x4e89>, <&dmac 0x4e8a>; dma-names = "tx", "rx"; power-domains = <&cpg>; resets = <&cpg R9A07G044_SCIF4_RST_SYSTEM_N>; status = "disabled"; }; sci0: serial@1004d000 { compatible = "renesas,r9a07g044-sci", "renesas,rz-sci"; reg = <0 0x1004d000 0 0x400>; interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 406 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 407 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "eri", "rxi", "txi", "tei"; clocks = <&cpg CPG_MOD R9A07G044_SCI0_CLKP>; clock-names = "fck"; power-domains = <&cpg>; resets = <&cpg R9A07G044_SCI0_RST>; status = "disabled"; }; sci1: serial@1004d400 { compatible = "renesas,r9a07g044-sci", "renesas,rz-sci"; reg = <0 0x1004d400 0 0x400>; interrupts = <GIC_SPI 409 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 410 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 411 IRQ_TYPE_EDGE_RISING>, <GIC_SPI 412 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "eri", "rxi", "txi", "tei"; clocks = <&cpg CPG_MOD R9A07G044_SCI1_CLKP>; clock-names = "fck"; power-domains = <&cpg>; resets = <&cpg R9A07G044_SCI1_RST>; status = "disabled"; };
设备树文件路径
arch/arm64/boot/dts/renesas/r9a07g044.dtsi
根据项目需要,使能需要使用的设备节点,如欲使用SCIFA2:
&scif2 { pinctrl-0 = <&scif2_pins>; pinctrl-names = "default"; uart-has-rtscts; status = "okay"; };
注意需通过scif2_pins正确处理IO口复用问题。如果不使用DMA需要将设备节点中的dmas和dma-names删除。
编译内核:
export ARCH=arm64 export CROSS_COMPILE=aarch64-none-elf- export PATH=$PATH:/opt/arm/gcc-arm-10.2-2020.11-x86_64-aarch64-none-elf/bin make defconfig O=.out && make -j8 O=.out
使用当前编译生成的内核Image和dtb
.out/arch/arm64/boot/Image .out/arch/arm64/boot/dts/renesas/r9a07g044l2-smarc.dtb
启动板子后就能在系统路径下生成/dev/ttySC2节点。
Linux应用层使用RZ/G2L的串口SCI
RZ/G2L的串口设备节点在Linux应用层遵循POSIX标准,使用方法和PC端的Ubuntu系统并无差别。
RZ/G2L除了支持市面上常用的串口波特率如9600/115200/921600等,实际上除POSIX系统定义的波特率都支持外,RZ/G2L能够支持的最大串口波特率是12.5Mbps,下一篇我们将介绍如何在内核驱动代码中实现RZ/G2L的最大波特率12.5Mbps。
如需了解更详细的使用方法请参考如下网站:
1、瑞萨官网
https://www.renesas.cn/cn/zh/products/microcontrollers-microprocessors/rz-mpus/rzg2l-getting-started
2、RZ产品WIKI网站
您可点击下方网址进入瑞萨中文论坛查看:
RZ/G2L支持的最大波特率
RZ/G2L的SCIFA异步通讯模式下支持的最高波特率可以达到12.5Mbps,如果异步基础时钟选择16倍波特率,同时关闭波特率发生器的倍频模式下依然可以达到3.125Mbps。如果异步基础时钟选择8倍波特率或者波特率发生器开启倍频模式,最大波特率可以达到6.25Mbps。
在上集中我们有讲过RZ/G2L在Linux下的使用遵循POSIX标准。只要POSIX支持的波特率,RZ/G2L都可以支持,并且支持各种波特率下的误差修正,需要开启MDDRS寄存器。
Linux下串口的波特率
Linux下termbits.h支持的波特率如下
/* c_cflag bit meaning */ #define CBAUD 0000377 #define B0 0000000 /* hang up */ #define B50 0000001#define B75 0000002 #define B110 0000003#define B134 0000004 #define B150 0000005#define B200 0000006 #define B300 0000007#define B600 0000010 #define B1200 0000011#define B1800 0000012 #define B2400 0000013#define B4800 0000014 #define B9600 0000015#define B19200 0000016 #define B38400 0000017#define EXTA B19200 #define EXTB B38400#define CBAUDEX 0000000 #define B57600 00020#define B115200 00021 #define B230400 00022#define B460800 00023 #define B500000 00024#define B576000 00025 #define B921600 00026#define B1000000 00027 #define B1152000 00030#define B1500000 00031 #define B2000000 00032#define B2500000 00033 #define B3000000 00034#define B3500000 00035 #define B4000000 00036
也就是标准的Linux支持的最大波特率是4Mbps,但并不是4Mbps以下任意一个波特率都可以支持,只有30种选择。
那如果在特殊的应用场景中,需要这30种波特率以外的选择,是否能够实现呢?答案是肯定的,但是比较复杂。
这里我们提供一种Linux下实现非POSIX标准串口波特率的方法给大家参考。
Linux串口非标波特率的实现
涉及两部分他,包括内核和应用层
首先第一步:我们需要修改内核中的串口驱动,确保串口驱动能够支持需要添加的非标波特率。上集我们已经分享过RZ/G2L的串口驱动代码路径是drivers/tty/serial/sh-sci.c,目前通过开启MDDRS,RZ/G2L几乎可以支持12.5Mbps以下的任意串口波特率。
这里我们以前面提到的3.125Mbps/6.25Mbps/12.5Mbps为例,github上下载的sh-sci.c驱动默认并没有开启波特率发生器的倍频模式,异步基础时钟选择的是默认的16倍波特率。所以最大的波特率可以支持到3.125Mbps,如果需要支持6.25Mbps或者更高的12.5Mbps,需要开启波特率发生器的倍频模式,并且允许异步基础时钟选择8倍波特率。
+ #if ABCS0_BGDM_EN + if(baud > 6250000){ + //SEMR_BGDM:Baud rate generator double-speed mode Select: + //SEMR_ABCS0:Asynchronous Base Clock Select: + serial_port_out(port, SEMR, + serial_port_in(port, SEMR) | (SEMR_ABCS0 | SEMR_BGDM)); + freq *= 2; + prediv /= 2; + }else if(baud > 3125000){ + //SEMR_BGDM:Baud rate generator double-speed mode Select: + serial_port_out(port, SEMR, + serial_port_in(port, SEMR) | SEMR_BGDM); + freq *= 2; + } + #endif
这部分代码与RZ/G2L的平台相关,需要根据RZ/G2L的规格书配置对应的寄存器。
第二步:为了允许应用层配置我们添加的这三种波特率,需要修改drivers/tty/tty_baudrate.c和include/uapi/asm-generic/termbits.h,这两个文件与平台无关。想要在内核中添加系统默认的30种波特率以外的波特率都需要修改这两个文件。这两个文件的修改内容可以参考以下:
diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c index bdfaee2c1331..75d287893d11 100644 --- a/drivers/tty/tty_baudrate.c +++ b/drivers/tty/tty_baudrate.c @@ -24,7 +24,7 @@ static const speed_t baud_table[] = { 1000000, 1152000, 1500000, 2000000 #else 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, - 2500000, 3000000, 3500000, 4000000 + 2500000, 3000000, 3500000, 4000000, 3125000, 6250000, 12500000 #endif }; @@ -36,7 +36,7 @@ static const tcflag_t baud_bits[] = { B1000000, B1152000, B1500000, B2000000 #else B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, - B2500000, B3000000, B3500000, B4000000 + B2500000, B3000000, B3500000, B4000000, B3125000, B6250000, B12500000 #endif }; @@ -73,6 +73,14 @@ speed_t tty_termios_baud_rate(struct ktermios *termios) else cbaud += 15; } + if (cbaud & CBAUDEX2) { + cbaud &= ~CBAUDEX2; + + if (cbaud < 1 || cbaud + 30 > n_baud_table) + termios->c_cflag &= ~CBAUDEX2; + else + cbaud += 30; + } return cbaud >= n_baud_table ? 0 : baud_table[cbaud]; } EXPORT_SYMBOL(tty_termios_baud_rate); diff --git a/include/uapi/asm-generic/termbits.h b/include/uapi/asm-generic/termbits.h index 7db62a33ee52..1353300b6934 100644 --- a/include/uapi/asm-generic/termbits.h +++ b/include/uapi/asm-generic/termbits.h @@ -110,7 +110,7 @@ struct ktermios { #define FF1 0100000 /* c_cflag bit meaning */ -#define CBAUD 0010017 +#define CBAUD 0030017 #define B0 0000000 /* hang up */ #define B50 0000001 #define B75 0000002 @@ -158,7 +158,9 @@ struct ktermios { #define B3500000 0010016 #define B4000000 0010017 +#define CBAUDEX2 0020000 +#define B3125000 0020001 +#define B6250000 0020002 +#define B12500000 0020003 #define CIBAUD 002003600000 /* input baud rate */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */
经过上面两步修改,内核已支持我们需要添加的3种非POSIX标准的串口波特率。
接下来演示应用层如何使用我们添加的这三种串口波特率。
#define B3125000 0020001 #define B6250000 0020002 #define B12500000 0020003 ** ** 串口配置 ** 参数 cfg 指向一个 uart_cfg_t 结构体对象 **/ static int uart_cfg(const uart_cfg_t *cfg) { struct termios new_cfg = {0}; //将 new_cfg 对象清零 speed_t speed; /* 设置为原始模式 */ cfmakeraw(&new_cfg); /* 使能接收 */ new_cfg.c_cflag |= CREAD| CLOCAL; /* 设置波特率 */ speed = B3125000; // B3125000 B6250000 B12500000 new_cfg.c_cflag |= speed; /* 串口的其他属性配置参考标准的POSIX */ /* 写入配置、使配置生效 */ if (0 > tcsetattr(fd, TCSANOW, &new_cfg)) { fprintf(stderr, "tcsetattr error: %s\n", strerror(errno)); return -1; }
经过以上修改,我们就可以在linux下使用文章开头提到的RZ/G2L的最大波特率12.5Mbps进行串口通讯。
需要注意的是,我们给RZ/G2L添加的这三个波特率尤其是6.25Mbps或者12.5Mbps远超标准linux下支持的最大波特率4Mbps,所以,通过PC端的Ubuntu是无法使用这三种波特率与RZ/G2L的SMARC EVK板进行通讯测试的,如果要使用我们上面添加的这三种波特率,只能在两个SMARC EVK板上进行。
所以,除以上添加的这三种波特率外,如果要添加POSIX标准支持的30种以外的其他波特率,都可以参考这个方法来实现。
如需了解更详细的使用方法请参考如下网站:
1、瑞萨官网
https://www.renesas.cn/cn/zh/products/microcontrollers-microprocessors/rz-mpus/rzg2l-getting-started
2、RZ产品WIKI网站
您可点击下方网址进入瑞萨中文论坛查看:
来源:瑞萨嵌入式小百科:RZ/G2L串口SCI的使用(上)、RZ/G2L串口SCI的使用(下)
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。