以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除。

一、uboot和内核的实质

1、uboot是一个裸机程序

  • uboot的本质就是一个复杂点的裸机程序;

2、内核是一个裸机程序

  • 操作系统内核也是一个裸机程序,和其他裸机程序并没有本质区别。
  • 区别是:操作系统运行起来后在软件上分为内核层和应用层。分层后两层的权限不同,内存访问和设备操作的管理上更加精细(内核可以随便访问各种硬件,而应用程序只能被限制的访问硬件和内存地址)。

3、均部署在SD卡中特定分区内

(1)一个完整的软件+硬件的嵌入式系统

  • 静止时,bootloader、kernel、rootfs等都以镜像的形式存储在启动介质中(X210中是iNand/SD卡)。
  • 运行时,都是在DDR内存中运行的,与存储介质无关。
  • 从静止态到运行态的过程,即启动过程。

(2)动态启动过程

  • 一个从SD卡逐步搬移到DDR内存,并且运行启动代码进行相关的硬件初始化和软件架构的建立,最终达到运行时稳定状态的过程。

(3)静止时u-boot.bin,zImage,rootfs都在SD卡中

  • 不能随意存在于SD卡的任意位置;
  • 因此需要对SD卡进行一个分区,然后将各种镜像各自存在各自的分区中,这样在启动过程中uboot、内核等就知道到哪里去找谁;
  • uboot和kernel中的分区表必须一致,同时和SD卡的实际使用的分区要一致。

4、两者运行时,都必须先加载到DDR中链接地址处

(1)uboot在第一阶段中进行重定位时,将第二阶段(整个uboot镜像)加载到DDR的0xc3e00000地址处,这个地址就是uboot的链接地址。

(2)内核也有类似要求,uboot启动内核时将内核从SD卡读取放到DDR中(也是个重定位的过程),不能随意放置,必须放在内核的链接地址处,否则启动不起来。(这个见内核移植部分,因为解压缩地址不是内核的链接地址,因此没有正确解压缩,内核运行不起来)

  • 譬如我们使用的内核链接地址是0x30008000。

5、内核启动需要必要的启动参数

(1)uboot是无条件启动的,从零开始启动的;

(2)内核不能自动完全从零开始启动,需要uboot帮忙。

  • uboot要帮助内核实现重定位(从SD卡到DDR),uboot还要给内核提供启动参数。

二、为什么要有uboot?

1、计算机系统的主要部件

  • 典型的计算机系统有:PC机(台式机+笔记本)、嵌入式设备(手机、平板电脑、游戏机)、单片机(家用电器像电饭锅、空调);
  • 所有的计算机系统运行时需要的主要核心部件都是3个东西:CPU + 外部存储器(Flash/硬盘) + 内部存储器(DDR SDRAM/SDRAM/SRAM)

2、PC机的启动过程

  • 典型的PC机的部署:BIOS程序部署在PC机主板上(随主板出厂时已经预制了),操作系统部署在硬盘上,内存在掉电时无作用,CPU在掉电时不工作。
  • 启动过程:PC上电后先执行BIOS程序(实际上PC的BIOS就是NorFlash),BIOS程序负责初始化DDR内存,负责初始化硬盘,然后从硬盘上将OS镜像读取到DDR中,然后跳转到DDR中去执行OS直到启动(OS启动后BIOS就无用了)。

3、典型嵌入式linux系统启动过程

  • 典型嵌入式系统的部署:uboot程序部署在Flash(能作为启动设备的Flash)上,OS部署在FLash(嵌入式系统中用Flash代替硬盘)上、内存在掉电时无作用,CPU在掉电时不工作。
  • 启动过程:嵌入式系统上电后先执行uboot、然后uboot负责初始化DDR,初始化Flash,然后将OS从Flash中读取到DDR中,然后启动OS(OS启动后uboot就无用了)

4、总结

  • 嵌入式系统和PC机的启动过程几乎没有两样,只是BIOS成了uboot,硬盘成了Flash。

5、android系统启动过程

  • android系统的启动和linux系统(前面讲的典型的嵌入式系统启动)几乎一样,只是在内核启动后加载根文件系统后不同了。
  • 可以认为启动分为2个阶段:第一个阶段是uboot到OS启动;第二个阶段是OS启动后到rootfs加载到命令行执行。
  • 现在我们主要研究第一个阶段,android的启动和linux的差别在第二阶段。

6、uboot的作用

  • uboot主要作用是用来启动操作系统内核。
  • uboot还要负责部署整个计算机系统。
  • uboot中还有操作Flash等板子上硬盘的驱动。
  • uboot还得提供一个命令行界面供人来操作。

三、为什么是uboot?

1、uboot从哪里来的?

  • uboot是SourceForge上的开源项目。
  • uboot项目的作者:一个德国人最早发起的项目。
  • uboot就是由一个人发起,然后由整个网络上所有感兴趣的人共同维护发展而来的一个bootloader。

2、uboot的发展历程

  • 自己使用的小开源项目。
  • 被更多人认可使用。
  • 被SoC厂商默认支持。
  • uboot经过多年发展,已经成为事实上的业内bootloader标准。现在大部分的嵌入式设备都会默认使用uboot来做为bootloader。

3、uboot的版本号问题

  • 早期的uboot的版本号类似于这样:uboot1.3.4,后来版本号便成了类似于uboot-2010.06。
  • uboot的核心部分几乎没怎么变化,越新的版本支持的开发板越多而已,对于一个老版本的芯片来说,新旧版本的uboot并没有差异。

4、uboot的可移植性的正确理解

  • uboot就是universal bootloader(通用的启动代码),通用的意思就是在各种地方都可以用,所以说uboot具有可移植性。
  • uboot具有可移植性并不是说uboot在哪个开发板都可以随便用,而是说uboot具有在源代码级别的移植能力,可以针对多个开发板进行移植。

四、uboot必须解决哪些问题

1、自身可开机直接启动

  • 一般的SoC都支持多种启动方式,譬如SD卡启动、NorFlash启动、NandFlash启动等。
  • uboot要能够开机启动,必须根据具体的SoC的启动设计来设计uboot。
  • uboot必须进行和硬件相对应的代码级别的更改和移植,才能够保证可以从相应的启动介质启动。
  • uboot中第一阶段的start.S文件中具体处理了这一块。

2、能够引导操作系统内核启动并给内核传参

  • uboot的终极目标就是启动内核。
  • linux内核在设计的时候,设计为可以被传参。我们可以在uboot中事先给linux内核准备一些启动参数,放在内存中特定位置然后传给内核,内核启动后会到这个特定位置去取这些参数,然后在内核中解析这些参数,这些参数将被用来指导linux内核的启动过程。

3、能提供系统部署功能

  • uboot必须能够(被人借助而)完成整个系统(包括uboot、kernel、rootfs等的镜像)在Flash上的烧录下载工作。
  • 裸机教程中刷机(ARM裸机第三部分)就是利用uboot中的fastboot功能将各种镜像烧录到iNand中,然后从iNand启动。

4、能进行soc级和板级硬件管理

  • uboot中实现了一部分硬件的控制能力(即uboot中初始化了一部分硬件),因为uboot为了完成一些任务必须让这些硬件工作。
  • 譬如uboot要实现刷机必须能驱动iNand,譬如uboot要在刷机时LCD上显示进度条就必须能驱动LCD,譬如uboot能够通过串口提供操作界面就必须驱动串口。譬如uboot要实现网络功能就必须驱动网卡芯片。
  • SoC级(譬如串口)就是SoC内部外设,板级就是SoC外面开发板上面的硬件(譬如网卡、iNand)

5、uboot的生命周期

  • uboot的生命周期,指uboot什么时候开始运行,什么时候结束运行。
  • uboot本质上是一个裸机程序(不是操作系统),一旦uboot开始SoC就会单纯运行uboot,别的程序是不可能同时运行的,一旦uboot结束运行则无法再回到uboot。
  • uboot的入口是开机自动启动,uboot的唯一出口就是启动内核。
  • uboot还可以执行很多别的任务(譬如烧录系统),一般任务执行完后都可以回到uboot的命令行,但启动内核命令一旦执行就回不来了。

五、uboot的工作方式

1、从裸机程序镜像uboot.bin说起

  • uboot的本质就是一个裸机程序,和我们裸机全集中写的那些裸机程序xx.bin并没有本质区别。如果非说要有区别,那就是:我们写的大部分小于16KB,而uboot大于16KB(一般uboot在180k-400k之间)。
  • uboot本身是一个开源项目,由若干个.c文件和.h文件组成,配置编译之后会生成一个uboot.bin,这就是uboot这个裸机程序的镜像文件。然后这个镜像文件被合理的烧录到启动介质中拿给SoC去启动。也就是说uboot在没有运行时表现为uboot.bin,一般躺在启动介质中。
  • uboot运行时会被加载到内存中然后一条指令一条指令的拿给CPU去运行。

2、uboot的命令式shell界面

  • 普通的裸机程序运行起来就直接执行了,执行时效果和代码有关。
  • 有些程序需要和人进行交互,于是程序中就实现了一个shell(shell就是提供人机交互的一个界面),uboot就实现了一个shell。
  • 注意:shell并不是操作系统,和操作系统一点关系都没有。linux中打开一个终端后就得到了一个shell,可以输入命令回车执行。uboot中的shell工作方式和linux中的终端shell非常像(其实几乎是一样的,只是命令集不一样。譬如linux中可以ls,uboot中ls就不识别)

3、掌握uboot使用的2个关键点:命令和环境变量

  • uboot启动后大部分时间和工作都是在shell下完成的(譬如uboot部署系统要在shell下输命令、要设置环境变量也得在命令行下,要启动内核也要在命令行敲命令)
  • 命令就是uboot的shell中可以识别的各种命令。uboot中有几十个命令,其中有一些常用另一些不常用(我们还可以自己给uboot添加命令)。
  • uboot的环境变量和操作系统的环境变量工作原理和方式几乎完全相同。uboot在设计时借助了操作系统的设计理念(命令行工作方式借鉴了linux终端命令行,环境变量借鉴了操作系统的环境变量,uboot的驱动管理几乎完全照抄了linux的驱动框架)。
  • 环境变量可以被认为是系统的全局变量,环境变量名都是系统内置的(认识就认识,不认识就不认识,这部分是系统自带的默认的环境变量,譬如PATH;但是也有一部分环境变量是自己添加的,自己添加的系统就不认识但是我们自己认识)。系统或者我们自己的程序在运行时可以通过读取环境变量来指导程序的运行。这样设计的好处就是灵活,譬如我们要让一个程序更改运行方法,不用去重新修改程序代码再重新编译运行,而只要修改相应的环境变量就可以了。
  • 环境变量就是运行时的配置属性。

六、uboot的常用命令

1、类似linux终端的行缓冲命令行

  • 当我们向终端命令行输入命令的时候,这些命令没有立即被系统识别,而是被缓冲到一个缓存区(也就是系统认为我们还没有输入完),当我们按下回车键(换行)后系统就认为我们输入完了,然后将缓冲区中所有刚才输入的作为命令拿去分析处理。
  • linux终端设计有3种缓冲机制:无缓冲、行缓冲、全缓冲

2、有些命令有简化的别名

  • 譬如printenv命令可以简化为print,譬如setenv可以简化为set

3、有些命令会带参数(注意格式是固定的)

  • uboot的每个命令都有事先规定好的各种格式。有些命令就是不带参数的,譬如printenv/print命令;有些命令带可选的参数(可以带也可以不带,当然带不带参数的执行结果是不同的);有些命令带必须的参数(譬如setenv/set命令)

4、命令中的特殊符号(譬如单引号)

  • uboot的有些命令带的参数非常长,此时使用单引号把参数引起来。

5、有些命令是一个命令族(譬如movi)

  • 命令族意思就是好多个命令开头都是用同一个命令关键字的,但是后面的参数不一样,这些命令的功能和作用也不同。这就叫一个命令族。
  • 同一个命令族中所有的命令都有极大的关联,譬如movi开头的命令族都和moviNand(EMMC、iNand)操作有关。

6、第一个命令:printenv/print

  • print命令不用带参数,作用是打印出系统中所有的环境变量。
  • 环境变量就好像程序的全局变量一样。程序中任何地方都可以根据需要去调用或者更改环境变量(一般都是调用),环境变量和全局变量不同之处在于:全局变量的生命周期是在程序的一次运行当中,开始运行时诞生程序结束时死亡,下次运行程序时从头开始;但是环境变量被存储在Flash的另一块专门区域(Flash上有一个环境变量分区),一旦我们在程序中保存了该环境变量,那么下次开机时该环境变量的值将维持上一次更改保存后的值。

7、设置(添加/更改)环境变量:setenv/set

  • 用法:set name value

8、保存环境变量的更改:saveenv/save

  • saveenv/save命令不带参数,直接执行,作用是将内存中的环境变量的值同步保存到Flash中环境变量的分区。
  • 注意:环境变量的保存是整体的覆盖保存,也就是说内存中所有的环境变量都会整体的将Flash中环境变量分区中原来的内容整体覆盖。
  • 彻底更改一个环境变量的值,需要2步:第一步set命令来更改内存中的环境变量,第二步用save命令将其同步到Flash中环境变量的分区。

9、网络测试指令:ping

  • 命令用法: ping ip地址
  • 注意:ping是测试开发板和主机之间的网络链接。

10、tftp下载指令:tftp

(1)uboot主要目标是启动内核,为了完成启动内核必须要能够部署内核,uboot为了部署内核就需要将内核镜像从主机中下载过来然后烧录到本地flash中。uboot如何从主机(windows或者虚拟机ubuntu)下载镜像到开发板上?有很多种方式,主流方式是:fastboot和tftp。

  • fastboot的方式是通过USB线进行数据传输。
  • tftp的方式是通过有线网络的。典型的方式就是通过网络,fastboot是近些年才新发展的。

(2)tftp方式下载时实际上uboot扮演的是tftp客户端程序角色,主机windows或虚拟机ubuntu中必须有一个tftp服务器,然后将要下载的镜像文件放在服务器的下载目录中,然后开发板中使用uboot的tftp命令去下载即可。

(3)虚拟机搭建的时候设置的tftp下载目录是/tftpboot,将要被下载的镜像复制到这个目录下。

(4)检查开发板uboot的环境变量,注意serverip必须设置为虚拟机ubuntu的ip地址。(serverip这个环境变量的意义就是主机tftp服务器的ip地址)

(5)然后在开发板的uboot下先ping通虚拟机ubuntu,然后再尝试下载:tftp 0x30000000 zImage-qt

  • 意思是将服务器上名为zImage-qt的文件下载到开发板内存的0x30000000地址处。

(6)镜像下载到开发板的DDR中后,uboot就可以用movi指令进行镜像的烧写了。

11、nfs启动内核命令:nfs

12、SD卡/iNand操作指令movi

(1)开发板如果用SD卡/EMMC/iNand等作为Flash,则在uboot中操作flash的指令为movi(或mmc)

(2)movi指令是一个命令集,有很多子命令,具体用法可以help movi查看。

(3)movi的指令都是movi read和movi write一组的

  • movi read用来读取iNand到DDR上,movi write用来将DDR中的内容写入iNand中。
  • 理解这些指令时一定要注意涉及到的2个硬件:iNand和DDR内存。

(4)movi read  {u-boot | kernel} {addr}

  • 这个命令使用了一种通用型的描述方法来描述:movi 和 read外面没有任何标记说明每一次使用这个指令都是必选的;一对大括号{}括起来的部分必选1个,大括号中的竖线表是多选一。中括号[]表示可选参数(可以有也可以没有)
  • 譬如 movi read u-boot 0x30000000,意思就是把iNand中的u-boot分区读出到DDR的0x30000000起始的位置处。
  • uboot代码中将iNand分成了很多个分区,每个分区有地址范围和分区名,uboot程序操作中可以使用直接地址来操作iNand分区,也可以使用分区名来操作分区。
  • 注意这里的0x30000000也可以直接写作30000000,意思是一样的(uboot的命令行中所有数字都被默认当作十六进制处理,不管你加不加0x都一样)。

13、NandFlash操作指令nand

  • 理解方法和操作方法完全类似于movi指令

14、内存操作指令:mm、mw、md

  • DDR中是没有分区的(只听说过对硬盘、Flash进行分区,没听说过对内存进行分区……),但是内存使用时要注意,千万不能越界踩到别人了。
  • 因为uboot是一个裸机程序,不像操作系统会由系统整体管理所有内存,系统负责分配和管理,系统会保证内存不会随便越界。
  • uboot并不管理所有内存,内存是散的随便用的,所以如果使用uboot的人不注意就可能出现自己把自己的数据给覆盖了。
  • md就是memory display,用来显示内存中的内容。
  • mw就是memory write,将内容写到内存中
  • mm就是memory modify,修改内存中的某一块,说白了还是写内存(如果需要批量的逐个单元的修改内存,用mm最合适)

15、启动内核指令:bootm、go

  • uboot的终极目标就是启动内核,启动内核在uboot中表现为一个指令,uboot命令行中调用这个指令就会启动内核(不管成功与否,所以这个指令是一条死路)。
  • 差别:bootm启动内核同时给内核传参,而go命令启动内核不传参。
  • bootm其实才是正宗的启动内核的命令,一般情况下都用这个。
  • go命令本来不是专为启动内核设计的,go命令内部其实就是一个函数指针指向一个内存地址然后直接调用那个函数,go命令的实质就是PC直接跳转到一个内存地址去运行而已。
  • go命令可以用来在uboot中执行任何的裸机程序(有一种调试裸机程序的方法就是事先启动uboot,然后在uboot中去下载裸机程序,用go命令去执行裸机程序)。

七、uboot的常用环境变量

1、如何理解环境变量?

2、环境变量如何参与程序运行?

  • 环境变量有2份,一份在Flash中,另一份在DDR中。uboot开机时一次性从Flash中读取全部环境变量到DDR中作为环境变量的初始化值,然后使用过程中都是用DDR中这一份,用户可以用saveenv指令将DDR中的环境变量重新写入Flash中去更新Flash中环境变量。下次开机时又会从Flash中再读一次。
  • 环境变量在uboot中是用字符串表示的,也就是说uboot是按照字符匹配的方式来区分各个环境变量的。因此用的时候一定要注意不要打错字了。

3、自动运行倒数时间:bootdelay

4、网络设置:ipaddr serverip ……

(1)ipaddr是开发板的本地IP地址

(2)serverip是开发板通过tftp指令去tftp服务器下载东西时,tftp服务器的IP地址。

(3)gatewayip是开发板的本地网关地址

(4)netmask是子网掩码

(5)ethaddr是开发板的本地网卡的MAC地址。

5、自动运行命令设置:bootcmd

(1)uboot启动后会开机自动倒数bootdelay秒,如果没有人按下回车打断启动,则uboot会自动执行启动命令来启动内核。

(2)uboot开机自动启动时实际就是在内部执行了bootcmd这个环境变量的值所对应的命令集。

(3)bootcmd=movi read kernel 30008000; bootm 30008000

  • 意思是:将iNand的kernel分区读取到DDR内存的0x30008000地址处,然后使用bootm启动命令从内存0x30008000处去启动内核。
  • set bootcmd printenv,然后saveenv;然后重启则会看到启动倒数后自动执行printenv命令打印出环境变量。这个小实验说明开机自动执行了bootcmd。

6、uboot给kernel传参:bootargs

(1)linux内核启动时可以接收uboot传递的启动参数,这些启动参数是uboot和内核约定好的形式、内容,linux内核在这些启动参数的指导下完成启动过程。

(2)我们要做的事情就是:在uboot的环境变量中设置bootargs,然后bootm命令启动内核时会自动将bootargs传给内核。

(3)bootargs=console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3意义解释:

  • console=ttySAC2,115200 ,控制台使用串口2,波特率115200
  • root=/dev/mmcblk0p2 rw,根文件系统在SD卡端口0设备(iNand)第2分区,根文件系统是可读可写的
  • init=/linuxrc,linux的进程1(init进程)的路径
  • rootfstype=ext3,根文件系统的类型是ext3

(4)内核传参非常重要。在内核移植的时候,新手经常因为忘记给内核传参,或者给内核传递的参数不对,造成内核启动不起来。

7、新建、更改、删除一个环境变量的方法

(1)新建一个环境变量,使用set var value

(2)更改一个环境变量,使用set var value

(3)删除一个环境变量,使用set var

八、uboot中对Flash和DDR的管理

1、uboot阶段Flash的分区

(1)所谓分区,就是说对Flash进行分块管理。

(2)PC机等产品中,因为大家都是在操作系统下使用硬盘的,整个硬盘由操作系统统一管理,操作系统会使用文件系统帮我们管理硬盘空间。(管理保证了文件之间不会互相堆叠),使用者不用自己太过在意分区问题。

(3)在uboot中没有操作系统,因此我们对Flash(相当于硬盘)的管理必须事先使用分区界定

  • 实际上在uboot中和kernel中都有个分区表,分区表就是我们在做系统移植时对Flash的整体管理分配方法。
  • 有了这个界定后,我们在部署系统时按照分区界定方法来部署,uboot和kernel的软件中也是按照这个分区界定来工作,就不会错。

(4)分区方法不是一定的,不是固定的,是可以变动的。但是在一个移植中必须事先设计好定死,一般在设计系统移植时就会定好,定的标准是:

  • uboot必须从Flash起始地址开始存放(也许是扇区0,也许是扇区1,也许是其他,取决于SoC的启动设计);
  • uboot分区的大小必须保证uboot肯定能放下,一般设计为512KB或者1MB(因为一般uboot肯定不足512KB,给再大其实也可以工作,但是浪费);
  • 环境变量:环境变量分区一般紧贴着uboot来存放,大小为32KB或者更多一点。
  • kernel:kernel可以紧贴环境变量存放,大小一般为3MB或5MB或其他。
  • rootfs:······
  • 剩下的就是自由分区,一般kernel启动后将自由分区挂载到rootfs下使用

(5)总结

  • 各分区彼此相连,前面一个分区的结尾就是后一个分区的开头。
  • 整个flash充分利用,从开头到结尾。
  • uboot必须在Flash开头,其他分区相对位置是可变的。
  • 各分区的大小由系统移植工程师自己来定,一般定为合适大小(不能太小,太小了容易溢出;不能太大,太大了浪费空间)
  • 分区在系统移植前确定好,在uboot中和kernel中使用同一个分区表。将来在系统部署时和系统代码中的分区方法也必须一样。

2、uboot阶段DDR的分区

(1)DDR的分区和Flash的分区不同,主要是因为Flash是掉电存在的,而DDR是掉电消失,因此可以说DDR是每次系统运行时才开始部署使用的。

(2)内存的分区主要是在linux内核启动起来之前,linux内核启动后内核的内存管理模块会接管整个内存空间,那时候就不用我们来管了。

(3)内存分区关键在于,内存中哪一块用来干什么必须分配好,以避免各个不同功能使用了同一块内存造成的互相踩踏。

  • 譬如说我们tftp 0x23E00000 zImage去下载zImage到内存的0x23E00000处就会出错,因为这个内存处实际是uboot的镜像所在。这样下载会导致下载的zImage把内存中的uboot给冲掉。

uboot的一般性介绍相关推荐

  1. dm365启动分析以及RBL、UBL、Uboot的简单介绍

    dm365启动方式有许多种,我们的板子上面有一个拨码开关,EM_A[13:11]用来选择启动方式,参照tm320dm365的原理图,启动方式有: EM_A[13:11] BOOT from 000 R ...

  2. uboot之fdt介绍

    [uboot] (番外篇)uboot之fdt介绍 2016年11月17日 20:36:11 阅读数:2933 以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为例 ...

  3. 嵌入式Linux开发-uboot常用命令介绍(上篇)

    1. 前言 U-boot是一种开源bootloader, 作用是用来引导操作,以及给开发人员提供测试调试工具.本身算是个精简的Linux系统,主要是负责硬件的初始化和引导,本身带有一些工具,作为引导程 ...

  4. u-boot FIT image介绍

    1. 前言 Linux kernel在ARM架构中引入device tree(全称是flattened device tree,后续将会以FDT代称)的时候[1],其实怀揣了一个Unify Kerne ...

  5. [uboot] (番外篇)uboot之fdt介绍

    以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为例 [uboot] uboot流程系列: [project X] tiny210(s5pv210)上电启动流程( ...

  6. Davinci及U-boot的一些介绍

    TI推出的数字多媒体平台DM系列,集成了ARM与DSP双核处理器:DSP处理器运行DSP/BIOS操作系统,负责音视频编解码算法以及其他图形处理算法:ARM处理器运行MontaVista Linux操 ...

  7. (一) u-boot 基本介绍

    ▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ 分享一个大神朋友的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到 ...

  8. 6-uboot relocation介绍

    [uboot] (番外篇)uboot relocation介绍 2016年11月05日 21:29:22 阅读数:1844 以下例子都以project X项目tiny210(s5pv210平台,arm ...

  9. UBOOT手动设置环境变量

    Arm板系统文件一般有三个--bootloader(uboot).kernel(uImage)及根文件系统(rootfs). 在arm板上电后,按uboot->kernel->rootfs ...

最新文章

  1. vue.js created函数注意事项
  2. 芬兰开放“线上AI速成班”课程,全球网民均可免费观看
  3. boost::histogram::histogram::fill用法的测试程序
  4. Web前端开发笔记——第二章 HTML语言 第一节 标签、元素、属性
  5. 洪水同频率放大的方法_我们应该怎么选择放大器配件?
  6. autosar网络管理_AP AUTOSAR平台设计(11)——网络管理
  7. Picasso遇到的坑
  8. JAVA 的StringBuffer类
  9. mrc20温控f1什么意思_精确率、召回率、F1 值、ROC、AUC 各自的优缺点是什么?
  10. 泰山游记:晚上爬并无乐趣,什么也看不到
  11. web中使用阿里巴巴矢量库作为图标管理
  12. android视图编辑器,任何未出现在android studio编辑器中的视图
  13. 基于STM32F429,Cubemx的SAI音频播放实验
  14. 基于ROS的机器人模型建立及3D仿真【物理/机械意义】
  15. “换头术”所引发的“长生不死”
  16. 班级小工具一【微信接龙】
  17. 锁子甲 bulid+sim
  18. ./与../和/的区别
  19. XDOJ 235-月份判断
  20. java 判断请求来自手机或电脑

热门文章

  1. tinydate.js[v0.3] 新增了字符串格式化为日期对象的函数
  2. [BZOJ 3236] [Ahoi2013] 作业 [BZOJ 3809] 【莫队(+分块)】
  3. 使用keil建立标准STM32工程模版(图文详细版!)
  4. 人的幸福感取决于什么
  5. oracle客户端 tsnping时出现TNS-03505:无法解析名称
  6. 驱动开发之 设备读写方式:缓冲区方式
  7. sourcetree不好做到的一些git操作
  8. 用jquery写一个属于自己的音乐播放器
  9. HashMap vs ConcurrentHashMap — 示例及Iterator探秘
  10. python读取postgresql数据库并发送相关提醒邮件