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

就是把串口的波特率提上去,硬件环境呢,就是采用飞凌的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。这三个时钟的关系以及计算方法我就不赘述了,我主要参考博客http://blog.csdn.NET/dong_zhihong/article/details/8469269进行修改
1)首先找到bootloader中 INC文件夹下的Option.inc文件,打开以后,找到如下代码段,这段代码就是主频400M时对应的M,P和S值设置,需要更改主频的话更改其中相应的数值几个(后来我发现,其实这个地方不改也行,因为最终起作用的是第二步)
[ FCLK = 400000000
CLKDIV_VAL EQU5
;1:4:8
M_MDIV EQU
127 ;127
M_PDIV EQU
2 ;2
[ CPU_SEL = 32440001
M_SDIV EQU
1 ; 2440A
|
M_SDIV EQU
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结构体,参照博客http://blog.chinaunix.Net/uid-26583794-id-3208153.html以及http://wenku.baidu.com/view/13b4c686b9d528ea80c77904.html我找到了linux下的mach-smdk2440.c这个文件,这个文件中定义了串口所用的clk结构体,这也是linux系统启动时对串口的初始化配置结构体都在这,但是我更改过这个地方,让他初始化配置是首选fclk作为串口的时钟源,但是我发现这并没有效果,所以继续寻找中。
这样就剩下一个函数可以考虑了,s3c24xx_serial_getclk(),进入这个函数你会发现,这个函数是对串口时钟及波特率一个全面的配置,进入这个函数中,就有个结构体tmp_clksrc,这个结构体很关键,他的内容如下:
static struct s3c24xx_uart_clksrc tmp_clksrc = {
.name = "pclk",
.min_baud
= 0,
.max_baud
= 0,
.divisor
= 1,
};
从这个名字中就可以看出,它把串口的时钟源内定成为了pclk,这也是罪魁祸首,但是当我把name更改为fclk时,整个系统就无法启动了,包括前面说的更改mach-smdk2440.c中初始化配置,也是无法启动,后来在配置串口是做了一个判断,当波特率低于200000时,才有系统源配置不变,当波特率高于200000时,不在采用tmp_clksrc这个结构体,而是采用我自己定义的一个结构体,当然就是把name改成fclk,发现虽然只是能够更改 里面部分参数的时钟源,而正在的时钟源还是pclk,说明我的更改根本么有生效,由于这个linux调用太庞杂了,我就抱着试试看的态度,也是没有办法的办法,在配置完串口时钟的代码之后,添加了如下几行代码,直接更改S3C2440的寄存器,我知道这样做是很不“道德”的,而且很容易引起系统混乱,但是我只是这么试试,没想到还真的有用。

在 samsung.c文件中添加
if (baud >= 200000)
{
printk("baud >= 200000 @-------------samsung.c\n");
__raw_writel(0x1fc5,S3C24XX_VA_UART0 + S3C2410_UCON);
__raw_writel(0x0fc5,S3C24XX_VA_UART1 + S3C2410_UCON);
__raw_writel(0x8fc5,S3C24XX_VA_UART2 + S3C2410_UCON);
__raw_writel(32,S3C24XX_VA_UART0 + S3C2410_UCON+0x24);//保证控制台的波特率还是115200用于显示
__raw_writel(3,S3C24XX_VA_UART1 + S3C2410_UCON+0x24);//921600
//__raw_writel(3,S3C24XX_VA_UART1 + S3C2410_UCON+0x24);
}
上面这段代码经我多次试验得到的,因为一开始用的系统主时钟fclk为400M,这样算出来UBRDIV1分频应该为3,但是这样的话错误率比较高,还是导致无法传输,至此我终于明白手册上为什么说pclk在60M 可以实现921600了,因为用60M时钟计算的话,分频UBRDIV1为3.069,最接近整数3,所以在这个错误率下可以实现921600的波特率传输,所以我将系统时钟fclk设置为420M,其中MDIV=97,PDIV=1,SDIV=1,而ucon0=0x1fc5,ucon1=0x0fc5,ucon2=0x8fc5,这样n=1+6=7,所以串口的时钟源为fclk/n=60M,可以得到精确的921600波特率,所以实现我刚开始的目标,其实要实现其他的波特率也可以,比如460800,计算后主时钟fclk(尽量算出的分频UBRDIV1最贴近整数),然后就可以实现了。

在这还有个小想法,提高串口波特率,还可以使用USB转串口,因为USB转串口可以实现921600,而linux中以及集成了USB转串口的驱动,只需要在调用串口的那个open函数中改为调用USB转串口的节点即可,当然,这个方案我没有试,因为我们就一个USB口,而且还被占用了,所以希望有需要的朋友可以试一下。

用 stty 命令 (使用前请确认你的终端设备确实支持这个速率), 比如

stty 115200   # 设置 baud rate 到 115200

stty speed    # 查看当前终端 baud rate

# 如果不是设置当前终端,则用下面的命令设置指定终端设备
stty -F /dev/<tty_name>  115200


88、四时田园杂兴范大成

88、四时田园杂兴 范大成

  • 鍩轰簬S3C2440鐨勫祵鍏ュ紡Linux寮鍙戝疄渚嬬洰褰
    绛旓細绗1绔狅細宓屽叆寮忕郴缁熷紑鍙戝熀纭 1.1 宓屽叆寮Linux绯荤粺寮鍙戞ā寮 1.1.1 宓屽叆寮忕郴缁熻璁$壒鐐 1.1.2 璁捐娴佺▼涓庤蒋纭欢鍒掑垎 1.2 杞欢璁捐 1.2.1 閫夋嫨宓屽叆寮忚蒋浠跺钩鍙 1.2.2 鎬ц兘璁捐涓庡紑鍙戞祦绋 1.3 寮鍙戠數璺熀纭 1.3.1 鐢佃矾鍘熺悊鍥句笌PCB璁捐 1.3.14-1.3.20锛氳缁嗕粙缁嶄簡PC...
  • 濡備綍鍦⊿3C2440涓妉inux鎿嶄綔绯荤粺涓嬪皢涓插彛鐨勬尝鐗圭巼鎻愰珮浠ヨ嚧921600
    绛旓細棣栧厛鍙戠幇浜s3c2440.c杩欎釜鏂囦欢,閫氳繃璋冭瘯寰楃煡,鍒濆鍖栫殑鏃跺欒皟鐢ㄤ簡鍏朵腑鐨剆3c2440_serial_init()鍑芥暟,鍒氬紑濮嬩互涓哄湪杩欎釜鏂囦欢涓氨杩欎釜鍑芥暟鏈夌敤,鍏跺疄鍚庢潵鎵嶇煡閬,杩欎釜鏂囦欢涓殑s3c2440_serial_getsource()鍜宻3c2440_serial_setsource()鍦ㄩ┍鍔ㄤ腑澶氭琚皟鐢ㄣ傜劧鍚庤冭檻鍒,鍦ㄤ笂浣嶆満璁剧疆娉㈢壒鐜囩殑鏃跺,璋冪敤鐨勬槸绯荤粺鍑芥暟cfsetispeed(),...
  • 濡備綍鍦⊿3C2440涓妉inux鎿嶄綔绯荤粺涓嬪皢涓插彛鐨勬尝鐗圭巼鎻愰珮浠ヨ嚧921600
    绛旓細鐢ㄥ懡浠inicom-s鍙互杩涘埌涓插彛鐨勮缃晫闈竴鑸覆鍙g殑SerialDevice鍊兼槸濉/dev/ttyS0鐒跺悗璁剧疆涓涓婤ps/Par/Bits淇濆瓨,鏍规嵁鎻愮ず鐧婚檰涓插彛鍗冲彲
  • S3C2440鑺墖涓婄Щ妞linux绯荤粺鍚,濡備綍浣跨敤瀹氭椂鍣0,1,2,3,鑳藉惁鍍忓閮ㄤ腑鏂...
    绛旓細STC89C52RC缁欏畾鐨勬湁4澶栭儴涓柇婧愶紝澶栭儴涓柇0鍜1浣犵煡閬撲簡锛屽閮ㄤ腑鏂2鍜3鐨勭敤娉曞拰澶栭儴涓柇0鍜1涓鏍凤紝鍒嗗埆璁剧疆鐩稿簲瀵勫瓨鍣ㄥ氨琛屼簡銆傚閮ㄤ腑鏂2鍜3鍒嗗埆鍦≒4.3鍜孭4.2瀵瑰簲鐨勫紩鑴氫笂銆傚簲鐢ㄤ竴瀹氱殑鎶宸э紝鍦ㄥ閮ㄤ腑鏂笉澶熺敤鐨勬儏鍐典笅锛岃繕鍙互浣跨敤瀹氭椂鍣/璁℃暟鍣ㄦ墿灞曞閮ㄤ腑鏂
  • 鎴戞槸澶╁祵s3c2440鐨勬澘瀛,鐜板湪Linux绉绘,涓鐩存寜鍘傚鎵嬪唽鍋氱殑,鍙槸make...
    绛旓細娉ㄦ剰鎻愮ず锛屾槸 gcc 杩欎釜鍛戒护鏈壘鍒帮紝鑰屼笉鏄 arm-linux-gcc 杩欎釜鍛戒护鏈壘鍒般傝屼笖鍐嶇湅绗竴琛屾彁绀 HOSTCC scripts/basic/fixdep 杩欒閲岄潰鐨 HOSTCC 锛孒OST 涓鑸浜 Linux 鏉ヨ鏄湰鍦扮殑涓滆タ鎰忔濓紝涔熷氨鏄杩欒鐢ㄧ殑鏄綋鍓嶇郴缁熶娇鐢ㄧ殑 cc 锛堣繖涓 cc 鏄 C Compiler 鐨勬剰鎬濓紝gcc 鍛戒护鏄 GNU Compiler ...
  • ARM s3c2440-linux濡備綍閲婃斁浣滀负console鐨則tyS0涓插彛
    绛旓細鍦ㄤ綘鐨s3c2440鏉垮瓙涓婏紝浣犵殑涓插彛鑺傜偣椹卞姩锛屽彲鑳戒笉鏄痶tys0锛岃繖鏍风殑椹卞姩鏂囦欢锛屽湪鍚勪釜鍒朵綔绯荤粺鏂囦欢鏃朵覆鍙g殑椹卞姩鑺傜偣锛屽彲鑳芥槸鍒殑鏂囦欢鍚嶏紝浣犱粩缁嗙殑瑙傚療涓嬶紝缁欎綘涓缓璁紝鎴戠殑涓插彛椹卞姩鑺傜偣鏄痵3c2440-serial杩欎釜鏂囦欢锛屼笉鏄痶tys0浣犵湅涓涓嬫槸涓嶆槸杩欎釜
  • 鍩轰簬ARM鐨LINUX绉绘浜庡垎鏋
    绛旓細[*] SMDK2440 with S3C2440 CPU module 3.Boot options ---> 灏 (root=/dev/hda1 ro init=/bin/bash console=ttySAC0) Default kernel command string 鏀规垚 (noinitrd root=/dev/mtdblock2 console=ttySAC0,115200 init=/linuxrc 锛夎繖閲岃鐗瑰埆娉ㄦ剰root=/dev/mtdblock2 杩欎釜鍙傛暟,mtd...
  • 鎴戞湁涓鍧s3C2440寮鍙戞澘,璇烽棶鍙惁鍦ㄥ叾涓婇潰鐨linux绯荤粺閲岃涓婄櫨搴︿簯绠″...
    绛旓細涓嶈 浣嗘槸浣犺兘瀹夎python 鍜宐ypy 鏉ヨ闂櫨搴︿簯
  • 宓屽叆寮linux骞冲彴鐨勬瀯寤轰互鍙夿ootloader鐨勮蒋浠跺紑鍙
    绛旓細浠庝綘鐨勫彊杩颁笂浣犺佸笀濂藉儚鏄渶瑕佷綘浜嗚Вbootloader,鐢╲ivi鎴栬卽boot鍚姩瀹為獙鏉夸笂鐨linux vivi缂栬瘧鍚庨渶瑕佸啓鍒癰oot鍖哄煙閲岄潰,鍏蜂綋鍜屽疄楠屾澘鏈夊叧,浣犺鑷繁鏌ヨ祫鏂 s3c2440 vivi鐨勫惎鍔ㄨ繃绋嬶細鍚姩鏄粠鏂囦欢vivi/arch/s3c2440/head.S寮濮嬬殑 1. 鍦ㄨ繖涓枃浠朵腑锛屽仛浜嗚繖鏍风殑宸ヤ綔锛(1) 鍏抽棴鐪嬮棬鐙 (2) 绂佹鎵鏈変腑鏂 (3...
  • linux涓婼3C2440鏇存敼纭欢鏃堕棿鑺墖鑷繁淇濆瓨涓嶄簡,鏀逛簡閲嶅惎杩樻槸浠ュ墠鐨,浣 ...
    绛旓細濡傛灉浣犲湪鍛戒护娌℃湁淇敼鍒扮‖浠舵椂闂, 閭h鏄庝綘鐨勫懡浠ゆ病鏈夋垚鍔熸搷浣滃埌鏃堕挓鑺墖, 浣犲彲浠ョ湅涓涓嬬洰鏍囩増鐨勬椂閽熻姱鐗囨槸鍝釜鍨嬪彿鐨, 鎵惧埌瀵瑰簲鐨刣atasheet, 鐪嬬湅璇ヨ姱鐗囬噰鐢ㄤ粈涔堟荤嚎鎺ュ彛杩炴帴浣犵殑s3c2440, 涓鑸椂閽熻姱鐗囬兘鐢╥2c鎺ュ彛, 閭d箞浣犲彲浠ヤ豢鐓2c鎬荤嚎瑙勮寖鍐欎竴涓搷浣渋2c浠庤澶囧瘎瀛樺櫒鐨勭▼搴, 鐩存帴瀵规椂閽熻姱鐗囩殑...
  • 扩展阅读:高清线hdmi ... e人e本t8s ... www.sony.com.cn ... 华为s24色域 ... e人e本a2 ... 在线车牌查询车主 ... 视频直播sdk快速接入 ... 二手奔驰s300出售 ... s3c2416xh-40详细参数 ...

    本站交流只代表网友个人观点,与本站立场无关
    欢迎反馈与建议,请联系电邮
    2024© 车视网