一.ubuntu系统需要安装的软件包
二.课程SDK
Linux 嵌入式Linux系统相关
images 嵌入式Linux系统镜像(rom)
prebuilts 交叉编译工具链
src 嵌入式Linux系统源码
tools 开发工具
package 软件包
sudo apt-get install stardic
sudo cp dic/* /usr/share/stardict/dic/ -rf
extern 软件包
三.嵌入式系统
不带系统
MCU
带系统
SOC Linux/Android
四.工作岗位
硬件工程师(设计电路画板)
软件工程师
应用程序开发
驱动开发
第一次开发:半导体原厂做,高通 三星 飞思卡尔 TI 小米 华为 联发科 全志
第二次开发:开发板解决方案厂商
第三次开发:项目
五.ARM
arm
cpu SOC
经典处理器:
arm7 ------> S3C44B0
arm9 ------> S3C2410/S3C2440
arm11 -----> S3C6410
cortex系列:
arm-cortex-a
a8 S5PV210 三星 单核 win android linux
AM335 TI 单核 win android linux
a9 Exynos4412 三星 4核
Omap4460 TI 双核
S5P4418 三星 四核
Imax6Q NXP 四核
Imax6D NXP 双核
a15 Exynos5210 三星 8核心(4个a15,4个a7)
arm-cortex-m
m3 stm32f103
m4 stm32f407
m7 stm32f707
arm-cortex-r
realtime
V8:arm-cortex-a
a50
a53 S5P6818
a57
a72
a73
S5P6818开发板启动方式
1.sd启动
2.emmc
3.usb
六.软件架构
应用程序
/ init进程---->其他进程
kernel 进程管理 内存管理 文件系统支持 网络 设备驱动,挂载根文件系统
bootloader 初始化硬件,加载内核
原厂启动代码 初始化基本硬件,检测启动方式,加载bootloader
-----------------------------------------------------
SOC+DDR(1G)+EMMC(8G)+LCD+SOUND+NET+WIFI+BLE+USB+.........
七.Andriod系统和Linux系统
Android手机
emmc{bootloader uImage ramdisk [system][data][cache][storage]}
bootloader---->uImage---->ramdisk(内存)
/system 系统软件
/data 用户自己安装的软件通讯录配置
/cache
/storage 用户软件产生的数据
Android系统的rom:
bootloader
uImage
ramdisk
system.img
userdata.img
cache.img
针对我们的开发板:
emmc{bootloader [uImage ramdisk][system][data][cache][storage]}
Android系统的rom:
bootloader
boot.img
system.img
userdata.img
cache.img
Linux系统:
emmc{booloader uImage [rootfs]}
Linux系统的rom:
bootloader
uImage
rootfs.img
针对我们的开发板:
emmc{booloader [uImage][rootfs]}
Linux系统的rom:
bootloader
boot.img
rootfs.img
=========================================================================================
八.刷机原理
1.板子首次启动需要sd卡启动
2.sd中的bootloader启动后运行fastboot命令进入刷机模式
3.pc把刷机rom发送给开发板,开发板的fastboot把收到的镜像文件写到emmc的合适位置
九.刷机
刷机Linux系统:
Linux系统rom:/home/zyli/6818/s5p6818sdk_lzy1/Linux/images
S5P6818如果从sd卡启动,会从sd卡的第二个扇区读取bootloader
sd{512bytes|bootloader [--------------------][-----------------]}
/dev/sdx /dev/sdx1 /dev/sdx2
1>建立sd分区
参考<建立sd卡分区.mp4>
2>把bootloader烧写到sd卡
sudo dd if=./ubootpak.bin of=/dev/sdx seek=1
3>配置minicom
安装:sudo apt-get install minicom
配置:sudo minicom -s
+-----[configuration]------+
| Filenames and paths |
| File transfer protocols |
| Serial port setup |
| Modem and dialing |
| Screen and keyboard |
| Save setup as dfl |
| Save setup as.. |
| Exit |
| Exit from Minicom |
+--------------------------+
选择Serial port setup
+------------------------------------------+
| A - Serial Device : /dev/ttyUSB0 |
| B - Lockfile Location : /var/lock |
| C - Callin Program : |
| D - Callout Program : |
| E - Bps/Par/Bits : 115200 8N1 |
| F - Hardware Flow Control : No |
| G - Software Flow Control : No |
| |
| Change which setting? |
+------------------------------------------+
运行:sudo minicom
4>在开发板上运行uboot,在minicom中观察启动过程
a>运行minicom
b>把sd卡插入卡槽(前提是在sd卡中烧写了bootloader)
c>给开发板上电(或者重启),在minicom中观察启动过程
d>在启动后,minicom中会有倒计时,在倒计时完成前敲键盘的任意键
e>敲任意键后板子会进入uboot提供的shell命令行
[zyli@Uboot]#
5>fastboot刷机
确保:usb线以及连接
a>在uboot的shell中执行fastboot
[zyli@Uboot]# fastboot
b>在电脑上执行刷机命令
[ubuntu@Ubuntu]# sudo fastboot devices
[ubuntu@Ubuntu]# sudo fastboot flash ubootpak ./ubootpak.bin
[ubuntu@Ubuntu]# sudo fastboot flash boot ./boot.img
[ubuntu@Ubuntu]# sudo fastboot flash system ./rootfs.ext2
c>切换到minicom
在minicom中执行Ctrl+C
[zyli@Uboot]#
6>修改环境变量
目的:告诉告诉开发板内核和根的位置
注意:以下命令在开发板上(也就是minicom中)执行
bootloader启动后3s如果没有敲键盘则bootloder会默认执行环境变量bootcmd指定的操作
[zyli@Uboot]# set bootcmd "ext4load mmc 2:1 0x48000000 uImage;bootm 0x48000000"
解释:ext4load 命令 从emmc中把文件加载到内存
uImage 被加载的文件
mmc 固定
2:1 2代表第二个设备 板子上有三个mmc设备(sd0, sd1, emmc)
0x48000000 开发板的内存地址
bootm 命令 启动内核
注意:接下来要告诉内核根的位置
[zyli@Uboot]# set bootargs root=/dev/mmcblk0p2 tp=gslx680-linux
注意:如果是mipi接口的屏幕,需要增加一个参数lcd=wy070ml
解释:bootargs这个环境变量的值最终会传给内核
root 指定根的位置
/dev/mmcblk0p2
内核启动后会识别emmc,emmc被识别为/dev/mmcblk0
两个分区分别被识别为/dev/mmcblk0p1 /dev/mmcblk0p2
tp执行触摸屏的类型
注意:环境变量修改后需要保存
[zyli@Uboot]# save
7>重启开发板
如果正常的话会进入linux系统
在开发板的屏幕上会出现基于QT5的界面
在minicom中会出现要求登录的界面(用户名root,密码123456)
刷Android系统:
1>在开发板运行fastboot命令
[zyli@Uboot]# fastboot
2>在PC上依次执行如下命令
[ubuntu@Ubuntu]# sudo fastboot flash ubootpak ubootpak.bin
[ubuntu@Ubuntu]# sudo fastboot flash boot boot.img
[ubuntu@Ubuntu]# sudo fastboot flash system system.img
[ubuntu@Ubuntu]# sudo fastboot flash userdata userdata.img
[ubuntu@Ubuntu]# sudo fastboot flash cache cache.img
3>修改环境变量
[zyli@Uboot]# set bootcmd "ext4load mmc 2:1 0x48000000 uImage;ext4load mmc 2:1 0x49000000 root.img.gz;bootm 0x48000000"
[zyli@Uboot]# set bootargs lcd=vs070cxn tp=gslx680
[zyli@Uboot]# save
[zyli@Uboot]# reset
给Android安装软件
adb 可以通过usb控制android系统
安装adb:
[ubuntu@Ubuntu]# sudo apt install android-tools-adb
利用adb给Android系统安装软件:
[ubuntu@Ubuntu]# adb devices
[ubuntu@Ubuntu]# adb install 100Project.apk
=========================================================================================
十.编译Linux系统rom
uboot
解压uboot源码:
[src]$ tar -xvf uboot6818.tar.bz2
[src]$ cd uboot
[uboot]$ make x6818_config
[uboot]$ vim include/configs/x6818.h
141 #define CONFIG_SYS_PROMPT "[uplooking@Uboot]# "
交叉编译工具链:
arm-eabi-gcc
arm-eabi-ld
arm-eabi-as
arm-eabi-objdump
arm-eabi-objcopy
arm-eabi-nm
配置交叉编译工具链:
[uboot]$ vim Makefile
203 CROSS_COMPILE=/home/zyli/6818/s5p6818sdk_lzy1/Linux/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
[uboot]$ vim board/s5p6818/x6818/config.mk
27 CROSS_COMPILE=/home/zyli/6818/s5p6818sdk_lzy1/Linux/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
编译:
[uboot]$ make -j4
[uboot]$ sudo cp tools/mkimage /usr/bin
####
u-boot-->u-boot.bin-->ubootpak.bin
####
kernel
[src]$ tar -xvf linux-3.4.tar.bz2
[src]$ cd kernel/
[kernel]$ make x6818_defconfig
[kernel]$ vim Makefile
195 ARCH ?= arm
196 CROSS_COMPILE ?= /home/zyli/6818/s5p6818sdk_lzy1/Linux/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
[kernel]$ make -j4
#####
vmlinux--->arch/arm/boot/zImage----uImage
uboot要求在zImage前面加一个头[arm Linux]zImage
#####
##制作uImage:
[kernel]$ make uImage
##制作boot.img:
[tools]$ tar -xvf boot.tar.bz2
[tools]$ cd boot
##删掉和Linux系统无关的文件
[boot]$ rm debug-ramdisk.img ramdisk-recovery.img root.img.gz
##用我们自己的内核替换原来的内核
[boot]$ cp ../../src/kernel/arch/arm/boot/uImage ./
[boot]$ cd ..
##制作镜像文件
[tools]$ ./make_ext4fs -s -l 64M -L linux boot.img boot
rootfs
#####
根文件系统:硬盘一个分区 /
abc dev initrd.img.old libx32 nfsroot run
bin etc lib lost+found opt sbin
boot home lib32 media proc snap
cdrom initrd.img lib64 mnt root srv
Busybox:工具集---->命令
buildroot:busybox qt5 python go mplayer mpg123
#####
[src]$ tar -xvf buildroot.tar.bz2
[src]$ cd buildroot/
[buildroot]$ make x6818_defconfig
[buildroot]$ make -j4
[buildroot]$ vim output/build/host-ncurses-5.9/include/curses.tail
104 extern NCURSES_EXPORT(bool) mouse_trafo (int*, int*, bool);
[buildroot]$ make -j4
编译完成后:buildroot/output/images/rootfs.ext2
经过编译:ubootpak.bin boot.img rootfs.ext2
刷机:正真产品发布的时候
开发:uboot---->sd
uImage---->tftp
rootfs---->nfs
=========================================================================================
十一.tftp
作用:用于开发板从PC下载文件,直接把文件下载到内存
配置tftp服务器:
配置方法参考
开发板的uboot中自带tftp客户端:
确保:开发板和PC之间要联网
[lzy@Uboot]# set ipaddr 192.168.100.250
[lzy@Uboot]# set serverip 192.168.100.199
[lzy@Uboot]# save
[lzy@Uboot]# ping 192.168.100.199
如果提示not alive则再次ping
[lzy@Uboot]# tftp 0x48000000 uImage
###下载成功的界面:
Speed: 1000, full duplex
Using dwmac.c0060000 device
TFTP from server 192.168.100.199; our IP address is 192.168.100.250
Filename 'uImage'.
Load address: 0x48000000
Loading: #################################################################
#################################################################
#################################################################
#################################################################
#################################################################
##########################################
2.6 MiB/s
done
Bytes transferred = 5383216 (522430 hex)
##测试文件的正确性
[lzy@Uboot]# bootm 0x48000000
笔记本与开发板网络链接方法:
开发板与PC的以太网卡直连
PC的wifi与路由器链接用来上外网
<详细内容参考 网络配置.mp4>
十二.网络文件系统
1>在PC上配置nfs服务
[redis]$ sudo apt-get install nfs-kernel-server
[redis]$ sudo vim /etc/exports
/redis_root *(rw,sync,no_root_squash)
[redis]$ sudo mkdir /redis_root
[redis]$ sudo chmod 777 /redis_root/
[redis]$ sudo /etc/init.d/nfs-kernel-server restart
2>测试
[buntu@Ubuntu]# sudo mount 192.168.200.172:/redis_root /mnt
然后可以通过访问/mnt来达到访问对方redis_root的目的
[buntu@Ubuntu]# sudo unmount /mnt
十三.搭建nfs网络根文件系统
[images]$ sudo tar -xvf rootfs.tar -C /redis_root/
十四.让开发板内核启动后挂在nfs
[lzy@Uboot]# set bootargs root=/dev/nfs nfsroot=$serverip:/redis_root ip=$ipaddr tp=gslx680-linux
[lzy@Uboot]# save
十五.启动开发板
为了避嫌我们先把emmc擦除掉
[lzy@Uboot]# mmc erase 0 10240
[lzy@Uboot]# ping $serverip
[lzy@Uboot]# tftp 0x48000000 uImage
[lzy@Uboot]# bootm 0x48000000
问题:
当Linux挂在nfs后,启动init进程---->执行脚本(/etc/init.d/rcS)---->执行其他脚本
=========================================================================================
十六.嵌入式应用软件开发
扩展buildroot
<参考视频 BuildRoot扩展选项.mp4>
安装交叉编译器:
[extern]$ tar -xvf arm-linux-gcc-4.5.1.tar.bz2
[extern]$ vim ~/.bashrc
PATH=/home/zyli/6818/s5p6818sdk_lzy1/extern/4.5.1/bin:$PATH
[extern]$ source ~/.bashrc
本地程序开发:
在PC上对程序进行交叉编译:
[ubuntu@Ubuntu]# touch hello.c
#include
int main(void) {printf("hello arm
");}
[ubuntu@Uboot]# arm-linux-gcc hello.c -o hello
把程序拷贝到共享目录
[ubuntu@Uboot]# cp hello /redis_root
在开发板上启动内核,并且挂载nfs
[x6818@localhost]# /hello
hello arm
QT程序开发:
1>创建QT工程,编写代码,在PC测试运行
2>交叉编译
[test]$ cp qtemb/ qtemb_board -rf
[test]$ cd qtemb_board
[qtemb_board]$ ~/6818/s5p6818sdk_lzy1/Linux/src/buildroot/output/host/usr/bin/qmake
[qtemb_board]$ make
3>把程序放到开发板执行
让自己开发的程序能够自启动
1>改变开发板根文件系统中的文件
[ubuntu@Ubuntu]$ sudo vim /redis_root/etc/init.d/S99qttest
或者:
[x6818@localhost]# vim /etc/init.d/S99qttest
修改如下:
#/usr/share/demo/qttest &
/usr/bin/qtemb &
2>让开发板能够自动下载内核和启动内核
[lzy@Uboot]# set bootcmd "ping 1;ping 2;tftp;tftp;bootm"
[lzy@Uboot]# save
======================================================================================
十七.远程登录开发板
[ubuntu@Ubuntu]# ssh root@192.168.200.123
十八.嵌入式软件移植例子
移植sqlite3
[下载]$ tar -xvf sqlite-autoconf-3200100.tar.gz
[下载]$ cd sqlite-autoconf-3200100/
[sqlite-autoconf-3200100]$ mkdir /redis_root/sqlite
[sqlite-autoconf-3200100]$ ./configure --prefix=/redis_root/sqlite/ --host=arm-linux CC=arm-linux-gcc --enable-shared --enable-static
[sqlite-autoconf-3200100]$ make -j4
[sqlite-autoconf-3200100]$ make install
=====================================================================================
作业前传:
1>数据库基本使用
2>嵌入式QT中调用数据库
作业:
计算器改造:
1>把计算历史存储到数据库 1 + 2 + 3 = 6
2>在计算器界面增加两个按键,用来查看计算历史
=====================================================================================
问题解决:
home分区太小 根大
sudo mkdir /document
sudo chown zyli:zyli /document
ln -s /document ~/document
=====================================================================================
十九.Arm架构和Arm汇编
-5 1000000000.....101
1111111111.....011 >> 1
1111111111.....101---->10000000.....011
0111111111.....101---->2^31-1-2
|-----与外界通信
ARM=Arm_Core+MMU+协处理器+Cache+Cache控制器+TCM+总线接口+移位器+........
| | | |----I-cache |---I-TCM |---<< >>
| | | |----D-cache |---D-TCM
| | |------控制CP15
| | |------调试CP14
| |----内存管理单元(虚拟到物理的转换)
|---------执行指令,r0,r1,...,r15
Arm处理器的模式
七种模式:
-普通模式 user 用来执行进程代码
-特权模式 system
-异常模式
irq 用来执行中断代码
--产生了中断
fiq 用来执行快速中断代码
--产生了快速中断
und 用来处理未定义指令
--1.cpu遇到了未定义指令
svc 用来执行bootloader和内核
-----swi/svc用来由user切换到svc(arm平台的系统调用)
-----reset(上电,重启按钮,看门狗)
abt 用来处理中止异常
--1.越界
--2.内存地址不存在
cpu上电运行的默认模式:
svc
新增的模式:
1.虚拟化模式
2.安全
指令集
Arm指令 32位/高效
经典处理器 a系列
Thumb指令 16位
早期的经典处理器
Thumb2指令 32/16位
m系列
流水线
arm7
取指 译码 执行
6----------------
5----------------
4----------------
3----------------取指
2----------------取指 译码
1----------------取指 译码 执行
寄存器
参考 P43
R0, R1, R2 .... R15
每一种异常模式都有自己的R13/R14
R0-R12 32位
R13 SP stack pointer
R14 LR link register
R15 PC 指向正在被取指的指令
R9 SB
bar:
-------push {lr}-----
---------------------
---------------------
---------------------
---------------------
-------pop {lr}------
--------bx lr-------- PC=LR
foo:
-------push {lr}-----
---------------------
---------------------
-----bar()-bl bar---- LR=下一条指令的地址 PC=bar
---------------------
-------pop {lr}------
--------bx lr-------- PC=LR
main:
-------push {lr}-----
---------------------
----foo()-bl foo----- LR=下一条指令的地址 PC=foo
---------------------
-------pop {lr}------
--------bx lr--------
结构
哈佛结构
指令和数据分开存放
arm7
冯诺依曼结构
指令和数据一起存放
arm7---cahce----ddr
arm---I-cache
--------cache------ddr
---D-cache
6----------------
5----------------
4----------------
3----------------取指
2----------------取指 译码
1----------------取指 译码 执行 把一个数据存放到内存 *p=123
arm-cortex-a8 只能做单核
arm-cortex-a9/15/53 多核
a8自带一级和二级cache
arm---I-cache
--------cache-
---D-cache
a9只有一级cache
arm---I-cache
---D-cache
ARM汇编
Arm常用指令参考
代码参考
汇编指令<--汇编-->机器码
hello.c--->hello.s---->hello.o--->hello
内嵌汇编 在C/C++中写汇编
语法:
1.
unsigned int register c asm("sp");
unsigned int register c asm("r0");
c = 0x100;
2.
int main() {
int a = 5;
int b = 6;
int c;
//C
asm volatile(
);
__asm__ __volatile__(
"mov r0, #20
"
"mov r0, #20
"
"mov r0, %[aa]
"
"mov r0, %1
"
"mov %0, #2
"
"r0,"
"#20
"
:[bb]"=&r"(b), [cc]"+r"(c)声明输出变量和输入输出变量
:[aa]"r"(a)声明输入变量
:"r0"保护寄存器和内存
注意:&表示输出不采用输入变量使用过的寄存器
);
}
=======================================================================
插曲:通过网络把文件从PC拷贝到board
前提:板子已经启动(根在emmc)
保证:板子和PC之间能够ping通
在板子上执行如下命令:
[root@X6818:~]# mount -t nfs -o nolock,rw 172.16.170.179:/redis_root /mnt
=======================================================================
通过串口下载文件
保证:minciom正常启动
开发板启动Linux系统
进入[root@X6818:~]#
操作:
ctrl+a--->z--->s
=======================================================================
反汇编 arm-linux-objdump -D 04in_out >04in_out.s
8388: e3a0000f mov r0, #15
838c: e3a00eff mov r0, #0x00000ff0 ; 0xff
mov r0, #0x7f8
0111 1111 1000--->ff 3
e3a00eff
mov r0, #0x3f4
0011 1111 0100--->fd 2
e3a00ffd
0xe = 14 * 2 = 28
32 - 28 = 4
立即数规则:1.本身小于等于255
2.经过循环右移偶数位之后小于等于255
3.特殊情况 mov r0, #0xffffff00
mvn r0, #0xff
CPSR 当前程序状态寄存器
31 30 29
N Z C V Q EAIFT M[4:0]
E:如果E==1代表大端,否则为小端(默认),任何模式不得改变
但是通过协处理器cp15可以修改
A:中止禁止位,如果为1代表禁止
I:中断禁止位
F:快速中断禁止位
T:thumb
user模式只能修改NZCVQ
M:表示当前处理器的模式,特权模式下可以修改
N:如果出现了负操作,那么N会被硬件置1,否则清零
Z:如果出现了0操作,那么Z会被硬件置1,否则清零
C:加法,如果进位了会被硬件置1,否则清零
减法,如果借位了会被硬件清零,否则置1
注意:如果指令的结果想影响cpsr的标志为,那么指令需要+s
0x60030010
0110 0000 0000 0011 0000 0000 0001 0000
伪指令:cpu不承认 但编译器承认
ldr r0, =0x12345678 ------> r0=0x12345678
make环境变量
[base]$ export CC=arm-linux-gcc
[base]$ export CFLAGS=-march=armv7-a
[base]$ make 07mul
arm-linux-gcc -march=armv7-a 07mul.c -o 07mul
条件执行
a = 5; b = 6;
if (a > b) { a - b ---> NZ N=1 Z=0
c = 1; N=0 && Z=0
xxxx
} else {
c = 0; N=1 || Z=1
yyyyy
}
arm指令大部分可以加条件 lt gt le ge ne eq
moveq r0, #123 Z=1
跳转
while(1); for(;;);----------------------> b .
PC 是一寄存器,保存永远都是正在被取指的指令,也就是正在被执行指令的下下条指令的地址
bl biaohao 在跳转到标号所指定的代码段执行之前会把bl的下一条指令的地址保存到lr
APCS规则:规定了C/C++和汇编之间相互调用的规则
1.编译器
2.程序员
1.传参 r0-r3 多余的参数从后往前依次入栈
2.栈 满递减栈
fd
fa
ed
ea
3.返回值 r0 r1r0
总结:
一.嵌入式系统架构
二.刷机
三.编译
四.tftp nfs
五.作业
六.Arm架构
七.汇编语言
二十.裸板开发
模板
├── inc
│ ├── common.h
│ └── hw.h
├── Makefile
└── src
├── hw.c
├── main.c
├── Makefile
└── start.s
裸板代码编译:
[src]$ arm-linux-gcc -c -o hw.o hw.c -I../inc
[src]$ arm-linux-gcc -c -o main.o main.c -I../inc
[src]$ arm-linux-as -o start.o start.s
[src]$ arm-linux-ld start.o main.o hw.o -o arm -Ttext 0x50000000
[src]$ arm-linux-objcopy -O binary arm arm.bin
链接地址:假设的程序运行地址
位置相关:运行地址必须==链接地址
位置无关:运行地址可以!=链接地址
注意:为了保证程序能够正常执行,最好运行地址==链接地址
在Uboot源码中可以找到System.map,在这个文件中可以找到printf的地址
0x43c1c5e0
GPIO
通用的输入输出口
可以配置输出功能或者输入功能或者其他功能
SOC S5P6818简介
SMP/AMP
SOC ---> SCP 需要外接内存
POP 自带内存
3个mmc接口
0--->msd
1--->msd
2--->emmc
emmc/nand
emmc=控制器+nand
UART/USART
115200 8N1
9600
38400
发送寄存器 FIFO 发送器-------------------------->>>>------------------
接收寄存器 FIFO 接收器--------------------------<<<<------------------
数据传输方式:
1.DMA
2.irq GIC VIC NVIC
3.poll
##################################################################################
内核驱动: 内核接口 硬件
c /dev/ttyUSB0 /dev/my-led
--------------------
uart_driver:1.内核
2.硬件
led_drivrer:1.内核
2.硬件
-------------------
uart硬件 led buzzer wdt
##################################################################################
项目使用:使用QT操作uart
<参考嵌入式天空:QT5.8编程之串口编程>