如何在S3C2440上linux操作系统下将串口波特率提高到921600?

说一下我做的事情,其实听起来很简单,就是提高串口的波特率。至于硬件环境,就是用凌飞的TE2440-II(比较老,请不要喷),操作系统是linux2.6.28,大家都知道,一般情况下,linux下串口的波特率是115200,因为我们比较特殊。

那么,首先要研究一下硬件,看能不能满足我们的要求。在UART那一章,主控芯片S3C2440说在系统时钟下波特率可以达到115200,然后备注说如果pclk达到60M就可以达到921600,我就按他说的提高主频,顺便提高Pclk。发现921600根本无法实现。230400的波特率虽然可以过,但是误码率很高,根本用不上。然后我试着把Pclk提高到70M。通过这种方式可以将波特率提升到230400并且传输稳定,但是更高的波特率无法实现,Pclk也无法无限提高,因为我们的开发板还是连着的。Pclk70M的情况下,触摸屏频繁重启,说明这个方案不可行,所以pass掉了。让我简单说说我是如何改变系统时钟FCLK、HCLK和PCLK的。这三个时钟的关系和计算方法我就不赘述了。我主要参考了blog/view/13 b4c 686 b 9d 528 ea 80 c 77904 . html,我在linux下找到了文件mach-smdk2440.c,这个文件定义了串口使用的clk结构,也是linux系统启动时对串口的初始化配置结构。但是我换了这个地方,让他初始化配置。fclk作为串口的时钟源是第一选择,但是我发现不行,就继续找。

这就剩下一个函数要考虑了,s3c24xx_serial_getclk()。当你进入这个功能,你会发现这个功能是对串行时钟和波特率的综合配置。进入这个函数,有一个结构tmp_clksrc,非常关键。他的内容如下:

静态结构s 3c 24 xx _ UART _ clk src tmp _ clk src = {

。name = "pclk ",

。最小波特

= 0,

。最大波特

= 0,

。除数

= 1,

};

从这个名字可以看出,它将串口的时钟源设置为pclk,这也是罪魁祸首。但是当我把名字改成fclk的时候,整个系统都无法启动,包括上面提到的mach-smdk2440.c中的初始化配置。后来我在配置串口的时候做了一个判断。当波特率低于200000时,系统源配置保持不变。当波特率高于200000时,我不使用结构tmp_clksrc,而是使用自己定义的结构。当然,我把名字改成了fclk。我发现虽然只是时钟源可以改变里面的一些参数,但是时钟源还是pclk,也就是说我的改变根本没有生效。因为这个linux调用太复杂了,我就来试试。没有出路。配置完串行时钟代码后,我添加了以下几行代码来直接更改S3C2440的寄存器。我知道这样做不道德,容易造成系统混乱,但我只是尝试了一下,没想到真的有用。

在samsung.c文件中添加

如果(波特& gt= 200000)

{

printk("波特& gt= 200000 @ Samsung . c \ n ");

__raw_writel(0x1fc5,s 3c 24 xx _ VA _ UART 0+s 3c 2410 _ UCON);

__raw_writel(0x0fc5,s 3c 24 xx _ VA _ UART 1+s 3c 2410 _ UCON);

__raw_writel(0x8fc5,s 3c 24 xx _ VA _ UART 2+s 3c 2410 _ UCON);

__raw_writel(32,s 3c 24 xx _ VA _ UART 0+s 3c 2410 _ UCON+0x 24);//确保控制台的波特率仍然是115200进行显示。

__raw_writel(3,s 3c 24 xx _ VA _ UART 1+s 3c 2410 _ UCON+0x 24);//921600

//__raw_writel(3,s 3c 24 xx _ VA _ UART 1+s 3c 2410 _ UCON+0x 24);

}

上面的代码是我多次实验得到的,因为一开始用的系统主时钟fclk是400M,所以计算出UBRDIV1分频应该是3,但是这种情况下误码率比较高,还是无法传输。所以我终于明白为什么手册上说pclk在60M可以实现921600了,因为如果用60M时钟计算,分频UBRDIV1是3.069,最接近整数3,所以在这个误码率下可以实现921600的波特率传输,所以我把系统时钟fclk设置为420M,这里MDIV=97,PDIV=1,PDIV = 65438Ucon1=0x0fc5,ucon2=0x8fc5,所以n=1+6=7,所以串口的时钟源为fclk/n=60M,可以得到准确的波特率921600。所以,要实现我最初的目标,其实可以实现其他波特率,比如46088。

这里还有一个小思路,提高串口的波特率,我们也可以用USB转串口,因为USB转串口可以做到921600,linux中集成的USB转串口的驱动只需要在调用串口的open函数中调用USB转串口的节点即可。当然这个方案我没有尝试过,因为我们只有一个USB口,也是被占用的,希望有需要的朋友可以尝试一下。