2019-10-25 09:55:35 qq_42173406 阅读数 143
  • 嵌入式Linux文件与串口编程

    本课程介绍Linux环境下shell编程,普通文件与设备文件的编程方法,串口介绍与应用编程。 学习条件: 1.C语言编程基础 2.嵌入式Linux开发基础

    7358 人正在学习 去看看 沈寒

linux 操作系统启动过程和内核参数修改添加方法

操作系统启动过程

操作系统启动过程一般分为五个阶段:(centos7为例)

  1. BIOS初始化
  2. 加载MBR到内存
  3. GRUB阶段
  4. 加载内核和initramfs模块
  5. systemd阶段

BIOS初始化

上电后,主板BIOS运行POST(Power on self test)代码,进行开机自检,检查硬件:CPU、内存、显卡、硬盘、CD-ROM、串口、并口、软驱等。

加载MBR到内存

自检硬件没有问题时候,这里以BIOS为例,BIOS将会直接找硬盘的第一个扇区,找到前446字节,将MBR加载到内存中,MBR将告诉程序下一阶段去哪里找系统的grub引导。此阶段属于grub第1阶段。grub还有1.5阶段和2阶段。

GRUB阶段

主要操作是装载stage1,装载stage1.5,装载stage2。
然后读取/boot/grub.conf文件显示启动菜单,装载所选的kernel和initrd文件到内存中。
grub启动三阶段:

stage1: 引导安装在MBR中的引导程序(bootloader)
stage1.5: mbr之后的扇区,让stage1中的bootloader能识别stage2所在的分区上的文件系统;
stage2:读取存放在磁盘上的grub(存放位置:/boot/grub),grub的配置文件:/boot/grub/grub.conf,在etc目录下有此文件的连接文件:/etc/grub.conf

加载内核和initramfs模块

加载内核,核心开始解压,启动一些最核心的程序。

为了让内核足够的轻小,硬件驱动并没放在内核文件里面。

kernel内核开始初始化,用systemd来代替centos6以前的init程序
先执行initrd.target
包括挂载/etc/fstab文件中系统,挂载之后,就可以切换到根目录。

从initramfs根文件系统切换到磁盘的根目录
systemd执行默认target配置
centos7表面有“运行级别”这个概念,实际是为了兼容以前的系统,每个所谓“运行级别”都有对应的软连接指向,默认的启动级别/etc/systemd/system/default.target,根据它的指向可以找到系统要进入到哪个模式。

模式:

0 ==> runlevel0.target, poweroff.target
1 ==> runlevel1.target, rescue.target
2 ==> runlevel2.target, multi-user.target
3 ==> runlevel3.target, multi-user.target
4 ==> runlevel4.target, multi-user.target
5 ==> runlevel5.target, graphical.target
6 ==> runlevel6.target, reboot.target

systemd阶段

systemd执行sysinit.target
systemd启动multi-user.target下的本机与服务器服务
systemd执行multi-user.target下面的/etc/rc.d/rc.local
systemd执行multi-user.target下的getty.target及登录服务
getty.target是启动终端的systemd对象。如果到此步骤,系统没有指定启动图形桌面,到此就可以结束,如果需要启动图形界面,要在此基础上启动桌面程序。

systemd执行graphical图形化需要的服务
至此系统启动完成,可以正常使用。

 

内核参数

修改内核参数

内核命令行参数(也称为内核参数)仅用于在引导时自定义Linux的行为。
内核命令行参数保存在boot/grub/grub.cfg配置文件中,该文件为 由GRUB2引导加载程序生成。不要编辑此配置文件。仅对该文件所做的更改,由配置脚本制作。

  1. 使用纯文本编辑器(例如vim或Gedit)以root身份打开/etc/default/grub配置文件。
  2. 在此文件中,找到以GRUB_CMDLINE_LINUX开头的行,如下所示:
    GRUB_CMDLINE_LINUX =“ rd.lvm.lv=rhel/swap crashkernel=auto rd.lvm.lv= rhel/root rhgb quiet”
  3. 更改所需的内核命令行参数的值。然后,保存文件并退出编辑器。
  4. 使用编辑后的默认文件重新生成GRUB2配置。如果您的系统使用BIOS固件,执行以下命令:
    #grub2-mkconfig -o /boot/grub2/grub.cfg
    在具有UEFI固件的系统上,改为执行以下操作:
    #grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg
    完成上述步骤后,将重新配置引导加载程序,并在下次重新引导后应用您在其配置文件中指定的内核命令行参数

修改内核可调参数

内核可调参数用于在引导时或在系统运行时按需自定义Linux的行为。 一些硬件参数仅在引导时指定,并且一旦系统运行就无法更改,但是大多数硬件参数可以根据需要进行更改,并在下次引导时永久设置。

使用sysctl命令
sysctl命令用于列出,读取和设置内核可调参数。 当列出或读取或临时设置或永久设置可调参数时,它可以过滤可调参数。

  1. 列出变量
    #sysctl -a
  2. 读取变量
    #sysctl kernel.version +
    kernel.version =#1 SMP 2018年1月19日星期五13:19:54
  3. 临时写变量
    #sysctl <tunable class>.<tunable>=<value>
  4. 永久写入变量
    #sysctl -w <tunable class>.<tunable>=<value > >> /etc/sysctl.conf

要在引导时覆盖默认值,还可以在/etc/sysctl.d中手动填充文件。

  1. 在/etc/sysctl.d中创建一个新文件
    #vim /etc/sysctl.d/99-custom.conf
  2. 包含您要设置的变量,每行一个,格式如下
    <tunable class>.<tunable> = <value> +
    <tunable class>.<tunable> = <value>
  3. 保存文件
  4. 重新引导计算机以使更改生效,或执行sysctl -p /etc/sysctl.d/99-custom.conf以应用更改而无需重新引导。

编写添加内核参数

在Linux系统下,使用sysctl命令可以查看和修改系统参数,添加一个系统参数的方法:

在ctl_table中注册内核参数

在source/net/ipv4/sysctl_net_ipv4.c文件中有这样一个结构体数组

static struct ctl_table ipv4-table[] = {
    ......
},
{
    ......
}
......

在目录/proc/sys/net/ipv4/下面所有的系统参数都得先到这里注册,下面给出一个具体例子。

{ 
	.procname = "tcp_vegas_alpha",
	.data     = &sysctl_tcp_vegas_alpha,
	.maxlen   = sizeof(int),
	.mode     = 0644,
	.proc_handler  = proc_dointvec
},
{
	.procname = "tcp_vegas_beta",
	.data     = &sysctl_tcp_vegas_alpha,
	.maxlen   = sizeof(int),
	.mode     = 0644,
	.proc_handler  = proc_dointvec

}

这两个参数是拥塞控制算法Vegas在拥塞控制阶段调节cwnd用的。
这里是struct ctl_table的具体定义。

/* 结构位置:include/linux/sysctl.h */
struct ctl_table
{
    const char    *procname;    /* Text ID for /proc/sys, or zero */
    void          *data;
    int           maxlen;
    umode_t       mode;
    struct        ctl_table *child;  /* Deprecated */
    proc_handler  *proc_handler;     /* Callback for text formatting */
    struct ctl_tabel_poll *poll;
    void *extral;
    void *extra2;
};

现在简单介绍一下这些结构体成员变量。
*procname 表示在/proc/sys/下显示的文件名称,
*data 表示对应于内核中的变量名称,
maxlen 表示允许的最大长度,
mode 表示访问权限,
proc_handler表示回调函数,有一些常用取值:
porc_dointvec 读写包含一个或多个整数的数组,
proc_dostring 读写一个字符串,
proc_dointvec_minmax 写的整数必须在min~max范围内。

声明内核参数

用于TCP的内核参数在source/include/net/tcp.h声明。

/* 进入tcp.h文件可以看到大量的变量声明,这里只列出上文提及到的两个变量 */
...
extern int sysctl_tcp_vegas_alpha;
extern int sysctl_tcp_vegas_beta
...

定义内核参数

内核参数的定义可能在不同的文件中,这个根据内核参数的用途而定。
systcl_tcp_vegas_alpha和sysctl_tcp_vegas_beta这两个变量的定义位置:
source/net/ipv4/tcp_retrans.c

int sysctl_tcp_vegas_alpha = 2;
int sysctl_tcp_vegas_beta = 4;

经过上面这些步骤,内核参数就添加成功了,当我们编译重启系统后,就会发现在目录:/proc/sys/net/ipv4/下有两个文件分别是tcp_vegas_alpha和tcp_vegas_beta,以后就可以通过echo命令动态修改这两个值。

常用的内核参数

下列文件所在目录:/proc/sys/net/ipv4/

名称 默认值 描述
tcp_syn_retries 5 对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃。不应该大于255,默认值是5,对应于180秒左右时间。。(对于大负载而物理通信良好的网络而言,这个值偏高,可修改为2.这个值仅仅是针对对外的连接,对进来的连接,是由tcp_retries1决定的)
tcp_synack_retries 5 对于远端的连接请求SYN,内核会发送SYN + ACK数据报,以确认收到上一个 SYN连接请求包。这是所谓的三次握手( threeway handshake)机制的第二个步骤。这里决定内核在放弃连接之前所送出的 SYN+ACK 数目。不应该大于255,默认值是5,对应于180秒左右时间。
tcp_keepalive_time 7200 TCP发送keepalive探测消息的间隔时间(秒),用于确认TCP连接是否有效。防止两边建立连接但不发送数据的攻击
tcp_keepalive_probes 9 TCP发送keepalive探测消息的间隔时间(秒),用于确认TCP连接是否有效。
tcp_keepalive_intvl 75 探测消息未获得响应时,重发该消息的间隔时间(秒)。默认值为75秒。 (对于普通应用来说,这个值有一些偏大,可以根据需要改小.特别是web类服务器需要改小该值,15是个比较合适的值)
tcp_retries1 3 放弃回应一个TCP连接请求前﹐需要进行多少次重试。RFC规定最低的数值是3
tcp_retries2 15 在丢弃激活(已建立通讯状况)的TCP连接之前﹐需要进行多少次重试。默认值为15,根据RTO的值来决定,相当于13-30分钟(RFC1122规定,必须大于100秒).(这个值根据目前的网络设置,可以适当地改小)
tcp_orphan_retries 7 在近端丢弃TCP连接之前﹐要进行多少次重试。默认值是7个﹐相当于 50秒 - 16分钟﹐视 RTO 而定。如果您的系统是负载很大的web服务器﹐那么也许需要降低该值﹐这类 sockets 可能会耗费大量的资源。另外参的考tcp_max_orphans。(事实上做NAT的时候,降低该值也是好处显著的)
tcp_fin_timeout 60 对于本端断开的socket连接,TCP保持在FIN-WAIT-2状态的时间。对方可能会断开连接或一直不结束连接或不可预料的进程死亡。默认值为 60 秒
tcp_max_tw_buckets 180000 系统在同时所处理的最大 timewait sockets 数目。如果超过此数的话﹐time-wait socket 会被立即砍除并且显示警告信息。之所以要设定这个限制﹐纯粹为了抵御那些简单的 DoS 攻击﹐不过﹐如果网络条件需要比默认值更多﹐则可以提高它(或许还要增加内存)。(事实上做NAT的时候最好可以适当地增加该值)
tcp_tw_recycle 0 打开快速 TIME-WAIT sockets 回收。除非得到技术专家的建议或要求﹐请不要随意修改这个值。(做NAT的时候,建议打开它)
tcp_tw_reuse 8192 系统所能处理不属于任何进程的TCP sockets最大数量。假如超过这个数量﹐那么不属于任何进程的连接会被立即reset,并同时显示警告信息。之所以要设定这个限制﹐纯粹为了抵御那些简单的 DoS 攻击﹐千万不要依赖这个或是人为的降低这个限制。如果内存大更应该增加这个值。(这个值Redhat AS版本中设置为32768,但是很多防火墙修改的时候,建议该值修改为2000)
tcp_abort_on_overflow 0 当守护进程太忙而不能接受新的连接,就象对方发送reset消息,默认值是false。这意味着当溢出的原因是因为一个偶然的猝发,那么连接将恢复状态。只有在你确信守护进程真的不能完成连接请求时才打开该选项,该选项会影响客户的使用。(对待已经满载的sendmail,apache这类服务的时候,这个可以很快让客户端终止连接,可以给予服务程序处理已有连接的缓冲机会,所以很多防火墙上推荐打开它)
tcp_syncookies 0 只有在内核编译时选择了CONFIG_SYNCOOKIES时才会发生作用。当出现syn等候队列出现溢出时象对方发送syncookies。目的是为了防止syn flood攻击。
tcp_stdurg 0 使用 TCP urg pointer 字段中的主机请求解释功能。大部份的主机都使用老旧的 BSD解释,因此如果您在 Linux打开它﹐或会导致不能和它们正确沟通。

等等。

所处目录/proc/sys/net/ipv4/netfilter/
文件需要打开防火墙才会存在

名称 默认值 描述
ip_conntrack_max 65536 系统支持的最大ipv4连接数,默认65536(事实上这也是理论最大值),同时这个值和你的内存大小有关,如果内存128M,这个值最大8192,1G以上内存这个值都是默认65536,这个值受/proc/sys/net/ipv4/ip_conntrack_max限制
ip_conntrack_tcp_timeout_established 432000 已建立的tcp连接的超时时间,默认432000,也就是5天。影响:这个值过大将导致一些可能已经不用的连接常驻于内存中,占用大量链接资源,从而可能导致NAT ip_conntrack: table full的问题。建议:对于NAT负载相对本机的 NAT表大小很紧张的时候,可能需要考虑缩小这个值,以尽早清除连接,保证有可用的连接资源;如果不紧张,不必修改
ip_conntrack_tcp_timeout_time_wait 120 time_wait状态超时时间,超过该时间就清除该连接
ip_conntrack_tcp_timeout_close_wait 60 close_wait状态超时时间,超过该时间就清除该连接
ip_conntrack_tcp_timeout_fin_wait 120 fin_wait状态超时时间,超过该时间就清除该连接

等等。

文件所处目录/proc/sys/net/core/

名称 默认值 描述
netdev_max_backlog 1024 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目,对重负载服务器而言,该值需要调高一点。
somaxconn 128 用来限制监听(LISTEN)队列最大数据包的数量,超过这个数量就会导致链接超时或者触发重传机制。web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。对繁忙的服务器,增加该值有助于网络性能
wmem_default 129024 默认的发送窗口大小(以字节为单位)
rmem_default 129024 默认的接收窗口大小(以字节为单位)
rmem_max 129024 最大的TCP数据接收缓冲
wmem_max 129024 最大的TCP数据发送缓冲

等等。

2013-01-30 12:50:52 zyphio 阅读数 2432
  • 嵌入式Linux文件与串口编程

    本课程介绍Linux环境下shell编程,普通文件与设备文件的编程方法,串口介绍与应用编程。 学习条件: 1.C语言编程基础 2.嵌入式Linux开发基础

    7358 人正在学习 去看看 沈寒


jtag:一个并口,主要功能是为空白的flash芯片写入bootloader(有时又称为cfe或uboot),速度很慢;

ttl:一个串口,能在路由bootloader完好的情况下,查看系统自检和刷入固件;

tftp:一种传输协议,能在路由器的bootloader完好的情况,在Linux下重新刷入固件;

telnet:一种传输协议,当路由器里的Linux系统正常运作并打开telnet服务时,可在Windows或Linux下访问路由里的Linux系统的终端,可刷写固件;

ssh:一种传输协议,当路由器里的Linux系统正常运作并打开ssh服务时,可在Windows或Linux下访问路由里的Linux系统的终端,可刷写固件。

2019-03-28 20:43:44 weixin_40535588 阅读数 29
  • 嵌入式Linux文件与串口编程

    本课程介绍Linux环境下shell编程,普通文件与设备文件的编程方法,串口介绍与应用编程。 学习条件: 1.C语言编程基础 2.嵌入式Linux开发基础

    7358 人正在学习 去看看 沈寒

一.简介:

    U-Boot是通用的Bootloader,是遵循GPL条款的开放源代码项目。

有下面特点(只列重点):

1.U-Boot的作用是系统引导,支持 linux,VxWorks, QNX, RTEMS, ARTOS, LynxOS, android等嵌入式操作系统

2.支持NFS挂载

3.有丰富的设备驱动源码,如串口,以太网,SDRAM等

4.上电自检

二.U-boot的源码结构

源码可从https://sourceforge.net/directory/os:windows/https://www.denx.de/wiki/U-Boot/SourceCode获取

三.U-boot工作流程(即BootLoader)

1.初始化硬件:关看门狗,设置时钟,初始化串口,以及各种驱动,设置SDRAM,初始化NAND FLASH/NOR FLASH

2.如果BootLoader比较大,要把它重定位到SDRAM

3.把内核从NAND FLASH/NOR FLASH读到SDRAM(因为我们的程序一般放在nor上或者是nand上  ,为什么不直接放在运行内存RAM(SDRAM)上呢,因为RAM上电会丢失。程序不能在flash上跑,所以要把flash中的程序读到SDRAM上)

4.设置栈(为了用到c库,因为汇编工作能力有限)

5.启动内核

2018-11-22 14:34:02 xstardust 阅读数 66
  • 嵌入式Linux文件与串口编程

    本课程介绍Linux环境下shell编程,普通文件与设备文件的编程方法,串口介绍与应用编程。 学习条件: 1.C语言编程基础 2.嵌入式Linux开发基础

    7358 人正在学习 去看看 沈寒

摘要: 怎么才能在RTOS系统中,通过 串口shell控制LED的开关。

在日常嵌入式开发中,我们经常会用串口命令来使设备进入某种特定的状态,或执行某个特定的操作。如系统自检,模拟运行,或者进入手动模式进行设备点动。linux下有强大的shell工具,可以让用户和片上系统进行交互,而在传统的单片机系统中,用户往往需要自行实现一套类似的交互工具。AliOS-Things原生带有一套名为cli(command-line interface)的命令行交互工具,在提供基本的系统交互命令的基础上,也支持用户自定义命令。本文将介绍如何自定义cli命令并执行。

我们通过在《【AliOS Things学习笔记】在Developerkit开发板上运行blink例程》基础上,注册一个cli命令,通过命令行的方式控制LED的亮灭的例子,来演示一个带有参数的cli命令如何被注册以及调用。

首先,我们先保证Developerkit的原有cli功能可用。将开发板通过USB连接线和PC连接。

3b06db95172f9fc8a5a68358d6d679fd742cdb6c

windows用户通过设备管理器确认开发板所虚拟出的串口号,MAC和linux用户可用在终端中输入如下命令来查看USB串口是否已正确连接。

ls /dev/tty.*

如果出现如下设备列表,则表示连接正确。usbmodem后的数字可能会因为计算机不同而不同。

/dev/tty.usbmodem14103

此时,可用打开PC上的串口调试工具,设置对应的串口,波特率默认为115200bps。建议串口调试助手具备终端功能,这样会在cli的使用中有更好的体验。接下来我将以植入VScode中的aos-cube工具的串口监视器功能为例进行演示。打开VScode,确保已经按照alios-studio和aos-cube插件。点击alios-studio工具条中的“插头”按钮,启动串口monitor

30aa210650524bfbfdae0967fbfd3e2440ba1650

如果工具没能正确地打开串口,也可以尝试在控制台中使用命令行的方式启动串口monitor。命令格式如下:

aos monitor /dev/tty.usbmodem14103 115200      #mac linux下命令
aos monitor com5 115200                        #windows 下命令

成功进入串口monitor后,会从终端中打印出帮助信息。输入回车,会出现“#”提示符,此时就可以输入命令了。

--- Miniterm on /dev/tty.usbmodem14103  115200,8,N,1 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---

#
#

输入“help”回车,会看到当前支持的cli命令

# help
====Build-in Commands====
====Support 4 cmds once, seperate by ; ====
help      : print this
p         : print memory
m         : modify memory
echo      : echo for command
exit      : close CLI
devname   : print device name
sysver    : system version
reboot    : reboot system
time      : system time
ota       : system ota

====User Commands====
loglevel  : set log level
tasklist  : list all thread info
dumpsys   : dump system info
udp       : [ip] [port] [string data] send udp data
wifi_debug: wifi debug mode
mac       : get/set mac
kv        : kv [set key value | get key | del key | list]
version   : show version

#

输入“tasklist”,可以看到现有的任务运行情况

# tasklist
------------------------------------------------------------------------
cpu usage period = 25
CPU usage :   1.89
------------------------------------------------------------------------
Name               State    Prio StackSize MinFreesize Runtime %CPU Candidate
------------------------------------------------------------------------
dyn_mem_proc_task  PEND     6    256       216         22         0.00   N
idle_task          RDY      61   200       177         745102697 98.11   N
DEFAULT-WORKQUEUE  PEND     20   768       738         23         0.00   N
timer_task         PEND     5    300       254         25         0.00   N
aos-init           PEND     32   1536      1389        1419569    1.38   N
cli                RDY      60   512       271         491760     0.47   Y
------------------------------------------------------------------------

到此,我们已经验证了cli功能在Developerkit开发板上,接下我们开始注册和使用自己的cli命令。

我们依然打开blink.c文件,在其中添加代码实现。首先,cli命令的注册,依赖于一个名为cli_command结构体,结构体描述如下:

struct cli_command {
    const char *name;            // 命令体,字符串
    const char *help;            // 命令的帮助说明文本,字符串
    
    void (*function)(char *pcWriteBuffer, int xWriteBufferLen, int argc, char **argv);
    // 命令被执行时实际调用的功能函数    
};

在本例中,我们将cli命令命名为“led_switch”,帮助文本字符串为“[on] turn on led2;[off] trun off led2”

接下来我们来实现cli命令的功能函数。将下面函数直接加入blink.c文件中。

static void led_switch(char *pwbuf, int blen, int argc, char **argv)
{
    if(argc == 1)                       // 如果参数为空,则报错返回
    {
        LOG("参数错误");
        return;
    }
    if(strcmp(argv[1],"on") == 0)       // 如果输入参数为“on”,则点亮led
    {
        hal_gpio_output_low(&led);      // GPIO输出低,点亮LED2
    }
    else
    {
        hal_gpio_output_high(&led);     // GPIO输出高,熄灭LED2
    }
}

cli函数具有固定的形式和参数,参考上述函数实现,用户只需要修改函数名,请保持参数与上述函数一致,参数的意义如下:

参数名称

参数描述

char *pwbuf

当函数执行完成返回时,通过控制台打印出来的字符串指针。可以不传入。

int blen

上述字符串长度

int argc

命令调用时传入的参数长度,没有参数传入时为1

char **argv

传入参数缓存,字符串。第一个有效参数的角标从1开始。

接下来填写注册用结构体,以便将命令信息传递给cli服务。按照前所讲的设计,注册结构体信息如下,将结构体拷贝到blink.c文件中。

struct cli_command led_switch_command[] = {
    {
        .name = "led_switch",            // 命令名称
        .help = "[on] turn on led2;[off] trun off led2",// 帮助文本
        .function = led_switch           // 命令具体执行的函数指针
    }
};

将cli命令注册到系统中。cli命令注册只需要一个函数如下:

aos_cli_register_commands(&led_switch_command[0],1);

函数需要传入两个参数,参数1为刚刚创建的命令信息体的结构体指针;参数2,为本次需要注册的命令数,也就是说可以一次性注册多个命令,只需要在命令信息结构体中,用数组的方式同时填入几个命令的信息即可。

将上述函数调用加入到blink.c文件application_start函数的如下位置:

    aos_cli_register_commands(&led_switch_command[0],1); // 注册cli命令函数
    aos_loop_run();

至此,一个cli命令的实现和注册的代码编写部分就完成了。编译并下载至开发板中运行。在cli控制台输入help,看到led_switch命令已注册成功。

# help
====Build-in Commands====
====Support 4 cmds once, seperate by ; ====
help      : print this
p         : print memory
m         : modify memory
echo      : echo for command
exit      : close CLI
devname   : print device name
sysver    : system version
reboot    : reboot system
time      : system time
ota       : system ota

====User Commands====
loglevel  : set log level
tasklist  : list all thread info
dumpsys   : dump system info
udp       : [ip] [port] [string data] send udp data
wifi_debug: wifi debug mode
mac       : get/set mac
kv        : kv [set key value | get key | del key | list]
version   : show version
led_switch: [on] turn on led2;[off] trun off led2

测试命令是否执行,在命令提示符下输入如下命令,并回车:

#led_switch on

led2点亮

测试参数有效性判断,输入如下指令,不带参数。命令按设计返回错误报警。

## led_switch
[1291080]<V> 参数错误

赶快试试,加入自己的cli功能吧!

2016-07-06 22:14:26 bona020 阅读数 3940
  • 嵌入式Linux文件与串口编程

    本课程介绍Linux环境下shell编程,普通文件与设备文件的编程方法,串口介绍与应用编程。 学习条件: 1.C语言编程基础 2.嵌入式Linux开发基础

    7358 人正在学习 去看看 沈寒
rt,虽然ext4文件系统比较“结实”,但也经不起每次都非正常关机的折腾


如果你发现你的派半天都没启动起来,绿灯不闪或一直连续的闪,接上显示或串口后发现系统提示文件系统错误,那么你就成功的搞坏了文件系统。


万一你真搞坏了,如果你的电脑上有linux系统,可以执行:
fsck.ext4 /dev/sdb2 #设备名按实际情况修改
来修复文件系统
如果你只有windows,基本上就只能重写系统了


不过你可以让树莓派的系统在每次启动时都去检查一遍文件系统,应该能起到一些效果
执行:
sudo touch /forcefsck
sudo chattr +i /forcefsck

这样树莓派每次启动会慢5~10秒,但总比你重写一遍系统快



修复方法:

1、手动修复:借助其他完整系统启动,对所在磁盘分区卸载,比如要修复/dev/mmcblk0p2,

执行命令 fsck.ext4 /dev/mmcblk0p2 可检查修复系统;


2、自动修复:

条件:

(1)、  自动修复要保证,bootloader参数bootargs 生命挂载以制度方式挂载根文件系统

            console=tty1 console=ttySAC2,115200n8 root=UUID=e139ce78-9841-40fe-8823-96a304a09859 rootwait ro

  如果最后ro是rw,将不能完成自动修复。

(2)、   编辑/etc/fstab 挂载最后一个选项设置为1,标明启动时自动检测文件系统,如下:

UUID=e139ce78-9841-40fe-8823-96a304a09859       /       ext4    errors=remount-ro,noatime,nodiratime            01

(3)、  编辑 /etc/default/rcS 最后一个选项(其他linux系统有区别)

# automatically repair filesystems with inconsistencies during boot
FSCKFIX=yes

然后,可以参考/etc/init/mountall.conf

[cpp] view plain copy
  1. description     "Mount filesystems on boot"  
  2.   
  3. start on startup  
  4. stop on starting rcS  
  5.   
  6. expect daemon  
  7. task  
  8.   
  9. emits virtual-filesystems  
  10. emits local-filesystems  
  11. emits remote-filesystems  
  12. emits all-swaps  
  13. emits filesystem  
  14. emits mounting  
  15. emits mounted  
  16.   
  17. script  
  18.     . /etc/default/rcS || true  
  19.     [ -f /forcefsck ] && force_fsck="--force-fsck"  
  20.     [ "$FSCKFIX" = "yes" ] && fsck_fix="--fsck-fix"  
  21.   
  22.     # Doesn't work so well if mountall is responsible for mounting /proc, heh.  
  23.     if [ -e /proc/cmdline ]; then  
  24.         read line < /proc/cmdline  
  25.         for arg in $line; do  
  26.             case $arg in  
  27.                 -q|--quiet|-v|--verbose|--debug)  
  28.                     debug_arg=$arg  
  29.                     ;;  
  30.             esac  
  31.         done < /proc/cmdline  
  32.     fi  
  33.     # set $LANG so that messages appearing in plymouth are translated  
  34.     if [ -r /etc/default/locale ]; then  
  35.         . /etc/default/locale || true  
  36.         export LANG LANGUAGE LC_MESSAGES LC_ALL  
  37.     fi  
[cpp] view plain copy
  1.     exec mountall --daemon $force_fsck $fsck_fix $debug_arg  
  2. end script  
[cpp] view plain copy
  1. post-stop script  
  2.     rm -f /forcefsck 2>dev/null || true  
  3. end script  
(4)、 系统检测到分区有问题时,会再根目录下创建一个空文件/forcefsck,重启后,执行mountall,自动进行修复,然后删除forcefsck,也可以手动创建/forcefsck,系统同样会在下次启动时强制检查修复文件系统;


Log:

系统启动检查修复过程的log,不在/var/log/fsck/目录下,而是在/var/log/upstart/目录下,文件为 mountall.log,如下:

[cpp] view plain copy
  1. # cat mountall.log  
  2. mount: mount point /media/boot does not exist  
  3. mountall: mount /media/boot [382] terminated with status 32  
  4. mountall: Filesystem could not be mounted: /media/boot  
  5. Skipping /media/boot at user request  
  6. Skipping /media/boot at user request  
  7. Skipping /media/boot at user request  
  8. fsck from util-linux 2.20.1  
  9. e2fsck 1.42.9 (4-Feb-2014)  
  10. /dev/mmcblk0p2: clean, 223220/393216 files, 1282976/1572864 blocks  

其他:

也可以通过设置 系统挂载的次数来自动检查修复文件系统

比如:

tune2fs -c 30 /dev/mmcblk0p2 系统每启动30次,就会检查修复一次。


修复完成后,通过 tune2fs -l /dev/mmcblk0p2看到没有错误信息,如下:


没有更多推荐了,返回首页