项目介绍:嵌入式QEMU教程

项目介绍:嵌入式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项目kernel、U-Boot、BusyBox rootfs编译和运行
使用的开源库

一、前言

  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)完整的环境安装步骤

  • 写在前面,我会提供已经安装好各种工具的MSYS2环境,如果你没用过Linux,建议你直接下载本系统压缩包cj_msys64.zip(该压缩包太大,有2G,暂未上传),解压后使用,或者自行使用VMware Player虚拟机+Ubuntu安装开发环境,因为MSYS2中安装软件的教程很难快速找到,需要有一些使用Linux的经验才知道怎么安装特定软件;我的MSYS2环境添加了32位和64位的交叉编译工具,他们的来源不一样,后面会详述。

  • 下面是从头到尾的工具软件安装步骤:

    • 推荐使用MSYS2 + 已经用MinGW32或MinGW64编译好的程序,基本上开发过程中你能在Linux下实现的,也都能在这个环境下实现,只是有些教程没有Ubuntu下那么好找;在MSYS2中不能使用Linux的程序,必须用MinGW将源码重新编译过后才能使用,这一般是软件供应商已经做好的。
    • MSYS2的更多信息详见本仓库子文档《04_MSYS2简述.md》
表2 MSYS2、MinGW和Cygwin的关系
软件名版本作用特点
MSYSMSYS,MSYS2Linux命令行终端:Shell,Bash没有在Windows下编译Linux程序的工具集,会自带已经被MinGW编译好的一些包;脱胎于Cygwin,但容量更小;MSYS2是因为MSYS常年不更新而新组的的一个项目;MSYS2安装完后的文件名为msys64,你可以将你安装好之后的msys64文件夹打包发给别人,这样别人无安装就可以用了,只是容量有点大,几十G
MinGWMinGW32,MinGW64一组编译工具链编译后生成的是纯粹的Windows程序;它自带的命令行终端很难用也不全,要和MSYS2终端配合使用;MinGW64是因为MinGW32常年不更新而新组的的一个项目
CygwinCygwin编译工具+命令行有模拟层,将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。
    效果如下:在这里插入图片描述
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= P A T H : / m i n g w 64 / b i n e x p o r t P A T H = PATH:/mingw64/bin export PATH= PATH:/mingw64/binexportPATH=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 上的小型嵌入式系统

(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_mailboxesCPU和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_virtualmemoryMMU虚拟内存映射
11_exceptions测试异常中断
12_printf测试printf输出
13_debuggergdb调试输出
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

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

在这里插入图片描述

7)0A_pcscreenfont

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

在这里插入图片描述

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-12Raspberry Pi Model BBCM2835 ARM1176JZF-S 700MHz 512M有网口、无WiFi和蓝牙
2014-7-14Raspberry Pi Model B+同上,BCM2835 ARM1176JZF-S 700MHz 512M同上
2014-11-11Raspberry Pi Model A+同上,BCM2835 ARM1176JZF-S 700MHz 512M无网口、WiFi和蓝牙
2015-02-02Raspberry Pi 2 Model BBCM2836 ARM Cortex-A7 900MHz 4核 1G有网口、无WiFi和蓝牙
2015-11-26Raspberry Pi ZeroBCM2835 ARM11 1GHz DDR512M无网口、WiFi和蓝牙
2016-02-29Raspberry Pi 3 Model BBCM2837 ARM Cortex-A53 1.2GHz 64位4核 1GB有网络、WiFi和蓝牙
2017-3-1Raspberry Pi Zero WBCM2835 ARM11 1GHz 512M无网口,有WiFi和蓝牙
2018-3-4Raspberry Pi 3 Model B+BCM2837 ARM Cortex-A53 1.2GHz 64位4核 1GB有网络、WiFi和蓝牙
2018-11-15Raspberry Pi 3 Model A+BCM2837B0 ARM Cortex-A53 1.4GHz 64位4核 1GB无网络、有WiFi和蓝牙
2019-06-24Raspberry Pi 4 Model BBCM2711 ARM Cortex-A72 1.5GHz 64位4核 8GB有网络、WiFi、蓝牙

2)BCM2836芯片资源

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

七、BCM2836裸机编程

1)可以参考的教程

  • Boot流程介绍:

    • 一般ARM芯片从0地址启动,而0地址默认是复位中断的入口,写了复位中断处理程序后,进一步向下执行就是配置堆和栈的地址与大小,配置系统频率、DDR内存,跳转到C语言Main()函数执行。
    • 而BCM2836是GPU先运行,并且GPU的Boot程序是闭源的,所以是GPU从0地址开始跑;
    • GPU先运行bootcode.bin这个程序,再引导start.elf程序运行,然后再引导kernel8.img这个ARM程序运行,ARM程序运行的起始地址是固定的0x8000,所以写ARM裸机程序的时候第一个代码段要指定到这个地址。
    • 写ARM裸机程序时,一些必要的芯片初始化也可以省略,因为GPU已经帮忙做了,外设寄存器地址从0x3F000000虚拟地址开始
    • 有关BCM2836 Boot的介绍详见本地文档./raspi3-tutorial/README.md 的“About the hardware”小节。
    • BCM2836 ARM启动前的Boot程序下载地址:Welcome to the Raspberry Pi Firmware Wiki
    • Boot固件下载地址2:raspberrypi/firmware
    • 这里有树莓派官方的ARM Boot汇编代码:tools/armstubs/armstub8.S
  • 几个对裸机编程有帮助的教程:

  • 参考网址:

  • https://github.com/raspberrypi 里有树莓派的一些仓库集合,有用的一些仓库有:

    • https://github.com/raspberrypi/tools
    • Source code for ARM side libraries for interfacing to Raspberry Pi GPU:https://github.com/raspberrypi/userland
    • https://github.com/raspberrypi/libcamera
    • https://github.com/raspberrypi/firmware
    • The official documentation for Raspberry Pi computers and microcontrollers:https://github.com/raspberrypi/documentation
    • https://github.com/raspberrypi/linux
    • Github链接如果打不开,则可以将链接放到Gitee里搜索,一般都有人上传镜像

2)本地裸机项目介绍

表6 源文件结构与描述
文件夹文件名作用描述
arch硬件相关源码的文件夹
samples单元测试用例所在的文件夹验证某项功能是否已实现
samples/01_asm_bootBCM2836的汇编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版本。
  • linux_6.1-rc4版本代码查看和下载路径:Linux 6.1-rc4
  • arch文件夹里面存放和硬件相关的内容,能抽象出去的纯逻辑内容都会剥离出去。
  • 因为一个功能或者模块可能会被拆分为硬件相关和硬件无关的部分,所以其它文件夹里的.c/h文件,可能在arch文件夹内会有同名的文件存在。
  • 不像普通的单片机源码结构同名的.c源文件和.h头文件放在同一个文件夹内,这个裸机工程里源文件和头文件是放在不同的文件夹内的;头文件单独放在一起方便单独输出调用接口;这样在有需要时也方便对底层代码保密,用多了也就能对这种代码组织结构习惯了。
  • arch文件夹里面有汇编写的Boot代码,汇编先执行后再引导C语言的main()函数。
    • Cortex-A7汇编语言、关键字、伪指令和编码风格详见本仓库内的子文档:[《05_ARM Cortex-A7汇编语言和GNU伪指令介绍.md》](./doc/05_ARM Cortex-A7汇编语言和GNU伪指令介绍.md)
  • BCM2836外设地址可以参见Linux中设备树的源码:https://gitee.com/mirrors/linux_old1/blob/master/arch/arm/boot/dts/bcm2836-rpi-2-b.dts ,和https://gitee.com/mirrors/linux_old1/blob/master/arch/arm/boot/dts/bcm283x.dtsi
  • BCM2836的汇编boot可以参见Linux中arch/arm/boot/中的代码: https://gitee.com/mirrors/linux_old1/blob/master/arch/arm/boot/bootp/init.S
  • BCM2836的汇编boot也可以参见U-Boot中arch/arm/cpu/armv7/中的代码:https://gitee.com/mirrors/u-boot/blob/master/arch/arm/cpu/armv7/start.S
  1. BCM2836的寄存器地址头文件,通过在Ubuntu下下载Linux kernel源码,安装树莓派提供的ARM交叉编译工具,将BCM2835的默认配置改成BCM2836的,然后编译生成。
3、samples文件夹
  • 大量测试用例的工程都在samples文件夹中
  • 已实现的有汇编boot,串口输出,
4、

八、RTOS编程

九、Linux编程

1)编译Linux kernel

  • 如果要编译用于BCM2836的Linux kernel,则必须要在Linux环境如Ubuntu中编译,因为kernel源码中有三个以aux命名的文件,这个文件名在Windows环境中不允许存在,在Windows中解压或者拷贝kernel源码时都会报错;如果一定要在Windows下的MinGW中编译,网上找不到任何教程,你可以在kernel源码中强行修改aux文件名和对应的Kconfig、Makefile后自行尝试。

    • 不要在Windows下git clone kernel源码后再拷贝到Linux系统中编译,会丢失软连接,导致dt-bindings/pinctrl/xxx.h文件明明有,但是链接器提示找不到文件的报错,该问题很难解决。
    • (当前不使用)树莓派官方提供了从Linux kernel中派生的源码,路径为https://github.com/raspberrypi/linux 。
    • (使用)但是Linux kernel官方源码中也支持BCM2835/6/7,路径为https://gitee.com/mirrors/linux_old1 ;我当前使用Linux官方的源码,但是推荐使用树莓派自己的源码;整个仓库有好几G,如果用git clone的方式拉代码,中间时间比较久,一旦中间网络中断,则无法恢复,需要重新clone;推荐直接下载zip压缩包,这样只有250M。
  • (不使用)树莓派官方提供了交叉编译工具:https://github.com/raspberrypi/tools ,下载解压后,BCM2836能用的交叉编译工具的目录在 ./arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/;注意:这只能编译U-Boot、Linux kernel和Linux应用,不能编译ARM裸机程序;也可以不用树莓派提供的,而自行去ARM官方或者Linaro官方交叉编译工具。

    • 如果用Linux官方的kernel源码,则不能使用树莓派的交叉编译工具:
      • Linux kernel源码的下载路径:https://gitee.com/mirrors/linux_old1/tree/v6.1-rc4
      • 先在Linux系统环境中修改芯片类型和编译器名称:
      • export ARCH=arm
      • export CROSS_COMPILE=arm-linux-gnueabihf-
      • 再 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/
      • (使用)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
  • 安装了Linux发行版系统,在里面下载了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版本中正式替代寄存器头文件。

    • .dtsi设备树文件中只有各个模块的起始寄存器地址,没有每个寄存器详细的描述,而每个模块的寄存器定义和偏移则在每个驱动的源文件中,不会有一个统一的.h头文件包含了所有的寄存器地址定义。
    • 设备树添加之前的2.6.xx版本中,能在/arch/arm/plat-xxx和/arch/arm/mach-xxx中看到芯片的所有模块的寄存器基地址,和模块中所有寄存器的头文件宏定义。例如:https://gitee.com/mirrors/linux_old1/blob/v3.0/arch/arm/mach-bcmring/include/mach/csp/mm_addr.h ,https://gitee.com/mirrors/linux_old1/blob/v3.0/arch/arm/include/asm/hardware/dec21285.h 和 https://gitee.com/mirrors/linux_old1/blob/v3.0/arch/arm/mach-bcmring/include/mach/reg_umi.h 等。
  • 参考网址

2)编译U-Boot并在QEMU中运行



  • 从ARM官网下载最新的,在64位PC上使用的32位ARM交叉编译工具,下载速度比较慢。

    1. 下载地址:[arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz]https://developer.arm.com/-/media/Files/downloads/gnu/11.3.rel1/binrel/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz)
    • 这是最新版本的查看地址:https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
    1. 或者从Linaro上下载当前最新的稳定版本,下载地址:gcc-linaro-12.2.1-2022.11-x86_64_arm-linux-gnueabihf.tar.xz
    • Linaro的下载速度也很慢;暂时没找到国内提供的下载镜像。
  • 输出芯片架构和交叉编译工具名称的环境变量

  • 输出交叉编译工具的路径

  • 编译uboot时报错发现未安装而需要安装的软件:

    • 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运行即可。

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
......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值