linux多串口改波特率,如何在S3C2440上linux操作系统下将串口的波特率提高以致921600...

首先声明,CSDN中藏龙卧虎,说不定就出来个大牛,所以请各位大牛批评指正 在说说我做的这个事情,其实听起来很简单,就是把串口的波特率提上去,硬件环境呢,就

首先声明,CSDN中藏龙卧虎,说不定就出来个大牛,所以请各位大牛批评指正

在说说我做的这个事情,其实听起来很简单,就是把串口的波特率提上去,硬件环境呢,就是采用飞凌的TE2440-II(比较古老了,大家勿喷)操作系统是linux2.6.28,大家都知道,正常情况下,linux下串口波特率最高到115200,因为我们特殊需要的原因,需要把波特率提高到至少460800,当然最理想的结果就是波特率达到921600,大的背景就是这个样子了。

然后先考究硬件,看看在硬件上到底能不能满足我们的要求,主控芯片S3C2440,在UART一章说在系统时钟下,波特率最高可达115200,然后注释中说如果Pclk达到60M,可以实现921600,我就按他说的,将主频提高,顺便将pclk提高到了60M,发现921600根本实现不了,230400波特率虽然能通,但是错误率很高,根本无法用,然后我又尝试着将Pclk提高到了70M,通过这种饮鸩止渴的方式,波特率可以提高到230400并且稳定传输,但是更高的波特率则无法实现,而Pclk不能无限提高,因为我们开发板还连接了触摸屏,在Pclk70M的情况下,触摸屏经常重启,说明这个方案不可行,所以就pass掉了,下面简单说一下我怎么更改的系统时钟Fclk,Hclk,Pclk。这三个时钟的关系以及计算方法我就不赘述了,我主要参考博客进行修改

1)首先找到bootloader中 INC文件夹下的Option.inc文件,打开以后,找到如下代码段,这段代码就是主频400M时对应的M,P和S值设置,需要更改主频的话更改其中相应的数值几个(后来我发现,其实这个地方不改也行,因为最终起作用的是第二步)

[ FCLK = 400000000

CLKDIV_VALEQU5;1:4:8

M_MDIVEQU

127;127

M_PDIVEQU

2;2

[ CPU_SEL = 32440001

M_SDIVEQU

1; 2440A

|

M_SDIVEQU

0; 2440X

]

]

2)找到u2440mon.c,然后在main()函数中找到如下代码,修改case2中的mpll_val = (92<<12)|(1<<4)|(1);这一行(为啥修改这一行?因为在这个switch代码有个j=2),其中三个数分别代表M,P,S。这才是决定主频的关键。

switch(j) {

case 0:

//240

key = 14;

mpll_val = (112<<12)|(4<<4)|(1);

break;

case 1:

//320

key = 14;

mpll_val = (72<<12)|(1<<4)|(1);

break;

case 2:

//400

key = 14;

mpll_val = (92<<12)|(1<<4)|(1);

break;

case 3:

//420!!!

key = 14;

mpll_val = (97<<12)|(1<<4)|(1);

break;

default:

key = 14;

mpll_val = (92<<12)|(1<<4)|(1);

break;

}

3)然后再 2440lib.c文件中,找到 ChangeClockDivider()函数,这个函数是控制分频比的,代码如下,这两个一个控制h_div,一个控制p_div。其中case 18: hdivn=2; break;这一行控制H分频,具体怎么改可以参考手册。

switch(hdivn_val) {

case 11: hdivn=0; break;

case 12: hdivn=1; break;

case 13:

case 16: hdivn=3; break;

case 14:

case 18: hdivn=2; break;

}

switch(pdivn_val) {

case 11: pdivn=0; break;

case 12: pdivn=1; break;

}

只需以上三步,就可以更改系统主频以及分频比,得到自己想要的Fclk和Pclk。

然后再说说我把上一个方案否定了以后,再仔细阅读芯片手册,发现串口的时钟源可以有三种方式获得:pclk,fclk/n,exclk,而且手册上说采用外部时钟的话,可以做到更高的波特率,但是这需要更改硬件,从指定那个引脚引入一个时钟,然后还要更改驱动程序,所以放弃了,所以只剩下一个路可以走,就是采用fclk/n的方式作为串口的时钟源,因为fclk频率很高,所以时钟源提高了,就可以把波特率提上来。然后就开始看linux内核源代码,因为串口的驱动早就集成到了linux内核之中,然后我就跳进了一个大坑。

其实串口本身的驱动并不复杂,如果裸机开发的话我感觉不难(强调一下,这个串口的裸机开发我没有做过,请做过的人不要喷我),因为串口被封装到了linux系统中,并且是层层封装,最终被封装成了tty的形式,所以我就从tty的驱动看起,抽丝剥茧,从里面寻找蛛丝马迹,

首先发现了s3c2440.c这个文件,通过调试得知,初始化的时候调用了其中的s3c2440_serial_init()函数,刚开始以为在这个文件中就这个函数有用,其实后来才知道,这个文件中的s3c2440_serial_getsource()和s3c2440_serial_setsource()在驱动中多次被调用。

然后考虑到,在上位机设置波特率的时候,调用的是系统函数cfsetispeed(),后经调试得知,这个函数调用了Samsung.c这个文件中的s3c24xx_serial_set_termios()这个函数,所有与串口相关的配置都与这个函数有关,因此锁定了方向,只要从这个函数中找到与波特率以及时钟源相关的语句,更改成我想要的即可,而这个函数又调用了很多子函数,但真正与波特率及时钟源相关的函数就是如下几句

/*

* Ask the core to calculate the divisor for us.

*/

baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);

if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)

quot = port->custom_divisor;

else

quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);

/* check to see if we need  to change clock source */

if (ourport->clksrc != clksrc || ourport->baudclk != clk) {

s3c24xx_serial_setsource(port, clksrc);

if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {

clk_disable(ourport->baudclk);

ourport->baudclk  = NULL;

}

clk_enable(clk);

ourport->clksrc = clksrc;

ourport->baudclk = clk;

}

其中,uart_get_baud_rate()函数用于计算出上位机程序到设置的波特率的值,经我调试得知,上位机波特率从2400到921600都可以被准确的计算出来;所以这个函数跳过,然后看最后那个if语句,这个语句的作用是产看目前的时钟源是否与设置的时钟源相同,如果不相同,则按照设置的时钟源进行更改,这里面还涉及linux下的关于管理时钟的一个结构体clk结构体,参照博客以及我找到了linux下的mach-smdk2440.c这个文件,这个文件中定义了串口所用的clk结构体,这也是linux系统启动时对串口的初始化配置结构体都在这,但是我更改过这个地方,让他初始化配置是首选fclk作为串口的时钟源,但是我发现这并没有效果,所以继续寻找中。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值