Archive for the '开发' category

随声而动的彩灯

六 08 2014 由 创建在标签 开发

在网络上看到有人用Arduino搭建了一个音乐控制的彩色LED灯带。其使用的是PC分析输入音频的频谱,然后通过串口将分析好的频谱数据发送给Arduino,最后由Arduino控制并显示出来。

由于音频数据的处理借助于电脑,这就对显示带来局限性,所以移动性差。音频的频谱其实就是傅里叶变换,将时域分量转换成频域,DSP中也提到了快速傅里叶变换(FFT)的算法,降低了计算的次数,而且当前MCU的处理能力也在不断提高,有的MCU直接提供了FFT算法。所以就打算用MCU来做一个彩带控制器。

总体结构

其基本原理如下图所示:

音频经过放大器放大后给MCU中的AD采样,采用后的数据再经过FFT变换,转换成频域的数据,再将每个不同频率的功率转换成LED阵列显示。下面将逐个介绍每个模块的实现。

放大器

使用TI的TLV2782来放大、滤波,其原理图如下图所示。

RGB LED阵列

对于RGB LED的控制都是使用PWM来控制,初步设计时想使用8*8的LED阵列,这样要对每一个LED控制会比较麻烦,即使使用视觉残留原理,通过MCU来控制每个LED也是一个不小的运算,而且IO口的资源也不能满足这样的控制。如果让每排的LED使用同样的颜色,这样会大大减少IO的使用。就在我究竟如何设计时,万能的淘宝给我带来了好消息,有自带RGB控制器的LED。看了介绍后发现十分满足自己的需求。网上搜了一圈之后就决定使用WS2812B,其特点可以看一下Datasheet。

但是在使用高速模式时,其时间较短,所以时序要求比较严格,在调试时甚至尝试用汇编来写代码,但控制也不能十分精准,最终不得不放弃。而国外也有一些网友用了一个曲线救国的方式,使用SPI和DMA的方式来控制LED显示。将LED的显示数据进行编码后存储起来,然后通过DMA将数据通过SPI口发送出去,通过硬件来保证时序,这也是低速设备运行的局限。

也想过用速度较快的ARM,但是考虑到手头上的ARM没有提供较好的接口,想要使用硬件控制时序的方式也不是件容易的事情,毕竟汇编代码和阻塞的处理对时间要求较高的场景不是一个很好的选择。如果要有更好的表现和更多的LED控制,可以考虑使用FPGA来控制WS2812B的时序。但是经过试验,MCU的SPI已经够用了,就没有去深究如何通过FPGA去控制LED。有兴趣的时候也可以研究一下。

MCU

MCU主要做三件事:采样,FFT计算,显示各个频率的功率。以前玩过一段时间的430,所以在选型的时候也就选了一款熟悉的产品MSP430F5438。

采样:使用Timer来控制采样频率(奈奎斯特定理),通过DMA来保存采样的数据。

FFT:TI一款EVB板的参考代码中有用汇编写的FFT运算,但是其采样点比较多,当前只使用了8*8的LED阵列,为了减少运算,直接使用8点的FFT运算,放弃了TI原有的FFT。

显示:在RGB LED阵列中已经结束如何实现。

电源

使用开关电源将220V转换成5V,然后通过TPS7301来给MCU和运放提供3.3V的电压。同时也用5V为LED阵列供电。LED阵列同时显示白光的时候电流比较大,为了保证安全和稳定,使用开关电源,不过这也有点奢侈。64个LED用1A的手机充电器其实也能够满足。

参考文章

1. FFT

2. WS2812b RGB-LED controlled with an MSP430

无评论

PHP 开发环境搭建——Nginx+PHP+Eclipse(PHP)

十 10 2013 由 创建在标签 开发

概述

以前做PHP时搭建服务器时整理的文档,现将它与大家分享。本文描述PHP环境的搭建步骤,以及配置过程;形成一个能够通过IDE进行单步调试的开发测试环境,节省开发时间。

软件准备

Windows7 64位系统

软件包

php-5.5.1-nts-Win32-VC11-x64

eclipse-php-helios-SR2-win32-x86_64

nginx-1.4.2

php_xdebug-2.2.3-5.5-vc11-nts-x86_64.dll

环境搭建

软件包均使用的是绿色版,可以打包直接拷贝(由于当前配置的机器是64位,32位需要重新配置)。

HTTP server

当前安装使用Nginx,也可以使用其他的Server,可以在此补充。

Nginx

配置使其支持PHP请求,找到如下所示首行的文本,去掉这块的注释(删除#号);把标记为红色的/scripts改为”$document_root”,这里的”$document_root”就是指前面”root”所指的站点路径。

location ~ \.php$ {
root D:/web/website;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

Nginx使用PHP需要使用CGI,所以PHP和Nginx都需要配置CGI参数。

PHP

PHP主要配置三个方面,一个是扩展包,另一个是关于CGI参数的解析,还有一个是关于与eclipse联合单步调试的配置。

扩展包

; extension_dir = "ext" 改为
extension_dir = "ext"

CGI参数修正

;cgi.fix_pathinfo=1 改为
cgi.fix_pathinfo=1

XDebug扩展

将下载的XDebug扩展的dll放到php的ext文件夹中,编辑php.ini,在最后添加如下的配置:

[Xdebug]
zend_extension = php_xdebug-2.2.3-5.5-vc11-nts-x86_64.dll
;下面的线程安全版本的配置
;zend_extension_ts = php_xdebug-2.2.3-5.5-vc11-nts-x86_64.dll
xdebug.remote_enable=true
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9001
xdebug.remote_mode = req
xdebug.remote_handler=dbgp

XDebug配置成功后调用phpinfo会显示有Xdebug运行,如果没有如图 31所示的Xdebug信息则说明配置失败。


图 31:XDebug配置后phpinfo显示

Eclipse

运行

Eclipse运行时使用的是jre运行,jre已经放在eclipse配置文件中。

eclipse.ini中添加如下配置(jre放在eclipse根目录下,下载的jre有版本号,此配置中已经把版本号删除):

-vm
jre/bin/javaw.exe

注:如果电脑上已经安装jdk,可以不用下载安装jre,也可以不用修改配置文件。

配置单步调试

在Window -> Preferences窗口的左边选择PHP -> Debug(如图 32),在窗口右边的PHP Debugger这一项中选择XDebug,这个选项的右边有个Configure链接,点进去可以对XDebug进行设置,请确保XDebug使用的端口号与php.ini文件中指定的相同(通常为9001)。


图 32:调试选项

调试的使用

打开 Eclipse ,新建立一个PHP Project,我继续建立一个测试项目,打开 index.php 页面。选择 Eclipse 菜单里的 Run –>Run Configurations,设置一下:


图 33:运行配置选项卡


图 34:开始调试

其他

自动运行和停止脚本

在启动脚本中,由于windows不能像Linux那样用&符号将程序在后头运行,所以在需要使用RunHiddenConsole工具,这样就能让windows程序在后台运行。启动脚本如下:

echo Starting PHP FastCGI...
RunHiddenConsole D:/web/php-5.5.1-nts/php-cgi.exe -b 127.0.0.1:9000 -c D:/web/php-5.5.1-nts/php.ini
echo Starting nginx...
RunHiddenConsole D:/web/nginx-1.4.2/nginx.exe -p D:/web/nginx-1.4.2

停止脚本:

echo off
echo Stopping nginx...
taskkill /F /IM nginx.exe > nul
echo Stopping PHP FastCGI...
taskkill /F /IM php-cgi.exe > nul
exit

遇到的问题和解决方案

Php不能运行,提示缺少DLL错误

这个是由于系统没有安装VS造成的,在PHP的下载首页可以看到提示到微软的官网上下载VC11的补丁;

不能断点调试

由于php和eclipse的配置造成的。一个是端口的冲突,由于FastCGI使用的是9000端口,按照网上的默认配置XDebug还是使用9000端口,在保证端口能够使用的情况下还要注意端口不要产生冲突;另一个是因为XDebug配置是使用的是extension参数而不是使用zend_extension。

参考资料

说明:本文中的图片也引用于上面两个资料,而不是自己配置时实际执行时截屏,在配置过程中仅有版本号不同,其余均与两个资料中的情况相同。

无评论

udev的使用

十 08 2013 由 创建在标签 开发

UDEV的文章网上有很多,但是很多都是直接转载过来,所以搜了很久都是相同的东西。关于UDEV英文的资料已经很全面了,我也不会去翻译那些文档。我主要从如何使用着手去写这篇文章,让读的人能够很快找到自己想要的东西。

配置

Udev有两种配置,一种是udev的配置,另一种是热插拔设备的规则配置;

udev配置文件

一个典型的配置如下:

# cat /etc/udev/udev.conf
# udev.conf
# The initial syslog(3) priority: "err", "info", "debug" or its
# state can be changed with: "udevcontrol log_priority=".
udev_root="/dev/" # 设备节点的根目录
udev_rules="/etc/udev/rules.d" #规则文件的路径,里面的具体文件格式在下一节介绍
udev_log="err" #udev的日志级别

规则配置文件

规则文件以.rules为后缀名,每一个文件处理一系列规则来帮助udev分配名字给设备文件以保证能被内核识别。

在一个规则文件中,以”#”开头的行被认为是注释。每一个非空的行都是一条规则,规则不能跨越多行。一条规则由多个规则语句(条件判断或赋值)组成,每个规则间用‘,’分隔。如 key OP vaule(OP表示操作符,后面提到的key和value均指此处)。

操作符

操作符如下表所示。

操作符 意义
== 比较是否相等
!= 比较是否不相等
= 给一个key 赋值。 表示一个列表的key会被重置,并且把这个唯一的值传给它
+= 将一个值增加到key中
:= 将一个值传给一个key,并且不允许再修改这个key

匹配关键字

这些关键字用于匹配设备,可以根据指定的条件执行特定的动作。

关键字 意义
ACTION 匹配事件的动作名
DEVPATH 匹配事件的设备devpath
KERNEL 匹配事件的设备名
NAME 匹配网络接口或者设备节点的名字。NAME 只有在前面的规则赋值之后才可以使用。
SYMLINK 匹配设备节点符号链的名字。SYMLINK 只有在前面的规则赋值之后才可以使用。可以有多个symlinks,只需要匹配一个。
SUBSYSTEM 匹配设备子系统,如block表示块设备,net代表网络等;
DRIVER 匹配设备的驱动名。只对绑定到一个驱动的设备有用。
ATTR { filename } 匹配事件设备的 sysfs 属性。
KERNELS 向上搜索devpath,直到找到一个匹配的设备名
SUBSYSTEMS 向上搜索devpath,直到找到一个匹配的子系统名
DRIVERS 向上搜索devpath,直到找到一个匹配的驱动名
ATTRS{ filename } 向上搜索devpath,直到找到一个含匹配 sysfs 属性的设备
ENV{key} 内核设置的环境变量
TAG 设备的 tag(暂时没有明白这个的用途)
TEST{octal mode mask} 测试一个文件是否存在,可以指定一个8进制的模式掩码。
PROGRAM 执行一个程序。如果程序成功返回, key 为 true。设备的属性被放在被执行进程的环境变量中,该程序的输出为 stdout, 可以从 RESULT 这个 key 读取。
RESULT 匹配最近一次 PROGRAM 调用的返回字符串。它应该在 PROGRAM 之后使用。

注:加了s的关键字会找其devpath的父目录,可以使用udevinfo -a -p /sys/***来查看具体的路径;

赋值关键字

这部分关键字用于修改设备的属性或者环境变量。

操作符 意义
NAME 修改网络设备的节点
SYMLINK 创建设备节点的符号链接;
OWNER, GROUP, MODE 设备节点的属性,用于修改用户组的权限
ATTR {key} 修改sysfs中设备属性的值
ENV {key} 修改环境变量
RUN 对于特定设备指定执行的命令
LABEL GOTO 可以跳到的地方
GOTO 跳到下一个带有匹配名字的 LABEL 处

上面对基本的配置进行了简单的介绍,现在看了一下之后基本上就是man手册里面的内容了,可以参考man udev中的内容。

配置实例

  • 网络设备的开机自动up和更名
SUBSYSTEM=="net", ACTION=="add", KERNEL=="eth*", NAME="lan", RUN+="/sbin/ifconfig lan up"
SUBSYSTEM=="net", ACTION=="add", KERNEL=="lo", RUN+="/sbin/ifconfig lo up"

上例中,网络设备的子系统名字是“net”,在开机时会有“add”事件,kernel中用了*号来匹配设备号,后面的NAME用于将eth0改成lan,这里之所以这样是因为我们的嵌入式设备只有一个网卡,不会因为多个网卡而造成冲突,同时将eth*改为lan的目的是为了管理起来方便(这样每次设备插入时就自动改为lan,不需要改上层的软件代码,增强代码的可移植性);最后RUN用于将接口UP。

  • 磁盘热插拔
ACTION=="add", KERNEL=="sd[a-z][1-9]", SUBSYSTEM=="block",  SYMLINK+="disk/by-name/%k"
ACTION=="add", KERNEL=="sd[a-z][1-9]", SUBSYSTEM=="block", RUN+="/bin/mkdir -p /disk/%k"
ACTION=="add", KERNEL=="sd[a-z][1-9]", SUBSYSTEM=="block", RUN+="/bin/mount -t auto /dev/%k /disk/%k"
ACTION=="remove", KERNEL=="sd[a-z][1-9]", SUBSYSTEM=="block", RUN+="/bin/umount -l /disk/%k"
ACTION=="remove", KERNEL=="sd[a-z][1-9]", SUBSYSTEM=="block", RUN+="/bin/rm -rf /disk/%k"

磁盘热插拔分为两个部分,一个是磁盘的插入,另一个是磁盘的移除;插入时现在devfs中创建按磁盘名字区分的链接;第二句穿件要mount的目录;第三句是自动mount到刚刚创建的目录;最后两句是移除磁盘时的操作,即先umount,再删除mount的路径。

udevinfo工具

通过udevinfo工具可以查看到设备的一些变量,这样可以帮助我们来写规则文件。下面是一个磁盘设备在执行udevinfo命令后的输出。

  looking at device '/block/sdb/sdb1':
    KERNEL=="sdb1"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{dev}=="8:17"
    ATTR{partition}=="1"
    ATTR{start}=="63"
    ATTR{size}=="7892929"
    ATTR{ro}=="0"
    ATTR{alignment_offset}=="0"
    ATTR{discard_alignment}=="0"
    ATTR{stat}=="     322      391      800     4900      351    43241    43592   464200        0     7700   469100"
    ATTR{inflight}=="       0        0"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0/host3/target3:0:0/3:0:0:0/block/sdb':
    KERNELS=="sdb"
    SUBSYSTEMS=="block"
    DRIVERS==""
    ATTRS{dev}=="8:16"
    ATTRS{range}=="16"
    ATTRS{ext_range}=="256"
    ATTRS{removable}=="1"
    ATTRS{ro}=="0"
    ATTRS{size}=="7892992"
    ATTRS{alignment_offset}=="0"
    ATTRS{discard_alignment}=="0"
    ATTRS{capability}=="51"
    ATTRS{stat}=="     323      391      808     4900      351    43241    43592   464200        0     7700   469100"
    ATTRS{inflight}=="       0        0"
    ATTRS{events}=="media_change"
    ATTRS{events_async}==""
    ATTRS{events_poll_msecs}=="-1"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0/host3/target3:0:0/3:0:0:0/block':
    KERNELS=="block"
    SUBSYSTEMS==""
    DRIVERS==""

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0/host3/target3:0:0/3:0:0:0':
    KERNELS=="3:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{device_blocked}=="0"
    ATTRS{type}=="0"
    ATTRS{scsi_level}=="3"
    ATTRS{vendor}=="ADATA   "
    ATTRS{model}=="USB Flash Drive "
    ATTRS{rev}=="0.00"
    ATTRS{state}=="running"
    ATTRS{timeout}=="30"
    ATTRS{iocounterbits}=="32"
    ATTRS{iorequest_cnt}=="0x2b9"
    ATTRS{iodone_cnt}=="0x2b9"
    ATTRS{ioerr_cnt}=="0x1"
    ATTRS{modalias}=="scsi:t-0x00"
    ATTRS{evt_media_change}=="0"
    ATTRS{queue_depth}=="1"
    ATTRS{queue_type}=="none"
    ATTRS{max_sectors}=="240"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0/host3/target3:0:0':
    KERNELS=="target3:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""
    ATTRS{uevent}=="DEVTYPE=scsi_target"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0/host3':
    KERNELS=="host3"
    SUBSYSTEMS=="scsi"
    DRIVERS==""
    ATTRS{uevent}=="DEVTYPE=scsi_host"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0':
    KERNELS=="1-1:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb-storage"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bNumEndpoints}=="02"
    ATTRS{bInterfaceClass}=="08"
    ATTRS{bInterfaceSubClass}=="06"
    ATTRS{bInterfaceProtocol}=="50"
    ATTRS{modalias}=="usb:v125FpC82Ad0100dc00dsc00dp00ic08isc06ip50"
    ATTRS{supports_autosuspend}=="1"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1':
    KERNELS=="1-1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{dev}=="189:2"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="80"
    ATTRS{bMaxPower}=="480mA"
    ATTRS{urbnum}=="2092"
    ATTRS{idVendor}=="125f"
    ATTRS{idProduct}=="c82a"
    ATTRS{bcdDevice}=="0100"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{speed}=="480"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="3"
    ATTRS{devpath}=="1"
    ATTRS{version}==" 2.00"
    ATTRS{maxchild}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{authorized}=="1"
    ATTRS{manufacturer}=="ADATA"
    ATTRS{product}=="ADATA USB Flash Drive"
    ATTRS{serial}=="0000000C082ACB"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1':
    KERNELS=="usb1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{dev}=="189:0"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bMaxPower}=="  0mA"
    ATTRS{urbnum}=="38"
    ATTRS{idVendor}=="1d6b"
    ATTRS{idProduct}=="0002"
    ATTRS{bcdDevice}=="0300"
    ATTRS{bDeviceClass}=="09"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{speed}=="480"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="1"
    ATTRS{devpath}=="0"
    ATTRS{version}==" 2.00"
    ATTRS{maxchild}=="2"
    ATTRS{quirks}=="0x0"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{authorized}=="1"
    ATTRS{manufacturer}=="Linux 3.0.8 ehci_hcd"
    ATTRS{product}=="HIUSB EHCI"
    ATTRS{serial}=="hiusb-ehci"
    ATTRS{authorized_default}=="1"

  looking at parent device '/devices/platform/hiusb-ehci.0':
    KERNELS=="hiusb-ehci.0"
    SUBSYSTEMS=="platform"
    DRIVERS=="hiusb-ehci"
    ATTRS{modalias}=="platform:hiusb-ehci"
    ATTRS{companion}==""

  looking at parent device '/devices/platform':
    KERNELS=="platform"
    SUBSYSTEMS==""
    DRIVERS==""
    ATTRS{uevent}==""

参考资料

  1. http://www.linuxsir.org/bbs/thread323186.html
  2. http://www.cnitblog.com/luofuchong/archive/2007/12/18/37831.html
  3. linux man udev;
  4. udev wiki
  5. 编写UDEV规则

 

无评论

在链表寻找环

四 14 2013 由 创建在标签 开发

编程之美:两个链表相交问题

编程之美中有一篇获取链表中是否有环的问题,作者提出来两种解法,一种是将B链表尾部与A链表头相连,然后以此为A为起点遍历,要是遍历到A节点,则两个链表指向同一个节点;

另一个解法是直接遍历到链表尾部,比较最后一个节点是否为同一个节点,相同即两链表相交,不同则链表无焦点。

 

判断一个链表中是否形成环

上面的解法一可以扩展一下,如果有一个链表,开始我们不知道是否有环,如何判断是否形成了环?

解法一:

假设有N个节点,我们可以先遍历N次,然后以此节点作为参考,继续遍历,要是中途有相同的节点,则有环;若无环,则不会循环比。

解法二:

上面一种解法有一个很严重的漏洞,就是如果我的节点个数未知,那如何比较呢?我们不清楚究竟从何处开始形成环,也没有办法选择参考。

此时可以参考图深度(广度)遍历算法中使用的方法,增加一个标志位来记录已经访问过的节点,只要每次比较和记录节点的颜色就可以判断是否已经成环,如果遍历过程中有已经访问过的节点,则说明已经成环;如果遍历结束,则未成环。

这种算法通过增加空间来标识访问的节点,需要增加的存储空间为O(N);

解法三:

如果我们将现在的链表表头同时赋给两个不同的指针,同时遍历链表,但是两个以不同的步长遍历,一个指针依次遍历每个节点,而另一个节点每次以2为步长遍历,即每次遍历时间隔一个节点。通过判断两个指针是否相同或者是否到达尾部来确定是否成环。

这个类似于两个人跑步,一个人是另一个人速度的两倍,当围着环形操场跑时(即链表有环),则会出现一种情况,快的追赶跑得慢的人,每次两个人缩短1的距离,这样一旦慢的进入环中,最多只要慢的跑半个环就可以判断是否存在环了。

bool IsExitsLoop(slist *head)

{

slist *slow = head, *fast = head;

while ( fast && fast->next )

{

slow = slow->next;

fast = fast->next->next;

if ( slow == fast ) break;

}

return !(fast == NULL || fast->next == NULL);

}

判断环的交点

一个个去遍历判断效率会很慢,可以使用一个定理:

碰撞点p到连接点的距离=头指针到连接点的距离

因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。

证明:
辅助理解图
假设单链表的总长度为L,头结点到环入口的距离为a,环入口到快慢指针相遇的结点距离为x,环的长度为r,慢指针总共走了s步,则快指针走了2s步。另外,快指针要追上慢指针的话快指针至少要在环里面转了一圈多(假设转了n圈加x的距离),得到以下关系:

r = L – a + 1;

s = a + x;

2s = a + nr + x;

则:a + x = nr;

a = nr - x;

由上式可知:若在头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点。

slist* FindLoopPort(slist *head)
{
    slist *slow = head, *fast = head;

    while ( fast && fast->next )
    {
        slow = slow->next;
        fast = fast->next->next;
        if ( slow == fast ) break;
    }

    if (fast == NULL || fast->next == NULL)
        return NULL;

    slow = head;
    while (slow != fast)
    {
         slow = slow->next;
         fast = fast->next;
    }

    return slow;
}

判断环的长度

当发生碰撞后,再次碰撞所走过的操作数就是环的长度s。

参考

1、http://blog.csdn.net/liuxialong/article/details/6555850

2、编程之美

无评论

MiniGUI核心库自动编译脚本

一 17 2013 由 创建在标签 开发

前一段时间整理了一下MiniGUI的编译,写了一个自动编译的脚本,把所有的环境变量都添加在脚本中,免去配置的痛苦,只需要更改相应的环境变量配置即可。

脚本如下:

#!/bin/sh
# Author : sgbihu.com
# Create date: 2013-01-17
# Function: compile the minigui lib
#
#

CURPATH=$PWD
# The complie path
MINIGUIROOTDIR=/home/linux/minigui

# Compile env
export CC=arm-linux-gcc
export CXX=arm-linux-g++
export LD=arm-linux-ld
export AS=arm-linux-as
export AR=arm-linux-ar
export CFLAGS="-I/usr/local/minigui/include"
export CPPFLAGS="-g -I/usr/local/minigui/include"
export CXXFLAGS="-g -I/usr/local/minigui/include"
export LIBS="-L/usr/local/minigui/lib"
export STRIP=arm-linux-strip

# The path you want to install
INSTALLPATH="/usr/local/minigui"
# The crosstool's include, Now only used by miniGUI Core lib.
CROSSCOMPILEINCLUDE="/opt/crosstool/arm-linux/gcc-3.4.4-glibc-2.3.5/arm-linux/arm-linux/include"
# The Compile devices
HOST=arm-linux
BUILD=i386-linux
TARGET=arm-linux

cd $MINIGUIROOTDIR

# Zlib
cd ./zlib-1.2.6
./configure --prefix=$INSTALLPATH --shared
make
make install
#PNG
cd ../libpng-1.5.8
./configure --prefix=$INSTALLPATH --includedir=$INSTALLPATH/include --build=$BUILD --host=$HOST --target=$TARGET

make
make install

#JEPG
cd ../jpeg-8c

./configure --prefix=$INSTALLPATH --build=$BUILD --host=$HOST --target=$TARGET --enable-shared
make
make install

# FREE TYPE
cd ../freetype-1.3.1

export ac_cv_sizeof_int=4
export ac_cv_sizeof_long=4
./configure --prefix=$INSTALLPATH --build=$BUILD --host=$HOST --target=$TARGET --enable-static

unset ac_cv_sizeof_int
unset ac_cv_sizeof_long
make
make install

# MiniGUI resource
cd ../minigui-res-be-3.0.12
./configure --prefix=$INSTALLPATH
make
make install

# MiniGUI Core Lib
cd ../libminigui-gpl-3.0.12
./configure --prefix=$INSTALLPATH --build=$BUILD --host=$HOST --target=$TARGET --with-osname=linux --with-style=classic \
            --with-targetname=fbcon --enable-autoial --enable-rbf16 --disable-vbfsupport --oldincludedir=$CROSSCOMPILEINCLUDE

make
make install

# Strip
$STRIP $INSTALLPATH/lib/*

在执行脚本中还是会遇到错误,需要改几个Makefile的生成模板。Makefile.in和Makefile.am。同时需要注释掉一些测试程序的编译。注意点如下:

freetype库:在Makefile.in中去掉“all:”后的变量“tttest”,注释掉“install:”下的第二行: $(FTTESTDIR); $(MAKE) –f$(MAKEFILE) install。

minigui核心库:所有目录下的Makefile.in和Makefile.am都有一个/usr/include的绝对路径,将这个路径替换成$(oldincludedir),执行这个脚本即可编译minigui的核心库。

最后编译一个例子程序,然后在你的开发板上运行吧!

无评论

谣言止于智者

四 19 2012 由 创建在标签 开发

这段时间在网上看到很多关于谣言的报道,对于部分报道我感到很无语,也很失望,甚至让人感觉是在洗脑。本不想说什么,但是还是忍不住在自己的博客上写点东西,因为实在憋不住了。

互联网在全球发展迅猛,各种技术日新月异,让世界的距离变小,让我们能够找到我们想要的信息。而互联网上的信息混杂,我们需要去区分,不是一味地去接受。但是我们的教育教会我们去区分了吗?我们的社会教会我们信任了吗?我想大家都心知肚明,谈到教育,大家都会吐槽,教改改了多年,学生还是一味地学习那些死知识,没有教会大家如何运用自己所学来区分是非,大是大非学校倒是提得不少,但是听起来只像是口号,有时连倡导的人都不会去做,甚至有些只是为了宣传为了面子而做!能不能做一点实事?至少教会大家如何思考,不是一味相信权威。

而现在权威的力量已然受到威胁,因为太多的事实在刺激着大家神经,从三聚氰胺开始,大家的神经就变得敏感,但是此次事件并没有让我的生活变得更加美好,相反,我们的生活的环境反而越来越恶劣。食品安全事故、贪污腐败、分配不均等等问题,已然让大家敏感的神经更加敏感。加上政府在一些事件上的一些表现,让很多人失望,为什么人民的公仆不能对人民透明一点呢?不接受人民的意见呢?

想想发现,大家连最基本生活能够得到保证了,出门怕被富二代官二代撞了,吃的东西都要自己去种了,甚至连打工的都会变成替罪羔羊……那些大企业的良心何在?那些先富起来人的良心何在?有没有一点社会责任?到这里,我们的监督部门跑哪里去了?大多数时候只是选择性公布,你们是这样为人民服务的吗?你们的那些口号呢?那些墙上的标语跑哪里去了?

微博是谣言的温床,感觉这是现在宣传的重点,让人民不要相信互联网,远离网络,有益健康。但是微博上部分事情渐渐变成了事实,即使出来澄清或者辟谣,但是无情的事实让我们选择了相信那些所谓的“谣言”。曾经在某公司实习的时候一个员工说的话——他们正着说你反着来就对了。正可谓是越辟越邪,我想这对于那些权威部分是极大的讽刺,你们在人们的心里是如此的“高大不凡”。我也承认,微博上是有一些谣言,但是如果你们教会了大家思考,人们会去相信那些谣言吗?如果你们能够公开信息,让事实证明你们都是对的,大家还会去相信那些八卦吗?微博信息的传递速度很快,其实这对你们来说是一种帮助,只要你们所说的所做的能够让人信服和相信,那些谣言自然不会被人采纳;而且那也是监督的一个平台,人都是不自觉的,有了这个平台,我相信会让有些黑心的人畏手畏脚的,更不敢为所欲为!为什么你们要一味的封杀呢?

最后用你们教给大家的一句话,也是我的题目——谣言止于智者,不要一味地封锁信息,在这个信息的时代里,你不可能封锁得了所有的信息传递窗口;你也不可能让每个人禁言;更不要阻止那些说真话的人而帮助那些睁眼说瞎话的人。因为你的公信力已经很弱了。教会大家去思考,让大家畅所欲言,那样对你和大家都是好事,而且两全其美。你的公信力上升,谣言也会停止,那个时候你还会这样担心吗?

无评论

3G modem在linux上的移植

三 31 2012 由 创建在标签 开发

3G模块调试

第三代移动通信技术(3rd-generation,3G),是指支持高速数据传输的蜂窝移动通讯技术。3G服务能够同时传送声音及数据信息,速率一般在几百kbps以上。目前3G存在四种标准:CDMA2000,WCDMA,TD-SCDMA,WiMAX。

1简介

现在市场上的3G模块大部分都是zero CD模式,只能识别成CD-ROM,在这个虚拟的光驱中提供驱动,但是大部分厂商只会提供Windows驱动,少部分厂商提供Linux驱动(大部分厂商都是通过自己的工具或者通过udev来转换modem的模式,而嵌入式系统一般使用mdev),没有厂商提供嵌入式Linux驱动,对于做嵌入式Linux的人来说就要自己动手了。因而不能识别成我们所需要的串口设备,这样就没有办法去享受移动网络所带来的便利,也就没有办法完成任务了。网上有很多方法来让设备变成串口设备,所以让3G modem上网的主要工作就是将存储设备转换成串口设备。
USB modem转换成串口设备的方法主要有以下几种方法。

1.1eject命令

就是讲CD-ROM弹出,这个命令需要设备的支持,网上有很多人用这种方法来做,但是有很大一部分人来做,如果你买的设备支持,那恭喜你,可以不用看后面的内容了。

1.2修改通用设备将对应的设备忽略

文件drivers/usb/storage/unusual_devs.h中可以通过宏忽略我们的设备为通用设备,我们通过lsusb或者在windows设备管理器中可以查到设备的vendorID和productID,在文件中添加如下代码即可。

UNUSUAL_DEV(  vendorID, productID, 0x0000, 0x0000,
                "AzureWave",
                "AzureWave CDROM USB Device",
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_IGNORE_DEVICE ),

我使用的设备在这样修改后可以识别成一个ttyUSB0,没有测试那个串口是否可以直接发送AT命令,但是为了保险起见,还是想办法将其识别成多个串口设备。很多网上的资料都说要识别成多个串口,我猜可能是单个串口会影响到网速(个人猜测,没有验证)。

1.3通过usb_modeswitch切换modem的运行模式

我在这个过程中走了很多弯路,主要花在这个抓usb传输消息的过程,然后测试不同的消息发到USB modem那边看是否有反应,能否识别成多个串口。反复测试无果,只能想其他办法。

抓包是通过usbsniffer工具在windows下做的,因为一般的设备都提供了windows的驱动,在windows下可以获得驱动是如何让设备转换zeroCD模式的,如果知道了驱动发送的消息,我们在linux下面通过工具发送同样的消息就可以使设备安装我们的意愿工作了。

然而事情往往没有我们想象中的那么单纯,有了抓包这一步,就需要去区分哪些有用消息哪些是无效的消息,而抓包的过程中会产生很多报文,通过sh脚本和windows下自己写的工具来将数据提取出来(代码写得太挫,只为了提取数据)。通过TTerm的脚本批量发送获取的消息。

本以为到此结束,谁曾想到这只是一个开始,大量的数据中没有找到我要数据,那个伤心呐~~一时之间陷入困境,开始看USB子系统相关的知识。

功夫不负有心人,结合厂商提供的udev规则,发现我们的设备是工作在第二配置下,而在识别设备的时候都是直接使用的配置一。只要有工具能够修改设备的配置就可以了,本打算自己动手写一个,后来看usb_modeswitch代码的时候发现它是可以完成这个工作的,本打算只用它来发消息的,没想到它还能修改配置模式,可谓是转了一圈又回到了原点。这样修改配置后,设备就可以识别成我们想的串口了,一下子转换成12个ttyUSB,真是幸福来得太快了,但是这样也不好,需要区分哪些是可以发送AT命令的串口,只要做些区分就可以安装我们的意愿来工作了,可以在proc文件系统中看USB设备各个接口的工作模式,找到对应的串口就可以直接发送AT命令了。

1.4通过工具在Windows下禁用设备的zero CD模式

这个方法就是通过工具对设备进行操作,让设备在识别的时候就只能识别出串口设备,具体的机制不太明白,有点像软改。那样插上设备就可以直接识别出串口设备了。

1.5通过SYS文件系统

这个方法是我在读USB子系统的内核源码发现的,就是通过SYS文件系统提供的方法来实现USB设备配置的更改,与USB_modeswitch工具的原理是一样的,只是一个通过工具来做,一个是通过内核提供的文件系统来做,原理是相通的。

1.6几种方法的比较

第四种方法简单,但是并不建议使用,所以我在捣腾的过程中直接忽略这种方法,毕竟一个产品如果量产,我们要去修改每一个3G modem,那样工作量就太大了。还是比较推荐使用usb_modeswitch工具来修改设备的配置,这样最稳定,也不会留下任何后遗症;第二种方法其实并不可取,因为我们只是不识别成串口了,其他接口同样没有被识别出来,我虽然没有尝试就用一个串口来进行拨号,但是那样设备并没有真正工作在modem模式,不能叫设备正常运行;如果能够拨号成功,也不能算错或者有问题,最糟糕的就应该是识别出来的不是AT命令对应的tty口,那就让人郁闷了,拨号的时候不能拨通。

有了第五种方法后,usb_modeswitch工具似乎就可以不用了,但是这个只适用于USB设备是采用的多个配置方式来实现设备的,如果像华为那样通过消息来改变设备的工作模式的话,此方法并不可取,必须通过工具来实现运行模式的切换。

2内核配置

Device Drivers  --->
  [*] USB support  --->
       USB Serial Converter support  --->
      [*]   USB Generic Serial Driver
         USB driver for GSM and CDMA modems
  [*] Network device support  --->
          PPP (point-to-point protocol) support
       [*]     PPP multilink support (EXPERIMENTAL)
       [*]     PPP filtering
            PPP support for async serial ports
            PPP support for sync tty ports
            PPP Deflate compression
            PPP over Ethernet (EXPERIMENTAL)

2.1修改option.c文件

让option能够支持我们的模块。

2.2安装模块

/ # insmod /lib/modules/2.6.28/usbserial.ko
/ # insmod /lib/modules/2.6.28/option.ko

3 USB工具

俗话说:“工欲善其事必先利其器”,有好的工具就能够带来很高的效率。下面是我在测试3G模块成功过程中所用到的工具。可以根据自己的需要选用恰当的工具。

3.1 usbsniffer

windows下的USB抓包工具,可以监听usb口的数据传输,分析USB数据包。有很多工具可以使用,需要的可以在网上搜一下。我用的是SniffUsb。

3.2 libusb

其实这只是一个usb库,它不提供任何功能,但是下面的三个工具都会使用到这个库,所以在USB modem的调试过程中起着至关重要的作用。我们也可以通过这个库来写适合自己的小工具,USB库已经把与内核通信的接口封装好了,使用起来比较方便。写自己工具的适合可以适当参考usb_modeswitch工具的源码,那个里面包含了自动识别设备及接口的代码,以及消息的发送方法,有较大的参考意义。

3.2.1 交叉编译

[root@localhost] CC=/opt/EmbedSky/4.3.3/bin/arm-linux-gcc \
			     CXX=/opt/EmbedSky/4.3.3/bin/arm-linux-g++\
			     ./configure --build=i686-linux \
                                    --host=arm-linux \
			     --target=arm-linux \
			     --prefix=/home/ driver/3g/libusb-0.1.12/_install
[root@localhost] make
[root@localhost] make install

3.3 usb_modeswitch

切换多重USB设备运行模式的转换工具。现在一些新的USB 设备(特别是一些高速 WAN 设备,很贵的那种)都有MS Windows的驱动程序,当第一次插入机子的时候,它们处于闪存模式,并从中提取和安装驱动。在驱动安装完毕之后,驱动马上转换模式,储存设备消失(基本上都是这样的),然后一个新的设备(比如一个USB modem)出现。

此工具在网上有现成的配置文件可以下载,如果你的设备包含在其中的话,那就恭喜你能够省略很多繁琐的步骤去做抓包工作了,也可以少走很多弯路。

3.3.1 交叉编译

[root@localhost] CC=arm-none-linux-gnueabi-gcc \
                 CXX=arm-none-linux-gnueabi-g++ \
                 LD=arm-none-linux-gnueabi-ld \
                 CFLAGS="-I/home/driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CPPFLAGS="-g -I/home/driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CXXFLAGS="-g -I/home/driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                   ./configure --prefix=/home/driver/3g/libusb-0.1.12/_install \
                   --host=arm-linux\
                   --target=arm-linux
[root@localhost] make
[root@localhost] make install

3.4 lsusb

lsusb是一个学习USB驱动开发,认识USB设备的助手,它用于查询usb设备的信息,它依赖于虚拟文件中proc系统,在使用时需要配置内核。

3.4.1 交叉编译

[root@localhost] CC=arm-none-linux-gnueabi-gcc \
                 CXX=arm-none-linux-gnueabi-g++ \
                 LD=arm-none-linux-gnueabi-ld \
                 CFLAGS="-I/home/ driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CPPFLAGS="-g -I/home /driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CXXFLAGS="-g -I/home/ driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                   ./configure --prefix=/home/ driver/3g/libusb-0.1.12/_install \
                   --host=arm-linux\
                   --target=arm-linux
[root@localhost] make
[root@localhost] make install

3.5 ppp

智能拨号工具,其他拨号工具也会依赖此工具,如wvdial。拨号使用到两个可执行程序pppd和chat,有了这两个工具只要借助脚本就可以是modem拨号上网了。

这个工具的交叉编译也不是很难,只要修改一下makefile,然后直接make就可以了。

3.6 wvdial

自动拨号工具,通过wvdialconf工具可以测试接口支持的速率并自动生成配置文件,只需要改少量的配置就可以拨号上网。

我也没有交叉编译过此工具,只是在pc上用它生成过配置文件,并验证能否上网,在嵌入式设备上并没有使用它,因为开发板上的资源太紧张了。

3.7 ppp和wvdial比较

上两种方式各有自己的优缺点,第一种方式智能稳定,他不需要chat程序,使用集成的wvdial工具包直接连接ISP,安全稳定,可以断线自动重拨。第二方式,使用chat程序,但是很多的参数需要自己去配置,虽然比较灵活,但是如果遇到了拨号错误以后,你若不清ppp协议拨号实现的具体机制和每个参数的含义,你就会很吃力,也许运气好的时候,你运行的环境正好和本地的移动isp配置吻合,恭喜你能上网了,但是你遗憾的是没有学到东西,想了解 ppp机制的朋友,可以试试第2种方式,在了解大体了解ppp协议的前提下,观察思考/var/log/messages中的信息。

3.8 其他

minicom是linux下一款比较方便的串口助手,类似于Windows下的超级终端,功能比较强大可以自己使用的时候尝尝鲜。

3.8.1 ncurses-5.5

minicom的依赖库。

[root@localhost]# mkdir install
[root@localhost]# ./configure --build=i686-linux --host=arm-linux --prefix=/home/minicom/ncurses-5.5/install
[root@localhost]# make&&make install

3.8.2 minicom-2.1

minicom工具的编译。

[root@localhost]# mkdir install
[root@localhost]# ./configure --build=i686-linux --host=arm-linux --prefix=/ home /minicom/minicom-2.1/install/ CPPFLAGS="-I / home /minicom/ncurses-5.5/install/include/ncurses" LDFLAGS="-L / home /minicom/ncurses-5.5/install/lib"

3.8.3 minicom使用

至此工具已经编译完成,剩下的工作就是拷贝到开发板上去运行我们交叉编译的程序,不要以为工作已经全部完成,还有一步需要我们去做。就是配置minicom运行的环境变量。

如果没有配置终端信息的话,运行时会提示错误,需要将lib目录下的tesrminfo的v文件夹中的终端信息拷贝到文件系统中,并导出环境变量,这样在开发板上才能正确运行。

cp -r /lib/terminfo/v $rootfs/usr/share/terminfo
export TERMINFO=/usr/share/terminfo

4 热插拔脚本

开始尝试直接在hotplug文件中直接执行usb_modeswitch程序,但是在添加USB设备的阶段还是早了一点,于是就在mdev.conf文件中添加执行脚本。但是下面这段代码可以用来动态添加和删除模块。

SUBACTION="$SUBSYSTEM.$ACTION"
if [ "$SUBACTION" = "usb-serial.add" ] ; then
    SUBINFO=${PRODUCT:0:8}
    echo $SUBINFO>>/var/test
    if [ "$SUBINFO" = "4cc/231f" ] ; then
      /bin/usb_modeswitch -v 0x04cc -p 0x231f -u 2
      echo "testtttt">>/var/test
    fi
fi

5 拨号

设备识别出来后,下一步要做的工作就是拨号上网,其中内核中关于PPP的配置一定要配置上,否则拨号会失败。

5.1 运营商设置

不同的运营商会使用不同的拨号参数,虽然设备是一个,但是需要根据运营商来设置我们拨号相关的参数。而拨号的脚本基本相同,但是不同设备间可能会有少许差异,不同的设备可以根据实际来作简单调整。

5.1.1 电信3G设置

Dail number : #777
User name : card
Password : card

5.1.2 中国联通3G设置

APN:3gnet
Access number:*99#  (拨号号蚂)
User name: uninet
Password:空

5.1.3 中国移动 3G 设置

APN: cmnet
Access number 拨号号码: *99***1#
User name (账号) :空
Password (密码)  : 空

5.2 自动拨号

pppd connect 'chat  -v -s -r "/var/report" -f "/etc/ppp/ppp-on-dialer"' /dev/ttyUSB0 115200 mru 1280 mtu 1280 nodetach debug dump defaultroute usepeerdns novj novjccomp noipdefault ipcp-accept-remote connect-delay 5000 linkname ppp0
ABORT   BUSY
ABORT   'NO CARRIER'
ABORT   ERROR
REPORT  CONNECT
TIMEOUT 10
""      "AT&F"
OK      "ATE1"
OK      'AT+CGDCONT=1,"IP","3gnet"'
SAY     "Calling UMTS/GPRS"
TIMEOUT 30
OK      "ATD*99#"
CONNECT ' '

6 UI需求

拨号号码

apn
username
password

7 总结

还没有完全整理完毕,后续会继续补充。

附录:

1. usb_modeswitch网站(http://www.draisberghof.de/usb_modeswitch);
2. SniffUSB(http://www.pcausa.com/Utilities/UsbSnoop/default.htm);
3.

一条评论

ath9k_htc使用compatwireless在嵌入式linux上的使用

三 02 2012 由 创建在标签 开发

最近忙一个项目的无线模块,使用的是ath9k_htc这个wifi模块,由于官方没有提供驱动源码,只能使用无线兼容包。其实所有的驱动在高版本的内核中都已经包含,如果开发环境允许,可以使用高版本的内核,也许就不会遇到那么多的问题了。下面就言归正传,说说我是如何在2.6.28的内核上移植无线驱动的。

开发环境

内核版本:2.6.28

交叉编译器:gcc version 4.4.0 (Faraday C/C++ Compiler Release 20100325)

compatwireless:2.6(日期是2012-02-15)

firmware:1.3

wireless-tool:29

iw(配置ap模式,并没有实际测试)

配置内核

[*] Networking support  --->
    [*]   Wireless  --->
        [*]   Wireless extensions
        [*]     Wireless extensions sysfs files

-*- Cryptographic API  --->
    {M}   Cryptographic algorithm manager
       ARC4 cipher algorithm

配置内核使内核支持无线,由于802.11需要用到一些加密算法,所以需要把加密模块编译成模块,由于开始没有考虑加密,所以无线在连接的时候总是连不上,最终不得不在代码中寻找问题,后面我也会详细来说。

编译compatwireless

# 配置驱动类型
./scripts/driver-select ath9k_htc
# 编译驱动
make KLIB=//linux-2.6.28 KLIB_BUILD=/linux-2.6.28

这使ath9k_htc驱动的主体部分,它需要读取内核配置文件.conf,然后根据内核的配置来决定编译哪些模块。编译的时候会遇到很多问题,都可以根据它的提示来解决。主要是trace.h包含的一些调试函数,基本上所有的错误都是由于这个头文件里的函数造成的。我的处理办法就是把他们全部注释掉,但是这样就不能跟踪代码了。其实我们使用这个驱动也没有必要来跟踪代码,毕竟我们对802.11协议还不是十分了解,让我们这些外行跟踪内部的东西那就不敢想象其中的工作量了。

编写驱动加载脚本

# 兼容包及802.11驱动
insmod /lib/modules/2.6.28/compat.ko
insmod /lib/modules/2.6.28/compat_firmware_class.ko
insmod /lib/modules/2.6.28/rfkill_backport.ko
insmod /lib/modules/2.6.28/cfg80211.ko
insmod /lib/modules/2.6.28/mac80211.ko
# ath9k_htc驱动
insmod /lib/modules/2.6.28/ath.ko
insmod /lib/modules/2.6.28/ath9k_hw.ko
insmod /lib/modules/2.6.28/ath9k_common.ko
insmod /lib/modules/2.6.28/ath9k.ko
insmod /lib/modules/2.6.28/ath9k_htc.ko
# 加密模块
insmod /lib/modules/2.6.28/crypto_algapi.ko
insmod /lib/modules/2.6.28/arc4.ko

驱动编译完成后,先手动加载,发现驱动的加载有先后顺序,而且每次开机启动都要手动加载,那是相当的麻烦,所以就写了一个加载wifi驱动的脚本,开机后自动运行就可以了。主要是保证他们的加载先后顺序。

热插拔自动启动设备

#!/bin/sh

#do something that mdev has to do
/sbin/mdev $1

EVENT="$SUBSYSTEM.$INTERFACE.$ACTION";

if [ "$EVENT" = "net.wlan0.add" ] ; then
    iwconfig wlan0 essid "ap01"
    iwconfig wlan0 key 11111111111111111111111111
    echo "The wlan0 is created!">> /var/log
    ifconfig wlan0 up
# mdev 貌似不能发出linkup的热插拔时间,对此不太了解,所以在启动后就直接配置
#elif [ "$EVENT" = "net.wlan0.linkup" ] ; then
    ifconfig wlan0 192.168.88.188 netmask 255.255.255.0
    route add default gw 192.168.88.254
    echo "The wlan0 is up!">> /var/log
fi

可能显得没有很大的必要,因为设备一旦启动了,一般不会无缘无故把wifi设备拔掉,只要开机启动的时候做好就可以了,但是有了热插拔还有另一个好处,那就是自动配置设备,并启动设备。上面的配置也很简单,就是检测到无线wlan0插入后自动启动无线并配置ip地址,也可以根据实际应用开启相关的网络应用程序,保证对网络相关的程序能够正常执行。

遇到的问题及解决方案

wep不能认证

开始觉得很奇怪,为什么设备已经被识别了,而且能够正常工作,为什么加密后就不能连接ap,而是用open方式可以连接上ap。所就觉得不是驱动的问题,因为驱动有问题的话open方式的ap也就连接不上了,所以应该是加密或者配置的部分有问题。开始就在看compatwireless和wireless-tool的代码,代码实在是太庞大,想发现问题也没有那么容易,而且也没发现配置有问题,密码应该是配置下去了。

只有自己加一点调试信息,然后根据调试信息来定位,后来发现代码根本就没有走到认证的地方,无奈只能从驱动的初始化和wep加密相关的地方入手,就在初始化的过程中加了一些调试信息。同时修改内核,在内核配置的时候发现配置了内核中802.11协议栈的时候,发现协议栈对加密模块有依赖,而我在运行驱动的时候并没有加载加密的驱动,后来又跟踪到如下代码,发现用到了arc4算法,遂配置内核的加密模块,编译加载之,发现错误的调试信息就没有打印出来,同时也能上线了~~

int ieee80211_wep_init (struct ieee80211_local *local)
{
    /* start WEP IV from a random value */
    get_random_bytes (&local->wep_iv, WEP_IV_LEN);
    // 加载arc4加密模块
    local->wep_tx_tfm = crypto_alloc_cipher ("arc4", 0, CRYPTO_ALG_ASYNC);
    if (IS_ERR (local->wep_tx_tfm))
    {
        local->wep_rx_tfm = ERR_PTR (-EINVAL);
        return PTR_ERR (local->wep_tx_tfm);
    }

    local->wep_rx_tfm = crypto_alloc_cipher ("arc4", 0, CRYPTO_ALG_ASYNC);
    if (IS_ERR (local->wep_rx_tfm))
    {
        crypto_free_cipher (local->wep_tx_tfm);
        local->wep_tx_tfm = ERR_PTR (-EINVAL);
        return PTR_ERR (local->wep_rx_tfm);
    }

    return 0;
}

其实很难让人怀疑到是那个地方的错误,因为一般如果说某个函数不存在,在运行的时候会报错,而这个通过了一个接口封装,将算法的提取放到封装的函数接口中去了,而且这个接口特别友好,不会让你的程序在运行运行出错,只会告诉你一个简单的错误码。所以觉得有的时候太友好了导致的错误更让人头疼。

热插拔脚本不能执行

在/sbin目录下创建一个文件名为hotplug的shell脚本,在里面添加echo语句,但是前台没有打印,就直接判断不能执行热插拔的脚本。但是反复测试后发现即使用mdev来做也不会打印信息(有师兄说有时候会打印出echo输出的信息),但是其实它是在后台执行了的,只是没有表现出来而已。可以把打印出来的消息输入文件,然后在文件中查看,这样就可以确定是否真正运行了。

注意:需要注意的是hotplug可执行的脚本在第一行一定要加上:#!/bin/sh,否则不能执行。

ath9k_htc找不到firmware

这个问题我也不能完全确定,但是在两种情况下是不会发生的。第一:将mdev指定为/proc/sys/kernel/hotplug的执行程序;第二:在/sbin目录下添加上面写道hotplug脚本,而且需要添加:/sbin/mdev $1,如果不加也会出现错误。

所以就猜测是由于/sbin目录下不存在hotplug可执行程序且没有为其指定,但是至于为什么,现在还没有了解清楚。可能是插入USB wifi后需要处理一系列的热插拔事件,每个处理完了才能进入下一步。

iwconfig配置AP模式master时出错

用iwconfig配置模式的时候会出现配置错误,因为有了前面出错的经验,就直接在源码中寻找问题的所在。最终在函数cfg80211_wext_siwmode中找到问题所在,从代码中可以看出,当遇到配置为master时就会返回错误,然后就会提示配置错误。

int cfg80211_wext_siwmode(struct net_device *dev,
                          struct iw_request_info *info,
			  u32 *mode,
                          char *extra)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_registered_device *rdev;
	struct vif_params vifparams;
	enum nl80211_iftype type;
	int ret;

	rdev = wiphy_to_dev(wdev->wiphy);

	switch (*mode) {
	case IW_MODE_INFRA:
		type = NL80211_IFTYPE_STATION;
		break;
	case IW_MODE_ADHOC:
		type = NL80211_IFTYPE_ADHOC;
		break;
	case IW_MODE_REPEAT:
		type = NL80211_IFTYPE_WDS;
		break;
	case IW_MODE_MONITOR:
		type = NL80211_IFTYPE_MONITOR;
		break;
	default:
		return -EINVAL;
	}

	if (type == wdev->iftype)
		return 0;

	memset(&vifparams, 0, sizeof(vifparams));

	cfg80211_lock_rdev(rdev);
	ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams);
	cfg80211_unlock_rdev(rdev);

	return ret;
}

所以iwconfig不能配置,搜索后发现需使用其他工具iw。只找了一下,由于项目中不需要这个功能,且进度比较紧,所以就直接没有测试它是否真的有效。想配置的可以去尝试一下。

附录:

1、firmware下载链接;

2、ATH9k_htc驱动主页

3、无配置线工具(wireless-tool);

4、新的无线配置工具(iw);

 

10 条评论

miniGUI3.0在mini6410上的移植

二 12 2012 由 创建在标签 开发

简介

MiniGUI 是一款面向嵌入式系统的高级窗口系统(Windowing System)和图形用户界面(Graphical User Interface,GUI)支持系统,由魏永明先生于 1998 年底开始开发。2002 年,魏永明先生创建北京飞漫软件技术有限公司,为 MiniGUI 提供商业技术支持,同时也继续提供开源版本,飞漫软件是中国地区为开源社区贡献代码最多的软件企业。最后一个采用 GPL 授权的 MiniGUI 版本是 1.6.10,从 MiniGUI 2.0.4 开始 MiniGUI 被重写并使用商业授权,从3.0.12开始,部分版本使用GPL授权。历经十余年时间, MiniGUI 已经成为性能优良、功能丰富的跨操作系统嵌入式图形用户界面支持系统,支持Linux/uClinux、eCos、 uC/OS-II、 VxWorks、ThreadX、Nucleus 、pSOS、OSE 等操作系统和数十种 SoC芯片,已验证的硬件平台包括 ARM-based SoCs、MIPS based SoCs、IA-based SoCs、PowerPC、M68K(DragonBall /ColdFire)、Intel x86 等等。

准备工作

交叉编译器

友善提供,具体安装参考mini6410的使用手册;

源码的下载

miniGUI官网上下载,需要有新浪账号或者twitter账号。下面是我下载的版本。

[root@localhost minigui]# ls -l *.tar.gz
-rwxrw-rw-. 1 root root 1427072 Jan 16 17:30 freetype-1_3_1.tar.gz
-rw-rw-r--. 1 root root   63582 Jan 16 17:31 gvfb-1_0_0.tar.gz
-rw-rw-r--. 1 root root  602762 Jan 16 17:32 qvfb2-2_0.tar.gz  
-rwxrw-rw-. 1 root root  557220 Feb 11 00:56 zlib-1.2.6.tar.gz
-rwxrw-rw-. 1 root root 1059513 Feb 11 00:55 libpng-1.5.8.tar.gz
-rwxrw-rw-. 1 root root  986681 Feb 10 23:42 jpegsrc.v8c.tar.gz
-rw-rw-r--. 1 root root  340656 Jan 16 17:33 libmg3d-1_0_2.tar.gz
-rw-rw-r--. 1 root root 1545209 Jan 16 17:34 libmgi-2_0_4.tar.gz
-rw-rw-r--. 1 root root 1116885 Jan 16 17:33 libmgp-1_2_2.tar.gz
-rw-rw-r--. 1 root root  648207 Jan 16 17:34 libmgplus-1_2_4.tar.gz
-rw-rw-r--. 1 root root  659702 Jan 16 17:33 libmgutils-1_0_4.tar.gz
-rw-rw-r--. 1 root root 3202804 Jan 17 00:29 libminigui-gpl-3_0_12.tar.gz
-rw-rw-r--. 1 root root 2608473 Jan 16 17:29 mg-samples-3_0_12.tar.gz
-rw-rw-r--. 1 root root 3449215 Jan 16 17:29 minigui-res-be-3_0_12.tar.gz

官网上有几个库的版本太低,所以需要自己去网上下载,其中jpegsrc.v8c.tar.gzlibpng-1.5.8.tar.gzzlib-1.2.6.tar.gz都是从网上找的最近版本(png和zlib这两个soucefoge上都有,前面一个是网上搜的,所以不能保证链接长期有效,但是网上搜一下还是比较容易找到的)。其实我也是在运行例子程序的时候才发现问题的,库更新后就可以正常运行了。

简单介绍一下使用到的几个库。

freetype:FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,包括TrueType, OpenType, Type1, CID, CFF, Windows FON/FNT, X11 PCF等。支持单色位图、反走样位图的渲染。FreeType库是高度模块化的程序库,虽然它是使用ANSI C开发,但是采用面向对象的思想,因此,FreeType的用户可以灵活地对它进行裁剪。

gvfb与qvfb2:这两个主要用于pc上仿真,在嵌入式平台上没用,就不做说明。

zlib:zlib是提供数据压缩用的函式库,由Jean-loup Gailly与Mark Adler所开发,初版0.9版在1995年5月1日发表。zlib使用DEFLATE算法,最初是为libpng函式库所写的,后来普遍为许多软件所使用。

libpng:这个是用来显示png图形的,MiniGUI里很多图都是png的,如果没有这个库,MiniGUI将无法正常工作。

jpeg:用于显示jpeg图像,否则程序不能正常运行。

minigui-res:minigui3.0工具栏所使用的资源集合,包括字体、图标、位图等。

libminigui:minigui3.0的核心库。

mg-samples:minigui3.0的例子程序,有一两个小游戏,可以玩玩~~

minigui可选组件:libmg3d(3D支持)、libmgi(提供输入接口)、libmgp(提供打印机接口的支持)、libmgplus(2D矢量图支持和图像加速)、libmgutils(提供一些常用对话框的模板),可以根据自己的需要使用,在跑例子程序的时候使用到了libmgplus,所以就临时编了它的lib。

交叉编译图像库

先将代码解压到你所放置代码的位置,然后再进行如下步骤来编译安装图像库。我的安装目录是:/usr/local/minigui,可以根据自己的习惯和喜好安装在其他目录,通过prefix参数来配置安装目录。

编译zlib库

编译与配置脚本:

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 AS=arm-linux-as \
                 AR=arm-linux-ar \
                 ./configure --prefix=/usr/local/minigui \
                   --shared
#配置完成后
[root@localhost] make
[root@localhost] make install

 编译png库

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 AS=arm-linux-as \
                 AR=arm-linux-ar \
                ./configure --prefix=/usr/local/minigui \
                    --build=i386-linux \
                    --host=arm-linux \
                    --target=arm-linux
[root@localhost] make
[root@localhost] make install

编译Jpeg库

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 AS=arm-linux-as \
                 AR=arm-linux-ar \
                 ./configure --prefix=/usr/local/minigui \
                   --build=i386-linux \
                   --host=arm-linux \
                   --target=arm-linux \
                   --enable-shared
[root@localhost] make
[root@localhost] make install

 编译freetype库

自动配置还有问题,也没有尝试高版本的freetype能不能使用,暂时就先这样,好像例子代码里面并没有使用它。后面再尝试高版本的freetype。

[root@localhost] cd freetype-1.3.1/
[root@localhost] ./configure --host=arm-linux --enable-static --prefix=/usr/local/minigui
[root@localhost] vim config.cache
# 修改如下行
ac_cv_path_LD=${ac_cv_path_LD=arm-linux-gnu-ld}
ac_cv_prog_CC=${ac_cv_prog_CC=arm-linux-gnu-gcc}
ac_cv_prog_CPP=${ac_cv_prog_CPP='arm-linux-gnu-gcc -E'}
#重新配置
[root@localhost] ./configure --host=arm-linux --enable-static --prefix=/usr/local/minigui
# 修改Makefile文件,以跳过编译test目录。
# 去掉“all:”后的变量“tttest”
# 注释掉“install:”下的第二行:“cd $(FTTESTDIR); $(MAKE) –f$(MAKEFILE) install”
[root@localhost] make
[root@localhost] make install

安装minigui资源库

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 AS=arm-linux-as \
                 AR=arm-linux-ar \
                  ./configure --prefix=/usr/local/minigui
[root@localhost] make
[root@localhost] make install

编译minigui核心库

配置脚本:

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 CFLAGS="-I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                 CPPFLAGS="-g -I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                 CXXFLAGS="-g -I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                   ./configure --prefix=/usr/local/minigui \
                   --host=arm-linux \
                   --target=arm-linux \
                   --build=i386-linux \
                   --with-osname=linux \
                   --with-style=classic \
                   --with-targetname=fbcon \
                   --enable-autoial \
                   --enable-rbf16 \
                   --disable-vbfsupport
[root@localhost] make
[root@localhost] make install

遇到错误:pcxvfb.c:490:13: error: impossible constraint in ‘asm’,因为使用了错误的头文件,解决方法如下:

 mv select.h select.h.bak
 cp /opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include/bits/select.h ./
 rm select.h
 mv select.h.bak select.h

编译minigui例子程序

例子程序也不是一帆风顺的,从配置到最后编译都会有问题。具体配置脚本如下:

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 CFLAGS="-I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                 CPPFLAGS="-g -I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                 CXXFLAGS="-g -I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                 ./configure --prefix=/usr/local/minigui \
                    --build=i386-linux \
                    --host=arm-linux \
                    --target=arm-linux

在配置阶段或遇到环境变量的问题,但是在配置了环境变量后还是出现错误,就直接在configure文件中添加了变量,这样才通过配置。修改如下:

vim configure
# 在 $as_echo_n "checking for MINIGUI... " >&6; }后添加如下变量:
MINIGUI_CFLAGS = /usr/local/minigui/include
MINIGUI_LIBS = /usr/local/minigui/lib

然后开始make,又出现如下错误:no such file: File format not recognized collect2: ld returned 1 exit status。经过网上查资料后发现是生成的Makefile有问题,需要逐个修改Makefile。修改每个Makefile钟的如下行:

 LIBS = -lminigui_ths -ljpeg -lm -lpthread -ldl
 LDFLAGS = -L/usr/local/minigui/lib

这样就可以通过编译并生成可执行文件了。

部署图像库

其实这个工作很简单,主要有两个步骤,一个修改minigui的配置文件,另一个是拷贝库文件到文件系统就可以了。配置文件在minigui的wiki上也有较详细的介绍,可以参考:《MiniGUI V3.0 的运行

修改配置文件:

$ vim /usr/local/minigui/etc/MiniGUI.cfg
# 修改如下参数
# GAL engine and default options
gal_engine=fbcon

# IAL engine
ial_engine=console
mdev=/dev/input/mice
mtype=IMPS2

# 根据实际的显示大小填
[fbcon]
defaultmode=480x272-16bpp

拷贝库到文件系统:

$ cp /usr/local/minigui/* /myrootfs/usr/local

拷贝你的例子程序就可以在开发板上运行了~~

参考文档和链接

  1. minigui的wiki
  2. MiniGUI-1.6.10 MiniGUI-1.6.10在mini2440上的移植(网络文档)
  3. miniGUI官网

6 条评论

支持6410从SD卡启动的Uboot

一 16 2012 由 创建在标签 开发

友善提供的Superboot确实很好用,但是samsung提供的uboot版本比较低,从友善的官网也看到对应的uboot介绍,了解到它启动的时候并不能很好地支持SD卡,尤其是SDHC的支持很不好,那个是因为uboot版本太低,而且SD卡也不能超过2G。最让人头疼的是不能从SD卡直接启动系统,只能将img拷贝到NAND,然后再从NAND中启动(参考友善官网6410的bootloader介绍)。对于想定制自己的Bootloader人就会遇到想不到的麻烦,所以就想着找一个能够很好支持SD卡启动Linux的Uboot。

SD/MMC的启动原理

要想知道启动的原理,就必须先了解芯片的特性和它的启动过程,需要查看厂商提供的Datasheet和芯片相关的资料。对于6410,samsung提供了一份启动相关的文档——《SMDK6410_IROM_APPLICATION NOTE_REV 1.00》,想了解的人可以自己在网上搜一下,我只简单说一下我看了之后对我比较有用的东西,肯定会有信息遗漏。

6410最开始启动的时候先执行固化在芯片里面的代码,iRom(BL0)它所做的事情很简单,主要完成系统时钟、堆栈、设备控制器和启动设备标识的初始化,确定下一阶段(BL1)的启动设备和起始地址,拷贝BL1到启动区域,然后将执行权交给启动区域,开始BL1的执行。其中iRom初始化了很多函数指针和全局变量,这些都为BL1阶段的执行和代码的拷贝做好准备;6410通过从引脚来判断是从Nand还是从SD卡拷贝数据的,在6410中就有一个开关来选择是从NAND还是从SD卡启动的。BL1就已经是Bootloader的代码了,但是BL1的大小是有8k的限制,不能完成所有的Bootloader的工作,还需要BL2的配合才能真正完成所有的引导过程。

Uboot的移植

其实写到这里就已经没有多少我的东西了,因为自己并没有真正去移植,所以后面说的有点人云亦云,我只是从网上下了一份tekkamanninja移植好的代码(亲自测试,可以运行,运行时有启动背景),自己做了一些比较,说说他的这份代码是如何移植的,而且作者的博客上也有很多关于Uboot移植的代码和一些关于这方面原理的分析。如果有机会自己移植的话再写一些关于Uboot移植的东西。

/u-boot-2011.06mini6410/arch/arm/include/asm/arch-s3c64xx
# ls -l
total 80
-rw-rw-r--. 1 root root 1995 Sep  7 07:30 hardware.h
-rw-rw-r--. 1 root root 2066 Sep  7 07:30 mmc.h
-rw-rw-r--. 1 root root 13667 Sep  7 07:30 regs-fb.h
-rw-rw-r--. 1 root root 5470 Sep  7 07:30 regs-fb-v4.h
-rw-rw-r--. 1 root root 36503 Sep  7 07:30 s3c6400.h
-rw-rw-r--. 1 root root 9205 Sep  7 07:30 s3c64x0.h

上面列出了初始化时需要调用的一些公共函数、结构体、宏等相关的声明,主要增加了SD卡和mini6410的LCD支持,完成他们的初始化,使得开机时能够显示Logo、背景以及SD卡启动系统。

/u-boot-2011.06mini6410/arch/arm/cpu/arm1176
# ls -l
total 56
-rw-rw-r--. 1 root root 1319 Sep  7 07:30 config.mk
-rw-rw-r--. 1 root root 1717 Sep  7 07:30 cpu.c
-rw-rw-r--. 1 root root 1496 Sep  7 07:30 Makefile
drwxrwxr-x. 2 root root 4096 Jan 14 00:26 s3c64xx
-rw-rw-r--. 1 root root 15078 Sep  7 07:30 start.S
-rw-rw-r--. 1 root root 1712 Sep  7 07:30 u-boot.lds
# cd s3c64xx/
# ls -l
total 76
-rw-rw-r--. 1 root root 1319 Sep  7 07:30 config.mk
-rw-rw-r--. 1 root root 5424 Sep  7 07:30 cpu_init.S
-rw-rw-r--. 1 root root 1459 Sep  7 07:30 Makefile
-rw-rw-r--. 1 root root 1109 Sep  7 07:30 reset.S
-rw-rw-r--. 1 root root 3441 Sep  7 07:30 speed.c
-rw-rw-r--. 1 root root 4363 Sep  7 07:30 timer.c

上面列出了与芯片有关的初始化代码,作者修改了cpu_init.S和start.S,其中cpu_init.S主要是自动检测内存大小的代码(参考Mini6410自动识别内存大小);star.S主要是增加启动时自动检测内存、确定是从SD卡还是从NAND启动以及LED功能。

/u-boot-2011.06mini6410/arch/arm/lib
# ls -l
-rw-rw-r--. 1 root root 17540 Sep  7 07:30 board.c

上面列出了lib中修改了的文件,它的修改主要是为了添加LED功能。

/u-boot-2011.06mini6410/drivers/mmc
# ls -l
-rw-rw-r--. 1 root root 24139 Sep  7 07:30 mmc.c
-rw-rw-r--. 1 root root 11091 Sep  7 07:30 s3c64x0_mmc.c

上面新增了s3c64x0_mmc.c文件,它主要完成6410 SD卡的初始化;mmc.c主要添加了一些打印信息。

/u-boot-2011.06mini6410/drivers/video
# ls -l
total 552
-rw-rw-r--. 1 root     root     49102 Sep  7 07:30 cfb_console.c
-rw-rw-r--. 1 root     root      9151 Jan 14 00:14 s3c64x0_fb.c
-rw-rw-r--. 1 root     root      8945 Sep  7 07:30 videomodes.c
-rw-rw-r--. 1 root     root      3480 Sep  7 07:30 videomodes.h

上面主要增加了对LCD的支持,支持开机时使用友善的上自带的LCD,可以显示开机Logo和背景。

/u-boot-2011.06mini6410/mmc_spl/board/samsung/mini6410
# ls -l
lrwxrwxrwx. 1 root     root       86 Jan  5 22:58 cpu_init.S
lrwxrwxrwx. 1 root     root       85 Jan  5 22:58 lowlevel_init.S
-rw-rw-r--. 1 root     root     2417 Sep  7 07:30 mmc_boot.c
lrwxrwxrwx. 1 root     root       75 Jan  5 22:58 start.S
-rw-rw-r--. 1 root     root     1725 Sep  7 07:30 u-boot.lds

上面这个目录为新增目录,它们就是针对mini6410启动初始化的过程,其实cpu_init.S等汇编代码其实只是上面体系结构目录下的符号链接,它们将烧写在BL1中,作为iRom执行后第一个执行的部分,主要就是完成初始化,并调用mmc_boot.c中的初始化函数,其中copy_uboot_to_ram函数从BL2中拷贝代码到内存,并跳转到对应的区域执行,从而进入BL2的代码段执行。

其他修改过的文件都只是一些配置相关的,因为作者增加了很多新的功能,所以在编译的时候还需要让其他部分也编译进去。

烧写Uboot

在Linux中可以通过命令和网友Amankwah提供的工具(下载地址)。但是在使用的时候要获得root权限,我在Fedora下面也是可以正常工作的。但是在使用的时候注意将BL1的目录选择mmc_spl目录下,否则默认的是NAND那个目录下。烧写的命令如下:

$ sudo fdisk /dev/sdb

Command (m for help): p
Disk /dev/sdb: 7969 MB, 7969177600 bytes
246 heads, 62 sectors/track, 1020 cylinders
Units = cylinders of 15252 * 512 = 7809024 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1   *           1           6       45755+   b  W95 FAT32
/dev/sdb2   *           7        1020     7732764   83  Linux

##################################################################
# 所以总块数是7969177600/512=15564800
# IROM所认为的总块数15563776(15564800-1024)(仅在SDHC时需要减去1024)
# 所以nand_spl/u-boot-spl-16k.bin烧写的位置是15563758块(15563776-18)
# u-boot.bin烧写的位置是15557632块(15563776-6144(3MB))(根据我的Uboot配置文件)
###################################################################
# 烧写命令:
sudo dd if='(Uboot源码)/nand_spl/u-boot-spl-16k.bin'     of=/dev/(SD卡的设备节点) bs=512   seek=15563758
sudo dd if='/(Uboot源码)/u-boot.bin'      of=/dev/(SD卡的设备节点) bs=512   seek=15557632

其实觉得友善的Superboot和这个应该差不多,友善的烧写工具应该也是将他们分成两步来做的,因为我用这个版本的Uboot编译后用友善的烧写工具烧写发现打开的文件格式错误,再加上看了6410的启动过程,所以感觉友善的编译出来的Uboot和Superboot应该是将两个打包成一个了,然后在烧写时再做区分,分别写到对应的区域中去。

现在我已经用网友提供的 Uboot引导成功,能够正常进入了,也设置了开机画面和背景。其实这篇文章主要是参考的别人的博客,自己只是把别人的博客和代码拿过来整理了一下,希望能够对6410学习的人和想移植Uboot的人有所帮助。

参考网站

Tekkaman Ninja的博客

一条评论

下一页 »