-------木桶首先要能装水,再是能装多少水
KT人才公司总经理 胡运旺
在本人8年的IC人才猎头服务中,接触了上万IC行业的朋友,在交流中,谈得最多一个词是:Delay(延期)!某些环节细小的失误甚至失误都不能算的衔接问题,导致了产品一次又一次的delay。IC设计delay,生产运营delay,系统方案delay,市场推广delay,delay再delay!在接连不断的
delay中,各种资源白白浪费了,竞争对手起来了,目标客户跑掉了,市场丢失了!最后,公司的钱也没有了,可VC们不Delay却直接消失了!
这种大错没有小错不断到底是为什么呢?为什么会产生如此多的delay现象呢?
我认为,多数IC企业缺少一个串线的人!在芯片制造行业中,不同的工艺工序有上百种,因此设置了"串线工程师"的岗位(也叫工艺整合)。而在一个IC设计企业,同样也需要这样一个串线的人,叫产品线负责人(产品线经理),负责从IC市场需求开始,到IC的产品定义、算法设计、架构设计、前端设计、IC验证、模拟设计、版图/后端设计、流片、封装、测试、方案硬件与系统软件设计、市场、销售、FAE,甚至包括产品退出市场等完整过程的协调管理,即让IC从0到
1再到0的一个完全的协调人。这个协调人必须有能力和权限去协调本产品线所有相关部门,例如,人力、进度、生产资料等,确保产品计划的顺利、及时、正确地执行。
产品线负责人的岗位职责,具体如下:
1
全面负责从产品定义,商业计划,上下游部门界面管理,风险评估及对策到量产和市场导入的全过程。即市场,研发,生产到销售的全过程产品线运作负责人。
2 带领团队对控制和产品线研发和市场推广进程做合理决定。
3
项目执行中,根据预算,在公司内部或外部找到合理资源,解决项目进程节点的阻碍。
4 如果超出项目计划,及时做出变更或变通方案。保障项目进行。
5 在产品研发期,控制芯片研发到投放市场的过程中产品成本,质量和时间进程
6
在产品试生产期带领团队合理调整商业策略,优化可变成本,降低研发成本,提高利润率。
7
在市场导入过程中,做好客户群和供应商管理,综合评定客户优先级,确保重要客户的芯片供应和前期技术服务。
8 在产品销售过程中,积极参与下一代产品road map的制定。
什么样的人才适合做产品线负责人呢?
总体来说,这个人应该是个全才,是有眼光、有思想、有技术、有魅力的"四有""老人"。
1
这个人必须懂得系统,能够定义合理的架构,使设计更容易实现,使系统成本更具有竞争优势。
2
要懂设计。产品在研发过程中会遇到不同设计人员之间的协调问题。很多人在设计中往往只考虑自己做的模块,因此即使在设计中所有模块都做到性能最好,做出来的产品也不一定是最好的。就这需要互相的"妥协",在设计中叫做tradeoff。有句古话叫"适合的才是最好的",在IC设计这句话更重要。
3
要了解工艺和制程。产品线负责人要规划一个产品推向市场的时间,需要精确到每一个环节,要能选择合适的工艺和所需要的时间。另外,出现产品因为制造导致的问题,产品负责人需要跟生产方之间协调,不懂,如何谈?
4
要懂得市场和应用,根据市场制定合理的开发时间。能够在推广的过程中及时解决客户遇到的问题是把一个产品尽快推向市场的关键。
5
最重要的,就是良好的人际关系和个人魅力。在设计过程中遇到的问题会很多,往往是产品线负责人在背后推动,但是工程师不归你管理,难免遇到推三阻四的问题。良好的人际协调能力就显示出重要性了。
这个"串线"的产品线管理人对IC公司来说非常的重要。原因可以用木桶理论来说明。众所周知,"木桶原理"讲的是木桶由最短的木板来决定能装多少水。没错!但是,木桶能装水才是第一要素!木桶得能装水,然后,才是装多少水!什么原因会让木桶不能装水呢?
缝隙!
只要有缝隙,木桶就根本不能装水,更谈不上装多少水。一个组织中不同部门的不同岗位就好像是组成木桶的木板。让真正的木桶无缝隙还是比较容易的。但一个组织,由不同部门、不同岗位的一个个活生生的人组成,要达到"没有缝隙"是在太难!特别是对IC设计公司来说,几乎都是由高学历高智商的人才组成,达到无缝更加地难!
一颗芯片从开始市场调研到成功进入市场量产,都要经历从市场需求调研开始的10多种工序。如果没有负责产品线管理的人来做沟通协调,就必然出现太多的扯皮、太多的混乱,导致处处是问题,处处是缝隙!有了缝隙就需要人力与时间去弥补,去不断捉虫子、debug,由此进入不断的
delay再delay的恶性循环中!
产品线负责人如此重要,但为什么太多的中国IC公司没有配置呢?我认为主要有以下几方面的原因:
1
欧美公司没有培养出这样的中国本土IC人才。欧美公司几乎不会招聘中国本土人才来做产品线管理,因为欧美公司的这个职位需要衔接协调海外的部门,对英语要求太高!而海外的留学生也基本都在做技术开发,可以成为一个点的高手或者一块小木板的leader,但是几乎没有机会负责整个产品线的管理。
2
对产品线负责人来说,需要很宽的知识面,从市场机会、产品定义到IC设计、IC制造、系统方案,再到市场销售,整个环节都需要了解。中国IC大规模发展也才10年,这么短的时间内也很难培养出这样的全方位人才。
3
就产品线管理而言,对负责人的素养要求非常高,不但沟通协调能力要非常强,而且还要具有非常强的责任心、人格魅力和原则性等。夸张地说,就如同周总理管理20个部委一样,可见难度有多大!
4
中国的工程师大都崇尚技术而轻视管理,对技术不如自己的人,就不愿意接受其协调和管理,这也导致知识面宽而不精的产品线管理者无法顺利地开展工作。
5
在中国,由于职业道德和精神的缺位,这样的合格的产品线负责人,由于对每道"工序"都了解,太容易拉出一帮人另立山头了,因此许多中国本土IC公司的CEO们不敢招,也不敢用!
由此可见,目前市场上还难于找到这样合格的产品线负责人,本人8年中也就遇到几个而已,这个岗位的人才是中国目前最紧缺的人才。这或许也是目前中国IC设计公司无法配置这样职位的重要原因。
因此,在中国的IC公司,特别是规模小点的公司,没有配置专门的产品线负责人,基本就是CEO来亲自抓这个产品线管理。但CEO们"日理万机",在公司战略方向、产业链上下游关系处理特别是融资事情上,需要占用太多时间和精力,而产品线管理是个非常日常化的琐碎工作,需要通过不断地协调沟通去弥补无数的小缝隙,必然要花费相当多的时间精力,由此,CEO们怎么可能做得好!后果必然就是管不精也管不好!当然,中国的CEO们本身之前也几乎没有完整的产品线管理经验,知识面也不够宽,因此严重影响了产品线管理的执行力度,也就使得公司各部门处于不断的delay再delay中。
鉴于此,我认为中国IC设计公司应该抓紧培养产品线管理人才,选择沟通力强的、知识面宽的、经验相对丰富的一些项目经理来培养。另外,中国IC公司特别是抗风险能力较弱的中小型公司要敢于重用这样的人才,给予足够的权利、薪资及股份等,用好之,留住之,以便让CEO们能够抓大放小,将主要精力放在公司的未来战略和发展方面。只有培养出了合格的产品线负责人,产品的Delay就会减少了,就能够整合出没有缝隙的木桶,这样,中国IC设计公司才真正有前途!
2009年9月17日星期四
2009年9月16日星期三
Linux操作系统内核启动参数详细解析
Linux内核在启动的时候,能接收某些命令行选项或启动时参数。当内核不能识别某些硬件进而不能设置硬件参数或者为了避免内核更改某些参数的值,可以通过这种方式手动将这些参数传递给内核。
如果不使用启动管理器,比如直接从BIOS或者把内核文件用"cp zImage
/dev/fd0"等方法直接从设备启动,就不能给内核传递参数或选项--这也许是我们使用引导管理器比如LILO的好处之一吧。
Linux的内核参数是以空格分开的一个字符串列表,通常具有如下形式:
name[=value_1][,value_2]...[,value_10]
"name"是关键字,内核用它来识别应该把"关键字"后面的值传递给谁,也就是如何处理这个值,是传递给处理例程还是作为环境变量或者抛给"init"。值的个数限制为10,你可以通过再次使用该关键字使用超过10个的参数。
首先,内核检查关键字是不是 `root='',`nfsroot='', `nfsaddrs='', `ro'',
`rw'',`debug''或`init'',然后内核在bootsetups数组里搜索于该关键字相关联的已注册的处理函数,如果找到相关的已注册的处理函数,则调用这些函数并把关键字后面的值作为参数传递给这些函数。比如你在启动时设置参数name=a,b,c,d,内核搜索bootsetups数组,如果发现"name"已注册,则调用"name"的设置函数如name_setup(),并把a,b,c,d传递给name_setup()执行。
所有型如"name=value"参数,如果没有被上面所述的设置函数接收,将被解释为系统启动后的环境变量,比如"TERM=vt100"就会被作为一个启动时参数。所有没有被内核设置函数接收也没又被设置成环境变量的参数都将留给init进程处理,比如"single"。
常用的设备无关启动时参数。
1、init=...
设置内核执行的初始化进程名,如果该项没有设置,内核会按顺序尝试/etc/init,
/bin/init,/sbin/init, /bin/sh,如果所有的都没找到,内核会抛出 kernel
panic:的错误。
2、nfsaddrs=...
设置从网络启动时NFS的启动地址,已字符串的形式给出。
3、nfsroot=...
设置网络启动时的NFS根名字,如果该字符串不是以
"/"、","、"."开始,默认指向"/tftp-boot"。
以上2、3在无盘站中很有用处。
4、no387
该选项仅当定义了CONFIG_BUGi386时才能用,某些i387协处理器芯片使用32位的保护模式时会有BUG,比如一些浮点运算,使用这个参数可以让内核忽略387协处理器。
5、no-hlt
该选项仅当定义了CONFIG_BUGi386时才能用,一些早期的i486DX-100芯片在处理"hlt"指令时会有问题,执行该指令后不能可靠的返回操作系统,使用该选项,可以让Linux系统在CPU空闲的时候不要挂起CPU。
6、root=...
该参数告诉内核启动时使用哪个设备作为根文件系统。比如可以指定根文件为hda8:root=/dev/hda8。
7、ro和rw
ro参数告诉内核以只读方式加载根文件系统,以便进行文件系统完整性检查,比如运行fsck;rw参数告诉内核以读写方式加载根文件系统,这是默认值。
8、reserve=...
保留端口号。格
式:reserve=iobase,extent[,iobase,extent]...,用来保护一定区域的I/O端口不被设备驱动程序自动探测。在某些机器上,自动探测会失败,或者设备探测错误或者不想让内核初始化设备时会用到该参数;比如:
reserve=0x300,32device=0x300,除device=0x300外所有设备驱动不探测
0x300-0x31f范围的I/O端口。
9、mem=...
限制内核使用的内存数量。早期BIOS设计为只能识别64M以下的内存,如果你的内存数量大于64M,你可以指明,如果你指明的数量超过了实际安装的内存数量,系统崩溃是迟早的事情。
如:mem=0x1000000意味着有16M内存,如果是mem=0x6000000,就是96M内存了。
注意:很多机型把部分内存作为BIOS的映射,所以你在指定内存大小的时候一定要预留空间。你也可以在
pentium或者更新的CPU上使用mem=nopentium关闭4M的页表,这要在内核配置时申明。
10、panic=N
默认情况,内核崩溃--kernel panic
后会宕机而不会重启,你可以设置宕机多少秒之后重启机器;也可以在/proc/sys/kernel/panic文件里设置。
11、reboot=[warm|cold][,[bios|hard]]
该选项仅当定义了CONFIG_BUGi386时才能用。2.0.22的内核重启默认为cool
reboot,warm reboot 更快,使用"reboot=bios"可以继承bios的设置。
12、nosmp 和 maxcpus=N
仅当定义了
__SMP__,该选项才可用。可以用来禁用多CPU或者指明最多支持的CPU个数。
内核开发和调试的启动时参数
这些参数主要用在内核的开发和调试上,如果你不进行类似的工作,你可以简单的跳过本小节。
1、debug
Linux的日志级别比较多(详细信息可以参看Linux/kernel.h),一般地,日志的守护进程klogd只把比DEBUG级别高的日志写进磁盘;如果使用该选项,klogd也把内核的DEBUG信息写进日志。
2、profile=N
在做内核开发的时候,如果想清楚的知道内核在什么地方耗用了多少CPU的时钟周期,可以使用核心的分析函数设置变量prof_shift为非0值,有两种方式可以实现:一种是在编译时指定,另一种就是通过"profile="来指定;
他给出了一个相当于最小单位--即时钟周期;系统在执行内核代码的时候,profile[address
>;>; prof_shift]的值就会累加,你也可以从/proc/profile得到关于它的一些信息。
3、swap=N1,N2,N3,N4,N5,N6,N7,N8
设置内核交换算法的八个参
数:max_page_age, page_advance, page_decline,page_initial_age,
age_cluster_fract, age_cluster_min, pageout_weight,bufferout_weight。
4、buff=N1,N2,N3,N4,N5,N6
设置内核缓冲内存管理的六个参数:max_buff_age, buff_advance,
buff_decline,buff_initial_age, bufferout_weight, buffermem_grace。
使用 RAMDISK的参数
(仅当内核配置并编译了CONFIG_BLK_DEV_RAM)。一般的来说,使用ramdisk并不是一件好事,系统自己会更加有效的使用可用的内存;但是,在启动或者制作启动盘时,使用ramdisk可以很方便的装载软盘等设备上的映象(尤其是安装程序、启动过程中),因为在正真使用物理磁盘之前,必须要加载一些必要的模块,比如文件系统模块,scsi驱动等(可以参见我的initrd-x.x.x.img文件分析-制作安装程序不支持的根文件系统)。
早期的ramdisk(比如1.3.48的核心)是静态分配的,必须以ramdisk=N来指定ramdisk的大小;现在ramdisk可以动态增加。一共有四个参数,两个布尔型,两个整形。
1、load_ramdisk=N
如果N=1,就加载ramdisk;如果N=0,就不加载ramdisk;默认值为0。
2、prompt_ramdisk=N
N=1,提示插入软盘;N=0,不提示插入软盘;默认为1。
3、ramdisk_size=N或者ramdisk=N
设定ramdisk的最大值为N KB,默认为4096KB。
4、ramdisk_start=N
设置ramdisk的开始块号为N,当ramdisk有内核的映象文件是需要这个参数。
5、noinitrd
(仅当内核配置了选项CONFIG_BLK_DEV_RAM和CONFIG_BLK_DEV_INITRD)现在的内核都可以支持initrd了,引导进程首先装载内核和一个初始化的ramdisk,然后内核将initrd转换成普通的ramdisk,也就是读写模式的根文件系统设备。然后Linuxrc执行,然后装载真正的根文件系统,之后ramdisk被卸载,最后执行启动序列,比如/sbin/init。
选项noinitrd告诉内核不执行上面的步骤,即使内核编译了initrd,而是把initrd的数据写到
/dev/initrd,只是这是一个一次性的设备。
如果不使用启动管理器,比如直接从BIOS或者把内核文件用"cp zImage
/dev/fd0"等方法直接从设备启动,就不能给内核传递参数或选项--这也许是我们使用引导管理器比如LILO的好处之一吧。
Linux的内核参数是以空格分开的一个字符串列表,通常具有如下形式:
name[=value_1][,value_2]...[,value_10]
"name"是关键字,内核用它来识别应该把"关键字"后面的值传递给谁,也就是如何处理这个值,是传递给处理例程还是作为环境变量或者抛给"init"。值的个数限制为10,你可以通过再次使用该关键字使用超过10个的参数。
首先,内核检查关键字是不是 `root='',`nfsroot='', `nfsaddrs='', `ro'',
`rw'',`debug''或`init'',然后内核在bootsetups数组里搜索于该关键字相关联的已注册的处理函数,如果找到相关的已注册的处理函数,则调用这些函数并把关键字后面的值作为参数传递给这些函数。比如你在启动时设置参数name=a,b,c,d,内核搜索bootsetups数组,如果发现"name"已注册,则调用"name"的设置函数如name_setup(),并把a,b,c,d传递给name_setup()执行。
所有型如"name=value"参数,如果没有被上面所述的设置函数接收,将被解释为系统启动后的环境变量,比如"TERM=vt100"就会被作为一个启动时参数。所有没有被内核设置函数接收也没又被设置成环境变量的参数都将留给init进程处理,比如"single"。
常用的设备无关启动时参数。
1、init=...
设置内核执行的初始化进程名,如果该项没有设置,内核会按顺序尝试/etc/init,
/bin/init,/sbin/init, /bin/sh,如果所有的都没找到,内核会抛出 kernel
panic:的错误。
2、nfsaddrs=...
设置从网络启动时NFS的启动地址,已字符串的形式给出。
3、nfsroot=...
设置网络启动时的NFS根名字,如果该字符串不是以
"/"、","、"."开始,默认指向"/tftp-boot"。
以上2、3在无盘站中很有用处。
4、no387
该选项仅当定义了CONFIG_BUGi386时才能用,某些i387协处理器芯片使用32位的保护模式时会有BUG,比如一些浮点运算,使用这个参数可以让内核忽略387协处理器。
5、no-hlt
该选项仅当定义了CONFIG_BUGi386时才能用,一些早期的i486DX-100芯片在处理"hlt"指令时会有问题,执行该指令后不能可靠的返回操作系统,使用该选项,可以让Linux系统在CPU空闲的时候不要挂起CPU。
6、root=...
该参数告诉内核启动时使用哪个设备作为根文件系统。比如可以指定根文件为hda8:root=/dev/hda8。
7、ro和rw
ro参数告诉内核以只读方式加载根文件系统,以便进行文件系统完整性检查,比如运行fsck;rw参数告诉内核以读写方式加载根文件系统,这是默认值。
8、reserve=...
保留端口号。格
式:reserve=iobase,extent[,iobase,extent]...,用来保护一定区域的I/O端口不被设备驱动程序自动探测。在某些机器上,自动探测会失败,或者设备探测错误或者不想让内核初始化设备时会用到该参数;比如:
reserve=0x300,32device=0x300,除device=0x300外所有设备驱动不探测
0x300-0x31f范围的I/O端口。
9、mem=...
限制内核使用的内存数量。早期BIOS设计为只能识别64M以下的内存,如果你的内存数量大于64M,你可以指明,如果你指明的数量超过了实际安装的内存数量,系统崩溃是迟早的事情。
如:mem=0x1000000意味着有16M内存,如果是mem=0x6000000,就是96M内存了。
注意:很多机型把部分内存作为BIOS的映射,所以你在指定内存大小的时候一定要预留空间。你也可以在
pentium或者更新的CPU上使用mem=nopentium关闭4M的页表,这要在内核配置时申明。
10、panic=N
默认情况,内核崩溃--kernel panic
后会宕机而不会重启,你可以设置宕机多少秒之后重启机器;也可以在/proc/sys/kernel/panic文件里设置。
11、reboot=[warm|cold][,[bios|hard]]
该选项仅当定义了CONFIG_BUGi386时才能用。2.0.22的内核重启默认为cool
reboot,warm reboot 更快,使用"reboot=bios"可以继承bios的设置。
12、nosmp 和 maxcpus=N
仅当定义了
__SMP__,该选项才可用。可以用来禁用多CPU或者指明最多支持的CPU个数。
内核开发和调试的启动时参数
这些参数主要用在内核的开发和调试上,如果你不进行类似的工作,你可以简单的跳过本小节。
1、debug
Linux的日志级别比较多(详细信息可以参看Linux/kernel.h),一般地,日志的守护进程klogd只把比DEBUG级别高的日志写进磁盘;如果使用该选项,klogd也把内核的DEBUG信息写进日志。
2、profile=N
在做内核开发的时候,如果想清楚的知道内核在什么地方耗用了多少CPU的时钟周期,可以使用核心的分析函数设置变量prof_shift为非0值,有两种方式可以实现:一种是在编译时指定,另一种就是通过"profile="来指定;
他给出了一个相当于最小单位--即时钟周期;系统在执行内核代码的时候,profile[address
>;>; prof_shift]的值就会累加,你也可以从/proc/profile得到关于它的一些信息。
3、swap=N1,N2,N3,N4,N5,N6,N7,N8
设置内核交换算法的八个参
数:max_page_age, page_advance, page_decline,page_initial_age,
age_cluster_fract, age_cluster_min, pageout_weight,bufferout_weight。
4、buff=N1,N2,N3,N4,N5,N6
设置内核缓冲内存管理的六个参数:max_buff_age, buff_advance,
buff_decline,buff_initial_age, bufferout_weight, buffermem_grace。
使用 RAMDISK的参数
(仅当内核配置并编译了CONFIG_BLK_DEV_RAM)。一般的来说,使用ramdisk并不是一件好事,系统自己会更加有效的使用可用的内存;但是,在启动或者制作启动盘时,使用ramdisk可以很方便的装载软盘等设备上的映象(尤其是安装程序、启动过程中),因为在正真使用物理磁盘之前,必须要加载一些必要的模块,比如文件系统模块,scsi驱动等(可以参见我的initrd-x.x.x.img文件分析-制作安装程序不支持的根文件系统)。
早期的ramdisk(比如1.3.48的核心)是静态分配的,必须以ramdisk=N来指定ramdisk的大小;现在ramdisk可以动态增加。一共有四个参数,两个布尔型,两个整形。
1、load_ramdisk=N
如果N=1,就加载ramdisk;如果N=0,就不加载ramdisk;默认值为0。
2、prompt_ramdisk=N
N=1,提示插入软盘;N=0,不提示插入软盘;默认为1。
3、ramdisk_size=N或者ramdisk=N
设定ramdisk的最大值为N KB,默认为4096KB。
4、ramdisk_start=N
设置ramdisk的开始块号为N,当ramdisk有内核的映象文件是需要这个参数。
5、noinitrd
(仅当内核配置了选项CONFIG_BLK_DEV_RAM和CONFIG_BLK_DEV_INITRD)现在的内核都可以支持initrd了,引导进程首先装载内核和一个初始化的ramdisk,然后内核将initrd转换成普通的ramdisk,也就是读写模式的根文件系统设备。然后Linuxrc执行,然后装载真正的根文件系统,之后ramdisk被卸载,最后执行启动序列,比如/sbin/init。
选项noinitrd告诉内核不执行上面的步骤,即使内核编译了initrd,而是把initrd的数据写到
/dev/initrd,只是这是一个一次性的设备。
dm355压缩1027x768的视频
压缩的时候一开始会报错
@0x000a3d45:[T:0x40018CMEMK Error: Failed to find a pool which fits 2740224
070] venc - App-> Application started.
CMEM Error: getPool: Failed to get a pool fitting a size 2740224
@0x000a6b2b:[T:0x40018070] venc - ERROR: can't open mpeg4enc
@0x000a7176:[T:0x40018070] venc - app done.
root@192.168.1.222:/opt/dvsdk#
root@192.168.1.222:/opt/dvsdk# ./venc foreman
_vga_422i.yuv 2.mpeg4@0x000aea7a:[T:0x40018070] venc - main> venc
这是因为cmemk.ko分配的缓冲区太小导致的,在loadmodules.sh里将其改大
增加两个3M的pool
启动的时候会报错,说cmemk.ko占用了内核的内存空间,
在uboot内核参数中中将mem=116M
改成mem=109M即可,
正常的进行1024x768的视频压缩。
@0x000a3d45:[T:0x40018CMEMK Error: Failed to find a pool which fits 2740224
070] venc - App-> Application started.
CMEM Error: getPool: Failed to get a pool fitting a size 2740224
@0x000a6b2b:[T:0x40018070] venc - ERROR: can't open mpeg4enc
@0x000a7176:[T:0x40018070] venc - app done.
root@192.168.1.222:/opt/dvsdk#
root@192.168.1.222:/opt/dvsdk# ./venc foreman
_vga_422i.yuv 2.mpeg4@0x000aea7a:[T:0x40018070] venc - main> venc
这是因为cmemk.ko分配的缓冲区太小导致的,在loadmodules.sh里将其改大
增加两个3M的pool
启动的时候会报错,说cmemk.ko占用了内核的内存空间,
在uboot内核参数中中将mem=116M
改成mem=109M即可,
正常的进行1024x768的视频压缩。
DM355的启动方式
DM355有两种启动方式,是由BTSEL[1:0]引脚决定的
第一种是从片外的Asynchronous EMIF (AEMIF) 启动 是指从片外的三星OneNAND
器件启动
第二种方式是从片内的ROM启动,执行ROM中的ROM boot loader
(RBL),RBL支持三种片外介质,BTSEL决定RBL针对哪种介质进行启动
– BTSEL[1:0] = 00 - ARM NAND Boot
– BTSEL[1:0] = 10 - ARM MMC/SD Boot
– BTSEL[1:0] = 11 - ARM UART Boot
现在选择从片外的NAND启动,这种启动方式的具体步骤是RBL先从片外NAND上将UBL(user
boot loader)取进ARM内部的RAM中(copies a second stage user boot loader
(UBL) from NAND flash to ARM internal RAM (AIM) and transfers control to
the user-defined
UBL),然后执行,UBL进行的工作是从NAND中将剩下的数据取进DDR中并跳转到那里。
在NAND中存在两种代码,1是UBL,二是用户自己的代码APP,RBL是如何找到UBL的呢,原来对于RBL和APP在Nand中的存储必须符合一定的格式,在存储UBL或者APP代码的第一页是专门用来存储一个信息头,这个信息头的格式如下
/* Some of the parameters are modified runtime */
unsigned int ubldesc [] = {
0xA1ACED00, //Magic number
0x00000020, // Entry point for the UBL
0x00000007, // No. of pages for the UBL code
0x1, // Starting block of UBL in NAND
0x1 // Starting page of UBL in NAND
};
/* Some of the parameters are modified runtime */
unsigned int appdesc [] = {
0xB1ACED22, //Magic number
0x0000000A, // Start block in NAND
0x81080000, // Start address in DDR
0x81080000, // Entry point
0x00000200, // No. of pages for the complete Application
0x00000000 //compression flag
};
这个信息头分别包含了程序加载时的起始地址和入口点等等信息,当DM355复位时,片内ROM上的代码对NAND
CONTROLLER进行初始化并且在NAND中寻找UBL的Magic number
(事先已经约定好的),找到以后就根据信息头里提供的信息将UBL拷贝进片内RAM中(0x00000020,
// Entry point for the
UBL),然后进行执行,UBL的代码在光盘中有提供,其机制和RBL相同,只不过这个UBL是针对UBOOT的,如果不详执行UBOOT而是向执行自己的代码
那么需要将CCS编译出来的OUT文件转化成bin文件 下载到NAND中。
总结一下nand中存放的东西 UBL、uboot、LINUX的内核映像uimage、文件系统。
前两个的下载是用NAND_programmer进行,NAND_programmer的代码在光盘中也有,就是一段运行在DDR中的程序,将输入的UBL
和uboot文件加上信息头后存储到NAND中
后两个的下载用uboot就能实现。
第一种是从片外的Asynchronous EMIF (AEMIF) 启动 是指从片外的三星OneNAND
器件启动
第二种方式是从片内的ROM启动,执行ROM中的ROM boot loader
(RBL),RBL支持三种片外介质,BTSEL决定RBL针对哪种介质进行启动
– BTSEL[1:0] = 00 - ARM NAND Boot
– BTSEL[1:0] = 10 - ARM MMC/SD Boot
– BTSEL[1:0] = 11 - ARM UART Boot
现在选择从片外的NAND启动,这种启动方式的具体步骤是RBL先从片外NAND上将UBL(user
boot loader)取进ARM内部的RAM中(copies a second stage user boot loader
(UBL) from NAND flash to ARM internal RAM (AIM) and transfers control to
the user-defined
UBL),然后执行,UBL进行的工作是从NAND中将剩下的数据取进DDR中并跳转到那里。
在NAND中存在两种代码,1是UBL,二是用户自己的代码APP,RBL是如何找到UBL的呢,原来对于RBL和APP在Nand中的存储必须符合一定的格式,在存储UBL或者APP代码的第一页是专门用来存储一个信息头,这个信息头的格式如下
/* Some of the parameters are modified runtime */
unsigned int ubldesc [] = {
0xA1ACED00, //Magic number
0x00000020, // Entry point for the UBL
0x00000007, // No. of pages for the UBL code
0x1, // Starting block of UBL in NAND
0x1 // Starting page of UBL in NAND
};
/* Some of the parameters are modified runtime */
unsigned int appdesc [] = {
0xB1ACED22, //Magic number
0x0000000A, // Start block in NAND
0x81080000, // Start address in DDR
0x81080000, // Entry point
0x00000200, // No. of pages for the complete Application
0x00000000 //compression flag
};
这个信息头分别包含了程序加载时的起始地址和入口点等等信息,当DM355复位时,片内ROM上的代码对NAND
CONTROLLER进行初始化并且在NAND中寻找UBL的Magic number
(事先已经约定好的),找到以后就根据信息头里提供的信息将UBL拷贝进片内RAM中(0x00000020,
// Entry point for the
UBL),然后进行执行,UBL的代码在光盘中有提供,其机制和RBL相同,只不过这个UBL是针对UBOOT的,如果不详执行UBOOT而是向执行自己的代码
那么需要将CCS编译出来的OUT文件转化成bin文件 下载到NAND中。
总结一下nand中存放的东西 UBL、uboot、LINUX的内核映像uimage、文件系统。
前两个的下载是用NAND_programmer进行,NAND_programmer的代码在光盘中也有,就是一段运行在DDR中的程序,将输入的UBL
和uboot文件加上信息头后存储到NAND中
后两个的下载用uboot就能实现。
DM355的I2C调试
利用达盛的例程,pcf8574t开始老是报错:
DaVinci I2C WARNING: i2c: NACK detected
DaVinci I2C WARNING: i2c: RAR detected
这个报错是因为从设备没有反馈导致的,
后来发现是8574的地址写错了,导致I2C控制器老出现错误中断。
改正后测试I2C的SCL线的clock为400KHz。
为了和单片机连,需要降频。
修改drivers/i2c/buses/i2c-davinci.c文件
static int __init i2c_davinci_init(void)
{
int status;
struct device *dev = NULL;
DEB0("%s %s", __TIME__, __DATE__);
DEB1("i2c_davinci_init()");
/*
* NOTE: On DaVinci EVM, the i2c bus frequency is set to 20kHz
* so that the MSP430, which is doing software i2c, has
* some extra processing time
*/
if (machine_is_davinci_evm())
i2c_davinci_busFreq = 20;
else if (i2c_davinci_busFreq > 200)
i2c_davinci_busFreq = 400; /*Fast mode */
else
i2c_davinci_busFreq = 100; /*Standard mode */
i2c_clock = clk_get (dev, "I2CCLK");
}
DaVinci I2C WARNING: i2c: NACK detected
DaVinci I2C WARNING: i2c: RAR detected
这个报错是因为从设备没有反馈导致的,
后来发现是8574的地址写错了,导致I2C控制器老出现错误中断。
改正后测试I2C的SCL线的clock为400KHz。
为了和单片机连,需要降频。
修改drivers/i2c/buses/i2c-davinci.c文件
static int __init i2c_davinci_init(void)
{
int status;
struct device *dev = NULL;
DEB0("%s %s", __TIME__, __DATE__);
DEB1("i2c_davinci_init()");
/*
* NOTE: On DaVinci EVM, the i2c bus frequency is set to 20kHz
* so that the MSP430, which is doing software i2c, has
* some extra processing time
*/
if (machine_is_davinci_evm())
i2c_davinci_busFreq = 20;
else if (i2c_davinci_busFreq > 200)
i2c_davinci_busFreq = 400; /*Fast mode */
else
i2c_davinci_busFreq = 100; /*Standard mode */
i2c_clock = clk_get (dev, "I2CCLK");
}
DM355的UART调试
默认的内核中不支持Uart1,要在内核初始化时将它初始化。修改文件arch/arm/mach-davinci/board-dm355-evm.c,在函数board-init函数中增加如下红色部分
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_McBSP1, 1);
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_SPI, 1);
/* Turn on WatchDog timer LPSC. Needed for RESET to work */
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TIMER2, 1);
/*add uart1 by xujiaxin*/
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_UART1,1);
/*end add*/
davinci_serial_init(&serial_device);
davinci_writel(0x56837210, DAVINCI_VPSS_REGS_BASE + 0x810);
davinci_writel(0x7b3c0004, DAVINCI_VPSS_REGS_BASE + 0x814);
/*enable uart1 by jiaxinxu*/
ptr_pgmgt = (volatile int *)IO_ADDRESS(DAVINCI_UART1_BASE+0x30);
ptr_ier = (volatile int *)IO_ADDRESS(DAVINCI_UART1_BASE+0x4);
*ptr_pgmgt=0x0;
*ptr_ier =0x0;
int del;
for(del=0;del<100000;del++)
*ptr_pgmgt=0x6001;
/*end enable*/
运行rs232程序,一开始函数在发送0x0a时老是会先发送一个0x0d,后来在程序中加入下面两句话
/*RAW格式 否则会出错*/
options.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
options.c_oflag&=~OPOST;
就不会出错了。
board_setup_psc函数用来设置PSC模块,该模块的作用是开启某个模块的电源以及使能某个模块。
对UART2进行初始化的时候,必须注意UART2和SD1是复用的。没有改动前的内核初始化时自动的初始化SD1而不是UART2。需要进行一下几点动作才能将SD1的初始化屏蔽掉。
//choose uart2 instead of sd1 jiaxinxu
PINMUX3&=~0x0000ffff;
PINMUX3|= 0x0000a000;
将引脚功能置成UART2,
//conflict with uart2 by jiaxinxu
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_MMC_SD1, 0);
禁能PSC
#if defined(CONFIG_MMC_DAVINCI) || defined(CONFIG_MMC_DAVINCI_MODULE)
&mmc0_device,
//conflict with uart2 by jiaxinxu
//&mmc1_device,
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_McBSP1, 1);
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_SPI, 1);
/* Turn on WatchDog timer LPSC. Needed for RESET to work */
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TIMER2, 1);
/*add uart1 by xujiaxin*/
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_UART1,1);
/*end add*/
davinci_serial_init(&serial_device);
davinci_writel(0x56837210, DAVINCI_VPSS_REGS_BASE + 0x810);
davinci_writel(0x7b3c0004, DAVINCI_VPSS_REGS_BASE + 0x814);
/*enable uart1 by jiaxinxu*/
ptr_pgmgt = (volatile int *)IO_ADDRESS(DAVINCI_UART1_BASE+0x30);
ptr_ier = (volatile int *)IO_ADDRESS(DAVINCI_UART1_BASE+0x4);
*ptr_pgmgt=0x0;
*ptr_ier =0x0;
int del;
for(del=0;del<100000;del++)
*ptr_pgmgt=0x6001;
/*end enable*/
运行rs232程序,一开始函数在发送0x0a时老是会先发送一个0x0d,后来在程序中加入下面两句话
/*RAW格式 否则会出错*/
options.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
options.c_oflag&=~OPOST;
就不会出错了。
board_setup_psc函数用来设置PSC模块,该模块的作用是开启某个模块的电源以及使能某个模块。
对UART2进行初始化的时候,必须注意UART2和SD1是复用的。没有改动前的内核初始化时自动的初始化SD1而不是UART2。需要进行一下几点动作才能将SD1的初始化屏蔽掉。
//choose uart2 instead of sd1 jiaxinxu
PINMUX3&=~0x0000ffff;
PINMUX3|= 0x0000a000;
将引脚功能置成UART2,
//conflict with uart2 by jiaxinxu
board_setup_psc(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_MMC_SD1, 0);
禁能PSC
#if defined(CONFIG_MMC_DAVINCI) || defined(CONFIG_MMC_DAVINCI_MODULE)
&mmc0_device,
//conflict with uart2 by jiaxinxu
//&mmc1_device,
DM355的SD卡虚拟成U盘
将USB的驱动配置成设备模式。连接电脑后自动将SD卡识别成逻辑盘。
内核编译配置如usb. Txt内容。
在/etc/init.d/rcS中加入初始化语句。
insmod musb_hdrc.ko
insmod g_file_storage.ko file=/dev/mmcblk0p1
一开始插上USB以后老是显示无法初始化硬件,是因为USB小板上将D+和D-画反了
遇到的问题:
1.在拍照的过程中,拍摄100幅照片,第一次将USB插到主机上,会显示这100幅照片的大小都是0;但是在板子上输入ls –al /mnt/sdcard看 大小都是15.8K,是正确的。第二次插上USB以后有可能会有一些图像变正确,大小变为15.8K并且可以打开。其他的一些图像就坏掉了。
2.后来对这个问题进行进一步的研究,在不加载USB驱动的情况下拍摄100幅照片,拍摄完成后在串口终端上将SD卡上的数据拷贝到NFS上,再从Linux虚拟机下拷贝到windows上,看图片都是正确的,在串口终端上输入ls –al /mnt/sdcard看 大小都是15.8K。板子断电,拔下SD卡,通过读卡器插到pc机上,在windows下浏览,结果也都是正常。但是如果不进行上述的拷贝工作,只有一副照片m1.jpeg是正常的(随机的有可能其他几个是正常的,但不是所有的都正常),其他的都是0k。将SD卡再插回板子,上电再执行ls –al /mnt/sdcard,发现只有m1.jpeg是正常的,其他的都是0k。
内核编译配置如usb. Txt内容。
在/etc/init.d/rcS中加入初始化语句。
insmod musb_hdrc.ko
insmod g_file_storage.ko file=/dev/mmcblk0p1
一开始插上USB以后老是显示无法初始化硬件,是因为USB小板上将D+和D-画反了
遇到的问题:
1.在拍照的过程中,拍摄100幅照片,第一次将USB插到主机上,会显示这100幅照片的大小都是0;但是在板子上输入ls –al /mnt/sdcard看 大小都是15.8K,是正确的。第二次插上USB以后有可能会有一些图像变正确,大小变为15.8K并且可以打开。其他的一些图像就坏掉了。
2.后来对这个问题进行进一步的研究,在不加载USB驱动的情况下拍摄100幅照片,拍摄完成后在串口终端上将SD卡上的数据拷贝到NFS上,再从Linux虚拟机下拷贝到windows上,看图片都是正确的,在串口终端上输入ls –al /mnt/sdcard看 大小都是15.8K。板子断电,拔下SD卡,通过读卡器插到pc机上,在windows下浏览,结果也都是正常。但是如果不进行上述的拷贝工作,只有一副照片m1.jpeg是正常的(随机的有可能其他几个是正常的,但不是所有的都正常),其他的都是0k。将SD卡再插回板子,上电再执行ls –al /mnt/sdcard,发现只有m1.jpeg是正常的,其他的都是0k。
解决办法:linux下,向磁盘写入数据会先将数据缓存在内存里,系统在合适的时候再将数据从内存中写到磁盘里。所以SD卡拔下之前要运行sync命令,保证内存中的数据完全写入磁盘里
订阅:
博文 (Atom)