我尝试在 LX2160ARDB 板上运行 Linux 的 SoC 上的用户应用程序中使用 UART 串行端口。
有 2 个 UART 端口使用 PL011 UART 硬件(UART1、UART2)。
Linux启动后,我可以找到2个UART端口的设备节点(/dev/ttyAMA0、/dev/ttyAMA1)。
应用程序对设备文件执行
open(/dev/ttyAMAx)
和 write()
。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main( void )
{
int fd;
int retn;
int buf[10] = "write...\n";
/* Open UART */
fd = open( "/dev/ttyAMA1", O_RDWR );
if( fd < 0 )
{
perror("Open /dev/ttyAMA1 error!");
exit(-1);
}
printf("Opening /dev/ttyAMA1 -> success!\n");
/* Write Operation - Tx start */
int i;
for( i = 0; i < 10; i++ )
{
retn = write( fd, buf, 10 );
if( retn < 0 )
printf("Write() failed... retn=%d\n");
else
printf("Write() succeeded! retn=%d\n");
sleep(1);
}
/* Close UART */
printf("Closing /dev/ttyAMA1\n");
close(fd);
return 0;
}
我通过 RS232 电缆连接 SoC 的 UART 端口和我的笔记本电脑并运行应用程序,并通过终端仿真器检查信号。
尝试 /dev/ttyAMA0 (UART1) 时,我可以看到信号(“写... “字符串)在连接到 UART1 端口的终端仿真器上,但是当尝试 /dev/ttyAMA1 (UART2) 时,我看不到信号(“写... 连接到 UART2 端口的终端仿真器上的“字符串),并且应用程序进程不会终止。 ( 在这两种情况下,open()、write() 函数都返回有效值。 )
我通过访问/dev/mem检查了每个UART的控制寄存器值,发现UART2的ENABLE位没有设置为1,而UART1的ENABLE位设置为1。 (与设置波特率和数据位相关的寄存器也是如此。)
...
int main( void )
{
...
fd = open("/dev/mem", O_RDWR | O_SYNC);
...
/* mmap() UART, x can be 1 or 2 */
baseaddr = mmap(0,
UARTx_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
UARTx_BASE);
if( baseaddr == NULL )
{
perror("mmap() error");
exit(-1);
}
printf("mmap succeeded!\n");
/* set pointer of UART Control Register */
uartcr = ( uint32_t * )( baseaddr + UARTCR_OFFSET );
/* check value of Control Register */
printf("Current UARTCR value: %#010x\n", *( uartcr ));
...
}
----------
[RESULT]
UART1: Current UARTCR value: 0x00000b01 ( bit[0] is 1 )
UART2: Current UARTCR value: 0x00000300 ( bit[0] is 0 )
UARTCR's bit[0] is UARTEN bit
为控制台选择了 UART1,因此 Bootloader 似乎配置了 UART1 并设置了 ENABLE 位,但没有配置 UART2。
我的问题是:
如何在 Linux 中从用户应用程序设置 UART2 的 ENABLE 位? (更准确地说,如何调用 UART2 的初始化,而不是使用 /dev/mem)
我们不能在 Linux 上设置 UART 控制器的 ENABLE 位吗?只能在Bootloader中吗?
我搜索了一些驱动程序代码(amba-pl011.c等),但我无法理解串行设备的层..
我尝试了
termios
进行 UART2 设置。但看不到 Tx 字符串(“Hello World!
”)。
我使用的终端仿真器 (Tera Term) 设置是“115200 波特率、8 位数据位、无奇偶校验、1 位停止位、无硬件流控制”
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
int main( void )
{
int fd, ret;
char tx_buf[] = "Hello World!\n\r";
structt termios options;
/* open UART */
fd = open( "/dev/ttyAMA1", O_RDWR | O_NOCTTY );
if( fd < 0 )
{
printf("ERROR open /dev/ttyAMA1\n");
return -1;
}
/* configure UART */
tcgetattr( fd, &options );
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cc[VTIME] = 10;
options.c_cc[VMIN] = 0;
options.c_lflag &= ~( ICANON | ECHO | ECHOE | ISIG );
options.c_oflag &= ~OPOST;
options.c_iflag &= ~( ICRNL | IXON );
cfsetispeed( &options, B115200 );
cfsetospeed( &options, B115200 );
options.c_cflag |= ( CLOCAL | CREAD );
tcflush( fd, TCIFLUSH );
tcsetattr( fd, TCSANOW, &options );
/* test UART */
int i;
for( i = 0; i < 10; i++ )
{
ret = write( fd, tx_buf, sizeof(tx_buf) );
if( ret != sizeof(tx_buf) )
printf("ERROR write, ret=%d\n\r", ret);
printf("write successfully, ret=%d\n\r", ret);
sleep(1);
}
printf("Tx Test END!\n\r");
/* close UART */
close(fd);
return 0;
}
您应该更改 PBI(预引导加载程序初始化)以正确配置 UART 的 CCSR(QorIQ LX2160A 参考手册,第 8 章服务处理器)。或者您可以简单地在 U-boot 甚至 Linux 控制台中更改 CCSR。当我试图使 UART2 工作时,我从 UART1 读取寄存器并通过 bash 脚本将它们复制到 UART2。 (QorIQ LX2160A 参考手册,第 29 章 UART)
#!/usr/bin/env bash
# enable uart2
ccsr -w 0x21d0024 0x5e
ccsr -w 0x21d0028 0x3c
ccsr -w 0x21d002c 0x70
ccsr -w 0x21d0030 0xb01
ccsr -w 0x21d003c 0x50
# same with devmem2, but I recommend to use ccsr command
devmem 0x21d0024 w 0x5e
devmem 0x21d0028 w 0x3c
devmem 0x21d002c w 0x70
devmem 0x21d0030 w 0xb01
devmem 0x21d003c w 0x50
您还可以使用 md/mw 命令从 U-boot 控制台更改 ccsr。
=> md 21c0000
021c0000: 00000062 00000000 00000000 00000000 b...............
021c0010: 00000000 00000000 0000013e 00000000 ........>.......
021c0020: 00000000 0000005e 0000003c 00000070 ....^...<...p...
021c0030: 00000b01 00000012 00000050 00000002 ........P.......
021c0040: 00000000 00000000 00000000 00000000 ................
021c0050: 00000000 00000000 00000000 00000000 ................
021c0060: 00000000 00000000 00000000 00000000 ................
021c0070: 00000000 00000000 00000000 00000000 ................
021c0080: 00000000 00000009 00000000 00000000 ................
021c0090: 00000000 00000000 00000000 00000000 ................
021c00a0: 00000000 00000000 00000000 00000000 ................
021c00b0: 00000000 00000000 00000000 00000000 ................
021c00c0: 00000000 00000000 00000000 00000000 ................
021c00d0: 00000000 00000000 00000000 00000000 ................
021c00e0: 00000000 00000000 00000000 00000000 ................
021c00f0: 00000000 00000000 00000000 00000000 ................
=> md 21d0000
021d0000: 00000000 00000000 00000000 00000000 ................
021d0010: 00000000 00000000 00000196 00000000 ................
021d0020: 00000000 00000000 00000000 00000000 ................
021d0030: 00000300 00000012 00000000 00000002 ................
021d0040: 00000000 00000000 00000000 00000000 ................
021d0050: 00000000 00000000 00000000 00000000 ................
021d0060: 00000000 00000000 00000000 00000000 ................
021d0070: 00000000 00000000 00000000 00000000 ................
021d0080: 00000000 00000009 00000000 00000000 ................
021d0090: 00000000 00000000 00000000 00000000 ................
021d00a0: 00000000 00000000 00000000 00000000 ................
021d00b0: 00000000 00000000 00000000 00000000 ................
021d00c0: 00000000 00000000 00000000 00000000 ................
021d00d0: 00000000 00000000 00000000 00000000 ................
021d00e0: 00000000 00000000 00000000 00000000 ................
021d00f0: 00000000 00000000 00000000 00000000 ................
如果您想进行持久更改,您应该参考 PBI ccsr 数据配置。