S3C2440 如果串口驱动有问题,怎么调(二十二)

https://blog.csdn.net/thisway_diy/article/details/81169666

有很多人问我,为什么不录串口驱动?

实际上串口裸板很简单,但是串口驱动还是挺复杂的;

另外基本上所有芯片的内核源码中基本上都会有串口驱动。

所以我认为对于串口,我们只要会APP编程即可,不需要去写它的驱动程序

现在有2个问题:

1.怎么写串口APP? 
2.如果串口驱动有问题,怎么调?

第1个问题挺简单,百度搜搜就可以找到源码。

但是向我提问的人还是非常非常多,

扫描二维码关注公众号,回复: 2409560 查看本文章

我干脆写一个示例代码好了:serial_test.c

这个程序会一边往串口中写入数据0x5A,一边从串口中读出数据并打印出来。

serail_test.c代码如下:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>

/* 串口初始化 */
/* set_opt(fd,115200,8,'N',1) */
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
  struct termios newtio,oldtio;
  /* 保存测试串口参数设置,在这里如果串口号等出错,会有相关的出错信息 */
  if ( tcgetattr( fd,&oldtio) != 0) { 
    perror("SetupSerial 1");
    return -1;
  }
  bzero( &newtio, sizeof( newtio ) );
  /* 步骤一:设置字符大小 */
  newtio.c_cflag |= CLOCAL | CREAD; 
  newtio.c_cflag &= ~CSIZE; 

  newtio.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
  newtio.c_oflag  &= ~OPOST;   /*Output*/
	/* 设置停止位 */
  switch( nBits )
  {
  case 7:
    newtio.c_cflag |= CS7;
    break;
  case 8:
    newtio.c_cflag |= CS8;
    break;
  }
	/* 设置奇偶校验位 */
  switch( nEvent )
  {
  case 'O'://奇数
    newtio.c_cflag |= PARENB;
    newtio.c_cflag |= PARODD;
    newtio.c_iflag |= (INPCK | ISTRIP);
    break;
  case 'E': //偶数
    newtio.c_iflag |= (INPCK | ISTRIP);
    newtio.c_cflag |= PARENB;
    newtio.c_cflag &= ~PARODD;
    break;
  case 'N': //无奇偶校验位
    newtio.c_cflag &= ~PARENB;
    break;
  }
//设置波特率
switch( nSpeed )
  {
  case 2400:
    cfsetispeed(&newtio, B2400);
    cfsetospeed(&newtio, B2400);
    break;
  case 4800:
    cfsetispeed(&newtio, B4800);
    cfsetospeed(&newtio, B4800);
    break;
  case 9600:
    cfsetispeed(&newtio, B9600);
    cfsetospeed(&newtio, B9600);
    break;
  case 115200:
    cfsetispeed(&newtio, B115200);
    cfsetospeed(&newtio, B115200);
    break;
  default:
    cfsetispeed(&newtio, B9600);
    cfsetospeed(&newtio, B9600);
    break;
  }
  /* 设置停止位 */
  if( nStop == 1 )
    newtio.c_cflag &= ~CSTOPB;
  else if ( nStop == 2 )
  newtio.c_cflag |= CSTOPB;
  /* 设置等待时间和最小接收字符 */
  newtio.c_cc[VTIME] = 0; /* 设置从获取到1个字节后开始计时的超时时间 */
  newtio.c_cc[VMIN] = 0;  /* 设置要求等待的最小字节数 */
  /* 处理未接受字符 */
  tcflush(fd,TCIFLUSH);
  /* 激活新配置 */
  if((tcsetattr(fd,TCSANOW,&newtio))!=0)
  {
    perror("com set error");
    return -1;
  }
  //printf("set done!\n");
  return 0;
}

//想打开的的串口com
int open_port(char *com)
{
	int fd;
	//fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY);
	fd = open(com, O_RDWR|O_NOCTTY);
    if (-1 == fd){
		return(-1);
    }
	
	/* 恢复串口为阻塞状态 */
  if(fcntl(fd, F_SETFL, 0)<0)
  {
		printf("fcntl failed!\n");
		return -1;
  }

  fcntl(fd, F_SETFL, 0);
  
  return fd;
}


int main(int argc, char **argv)
{
	int oldstate;
	int oldtype;
	int iRet;
	int fd = -1;
	unsigned char c;
	int ok_cnt = 0;
	int err_cnt = 0;

	if (argc != 2)
	{
		printf("Usage: \n");
		printf("%s </dev/ttySAC1 or other>\n", argv[0]);
		return -1;
	}

	fd = open_port(argv[1]);
	if (fd < 0)
	{
		printf("open port err!\n");
		return -1;
	}

	iRet = set_opt(fd, 115200, 8, 'N', 1);
	if (iRet)
	{
		printf("set port err!\n");
		return -1;
	}

	printf("It will write 0x5A to %s ....\n", argv[1]);
	printf("Data recv: \n");

	while (1)
	{
		c = 0x5A;
		write(fd, &c, 1);
		iRet = read(fd, &c, 1);
		if (iRet == 1)
		{
			printf("%02x ", c);
		}
	}

	return 0;
}

用法为:

a. 编译: 
arm-linux-gcc -o serial_test serail_test.c -static 


b. 在开发板上运行: 
./serial_test </dev/XXX> // /dev/XXX为串口的设备节点

比如在jz2440的3.4.2内核上:

./serial_test /dev/ttySAC1

比如在jz2440的2.6.22.6内核上:

./serial_test /dev/s3c2410_serial1

c. 然后用镊子短接串口的TXD、RXD引脚,即可看到这个程序不断打印0x5a:这表明测试成功

PS:TXD和RXD引脚在串口的中间,使这两个引脚相连。(本人是用剪刀来使两个引脚短接)

效果图如下:

第2个问题:总有一些不太完善的驱动程序需要我们稍微调整。

比如jz2440用的linux 3.4.2内核,它的/dev/ttySAC2无法使用。

需要修改2个文件,mach-smdk2440.c和samsung.c,这些文件的源码我一起打包上传,需要代码联系我即可。

下面讲解。

解决方法为:

a. 修改内核 arch/arm/mach-s3c24xx/mach-smdk2440.c

找到”ulcon = 0x43;” 改为 “ulcon = 0x03;”

2440的串口2可以用作红外接收或发送, 我们要把它改为一般的串口。

b. 修改内核 drivers/tty/serial/samsung.c

对于串口2,该文件中没有配置对应的GPIO用于串口。

修改方法如下:

b.1 在前面添加头文件:

#include <mach/regs-gpio.h> 
#include <plat/gpio-cfg.h>

b.2 在s3c24xx_serial_startup函数中加入:

if (ourport->cfg->hwport == 0) 

printk(“config pin for uart %d\n”, ourport->cfg->hwport); 
s3c_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0); 
s3c_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0); 

else if (ourport->cfg->hwport == 1) 

printk(“config pin for uart %d\n”, ourport->cfg->hwport); 
s3c_gpio_cfgpin(S3C2410_GPH(4), S3C2410_GPH4_TXD1); 
s3c_gpio_cfgpin(S3C2410_GPH(5), S3C2410_GPH5_RXD1); 

else if (ourport->cfg->hwport == 2) 

printk(“config pin for uart %d\n”, ourport->cfg->hwport); 
s3c_gpio_cfgpin(S3C2410_GPH(6), S3C2410_GPH6_TXD2); 
s3c_gpio_cfgpin(S3C2410_GPH(7), S3C2410_GPH7_RXD2); 
}

猜你喜欢

转载自blog.csdn.net/xiaodingqq/article/details/81216317