第七篇 系统BSP开发
文章目录
- 第七篇 系统BSP开发
- 1. 嵌入式Linux系统介绍
- 嵌入式Linux系统组成
- 产品形态
- 嵌入式芯片
- 启动流程
- Linux系统
- Linux系统框架
- 嵌入式编译环境
- 2.嵌入式Linux开发准备
- 手册文档
- 开发工具
- 配套硬件
- 工程源码
- 3.嵌入式Linux开发组成概述
- 编译工具链
- 什么是工具链
- 什么是交叉编译工具链
- 获得合适的交叉编译工具链
- sysroot
- 自由软件许可
- 常见开源组件
- 自由软件与更改分开
- 编译工具
- GUN组织
- Makefile
- Autotools
- Cmake
- Meson
- 编译系统
- buildroot
- Yocto
- Openwrt
- 构建系统对比
- 其他构建工具
- 发行版rootfs
- 4.使用Buildroot BSP构建系统
- 配置开发环境
- 下载vmware虚拟机工具
- 获取Ubuntu系统镜像
- 运行虚拟机系统
- 安装编译所需依赖
- 获取配套源码
- Git下载
- 下载其他
- Buildroot简介
- 构建原理
- skeleton
- 构建流程
- 编译构建系统
- 执行配置命令
- Q:编译nncase错误
- A: 解决方式
- Q:编译AI示例报错
- A: 解决方式
- 构建成功镜像介绍
- 更新系统镜像
- 1.5.1 硬件操作
- 1.5.2 烧录镜像
- 1.5.3 安装WinUSB烧录驱动
- 1.5.4 完整烧录镜像
- 1.5.5 启动EMMC系统
- 5. 使用SDK配套工具链开发应用
- 交叉编译工具链所在位置
- gcc编译器
- 系统组件lib库
- 系统组件头文件
- 支持Makefile
- 配置工具链环境
- 支持Cmake示例
- 6.使用工具链进行驱动开发-简单
- 开发helloword驱动
- 开发gpio点灯驱动+应用
- 7.针对系统进行定制化开发操作
- 支持需要的组件库
- 定义自己的系统启动程序
1. 嵌入式Linux系统介绍
嵌入式Linux系统组成
产品形态
上面的产品都运行的Linux系统,产品的种类外观 场景 非常多,上至飞机,下至 车机 手机。
嵌入式芯片
接下来介绍软件层面的区别
启动流程
Linux系统
-
发行版 系统
-
嵌入式系统
一般称 Linux发行版系统为 大系统,嵌入式自定义系统 为 小系统
Linux系统框架
嵌入式编译环境
2.嵌入式Linux开发准备
资料 资料 资料 !!!
开发板公司做的资料
- 全志T113-S3原厂资料
总结来看只需要:**原厂主芯片资料+BSP源码+ 开发板厂家原理图 位图规格书等。**就可以开始嵌入式开发工作。
手册文档
-
原厂支持的手册 https://github.com/kendryte/k510_docs/
-
K510 主芯片手册
- K510 BSP开发手册
-
DongshanPI-Vision开发板位号图与原理图
开发工具
- 系统烧写工具 KendryteBurningTool: https://github.com/kendryte/BurningTool
配套硬件
- 核心板
- DongshanPI-Vision底板
- MIPI CSI IMX219 摄像头 x2
- 5.5寸 1080P MIPIx4LINE 显示屏
工程源码
- 原厂K510 BSP源码 https://github.com/kendryte/k510_buildroot
-
百问网DongshanPI-Vision BSP源码
-
https://e.coding.net/weidongshan/dongshanpi-vision/buildroot-2020.02.11.git
-
https://e.coding.net/weidongshan/dongshanpi-vision/br2-canaan-k510.git
-
3.嵌入式Linux开发组成概述
编译工具链
什么是工具链
工具链是一组编程工具,用于开发软件、创建软件产品。工具链通常是另一个计算机程序或一组相关程序。通常,工具链里有多个工具,前一个工具的输出结果,是下一个工具的输入,也就是说前一个工具处理完,再交给下一个工具处理。
一个简单工具链可能由三部分组成:编译器和链接器(将源代码转换为可执行程序)、库(为操作系统提供接口)和调试器(用于测试和调试创建的程序)。一个复杂的软件产品,如视频游戏,需要准备音效、音乐、纹理、3 维模型和动画的工具,以及将这些资源组合成成品的附加工具。
**GNU ** 工具链 是一个广泛收集的、遵守GNU协议的、众多编程工具。这些工具形成一个工具链,用于开发应用程序和操作系统。
GNU 工具链在Linux、一些BSD系统和嵌入式系统软件的开发中起着至关重要的作用。
什么是交叉编译工具链
**交叉编译器:**在平台A上使用它能够生成程序,这个程序时运行在平台B上的。例如,在PC上运行程序,但这个程序是在Android 智能手机上运行的,这个编译器就是交叉编译器。
在PC上为其他平台(目标平台)编译代码时,需要交叉编译器。能否直接在目标平台上编译程序?比如在ARM板上编译程序?大多时候不可行,因为ARM板资源很可能受限。
交叉编译器的基本用途是将构建环境与目标环境分开。这在几种情况下很有用:
-
设备资源极其有限的嵌入式计算机。例如,微波炉将有一个非常小的计算机来读取它的键盘和门传感器,向数字显示器和扬声器提供输出,并控制烹饪食物的机器。这台计算机通常不够强大,无法运行编译器、文件系统或开发环境。
-
为多目标编译。例如,公司可能希望用同一套代码,支持多个不同的操作系统。通过使用交叉编译器,可以设置单个构建环境,为每个目标系统单独编译程序。
-
在服务器上编译。服务器性能强大,很多公司都是在服务器上为其他平台编译程序。
-
引导到新平台。在为新平台开发软件时,人们使用交叉编译器来编译必要的工具,例如操作系统和本地编译器。
获得合适的交叉编译工具链
-
获取现成的
- 来自发行版系统内: Ubuntu 和 Debian 有许多现成的交叉编译器。
-
来自不同组织:
-
芯片原厂提供的交叉编译工具链(一般包含在配套的BSP内)。
-
Bootlin社区提供的各种架构工具链 。
-
ARM 官方提供的aarch32 aarch64工具链。
-
Linaro 提供 ARM 和 AArch64 工具链,以及一些早期版本工具链。
-
gnutoolchains 提供可以在windows上运行的交叉编译工具链。
-
riscv-collab 提供的riscv GNU 工具链。
-
-
自己编译构建
-
Crosstool-NG,专门构建交叉编译工具链的工具。 迄今为止拥有最可配置选项/并支持多种功能的。
-
嵌入式Linux构建系统一般都知道如何构建交叉编译工具链:Yocto/OpenEmbedded、Buildroot、OpenWRT等。
-
-
参考文档
-
Crosstool-NG 文档,https://github.com/crosstool-ng/crosstool-ng/blob/master/docs/
-
GCC 文档,https://gcc.gnu.org/onlinedocs/
-
Binutils 文档,https://sourceware.org/binutils/docs/
-
sysroot
参考PPT 03-BUILDROOT课程第一部分之Linux工具链.pptx P18
-
sysroot 是头文件和库 的 逻辑根目录。
-
gcc 寻找头文件,ld 寻找库的地方
-
gcc 和 binutils 都是使用 --with-sysroot= 参数构建的。
-
内核头文件和 C 库安装在 。
-
如果工具链已经移动到不同的位置,如果它在 --prefix 的子目录中,gcc 仍然会找到它的 sysroot ,但是需要在编译时指定如下参数。
--prefix=
--with-sysroot=
-
可以在运行时使用 gcc 的 --sysroot 选项覆盖。
-
可以使用 -print-sysroot 选项打印当前的 sysroot。
可以理解为 sysroot 就是提前帮你约束好了一个统一存放非标准GCC库以外的其他组件/应用 lib库 头文件的位置,方便其他程序 调用,去使用它! 而不用频繁去
增加 -I -L参数进行指定位置。
参考:https://ryan0988.pixnet.net/blog/post/207806602-gcc-sysroot-&-spec-files
参考:https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html
参考: https://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Spec-Files.html#Spec-Files
自由软件许可
常见开源组件
Target设备工具: 系统工具
-
dbus, 一种应用程序间面向对象的通信总线。
-
gpsd,一个解析和共享 GPS 数据的守护进程
-
libusb,一个无需编写内核驱动程序即可访问 USB 设备的用户空间库。
-
内核子系统的实用程序:用于 I2C 的 i2c-tools、用于输入的 input-tools、用于 MTD 设备的 mtd-utils、用于 USB 设备的 usbutils。
Target设备工具:编程语言
-
提供最常见脚本语言的解释器,常用于:
-
应用开发
-
网络服务开发
-
脚本
-
-
支持的编程语言
-
shell(bash、sh…)
-
Lua,简单的嵌入式C应用。
-
python
-
Perl
-
Ruby
-
TCL
-
PHP
-
Target设备工具: 音频 视频 多媒体
- GStreamer,一个多媒体框架
允许对各种编解码器进行解码/编码(FFmpeg)。
通过插件支持硬件编码器和解码器,专有/特定插件通常由 SoC 供应商提供。 - alsa-lib,与 ALSA 内核声音子系统关联的用户空间库
直接使用编解码库, - 如果决定不使用GStreamer:
- libavcodec:来自 ffmpeg 项目,用于 vlc 和 mplayer 等播放器,支持大多数音视频编解码器(mpeg4、h264、vp8、vp9…)
- libvpx:vp8 和 vp9 视频编码
- libflac:FLAC:免费无损音频编解码器
- libopus:最新最大的有损音频编解码器
- libmad:解码mp3音频
Target设备工具: 图形套件(Low-Level)
- Gtk: 著名的工具包,提供基于widget 的高级API 来开发图形应用程序
C 语言中的标准 API,但存在针对各种语言的绑定:C++、Python 等。
在 X.org 和 Wayland 之上工作。
没有窗口系统,运行多个应用程序需要一个轻量级的窗口管理器。 可能的解决方案:Matchbox.。
License:LGPL
多平台:Linux、MacOS、Windows。
官网 https://www.gtk.org
- Wayland: 更简单的 X 替代品
Wayland 是一种供合成器与其客户对话的协议,以及该协议的 C 库实现。
Weston:Wayland 合成器的最小且快速的参考实现,适用于许多嵌入式和移动用例。
大多数图形工具包(Gtk、Qt、EFL…)现在都支持 Wayland。
大多数桌面发行版都支持它:Fedora、Debian、Ubuntu(从 21.04 开始)
https://en.wikipedia.org/wiki/Wayland_(display_server_protocol)
- Qt : 一个著名的工具包,提供基于小部件的高级 API 来开发图形应用程序
C++语言实现
Target(目标)系统需要 C++ 库
C++ 使用的标准 API,但有其他语言的绑定
可以工作在
Framebuffer
X11
wayland
支持多平台:Linux、MacOS、Windows。
拥有非常丰富的文档教程
官网:https://www.qt.io/
License:LGPLv3 和 GPLv3 混合(某些部分是 LGPLv2 和 GPLv2),使得非 GPL 应用程序难以实现。 根据客户的说法,商业许可非常昂贵。
Target设备工具: 数据库
-
SQLite
官网:https://www.sqlite.org
SQLite 是一个小型的 C 库,它实现了一个自包含的、可嵌入的、轻量级的、零配置的 SQL 数据库引擎
嵌入式 Linux 系统的首选数据库引擎
可以作为普通库使用
可以直接嵌入到应用程序中,甚至是专有应用程序,因为 SQLite 是在公共领域发布的
Target设备工具: 网络浏览器
-
WebKit https://webkit.org/ 网络浏览器引擎。 可用于开发 Web 浏览器或向应用程序添加 HTML 渲染功能的应用程序框架。 您还可以用全屏浏览器(更容易实现)替换您的应用程序。
License:LGPL 中的部分和 BSD 中的其他部分允许专有应用。
被许多网络浏览器使用:Safari、iPhone 和 Android 默认浏览器…谷歌浏览器现在使用其 WebCore 组件的一个分支)。 电子邮件客户端也使用它来呈现 HTML。
多个图形后端:Qt、GTK、EFL…
自由软件与更改分开
编译工具
-
每个开源组件都有配置、编译和安装的机制
-
一个基本的 Makefile 需要阅读 Makefile 以了解它是如何工作的以及如何调整它以进行交叉编译
-
基于 Autotools 的构建系统 这是最常见的构建系统。
-
CMake,https://cmake.org/ 比 autotools 更新更简单。 (有时是大型)项目使用。例如 KDE、KiCad、LLVM/Clang、Scribus、OpenCV、Qt。
-
Meson,https://mesonbuild.com/ 使用起来更快更简单。 现在被 GNOME(partially)、GTK+、Gstreamer、Mesa、Systemd、Wayland (Weston) 等项目使用。
-
还有更多…
GUN组织
Makefile
Autotools
一系列工具,它们关联在一起形成了一个完整且可扩展的构建系统
-
autoconf 用于处理软件包的配置
-
automake 用于生成构建软件包所需的 Makefile
-
pkgconfig 用于简化针对已安装共享库的编译
-
llibtool 用于以系统无关的方式处理共享库的生成
这些工具中的大多数都比较陈旧且使用起来相对复杂,但如今大多数免费软件包都在使用它们。 人们必须对他们做什么以及他们如何工作有一个基本的了解。
Cmake
CMake 是一个开源的跨平台工具系列,旨在构建、测试和打包软件。 CMake 用于使用简单的平台和编译器独立配置文件来控制软件编译过程,并生成可在您选择的编译器环境中使用的本机 makefile 和工作区。 CMake 工具套件是由 Kitware 创建的,旨在响应 ITK 和 VTK 等开源项目对强大的跨平台构建环境的需求。
CMake 是 Kitware 的商业支持开源软件开发平台集合的一部分。
Meson
概述:Meson 是一个开源构建系统,其速度非常快,重要的是,它对于用户尽可能友好。
Meson 主要特点是:开发人员花在编写或调试构建定义上的每一刻都是浪费一秒钟。
等待构建系统从开始编译代码的每一秒也是如此。
特征:对 Linux、macOS、Windows、GCC、Clang、Visual Studio 和
其他受支持语言的多平台支持,包括 C、C++、D、Fortran、Java、Rust 构建定义,
采用非常易读且用户友好的非图灵完备 DSL 交叉编译,适用于许多操作系统以及裸机系统。
在保证准确性的情况下最大程度优化了速度和增量构建,
与发行包一起工作的内置多平台依赖提供程序。
编译系统
- Buildroot,由社区开发 https://buildroot.org
- OpenWRT,最初是无线路由器Buildroot的一个分支,现在是一个更通用的项目 https://openwrt.org
- OpenEmbedded,更灵活但也更复杂 http://www.openembedded.org 及其工业化版本 Yocto 项目。
- lPTXdist,由 Pengutronix 开发 https://www.ptxdist.org 类似的配置界面(menuconfig),但刚开始有点难掌握。
buildroot
Yocto
Openwrt
构建系统对比
其他构建工具
发行版rootfs
4.使用Buildroot BSP构建系统
配置开发环境
HOST主机配置建议:
- i5 8代以上处理器,至少 4核心 主频在 3Ghz以上
- DDR3 1660Mhz 12GB以上内存
- 300G以上存储可用空间
- 电脑预留至少两个 USB 2.0 TYpeA接口
- 电脑支持 WiFi 2.4Ghz 频率无线上网
- 电脑支持 Windows10+ 以上系统 (不支持Mac 不支持裸跑ubuntu/其他版本Linux)
下载vmware虚拟机工具
使用浏览器打开网址 https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html 参考下图箭头所示,点击下载安装 Windows版本的VMware Workstation ,点击 DOWNLOAD NOW 即可开始下载。
下载完成后全部使用默认配置一步步安装即可。
获取Ubuntu系统镜像
- 使用浏览器打开 https://www.linuxvmimages.com/images/ubuntu-2004/ 找到如下箭头所示位置,点击 VMware Image 下载。
- 或者使用资料光盘内:
1_DongshanPI-Vision资料\3_DongshanPI-Vision_配套工具\【VMware】Ubuntu-20.04虚拟机系统镜像
目录下Ubuntu_20.04.4_VM.7z
下载过程可能会持续 10 到 30 分钟,具体要依据网速而定。
运行虚拟机系统
- 解压缩 虚拟机系统镜像压缩包,解压缩完成后,可以看到里面有如下两个文件,接下来,我们会使用 后缀名为 .vmx 这个 配置文件。
- 打开已经安装好的 vmware workstation 软件 点击左上角的 文件 → 打开 找到上面的 Ubuntu_18.04.6_VM_LinuxVMImages.COM.vmx 文件,之后会弹出新的虚拟机对话框页面。
- 如下图所示为 为我们已经虚拟机的配置界面,那面我们可以 点击 红框 1 编辑虚拟机设置 里面 去调正 我们虚拟机的 内存 大小 和处理器个数,建议 最好 内存为 8GB 及以上,处理器至少4 个,网络适配器最好使用 桥接模式。 调整好以后,就可以 点击 开启此虚拟机 来运行此虚拟机了
第一次打开会提示 一个 虚拟机已经复制的 对话框,我们这时,只需要 点击 我已复制虚拟机 就可以继续启动虚拟机系统了。
等待数秒,系统就会自动启动了,启动以后 鼠标点击 Ubuntu 字样,就可以进入登录对话框,输入 密码 ubuntu 即可登录进入ubuntu系统内。
注意:
Ubuntu默认的用户名密码分别为 ubuntu ubuntu
Ubuntu默认的用户名密码分别为 ubuntu ubuntu
Ubuntu默认的用户名密码分别为 ubuntu ubuntu
ubuntu默认需要联网,如果你的 Windows电脑已经可以访问Internet 互联网,ubuntu系统后就会自动共享 Windows电脑的网络 进行连接internet 网络。
安装编译所需依赖
- 安装必要软件包, 鼠标点击进入 ubuntu界面内,键盘同时 按下 ctrl + alt + t 三个按键会快速唤起,终端界面,唤起成功后,在终端里面执行如下命令进行安装必要依赖包。
你的ubuntu虚拟机 第一次启动是 无法 通过 windows下复制 命令 粘贴到 ubuntu内的,则需要先手敲 执行如下命令 安装一个 用于 虚拟机和 windows共享剪切板的工具包,安装完成后,点击右上角的 电源按钮,重启ubuntu系统,或者 直接输入 sudo reboot 命令进行重启。重启系统后 才可以执行 Windows复制 粘贴至 ubuntu的拖拽操作。
sudo apt install open-vm-tools-desktop
重启系统后,重新打开终端 复制如下 命令 来安装 编译 DongshanPI-Vision系统所需的必要依赖包,键盘同时 按下 ctrl + alt + t 三个按键会快速唤起,终端界面,唤起成功后,在终端里面执行如下命令进行安装必要依赖包。
sudo apt-get install -y g++ vim libssl-dev android-tools-fastboot python3-pip mtd-utils libncurses5-dev libgdbm-dev libnss3-dev libreadline-dev libgdbm-dev libffi-dev wget sed make binutils build-essential gcc bash patch gzip bzip2 perl tar cpio unzip rsync file bc python cvs git mercurial subversion android-tools-mkbootimg zlib1g-dev libgdbm-dev libc6:i386 libstdc++6:i386 libncurses5:i386 zlib1g:i386
这时就可以 通过windows端向ubuntu内粘贴文件,或者拷贝拷出文件了。
做完这一步以后,就可以继续往下,获取源码。
如果下载安装速度非常慢,可以修改 软件源地址为 国内 阿里云源 或者 清华源
获取配套源码
Git下载
打开VMware虚拟机工具启动Ubuntu20.04系统,启动完成后在用户目录中打开终端,创建DongshanPI-Vision
文件夹,用于存放系统源码。
进入DongshanPI-Vision
目录下,拉取系统源码:https://e.coding.net/weidongshan/dongshanpi-vision/br2-canaan-k510.git。
进入br2-canaan-k510
目录下,拉取buildroot源码:https://e.coding.net/weidongshan/dongshanpi-vision/buildroot-2020.02.11.git。
ubuntu@ubuntu2004:~$ mkdir DongshanPI-Vision && cd DongshanPI-Vision
ubuntu@ubuntu2004:~/DongshanPI-Vision$ git clone https://e.coding.net/weidongshan/dongshanpi-vision/br2-canaan-k510.git
ubuntu@ubuntu2004:~/DongshanPI-Vision$ cd br2-canaan-k510/
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ git clone https://e.coding.net/weidongshan/dongshanpi-vision/buildroot-2020.02.11.git
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ ls
board Config.in docs external.mk Makefile package pkg-download release_notes.md tools
buildroot-2020.02.11 configs external.desc LICENSE mkdtb-local.sh patches README.md toolchain
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$
下载其他
为了加速整个编译的时间和避免出现因为某些包无法下载导致的问题,我们需要单独讲 我们提前准备好的 dl.tar.gz nds64le-elf-mculib-v5d.txz 压缩包单独下载下来 然后拷贝至 bsp工程目录内进行解压缩。
- dl.tar.gz 压缩包:
- 下载方式一:浏览器 访问 链接 点击下载 https://dongshanpi.cowtransfer.com/s/4d7394cfad3640
- 下载方式二:资料光盘内
1_DongshanPI-Vision资料/2_DongshanPI-Vision_BSP源码
dl.tar.gz
- nds64le-elf-mculib-v5d.txz 压缩包
- 下载方式一:浏览器 访问 链接 点击下载 https://dongshanpi.cowtransfer.com/s/bc101fb198e746
- 下载方式二:资料光盘内
1_DongshanPI-Vision资料/2_DongshanPI-Vision_BSP源码
nds64le-elf-mculib-v5d.txz
提前下载准备好 dl.tar.gz nds64le-elf-mculib-v5d.txz 两个压缩包以后,可以直接通过 Filezila tftp传输工具上传至 BSP工程目录,也可以通过拖拽方式 直接拉至 ubuntu文件管理器内。
切换到 终端命令行界面,可以看到 多出来的两个压缩包
解压压缩包dl.tar.gz文件
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ tar -xzvf dl.tar.gz
解压完成后可以在当前文件夹看到多出了一个名为dl
文件夹
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ ls
board dongshanpi-vision_defconfig patches
buildroot-2020.02.11 external.desc pkg-download
Config.in external.mk README.md
configs LICENSE release_notes.md
dl Makefile toolchain
dl.tar.gz mkdtb-local.sh tools
docs package
之后解压缩 nds64le-elf-mculib-v5d.txz 因为这个压缩包 最终要解压到 DongshanPI-Vision/br2-canaan-k510/toolchain 目录,所以我们需要使用 -C 指定解压路径来进行解压操作。
解压交叉编译工具链压缩包 nds64le-elf-mculib-v5d.txz
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510/toolchain$ tar -xvf nds64le-elf-mculib-v5d.txz -C toolchain
解压完成后,我们就可以开始进行 编译操作了!
Buildroot简介
参考课程嵌入式Linux Buildroot系列开发第一部分之基础知识课件 《BUILDROOT课程第一部分之Buildroot介绍.pptx》《BUILDROOT课程第一部分之配置Buildroot支持boards.pptx》
构建原理
skeleton
根文件系统 skeleton(骨架)
构建流程
一个ROOTFS 的完整构建流程
make 实现(带有一些辅助 shell 脚本) 所有交互通过在 Buildroot 源目录中调用 make 运行。
$ make help
无需以 root 身份运行,Buildroot 旨在以普通用户权限执行。甚至强烈建议不要以 root 身份运行!
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig$ make help
Cleaning:
clean - delete all files created by build
distclean - delete all non-source files (including .config)
Build:
all - make world
toolchain - build toolchain
sdk - build relocatable SDK
Configuration:
menuconfig - interactive curses-based configurator
nconfig - interactive ncurses-based configurator
xconfig - interactive Qt-based configurator
gconfig - interactive GTK-based configurator
oldconfig - resolve any unresolved symbols in .config
syncconfig - Same as oldconfig, but quietly, additionally update deps
olddefconfig - Same as syncconfig but sets new symbols to their default value
randconfig - New config with random answer to all options
defconfig - New config with default answer to all options;
BR2_DEFCONFIG, if set on the command line, is used as input
savedefconfig - Save current config to BR2_DEFCONFIG (minimal config)
update-defconfig - Same as savedefconfig
allyesconfig - New config where all options are accepted with yes
allnoconfig - New config where all options are answered with no
alldefconfig - New config where all options are set to default
randpackageconfig - New config with random answer to package options
allyespackageconfig - New config where pkg options are accepted with yes
allnopackageconfig - New config where package options are answered with no
Package-specific:
<pkg> - Build and install <pkg> and all its dependencies
<pkg>-source - Only download the source files for <pkg>
<pkg>-extract - Extract <pkg> sources
<pkg>-patch - Apply patches to <pkg>
<pkg>-depends - Build <pkg>'s dependencies
<pkg>-configure - Build <pkg> up to the configure step
<pkg>-build - Build <pkg> up to the build step
<pkg>-show-info - generate info about <pkg>, as a JSON blurb
<pkg>-show-depends - List packages on which <pkg> depends
<pkg>-show-rdepends - List packages which have <pkg> as a dependency
<pkg>-show-recursive-depends
- Recursively list packages on which <pkg> depends
<pkg>-show-recursive-rdepends
- Recursively list packages which have <pkg> as a dependency
<pkg>-graph-depends - Generate a graph of <pkg>'s dependencies
<pkg>-graph-rdepends - Generate a graph of <pkg>'s reverse dependencies
<pkg>-dirclean - Remove <pkg> build directory
<pkg>-reconfigure - Restart the build from the configure step
<pkg>-rebuild - Restart the build from the build step
busybox:
busybox-menuconfig - Run BusyBox menuconfig
linux:
linux-menuconfig - Run Linux kernel menuconfig
linux-savedefconfig - Run Linux kernel savedefconfig
linux-update-defconfig - Save the Linux configuration to the path specified
by BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE
Documentation:
manual - build manual in all formats
manual-html - build manual in HTML
manual-split-html - build manual in split HTML
manual-pdf - build manual in PDF
manual-text - build manual in text
manual-epub - build manual in ePub
graph-build - generate graphs of the build times
graph-depends - generate graph of the dependency tree
graph-size - generate stats of the filesystem size
list-defconfigs - list all defconfigs (pre-configured minimal systems)
Miscellaneous:
source - download all sources needed for offline-build
external-deps - list external packages used
legal-info - generate info about license compliance
show-info - generate info about packages, as a JSON blurb
printvars - dump internal variables selected with VARS=...
make V=0|1 - 0 => quiet build (default), 1 => verbose build
make O=dir - Locate all output files in "dir", including .config
For further details, see README, generate the Buildroot manual, or consult
it on-line at http://buildroot.org/docs.html
make defconfig
make menuconfig
make -dirclean
make -rebuild
make savedefconfig
make sdk
make V=1
编译构建系统
执行配置命令
在DongshanPI-Vision/br2-canaan-k510
目录下,执行make CONF=dongshanpi-vision_defconfig
,在SDK源码内指定DongshanPI-Vision开发板系统配置文件。
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ make CONF=dongshanpi-vision_defconfig
配置完成后会自动开始编译系统。编译时间可能会比较长,大概需要 2 - 3个小时!
为了加速编译过程,我们直接使用我们提前准备好的 输出工程,放在 BSP 工程目录来加速编译,确保 你的Ubuntu 环境没有问题,如果你希望 可以重头编译,查看编译详细过程,就不需要操作这一步。我们直接将资料光盘内 1_DongshanPI-Vision资料/2_DongshanPI-Vision_BSP源码
dongshanpi-vision_defconfig.tar.gz 通过拖拽方式/tftp方式上传至 **~/DongshanPI-Vision/br2-canaan-k510 **目录,然后 使用 rm -r dongshanpi-vision_defconfig/ 命令 删除刚才的缓存数据,之后解压缩 dongshanpi-vision_defconfig.tar.gz 压缩包,解压成功后继续执行 make CONF=dongshanpi-vision_defconfig 命令。
Q:编译nncase错误
验证命令
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig$ make nncase_linux_runtime-rebuild
A: 解决方式
配置ubuntu默认 python 版本一定要为 3.8 ,否则无法安装 nncase-k510
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 2
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ update-alternatives --list python
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ sudo update-alternatives --config python
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ python -m pip install --upgrade pip
配置完成后 需要 重启Ubuntu系统生效 才能继续执行后续的命令
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ pip install nncase-k510 -i https://pypi.tuna.tsinghua.edu.cn/simple
Q:编译AI示例报错
验证命令
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig$ make ai-rebuild
A: 解决方式
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig$ pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/simple
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig$ pip install onnxsim -i https://pypi.tuna.tsinghua.edu.cn/simple
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig$ pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ make ai-rebuild
方法二: 使用资料光盘内的 pip 包集合1_DongshanPI-Vision资料/2_DongshanPI-Vision_BSP源码
requirements.txt 执行如下命令进行统一安装!
构建成功镜像介绍
编译完成后,会生成dongshanpi-vision_defconfig
文件夹
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510$ cd dongshanpi-vision_defconfig/
ubuntu@ubuntu2004:~/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig$ ls
build host images Makefile nand_target staging target
其中各文件描述如下:
文件 | 内容描述 |
---|---|
Makefile | 编译镜像使用的Makefile。 |
build | 所有源码包的编译目录。例如linux kernel,u-boot,BBL,busybox等,源码都会解压到build目录下并编译。 |
host | 所有host package的安装路径,toolchain也会拷贝至此目录下,用于构建交叉编译环境。 |
images | 编译生成的目标文件目录(详见下面的说明) |
nand_target | 根文件系统原始目录(生成NandFlash镜像使用) |
target | 根文件系统原始目录(生成eMMC和SD卡镜像使用) |
- dongshanpi-vision_defconfig/images目录下是烧录镜像,其中各个文件的说明如下。
文件 | 内容描述 |
---|---|
bootm-bbl.img | Linux+bbl内核镜像(打包过内核的bbl目标文件,用于uboot引导bbl) |
k510.dtb | 设备树 |
sysimage-emmc.img | emmc烧录文件:已整个打包uboot_burn、kernel和bbl |
sysImage-sdcard.img | sdcard烧录文件:已整个打包uboot_burn、kernel和bbl |
sysImage-nand.img | nand烧录文件:已整个打包uboot_burn、kernel和bbl |
u-boot.bin | uboot 二进制文件 |
u-boot_burn.bin | uboot 烧录文件 |
uboot-emmc.env | uboot环境变量:用于emmc启动 |
uboot-sd.env | uboot环境变量:用于sdcard启动 |
uboot-nand.env | uboot环境变量:用于nand启动 |
vmlinux | Linux内核镜像文件(带elf调试信息) |
rootfs.ext2 | buildroot格式rootfs ext2镜像文件 |
sysimage-sdcard-debian.img | sdcard烧录文件:卡镜像(debian格式rootfs) |
- dongshanpi-vision_defconfig/build 目录下是所有被编译对象的源码,其中几个重要的文件说明如下。
文件 | 内容描述 |
---|---|
linux-xxx | 被编译的 Linux kernel源码目录 |
uboot-xxx | 被编译的 Uboot 源码目录 |
riscv-pk-k510-xxx | 被编译的 bbl 源码目录 |
… |
注: xxx是版本号。后面章节引用kernle,bbl和uboot的路径时,xxx均表示版本号。
需要特别注意:当make clean 的时候,dongshanpi-vision_defconfig文件夹下所有内容将被删除。所以,如果需要修改kernel、bbl或者uboot代码,不要直接在build目录下修改,可以进行 单独 编译 uboot kernel 操作。
单独清理 缓存,重新生成系统镜像 rm output/target; find output/build/ -name .stamp_target_installed | xargs rm; make
更新系统镜像
硬件要求:
- DongshanPI-Vision开发板
- Type-c数据线 x2
软件要求:
- 拷贝前面编译打包好的emmc系统镜像 sysimage-emmc.img 至 Windows 目录内,并记住它在计算机中保存的位置。
- 解压资料光盘内
1_DongshanPI-Vision资料\3_DongshanPI-Vision_配套工具\【Windows】DongshanPI-Vision EMMC烧录工具
KendryteBurningTool 烧录工具。
1.5.1 硬件操作
将下图中的拨码开关的boot0和boot1都向上拨,使开发板进入下载模式。使用两条Type-C线连接开发板端和电脑端,用于给开发板进行供电和使用串口进行烧录EMMC系统。
1.5.2 烧录镜像
下载EMMC镜像并记住它在计算机中的位置。打开KendryteBurningTool 烧录工具,进入KendryteBurningTool\bin
目录下,双击打开BurningTool.exe
,如下所示的文件。
注意:在使用KendryteBurningTool 烧录工具时需要关闭串口软件和虚拟机,防止串口被占用。
打开BurningTool.exe
程序后会进入如下界面:
点击选择文件,选择下载好的EMMC镜像。选择完成后点击保存,操作步骤如下所示:
保存后需要在串口选择中选择开发板的串口号,当我们将开发板和PC电脑端通过Type-C连接起来后,可以在BurningTool软件中点击红色箭头处查看我开发板的端口号,选择开发板的串口端口号。(我们也可以在设备管理器中确认开发的端口号)
选择完成后,点击开始烧录烧录。如果您不是第一次进行烧录,此时等待成功烧录完成即可。如果您是第一次进行烧录请继续阅读下面的内容。第一次烧录步骤如下所示:
当PC电脑首次进行烧录时,第一个进度条结束后,会显示下图中的错误信息。此时需要安装驱动。
1.5.3 安装WinUSB烧录驱动
- 找到资料光盘内
1_DongshanPI-Vision资料\3_DongshanPI-Vision_配套工具\【Windows】DongshanPI-Vision EMMC烧录工具
zadig-2.4.exe 双击并运行。
打开zadig-2.4
软件,进入如下界面
点击Option
中的选择List All Devices
(列出所有设备),具体操作如下所示:
上述操作完成后,可以看到在虚线框内出现了设备名,我们需要切换设备为 Mass storage devices
,具体操作如下所示:
点击Replace Driver
替换驱动程序,此时会弹出一个确认窗口,点击是
。
安装完成后会弹出以下窗口点击close
到此烧录驱动成功安装。
1.5.4 完整烧录镜像
安装完成烧录镜像后,再次打开BurningTool.exe
烧录工具软件,按一下开发板 RESET按键,按照1.5.3章节中的操作进行烧录即可。完整烧录步骤如下所示:
1.5.5 启动EMMC系统
将下图中的拨码开关的boot0和boot1都向下拨,使开发板进入EMMC启动模式。使用两条Type-C线连接开发板端和电脑端,用于给开发板进行供电和使用串口登录开发板控制台。
使用串口软件查看串口控制台,成功启动后会进入开发板控制台。
之后 我们需要参考 文章开头 开发板使用章节 使开发板可以连接WiFi网络,进行后续的 程序开发上传操作
5. 使用SDK配套工具链开发应用
交叉编译工具链所在位置
gcc编译器
所在路径:~/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/bin
系统组件lib库
所在路径:~/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/riscv64-buildroot-linux-gnu/sysroot/usr/lib
系统组件头文件
所在路径:~/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/riscv64-buildroot-linux-gnu/sysroot/usr/include
支持Makefile
配置工具链环境
如果需要在任意位置或者终端都可以使用交叉编译工具链,则需要单独 增加 工具链bin的路径至 ubuntu PATH环境变量里,可以添加至 ~/.bashrc
也可以在每一个终端单独配置。export PATH=$PATH:/home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/bin
配置完成后,执行 riscv64-linux-gcc -v
验证是否配置成功。
ubuntu@ubuntu2004:~$ export PATH=$PATH:/home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/bin
ubuntu@ubuntu2004:~$ riscv64-linux-gcc -v
"/home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/opt/ext-toolchain/bin/riscv64-linux-gcc.gnu" "--sysroot" "/home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/riscv64-buildroot-linux-gnu/sysroot" "-mabi=lp64d" "-march=rv64imafd" "-v"
Using built-in specs.
COLLECT_GCC=/home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/opt/ext-toolchain/bin/riscv64-linux-gcc.gnu
COLLECT_LTO_WRAPPER=/home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/opt/ext-toolchain/bin/../libexec/gcc/riscv64-linux/7.3.0/lto-wrapper
Target: riscv64-linux
Configured with: /local/sqa/Jenkins/workspace/build-system-3/source-packages/gcc-7.4.0-riscv-ast-v3_2_0-branch-official/configure --target=riscv64-linux --prefix=/local/sqa/Jenkins/workspace/build-system-3/toolchain/nds64le-linux-glibc-v5d --with-pkgversion=2019-11-20_nds64le-linux-glibc-v5d-6c120106e03 --disable-nls --enable-languages=c,c++ --enable-lto --with-gmp=/local/sqa/Jenkins/workspace/build-system-3/host-tools --with-mpfr=/local/sqa/Jenkins/workspace/build-system-3/host-tools --with-mpc=/local/sqa/Jenkins/workspace/build-system-3/host-tools --with-isl=/local/sqa/Jenkins/workspace/build-system-3/host-tools --with-cloog=/local/sqa/Jenkins/workspace/build-system-3/host-tools --with-arch=rv64imafdcxv5 --with-tune=nx25 --enable-gp-insn-relax-default=yes --with-abi=lp64d --disable-werror --disable-multilib --enable-shared --enable-tls --with-sysroot=/local/sqa/Jenkins/workspace/build-system-3/toolchain/nds64le-linux-glibc-v5d/riscv64-linux/sysroot CFLAGS='-O2 -g -Wno-implicit-fallthrough -Wno-int-in-bool-context -Wno-cast-function-type -Wno-tautological-compare ' CXXFLAGS='-O2 -g -Wno-implicit-fallthrough -Wno-int-in-bool-context -Wno-cast-function-type -Wno-tautological-compare ' CC=/local/sqa/Jenkins/workspace/build-system-3/host-tools/bin/gcc CXX=/local/sqa/Jenkins/workspace/build-system-3/host-tools/bin/g++ LD=/local/sqa/Jenkins/workspace/build-system-3/host-tools/bin/ld AR=/local/sqa/Jenkins/workspace/build-system-3/host-tools/bin/gcc-ar RANLIB=/local/sqa/Jenkins/workspace/build-system-3/host-tools/bin/gcc-ranlib NM=/local/sqa/Jenkins/workspace/build-system-3/host-tools/bin/nm --enable-checking=release LDFLAGS=--static 'CFLAGS_FOR_TARGET=-O2 -g -mstrict-align -msoft-fp16' 'CXXFLAGS_FOR_TARGET=-O2 -g -mstrict-align -msoft-fp16' LDFLAGS_FOR_TARGET=
Thread model: posix
gcc version 7.3.0 (2019-11-20_nds64le-linux-glibc-v5d-6c120106e03)
ubuntu@ubuntu2004:~$
讲工具链路径增加至环境变量以后,可以使用Makefile 指定我们的交叉编译工具链,编译一个 hello.c 通过 scp 方式,传输至开发板内,进行运行。
如下所示,为Makefile 示例,以及 hello.c 程序示例。
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/makefile-hello$ cat Makefile
CC := riscv64-linux-gcc
hello: hello.c
${CC} -o hello hello.c
clean:
rm hello
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/makefile-hello$ cat hello.c
#include <stdio.h>
int main(void)
{
printf ("Hello 100ASK DongshanPI-Vision K510 AI Board !!! \r\n");
return 0;
}
写完程序后,执行make命令来编译,编译完成后可以通过 网络方式讲 文件传输至开发板内。
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/makefile-hello$ make
riscv64-linux-gcc -o hello hello.c
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/makefile-hello$ file hello
hello: ELF 64-bit LSB executable, UCB RISC-V, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-riscv64-lp64d.so.1, for GNU/Linux 4.15.0, with debug_info, not stripped
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/makefile-hello$
如下为传输命令,先确保开发板 可以连接网络,之后 我们 讲 ubuntu下编译好的程序,拖拽到 windows下,使用 ssh 登陆开发板,然后 通过 tftp等命令上传编译后的 hello 可执行程序。
[root@canaan /usr ]$ wpa_passphrase Programmers 100asktech > /etc/wpa_supplican
t.conf
[root@canaan /usr ]$ cat /etc/wpa_supplicant.conf
network={
ssid="Programmers"
#psk="100asktech"
psk=934634dfcb4c3d40869ffb1ad66fd7857d80b2751d576e31e05bc587f20c9985
}
[root@canaan /usr ]$
[root@canaan /usr ]$ wpa_supplicant -D nl80211 -i wlan0 -c /etc/wpa_supplicant.conf &
Successfully initialized wpa_supplicant
[ 2199.972897] [dhd] P2P interface registered
[ 2200.006809] [dhd] WLC_E_IF: NO_IF set, event Ignored
[ 2200.014276] [dhd] P2P interface started
[ 2200.051980] [dhd] [wlan0] wl_run_escan : LEGACY_SCAN sync ID: 0, bssidx: 0
wlan0: Trying to associate with SSID 'Programmers'
[ 2201.178392] [dhd] CFG80211-ERROR) wl_set_set_cipher : set wsec_info error (0)
[ 2201.191461] [dhd] [wlan0] wl_conn_debug_info : Connecting with 94:d9:b3:b7:c9:0a ssid "Programmers", len (11), channel=2g-7(chan_cnt=1), sec=wpa2/psk/mfpn/tkip/aes, rssi=-39
[ 2201.272947] [dhd] [wlan0] wl_ext_iapsta_link : [S] Link UP with 94:d9:b3:b7:c9:0a
[ 2201.284568] [dhd] [wlan0] wl_bss_connect_done : Report connect result - connection succeeded
wlan0: Associated with 94:d9:b3:b7:c9:0a
wlan0: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0
[ 2201.327785] [dhd] [wlan0] wl_add_keyext : key index (0) for 94:d9:b3:b7:c9:0a
wlan0: WPA: Key negotiation completed with 94:d9:b3:b7:c9:0a [PTK=CCMP GTK=TKIP]
wlan0: CTRL-EVENT-CONNECTED - Connection to 94:d9:b3:b7:c9:0a completed [id=0 id_str=]
[root@canaan /usr ]$ udhcpc -i wlan0
udhcpc: started, v1.31.1
udhcpc: sending discover
udhcpc: sending select for 192.168.0.174
udhcpc: lease of 192.168.0.174 obtained, lease time 122
deleting routers
adding dns 192.168.0.1
adding dns 192.168.0.1
[root@canaan /usr ]$
最后执行程序,即可看到通过 Makefile 交叉编译生成的hello 可执行程序在开发板上运行了起来。
支持Cmake示例
使用CMake构建语言就和Makefile存在了一定的区别,如下演示示例,提供同样的 hello.c 程序,通过CMake构建语言去指定交叉编译工具链头文件lib库等位置,编写出 CMakeLists.txt
编译规则文件,最后使用 cmake
进行编译生成
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/cmake-hello$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(helloword)
SET(CROSS_COMPILE 1)
set(CMAKE_SYSTEM_NAME Linux)
#CROSS_COMPILE Path
set(CMAKE_C_COMPILER "/home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/bin/riscv64-linux-gcc")
#Link LibsPath
link_directories(
/home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/riscv64-buildroot-linux-gnu/sysroot/usr/lib
)
#Include Path
include_directories(/home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/riscv64-buildroot-linux-gnu/sysroot/usr/include/)
add_executable(hello_word hello.c)
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/cmake-hello$ cat hello.c
#include <stdio.h>
int main(void)
{
printf ("Hello Cmake 100ASK DongshanPI-Vision K510 AI Board !!! \r\n");
return 0;
}
如下图所示为编译演示步骤,需要先在工程目录下 创建一个 build 目录,之后进入到这个 build 目录内,执行 cmake … 命令,进行编译前的检查配置,检查通过后,执行make命令来开始编译,最终生成hello_word 可执行程序,通过adb 命令上传至开发板,最后在开发板内执行。
这里只列举了两个简单的示例,大家可以自行根据《第三节课嵌入式Linux开发简述》课程里面 Autotools 举例的helloword示例,以及 meson 举例的 helloword示例,如何进行交叉编译在开发板上运行。
6.使用工具链进行驱动开发-简单
开发helloword驱动
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/hello_drv$ cat hello_drv.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
/* 1. 确定主设备号 */
static int major = 0;
static char kernel_buf[1024];
static struct class *hello_class;
#define MIN(a, b) (a < b ? a : b)
/* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_to_user(buf, kernel_buf, MIN(1024, size));
return MIN(1024, size);
}
static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_from_user(kernel_buf, buf, MIN(1024, size));
return MIN(1024, size);
}
static int hello_drv_open (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static int hello_drv_close (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
/* 2. 定义自己的file_operations结构体 */
static struct file_operations hello_drv = {
.owner = THIS_MODULE,
.open = hello_drv_open,
.read = hello_drv_read,
.write = hello_drv_write,
.release = hello_drv_close,
};
/* 4. 把file_operations结构体告诉内核:注册驱动程序 */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init hello_init(void)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
major = register_chrdev(0, "hello", &hello_drv); /* /dev/hello */
hello_class = class_create(THIS_MODULE, "hello_class");
err = PTR_ERR(hello_class);
if (IS_ERR(hello_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "hello");
return -1;
}
device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
return 0;
}
/* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */
static void __exit hello_exit(void)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
device_destroy(hello_class, MKDEV(major, 0));
class_destroy(hello_class);
unregister_chrdev(major, "hello");
}
/* 7. 其他完善:提供设备信息,自动创建设备节点 */
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/hello_drv$ cat hello_drv_test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/*
* ./hello_drv_test -w abc
* ./hello_drv_test -r
*/
int main(int argc, char **argv)
{
int fd;
char buf[1024];
int len;
/* 1. 判断参数 */
if (argc < 2)
{
printf("Usage: %s -w <string>\n", argv[0]);
printf(" %s -r\n", argv[0]);
return -1;
}
/* 2. 打开文件 */
fd = open("/dev/hello", O_RDWR);
if (fd == -1)
{
printf("can not open file /dev/hello\n");
return -1;
}
/* 3. 写文件或读文件 */
if ((0 == strcmp(argv[1], "-w")) && (argc == 3))
{
len = strlen(argv[2]) + 1;
len = len < 1024 ? len : 1024;
write(fd, argv[2], len);
}
else
{
len = read(fd, buf, 1024);
buf[1023] = '\0';
printf("APP read : %s\n", buf);
}
close(fd);
return 0;
}
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/hello_drv$ cat Makefile
# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH, 比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
# 请参考各开发板的高级用户使用手册
KERN_DIR = /home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/build/linux-origin_master/
all:
make -C $(KERN_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
rm -f hello_drv_test
obj-m += hello_drv.o
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/hello_drv$
export PATH=$PATH:/home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/host/bin/
export ARCH=riscv
export CROSS_COMPILE=riscv64-linux-
开发gpio点灯驱动+应用
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/led_drv$ cat leddrv.c
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
/* 1. 确定主设备号 */
static int major = 0;
static struct class *led_class;
static struct gpio_desc *led_gpio;
/* 3. 实现对应的open/read/write等函数,填入file_operations结构�? */
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
/* write(fd, &val, 1); */
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
char status;
//struct inode *inode = file_inode(file);
//int minor = iminor(inode);
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_from_user(&status, buf, 1);
/* 根据次设备号和status控制LED */
gpiod_set_value(led_gpio, status);
return 1;
}
static int led_drv_open (struct inode *node, struct file *file)
{
//int minor = iminor(node);
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
/* 根据次设备号初始化LED */
gpiod_direction_output(led_gpio, 0);
return 0;
}
static int led_drv_close (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
/* 定义自己的file_operations结构�? */
static struct file_operations led_drv = {
.owner = THIS_MODULE,
.open = led_drv_open,
.read = led_drv_read,
.write = led_drv_write,
.release = led_drv_close,
};
/* 4. 从platform_device获得GPIO
* 把file_operations结构体告诉内核:注册驱动程序
*/
static int chip_demo_gpio_probe(struct platform_device *pdev)
{
//int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
/* 4.1 设备树中定义�? led-gpios=<...>; */
led_gpio = gpiod_get(&pdev->dev, "led", 0);
if (IS_ERR(led_gpio)) {
dev_err(&pdev->dev, "Failed to get GPIO for led\n");
return PTR_ERR(led_gpio);
}
/* 4.2 注册file_operations */
major = register_chrdev(0, "100ask_led", &led_drv); /* /dev/led */
led_class = class_create(THIS_MODULE, "100ask_led_class");
if (IS_ERR(led_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "led");
gpiod_put(led_gpio);
return PTR_ERR(led_class);
}
device_create(led_class, NULL, MKDEV(major, 0), NULL, "100ask_led%d", 0); /* /dev/100ask_led0 */
return 0;
}
static int chip_demo_gpio_remove(struct platform_device *pdev)
{
device_destroy(led_class, MKDEV(major, 0));
class_destroy(led_class);
unregister_chrdev(major, "100ask_led");
gpiod_put(led_gpio);
return 0;
}
static const struct of_device_id ask100_leds[] = {
{ .compatible = "100ask,leddrv" },
{ },
};
/* 1. 定义platform_driver */
static struct platform_driver chip_demo_gpio_driver = {
.probe = chip_demo_gpio_probe,
.remove = chip_demo_gpio_remove,
.driver = {
.name = "100ask_led",
.of_match_table = ask100_leds,
},
};
/* 2. 在入口函数注册platform_driver */
static int __init led_init(void)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = platform_driver_register(&chip_demo_gpio_driver);
return err;
}
/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函�? * 卸载platform_driver
*/
static void __exit led_exit(void)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
platform_driver_unregister(&chip_demo_gpio_driver);
}
/* 7. 其他完善:提供设备信息,自动创建设备节点 */
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/led_drv$ cat ledtest.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/*
* ./ledtest /dev/100ask_led0 on
* ./ledtest /dev/100ask_led0 off
*/
int main(int argc, char **argv)
{
int fd;
char status;
/* 1. 判断参数 */
if (argc != 3)
{
printf("Usage: %s <dev> <on | off>\n", argv[0]);
return -1;
}
/* 2. 打开文件 */
fd = open(argv[1], O_RDWR);
if (fd == -1)
{
printf("can not open file %s\n", argv[1]);
return -1;
}
/* 3. 写文件 */
if (0 == strcmp(argv[2], "on"))
{
status = 1;
write(fd, &status, 1);
}
else
{
status = 0;
write(fd, &status, 1);
}
close(fd);
return 0;
}
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/led_drv$ cat Makefile
# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH, 比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
# 请参考各开发板的高级用户使用手册
KERN_DIR = /home/ubuntu/DongshanPI-Vision/br2-canaan-k510/dongshanpi-vision_defconfig/build/linux-origin_master/
all:
make -C $(KERN_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o ledtest ledtest.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
rm -f ledtest
# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.o
obj-m += leddrv.o
ubuntu@ubuntu2004:~/DongshanPI-Vision-Example/led_drv$