OpenWrt与嵌入式Linux

2023-05-16

OpenWrt与嵌入式Linux

由于要接手学长留下来的一个项目,“被迫”要学习OpenWrt的配置方法——虽然对于一个five电工来说这事挺莫名其妙的,但还是硬着头皮上吧(我本想拒绝,但他给的是在太多了)

简介

在官网中这样描述OpenWrt

OpenWrt项目是一个针对嵌入式设备的Linux操作系统。OpenWrt不是一个单一且不可更改的固件,而是提供了具有软件包管理功能的完全可写的文件系统。这使您可以从供应商提供的应用范围和配置中解脱出来,并且让您通过使用适配任何应用的软件包来定制设备。对于开发人员来说,OpenWrt是一个无需围绕它构建完整固件就能开发应用程序的框架; 对于普通用户来说,这意味着拥有了完全定制的能力,能以意想不到的方式使用该设备。

听上去很高大上,实际上OpenWrt就和Ubuntu、CentOS、Raspbian等GNU/Linux发行版一样,是一个基于Linux内核的操作系统。只不过它具有高度模块化可定制的特点,并且自带一系列网络组件,因此常常被用于路由器、工控、智能家居、小型交换机中。笔者接手的这个项目就是基于OpenWrt实现路由器-交换机的应用,并配置一个网络摄像头和一个网口数据转串口

OpenWrt除了以上特点外,还有一个堪称嵌入式Linux杀手锏的特性:超级大规模的开源社区。可能是因为大家都很喜欢软路由,OpenWrt的软件包已经达到了好几千,这让它能秒掉一堆其他的嵌入式Linux发行版

OpenWrt与桌面Linux操作系统

可能大家无法理解OpenWrt这种发行版的独特之处,请允许我在这里为大家重新介绍一下桌面Linux操作系统

一般的桌面操作系统都很难在低性能的嵌入式设备上运行,这是因为两点:

  1. 它们需要占用大量的系统资源,尤其是内存用于支持各种deamon的运行

    一般的GNU/Linux发行版都采用Bash乃至更人性化也更占用资源的Zshell作为终端;而OpenWrt为了适应低性能的处理器,采用更简单的Ash作为默认shell。此外,OpenWrt使用的C库是uClibc而不是glibc,这是一个面向嵌入式系统的小型C标准库,也有很多RTOS比如FreeRTOS和RT-Thread都采用了这个C库

  2. 它们的体积都比较大,一个典型的桌面操作系统占用的存储空间至少在1GB以上

    Ubuntu已经膨胀到了2GB,Debian也往往需要占据1GB的硬盘/SD卡/Flash空间;但OpenWrt具有很强的可裁减性,其内核、驱动、自带软件都可以方便地通过menuconfig进行配置,它的运行内存最小只要32M,存放代码数据的Flash空间最小只要8M,但支持使用完备的Linux内核,支持无线、有线网络应用

OpenWrt牺牲了兼容性,但是由于庞大的开源社区资源,他能够对大多数网络嵌入式设备提供支持

OpenWrt优化了效率和资源占用,然而因为难以支持更高性能开销的应用导致其工作范围局限在嵌入式领域

OpenWrt与一般的嵌入式Linux

一般的嵌入式Linux都具有上面所说的特点,一些介于桌面Linux操作系统和嵌入式Linux操作系统之间并经过特殊优化的操作系统如Raspbian甚至能够提供更高的性能-资源占用比,但是OpenWrt相比一般的嵌入式Linux系统具有强大的多的网络应用:

  • 默认自带SSH

  • 可选的图形化网络操作界面Luci(Lua Configuration Interface)

    这是一个使用Lua脚本语言编写的mvc架构的web框架,包含了openwrt的配置界面和一套扩展API。安装luci-core后只要在浏览器中输入OpenWrt设备的IP地址,即可出现其登录界面,可以通过安装luci扩展app实现对OpenWrt设备方方面面的管理

    这个操作界面是对OpenWrt没有图形界面的有效弥补,也是它不同于其他嵌入式Linux的特殊点,这也使OpenWrt相当好上手

  • 自带软路由模块和交换机模块,可配合硬件实现软/硬件路由功能

  • 可选搭建VPN

  • 可运行轻量级服务器软件

  • 可运行轻量级流量整形与捕获分析软件

    OpenWrt常常被用于搭建软路由,很大程度上就是因为它支持各种控制网络流量和数据包的应用扩展

除了以上网络特性,OpenWrt还支持嵌入式Linux所具有的基本能力,包括对POSIX的兼容和VFS等

OpenWrt与LEDE

LEDE是一个源于OpenWrt的分支嵌入式Linux系统,最初一批OpenWrt开发者觉得OpenWrt规则太老套,于是fork了OpenWrt的源码,然后创建了LEDE的分支,在里面添加了很多新开发流程和新功能,然后越来越多OpenWrt开发者转移到LEDE,最后二者又在2018年合并,形成了现在的OpenWrt

有的时候OpenWrt源里面会注明LEDE package,其实和OpenWrt一样,把它看成OpenWrt的某个版本即可

官网这样解释:

OpenWrt/LEDE是一个为嵌入式设备(通常是无线路由器)开发的高扩展度的GNU/Linux发行版。与许多其他路由器的发行版不同,OpenWrt是一个完全为嵌入式设备构建的功能全面、易于修改的由现代Linux内核驱动的操作系统。在实践中,这意味着您可以得到您需要的所有功能,却仍能避免臃肿。

在2016年,LEDE项目作为OpenWrt项目的副产品而诞生,与OpenWrt共享很多相同的目标。该项目旨在成为一个嵌入式Linux版本,能让开发者、系统管理员或其他Linux爱好者轻松的为嵌入式设备特别是无线路由器构建或定制软件。LEDE这一名称代表Linux Embedded Development Environment

项目成员与OpenWrt社区活跃成员高度重合,他们计划通过建立一个高度透明、注重协作和去中心化的社区为嵌入式Linux的开发带来新生。

LEDE已公布的目标包括:

  • 构造一个的伟大的嵌入式Linux发行版,运行稳定且功能实用
  • 伴随社区设备测试反馈,形成定期、可预期的版本迭代
  • 通过广泛的社区参与和公开会议,建立透明的决策机制

LEDE项目的形成是为解决那些被OpenWrt项目或社区认为无法解决的长远问题

  1. 活跃核心开发者数量一直很低,而且无法吸引新面孔加入项目。
  2. 不可依赖的基础设施,内部不同意和单点故障阻碍了错误修复。
  3. 在OpenWrt项目中缺少沟通交流、透明度和协调, 无论是在核心团队内部还是在核心团队和其他团队之间。
  4. 没有足够拥有权限的人处理补丁来流,很少关注测试和定期版本。
  5. 不重视对稳定性和文档。

为解决这些问题,LEDE项目采用了与OpenWrt不同的组织架构:

  1. 所有交流频道均是公开的,对非成员只读的频道控制在一个很好的信噪比。
  2. 决策过程更公开,拥有投票权的开发者和重度用户数量接近50比50。
  3. 大大简化基础设施,确保减少我们的维护工作量。
  4. 更开明的合并政策,基于我们在处理Github上OpenWrt软件包反馈信息的经验。
  5. 高度重视与简化发布流程合并的自动化测试。

2018年1月,OpenWrt和以前的LEDE项目同意以OpenWrt这一名称进行合并。

新的、统一的OpenWrt项目将按照 由前LEDE项目建立的章程 进行管理。以前的LEDE和OpenWrt项目的积极成员将继续在统一的OpenWrt上工作。

OpenWrt慢速上手

之所以这部分名叫《慢速上手》,是因为笔者要从底层开始到建立OpenWrt开发环境的全过程进行梳理,至于为什么——这就是我接手这个项目时遇到的窘境:学长跑路,给我留下了一堆残缺的资料,还有一个时灵时不灵的远程支援(虽然在前期的嵌入式开发debug部分确实给我帮了很大忙,但是怎么还在我滚挂系统的时候幸灾乐祸…这对青少年造成的坏影响,不可估量),于是只能从底层开始

所有我遇到的问题都会在

引用栏

中说明,避免后来者掉到坑里

硬件

硬件设备使用的是海凌科的MT7621模块,基于联发科7621A SoC开发

  • MIPS架构CPU 1004Kc,双核主频880MHz
  • 256MB内存,32MB片上Flash,16位DDR2
  • 自带片上、板载晶振
  • 3.3V、500mA工作电压电流
  • JTAG调试接口
  • 双WiFi接口
  • 1个WAN口,4个LAN口,全千兆
  • 2路SPI、1路IIC
  • I2S、PCM等组成的音频接口
  • 2路USB2.0、3.0接口
  • 3路UART接口
  • GPIO引出

GPIO

手头的MT7621 SoC带有GPIO外设,可以通过控制GPIO_MODE寄存器来使能对应引脚,默认情况下会直接将GPIO复用到其他外设。GPIO是32位的,每个寄存器控制32个IO

常用寄存器如下所示:

  • GPIO_CTRL_X 方向控制寄存器,用于控制GPIO状态为1输出,0输入,2高阻态
  • GPIO_POL_X 极性控制寄存器
  • GPIO_DATA_X 数据寄存器,通过读取这个寄存器来获取当前GPIO的值
  • GPIO_DSET_X 设置寄存器,置1进行使能GPIO
  • GPIO_DCLR_X 清除寄存器,置1进行失能GPIO

使用方法如下:

  1. 登录OpenWrt,使用

    reg s 0
    reg w 60 0x48258
    

    读取GPIO_MODE寄存器值,将要配置为GPIO的引脚位设为1

    使用reg r 60查看是否配置成功

  2. 对应datasheet按照寄存器顺序使用指令

    reg w <寄存器位> <要写入的寄存器值>
    

    进行配置

特别地,有些系统中提供了脚本控制的方法,这会使GPIO配置异常简单:

echo "13" > /sys/class/gpio/export #要设置的引脚
echo "out" > /sys/class/gpio/gpio13/direction #引脚模式
echo "1" > /sys/class/gpio/fpio13/value #设置GPIO输出值

当然如果你要给OpenWrt写一套串口驱动,那就必须按照Linux驱动标准来了,这里不再赘述

SPI与IIC

OpenWrt是支持SPI、IIC的,只要硬件支持就可以调用这俩东西

相对应的驱动随设备不同而不同,甚至需要在编译时单独加入

特别地,很多屏幕需要使用SPI驱动;很多摄像头需要使用IIC驱动(用来支持SCCB接口),因此最好在编译内核的时候将二者添加进去(占用空间并不是很大)

LAN口

路由器LAN口用来连接局域网,也就是内网,路由器可以为LAN口设备提供互联网接入将所有LAN口设备连接到一个VLAN实现交换机目的

相关的内容等到之后的配置OpenWrt再说

WAN口

路由器WAN口用于连接外网,通常会通过某个外部路由器接入互联网

WAN口是路由器的灵魂,没有WAN口的路由器就是个死交换机,有了WAN口,它才能从外网下载程序、实现路由功能等

一般路由器的配置都是单WAN口多LAN口

这里使用的路由模块配备了1WAN口4LAN口

很可惜,在硬件组装初期,笔者的路由器WAN口完全连不上,不仅仅无法ping通,甚至ifconfig根本看不到有这个接口

在这种情况下如果想安装软件包就必须使用LAN口,在路由器端使用SCP协议拉取上位机提供的软件包,然后用opkg进行安装(opkg是OpenWrt里面类似dpkg的一个软件包管理器,可以很方便地安装、更新、删除软件包、切换软件源)

解决方法在后文给出

网络变压器与Bob-Smith电路

在网络硬件设计中经常接触到RJ-45网口,现在的RJ45网口很多都自带了网络变压器,因此只要正常接入并记得使用75欧或50欧电阻进行阻抗匹配就可以了;但是对于这里的路由模块,它使用杜邦线-排针代替RJ45网口(别问为什么,问就是特殊领域),因此需要仔细设计网络变压器部分的电路,它被称为Bob-Smith电路

在这里插入图片描述

他有如下几个关键作用:

  1. 信号传输

    Bob-Smith电路分为电流型电压型,根据驱动网络变压器的是电流为主还是电压为主区分

    电流型:网络变压器输入侧(接PHY芯片或SoC的那一侧)需要在每个变压器抽头处上拉到电源,如果EMC要求更加严格,还会使用一个高频(75MHz-200MHz)电感跨接在抽头和电源之间,上拉电源可以是1.8、2.5、3.3等,这是为了增强网络变压器的驱动能力

    同时需要在输入侧变压器正负端跨接50-100欧姆(常用75欧姆)的分流电阻,用于调整信号驱动强度

    电压型:输入侧变压器抽头接到一起再通过100nF电容到地,这是为了提高网络变压器的EMC性能;正负端则分别接入50-100欧分压电阻到PHY芯片或SoC,用于调整信号驱动强度

  2. 阻抗匹配

    阻抗匹配:当传输路径上阻抗不连续时,会有反射发生,阻抗匹配的作用就是通过端接元器件时,保证传输路线上的阻抗连续以去除传输链路上产生的反射。

    网络变压器的输出端要接共模双绞线,双绞线上传输的是差分信号,因此需要使用100-150欧的阻抗匹配

    网络变压器输出端的抽头都需要接50欧或75欧(根据线缆长度不同决定,也可以改为100欧,但25欧因为阻值太低不常用)到线缆,同时需要一个100nF的电容用于旁路(滤波)

    这几个电阻就起到了阻抗匹配作用,计算公式如下
    Z = R − j 1 ω C Z=\sqrt{R-j\frac{1}{\omega C}} Z=RjωC1

  3. 波形修复

    输出端的旁路电容可以有效对外传输线路上的噪声实现滤除

  4. 抑制杂波

    电压型BS电路通过下拉到地的100nF滤波电容实现了滤出高频噪声的作用,而两个串联在变压器上的分压电阻配合变压器寄生电感可以提高电路对差模信号的抑制能力,从而滤除高频杂波,保证网口通信正常

    电流型BS电路则直接使用较高电流驱动的方式削弱从控制端输出的高频杂波影响。但是因为电流型电路会导致整体功耗较大,所以正在被电压型取代(不过在大功率信号传输的领域还是有一定应用)

  5. 隔离高压

    这一条也可以称为共模-差模防护,电路可以通过一系列泻放路径抵抗从网络变压器输出端而来的浪涌电压电流。

    具体实现出于篇幅所限不在这里列出,大致思路就是共模浪涌会被变压器和输出端电阻自行抵消,最多可能付出电容被击穿的代价,并不会伤害到控制端;而差模信号会被变压器引入到输入端,之后直接通过抽头的电容或上拉电阻被滤除,能够很大程度地减少对输入端和信号的影响

在配置过程中发现:WAN口无法使用

重新刷入三次系统,反复调试一周后发现还是这样,基本上排除了所有可能的软件问题。于是决定回到硬件检查是否网络变压器或引脚出问题。首先用万用表通断档依次检测电容两端对地是否导通,发现WAN口的输入电容两端都对地为0——短路了;之后换用电阻档断电测量输入输出电阻,原本电路中使用75欧电阻,但测量中发现有两个电阻阻值不对,一个是偏小到50欧,另一个则无穷大。换掉电容电阻,上电接网线,成功秒杀

自定制并编译内核

openwrt整个项目在github上可以找到

也可以通过官方OpenWrt源码下载

于是直接用git下载或下载压缩包到linux系统就可以使用了

一般来说可以使用虚拟机搭建环境,但是如果你习惯了使用桌面端linux,可以直接在你的双系统/纯linux环境中搭建openwrt的开发环境

配环境

根据openwrt项目中的README文档就可以简单地配好整个环境,这里摘录一下在ubuntu20中所需要安装的一些关键软件包

sudo apt install gcc g++ make gettext libncurses5-dev patch binutils flex bison subversion build-essential autoconf bzip2 libz-dev zlib1g-dev gawk git ccache gettext asciidoc libssl-dev sphinxsearch xsltproc sphinx-common libtool libssl-dev unzip

安装完依赖以后还要下载一些openwrt主分支中没有加入的源代码,这些都是诸如kernel、package之类的大号源码,需要从官方对应的版本库中拉取到本地

这里需要注意:版本!

在拉取之前应该确定你想要编译的内核版本

常用的大版本有14、15、16、17、18、19,小版本从.1到.9不等,各个版本差异都比较大,大版本之间软件包基本是不可能通用的,小版本之间的软件包安装也存在各种问题,所以选版本的时候尽量考虑清楚

使用指令git checkout openwrt-xx.xx来切换到某个指定的内核版本,可以通过git指令查看各个版本间的不同

选择版本后就要添加软件扩展包了:

首先

cp feeds.conf.default feeds.conf

设置所需要使用的源,然后

./scripts/feeds update -a
./scripts/feeds install -a

更新并安装扩展程序

完成后应该可以看到OpenWrt目录如下:

  • config 编译选项配置文件目录: 包含全局编译设置,开发人员设置和内核编译设置
  • include 就是普通的头文件目录,但是也包含了各种脚本和Makefile
  • package 软件包目录
  • scripts 环境脚本、下载补丁脚本、Makefile等
  • target 嵌入式平台移植包
  • toolchain 编译器和C库工具链
  • tools 用于生成固件的辅助工具
  • dl 下载的软件包目录

顺带一提,在编译完成时还能看到build_dir和staging_dir,二者分别是中间文件目录和编译安装目录

在完成配置后可以使用make defconfig来测试编译环境是否配置正确

千万注意不要被老版本的配环境资料误导,包括本篇!不要看见一个差不多的资料就从里面复制粘贴指令!

一定要选择适合自己系统的配环境资料,最好查阅官方文档!虽然会麻烦一点但是可以很大程度上避免滚挂系统!

不要问我怎么知道的,我只能说linux双系统有风险,滚挂系统重装好麻烦的!

menuconfig

配完环境以后就可以进行半可视化配置内核、应用程序的menuconfig了

先使用

make menuconfig

打开menuconfig半图形化配置界面,在里面添加需要选用的组件

操作:键盘上下移动光标,左右选择底部按键,回车是确认,空格是设置选择模式,选项最前面的选择模式有[*]表示编译进固件,[M]表示编译成安装包,[ ]表示不选择,esc是返回上级菜单,按?是帮助,按/是搜索

注意一般应用程序编译成安装包等进入系统后再安装,kmod内核驱动要编译进固件,带opkg字样的东西一定要编译进固件,不然没法安其他包

配置选项定义

配置选项含义
Target System目标平台,对应目录openwrt/target/linux 里的目录
Subtarget目录 openwrt/target/linux/(目标) 里的子目录,定义特定目标
Target Profile目标描述文件,在subtarget目录下面的profile目录中
Target Images编译生成目标固件的控制选项
Global build settings全局编译设置,按默认设置进行编译就可以
Advanced configuration options高级配置选项,无需理会
Build the OpenWrt Image Builder可以编译出一个编译系统供其它主机安装
Build the OpenWrt SDK编译生成SDK开发包,提供给其它主机进行应用开发
Package the OpenWrt-based Toolchain生成开发工具链包,提供给其它主机进行应用开发
Image configuration控制是否打开feed.conf中的模块
Base system基本软件包选择,主要是busybox组件
Boot Loaders引导系统的系统,不用管它
Development开发包、开发工具,如gcc、gdb之类
Firmware特定硬件的固件
Kernel modules内核模块、内核配置选项
Languages软件开发语言选择
Libraries动态链接库选择
Network网络功能模块选择
Utillities一些实用工具模块

(上面内容摘录自https://www.jianshu.com/p/e2b5a292392e)

完成选择后就可以保存退出了,生成的文件会让你命名,一般直接保持默认.config即可

在这个项目里,我遇到的最大问题就是在menuconfig的时候安装进模块的软件包无法使用,于是只能和OpenWrt内核版本、底层硬件驱动、网口配置斗智斗勇…在一般情况下面对嵌入式设备一定要首先考虑在menuconfig的时候安装软件包,否则后续的操作有可能反而比menuconfig复杂——尤其是在安装额外的kmod,也就是内核驱动时。自行编译的内核是具有独立的md5码的,并不能和官方的bin文件对应的md5码吻合,这就导致下载软件包的时候kmod无法匹配内核,所以要使用强制安装,而又因为你的内核是自行编译的,所以很有可能会出现因为内核版本不对而很多程序无法运行,甚至运行时崩溃的情况

漫长的编译

make就完事了,make的时候可以换各种姿势

make V=s #输出编译信息,第一次编译一般用这个,单核编译小水管不得不品尝
make V=99 #上面这个的老版本用法

make -j12 #j后面跟你的cpu核心数,对amd cpu很友好,但是不会输出编译信息,如果要反复编译还是比较适合的,省时间
make clean #重新编译之前记得用一下,不然下次编译可能出现莫名其妙的错误

特别地,现在GitHub有一个叫Actions的服务,有人利用这个服务制作了一套在线编译OpenWrt的系统

主要有以下特色:

  • 免费!快速!一次编译成功率高!
  • 一键快速自动多线程编译
  • 无需搭建编译环境,上手就用,用完就扔

根据项目的中文介绍页面里面的介绍一步步来就可以实现在线编译了(记得提前准备一个GitHub账号)

其中比较友好的是可以支持SSH连接到GitHub Actions虚拟服务器环境,直接在服务器上menuconfig

编译的时候出现了很多错误,不要嫌麻烦,挨个查看改正就行,第一次编译难免出错,正常情况下改一天肯定是能编译出来的

不过后续烧录能不能识别嘛…祈祷自己的设备比较常见吧;特种设备采用特殊器件装特殊系统…自求多福,运气好总能成功的

上位机连接到OpenWrt

终于完成了整个系统的编译,接下来就能尝试烧录并连接到设备了。烧录过程和设备具体硬件配置有关

烧录

如果你使用的是普通路由器,一般来说连上LAN口,登录网关地址,里面的选项里会有一个更新固件,直接把bin文件上传,点击烧录就可以了;如果使用的是一般的嵌入式设备,一般可以选择使用openocd配合jtag进行烧录,只要900+rmb氪入一套jlink基本可以完美烧录(笑)上面两个方法都太简单(没钱买设备是个人问题,有钱人烧录都很简单的)。下面介绍一下常用的三种烧录方法:

  1. uBoot烧录

    一般来说设备出厂以后都会烧录uBoot,这个东西和grub有点像,但是它工作在嵌入式领域,可以支持Linux、安卓、FreeBSD等系统的引导,支持MIPS、x86、ARM、RISC-V等等各种架构的CPU,而OpenWrt对应使用的uBoot往往会着重增强网络能力,因此一般OpenWrt设备的uBoot都会自带TFTP协议的功能,并且会打开一个操作界面,因此可以直接参考厂商给出的说明,按以下步骤启动设备

    • 连接LAN口到上位机
    • 修改上位机IP为厂商指定的静态IP地址,并按照地址设定子网掩码
    • 下位机设备断电,按住Boot按键(或者叫WPS按键)(当然如果没有这个按键应该从Boot引脚到地焊接一根跳线)
    • 将设备上电
    • 保持按键一段时间,等待设备从uBoot启动(类似于按住进入键盘上某个键进入BIOS设置界面)
    • 松开按键并在上位机打开厂商指定的IP地址(浏览器打开,别想着用什么奇奇怪怪的软件)
    • 选择固件、上传、等待
    • 等到足够长时间以后(具体多长要参考厂商说明)修改LAN口为dhcp或默认设置的静态IP
    • 尝试正常连接路由器

    如果中间没有操作界面,可以尝试反复ping要连接的uBoot地址,如果能ping通那就是连上了,之后使用类似下面的uboot命令(由厂商决定)

    tftp 固件保存地址 要上传的固件
    erase 固件启动地址 + $固件大小
    cp 固件保存地址 固件启动地址 $固件大小
    set bootcmd 固件启动地址
    save
    boot
    

    总体过程就是:上传-擦除原本固件-复制上传的固件到启动位置-设置固件启动位置-保存-重启设备

    uBoot功能很强大,在某种程度上说它就像桌面版linux的livecd一样,只要uboot不刷坏,设备就可以说是不死的,一直可以通过重新进入uboot的方式刷新系统

    顺便提一下,对于14.07版本的内核,应用在MT7621上时,安装kmod-usb-ehci与kmod-usb-hid可能会导致冲突让系统崩溃,就是因为同时安装了他俩让我不得不重新刷机好几次

  2. luci界面升级

    就是上面说过的登入网关以后从配置界面上传固件升级的过程,但是一般来说会保留原来系统的配置,所以最好刷更新的固件,而不是刷老版本固件,否则会有可能变砖,还需要用第一种方法再刷一次

  3. 烧录器烧录

    如果uBoot损坏、网口有问题甚至Flash挂了,那就必须使用这种方法了。

    一般来说需要使用专门的Flash烧录器配合上位机软件对准Flash的引脚进行烧录,Flash烧录器有1.8V、3.3V、5V三种,一般来说现在的SPI Flash(最典型的W25Q128)使用3.3V烧录器就可以,但是很多设备都用上了低功耗Flash,这就需要一个电平转换板或者直接使用1.8V烧录器进行烧录。如果是最为极端的情况,Flash挂了,那就必须把Flash拆下来,换一个新Flash上去再烧录

在艰难的配环境过程中,某个不愿透露姓名的学长就把Flash整废了,好巧不巧那块Flash还是特殊封装的贴片元件,极其难焊接,于是只能购入巨贵的专用烧录板,烧录新的Flash以后再装上去。由于没碰见过这种情况+快递速度缓慢,流程整整走了一周。

笔者接手项目以后,还遇到了uBoot死活不启动的情况,检查电路以后发现是板上的Boot线路被莫名划坏一道,于是补好了铜线才得以启动uBoot

新手注意:遇到uBoot不启动不要慌,较大可能是你按的时间不够久或者操作有疏忽导致uBoot启动被跳过了,只要认真多试几遍总能成功,在期间善用百度很关键

Luci

完成系统烧录以后,上电,上位机连上LAN口,等待几分钟,浏览器打开网关地址(一般是192.168.1.1),一般来说就能进入一个登陆界面,这就是OpenWrt的Luci界面

通过这个界面可以对设备的大多数设置进行调整,这里不多作介绍,都是很直接了当的东西

在某些角落会留着language的设置栏,在这里可以选择语言,省去啃生肉的烦恼

串口终端

最传统登录Linux的方法当然是串口终端——不论嵌入式linux还是服务器linux

TTL串口是人类的好朋友

这种方法不必多说,折腾过树莓派的人都懂,串口调试器连接UART Tx、Rx、GND,重启设备,开启Putty或者XShell,之后开机信息就会从界面喷涌而出

SSH

这种方法很适合具有WiFi功能的OpenWrt设备,能够省掉一根网线。不过有网线连接的时候也很实用,对于linux来说命令行总是比可视化可靠。

连上网线ping通后,直接

ssh 用户名(一般是root)@目标设备IP

就可以登录到OpenWrt了

任何其他Linux发行版允许的登录方式

只要在内核里面使能了某个可行的登陆方式,并且硬件允许它运行,那么用户就能用这种方式进行登录OpenWrt

毕竟这可是Linux啊!

联网

强调一下:如果是必须的kmod还是应该先想好然后在编译内核阶段完成安装

一般来说正常安装了网络设备驱动和普通luci界面的设备直接插上网线或者通过luci界面配置好wifi以后就可以联网了,但是如果无法联网可能有以下几个原因:

  1. 编译内核时没有把网络设备驱动编译进去(一般来说是默认添加且不能修改的,但是谁知道用户会做出什么逆天操作)
  2. 外部设备不支持联网(一般是硬件坏了,弄个交换机上OpenWrt还不如多花点钱买个带千/万兆网口的)
  3. 配置问题

1、2点需要重新编译或者检查硬件甚至重新选型,非常难以解决,所以一定要避免这两种问题出现;第三种相对容易解决一些,根据百度到的教程一步步来即可,一般来说都是因为路由器接口/netif/wpa/交换机接口配置出错,依次排除不要着急

在我调试这个板子的时候发生了一件很绝望的事情:板子无法联网,但是能够在内网登录luci界面并ssh。刚开始我以为是软件问题,先去查找了一遍OpenWrt的官方文档,通过luci界面配置了一遍接口,但是无济于事;然后又ssh进去通过vi查找配置文件,无果;因为项目进度逼的比较紧,于是只能换用离线装软件包的方法。等到折腾了一大通硬装软件包以后才想起来检查硬件问题,最后发现是开头说的网络变压器电路问题导致无法联网

所以嵌入式编程一定要先排除硬件问题

包管理器

OpenWrt最与众不同的一点就是它配备了opkg包管理器,它和apt、yum、pacman等指令使用方式类似,能够不是很智能地智能解决软件包依赖问题:只能解决一点点。一般来说自动解决需要一层依赖的软件包安装还是可以的,但是为了安全起见还是一步一步的安装软件包吧。opkg常用指令如下

opkg install 
opkg remove
opkg update
opkg upgrade

软件包管理器的设置位于/etc/opkg

这个包管理器也是支持换源的,如果某个软件源不好连接,完全可以更换当前使用的软件源,使用luci界面就可以轻松换源,如果非要使用命令行也可以像ubuntu那样直接编辑设置文件来换源

具体操作网上有很多,不再赘述,特别指出善用下面的指令可以快速更换软件源的域名

sed -i

特别地,安装软件包时如果碰到了kmod字样的软件包,就说明这是一个内核驱动包,在安装它的时候很可能会遇到内核版本不正确的情况——因为自行编译的OpenWrt生成时会自动携带一个经过修改的md5码,它往往和已有的内核驱动应该对应的验证码不一致,因此会出现报错,这种情况下在安装指令后面加上如下参数就可以解决问题了

--force-depends

如果还是不行,甚至出现系统崩溃、变砖的情况,就要考虑是否是自己的软件源选错抑或是自己编译的内核版本不对了

这就是为什么在上面反复强调要注意内核版本与内核驱动

snapshot版本和release版本区别

我们经常会看到软件源中的某些项目版本以release或snapshots结尾,一般来说snapshots版本代表正在开发中的版本(快照版本,一般处于开发阶段),release代表比较稳定的发布版本(这次迭代的所有功能都已经完成)

换源的操作对于嵌入式Linux,或者说OpenWrt来说不是很重要,但是在面对很难处理的软件bug时可以考虑换源来解决,我在处理项目时通过多次换源解决了一些软件包的依赖问题,使用到的源如下:

清华源 src/gz barrier_breaker_base http://mirrors.tuna.tsinghua.edu.cn/openwrt/barrier_breaker/14.07/ramips/mt7621/packages/base

稳定版官方源 src/gz barrier_breaker_base http://downloads.openwrt.org/snapshots/trunk/ramips/mt7621/packages/base

快照版官方源 src/gz barrier_breaker_base http://downloads.openwrt.org/snapshots/trunk/ramips/mt7621/packages/base

存档版官方源src/gz barrier_breaker_base https://archive.openwrt.org/snapshots/trunk/ramips/mt7621/packages/base

主要的思路就是查看自己要安装的软件包都需要什么依赖,然后对照依赖版本寻找对应的md5码,再根据md5码选择支持的官方源

在换源的时候可能会遇到下面的报错:Package xxx version xxx has no valid architecture, ignoring.

这是因为源指定的系统和设备上刷入的系统md5码不符合,可以直接在/etc/opkg.conf文件中加入对系统支持的architecture的设置,也就是在文件中添加下面的内容:

arch all 100
arch <arch类型1> 200
arch <arch类型2> 300

arch类型可以在源下面的package目录内配置文件中查找到,我使用的配置如下:

arch all 100
arch mips 200
arch ramips 300
arch unkown 400

换用官方archive源也可以帮助解决一些老版本不兼容的问题

安装软件包

只要登陆进luci界面,再让设备联网就可以轻松地进行可视化安装,并且luci界面还会将软件包依赖关系列出来,非常简便;命令行下的安装过程也不算复杂,和ubuntu、centos等发行版的软件安装方法类似

一般我们用opkg安装软件有两种方式:

  • 是连上网络后从官方网站安装

    opkg update
    opkg install xxx
    
  • 把软件下载到上位机(直接进入软件源网页,通过ftp下载即可),通过winscp或者linux下使用scp指令传到路由器tmp目录,再使用指令

    opkg install xxx.ipk
    

    安装

如果路由暂时上不了网,就无法使用前一种方法,后一种方法又有些麻烦,其实除此之外还可以通过上位机开启ftp/http服务,让设备接入来实现“在内网”安装:

  1. 在本机上开ftp/http/其他网络服务

  2. 修改/etc/opkgconfig,将第一行的网址(也就是软件源地址)改成上位机服务器放安装包的服务目录

  3. 从软件源下载需要的安装包到服务目录

  4. 把软件源的packages文件下载到服务目录

  5. 使用指令

    opkg update
    opkg install xxx
    

    安装软件

上面提到了本地安装软件包的方法,所以在这里特别提一下,实际上安装非常麻烦,所以尽量不要使用这种方法

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenWrt与嵌入式Linux 的相关文章

  • 在 vimrc 中切换匹配

    我的 vimrc 文件中有以下几行 hi ExtraWhitespace cterm NONE ctermbg green ctermfg green guibg green guifg green match ExtraWhitespac
  • 当在 python linux 中执行命令 os.system() 时,在 python 中给出响应 yes/no

    考虑一个像这样的命令 yum install boto 当我在终端中执行时 要继续 会询问我是 否 我可以像这样用 python 回应它吗 os system yum install boto Next Yes 将通过相同的 python
  • 命名互斥体的 Mono 替代方案

    在 Windows NET 上 命名的互斥体可用于同步多个进程 不幸的是 Mono 在 Linux 上不太支持这一点 他们的发行说明 http www mono project com Release Notes Mono 2 8 Shar
  • 如何在 Linux 中向热敏打印机发送 ESC/POS 命令

    我正在尝试在热敏打印机上发送 ESC POS 命令 但每当我发送它们时 热敏打印机都会将它们打印为文本 而不是作为命令执行它们 我在 prn 文件中编写这些命令 每当我执行 lp 命令来打印文件时 这些 prn 文件也会被打印 但作为文本
  • Linux 中有没有一种轻量级的方法来获取当前进程数?

    我希望我的 基于 C C 的 程序显示一个数字指示器 指示本地系统上当前有多少个进程 将经常查询正在运行的进程数值 例如每秒一次 以更新我的显示 有没有一种轻量级的方法来获取该数字 显然我可以调用 ps ax wc l 但我不想强迫计算机生
  • Linux 中的 Windows NAmed Pipes 替代品

    我们正在将现有的 Windows 代码移植到 Linux 我们使用 ACE 作为抽象层 我们使用 Windows 命名管道与多个客户端进行通信并执行重叠操作 linux 下这个相当于什么 我检查了linux命名管道 FIFO 但它们似乎只支
  • EULA 接受 Bash 脚本

    我有一个尝试安装垃圾箱的脚本 除了 bin 在 more 中打开 EULA 之外 一切正常 在脚本再次开始并自行完成安装之前 您必须手动 ctrl c 退出此 more 实例 因为这更多的是逃离 shell 所以脚本在打开后不知道要运行什么
  • 每个虚拟主机的错误日志?

    在一台运行 Apache 和 PHP 5 的 Linux 服务器上 我们有多个带有单独日志文件的虚拟主机 我们似乎无法分离 phperror log虚拟主机之间 覆盖此设置
  • 设置 Vim 背景颜色

    当我尝试更改背景颜色时 vimrc或者直接在 Vim 中使用以下命令 set background dark 这根本不影响我的背景 也没有light选项 不过 当我运行 gvim 时 看起来还不错 有没有办法在不更改 Konsole 设置的
  • tar.gz 和 tgz 是同一个东西吗? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我创建了 tgz 文件tar czvf filecommand then 我最终得到了一个 tgz 文件 我想知道它和tar gz 之间的
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • ARM 的内核 Oops 页面错误错误代码

    Oops 之后的错误代码给出了有关 ARM EX 中的恐慌的信息 Oops 17 1 PREEMPT SMP在这种情况下 17 给出了信息 在 x86 中它代表 bit 0 0 no page found 1 protection faul
  • php56 - CentOS - Remi 仓库

    我刚刚在测试盒上安装了 php 5 6 正常的 cli php 解释器似乎不存在 gt php v bash php command not found gt php56 v PHP 5 6 13 cli built Sep 3 2015
  • 期待、互动,然后再次期待

    有几篇关于相同内容的帖子 但我仍然无法使我的期望脚本正常工作 我的目的是自动化一切 但保留用户输入的密码 所以脚本有 3 个部分 自动登录 给予用户交互以输入密码 将控制权交还给 Expect 脚本以继续工作 所以我有一个将生成的脚本 其中
  • 为什么“script”命令会生成 ^[ 和 ^M 字符以及如何使用 vim 搜索和替换删除它们?

    在linux上 使用bash shell 当我使用script命令时 生成的文件称为typescript 当我用 vim 打开该文件时 每一行都包含 M字符 并且有几行 由于我的彩色命令提示符 包含一个字符 我想用任何东西替换这些字符 从而
  • SVN 不断提示我输入密码并拒绝缓存我的凭据

    环境 Eclipse Indigo Ubuntu 11 04 Subclipse 1 6 SVN 客户端 Subclipse RabbitVCS 我通过 svn ssh 连接 我的网址如下所示 svn ssh 我的名字 我的域名 路径 我可
  • 将 bash 脚本作为守护进程运行

    我有一个脚本 它每 X 次运行我的 PHP 脚本 bin bash while true do usr bin php f my script php echo Waiting sleep 3 done 我怎样才能将它作为守护进程启动 要从
  • 为什么 proc/ID/maps 有多个共享库条目

    我正在查看嵌入式Linux下的proc ID maps 我注意到一些共享库在进程的内存映射中出现了几次 为什么会这样呢 40094000 400d9000 r xp 00000000 b3 09 723 system lib libc so
  • Laravel 内存问题?

    各位 我在 DO 服务器上遇到这样的问题 我已经尝试了一切 整个网站在使用 Homestead 的 Linux 服务器上 100 正常工作 但上传后 它只能工作一次 在重新加载或刷新页面后会多次下降 我尝试增加 apache 服务器的内存
  • OS X 对 /usr/local/lib 的权限被拒绝

    我正在寻找有关权限问题的任何建议 直觉 线索 答案 自从我切换到新的 Macbook Pro 以来 这个问题一直困扰着我 这就是困境 某些程序在安装期间复制 usr local lib 下的库 并且在运行这些程序时出现崩溃 我认为这与此文件

随机推荐

  • UWB_IMU室内定位(beginner)——3

    又倒回到代码工程的编译上来了 xff0c 今天上午蔡师兄在实验室就问了一下他 xff0c 蔡师兄我感觉ROS代码能力极强 xff0c 他本科好像是成信的 xff0c 然后就在蒋老师的公司木牛流马工作了 xff0c 我百度了一下 https
  • Docker入门 (一)

    Docker入门 xff08 一 xff09 要学习Docker 首先应该知道什么是Docker xff0c 以及为什么会有Docker呢 xff1f 学习Docker之前最好是已经学习过linux的一些基本名命令 xff0c 以及对Mav
  • MySQL数据库的主键和外键详解

    MySQL数据库的主键和外键详解 主键 主键的定义 主键 xff1a 表中经常有一个列或多列的组合 xff0c 其值能唯一地标识表中的每一行 这样的一列或多列称为表的主键 xff0c 通过它可强制表的实体完整性 当创建或更改表时可通过定义
  • MySQL索引相关(索引的定义、分类、创建与查询)

    索引 索引的定义 在关系数据库中 xff0c 如果有上万甚至上亿条记录 xff0c 在查找记录的时候 xff0c 想要获得非常快的速度 xff0c 就需要使用索引 索引是 MySQL 中一种十分重要的数据库对象 它是数据库性能调优技术的基础
  • mysql基础常用语句

    mysql基础常用语句 数据表的增删改 数据表的新建 数据库只能有一个主键 但是可以存在联合主键 主键值必须唯一 即 xff0c 表中的每个行必须具有唯一的主键值 如果主键使用单个列 xff0c 则它的值必须唯一 如果使用多个列 xff0c
  • 基本数据类型的精度和范围

    Java中的数据类型分为 xff1a 基本数据类型和引用数据类型 如下图所示 xff1a 下面主要要讨论的是基本数据类型的数据表示范围是如何得到的 1 首先应该对计算机的存储单元有一定的了解 在计算机里无论是内存还是硬盘 xff0c 计算机
  • java中构造方法和普通方法的区别

    1 普通方法 xff1a 定义 xff1a 简单的说方法就是完成特定功能的代码块 普通方法定义格式 xff1a 修饰符 返回值类型 方法名 xff08 参数类型 参数名1 xff0c 参数类型 参数名2 xff0c xff09 函数体 xf
  • Microsoft.NET.Framework开机报错解决方法

    win10自动更新后每次开机都报错Microsoft NET Framework 如下图所示 xff1a 网上查了各种各样的方法折腾了好久 其中看到了这样一个回答 有两种可能 你电脑里的某个软件需要使用Microsoft NET Frame
  • 简述Ajax原理及实现步骤

    简述Ajax原理及实现步骤 1 Ajax简介 概念 Ajax 即 Asynchronous Javascript And XML xff08 异步 JavaScript 和 XML xff09 现在允许浏览器与务器通信而无须刷新当前页面的技
  • 计算机网络体系结构综述(上)

    首先附上原文链接 xff1a 计算机网络体系结构综述 xff08 上 xff09 摘要 xff1a 计算机网络体系结构标准的制定使得两台计算机能够像两个知心朋友那样能够互相准确理解对方的意思并做出优雅的回应 本文首先概述了计算机网络体系结构
  • java并发之通过线程工厂创建线程

    通过线程工厂创建线程 ThreadFactory接口的Thread newThread Runnable r 方法 package chapter1 import util Sleeper import java util concurre
  • C和 C ++ 的区别

    1 内联函数 xff1a 在函数的调用点 xff0c 把函数的代码全部展开 xff0c 编译阶段 xff08 一种更安全 xff08 进行类型检查 xff09 宏 xff09 宏 预编译阶段 xff08 字符串替换 xff0c 不进行类型检
  • C| |头文件中为什么只声明不定义,而类定义又可以放在头文件中

    头文件中为什么只声明不定义 xff0c 而类定义又可以放在头文件中 首先要了解几个基本概念 xff1a 编译单元 对于c语言 xff0c 每一个 c文件就是一个编译单元 仅仅从编译来说 xff0c 各个编译单元之间没有联系 未解决符号表 提
  • C#软件工程师、 .NET、 上位机软件开发工程师秋招面经八股汇总 及心得

    博主从七月到十月底一共投了142家企业 xff0c 流程走完的有9家 xff0c 收到7个offer xff0c 目前三方已签 xff0c 很满意签约的公司 xff0c 现在把这几个月我遇到常见问题写下来 xff0c 希望能帮助到大家 心得
  • 网络编程--网络字节序和主机字节序详解

    NBO 网络字节序 HBO 主机字节序 LE little endian xff1a 小端 BE big endian xff1a 大端 空中传输的字节的顺序即网络字节序为标准顺序 xff0c 考虑到与协议的一致以及与同类其它平台产品的互通
  • 实现batch内负采样和解决报错:tensorflow.python.framework.errors_impl.InvalidArgumentError

    在我们实现双塔等模型时一些负样本难以获取 xff0c 这时我们可以通过batch内负采样的方式来实现训练 xff0c 此时采集的样本数据仅需要正样本就够了 我们先来看一个案例 xff0c 通过此案例来理解此代码 import tensorf
  • RabbitMQ安装和使用(docker版本)

    1 查找镜像 xff1a xff08 management 版本的镜像才有管理界面 xff09 docker search rabbitmq management 2 拉取镜像 xff1a docker pull docker io mac
  • OpenCV与图像处理学习七——传统图像分割之阈值法(固定阈值、自适应阈值、大津阈值)

    OpenCV与图像处理学习七 传统图像分割之阈值法 xff08 固定阈值 自适应阈值 大津阈值 xff09 一 固定阈值图像分割1 1 直方图双峰法1 2 OpenCV中的固定阈值分割 二 自动阈值图像分割2 1 自适应阈值法2 2 迭代法
  • 驱动编写入门

    按键控制led驱动 一 框架 1 open read write 函数 static int second drv open struct inode inode struct file file 配置GPF0 2为输入 gpfcon am
  • OpenWrt与嵌入式Linux

    OpenWrt与嵌入式Linux 由于要接手学长留下来的一个项目 xff0c 被迫 要学习OpenWrt的配置方法 虽然对于一个five电工来说这事挺莫名其妙的 xff0c 但还是硬着头皮上吧 xff08 我本想拒绝 xff0c 但他给的是