显示标签为“ARM”的博文。显示所有博文
显示标签为“ARM”的博文。显示所有博文

星期一, 三月 10, 2008

s3c2410 LCD图片显示【转】

最近研究了s3c2410下LCD控制器的相关知识,主要的参考资料就是 三星s3c2410数据手册(arm920T),英文版,看的不是非常明白,后来参考了WinCE下的部分代码,似有所领悟。于是写了此程序,用以在LCD上显示图片。
本程序可以在LCD上居中显示小于800×480的任意大小的图片。用到的辅助工具就是上篇文章中的RGB分量提取器.
关键模块如下:

0、全局变量的定义:

#define DMA_BUFFER_BASE 0xAC000000
#define DMA_PHYSICAL_BASE 0x35000000 // S3C2410X01 0x30000000

#define FRAMEBUF_BASE (DMA_BUFFER_BASE + 0x00100000)
#define FRAMEBUF_DMA_BASE (DMA_PHYSICAL_BASE + 0x00000000)//0x00100000

#define IOP_BASE 0x56000000 // 0x56000000

typedef struct {
unsigned int GPACON; // 00
unsigned int GPADAT;
unsigned int PAD1[2];
...................
}IOPreg;

// Define LCD type of S3C2400X01
#define TFT24BPP 3
#define LCDTYPE TFT24BPP // define LCD type as upper definition.
//
// Registers : LCD Controller
//

#define LCD_BASE 0x4D000000 // 0x4D000000
typedef struct {
unsigned int LCDCON1; // 00
unsigned int LCDCON2; // 04
unsigned int LCDCON3; // 08
.....................
}LCDreg ;

// LCD register value

#define MODE_TFT_24BIT (224)
#define LCD_XSIZE_TFT (800)
#define LCD_YSIZE_TFT (480)
#define ARRAY_SIZE_TFT_24BIT (SCR_XSIZE*4*SCR_YSIZE)
#define HOZVAL_TFT (LCD_XSIZE_TFT-1)
#define LINEVAL_TFT (LCD_YSIZE_TFT-1)
#define MVAL (13)
#define MVAL_USED (0)
#define VBPD ((32-1)&0xff)
#define VFPD ((11-1)&0xff)
#define VSPW ((2-1) &0x3f)
#define HBPD ((88-1)&0x7f)
#define HFPD ((40-1)&0xff)
#define HSPW ((128-1)&0xff)
#define CLKVAL_TFT (1)
#define M5D(n) ((n) & 0x1fffff)

U32* pLCDBuffer24=(U32*)FRAMEBUF_DMA_BASE;
U32* picData;

volatile LCDreg *s2410LCD = (LCDreg *)LCD_BASE;

volatile IOPreg *s2410IOP= (IOPreg *)IOP_BASE;

int nCol = 800;//象素列数
int nRow = 480;//象素行数
U32* picDataT=NULL;

1、入口函数,其中包括了相应端口、寄存器初始化的入口,aa,bb,cc,dd,ee是可选择的5幅预定义图片的GRB码数组,具体代码如下

void lcd_Main(void)
{
char sel;
Uart_Printf("Lcd_Driver ");

lcd_port_init();
lcd_regs_init();

Uart_Printf("select one Picture to show(1 2 3 4 5 0) ");

while((sel = Uart_Getch()) != 'e')
{
Uart_Printf("%c ",sel);
switch(sel)
{
case '1':
picData = (U32*)aa;break;
case '2':
picData =(U32*)bb;break;
case '3':
picData = (U32*)cc;break;
case '4':
picData = (U32*)dd; break;
case '5':
picData = (U32*)ee;break;
default:
Uart_Printf("Input 1 2 3 4 5 0 ");
}

lcd_display();

Uart_Printf("select one Picture to show(1 2 3 4 5 0) ");
}
Uart_Printf("Exit");
//lcd_close();
}

2、相应端口设置,包括GPC,GPD,GPG的相应位的设置:


void lcd_port_init(void)
{

// LCD port initialize.
s2410IOP->GPCUP = 0xFFFFFFFF;
s2410IOP->GPCCON = 0xAAAAAAAA;

s2410IOP->GPDUP = 0xFFFFFFFF;
s2410IOP->GPDCON = 0xAAAAAAAA;

s2410IOP->GPGCON &= ~(3 <<>GPGCON |= (1 <<>GPGDAT |= (1 <<>LCDCON1 = (1 << vclk =" HCLK"> About 7 Mhz
(MVAL_USED <<>LCDCON2 = (VBPD <<>LCDCON3 = (HBPD <<>LCDCON4 = (MVAL <<>LCDCON5 = 0x00000000;
/**//*
s2410LCD->LCDCON5 = (0 <<>LCDSADDR1 = ((FRAMEBUF_DMA_BASE >> 22) <<>> 1)) << lcdbank =" ((FRAMEBUF_DMA_BASE">> 22) << lcdbaseu =" ((M5D(FRAMEBUF_DMA_BASE)">> 1) <<>LCDSADDR2 = (M5D(FRAMEBUF_DMA_BASE) >> 1) + ( (LCD_XSIZE_TFT*2) + 0 )*(LINEVAL_TFT+1);
//LCDBASEL = s2410LCD->LCDSADDR2

s2410LCD->LCDSADDR3 = (((LCD_XSIZE_TFT - LCD_XSIZE_TFT) / 1) << offsize =" (((LCD_XSIZE_TFT" pagewidth =" (LCD_XSIZE_TFT)">TPAL = 0x0;
s2410LCD->LCDCON1 |= 1;

#endif
}

4、居中显示图片:

void lcd_display(void)
{
int y;
int pw, ph;
int sw=800, sh=480;
U32* pdata;
U32* pBt=NULL;

lcd_clear();

get_XY();//获得图片的宽与高,以保存在RGB数组的头两个字节。
pw = nCol, ph = nRow;

pBt = pLCDBuffer24 + sw*(sh/2-ph/2) + (sw/2-pw/2);//定位图片显示的起始位置

pdata = (U32*)picDataT;
for(y=0; yLCDCON1 |= 0;

}

5、每次显示都要获得图片的宽度和高度,并且清除前面的屏幕,所谓清屏就是显示背景图片(蓝色):

void lcd_clear()
{
int y=0;
U32* pdata = (U32*)(bgData+2);
for(y=0; y<480; ++y)
{
memcpy((pLCDBuffer24+800*y),(char*)pdata,800*4);
pdata = (U32*)(pdata+800);
}
}

void get_XY(void)
{
nCol = picData[0];
nRow = picData[1];

picDataT =(U32*) (picData + 2);
}

Read More...

星期一, 一月 28, 2008

Linux启动时间的极限优化

  在上次完成嵌入式应用的Linux裁减后, Linux的启动时间仍需要 7s 左右,虽然勉强可以接受,但仍然没有达到我个人所追求的目标——2s 以内。况且,在实际的商用环境中,设备可靠性的要求可是“5个9”(99.999%,即OOS时间低于5分钟/年),这就意味着每减少一秒钟Linux启 动(设备复位)时间,对可靠性都是一个明显的提升。

  言归正传,如何着手对Linux的启动时间进行优化呢?

  CELF(The Consumer Electronics Linux Forum)论坛为我们指引了一个方向。

(1)首先是对Linux启动过程的跟踪和分析,生成详细的启动时间报告。

  较为简单可行的方式是通过PrintkTime功能为启动过程的所有内核信息增加时间戳,便于汇总分析。PrintkTime最早为CELF所 提供的一个内核补丁,在后来的Kernel 2.6.11版本中正式纳入标准内核。所以大家可能在新版本的内核中直接启用该功能。如果你的Linux内核因为某些原因不能更新为2.6.11之后的版 本,那么可以参考CELF提供的方法修改或直接下载它们提供的补丁:http://tree.celinuxforum.org/CelfPubWiki/PrintkTimes

  开启PrintkTime功能的方法很简单,只需在内核启动参数中增加“time”即可。当然,你也可以选择在编译内核时直接指定 “Kernel hacking”中的“Show timing information on printks”来强制每次启动均为内核信息增加时间戳。这一种方式还有另一个好处:你可以得到内核在解析启动参数前所有信息的时间。因此,我选择后一种 方式。

  当完成上述配置后,重新启动Linux,然后通过以下命令将内核启动信息输出到文件:

dmesg -s 131072 > ktime

  然后利用一个脚本“show_delta”(位于Linux源码的scripts文件夹下)将上述输出的文件转换为时间增量显示格式:

/usr/src/linux-x.xx.xx/scripts/show_delta ktime > dtime

  这样,你就得到了一份关于Linux启动时间消耗的详细报告。

(2)然后,我们就来通过这份报告,找出启动中相对耗时的过程。

  必须明确一点:报告中的时间增量和内核信息之间没有必然的对应关系,真正的时间消耗必须从内核源码入手分析。

  这一点对于稍微熟悉编程的朋友来说都不难理解,因为时间增量只是两次调用printk之间的时间差值。通常来说,内核启动过程中在完成一些耗时 的任务,如创建hash索引、probe硬件设备等操作后会通过printk将结果打印出来,这种情况下,时间增量往往反映的是信息对应过程的耗时;但有 些时候,内核是在调用printk输出信息后才开始相应的过程,那么报告中内核信息相应过程的时间消耗对应的是其下一行的时间增量;还有一些时候,时间消 耗在了两次内核信息输出之间的某个不确定的时段,这样时间增量可能就完全无法通过内核信息反应出来了。

  所以,为了准确判断真正的时间消耗,我们需要结合内核源码进行分析。必要的时候,例如上述第三种情形下,还得自己在源码中插入printk打印,以进一步确定实际的时间消耗过程。

  以下是我上次裁减后Linux内核的启动分析:

  内核启动总时间: 6.188s

  关键的耗时部分:
  1) 0.652s - Timer,IRQ,Cache,Mem Pages等核心部分的初始化
  2) 0.611s - 内核与RTC时钟同步
  3) 0.328s - 计算Calibrating Delay(4个CPU核心的总消耗)
  4) 0.144s - 校准APIC时钟
  5) 0.312s - 校准Migration Cost
  6) 3.520s - Intel E1000网卡初始化

  下面,将针对上述各部分进行逐一分析和化解。

(3)接下来,进行具体的分项优化。

  CELF已经提出了一整套针对消费类电子产品所使用的嵌入式Linux的启动优化方案,但是由于面向不同应用,所以我们只能部分借鉴他们的经验,针对自己面对的问题作出具体的分析和尝试。

  内核关键部分(Timer、IRQ、Cache、Mem Pages……)的初始化目前暂时没有比较可靠和可行的优化方案,所以暂不考虑。

  对于上面分析结果中的 2、3 两项,CELF已有专项的优化方案:“RTCNoSync”和“PresetLPJ”。

  前者通过屏蔽启动过程中所进行的RTC时钟同步或者将这一过程放到启动后进行(视具体应用对时钟精度的需求而定),实现起来比较容易,但需要为 内核打补丁。似乎CELF目前的工作仅仅是去掉了该过程,而没有实现所提到的“延后”处理RTC时钟的同步。考虑到这个原因,我的方案中暂时没有引入这一 优化(毕竟它所带来的时间漂移已经达到了“秒”级),继续关注中。

  后者是通过在启动参数中强制指定LPJ值而跳过实际的计算过程,这是基于LPJ值在硬件条件不变的情况下不会变化的考虑。所以在正常启动后记录下内核信息中的“Calibrating Delay”数值后就可以在启动参数中以下面的形式强制指定LPJ值了:

lpj=9600700

  上面分析结果中的 4、5 两项都是SMP初始化的一部分,因此不在CELF研究的范畴(或许将来会有采用多核的MP4出现?……),只能自力更生了。研究了一下SMP的初始化代 码,发现“Migration Cost”其实也可以像“Calibrating Delay”采用预置的方式跳过校准时间。方法类似,最后在内核启动参数中增加:

migration_cost=4000,4000

  而Intel的网卡驱动初始化优化起来就比较麻烦了,虽然也是开源,但读硬件驱动完全不比读一般的C代码,况且建立在如此肤浅理解基础上的“优 化”修改也实在难保万全。基于可靠性的考虑,我最终在两次尝试均告失败后放弃了这一条路。那么,换一个思维角度,可以借鉴CELF在 “ParallelRCScripts”方案中的“并行初始化”思想,将网卡驱动独立编译为模块,放在初始化脚本中与其它模块和应用同步加载,从而消除 Probe阻塞对启动时间的影响。考虑到应用初始化也可能使用到网络,而在我们的实际硬件环境中,只有eth0是供应用使用的,因此需要将第一个网口初始 化的0.3s时间计算在内。

  除了在我的方案中所遇到的上述各优化点,CELF还提出了一些你可能会感兴趣的有特定针对性的专项优化,如:

  ShortIDEDelays - 缩短IDE探测时长(我的应用场景中不包含硬盘,所以用不上)
  KernelXIP - 直接在ROM或Flash中运行内核(考虑到兼容性因素,未采用)
  IDENoProbe - 跳过未连接设备的IDE口
  OptimizeRCScripts - 优化initrd中的linuxrc脚本(我采用了BusyBox更简洁的linuxrc)

  以及其它一些尚处于设想阶段的优化方案,感兴趣的朋友可以访问CELF Developer Wiki了解详情。

(4)优化结果

  经过上述专项优化,以及对inittab、rcS脚本的冗余裁减,整个Linux内核的启动时间从优化前的 6.188s 下降到了最终的 2.016s,如果不包含eth0的初始化,则仅需 1.708s(eth0初始化可以和系统中间件及部分应用加载并行),基本达到了既定目标。与Kexec配合,可以大大降低软件故障导致的复位时间,有效的提升了产品的可靠性。

  大家如果对内核启动时间的优化还有什么建议或疑惑,都欢迎与我探讨。:)

Read More...

嵌入式应用Linux裁减的初次尝试

  前段时间因为嵌入式应用开发的需要,对Linux进行了一次大幅度的裁减。由于是初次接触Linux启动的核心部分,所以基本上还是对网上各种裁减方案的拼凑和整理,包含自己理解的部分实在很少。总的来说效果不算理想,后面还有很长的路要走。

这里就大致说说目前这个Linux裁减方案的“雏形”吧。

  1. 内核裁减

对Linux内核部分的裁减主要根据实际需求进行了重编译,去掉了大部分用不上的特性,以及实际硬件环境之外的设备驱动。这一过程没啥技术含量,就不细说了。

2. initrd改造

常规的Linux系统启动过程中,initrd仅仅充当一个临时的rootfs,在加载实际的rootfs后即被卸载或转移。出于精简的考虑,我将 原rootfs并入了initrd,让它直接充当rootfs,以节省启动时间,并减小体积。(这个改造方案相对来说最简单,也足以满足实际需要)

改造的过程主要是基于原make install自动生成的initrd镜像之上,进行以下“手术”:

(1) 用BusyBox的linuxrc替代原initrd中的初始化脚本,并将原linuxrc脚本中有用得上的初始化任务都合并至etc/inittab中,以节省启动时间。

(2) 因为要充当rootfs,所以还需为initrd添加Linux启动及运行所必须的一些文件夹和文件(主要复制自原rootfs):

/dev
tty3 - tty10 终端会话设备(Console登录使用)
ttyS0、ttyS1 串口终端设备(串口登录使用)
ptmx、pts 虚拟终端设备(远程登录使用)
/etc
fstab 加载设备的配置文件(后面详述)
gettydefs 仅保留Virtual Console一项
group 仅保留root对应的项
hostname 包含本机的主机名
inittab 初始化脚本(后面详述)
issue 包含本机的全程登录欢迎文字
passwd 仅保留root对应的项
shadow 仅保留root对应的项
termcap 仅保留用于本地console及远程登录的配置项
/etc/init.d
rcS 次级初始化脚本(后面详述)
/lib
libcrypt.so.1 登录认证(login)所需的库文件
/mnt
/proc
/sys
/tmp
/usr
/var

(3) 修改etc/fstab存储设备加载配置文件,只包含下面四行:

sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
tmpfs /dev/shm tmpfs size=512m 0 0
devpts /dev/pts devpts defaults 0 0

由于实际硬件环境的内存比较大,所以给临时文件系统分配的内存上限比较充裕

(4) 创建etc/inittab初始化脚本。由于init模块采用了BusyBox的精简版本,而它采用的inittab文件格式较普通版本有一些区别,所以特别按照BusyBox的格式重新编写了。文件较大,下面仅列举其中的关键部分:

::sysinit:/bin/mount -a 加载etc/fstab中配置的所有存储设备
::sysinit:/bin/mkdir /dev/shm/var 在tmpfs中划分用作var的部分
::sysinit:/bin/mkdir /dev/shm/tmp 在tmpfs中划分用作tmp的部分
::sysinit:/bin/chmod 1777 /dev/shm/var 修改var为合适的权限
::sysinit:/bin/chmod 1777 /dev/shm/tmp 修改tmp为合适的权限
::sysinit:/bin/mount --bind /dev/shm/var /var 将/var绑定到tmpfs中
::sysinit:/bin/mount --bind /dev/shm/tmp /tmp 将/tmp绑定到tmpfs中

::sysinit:/bin/hostname -F /etc/hostname 从etc/hostname中读取并设置主机名
::sysinit:/sbin/ifconfig lo 127.0.0.1 up 配置IP环回界面
::sysinit:/sbin/telnetd 启动Telnet Daemon
::sysinit:/etc/init.d/rcS 调用次级初始化脚本(完成不能在inittab中进行的初始化任务)

::sysinit:/bin/mkdir /var/log 创建日志文件夹
::sysinit:/bin/touch /var/log/messages 创建日志文件
::respawn:/sbin/syslogd -n -m 30 -C 加载循环缓冲模式的系统日志daemon
::respawn:/sbin/klogd -n

::askfirst:/bin/login 在console创建登录进程
tty2::askfirst:/bin/login 在tty2-tty6上创建额外的登录进程
tty3::askfirst:/bin/login
...
ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100 在串口COM1上创建登录进程
tty10::respawn:/sbin/logread -f 将所有日志打印输出到tty10

(5) 创建etc/init.d/rcS次级初始化脚本,包含以下内容:

/bin/mount -o remount,rw / 将rootfs重新加载为可读可写方式

注:由于试验的方便,生成的initrd采用了Ext2文件系统。在实际应用中考虑换为CRAMFS(压缩ROM镜像文件系统),以进一步缩减镜像文件体积并提高读取效率。

3. Boot Loader修改

由于这个裁减方案仅仅使用了内核镜像及initrd,保持了与标准引导方式的高度兼容,因此适用于几乎任何Boot Loader。由于裁减实验中需要频繁替换内核和initrd镜像,因此使用了便于控制的GRUB,以提高实验效率。如果最终方案采取Flash作为镜像 载体,则建议使用LILO,以提高兼容性并节省空间。
为了与本方案中以initrd作为rootfs保持一致,Boot Loader的配置文件中需要修改引导参数,指定“root=/dev/ram0”,无需其它额外的参数。

经过上述裁减,整个Linux的启动时间已经缩短到10s以内。内核+initrd的镜像大小也不足3M,基本达到了预期的目标。后续会针对启动的各个环节作进一步的分析和优化,以期进一步缩短启动时间。

Read More...

星期六, 一月 26, 2008

2410 第七章 时钟和电源管理

概述

时钟和电源管理模块由3部分组成:时钟控制、USB控制、电源控制。

时钟控制部分产生3种时钟信号:CPU用的FCLK,AHB总线用的HCLK,APB总线用的PCLK
2个锁相环,一个用于FCLK HCLK PCLK,另一个用48MHzUSB时钟。可以通过不使能锁相环来达到慢速省电目的。

电源管理模块提供了4种模式: Normal模式、Slow模式、Idle模式、Power_Off模式。
Normal Mode

该模式下如果所有外围设备都打开时电流消耗最大,允许用户通过软件关闭外围设备达到省电目的。

Slow Mode

不采用PLL的模式,能量消耗仅取决于外时钟的频率。由外部提供的时钟源作FCLK

Idle Mode

关掉了给cpuFCLK时钟,但外围设备时钟仍存在,任何到CPU的中断请求可以将cpu唤醒。

Power_off Mode

这种模式关掉了内部供电,仅有给wake_up部分的供电还存在。可以通过外部中断或实时时钟中断可以唤醒。

功能描述

时钟结构:主时钟源来自外部晶振XTlpll或外部时钟EXTCLK

时钟源选择:通过OM[3: 2]的高低电平选择,现在我们采用00OM[32]的状态在nRESET的上升沿锁存。尽管MPLL在上电复位后就开始工作,但是MPLL输出不作为系统时钟,只有对MPLLCON写入适当的数值后才可以。即使用户不想改变MPLLCON的值,也要重新写一遍才能使其起作用。

时钟控制逻辑:时钟控制逻辑决定要使用的时钟源,当锁相环被设置为一个新的值时,时钟控制逻辑切断FCLK直到PLL输出稳定。时钟控制逻辑在上电复位或从power_down状态启动时使能。

上电复位:注意上电后必须通过设置PLLCON才能使PLL作用。

在正常操作状态下改变PLL设置:通过改变PMS的值来实现。

USB时钟控制:UCLK不起作用直到UPLL被设置。

FCLK、HCLK、PCLK:可以通过HDIVNPDIVNCLKDIVN来改变3种时钟的比率,推荐采用124的比率。在设置完PMS的值后,需要设置CLKDIVN寄存器,该寄存器设置的值在PLL锁定后生效,只需要1.5HCLK即可完成比率的修改。

电源管理:4种模式及特点。

Power_Off模式:外部中断EINT[15:0]RTC alarm中断可以从该模式wakeup.

进入PowerOff模式的流程:1。将GPIO端口设置为适当的状态; 2……….

VDDiVDDiarm的控制:PowerOff模式,仅VDDiVDDiarm通过PWREN管脚控制被关闭。如果PWREN为高,VDDiVDDiarm被外部电源提供,如果为低则关闭。尽管VDDiVDDiarmVDDi_MPLLVDDi_UPLL可能被关闭,其他电源必须被提供。

EINT[15:0]启动信号: EINTn管脚必须被设置为中断管脚,在启动后,相应的EINTn管脚将不被用作启动,可以被用作外部中断请求。

电池故障信号(nBATT_FLT):cpu不在PowerOff模式时,nBATT_FLT将要引起低电平触发的中断。当在PowerOff模式时,nBATT_FLT信号将会禁止芯片从PowerOff模式启动,故所有的wakeup信号被屏蔽,此举用来保护系统电量低时不出现故障。

时钟和电源管理部分寄存器

LOCKTIME: UPLLMPLL 锁定时间的计数值。

MPLLCON UPLLCON:这两个寄存器都有MDIV PDIV SDIV设置,对于输入12M的晶振,有相应的推荐值,产生200M和48M的频率。

CLKCON: 为各种外围接口提供时钟。

CLKSLOW: 是否打开2个PLL。

CLKDIVN: 设置FCLKHCLKPCLK比率的寄存器。


Read More...

星期一, 一月 21, 2008

UDEV on embeded Linux-2.6.19.2 UDEV on embeded Linux-2.6.19.2[转]

UDEV,新一代的用户空间设备管理系统,用以取代臃肿的DEVFS(其实DEVFS我还没用过,谁叫我是新来的 ^_^ ,关于两者的对比,可以参考 udev_vs_devfs )。关于UDEV的使用已经有一遍不错的译文 udev轻松上路 ,不过里面关于配置文件的编写与 Writing udev rules 不符。/etc/udev/udev.conf 是udev启动检查的配置文件,包括路径,权限,规则目录等,具体的规则文件应该为/etc/udev/rules.d/10-local.rules 。

我开始移植的第一个Linux是2.6.19.2,已放弃对DEVFS的支持,下面谈谈UDEV在我的arm开发板上的应用。由于BusyBox已带有一个简化板的udev--mdev。通过简单的 mdev -s ,就能自动装配/dev目录下的设备文件:

# ls /dev
console null ptmx pts shm
# mdev -s && ls /dev
apm_bios ptypd tty24 tty56
console ptype tty25 tty57
fb0 ptypf tty26 tty58
full ram0 tty27 tty59
kmem ram1 tty28 tty6
kmsg ram2 tty29 tty60
loop0 ram3 tty3 tty61
... ...
启动热拔插支持的话,用这一句
echo /sbin/mdev > /proc/sys/kernel/hotplug
一切就是这么简单,相应的/dev目录下会出现一大堆设备文件,甚是难看 ^_^
mdev的规则文件是/etc/mdev.conf ,与传统的udev规则文件写法上有点区别(简化了^_^)。
KERNEL=="tty[0-9]*", NAME="vc/%n" //for udev
tty[0-9]* 0:5 660 //for mdev
如果选上FEATURE_MDEV_EXEC支持,规则后面可以执行相应的命令,如:
pts/ 0:0 755 $mount -t devpts /dev/pts /dev/pts
不过我的程序还算简单,mdev -s 对我而言已足够,规则,留作日后写吧 ^_^
我用的是mdev,因为简单 ^_^
在启动教本(如:linuxrc)加入这两句就搞定:
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

Read More...

busybox mdev的初始化问题


mdev来自动创建/dev中的设备文件,busybox的文档中说的很明白,使用
mdev时不加参数就是用hotplug机制来决定创建什么样的设备文件。

而用mdev -s是用sys文件系统提供的信息来创建设备文件的。我一开始没仔细看文档,在linuxrc中没加参数调用的mdev,结果造成真正的根文件系统没有挂载成功。因为那样mdev就要找hotplug而
buzybox好像还不能支持hotplug,我自己也没提供hotplug的机制,所以设备文件创建失
败,那么在mount 根文件系统的时候就失败了,后面再pivot_root也就没戏了。
最后一点要注意的是在你的initrd的/dev中必须要有console这个文件,要不启动的时候
就会报错的。
我把linuxrc贴在这,顺便加点注释:
#!/bin/ash
echo Start the script in initrd #输出一些信息
echo Press any key to continue #输出信息
read TEMP #等待你瞪大眼睛看后面的东西
/bin/mount -t proc /proc /proc #挂proc fs,其实我们这暂时还没用到,如果你要动
#态分析根文件系统,你就得分析kernel的cmdline,那个cmdline就在proc中
/bin/mount -t sysfs none /sys #挂sys为mdev填充/dev搜集信息
echo Creating /dev
/bin/mount -o mode=0755 -t tmpfs none /dev #在原有的/dev目录上再盖上一层,这
#样系统退出时就不会留下mdev填充的东西
#下面创建一些最基本设备文件,这些设备文件是mdev所使用的
/bin/mknod /dev/console c 5 1
/bin/mknod /dev/null c 1 3
/bin/mknod /dev/zero c 1 5
/bin/mkdir /dev/pts
/bin/mkdir /dev/shm
/sbin/mdev -s #mdev为我们自动填充/dev目录,该有的都会有的
#下面加载ext3所需的模块
echo "Loading ext3 modules"
/sbin/insmod /lib/jbd.ko
/sbin/insmod /lib/ext3.ko
/sbin/mdev -s #再次调用mdev,我不知道为什么,rh的initrd中就是调用两次,也许
#去掉前面的一次也没问题,回头我试试
/bin/umount /sys #卸掉sys,反正用完了
echo press any key to continue
read TEMP #等待你瞪大眼睛
echo Mounting root filesystem
/bin/mount -o defaults --ro -t ext2 /dev/hda1 /sysroot #挂载真正的根文件系统
,老道的技术应该是从kernel的cmdling中猜出根文件设备,而不是象我这样hard coded
/bin/mount -t tmpfs --bind /dev /sysroot/dev #保持新旧root 中的/dev是一样的
#下面的root切换都是标准动作在pivot_root的man page中有
echo Switching to new root
read TEMP
cd /sysroot
/sbin/pivot_root . mnt
exec /usr/sbin/chroot . /sbin/init
/bin/umount /mnt/dev #卸掉原来root 的dev目录

Read More...

移植2.6.22.1到2410上


今天在板子上移植了2.6.22内核,用uboot能正常引导进入cramfs文件系统,但是cs8900a网卡还不能正常工作,明天继续加油,得好好研究研究这块了。


主要是参考http://hi.baidu.com/wangy0919/blog/


这个blog收集的文章很全,呵呵,虽然不是原创,但是也难能可贵的,我也受益匪浅,谢谢blog主人了。


基本没出什么大问题,就是在制作根文件系统的时候,有点小问题,还有就是uboot的bootargs参数设置


Read More...

星期四, 一月 17, 2008

使U-BOOT正确引导linux内核

1、为了能使得U-BOOT正确引导linux内核。必须传递合适的参数给内核。
修改include/configs/zj2410.h如下:
/************************************************************
* RTC
************************************************************/
#define CONFIG_RTC_S 24X0 1
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
#define CONFIG_BAUDRATE 115200
/************************************************************/
/* My Add */
/* enable passing of ATAGs */#define CONFIG_CMDLINE_TAG 1
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_INITRD_TAG 1
/***********************************************************
* Command definition
***********************************************************/
#define CONFIG_COMMANDS \
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
CFG_CMD_NAND | \
/*CFG_CMD_EEPROM |*/ \
/*CFG_CMD_I |*/ \
/*CFG_CMD_USB |*/ \
CFG_CMD_REGINFO | \
CFG_CMD_DATE | \
CFG_CMD_ELF)
2、为了能稳定正确引导linux内核,得修改UBOOT的2410CPU频率。
smdk2410的U-BOOT原来运行频率是 ,在这个频率我已开始能正确引导内核,但是后来突然就不能引导了,
总是死在下面这个地方:
Uncompressing Linux....................................................... done, booting the kernel.
按照网上的说法,内核中,在\arch\arm\mach_s 2410\s 2410.c 中
fclk = s 2410_get_pll(MPLLCON, xtal); //读出来的fclk结果和bootloader的频率不一致。
既然不能用 ,VIVI的 能跑得好好的,那我把U-BOOT的频率改成 , 2.6.20 .3的内核和阳初光盘的2.4.18的内核都能正确稳定地引导了。
修改board/yangchu2410/smdk2410.c文件如下:
#define FCLK_SPEED 1
#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
//#define M_MDIV 0xA1
//#define M_PDIV 0x3
//#define M_SDIV 0x1
#define M_MDIV 0x /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0
#endif
好了,编译烧写U-BOOT到NAND FLASH,通过setenv 设置bootargs,引导内核时就可以将bootargs传递给内核了。
注意:
1、 对于U-BOOT而言,启动内核时候使用bootm命令才能传递内核参数,使用go命令是不传递内核参数的。
2、 bootm命令引导的只能是用U-BOOT的mkimage工具做过的内核映像,所以要引导阳初光盘带的内核映像,必须用其工具转换一下,至于这个工具怎么用,到U-BOOT的tools目录下找这个工具去吧,./mkimage --help 或者网上找找资料看下就知道了。^_^。

Read More...

移植uboot到2410上总结

这两天有点空闲时间,自己忙里偷闲,偷偷的在实验室的板子上移植了uboot
板子是我们自己制版焊接的,所以稳定性不是很好,不过凑合也能正常工作,一直以来工作都是用vivi,但是这个版本的vivi没有tftp下载功能,所以用xmodem协议下载zImage的时候太漫长了,而自己想移植个带tftp功能的vivi,可是由于没那么多时间就一直没成功,一直uboot也是试试,如果折腾折腾没成功,估计最后也得放弃,毕竟现在没那么多时间,而且主管也没给那个时间,这一切都是凭着工作之余,自己的兴趣所在。
板子是参考广州斯道2410的公版,还有友善之臂,反正内核什么的都没改直接就用他们的这些能正常在我们的板子上跑,我想硬件都一样吧,要不然也不能正常的跑,而且都是smdk2410公版的修改,(硬件是另一个同事做的,我具体不是很懂,不过应该和我想想的一样)
uboot是1.1.4的主要参考了
要参考了luofuchong 大侠
http://www.hhcn.com/cgi-bin/topic.cgi?forum=3&topic=562&start=0&show=
和bekars大侠
http://dev.csdn.net/article/84/84538.shtm
代码就是直接下载的xiaoluo的代码,然后打上他的补丁就ok了
make distclean
make clean
make smdk2410_config
make
就可以生成u-boot.bin了
用sjf2410烧写可以看到能够在板子上启动
一切都比较顺利(我想这都是因为xiaoluo都已经改过了)
但是还是有些问题,那就是不能正常引导内核
到Uncompressing Linux....................................................... done, booting the kernel的时候就停住了
这时候自己连uboot的基本命令都还不懂,又上网查了查用法
继续试验,还是不行,后来参考了另一个帖子,说是因为内核参数没有正确传递的原因,内核应该启动起来了,可是就是没有输出信息,和我在调试其他驱动的时候把console设为tty0一样,于是就朝着这个方向去解决问题
修改board目录下smdk2410.c
#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
//#define M_MDIV 0xA1
//#define M_PDIV 0x3
//#define M_SDIV 0x1
#define M_MDIV 0x /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0

#endif
在include/configs/smdk2410.h中加上

#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */

#define CONFIG_SETUP_MEMORY_TAGS 1

#define CONFIG_INITRD_TAG 1

然后重新编译uboot

重新下载后,问题还是一样,很是郁闷,就有上网抠,查到还有人说是频率不对,我下面转的

几个帖子就是。
smdk2410的U-BOOT原来运行频率是202.8M,把U-BOOT的频率改成200M,

"board/smdk2410/smdk2410.c"

#define FCLK_SPEED 1

#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
//#define M_MDIV 0xA1
//#define M_PDIV 0x3
//#define M_SDIV 0x1
#define M_MDIV 0x5c /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0
#endif

重新少些后问题依然,郁闷ing
后来又反复试验,在快要放弃的时候,突然发现有一次能引导kernel了
发现在这个uboot中有个bootargs参数要正确设置,由于受vivi影响,一直都是这么设置的
setenv bootargs="noinitrd console=ttyS0 root=/dev/mtdblock/4"
然后就saveenv了
以为没有问题,所以反复试验都没查这个,但是后来仔细printenv一看
bootargs="noinitrd=console=ttyS0 root=/dev/mtdblock/4"
不知道为什么多了个“=”
又反复设置,就是不能像vivi那样,不明白了,是不是这个uboot的bug还是uboot就是这样,没用过uboot不知道了
后来看设置bootcmd的时候是这样的:
setenv bootcmd=nand read 0x30000 0x1d0000
没有引号,不是自己想象的那样用引号括起来。
于是重新设置bootargs
setenv bootargs=noinitrd console=ttyS0 root=/dev/mtdblock/4
saveenv
这下终于可以boot kernel了
查点到这里就放弃了,回想起来,细心和坚持很重要,要不是坚持,可能这个问题就这么放过去了。
坚持!!!!!!!!!
再一次鼓励了我,虽然这次没什么太多的技术含量(个人感觉没有什么技术含量,就是google,还有就是直觉)
后来重新试验,发现上面修改的频率是有作用的,如果

#define M_MDIV 0x5c /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0
改为
#define M_MDIV 0x5c /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x2
就出现了乱码,可能是波特率也随着改变了,所以有输出但是乱码,
但是

#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */

#define CONFIG_SETUP_MEMORY_TAGS 1

#define CONFIG_INITRD_TAG 1

这个还没有机会试验呢,但是我想也应该有作用的
不然kernel的参数就传递不过来了

Read More...

星期三, 一月 16, 2008

U-BOOT移植到阳初2410的板子【转】

这个好东西是从阳初论坛上下载的。我自己还没有研究,希望有兴趣的朋友可以研究一下。附件上有源代码,还有专门的word文档说明。以后研究了再放上更多的详细介绍,先发给大家玩玩!最近忙考试和制作简历,没时间!!呵呵!!!!!

以下是作者在论坛的讨论的内容:

晕死,发了半天,居然都没发上来,说我字数限制,我都没几个字。

只能传了。

写的匆忙,还没来得及改,有错的地方,望各位指出。^_^

我的工作环境:

RedHat 9

arm-linux-gcc 4.1.1(glibc2.3.2)

U-BOOT1.2.0

目标板:阳初S3C2410开发板V2.3版

买回来,板子上没有NOR FLASH,给的也只有VIVI,我想用U-BOOT(这个用的比较广),所以只能修改U-BOOT从NAND FLASH启动了。

我的内容包括:

NAND FLASH启动;

NAND FLASH驱动,让U-BOOT可以对NAND FLASH读写;

环境变量保存到NAND FLASH。

引导linux内核

参照的主要是网上的文章,我只不过相当于拼凑了一下。呵呵。

我晕,大小上传也只有100KB。只能压缩传了。

顺便把U-BOOT中修改后的几个文件也发上来:

点击浏览该文件

编译后的U-BOOT.bin,可以利用JTAG烧写到NAND FLASH运行的:

点击浏览该文件

晕,之前做的U-BOOT不能正确阳初光盘编译好的linux映像内核。

下载到板子上0x30008000运行,不行,用bootm和go命令的结果都是和前面的结果一样,最后死在这里:

……

……

Uncompressing Linux....................................................... done, booting the kernel.

往下就没了。网上查了很多文章,说法不一,各人的遇到的特殊情况不同吧。

于是,我用2.6.20.3源码make s3c2410_defconfig默认配置,编译了一下,在板子上跑了一下,结果跑起来了,但是查看启动信息,发现U-BOOT的bootargs并没传递给内核:

U-BOOT的bootargs如下:

bootargs=root=/dev/ram rw initrd="0x308000",6000000 console="ttyS0",115200 mem="64M"

而内核启动显示如下:

Kernel command line: root="/dev/hda1" ro init="/bin/bash" console="ttySAC0"

说明U-BOOT并没有设置bootargs到参数里去。
再查看U-BOOT的include/configs/yangchu2410.h文件,发现没有定义如下:

#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */

#define CONFIG_SETUP_MEMORY_TAGS 1

#define CONFIG_INITRD_TAG 1

而#define CONFIG_CMDLINE_TAG 1是在传递cmdline时候必须设置的,所以在include/configs/yangchu2410.h文件中添加如上定义。

定义之后,重新编译U-BOOT,烧写到NAND FLASH中,启动板子。

再跑上面编译的2.6.20.3linux,内核启动信息中显示的参数信息和U-BOOT中设置的一致了。

设置U-BOOT的bootargs:noinitrd root="/dev/mtdblock/2" console="ttyS0" mac="00:01:5d:68:7a:0f",再跑阳初光盘带的linxu内核,往下看到兴奋的字眼了:

YANGCHU2410 # bootm 30008000

## Booting image at 30008000 ...

Image Name: yangchu_linux2.4.18

Created: 2007-08-26 8:06:16 UTC

Image Type: ARM Linux Kernel Image (uncompressed)

Data Size: 772272 Bytes = 754.2 kB

Load Address: 30008000

Entry Point: 30008040

Verifying Checksum ... OK

XIP Kernel Image ... OK

Starting kernel ...

Uncompressing Linux....................................................... done, booting the kernel.

Linux version 2.4.18-rmk7-pxa1 (fc@localhost.localdomain) (gcc version 2.95.3 20010315 (release)) #441 7 10 11:29:04 CST 2007

CPU: ARM/CIRRUS Arm920Tsid(wb) revision 0

Machine: Samsung-SMDK2410

On node 0 totalpages: 16384

zone(0): 16384 pages.

zone(1): 0 pages.

zone(2): 0 pages.

Kernel command line: noinitrd root="/dev/mtdblock/2" console="ttyS0" mac="00:01:5d:68:7a:0f"
……
……

楼顶的文章我已经改过了,上传了我更新过的文章。

相应要要修改的U-BOOT以及编译好的uboot.bin也重新上传了

UBOOT引导内核真是搞怪,前几天还能引导的,这几天又不能引导了,但是这些内核用VIVI都是能引导的,搞得头痛死了,总是死在下面这个地方:
Uncompressing Linux....................................................... done, booting the kernel.

后来发现是频率的问题。因为网上有人也遇到此问题,相关说法如下:

之后用仿真器追踪内核结果发现:

start_kernel函数的time_init()中程序进入死循环~~

我随之进入time_init()

继续进入 system_timer->init();

结果发现,我的fclk,pclk都不能得到正确的值,积存器正确,我拿笔都能算出来,可是他就是总出错,所以我一气之下把他们全部写死.

具体如下:
在\arch\arm\mach_s3c2410\s3c2410.c 中 搜索 fclk ;

fclk = s3c2410_get_pll(MPLLCON, xtal); //这是他原来的,结果不是我们想要的200MHZ
fclk =200*1000*1000 ; // 这是我加的
在\arch\arm\mach_s3c2410\time.c 中搜索 pclk:

pclk = clk_get_rate(clk); //这是原来的

pclk = 50*1000*1000; //这是我加的

当然这都是根据2410的DATASHEET而定的

我现在用的是FCLK : HCLK : PCLK = 1 : 2 : 4 ,所以我分别写死为200M 100M 50M.

看来我的问题差不多也出在这边了,fclk得不到正确的值,由于没有仿真器,只能这么推测了。因为我终端上显示出来的传递参数都没有问题。

我再看了看VIVI,它里面用的就是200M。

smdk2410的U-BOOT原来运行频率是202.8M,后来把U-BOOT的频率改成200M,2.6.20.3的内核和阳初光盘的2.4.18的内核都能稳定地引导了。

修改文件如下:

"board/yangchu2410/smdk2410.c"

#define FCLK_SPEED 1

#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
//#define M_MDIV 0xA1
//#define M_PDIV 0x3
//#define M_SDIV 0x1
#define M_MDIV 0x5c /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0
#endif

Read More...

星期一, 十二月 17, 2007

关于u8 u16 u32 以及arm中的长度问题。『转』

首先先来看看2个程序,第一次看会死人的。
#include <stdio.h>
struct test{
unsigned int a1;
unsigned char a2;
unsigned short a3;
unsigned char a5;
unsigned int a4;
};

int main(void)
{
printf("a:%d\n",sizeof(struct test));
return 0;
}
显示16
----------
#include <stdio.h>
struct test{
unsigned int a1;
unsigned char a2;
unsigned char a5;
unsigned short a3;
unsigned int a4;
};

int main(void)
{
printf("a:%d\n",sizeof(struct test));
return 0;
}
显示12
----------
为什么呢??
因为:
unsigned char a2;
unsigned short a3;
unsigned char a5;
主要是因为u16和u8的排列问题
--------------
如果char后面跟的是u16,那char就是2字节存储了。
后面的char是单字节,但是a5后面是int,所以a5就当4字节存储了。
u8就是unsigned char
那么u16=unsigned short
u32=unsigned int了呵呵。
short 16
char 8
int 32
在arm和32bit的intel中是这么定义的。
我晕,还要管哪家公司定义的。
结构体中的排列问题 是编译器的原因还是什么?
是 cpu架构和编译器共同作用
---------------------------------------
好了,我们回头看那个程序。
第一个:
4+2+2+4+4=16
4(unsigned char)+2(unsigned char因为后面的16、2个字节,所以变了)+2(unsigned short)+4(unsinged char因为后面的32、4个字节所以变了)+4(unsigned int)=16
第二个:
4+1+1+2+4=12
就没怎么变。(ps: 还不知道为什么这个就没有8--〉16变成2字节,或许不用吧, 下午再问)
在这里谢谢id=思想者的老兄了。呵呵。这么本质的问题都有。厉害。

Read More...

星期一, 十二月 10, 2007

s3c2410 _spi概述

概况:

S3C2410X的连续外围设备接口(SPI)能连接电路实现连续数据传递。S3C2410X包含2SPI,,每个都分别有两个8位转移寄存器用于数据的传输和接收。在一个SPI进行数据传递时,同步传送数据并连续输出数据。在某一频率的8位连续数据由它相应的通讯控制寄存器设置所决定。假如你只发送数据,接收数据就能设为哑元。反之,如果你只想接收数据,你应该发送设为哑元'1'数据。

S3C24104个与SPI传输有关的I/O信号引脚:SCK(SPICLK01)MISO(SPIMISOO1)数据线,MOSISPIMOSIO1)和低电平有效的/SS(nSS01)引脚(输入)

特点

SPI协议(Ver.2.11)兼容

8位移位寄存器输出

8位移位寄存器接收

8位预分频逻辑

查询,中断,DMA传输模式

 

 

SPI操作

采用SPI接口, S3C2410X可发送/接收与外部设备同步的8位数据。一个串行时钟线与两条用来移位和采样信息的数据线同步。 SPI为主机时,发送频率可以通过为SPPREn寄存器设置合适的值来控制。你可以通过调整波特率数据寄存器的值来修改它的频率。当SPI为从机时,其它的主机提供时钟。当编程者向SPTDATn寄存器写字节数据时,SPI的收/发将会同时开始。在其它情况下,在向SPTDATn寄存器写入字节数据时要把nSS激活。

 

编辑程序

 

当向SPTDATn寄存器写入字节时,如果ENSCKSPCONn被设置的话,SPI就开始传输

你可以使用一上典型的程序来操作一个SPI卡。

编程SPI模式,基本遵循这些基本步骤:

1.       设置波特率寄存器(SPPREn

2.       设置SPCONn以选择合适的SPI模式。

3.        写数据0xFFSPTDATn10次以初始化MMCSD卡。.

4.       设置GPIO引脚使其具有nSS功能,低电平时使MMCSD卡有效。

5.       发送数据:检查发送准备樗是否为1,如果为1 的话就开始向SPTDATn写数据。

6.       接收数据(1):SPCONn TAGD 位禁用 = 正常模式

    :向SPTDATn 0xFF,然后测试REDY,再从读缓存中读取数据。

7.       接收数据:SPCONnTAGD 能用 = 自动接收垃圾数据模式。

    :测试REDY,然后从读缓存中读取数据。

8.       设置GPIO引脚使其具有nSS功能,高电平时使MMCSD卡有效。

 

 

通过DMA发送的步骤

1.       SPI的配置为DMA模式

2.       DMA合适设置

3.       SPI请求DMA服务

4.       DMASPI发送一个字节数据.

5.        SPI向卡里发送数据

6.       返回到步骤3直到DAM计数变为0

7.       SMOD位把SPI设置为中断或查询模式

 

通过DMA接收的步骤

1.       SPI设置为DMASMOD位开始,并且设置TAGD.

2.       全适配置 DMA

3.       SPI从卡里接收一字节数据

4.       SPI请求DMA服务

5.       DMASPI接收数据

6.        自动的向SPIDATn写数据0xFF

7.        回到步骤4DAM计数变为0

8.       SMOD位把SPI配置为查询模式,并且清TAGD

9.       如果SPSTAnREDY 标志被设置,就读取最后的字节数据

 

:

总接收的数据 = DAM TC +在查询模式下的最后值.

DAM接收的第一个数据是哑元,所以使用者可以忽略它

SPI 从机接收模式和B模块

 

如果SPI从机接收模式有效和SPI模块被设成B模块,SPI操作将会失败。

READY信号这一内部信号将在SPI_CNT达到0之前变成高电平。因此,在DMA模式中,DATA_READ信号应该在最后一个数据结束之前产生。

注意

1)      DMA模式:这种模式不能在SPI从机接收模式和B模块下使用。

2)      查询模式:在SPI从机接收模式和B模块下DATA_READ信号应该推迟SPICLK的一个相位。

3)      中断模式:在SPI从机接收模式和B模块下DATA_READ信号应该推迟SPICLK的一个相位。

SPI特殊寄存器

SPI控制寄存器

SPI状态寄存器

SPI引脚控制寄存器

如果SPI系统使能时,除nSS引脚外的其它引脚的方向通过SPCONnMSTR位来控制。nSS引脚的方向总是输入。

SPI为主机时,nSS引脚用来检查由SPPINENMUL位提供的多主机错误信号,另一个GPIO应该选择从机。

如果SPI被设置为从机,nSS引脚奖被一个主机选择为从机。

SPIMISOSPIMOSI数据引脚用来发送和接收串行数据。当SPI为主机时,SPIMISO是数据输入引脚,SPIMOSI是数据输出引脚,SPICLKSCK)是时钟输出线。当SPI为从机时,这些引脚执行相反的功能。在多主机系统中,SPICLKSCK)、SPIMOSISPIMISO将被分别的配置在一个体系中。

当其它的SPI设备作为从机选择S3C2410 SPI为从机时,一个主机SPI可以发出一个多主机错误信号。当这个信号被探测到,将会立刻发生下面所说的事情。但是如果你想探测到这种信号的话必须事先设置SPPINnENMUL位。

 

1.       SPCONnMSTR位被强制为0来启动从机模式。

2.       SPSTAnMULF标志位被置位,一个SPI中断会产生。

概况:

S3C2410X的连续外围设备接口(SPI)能连接电路实现连续数据传递。S3C2410X包含2SPI,,每个都分别有两个8位转移寄存器用于数据的传输和接收。在一个SPI进行数据传递时,同步传送数据并连续输出数据。在某一频率的8位连续数据由它相应的通讯控制寄存器设置所决定。假如你只发送数据,接收数据就能设为哑元。反之,如果你只想接收数据,你应该发送设为哑元'1'数据。

S3C24104个与SPI传输有关的I/O信号引脚:SCK(SPICLK01)MISO(SPIMISOO1)数据线,MOSISPIMOSIO1)和低电平有效的/SS(nSS01)引脚(输入)

特点

SPI协议(Ver.2.11)兼容

8位移位寄存器输出

8位移位寄存器接收

8位预分频逻辑

查询,中断,DMA传输模式

 

 

SPI操作

采用SPI接口, S3C2410X可发送/接收与外部设备同步的8位数据。一个串行时钟线与两条用来移位和采样信息的数据线同步。 SPI为主机时,发送频率可以通过为SPPREn寄存器设置合适的值来控制。你可以通过调整波特率数据寄存器的值来修改它的频率。当SPI为从机时,其它的主机提供时钟。当编程者向SPTDATn寄存器写字节数据时,SPI的收/发将会同时开始。在其它情况下,在向SPTDATn寄存器写入字节数据时要把nSS激活。

Read More...