嵌入式AI快速入门课程-K510篇 (第七篇 系统BSP开发)
第七篇 系统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 builddistclean - delete all non-source files (including .config)Build:all - make worldtoolchain - build toolchainsdk - build relocatable SDKConfiguration:menuconfig - interactive curses-based configuratornconfig - interactive ncurses-based configuratorxconfig - interactive Qt-based configuratorgconfig - interactive GTK-based configuratoroldconfig - resolve any unresolved symbols in .configsyncconfig - Same as oldconfig, but quietly, additionally update depsolddefconfig - Same as syncconfig but sets new symbols to their default valuerandconfig - New config with random answer to all optionsdefconfig - New config with default answer to all options;BR2_DEFCONFIG, if set on the command line, is used as inputsavedefconfig - Save current config to BR2_DEFCONFIG (minimal config)update-defconfig - Same as savedefconfigallyesconfig - New config where all options are accepted with yesallnoconfig - New config where all options are answered with noalldefconfig - New config where all options are set to defaultrandpackageconfig - New config with random answer to package optionsallyespackageconfig - New config where pkg options are accepted with yesallnopackageconfig - New config where package options are answered with noPackage-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 stepbusybox:busybox-menuconfig - Run BusyBox menuconfiglinux:linux-menuconfig - Run Linux kernel menuconfiglinux-savedefconfig - Run Linux kernel savedefconfiglinux-update-defconfig - Save the Linux configuration to the path specifiedby BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILEDocumentation:manual - build manual in all formatsmanual-html - build manual in HTMLmanual-split-html - build manual in split HTMLmanual-pdf - build manual in PDFmanual-text - build manual in textmanual-epub - build manual in ePubgraph-build - generate graphs of the build timesgraph-depends - generate graph of the dependency treegraph-size - generate stats of the filesystem sizelist-defconfigs - list all defconfigs (pre-configured minimal systems)Miscellaneous:source - download all sources needed for offline-buildexternal-deps - list external packages usedlegal-info - generate info about license complianceshow-info - generate info about packages, as a JSON blurbprintvars - dump internal variables selected with VARS=...make V=0|1 - 0 => quiet build (default), 1 => verbose buildmake O=dir - Locate all output files in "dir", including .configFor 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 cleanrm -rf modules.orderrm -f hello_drv_testobj-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 cleanrm -rf modules.orderrm -f ledtest# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.oobj-m += leddrv.oubuntu@ubuntu2004:~/DongshanPI-Vision-Example/led_drv$
7.针对系统进行定制化开发操作
支持需要的组件库
定义自己的系统启动程序
相关文章:

嵌入式AI快速入门课程-K510篇 (第七篇 系统BSP开发)
第七篇 系统BSP开发 文章目录 第七篇 系统BSP开发1. 嵌入式Linux系统介绍嵌入式Linux系统组成产品形态嵌入式芯片启动流程Linux系统Linux系统框架嵌入式编译环境 2.嵌入式Linux开发准备手册文档开发工具配套硬件工程源码 3.嵌入式Linux开发组成概述编译工具链什么是工具链什么是…...

代码随想录算法训练营day52:图03:101. 孤岛的总面积;102. 沉没孤岛;103. 水流问题
101. 孤岛的总面积 卡码网:101. 孤岛的总面积(opens new window) 题目描述 给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿指的是由水平或垂直方向上相邻的陆地单元格组成的区域,且完全被水域单…...

开源大模型本地私有化部署
1、安装ollama ollma下载 https://ollama.com/download/windows linux 安装 curl -fsSL https://ollama.com/install.sh | sh 运行 ollama run gemma:2b ollama run gemma:7b 使用端口11434 2、下载 open-webui 代码 https://github.com/open-webui/open-webui.git 生成目录…...

站长为什么要搭建个人博客网站
搭建个人博客网站是一个值得考虑的选择,它不仅有助于个人成长,还能在多个方面带来积极的影响。以下是几个主要的理由: 一、记录与备忘 方便回顾与查阅:博客网站成为了一个个人知识库,记录下来的内容方便后续查阅和回顾…...

Golang | Leetcode Golang题解之第355题设计推特
题目: 题解: type Twitter struct {Tweets []intUserTweets map[int][]intFollows map[int][]intIsFollowMy map[int]bool }/** Initialize your data structure here. */ func Constructor() Twitter {// 每一次实例化的时候,都重新分配一次…...

Redis如何实现发布/订阅?
引言 Redis是一款高性能的内存数据存储系统,除了常用的键值存储功能外,还提供了发布/订阅(Pub/Sub)机制。通过发布/订阅机制,Redis可以实现消息的广播或者实时通知功能,是一种非常有用的功能。 本文将详细…...

EmguCV学习笔记 VB.Net 4.4 图像形态学
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 教程VB.net版本请访问:EmguCV学习笔记 VB.Net 目录-CSDN博客 教程C#版本请访问:EmguCV学习笔记 C# 目录-CSD…...

HarmonyOS 开发
环境 下载IDE 代码 import { hilog } from kit.PerformanceAnalysisKit; import testNapi from libentry.so; import { router } from kit.ArkUI; import { common, Want } from kit.AbilityKit;Entry Component struct Index {State message: string Hello HarmonyOS!;p…...

拒绝拖延!Kimi助你一天内速成论文初稿!
撰写学术论文是一项需要周密计划和精确执行的任务。它要求作者对文章的每个部分进行深入思考,以确保论文结构的合理性和论述的清晰度。利用Kimi的功能,我们可以更系统地进行写作,从构思到最终成稿,逐步构建出一篇高质量的学术论文…...

Python画笔案例-005 绘制迷宫
1、绘制迷宫 通过 python 的turtle 库绘制一个迷宫的图案,如下图: 2、实现代码 从图上可以看出,内测最短的竖线开始,每次右转 90 度后,线段都增加 8 个单位,所以我们是用 for 循环,循环 50 次…...

【鸿蒙学习】HarmonyOS应用开发者高级认证 - 应用性能优化二(代码层面)
学完时间:2024年8月22日 学完排名:第1801名 一、长列表优化概述 列表是应用开发中最常见的一类开发场景,它可以将杂乱的信息整理成有规律、易于理解和操作的形式,便于用户查找和获取所需要的信息。应用程序中常见的列表场景有新…...

【Docker】如何将A机器内的镜像,导入到B机器?
由于网络或者仓库的原因,经常遇到pull拉取镜像失败的情况!! 那么,如何将A机器内的镜像,通过命令,导入到B机器? 两条重要的命令: 1,在已经成功拉取pull的机器上执行命令…...

动手实现基于Reactor模型的高并发Web服务器(一):epoll+多线程版本
系统流程概览 main函数 对于一个服务器程序来说,因为要为外部的客户端程序提供网络服务,也就是进行数据的读写,这就必然需要一个 socket 文件描述符,只有拥有了文件描述符 C/S 两端才能通过 socket 套接字进行网络通信࿰…...

爬虫案例4——爬取房天下数据
简介:个人学习分享,如有错误,欢迎批评指正 任务:从房天下网中爬取小区名称、地址、价格和联系电话 目标网页地址:https://newhouse.fang.com/house/s/ 一、思路和过程 目标网页具体内容如下: …...

网络硬盘录像机NVR程序源码NVR全套运用方案
在当今社会,随着科技的飞速发展和人们对安全需求的日益增长,安防监控系统已成为保障公共安全、维护社会稳定的重要手段。其中,网络视频录像机(NVR)作为安防监控系统的核心设备,其智能化升级运用方案对于提高…...

03:电容的充放电特性及应用举例
1.电容的基本特性:电容两端的电压不能突变 2.影响电容两端电压的参数:整个回路中电阻,电容大小 3.如何计算电容的电压变化时间? τRC R1k C1uF 则得到τ1ms的时间 应用:芯片使能延时...

【专题】2023-2024中国游戏企业研发竞争力报告合集PDF分享(附原数据表)
原文链接: https://tecdat.cn/?p37447 在当今的数字时代,游戏产业已然成为经济与文化领域中一股不可忽视的重要力量。2023 年,中国自研游戏市场更是呈现出一片繁荣且复杂的景象,实际销售收入达到了令人瞩目的 2563.8 亿元&#x…...

会话跟踪方案:Cookie Session Token
什么是会话技术? Cookie 以登录为例,用户在浏览器中将账号密码输入并勾选自动登录,浏览器发送请求,请求头中设置Cookie:userName:张三 ,password:1234aa ,若登录成功,服务器将这个cookie保存…...

jemeter压力测试入门
1. 安装jemeter的压缩包并且解压 点击运行 2. 添加线程组 3. 线程组的参数设置 4. 添加http请求 5. 填写请求信息 添加监听器——结果树(结果),聚合报告(吞吐量报告) 6. 通过cvs数据文件设置,配置元件&…...

SpringBoot3 简单集成 Spring AI 并使用
文章目录 准备JDK17api key 创建项目编写配置文件创建controller启动并测试角色预设流式响应\异步响应ChatModel(聊天模型)ImageModel(文生图)文生语音语言翻译多模态Function Calling (函数调用第三方API)…...

【C/C++】程序设计基础知识(数据类型与表达式、控制语句、数组与结构)
【C/C】程序设计基础知识(数据类型与表达式、控制语句、数组与结构) 一、数据类型与表达式1.1C语言符号1.2C语言运算符1.3数据类型1.4常量与变量1.5基本运算1.6优先级和结合性1.7输入与输出 二、控制语句2.1顺序结构2.2选择结构2.3循环结构2.4break,cont…...

python库——sklearn的关键组件和参数设置
文章目录 模型构建线性回归逻辑回归决策树分类器随机森林支持向量机K-近邻 模型评估交叉验证性能指标 特征工程主成分分析标准化和归一化 scikit-learn,简称sklearn,是Python中一个广泛使用的机器学习库,它建立在NumPy、SciPy和Matplotlib这些…...

CAS-ViT实战:使用CAS-ViT实现图像分类任务(一)
摘要 在视觉转换器(Vision Transformers, ViTs)领域,随着技术的不断发展,研究者们不断探索如何在保持高效性能的同时,降低模型的计算复杂度,以满足资源受限场景(如移动设备)的需求。…...

处理数组下标的代码
以下是某个Ada编译器生成的一段汇编代码: mov ecx, eaxmov ebx, eaxsar ebx, 1Fhmov edx, ebxsar edx, 1Fhnot edxmov eax, edxsar eax, 1Fhand ecx, eax以上代码相当于以下C代码: ecx ((~(eax >> 62) >&…...

数学建模算法总结
数学建模常见算法总结 评价决策类模型 层次分析法 层次分析法根据问题的性质和要达到的总目的,将问题分解为不同的组成因素,并按照因素间的相互关联影响以及隶属关系将因素按不同层次聚集组合,形成一个多层次的分析结构模型,从…...

代码随想录算法训练营第五十五天 | 并查集理论基础、107. 寻找存在的路径
一、并查集理论基础 文章链接:并查集理论基础 | 代码随想录 (programmercarl.com) 二、107. 寻找存在的路径 题目连接:107. 寻找存在的路径 (kamacoder.com) 文章讲解:代码随想录 (programmercarl.com)——107. 寻找存在的路径...

ROS_package 、CMakeLists.txt、package.xml、ROS_node之间的关系
一、整体框架结构 二、关系描述 1、ROS.cpp 里面初始化了一个ROS节点,注意我的源文件里面只初始化了一个节点 // ROS.cpp #include "ros/ros.h"int main(int argc, char **argv) {ros::init(argc, argv, "node_name"); // 指定节点名称为 &…...

嵌入式学习----网络通信之TCP协议通信
TCP(即传输控制协议):是一种面向连接的传输层协议,它能提供高可靠性通信(即数 据无误、数据无丢失、数据无失序、数据无重复到达的通信) 适用情况: 1. 适合于对传输质量要求较高,以及传输大量数据 的通信。…...

【信息学奥赛一本通】1007:计算(a+b)×c的值
1007:计算(ab)c的值 时间限制: 1000 ms 内存限制: 65536 KB 提交数:184662 通过数: 150473 【题目描述】 给定3个整数a、b、c,计算表达式(ab)c的值。 【输入】 输入仅一行,包括三个整数a、b、c, 数与数之间以一个空格分开。(-10,…...

Linux系统之部署俄罗斯方块网页小游戏(三)
Linux系统之部署俄罗斯方块网页小游戏(三) 一、小游戏介绍1.1 小游戏简介1.2 项目预览二、本次实践介绍2.1 本地环境规划2.2 本次实践介绍三、检查本地环境3.1 检查系统版本3.2 检查系统内核版本3.3 检查软件源四、安装Apache24.1 安装Apache2软件4.2 启动apache2服务4.3 查看…...