1 Star 0 Fork 7

VelsonWang / 嵌入式QEMU教程

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

项目介绍:嵌入式QEMU教程

作者 将狼才鲸
创建日期 2022-11-14

  • 简介:硬件平台均为QEMU模拟器。
  1. 当前裸机项目使用ARM Cortex-A7 32位内核、带有GPU(2D 3D显示加速、图片和音频视频编解码)的博通BCM2836芯片(树莓派2B同款硬件,但不使用树莓派的系统和软件)。
  2. 当前Linux项目使用ARM Versatile Express开发板,从源码编译运行U-Boot、Linux和根文件系统。
表1 本仓库软硬件资源描述
软硬件资源 详情 备注
QEMU BCM2836芯片模拟器 900MHz 4核 ARM Cortex-A7 CPU, VideoCore IV 双核 GPU (2D 3D显示加速, 视频编解码), 1GB 内存, 100M以太网, HDMI显示, USB2.0 x 4, SD卡, 音频输出, GPIO, 摄像头输入, 液晶屏接口, 串口, SPI, I2C等嵌入式通用模块 树莓派2B同款硬件
硬件模块测试用例:raspi3-tutorial 裸机程序,包含让CPU运行的空程序、串口打印、屏幕图像输出、屏幕文字输出、读写SD卡、bootloader 树莓派3B同款硬件BCM2837,在仓库根目录raspi3-tutorial文件夹中, 开箱即用, 直接make, 直接在QEMU中运行
裸机项目 汇编boot,串口打印,......进行中...... 树莓派2B同款硬件BCM2836
RTOS项目 ......未开始......
Linux项目 uboot编译运行,Linux和根文件系统编译运行 ARM CoreTile Express开发板
使用的开源库

一、前言

  1. 作为一名嵌入式软件工程师,我想自己从头开始做一个实际的嵌入式产品;结合自己工作中接触过的技术,我希望最终的项目中有通信、GUI、音视频编码、音视频解码功能的设备。

  2. 创建这个仓库的目的,一是记录自己学习到的技术,防止时间久了忘记;二是给其他也想要做一个实际嵌入式项目的人一个参考,最好是能开箱即用,能看到产品的效果,然后能方便的阅读源码和注释,知晓原理,而不用自己去一步步搭建环境;搭环境是很痛苦的,往往遇到一个问题跨不过去,又没人指导,然后就不得不放弃了。

  3. 我不使用具体的开发板,而是使用QEMU模拟器;原因一就是上面“第2条前言”所描述的通用和开箱即用,因为不同的开发板太多了,开发板也很贵,真的没必要让看这个工程的人还去花钱买块板子,板子买回来很大的概率也是吃灰。原因二是我自己也从来没买过开发板,也不喜欢在开发板上频繁下载调试程序,很慢也很烦,一般纯逻辑的模块我会先用gcc或者模拟器验证好,然后再上板子调试。原因三是芯片原厂开发芯片开发包时,芯片还没设计好的初期也会先使用模拟器,不过他们完整的模拟器代码并没有流传出来而已。

  4. 在硬件选型的过程中,其实我最中意的是瑞芯微的芯片,但无奈他们家的产品在QEMU模拟器中并不支持;然后我查看了QEMU支持的所有嵌入式芯片,发现除了Intel、AMD,其它的芯片都不支持其中的显示加速、音视频编解码(一开始我以为QEMU对博通VideoCore GPU会支持,后面发现只是模拟了核间通信,但此时我已经做完了这个项目的准备工作了),有些芯片仅仅只支持了不加速的液晶屏显示、触摸屏、音频解码,还有些芯片只支持了串口、GPIO、SPI、I2C等基础的外设。阴差阳错间,我选择了树莓派。

  5. 树莓派不是最理想的选项,最新的几款树莓派芯片都是64位的ARM;嵌入式当前流行32位CPU,所以我选择树莓派32位CPU的老版本;而且树莓派所使用的博通芯片的手册还是不公开的,能找到的资料也少,这对嵌入式开发很不利,但还好基本的外设寄存器地址还是能找到的,网上也能找到一些底层开发的教程;我刚毕业时也用过博通BCM2042和BCM20730蓝牙芯片,对博通也不是两眼一抹黑;尽管困难重重,但也要慢慢解决问题。

  6. 其它带有GPU的MCU芯片还有RK3399、RV1126、RK3588、RK3288、Exynos4412、DM6446等;全志的资料不公开,和博通一样,只面向大客户公开资料,所以也放弃使用全志芯片;海思的芯片也没找到模拟器,也就不用了。

  7. 一些带2D显示加速和音视频编解码模块的嵌入式开发板信息:

二、QEMU模拟器介绍

三、树莓派介绍

  • 树莓派本质上是一个计算机,所以提供了完整的操作系统和应用软件,但是它的老款芯片是32位的ARM,也可以用于嵌入式领域。
  • 树莓派的详细介绍详见本仓库子文档《03_树莓派QEMU模拟器介绍.md》

四、必须的准备工作

  • 本章前面的总述和前面3小节只是对要做的工作进行一个文字描述,本章第4小节有完整的安装过程,可以直接跳到”4)完整的环境安装步骤“进行阅读。
  1. 首先,需要Linux或者Windows MinGW等环境,如果你是第一次使用Linux,则不应该摸索Windows下的MinGW环境,这应该是对Linux已经很熟悉之后才做的事,因为在里面装软件很麻烦;你应该直接使用Ubuntu或其它Linux发行板,推荐在Windows下使用VMware虚拟机安装Ubuntu;具体的过程略。

  2. Ubuntu下安装QEMU,这也等同于准备好了一块硬件开发板,过程略。

  3. Ubuntu下安装ARM交叉编译工具,过程略。

  4. 编译程序,运行程序。

  • 如果你以前用过树莓派,那么请忘掉它,我们按照嵌入式的模式来。

  • 写树莓派的底层程序,并不能像8051或普通MCU芯片一样,使用汇编,从零地址开始的复位中断开始写,能够控制芯片上电后执行的第一条指令;因为树莓派上电后是芯片里面的GPU先开始运行,并且这部分代码是不公开的,GPU底层的寄存器介绍也是不公开的,只能加载官方提供的GPU的驱动;GPU上电后再引导ARM CPU运行。

  • 但其实如果不是在芯片原厂,一般嵌入式开发人员也不需要知道芯片开发包里面的boot是如何实现的,编译器里面的C标准库是如何实现的,中断向量表和堆栈是如何分配的,各个驱动模板是如何实现的,操作系统是怎么移植的;能用就行。

1)安装Linux环境

  • 可以在Windows下安装MSYS2,或者安装Cygwin,这都是Linux运行环境;如果安装了Git,里面也会自带精简版的MSYS2+MinGW64;如果你有已经安装过MSYS2环境的朋友,特别是他已经安装好了树莓派交叉编译工具和其它工具,你可以将他安装过的文件夹拷过来,在你的电脑上也同样可以点开即用,换句话说就是安装过一次以后的MSYS2是绿色软件,只是文件比较大,会有几十G。
  • 也可以先安装VMware Player虚拟机,然后在虚拟机中安装Ubuntu系统,这是一个Linux发行版;直接使用Linux系统,安装软件的教程和各种资料会比MinGW更方便;如果你有已经在虚拟机中安装过Linux的朋友,特别是他在已经安装好了树莓派交叉编译工具、QEMU和其它工具,你可以将他安装过的系统文件夹拷贝过来。
  • 还可以使用双系统,或者干脆准备一台装了Linux的电脑。

2)用QEMU模拟器运行树莓派

3)编译树莓派程序

4)完整的环境安装步骤

  • 写在前面,我会使用Windows下的MSYS2环境 + QEMU,和VMware Player16 + Ubuntu18.04 + QEMU。如果你没用过Linux,则建议使用VMware虚拟机 + Ubuntu的开发环境,因为MSYS2中安装软件的教程很难快速找到,需要有一些使用Linux的经验才知道怎么安装特定软件;我的MSYS2环境添加了32位和64位的交叉编译工具,他们的来源不一样,后面会详述。
  • MSYS2中的QEMU只能运行裸机程序、U-Boot和Linux kernel(加载根文件系统会失败),而Ubuntu下的QEMU才能运行U-Boot + kernel + rootfs。如果你除了裸机编程,还想学习Linux编程,则建议你跳过本章节(第四章)剩下的内容,直接跳转到本文档的“九、Linux编程”章节安装Linux的环境,然后再继续第五章。
  • 下面是Windows下从头到尾的工具软件安装步骤:
    • 推荐使用MSYS2 + 已经用MinGW32或MinGW64编译好的程序,在Linux下常用的功能,也都能在这个环境下实现,只是有些教程没有Ubuntu下那么好找;在MSYS2中不能使用Linux的程序,必须用MinGW将源码重新编译过后才能使用,这一般是软件供应商已经编译好了,可以直接下载的。
    • MSYS2的更多信息详见本仓库子文档《04_MSYS2简述.md》
表2 MSYS2、MinGW和Cygwin的关系
软件名 版本 作用 特点
MSYS MSYS,MSYS2 Linux命令行终端:Shell,Bash 没有在Windows下编译Linux程序的工具集,会自带已经被MinGW编译好的一些包;脱胎于Cygwin,但容量更小;MSYS2是因为MSYS常年不更新而新组的的一个项目;MSYS2安装完后的文件名为msys64,你可以将你安装好之后的msys64文件夹打包发给别人,这样别人无安装就可以用了,只是容量有点大,几十G
MinGW MinGW32,MinGW64 一组编译工具链 编译后生成的是纯粹的Windows程序;它自带的命令行终端很难用也不全,要和MSYS2终端配合使用;MinGW64是因为MinGW32常年不更新而新组的的一个项目
Cygwin Cygwin 编译工具+命令行 有模拟层,将Linux API转成Windows API再执行程序,效率低,容量大,速度慢,2010年左右在Windows下搭建交叉编译环境时还多用它;要运行纯粹的Linux程序时也用它

4.1 安装MSYS2

  1. 我当前下载的版本是msys2-x86_64-20221028.exe
  1. 我将软件安装在D盘根目录,软件会安装在d:\msys64中,安装目录不能有空格、中文。
  2. 安装完之后先不打开软件,先将国外镜像地址换成国内镜像地址,参考上方教程。
  3. 电脑配置环境变量,在PATH中增加一行D:\msys64\usr\bin
  1. 双击运行主目录下的msys2.exe或者mingw64.exe都可以,其它的exe有些是32位的,有些是非gcc编译器对应的软件。

4.2 MSYS2中安装QEMU

  • 因为我已经有了MSYS2环境,可以在里面直接安装QEMU;你下载Windows版本的QEMU单独安装,也是走的MSYS2+MinGW这一套,只是和Git一样,它们都是在自己的软件安装包自带了精简版的MinGW环境。

  • 我们不需要用MinGW64或者MinGW32编译QEMU,我们只安装已经编译好的QEMU软件;网上没搜到MSYS2中安装QEMU的教程,但是我们知道MSYS2中的所有软件都在packages.msys2.org/reposMSYS2 Base PackagesMSYS2 Packages中有描述。

  • https://packages.msys2.org/base 中能找到mingw-w64-qemu;在https://packages.msys2.org/package/ 中能找到mingw-w64-x86_64-qemu;在https://packages.msys2.org/package/mingw-w64-x86_64-qemu?repo=mingw64 中能找到/mingw64/bin/qemu-system-aarch64.exe、/mingw64/bin/qemu-system-arm.exe,也能找到安装方法:pacman -S mingw-w64-x86_64-qemu;我当前使用的是Build Date: 2022-10-10 20:19:53,Installed Size: 768.72 MB,实际安装完后有2G。

  • 查看是否安装成功:进入cd /mingw64/bin/ 然后./qemu-system-arm.exe --version查看版本号;后续还需要设置环境变量,这里暂略。

  • 能看到输出信息:

jim@DESKTOP-SVP3BEM MSYS /mingw64/bin
$ ./qemu-system-arm.exe --version
QEMU emulator version 7.1.0
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers

4.3 MSYS2中安装32位和64位ARM交叉编译工具

4.4 用现成的程序从QEMU运行树莓派

  • 从以下网址https://gitee.com/mirrors_bztsrc/raspi3-tutorial/tree/master/0A_pcscreenfont 下载编译好的树莓派程序,我已下载好,存放在msys64家目录下的1_raspi/01_run文件夹中
  • 使用命令运行:/mingw64/bin/qemu-system-aarch64 -M raspi3b -kernel ~/1_raspi/01_run/kernel8.img -d in_asm
  • 能看到出现了QEMU窗口,并显示了hello world。 效果如下:img

4.5 交叉编译工具编译程序,并在树莓派QEMU模拟中运行

  1. mirrors_bztsrc/raspi3-tutorial下载一个国外的英文仓库,是演示64位ARM树莓派裸机编程的,我借鉴这里面的工程。
  • 这个工程已下载到当前仓库根目录下,我也会将这个目录拷贝到msys64的家目录下,我会将里面的Makefile和自动运行改成和msys64适配,保证一个make命令就能编译程序,一个make run就能在QEMU中运行刚刚编译的程序。
  • 输出qemu所在位置和aarch64编译器所在位置的环境变量,这样就不用每次都写完整的路径了。
  • 打开家目录也就是msys64/home/jim/下的.bashrc,在里面末尾加上
    export PATH=$PATH:/mingw64/bin  
    export PATH=$PATH:/mingw32/bin/gcc-linaro-7.5.0-2019.12-i686-mingw32_aarch64-linux-gnu/bin  
  • 生效配置 source ~/.bashrc
  • 查看环境变量,确认已经生效
    echo $PATH
  1. 进入msys64 raspi3-tutorial源码目录,编译并运行

4.6 有关树莓派裸机编程的介绍

  • 树莓派里面有GPU和ARM CPU,GPU先上电运行,然后再引导ARM运行

  • 树莓派的GPU底层固件(Bootloader)是闭源的,但可以在此基础上引导自己的U-Boot、Linux kernel,也可以不用U-Boot和Linux,直接引导裸机程序或者RTOS;这种引导方式和Xilinx ZYNQ类似,ARM和FPGA一个先启动一个后启动。

  • 一些其它的树莓派嵌入式相关的开源仓库:
    (1) 运行在 Raspberry Pi 上的小型嵌入式系统

  • Xinu project (xinu-os/xinu) 一个操作系统
  • Ultibo project (ultibohub/Core) 用Free Pascal编写的Raspberry Pi的全功能嵌入式(无操作系统)开发环境

(2) 一些在 Raspberry Pi 上可以嵌入在其他系统中的运行库

  • USPi(rsta2/uspi), 一个小型的支持 USB 通讯的库

(3) 以及其他一些基于 Raspberry Pi 裸机开发例子:


五、raspi3-tutorial硬件测试用例

  • 原始网址:mirrors_bztsrc / raspi3-tutorial
  • 本仓库中的地址:根目录/raspi3-tutorial/
  • msys64中的地址:家目录 ~/raspi3-tutorial/
  • 硬件是raspi3,64位ARM芯片,但因为有现成的代码,可以先熟悉编译环境,之后再在32位ARM上跑。
表3 raspi3-tutorial各测试用例的描述
用例名称 作用 备注
00_crosscompiler 文档,只是描述编译器相关的内容
01_bareminimum 空程序,在汇编中死循环,只是为了验证编译器和模拟器安装正确,能够编译和运行
02_multicorec 写汇编boot,并引导C语言main函数运行
03_uart1 串口打印Hello world,从MSYS2控制台输出
04_mailboxes CPU和GPU邮箱通信,通信成功后打印串口号
05_uart0 串口收发回环
06_random 打印随机数
07_delays 延时后打印
08_power 关机与重启
09_framebuffer 从屏幕显示未压缩的图片
0A_pcscreenfont 从屏幕显示点阵字库文字
0B_readsector 读SD卡扇区
0C_directory 读SD卡文件夹
0D_readfile 读SD卡文件
0E_initrd 根文件系统
0F_executionlevel 获取当前程序级别
10_virtualmemory MMU虚拟内存映射
11_exceptions 测试异常中断
12_printf 测试printf输出
13_debugger gdb调试输出
14_raspbootin64 一个简单的bootloader
15_writesector 写SD卡

1)03_uart1

  • 作用:串口打印Hello world,从MSYS2控制台输出
  • 效果:
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/03_uart1
$ make
rm kernel8.elf *.o >/dev/null 2>/dev/null || true
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c start.S -o start.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c main.c -o main.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c uart.c -o uart.o
aarch64-linux-gnu-ld -nostdlib -nostartfiles start.o main.o uart.o -T link.ld -o kernel8.elf
aarch64-linux-gnu-objcopy -O binary kernel8.elf kernel8.img

jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/03_uart1
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio
Hello World!

2)04_mailboxes

  • 作用:CPU和GPU邮箱通信,通信成功后打印串口号
  • 效果:
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/04_mailboxes
$ make
rm kernel8.elf *.o >/dev/null 2>/dev/null || true
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c start.S -o start.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c main.c -o main.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c mbox.c -o mbox.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c uart.c -o uart.o
aarch64-linux-gnu-ld -nostdlib -nostartfiles start.o main.o mbox.o uart.o -T link.ld -o kernel8.elf
aarch64-linux-gnu-objcopy -O binary kernel8.elf kernel8.img

jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/04_mailboxes
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio
My serial number is: 0000000000000000

3)05_uart0

  • 作用:串口收发回环(串口重定向到MSYS2命令行终端)
  • 效果:
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/05_uart0
$ make
rm kernel8.elf *.o >/dev/null 2>/dev/null || true
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c start.S -o start.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c main.c -o main.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c mbox.c -o mbox.o
aarch64-linux-gnu-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c uart.c -o uart.o
aarch64-linux-gnu-ld -nostdlib -nostartfiles start.o main.o mbox.o uart.o -T link.ld -o kernel8.elf
aarch64-linux-gnu-objcopy -O binary kernel8.elf kernel8.img

jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/05_uart0
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
My serial number is: 0000000000000000
aaaaddddd
asdfasfsafsa

4)07_delays

  • 延时后打印
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/07_delays
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Waiting 1000000 CPU cycles (ARM CPU): OK
Waiting 1000000 microsec (ARM CPU): OK
Waiting 1000000 microsec (BCM System Timer): OK

5)08_power

  • 关机与重启
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/08_power
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
 1 - power off
 2 - reset
Choose one: 2

 1 - power off
 2 - reset
Choose one: 1

 1 - power off
 2 - reset
Choose one:
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/08_power

6)09_framebuffer

  • 从屏幕显示未压缩的图片

img

7)0A_pcscreenfont

  • 从屏幕显示点阵字库文字

img

8)0F_executionlevel

  • 获取当前程序级别
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/0F_executionlevel
$ jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/0F_executionlevel
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Current EL is: 00000001

9)11_exceptions

  • 测试异常中断
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/11_exceptions
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Synchronous: Data abort, same EL, Translation fault at level 2:
  ESR_EL1 0000000096000006 ELR_EL1 0000000000080CC4
 SPSR_EL1 00000000200003C4 FAR_EL1 FFFFFFFFFF000000

jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/11_exceptions

10)12_printf

  • 测试printf输出
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/12_printf
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Hello World!
This is character 'A', a hex number: 7FFF and in decimal: 32767
Padding test: '00007FFF', '    -123'

jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/12_printf

11)13_debugger

  • gdb调试输出
jim@DESKTOP-SVP3BEM MSYS ~/raspi3-tutorial/13_debugger
$ make run
qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial stdio
Synchronous: Breakpoint instruction
> run
 x0: 000000000008EF7C   x1: 0000000000000301   x2: 0000000000000070
 x3: 000000000000000B   x4: 0000000000024000   x5: 0000000000000000
 x6: 0000000000000000   x7: 0000000000000000   x8: 0000000000000000
 x9: 0000000000000000  x10: 0000000000000000  x11: 0000000000000000
x12: 0000000000000000  x13: 0000000000000000  x14: 0000000000000000
x15: 0000000000000000  x16: 0000000000000000  x17: 0000000000000000
x18: 0000000000000000  x19: 0000000000000000  x20: 0000000000000000
x21: 0000000000000000  x22: 0000000000000000  x23: 0000000000000000
x24: 0000000000000000  x25: 0000000000000000  x26: 0000000000000000
x27: 0000000000000000  x28: 0000000000000000  x29: 000000000007FFF0
x30: 000000000008EF7C  elr_el1: 8EF7C  spsr_el1: 600003C4
  esr_el1: F2000000  far_el1: 0
sctlr_el1: 30D00800  tcr_el1: 0
>

六、BCM2836芯片描述

1)BCM2836芯片资料

  • 树莓派按时间的板子信息如下,因为嵌入式一般是用32位的CPU,所以我使用低版本树莓派,我会将要使用的型号加粗标注:
表4 树莓派的所有板子
发布时间 名称 芯片 外设
2011-12 Raspberry Pi Model B BCM2835 ARM1176JZF-S 700MHz 512M 有网口、无WiFi和蓝牙
2014-7-14 Raspberry Pi Model B+ 同上,BCM2835 ARM1176JZF-S 700MHz 512M 同上
2014-11-11 Raspberry Pi Model A+ 同上,BCM2835 ARM1176JZF-S 700MHz 512M 无网口、WiFi和蓝牙
2015-02-02 Raspberry Pi 2 Model B BCM2836 ARM Cortex-A7 900MHz 4核 1G 有网口、无WiFi和蓝牙
2015-11-26 Raspberry Pi Zero BCM2835 ARM11 1GHz DDR512M 无网口、WiFi和蓝牙
2016-02-29 Raspberry Pi 3 Model B BCM2837 ARM Cortex-A53 1.2GHz 64位4核 1GB 有网络、WiFi和蓝牙
2017-3-1 Raspberry Pi Zero W BCM2835 ARM11 1GHz 512M 无网口,有WiFi和蓝牙
2018-3-4 Raspberry Pi 3 Model B+ BCM2837 ARM Cortex-A53 1.2GHz 64位4核 1GB 有网络、WiFi和蓝牙
2018-11-15 Raspberry Pi 3 Model A+ BCM2837B0 ARM Cortex-A53 1.4GHz 64位4核 1GB 无网络、有WiFi和蓝牙
2019-06-24 Raspberry Pi 4 Model B BCM2711 ARM Cortex-A72 1.5GHz 64位4核 8GB 有网络、WiFi、蓝牙

2)BCM2836芯片资源

  • BCM2836是基于BCM2835的,只是在BCM2835的基础上将CPU从ARM11换成了ARM Cortex-A7,以为外设资源还需要看BCM2835的芯片手册。
表5 博通BCM2836芯片的所有模块
模块名称 描述 备注
GPU VideoCore IV,支持OpenGL ES 2.0,1080p 30帧 H.264和MPEG-4解码
HDMI HDMI音频视频输出
USB 4个USB 2.0,Core和Phy用的是Synopsys IP,该模块被GPU所拥有
SD EMMC 支持MultiMedia和SD卡
以太网 100M
定时器 1个64位定时器,2个32位定时器
Mailbox GPU和CPU核间通信
中断控制 GPU中断和ARM中断
UART 两个串口
SPI SPI1、SPI2
BSC(I2C) Broadcom Serial Controller (BSC),BSC0~2三个,I2C
DMA 数据快速搬运,16个通道
GPIO 54个IO口
I2S PCM 音频输入输出
PWM Pulse Width Modulator
SPI SPI总线

七、BCM2836裸机编程

1)可以参考的教程

2)本地裸机项目介绍

表6 源文件结构与描述
文件夹 文件名 作用 描述
arch 硬件相关源码的文件夹
samples 单元测试用例所在的文件夹 验证某项功能是否已实现
samples/01_asm_boot BCM2836的汇编boot和串口输出
……

1、硬件平台

  • 裸机项目使用QEMU模拟器
  • 树莓派模拟器介绍详见QEMU源码中的qemu\docs\system\arm\raspi.rst
    • 支持的板子有:raspi0、raspi1a+、raspi2b、raspi3a+、raspi3b
    • 支持的模块有:ARM核、GPU固件特性、ARM和GPU核间通信邮箱、中断控制、时钟与复位控制、定时器、GPIO、串口、随机数发生器、显示帧缓存、USB、SD卡、芯片温度传感器。
    • 不支持的模块有:SPI、ADC、PWM、GPU
    • 运行板子基础的命令有:qemu-system-aarch64 -M raspi3b
    • QEMU和树莓派有关的源码细节:
      • qemu\hw\arm\raspi.c
      • qemu\include\hw\intc\bcm2835_ic.h, bcm2836_control.h
      • qemu\include\hw\arm\bcm2836.h, bcm2835_peripherals.h
#include "hw/char/pl011.h"
#include "hw/char/bcm2835_aux.h"
#include "hw/display/bcm2835_fb.h"
#include "hw/dma/bcm2835_dma.h"
#include "hw/intc/bcm2835_ic.h"
#include "hw/misc/bcm2835_property.h"
#include "hw/misc/bcm2835_rng.h"
#include "hw/misc/bcm2835_mbox.h"
#include "hw/misc/bcm2835_mphi.h"
#include "hw/misc/bcm2835_thermal.h"
#include "hw/misc/bcm2835_cprman.h"
#include "hw/misc/bcm2835_powermgt.h"
#include "hw/sd/bcm2835_sdhost.h"
#include "hw/gpio/bcm2835_gpio.h"
#include "hw/timer/bcm2835_systmr.h"

2、arch文件夹

  1. 裸机源码目录和文件类型仿照Linux的风格来布置,参考的具体Linux版本为2022-11-07 07:07打tag的linux_6.1-rc4版本。
  1. BCM2836的寄存器地址头文件,通过在Ubuntu下下载Linux kernel源码,安装树莓派提供的ARM交叉编译工具,将BCM2835的默认配置改成BCM2836的,然后编译生成。

3、samples文件夹

  • 大量测试用例的工程都在samples文件夹中
  • 已实现的有汇编boot,串口输出,

4、

八、RTOS编程

九、Linux编程

  • 前提:编译U-Boot和Linux kernel源码时,源码版本、PC主机Linux系统版本、交叉编译器版本都有影响,最好按照网上教程中相同的版本来尝试,要不然经常会遇到编译时遇到了问题,但又搜不到解决方法的尴尬局面。

  • 必须在Linux系统中编译(如Ubuntu),不能在MSYS2中编译。

1)直接编译Linux源码并运行

1、编译U-Boot并在QEMU中运行



# 因为我当前不编译Linux PC下的程序,所以我直接将整个环境都配成交叉编译的
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
# 增加交叉编译器的路径,修改成你自己解压的路径
export PATH=$PATH:/home/jim/Desktop/tools/arm-gnu-toolchain-11.3/bin
  • 编译U-Boot:
    • make vexpress_ca9x4_defconfig
    • make -j4
  • 编译U-Boot时报错发现未安装而需要安装的软件:
    • sudo apt-get install make
    • sudo apt-get install gcc
    • sudo apt-get install bison
    • sudo apt-get install flex
    • sudo apt-get install libssl-dev
    • 如果lib/display_options.c:59:9: 编译器内部错误: 非法指令报错时将该行改成:
      unsigned long d = 1000000000;//1e9;
  • 编译完成后会在uboot源码目录下生成u-boot文件,将其用QEMU运行即可。
  • 编译好的u-boot文件我已经放在另一个仓库中,地址为:https://gitee.com/langcai1943/linux_kernel_u-boot_busybox_code_comments/tree/develop/bin/v1.0.0
jim@DESKTOP-SVP3BEM MSYS /d
$ qemu-system-arm -M vexpress-a9 -m 256 -kernel u-boot --nographic


U-Boot 2023.01-rc2 (Nov 25 2022 - 17:27:26 +0800)

DRAM:  256 MiB
WARNING: Caches not enabled
Core:  18 devices, 10 uclasses, devicetree: embed
Flash: 64 MiB
MMC:   mmci@5000: 0
Loading Environment from Flash... *** Warning - bad CRC, us
ing default environment
......

2、编译Linux kernel

  • 如果要编译用于BCM2836或ARM CoreTile Express开发板的Linux kernel,则必须要在Linux环境如Ubuntu中编译。一是因为编译过程中有各种依赖库;二是因为kernel源码中有三个以aux命名的文件,这个文件名在Windows环境中不允许存在,在Windows中解压或者拷贝kernel源码时都会报错;如果一定要在Windows下的MinGW中编译,网上找不到任何教程,你可以在kernel源码中强行修改aux文件名和对应的Kconfig、Makefile后,并安装各种依赖库,只能自行尝试;在MSYS2中安装各种依赖库软件也是需要自行摸索的,应该很少有教程。

    • 不要在Windows下git clone kernel源码后再拷贝到Linux系统中编译,会丢失软连接,导致dt-bindings/pinctrl/xxx.h文件明明有,但是链接器提示找不到文件的报错,该问题很难解决。
    • (使用)Linux kernel官方源码中也支持BCM2835/6/7和ARM CoreTile Express,源码查看路径为https://gitee.com/mirrors/linux_old1 ;我当前使用Linux官方最新的源码,下载路径为v6.1-rc6。整个仓库带所有Git历史的源码有好几G,如果用git clone的方式拉代码,中间时间比较久,一旦中间网络中断,则无法恢复,需要重新clone;推荐直接下载zip压缩包,这样只有250M。
    • (当前不使用)树莓派官方提供了从Linux kernel中派生的源码,但是版本比kernel官方低很多,路径为https://github.com/raspberrypi/linux
    • 编译好的zImage和vexpress-v2p-ca9.dtb文件我已经放在另一个仓库中,地址为:https://gitee.com/langcai1943/linux_kernel_u-boot_busybox_code_comments/tree/develop/bin/v1.0.0
  • Ubuntu主机和交叉编译工具可以直接用上面U-Boot同样的环境,下面介绍的是32位Ubuntu16.04下使用的交叉编译工具;Linux kernel在此环境下也能编译通过。


  • 这是在32位Ubuntu16.04下编译kernel的步骤,可以不看,后面有64位Ubuntu18.04中编译的介绍。
  • 因为我虚拟机中的64位Ubuntu18.04系统运行起来很慢,所以我最终都会在Ubuntu16.04中编译内核。
  • (使用)Linaro旧版本的地址支持32位主机的工具下载:https://releases.linaro.org/components/toolchain/binaries ,这里面Linaro gcc的最新版本是7.5.0;因为我虚拟机中安装的是32位的Ubuntu 16.04系统,32位的系统可以省去在64位系统中安装32位编译所需环境的步骤,所以我使用gcc-linaro-7.5.0-2019.12-i686_arm-linux-gnueabihf.tar.xz
  • (不使用)树莓派官方也提供了交叉编译工具:https://github.com/raspberrypi/tools ,但是比ARM官方或者Linaro官方的编译器版本要低。下载解压后,BCM2836能用的交叉编译工具的目录在 ./arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/;注意:这只能编译U-Boot、Linux kernel和Linux应用,不能编译ARM裸机程序;但是该编译器编译最新的Linux kernel源码会报错。
  • 如果用Linux官方的kernel源码,则不能使用树莓派的交叉编译工具:
# 因为我当前不编译Linux PC下的程序,所以我直接将整个环境都配成交叉编译的
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
# 增加交叉编译器的路径,修改成你自己解压的路径
export PATH=$PATH:/home/jim/Desktop/tools/arm-gnu-toolchain/bin
* 再 make bcm2835_defconfig
* 当前Linux kernel源码要求最低的gcc版本为Minimum GCC version: 5.1.0,而树莓派提供的版本为4.8.3,版本太低。
  • (不使用)ARM官网的交叉编译工具,当前只支持64位主机下的软件:https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
    • 当前ARM gcc的版本是12.2.0,arm官网从从2016年的GCC6开始只提供64位Linux的交叉编译器可执行文件
  • (不使用)Linaro gcc交叉编译器,最新的gcc版本是11.3,当前只支持64位主机下的下载地址:https://snapshots.linaro.org/gnu-toolchain/11.3-2022.06-1/arm-linux-gnueabihf/
  • 安装了Ubuntu 16.04 32位系统,在里面下载了Linux kernel源码,安装了Linaro gcc7.5.0交叉编译器后
    • make bcm2835_defconfig 生成.config,源码里 没有BCM2836的默认配置,只有2835的,先用这个,然后再在里面改。
    • make menuconfig 打开kernel配置界面。
    • 在kernel字符配置界面中:System type --> Platform selection 取消armv6的选择,只保留armv7;
    • make 因为之前已经配置了ARCH和CROSS_COMPILE变量(也可以只在kernel .config或者Makefile中指定这两个环境变量),直接make ,如果你不是虚拟机,可以make -j8,8核并行编译,加快编译速度;编译时间比较久,可能要几分钟到几十分钟;要生成uImage的话要指定地址,例如make uImage LOADADDR=0x8000,生成的uImage在arch/arm/boot/中。
    • 如果遇到编译报错,提示某些.h文件找不到,则一般是电脑上没安装对应的库;将报错信息百度,按照搜到的文章安装缺少的库,再重新编译即可。
  • 设备树在2011年3月在从Linux kernel源码3.1版本中正式替代寄存器头文件。

# 因为我当前不编译Linux PC下的程序,所以我直接将整个环境都配成交叉编译的
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
# 增加交叉编译器的路径,修改成你自己解压的路径
export PATH=$PATH:/home/jim/Desktop/tools/arm-gnu-toolchain/bin
  • 下载最新的Linux kernel源码:v6.1-rc4

  • 编译:

    • make vexpress_defconfig
    • make zImage dtbs -j4
  • 安装过程中遇到了报错,需要安装依赖库:

    • sudo apt-get install g++
    • sudo apt-get install libmpc-dev
    • 将arch/arm/boot/zImage和arch/arm/boot/dts/vexpress-v2p-ca9.dtb拷贝出来
  • 运行:

  • 运行效果:

jim@DESKTOP-SVP3BEM MSYS /d/1_git/cj-security-camera/linux
$ qemu-system-arm -M vexpress-a9 -m 256M -nographic -kernel zImage -dtb vexpress-v2p-ca9.dtb
Booting Linux on physical CPU 0x0
Linux version 6.1.0-rc6 (jim@jim) (arm-none-linux-gnueabihf-gcc (Arm GNU Toolchain 11.3.Rel1) 11.3.1
 20220712, GNU ld (Arm GNU Toolchain 11.3.Rel1) 2.38.20220708) #1 SMP Fri Nov 25 23:17:29 CST 2022
CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
OF: fdt: Machine model: V2P-CA9
Memory policy: Data cache writeback
Reserved memory: created DMA memory pool at 0x4c000000, size 8 MiB
OF: reserved mem: initialized node vram@4c000000, compatible id shared-dma-pool
cma: Reserved 16 MiB at 0x6f000000
Zone ranges:
  Normal   [mem 0x0000000060000000-0x000000006fffffff]
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x0000000060000000-0x000000006fffffff]
Initmem setup node 0 [mem 0x0000000060000000-0x000000006fffffff]
CPU: All CPU(s) started in SVC mode.
......
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]---

3、Busybox生成文件系统需要的系统应用程序和制作根文件系统

  • MSYS2中的QEMU不能引导文件系统(未尝试去查找解决该问题),在Linux下运行QEMU能正常引导。

    • 在Ubuntu下安装QEMU:sudo apt install qemu-system-arm
  • 从官网下载最新的BusyBox发布版本:busybox-1.35.0.tar.bz2

  • 因为BusyBox源码更新较慢,ARM最新的编译器11.3编译BusyBox报错无法解决,所以我改用老版本的编译器,能编译通过

  • 10.2版本编译器ARM官方下载地址:gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz

    • 解压后需要重新输出编译器路径:
  • 交叉编译环境的配置方法和上面编译U-Boot时相同

# 因为我当前不编译Linux PC下的程序,所以我直接将整个环境都配成交叉编译的
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
# 增加交叉编译器的路径,修改成你自己解压的路径
export PATH=$PATH:/home/jim/Desktop/tools/gcc-arm-10.2/bin
# 如果之前以及输出了别的版本gcc的路径,则需重新注销或者重启Ubuntu后再执行上面的步骤
  • 编译:
    • make menuconfig
    • 设置 Build Options 开启静态编译(提示: 可使用 / 搜索 static)
      • 在第一行Settings --->上回车,在滚动到中间位置,找到 [ ] Build static binary (no shared libs)并按空格,让括号内多一个星号表示选中,再按两次Esc,在弹出框中按回车保存配置
    • make -j4
    • make install
  • 编译过程中报错时需要安装的依赖库
    • sudo apt install libncurses5-dev

  • 以下内容无效。以下为尝试解决最新的ARM GCC编译器编译时的问题,但最终失败,但保留重新编译安装coreutils工具集的步骤:

  • 遇到报错无法解决:

coreutils/dd.c: 在函数‘dd_output_status’中:
coreutils/dd.c:123:21: 编译器内部错误: 非法指令
  123 | #define G (*(struct globals*)bb_common_bufsiz1)
      |                     ^~~~~~~
coreutils/dd.c:192:29: 附注: in expansion of macro ‘G’
  192 |         seconds = (now_us - G.begin_time_us) / 1000000.0;
      |                             ^
free(): invalid next size (fast)
editors/awk.c: 在函数‘next_token’中:
editors/awk.c:1121:17: 编译器内部错误: 已放弃
 1121 |                 debug_printf_parse("%s: using concat-inserted token\n", __func__);
      |                 ^~~~~~~~~~~~~~~~~~
  • 重新编译安装coreutils也无法解决报错的问题:
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabihf-
export PATH=$PATH:/home/jim/Desktop/tools/arm-gnu-toolchain-11.3/bin
  • 然后登出系统(注销),再重新登入(或者重启也可以),去掉当前环境中的交叉编译环境变量
  • 进入coreutils目录
  • ./bootstrap 运行要一会儿,且没有打印提示,可以通过看自己CPU占用率来判断是否结束
  • 执行时报错,则:
    • sudo apt-get install autoconf
    • sudo apt-get install autopoint
    • sudo apt-get install gperf
    • sudo apt-get install texinfo
  • ./configure
  • make CFLAGS='-w' -j4
  • sudo make install
  • 重新编译Busybox仍然报错。
  • 以上内容无效。

已在BusyBox源码文件夹下生成了_install目录,里面有板子上能用到的各种系统命令

制作根文件系统:
mkdir my_mnt
dd if=/dev/zero of=rootfs.img bs=1024 count=16384  # 创建 16MB 虚拟磁盘
mkfs.ext2 rootfs.img                               # 格式化成 ext2 格式文件系统
sudo mount -o loop rootfs.img my_mnt               # 将镜像文件和块设备关联并挂载设备到my_mnt
sudo cp -r _install/* my_mnt                       # 将 BUsybox 所有生成的程序拷贝到根目录

# 创建4个tty设备(c代表字符设备,4是主设备号,1~4分别是次设备号)
sudo mkdir -p my_mnt/dev
sudo mknod my_mnt/dev/tty1 c 4 1
sudo mknod my_mnt/dev/tty2 c 4 2
sudo mknod my_mnt/dev/tty3 c 4 3
sudo mknod my_mnt/dev/tty4 c 4 4

# 创建终端
sudo mknod -m 666 my_mnt/console c 5 1
sudo umount my_mnt                                        
  • 将生成的rootfs.img拷贝Ubuntu桌面
  • 将之前的u-boot和vexpress-v2p-ca9.dtb拷贝到Ubuntu桌面
  • 编译好的rootfs.img、zImage和vexpress-v2p-ca9.dtb文件我已经放在另一个仓库中,地址为:https://gitee.com/langcai1943/linux_kernel_u-boot_busybox_code_comments/tree/develop/bin/v1.0.0
  • 在Ubuntu桌面上打开终端
  • 在Ubuntu终端中执行 qemu-system-arm -M vexpress-a9 -m 256M -nographic -kernel zImage -dtb vexpress-v2p-ca9.dtb -sd rootfs.img -append "root=/dev/mmcblk0 rw console=ttyAMA0"
  • 可以看到效果:
jim@jim:~/Desktop/usr$ qemu-system-arm -M vexpress-a9 -m 256M -nographic -kernel zImage -dtb vexpress-v2p-ca9.dtb -sd rootfs.img -append "root=/dev/mmcblk0 rw console=ttyAMA0" 
WARNING: Image format was not specified for 'rootfs.img' and probing guessed raw.
         Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
         Specify the 'raw' format explicitly to remove the restrictions.
pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
Booting Linux on physical CPU 0x0
Linux version 6.1.0-rc6 (jim@jim) (arm-none-linux-gnueabihf-gcc (Arm GNU Toolchain 11.3.Rel1) 11.3.1 20220712, GNU ld (Arm GNU Toolchain 11.3.Rel1) 2.38.20220708) #1 SMP Fri Nov 25 23:17:29 CST 2022
CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
OF: fdt: Machine model: V2P-CA9
Memory policy: Data cache writeback
Reserved memory: created DMA memory pool at 0x4c000000, size 8 MiB
OF: reserved mem: initialized node vram@4c000000, compatible id shared-dma-pool
cma: Reserved 16 MiB at 0x6f000000
Zone ranges:
  Normal   [mem 0x0000000060000000-0x000000006fffffff]
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x0000000060000000-0x000000006fffffff]
Initmem setup node 0 [mem 0x0000000060000000-0x000000006fffffff]
CPU: All CPU(s) started in SVC mode.
percpu: Embedded 15 pages/cpu s30612 r8192 d22636 u61440
Built 1 zonelists, mobility grouping on.  Total pages: 65024
Kernel command line: root=/dev/mmcblk0 rw console=ttyAMA0
printk: log_buf_len individual max cpu contribution: 4096 bytes
printk: log_buf_len total cpu_extra contributions: 12288 bytes
printk: log_buf_len min size: 16384 bytes
printk: log_buf_len: 32768 bytes
printk: early log buf free: 14944(91%)
......
can't run '/etc/init.d/rcS': No such file or directory

Please press Enter to activate this console. 
/ # ls
bin         dev         linuxrc     lost+found  sbin        usr
/ # 

2)修改Linux源码并适配树莓派2b

空文件

简介

* 硬件平台均为QEMU模拟器。 1. 当前裸机项目使用ARM Cortex-A7 32位内核、带有GPU(2D 3D显示加速、图片和音频视频编解码)的博通BCM2836芯片(树莓派2B同款硬件,但不使用树莓派的系统和软件)。 2. 当前Linux项目使用ARM Versatile Express开发板,从源码编译运行U-Boot、Linux和根文件系统。 展开 收起
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
C
1
https://gitee.com/VelsonWang/cj-security-camera.git
git@gitee.com:VelsonWang/cj-security-camera.git
VelsonWang
cj-security-camera
嵌入式QEMU教程
develop

搜索帮助

53164aa7 5694891 3bd8fe86 5694891