嵌入式AI快速入门课程-K510篇 (第七篇 系统BSP开发)

news2024/11/30 20:40:03

第七篇 系统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 分钟,具体要依据网速而定。

运行虚拟机系统
  1. 解压缩 虚拟机系统镜像压缩包,解压缩完成后,可以看到里面有如下两个文件,接下来,我们会使用 后缀名为 .vmx 这个 配置文件。

在这里插入图片描述

  1. 打开已经安装好的 vmware workstation 软件 点击左上角的 文件打开 找到上面的 Ubuntu_18.04.6_VM_LinuxVMImages.COM.vmx 文件,之后会弹出新的虚拟机对话框页面。

在这里插入图片描述

  1. 如下图所示为 为我们已经虚拟机的配置界面,那面我们可以 点击 红框 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.imgLinux+bbl内核镜像(打包过内核的bbl目标文件,用于uboot引导bbl)
k510.dtb设备树
sysimage-emmc.imgemmc烧录文件:已整个打包uboot_burn、kernel和bbl
sysImage-sdcard.imgsdcard烧录文件:已整个打包uboot_burn、kernel和bbl
sysImage-nand.imgnand烧录文件:已整个打包uboot_burn、kernel和bbl
u-boot.binuboot 二进制文件
u-boot_burn.binuboot 烧录文件
uboot-emmc.envuboot环境变量:用于emmc启动
uboot-sd.envuboot环境变量:用于sdcard启动
uboot-nand.envuboot环境变量:用于nand启动
vmlinuxLinux内核镜像文件(带elf调试信息)
rootfs.ext2buildroot格式rootfs ext2镜像文件
sysimage-sdcard-debian.imgsdcard烧录文件:卡镜像(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系统。

image-20230721110228675

1.5.2 烧录镜像

下载EMMC镜像并记住它在计算机中的位置。打开KendryteBurningTool 烧录工具,进入KendryteBurningTool\bin目录下,双击打开BurningTool.exe,如下所示的文件。

注意:在使用KendryteBurningTool 烧录工具时需要关闭串口软件和虚拟机,防止串口被占用。

image-20230721104114404

打开BurningTool.exe程序后会进入如下界面:

image-20230721111848594

点击选择文件,选择下载好的EMMC镜像。选择完成后点击保存,操作步骤如下所示:

在这里插入图片描述

保存后需要在串口选择中选择开发板的串口号,当我们将开发板和PC电脑端通过Type-C连接起来后,可以在BurningTool软件中点击红色箭头处查看我开发板的端口号,选择开发板的串口端口号。(我们也可以在设备管理器中确认开发的端口号)

image-20230721113200863

选择完成后,点击开始烧录烧录。如果您不是第一次进行烧录,此时等待成功烧录完成即可。如果您是第一次进行烧录请继续阅读下面的内容。第一次烧录步骤如下所示:

在这里插入图片描述

在这里插入图片描述

当PC电脑首次进行烧录时,第一个进度条结束后,会显示下图中的错误信息。此时需要安装驱动。

image-20230721115810844

1.5.3 安装WinUSB烧录驱动
  • 找到资料光盘内 1_DongshanPI-Vision资料\3_DongshanPI-Vision_配套工具\【Windows】DongshanPI-Vision EMMC烧录工具 zadig-2.4.exe 双击并运行。

打开zadig-2.4软件,进入如下界面

image-20230721120130024

点击Option中的选择List All Devices(列出所有设备),具体操作如下所示:

在这里插入图片描述

上述操作完成后,可以看到在虚线框内出现了设备名,我们需要切换设备为 Mass storage devices,具体操作如下所示:

在这里插入图片描述

点击Replace Driver替换驱动程序,此时会弹出一个确认窗口,点击

image-20230831091224026

安装完成后会弹出以下窗口点击close

在这里插入图片描述

到此烧录驱动成功安装。

1.5.4 完整烧录镜像

安装完成烧录镜像后,再次打开BurningTool.exe烧录工具软件,按一下开发板 RESET按键,按照1.5.3章节中的操作进行烧录即可。完整烧录步骤如下所示:

在这里插入图片描述

1.5.5 启动EMMC系统

将下图中的拨码开关的boot0和boot1都向下拨,使开发板进入EMMC启动模式。使用两条Type-C线连接开发板端和电脑端,用于给开发板进行供电和使用串口登录开发板控制台。

image-20230721174905407

使用串口软件查看串口控制台,成功启动后会进入开发板控制台。

在这里插入图片描述

之后 我们需要参考 文章开头 开发板使用章节 使开发板可以连接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$ 

在这里插入图片描述

在这里插入图片描述

7.针对系统进行定制化开发操作

支持需要的组件库

定义自己的系统启动程序

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2059523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Linux#43][线程] 死锁 | 同步 | 基于 BlockingQueue 的生产者消费者模型

目录 1. 死锁 解决死锁问题 2. 同步 2.1 条件变量函数 cond 2.2 条件变量的使用&#xff1a; 3.CP 问题--理论 4. 基于 BlockingQueue 的生产者消费者模型 1. 基本概念 2.BlockQueue.hpp 基本设置&#xff1a; 生产关系控制&#xff1a; 消费关系的控制 ⭕思考点 …

公开整理-全国各省AI算力数据集(2000-2024年)

数据来源&#xff1a;本数据来源于&#xff0c;根据显卡HS编码筛选统计后获得时间跨度&#xff1a;2000-2024年数据范围&#xff1a;省级层面数据指标&#xff1a; 由于未发布2015至2016年的数据&#xff0c;因此该年份数据存在缺失。下表仅展示了部分指标及数据 年份 省份…

Mac apache 配置

命令 sudo apachectl -v //查看apache 版本 sudo apachectl -k start //启动apache sudo apachectl -k stop //停止apache sudo apachectl -k restart //重启apache配置 apache 的配置在 /etc/apache2/httpd.conf 默认情况下httpd.conf 为锁定状态&#xff0c;无法编辑 使用…

SAP B1 三大基本表单标准功能介绍-业务伙伴主数据(三)

背景 在 SAP B1 中&#xff0c;科目表、业务伙伴主数据、物料主数据被称为三大基本表单&#xff0c;其中的标准功能是实施项目的基础。本系列文章将逐一介绍三大基本表单各个字段的含义、须填内容、功能等内容。 附上 SAP B1 10.0 的帮助文档&#xff1a;SAP Business One 10…

单片机外部中断+定时器实现红外遥控NEC协议解码

单片机外部中断定时器实现红外遥控NEC协议解码 概述解码过程参考代码 概述 红外(Infrared&#xff0c;IR)遥控&#xff0c;是一种通过调制红外光实现的无线遥控器&#xff0c;常用于家电设备&#xff1a;电视机、机顶盒等等。NEC协议采用PPM(Pulse Position Modulation&#x…

敏感词替换为星号

编写一个函数&#xff0c;接收一个字符串参数&#xff0c;将其中 的敏感词替换为星号&#xff0c;并返回替换后的结果。 def getReplace(s):wordList["阿里巴巴","苹果","亚马逊","京东","字节","脸书"]for word …

月圆之夜梦儿时 贡秋竹唱响游子心声

自今年年初贡秋竹的首支单曲《逐梦》发布以来&#xff0c;其人气和传唱度便一直屡创新高&#xff0c;口碑上佳表现良好&#xff0c;网友们纷纷隔空喊话贡秋竹再发新作。时至今日&#xff0c;久经打磨的贡秋竹全新力作《低头思故乡》在千呼万唤中终于震撼首发&#xff01; 贡秋竹…

500以内开放式耳机哪款好?五款高性价比开放式耳机推荐

现在很多人会利用休闲时间进行锻炼&#xff0c;增强体质&#xff0c;在锻炼之前很多人会先入手一些运动设备&#xff0c;像慢跑鞋&#xff0c;还有臂环&#xff0c;运动手表等~当然运动耳机肯定也不能少&#xff0c;边运动边听音乐真的是一大享受&#xff01;但是哪种耳机比较适…

从零到一,全面掌握Apache DolphinScheduler发版流程,实战派经验分享!

引言 Apache DolphinScheduler的发版流程对于确保软件质量和社区协作至关重要&#xff0c;社区Committer王兴杰为我们详细介绍了Apache DolphinScheduler的发版流程&#xff0c;包括环境准备、流程文档、基础工具准备、依赖包确认等关键步骤&#xff0c;并指出了发版流程中可能…

一机两用的“多面手”既防勒索病毒又能做到数据防泄密!

随着数字化转型的加速&#xff0c;企业对互联网的依赖日益加深&#xff0c;网络安全风险也随之增加。勒索病毒作为网络安全领域的一大威胁&#xff0c;不仅加密重要文件&#xff0c;还可能泄露敏感信息&#xff0c;给企业带来巨大损失。SPN沙盒产品&#xff0c;以其独特的隔离技…

【python报错解决】ImportError: DLL load failed while importing win32gui: 找不到指定的程序

在 Python 中安装 pywin32 库 pip install pywin32安装完成后找到自己的 Python 根目录&#xff0c;在该目录下打开命令行。 在命令行中输入&#xff1a; python.exe Scripts/pywin32_postinstall.py -install执行后显示以下信息&#xff0c;即问题解决。 Parsed argumen…

KP8530X系列KP85302SGA 650V耐压 集成自举二极管的半桥栅极驱动器 专用于驱动功率MOSFET或IGBT

KP8530X系列KP85302SGA是一款 650V 耐压&#xff0c;集成自举二极管的半桥栅极驱动器&#xff0c;具有 0.3A 拉电流和 0.6A 灌电流能力&#xff0c;专用于驱动功率 MOSFETs 或 IGBTs。采用高压器件工艺技术&#xff0c;具有良好的电流输出及出色的抗瞬态干扰能力。在输入逻辑引…

React+Vis.js(05):vis.js的节点的点击事件

文章目录 需求实现思路抽屉实现完整代码需求 双击节点,弹出右侧的“抽屉”,显示节点的详细信息 实现思路 vis.network提供了一个doubleClick事件,代码如下: network.on(doubleClick, function (properties) {// console.log(nodes);let id = properties

el-date-picker根据某个时间动态规定可选的的时间范围

el-date-picker组件根据某一个时间段来动态规定当前时间选择的日期时间范围 例如&#xff1a;开始时间为2024-8-19&#xff0c;规定可循范围为30天的话&#xff0c;可选范围是2024-8-19至2024-9-19号之间 html <el-date-picker class"date" type"date"…

【GIS开发学员故事】地信本科前后跨过六个行业,勇气是人生的第七件装备

“出过外业、送过外卖、搞过环境设计......” 今天&#xff0c;我们就来看看X同学的就业故事&#xff1a; 自我介绍 我毕业于21年&#xff0c;大学是地理信息科学专业&#xff0c;考过一次研&#xff0c;但是没有考上。去年来的新中地学习GIS开发&#xff0c;目前是在广东的…

人机环境系统智能中有三种神经网络相互作用

在人机环境生态系统智能中&#xff0c;人、机器和环境之间的相互作用确实涉及到三种神经网络的协作&#xff0c;分别是人的神经网络、机器的神经网络和环境的神经网络。 1. 人的神经网络 人的神经网络指的是人类大脑及其神经系统的复杂结构&#xff0c;通过神经元之间的连接来处…

SpringBoot MySQL BinLog 监听数据变化(多库多表)

开始 1&#xff1a;引入mysql-binlog-connector-java.jar <!-- binlog --><dependency><groupId>com.zendesk</groupId><artifactId>mysql-binlog-connector-java</artifactId><version>0.27.1</version></dependency>…

亦菲喊你来学习之机器学习(6)--逻辑回归算法

逻辑回归 逻辑回归&#xff08;Logistic Regression&#xff09;是一种广泛使用的统计方法&#xff0c;用于解决分类问题&#xff0c;尤其是二分类问题。尽管名字中有“回归”二字&#xff0c;但它实际上是一种分类算法&#xff0c;因为它试图通过线性回归的方式去预测一个事件…

【计算机组成原理】二、数据的表示和运算:3.算术逻辑单元ALU(逻辑运算、加法器)

4.运算器ALU 文章目录 4.运算器ALU4.1逻辑运算非&#xff08;NOT&#xff09;与&#xff08;AND&#xff09;或&#xff08;OR&#xff09;异或&#xff08;XOR&#xff09;同或&#xff08;XNOR&#xff09; 4.2加法器4.2.1一位全加器4.2.2串行加法器4.2.3并行加法器 4.3ALU功…

金九银十简历石沉大海?别投了,软件测试岗位饱和了....

各大互联网公司的接连裁员&#xff0c;政策限制的行业接连消失&#xff0c;让今年的求职雪上加霜&#xff0c;想躺平却没有资本&#xff0c;还有人说软件测试岗位饱和了&#xff0c;对此很多求职者深信不疑&#xff0c;因为投出去的简历回复的越来越少了。 另一面企业招人真的…