EMSYM 昂信科技

苏州市嵌入式系统重点实验室

修改根文件系统/etc/profile

export QWS_DISPLAY=Transformed:mmWidth85:mmHeight:40:0

修改width与height

IMX233在批量生产阶段换了nandflash K9G2G08U0M,该款片子手册相当匮乏,没找到,只能初步了解其相关信息,是MLC工艺的,256M,其他的就无从了解,于是通过各种调试加仿写

在driver/mtd/nand/nand_device_info的结构体

image

中加入下述描述符

image

之所以加入这个描述符的原因在于,其在通过

image

查找nand chip时,找不到该片子信息,而该片子的配置信息对于后续的操作是至关重要的。所以加入修正,编译通过

一、获取Android源代码 

(以下安装文件如果不存在,建议更换/etc/source.list中的源)

 sudo apt-get install git-core curl

这条命令会从互联网的软件仓库中安装git-core和curl。

其中curl是一个利用URL语法在命令行方式下工作的文件传输工具,它支持很多协议,包括FTP、FTPS、HTTP、HTTPS、TELENT等,我们需要安装它从网络上获取Repo脚本文件。

curl http://android.git.kernel.org/repo >~/bin/repo

这句命令会下载repo脚本文件到当前主目录的/bin目录下,并保存在文件repo中。

最后我们需要给repo文件可执行权限

chmod a+x ~/bin/repo

  继续阅读

在调试SD卡的时候,发现一插入SD卡便导致板子重启,经过检测,返现VDDIO会有一个browout,因为一插入SD卡,VDDIO负载变大,导致出现电压变化,但是为什么重启了呢?

在imx233的启动文件中,有电源初始化,在power_prep.c中,_start函数中经过跟踪发现PowerPrep_EnableOutputRailProtection此函数导致重启,进入分析源码,对照芯片手册,发现针对HW_POWER_CTRL寄存器,开启了三路电源vddio vdda vddd的browout的中断,但是在源码后续分析中也发现,对于VDDIO的browout的侦测有时候是存在虚假的,可以禁止掉此中断,在函数PowerPrep_EnableOutputRailProtection中,

/* note that VDDIO brownout indicator has been found to falsely
* trigger due to a 5V connection.  Possibly also due to a pswitch
* press.
*/
#ifndef    DISABLE_VDDIO_BO_PROTECTION
HW_POWER_VDDIOCTRL.B.PWDN_BRNOUT = 1;
#endif

所以定义 #define DISABLE_VDDIO_BO_PROTECTION
即可,重启一切正常~~~~~~~~~~~

上述阶段只是针对,未启动内核之前,在启动内核之后,还要对电源重新进行一次初始化。通过对于源码的剖析,将主要流程在此叙述下,

针对采用IMX233config的内核来说,在drivers/power/mxs/linux.c中,有一个函数init_protection,此函数是为了完成一定的保护工作而作的电源硬件配置,在其中,有函数ddi_power_InitOutputBrownouts,便是完成的三路电源browout的中断配置,进入

void ddi_power_InitOutputBrownouts(void)
{
uint32_t temp;

__raw_writel(BM_POWER_CTRL_VDDD_BO_IRQ |
BM_POWER_CTRL_VDDA_BO_IRQ |
BM_POWER_CTRL_VDDIO_BO_IRQ,
REGS_POWER_BASE + HW_POWER_CTRL_CLR);

__raw_writel(BM_POWER_CTRL_ENIRQ_VDDD_BO |
BM_POWER_CTRL_ENIRQ_VDDA_BO |
BM_POWER_CTRL_ENIRQ_VDDIO_BO,
REGS_POWER_BASE + HW_POWER_CTRL_SET);

temp = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDDCTRL);
temp &= ~BM_POWER_VDDDCTRL_PWDN_BRNOUT;
__raw_writel(temp, REGS_POWER_BASE + HW_POWER_VDDDCTRL);

temp = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDACTRL);
temp &= ~BM_POWER_VDDACTRL_PWDN_BRNOUT;
__raw_writel(temp, REGS_POWER_BASE + HW_POWER_VDDACTRL);

temp = __raw_readl(REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
temp &= ~BM_POWER_VDDIOCTRL_PWDN_BRNOUT;
__raw_writel(temp, REGS_POWER_BASE + HW_POWER_VDDIOCTRL);
}

可以看到temp &= ~BM_POWER_VDDIOCTRL_PWDN_BRNOUT;

这便是开启相应电源路的browout中断,注释掉就可以了,重新编译启动即可,针对stm37XXX的配置,其思路是一样的只是文件位置不同而已

在C语言中,static的作用有三个:

1.限定作用范围

2.限定存储区域

3.限定默认值

实例1.

当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。为理解这句话,我举例来说明。我们要同时编译两个源文件,一个是a.c,另一个是main.c。

下面是a.c的内容

#include <stdio.h>

int a =99; //global variable
void hello()
{
printf(“Hello”);
}

下面是main.c的内容

#include <stdio.h>

int main(void)
{
extern int a;    //extern variable must be declared before use
printf(“%d “, a);
hello();
return 0;
}

程序的运行结果是:

99 Hello

这里的main函数之所以能够访问a.c文件中定义的a变量和hello函数,是因为他们默认的访问范围是全局的,如果在a变量和hello函数之前加上static作为修饰,则在main.c中不能对a和hello进行访问。

以上实例说明,static可以对变量和函数进行修饰,用来控制其作用范围。

实例2.

static还能影响存储区域。因为函数的存储区域不会有什么变化,所以我们只讨论static对变量存储区域的影响。

static修饰的变量存放在静态存储区中,在程序初始化的时对其进行第一次赋值(有且仅有这一次初始化),以下的实例说明,static可以影响变量的存储区域。

#include <stdio.h>

int fun(void){
static int count = 10;    // 事实上此赋值语句从来没有执行过
return count–;
}

int count = 1;

int main(void)
{
printf(“global\t\tlocal static\n”);
for(; count <= 10; ++count)
printf(“%d\t\t%d\n”, count, fun());

return 0;
}

程序的运行结果是:

global          local static

1               10

2               9

3               8

4               7

5               6

6               5

7               4

8               3

9               2

10              1

实例3.

静态变量的默认值为0,请自己动手做实验吧。

1. 移动光标
ctrl+f 向前移动一个字符
ctrl+b 向后移动一个字符
alt+f 向前移动一个单词
alt+b 向后移动一个单词
ctrl+a 移动到当前行首
ctrl+e 移动到当前行尾
ctrl+l 清屏,并在屏幕最上面开始一个新行
2. 编辑命令行
ctrl+d 删除当前的字符
ctrl+t 交换当前字符和前一个字符的位置
alt+t 交换当前单词和前一个单词的位置
alt+u 把当前单词变成大写
alt+l 把当前单词变成小写
alt+c 把当前单词变成首字母大写的单词
ctrl+v 添加一个特殊字符,例如,要添加一个制表符,按ctrl+v+tab
3. 剪切、粘贴快捷键
ctrl+k 剪切文本直到行的末尾
ctrl+u 剪切文本直到行的起始
ctrl+w 剪切光标前的单词
alt+d 剪切光标后的单词
ctrl+y 粘贴最近剪切的文本 //这个命令尝试使用无效?
alt+y 回退到先前剪切的文本并粘贴它
ctrl+c 删除整行

相关平台:

VMWARE WORKSTATION 7.1.3

UBUNTU 10.10

编译环境:

arm-none-linux-gnueabi (version 4.3.3)

移植编译步骤:

下载qt-extended-opensource-src-4.4.3.tar.gz

例如在/home文件夹下解压生成qt-extended-4.4.3文件夹,在/home目录下手动建立build目录

#cd build

#./run.sh(执行配置脚本)

#./bin/qbuild

#./bin/qbuild image

编译,安装结束

脚本:

../qt-extended-4.4.3/configure -verbose -release -image /opt/qtopia4 -prefix /opt/qtopia4 -no-pkg-config -no-dbus -xplatform linux-arm-g++ -arch arm -displaysizes 480×272 -build-qt -qtopia-sqlite -v4l2 -remove-module modem -remove-module bluetooth -remove-module drm -remove-module infrared -extra-qt-embedded-config “-xplatform qws/linux-arm-g++ -embedded arm -qconfig qpe -shared -little-endian -webkit -qt-kbd-usb -qt-libpng -qt-libjpeg -qt-gif -depths 4,8,16,24,32 -qt-mouse-tslib -I/usr/local/tslib/include -L/usr/local/tslib/lib” 2>../error.txt
执行脚本文件是为了配置相关模块,功能,库,以及生成的文件镜像的位置
最后把生成的镜像拷贝到文件系统当中,并且做相关配置:(VI  /etc/profile)
export T_ROOT=/usr/local
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_TSDEVICE=/dev/event1
export TSLIB_PLUGINDIR=$T_ROOT/lib/ts
export TSLIB_CONFFILE=$T_ROOT/etc/ts.conf
export TSLIB_CALIBFILE=/etc/pointercal
export QWS_MOUSE_PROTO=Tslib:/dev/event1
export QTDIR=/opt/qtopia4
export QPEDIR=/opt/qtopia4
export PATH=$QTDIR/bin:$PATH
export QT_PLUGIN_PATH=$QTDIR/plugins:$QTDIR/qt_plugins/
export QT_QWS_FONTDIR=$QPEDIR/lib/fonts/
export LD_LIBRARY_PATH=$QTDIR/plugins/qtopialmigrate/:$QTDIR/qt_plugins/imageformats/:$QTDIR/lib:/usr/local/lib:$LD_LIBRARY_PATH
关于tslib的移植请看另一篇blog——QT在imx23evk上的移植

基本步骤:

1、编译安装tslib以及QT

2、复制相关内容到文件系统目录下

详细说明:

1、下载tslib-1.4.tar.bz2、qt-everywhere-opensource-src-4.6.0,解压;

2、安装tslib:运行autogen.sh脚本,生成configure,执行./configure  –prefix=/usr/local/tslib –host=arm-none-linux-gnueabi- ac_cv_func_malloc_0_nonnull=yes(配置安装路径,编译器版本。。。),之后就make,make install

3、安装QT:编写一个脚本

./configure -prefix /usr/local/qt-4.6.0 -opensource -confirm-license -release -shared -embedded arm -xplatform qws/linux-arm-g++ -depths 16,18,24,32 -fast -optimized-qmake -pch -qt-sql-sqlite -qt-libjpeg -qt-zlib -qt-libpng -qt-freetype -little-endian -host-little-endian -no-qt3support -no-libtiff -no-libmng -no-opengl -no-mmx -no-sse -no-sse2 -no-3dnow -no-openssl -no-webkit -no-qvfb -no-phonon -no-nis -no-opengl -no-cups -no-glib -no-xcursor -no-xfixes -no-xrandr -no-xrender -no-separate-debug-info -nomake examples -nomake tools -nomake docs -qt-mouse-tslib -I/usr/local/tslib/include -L/usr/local/tslib/lib

以上配置项有些应根据需要选择,如要编写webkit的程序,则应将no-webkit去掉

在执行脚本之前,先修改mkspecs/qws/linux-arm-g++/qmake.conf ,将arm-linux-全部改为amr-none-linux-gnueabi-,当然这个修改是根据交叉编译器决定的,如果使用的是linux-arm就不需要修改

实行以上脚本,生成makefile,然后就make,make install

在make过程中如果遇到ts_open,ts_raw….未找到的问题,就修改mkspecs/qws/linux-arm-g++/qmake.conf,在QMAKE_CC = XXX 后加-lts,同样以下三行也要加

4、拷贝tslib,QT:

将安装后的tslib所有文件复制到根文件系统的/usr/local/下,将生成的QT下的lib全部复制到根文件系统的/usr/local/qt-4.6.0/(没有就自己创建)

vim usr/local/etc/ts.conf,将module_raw input前面的#号去掉即取消注释

vim etc/profile

在文件中添加如下内容:

export QTDIR=/usr/local/qt-4.6.0
export T_ROOT=/usr/local
export PATH=$QTDIR/bin:$PATH
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_TSDEVICE=/dev/event1
export TSLIB_PLUGINDIR=$T_ROOT/lib/ts
export TSLIB_CONFFILE=$T_ROOT/etc/ts.conf
export TSLIB_CALIBFILE=/etc/pointercal
export QWS_MOUSE_PROTO=Tslib:/dev/event1
export LD_LIBRARY_PATH=$T_ROOT/lib:$QTDIR/lib

vim etc/init.d/rcS

添加以下内容

source /etc/profile

echo “                           ” > /dev/tty1

echo “Starting touch calibrate ” > /dev/tty1

echo “                           ” > /dev/tty1

sleep 1

/usr/local/bin/ts_calibrate &  #开机启动触摸屏校准程序

大家在用stm378X默认配置的时候会出现报错,如何解决内,怎么去定位问题呢?

错误如下:

1. 首先是错误error “this machine class needs to define __arch_page_to_dma to use HIGHMEM”

然后是page_to_dma函数找不到,这个错误其实是一个错误,那就是宏__pfn_to_bus没有定义,

我们通过分析可以知道,这个宏的定义是在arch/arm/include/asm/memory.h中,

#ifndef __virt_to_bus//如果没有定义才会定义__pfn_to_bus,但是这个却定义了

#define __virt_to_bus    __virt_to_phys

#define __bus_to_virt    __phys_to_virt

#define __pfn_to_bus(x)    ((x) << PAGE_SHIFT)

#endif

查看其包含的头文件可知为mach/memory.h,即

arch/arm/plat-stmp3xxx/include/mach/memory.h中,发现已经定义了两项

#define __virt_to_bus(x)     __virt_to_phys(x)

#define __bus_to_virt(x)     __phys_to_virt(x)

与上面的冲突,所以注释掉之后(用/**/注释 不要用//注释),可以正常编译

2. 提示undefined reference to `__gnu_mcount_nc’这个是由于编译器版本不适合导致的,所以为了解决这个问题,有两种方法,一种是让内核适应编译器,另一种是下载另外的编译器,这里提供第一种的解决方案,给出补丁文件__gnu_mcount_nc_patch

3. 会出现stmp3xxx_register_regulator undefined reference,这个问题的根源,通过查看发现其实现是在drivers/regulator/stmp3xxx.c中的,所以可以初步判定是由于没有编译这个文件导致,可以查看是否生成了文件,我是直接在menuconfig中对于device drivers中的Voltage and Current Regulator Support下的STMP3XXX Regulator Support选中,然后重新编译解决。

4. 出现cpufreq_update_policy cpufre_trig_needed undefined reference解决方法类似,主要是支持CPU dvfs的选项没选上,在cpu power management 中选择 CPU Frequency scaling的支持,重新编译

总结:由于这个默认stm378的配置已经不太符合要求了,很多都没有选中,所以不建议再采用默认的,而是选择下面提供的config文件

具体的可以从文档管理系统中提取

使用的nand flash为64M ,共4096个块,一块=32页,一页=512Byte

在nand flash的使用过程中会产生坏块,当编程/擦除这个块时,不能将某些位拉高,这会造成Page Program和Block Erase操作时的错误,相应地反映到状态寄存器的相应位。由于单片机内存资源有限,针对当前的应用故写了一个简单的坏块管理

坏块判断原理:

在nand flash擦除和编程时都有可能产生坏块,所以在擦除和编程后读状态的flash。状态的最后一位(I/O0)为0说明操作成功,为1说明操作失败。

坏块表类型:

由于使用的flash为64M共有4096个块。因此数据类型使用  int  Bad_Block_Table[]来保存坏块地址。

好块的查找原理:

根据坏块表查找下一个能用的好块(例如第5块是坏快,将会判断第6块是否在坏块表中,如果是好块则返回好块地址,如果是坏块则继续向后查找)

坏块表建立流程:

  1. 如果不拷贝数据则从特定的一块地址中加载坏块表。
  2. 如果拷贝数据,往flash拷贝数据前先对flash擦除,在擦除过程中并不建立坏块表,是由于擦除过程中建立的坏块表,在写入数据时不一定能够写到,反而会在对地址映射时增加程序的开销
  3. 往flash中拷贝数据,写入一页数据后判断操作是否成功,如果成功继续写,不成功则将块地址保存在坏块表中,并查找下一个好块,将之前写入坏块的数据都拷贝到新的好块中。
  4. 拷贝完成后将坏块表保存到特定的一块地址中

在每次读数据前先调用地址映射函数,根据坏块表返回一个映射后的地址

地址重映射原理:

ulong Flash_Addr_Remap(ulong addr)

参数为:要查询的地址

返回值为:重映射后的地址

lwip作为一个开源的网络协议,它的实现主要就是实现几个底层函数:

(1)low_level_init:这个函数主要包括了硬件的初始化

(2)low_level_output:这个函数实现了以太网数据包最底层的发送

(3)low_level_input:实现了以太网数据包的接收

在编写这几个函数的注意点:

(1)low_level_init:一开始是网卡虚拟设备的说设置,要把实际硬件的初始化放到最后

(2)low_level_output:每次发送的时候是发送一个包,所以需要一个循环来写发送缓冲区,最后把“总长度”写入寄存器

(3)low_level_input:判断数据包的有效性,无效的数据包一定要丢弃,不然会造成pbuf的溢出

实现完成lwip之后,如果通过了测试,就可以开始往操作系统上移植,操作系统之上的移植主要包括几个函数的编写:

(1)邮箱(消息队列实现):

sys_mbox_new:邮箱建立

sys_mbox_free:删除邮箱

sys_mbox_post:邮箱消息的发送

sys_arch_mbox_fetch:邮箱消息的接收

(2)信号量:

sys_sem_new:建立信号量

sys_sem_signal:发送信号量

sys_arch_sem_wait:等待信号量

sys_sem_free:释放信号量

(3)其余:

sys_thread_new:由于ucosII没有线程的概念,所以用该函数通过封装之后,实现了任务的建立

sys_arch_timeouts:获取当前线程使用的sys_timeouts结构的指针(1、每一个线程都有一个timeouts链表; 2、要返回的sys_timeouts结构保存了timeouts链表的首地址;)

sys_init:初始化timeouts链表

这些代码现在网上基本上都有,可以直接拿过来使用,但是还是需要更具实际操作系统的情况来进行修改的

最后,也是最重要的:网络数据的接收不能放在中断里面去做(笔者在这个上面徘徊了整整一个月),单独建立一个任务来做数据接收,而且优先级要小于协议处理任务的优先级

在中断里面,主要就是做一些清楚标志位的操作,还有就是发送信号量给数据接收的线程,整个过程差不多就这样,但笔者做了大概有4个月,其中很多“注意点”都已近写出来了,这些注意点相当重要,是耗时良久的主要原因

文章主要实现对MX23的供电方式的种类,和不同电源之间的协调方法。

确定核心板的供电方案。

从芯片手册上看,主要的供电方式是VDD5V和锂电池供电。

VDD5V的获取可以从外部墙插供电,也可以通过USB供电。同时通过墙插和USB可以给锂电池充电。

但是USB作为主设备的时候需要能给外部提供5V的电压,手册中说能用PWM实现,这个待后面讨论。

作为核心板当然是越简单越好,再考虑调试方法,因此考虑主要通过USB供电,同时板子上留出外部的5V供电和锂电池供接口,使用插针实现,以节省面积。这样如果必要也可以调试电源管理功能。

核心板上出现不同电源时就需要考虑电源之间的切换。

先看下Mx23内部的PMU(Power Management Unit)单元结构图:

pmu.jpg 继续阅读

问:根域名的A记录(即 @.yourdomain.com ,windows称之为“与父文件夹相同”)设置不生效。nslookup 总是返回DNS服务器的IP。

答:原因是,DNS服务器默认把它自己的IP地址设置为根域名的A记录,等同于 @.yourdomain.com (windows称之为“与父文件夹相同”)。而且即使删除掉默认的、加上自己设置的A记录,过一段时间默认值仍然会被自动注册。

修改注册表,禁止自动注册。

在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters 新建一个键值。

键: DnsAvoidRegisterRecords
值: LdapIpAddress
数据类型: REG_MULTI_SZ


经过在网络上查找相关资料,看到,将下面代码保存为*.reg文件,然后导入到注册表,就可以发现在鼠标右击时就会出现选项 delete svn foleders,这样可以将该目录下以及子目录下所有.svn删除。

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\DeleteSVN]
@=”Delete SVN Folders”
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\DeleteSVN\command]
@=”cmd.exe /c \”TITLE Removing SVN Folders in %1 && COLOR 9A && FOR /r \”%1\” %%f IN (.svn) DO RD /s /q \”%%f\” \”"

在移动目录时,如果只是简单的在客户端copy,步骤繁琐,需要delete再add再commit,所以方法是通过右击要移动的目录拖动到目的目录下即可,简单,方便。

问:大的SVN项目会导致Redmine假死

答:默认情况下,访问Redmine的版本库时,Redmine会刷新SVN,如果版本库太大会导致执行时间过长。

解决方法,关闭Redmine的刷新机制:管理员登录,Administration –> Repository –> Autofetch commits去掉勾选

在后台刷新,执行如下命令

ruby /path_to_redmine/redmine/script/runner "Repository.fetch_changesets" -e production > /dev/null 2>&1

可以加入cron以便定时刷新

问:编新内核经常导致机器没法启动

答:grub指向新内核,但只有一次生效

echo "savedefault --default=1 --once" | grub --batch
reboot

比如新内核是grub菜单的第1项,以上的命令重启后,从新内核启动。如果重启不能起来,强行reset后,grub恢复从菜单指定的默认内核启动。

这个技巧对于headless机器十分有效。


问:把系统日志发送到真实的email信箱

答:新建 /root/.forward 文件,写上想要转发的邮箱地址。注:sendmail 或 postfix 等 SMTP 服务需配置正确。

每创建一个.C文件(例如:xxxx.c),必须相应的建立一个对应的.h文件(创建xxxx.h,当然由.C文件包含,#include(xxxx.h))。将.C文件中的全局变量或者宏在相应的.h文件中定义,这样的修改时为了更好的增加文件的可移植性和区别不同人的代码风格(当然也可以查看出每一个人的工作情况)并且能够在下一次PCB改版后能够直接在.H 文件中修改相应的引脚,免去了一个个在.C文件中查找并修改所浪费的时间。在.C文件中,每一个小功能函数(xxx_function()或者xxx_Configuration
)都要有使用说明,参数,返回值等等,类似如下:

/*******************************************************************************
* Function Name  : GPIO_Configuration
* Description    : Configures the different GPIO ports.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/

这样的好处能够让人一目了然,增加代码的可读性、增加使用性。

最后可以在增加一个主的函数功能假定为xxx_main(),该函数将每一个小的功能模块函数一次次调用,完成QA中分配好的项目功能,并且在整合时其他同事直接使用该函数。如下所示:

 void codec_main(unsight char vol_number)
{
    codec_init_function();        //codec芯片初始化

    codec_vol_function(vol_number);        //音量调节
}

如果平台结构会有变动,或者需要再次扩展或者外设模式的更改的时候(换句话说就是与平台有关或者芯片有关并且有可能经常变化的部分)合理的使用宏定义,例如:#if、#ifndef、#endif等等。如下所示:

#ifdef  VECT_TAB_RAM
  /* Set the Vector Table base location at 0×10000000 */
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0×0);
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0×08000000 */
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0×0);
#endif

开发人员(假设开发人员为A)完成了一个整体功能的开发后提供主函数的功能接口给其余使用该功能的程序员(假设该程序员为C),例如上面的xxx_main()。使用者只需要使用xxx_main()并传递相应的参数就可以了。

如果开发员A对这一功能做出了新的修改(比如芯片的更改、功能的改进、BUG修复),程序员C只需要将开发员B 提供的.C或者.H文件覆盖就可以了。

有理解错误的地方请大家纠正

 祝大家新年快乐

在freescale的31内核版本中,对于fec.c是存在bug的,其主要的bug在于设置MAC
时,如果不事先调用开启clock的操作,就会出现死机,其根本在于probe之后,驱动将
clock时钟关闭了,所以解决方案为在probe中将第一个clk_disable
函数注释掉,或者说在fec_set_mac_address中加入函数clk_enable;其次的bug就是在fep->
hwp + FEC_ADDR_HIGH中,原来的代码是fep + FEC_ADDR_HIGH应该改为fep->hwp +
FEC_ADDR_HIGH。
static int
fec_set_mac_address(struct net_device *dev, void *p)
{
    struct fec_enet_private *fep = netdev_priv(dev);
    struct sockaddr *addr = p;

    if (!is_valid_ether_addr(addr->sa_data))
        return -EADDRNOTAVAIL;

    memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);

    writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
        (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),
        fep->hwp + FEC_ADDR_LOW);
    writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24),
        fep->hwp + FEC_ADDR_HIGH);
    return 0;
}

由于XML在数据存储方面的优势,使得使用xml作为配置文件,是一种常用的手段。

libxml2是一个xml c语言版的解析器,本来是为Gnome项目开发的工具,是一个基于MIT License的免费开源软件。它除了支持c语言版以外,还支持c++、PHP、Pascal、Ruby、Tcl等语言的绑定,能在Windows、Linux、Solaris、MacOsX等平台上运行。功能还是相当强大的,相信满足一般用户需求没有任何问题。

最近在mipsel平台上需要用到libxml2库,这里做一个记录。

首先,从libxml2官网上下载相关软件包,我用的是libxml2-sources-2.7.8.tar.gz 。 继续阅读

前段时间一直在做PSAM卡的研究,直到完成大概有两个月了,时间有点长了,但还是有不少收获的。

言归正传,首先,PSAM卡的大致工作原理是这样:先给卡上电复位,然后开始对其进行操作(读、写)。整个流程看似简单,其实注意点很多:

1、数据格式:通过查阅一些资料,看到有两种说法:a、开始位+8数据位+校验位;b、开始位+8数据位+校验位+停止位。但是在实际用示波器测量的过程中,我发现第二种说法比较靠谱,但是也不是很靠谱,因为通过波形可以看到,停止位后面还有一位,而且总是高电平,实际操作的时候我就把它当做了最后由两位停止位,并没有出什么错

2、时钟:一开始做研究的时候,没有仔细看手册,只知道工作频率大概要达到3.57MHZ,并且我把一个数据为设置成了400个时钟,开始的时候能读出一些数据来,但是不准确,后来改成了373个时钟,在读ATR信息的时候,已经能够都读对了但是在往后模拟读写操作的时候,就发生问题了,由于数据位是时钟数不对,造成了发出命令后卡没有回应,最后仔细翻看手册,把373->372,就只有一位时钟之差,数据读出来了

3、持续性:我在模拟读写的时候,遇到了另一个问题,每次复位之后,发送命令卡没有反应,很郁闷,因为这个时候时钟已经对了,后来翻看手册,发现了一个断点续传的问题,由于不知道我这PSAM卡是否支持断点续传,所以我把程序作了改动,在复位之后就一直供时钟给卡,读数据成功,果然是这个问题,卡不支持断点续传

这些是我在模拟PSAM卡时候最主要的注意点,有些东西是要按照手册上严格执行的,但也有些东西规范不是很严格,但以上三点绝对是非常严格的……