使用FS4412开发板

网络配置

配置板子IP

编辑/etc/init.d/rcS文件,添加

1
2
ifconfig eth0 192.168.2.111
ifconfig eth0 up

重启板子即可。

配置虚拟机IP

点击虚拟网络编辑器

image-20240410150711037
image-20240410150741702

虚拟机有线网络设置

image-20240410151030759
image-20240410151047806

注意:虚拟机网络适配器需要更改为桥接模式

image-20240410151130855

编译软件

编译软件采用arm-linux-gcc

1
arm-linux-gcc a.c

文件传输

采用tftp工具进行传输

  1. 安装tftp服务器: 注意:虚拟机需要连外网

    1
    2
    sudo    apt-get    update
    sudo apt-get install tftpd-hpa tftp-hpa

  2. 配置tftp服务器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      sudo    vim    /etc/default/tftpd-hpa
    点i进入编辑模式
    TFTP_USERNAME="tftp"
    TFTP_DIRECTORY="/home/hqyj/tftpboot" //共享文件的路径;
    TFTP_ADDRESS="0.0.0.0:69"
    TFTP_OPTIONS="-l -c -s"
    点Esc退出编辑模式

    家目录下面创建目录tftpboot:
    sudo mkdir /home/hqyj/tftpboot
    修改共享文件的权限:
    sudo chmod 0777 /home/hqyj/tftpboot

  3. 启动tftp服务器: Ubuntu开机后只需要启动一次

    1
    sudo service tftpd-hpa restart

  4. 将需要传输的文件存储在共享目录中(/home/hqyj/tftpboot):

    1
    cp  <filename> /home/hqyj/tftpboot

要从远程主机192.168.1.2上下载 test.txt,则应输入以下命令

1
tftp -g -r test.txt 192.168.1.2

将磁盘中的文件上传到远程主机的命令

1
tftp -p -l file.txt 192.168.1.2

Linux文件操作

相关驱动文件存放在/dev中

1
2
int fd = open();
ioctl(fd, _IO('L',0));

ioctl的请求:

  • _IO('L',0) 开灯
  • _IO('L',2) 关灯

裸机操作

image-20240414091204368

可以发现LED3连接到GPX1_0,查询用户手册

image-20240414091553406
  • CON:配置寄存器
  • DAT:数据寄存器
  • PUD:
  • DRV:
image-20240414092432928
image-20240414092049105
image-20240414091844457

可以看到GPX1_0对应配置为GPX1CON[0],配置[3:0]位置即可设置状态

GPX1DAT[7:0]既可以配置输入输出电平,

打开板子开关,马上按回车,进入启动加载界面(U-boot),类似于终端

image-20240414094159863

通过pri命令可以打印基本配置信息

image-20240414094347917

通过set命令修改配置信息,save保存

image-20240414094547766

ping测试连通性

image-20240414094717566

注意:Ubuntu ping不同开发板,裸机只能由开发板主动发起ping

通过tftp下载文件,

1
2
3
tftp 内存地址 文件名
tftp 43e00000 a.out
go 43e00000

此时为裸机,需要用二进制文件才能识别

这个不为二进制数据文件

image-20240414101123569
image-20240414103310580

高级语言:(预处理->编译->汇编->链接)

  • 预处理:展开头文件
  • 编译:把高级语言转变为汇编语言
  • 汇编:转变为二进制
  • 链接:将多个二进制段结合在一起
1
2
3
4
5
6
7
8
9
10
#define GPX1CON (volatile unsigned int *)0x11000c20
#define GPX1DAT (volatile unsigned int *)0x11000c24

int main()
{
*GPX1CON = 0x1;
*GPX1DAT = 0x1;
while(1);
return 0;
}

转变为汇编语言

操作系统启动

量产:研发完成后,直接以一个整体放到内存中,直接启动 -> 产品

研发过程中,首先将系统分为4部分:

启动加载器(bootloader) + 系统内核(kernel) + 设备树(device tree) + 根文件系统(rootfs-root file system)

image-20240417150853819
image-20240417151100936
image-20240418150357886
1
2
3
4
5
6
7
相关命令:
printenv(pri):
saveenv(save):
setenv(set): set 变量名 (变量值) //变量值为空的话就删除变量
boot
bootm 内核 根文件系统 设备树
tftp

分段启动操作系统

1
2
3
将 u-sd.bin烧写进入SD卡
启动u-boot
tftp下载内核镜像,前提为网络可以ping通
image-20240417152243317
1
2
3
4
5
6
tftp 41000000 start/uImage
tftp 42000000 start/exynos4412-fs4412.dtb
tftp 43000000 start/ramdisk.img

bootm 41000000 43000000 42000000
内核 根文件系统 设备树

输入完成后即可进入此界面

image-20240417153246046

配置网络采用ifconfig eth0 ip地址

自启动操作系统

1
2
3
4
5
set bootcmd "tftp 41000000 start/uImage;tftp 42000000 start/exynos4412-fs4412.dtb;tftp 43000000 start/ramdisk.img;bootm 41000000 43000000 42000000"
set bootdelay 1
save

boot

NFS挂载启动

通过网络挂载一个共享文件夹

ramdisk.img是封装好的,rootfs.tar.gz是没封装的

Ubuntu下操作:

1.nfs安装,要有外网
         sudo   apt-get   update
         sudo   apt-get   install    nfs-kernel-server
2.准备好一个即将被共享出去的文件夹
     sudo   mkdir     nfs
     sudo    chmod   0777    nfs

3.将 文件系统 放入 nfs 文件夹, 解压文件系统   解压  rootfs.tar.xz
     tar  -xvf  rootfs.tar.xz

4.解压后进入到rootfs目录,使用pwd确定所对应的绝对路径
     cd    rootfs
     pwd   -->  /home/hqyj/nfs/rootfs 就是用来挂载的共享路径;
    
5.在nfs服务器的配置文件中说明 /home/hqyj/nfs/rootfs 需要共享出去
    sudo   vi    /etc/exports
    尾部加入, 添加新的一行:
        /home/hqyj/nfs/rootfs *(rw,sync,no_root_squash,no_subtree_check)
    解释:
        *:允许所有的网段访问,也可以使用具体的IP
        rw:挂接此目录的客户端对该共享目录具有读写权限
        sync:资料同步写入内存和硬盘
        no_root_squash:root用户具有对根目录的完全管理访问权限
        no_subtree_check:不检查父目录的权限

6.重启nfs共享
     sudo service nfs-kernel-server restart

7.检查是否开成功
     showmount -e
        Export list for ubuntu:
         /home/hqyj/nfs/rootfs  *       //共享成功的路径

开发板上操作(不进操作系统):

8.修改u-boot启动参数
    set   bootargs    "root=/dev/nfs nfsroot=192.168.2.222:/home/hqyj/nfs/rootfs,v3 rw console=ttySAC2,115200 clk_ignore_unused init=/linuxrc ip=192.168.2.111"
        注意更改:
            nfsroot=192.168.2.222:/home/hqyj/nfs/rootfs   //Ubuntu的ip地址,  要挂载的文件路径
        解释:
            root=/dev/nfs //文件系统在网上
            nfsroot=192.168.2.222:/home/hqyj/nfs/rootfs,v3 //那台电脑的哪个文件夹,而且用v3版本的协议
            rw //可读可写
            console=ttySAC2,115200 //通过串口2输出信息,波特率115200
            clk_ignore_unused //忽略未使用的时钟,如果不加很有可能卡住
            init=/linuxrc //当挂载成功后,自动执行init进程(文件夹下的linuxrc文件)
            ip=192.168.2.111 //内核起来之后用这个IP(开发板IP)
            
9.修改u-boot启动命令
set  bootcmd  "tftp  41000000  start/uImage;   tftp 43000000  start/exynos4412-fs4412.dtb;  bootm  41000000  -  43000000"
save

EMMC启动

要确保有一个u-emmc.bin

1
2
3
4
5
6
先SD卡启动,将u-emmc.bin 下载到运存
tftp 41000000 u-emmc.bin

将下载成功的u-emmc.bin放到emmc中
命令:movi write u-boot 41000000
解释:将41000000运存地址数据写入到emmc的u-boot区
image-20240418152230925
image-20240418152306126

进入后操作与前段相同

Bootloader

CPU架构:

1
2
3
4
5
6
7
8
X86(intel):高性能
C51(intel):低功耗,单片机-单应用(51单片机)
ARM(ARM):低功耗同时高性能,移动端市场
Cortex-A:高性能
Cortex-R:实时realtime
Cortex-M:低功耗(STM32)

powerPC:功耗非常高,性能好,用于大型后台服务器

什么是Bootloader?

  • 硬件启动的引导程序,是运行操作系统的前提。
  • 在操作系统内核或用户应用运行之前的一段代码。
  • 对于硬件进行初始化,为操作系统准备好环境。
  • 在嵌入式系统重,整个系统的启动加载任务通常由bootloader来完成。

Bootloader的特点:

  • 不属于操作系统,由汇编语言或C语言开发
  • 针对特定的硬件平台编写
  • 在移植系统时,首先要为开发板移植bootloader
  • bootloader不依赖于CPU的体系结构,依赖于嵌入式系统班设备的配置

bootloader的基本功能:

  • 初始化相关硬件,把bootloader自搬运到内存中
  • 执行用户的命令:访问环境变量,通过串口/网络通信,读写RAM/FLASH
  • 加载并执行内核

bootloader启动:

  1. 第一阶段:BL1
    1. 初始化基本的硬件
    2. 把bootloader搬运到内存
    3. 设置堆栈指针并将bss段清理,为后续执行C代码做准备
    4. 跳转到第二阶段代码
  2. 第二阶段:BL2
    1. 初始化本阶段需要用到底的硬件
    2. 读取环境变量
    3. 如果是自启动模式,从flash或通过网络加载内核并执行
    4. 如果是下载模式,接收用户的命令后执行

u-boot系统移植

1.抄板

仿照别人的板子修改一些信息, 改成自己的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vi boards.cfg 复制284行, yy复制, p粘贴, 将复制的285行中的两个origen修改为fs4412 

cp include/configs/origen.h include/configs/fs4412.h

cp -r board/samsung/origen/ board/samsung/fs4412

mv board/samsung/fs4412/origen.c board/samsung/fs4412/fs4412.c

vi Makefile 修改185行: CROSS_COMPILE ?= arm-none-linux-gnueabi

vi board/samsung/fs4412/Makefile 修改31行: COBJS += fs4412.o

make fs4412
//敲 fs4 用tab键补全 make完成后, 看看有没有报错信息, 没有的话就能生成 u-boot.bin 文件
image-20240418163234598

具体过程:

u-boot移植.pdf

代码修改

tool_SD_img.zip

tool_EMMC_bin.zip

movi 修改文件.zip

Linux内核

通常我们使用的Linux系统是一个集Linux内核、工具集、各种库、桌面管理器、应用程序于一体的一个发布包

一个内核不是一套完整的操作系统,

“内核”指的是一个提''供硬件抽象层、磁盘以及文件控制、多任务等功能的系统软件

内核移植

准备

安装插件exuberant-ctags和libncurses5-dev

1
2
3
sudo apt-get update //更新软件
sudo apt-get install exuberant-ctags
sudo apt-get install libncurses5-dev

获取Linux源码,并解压

1
tar -xvf linux-3.14.tar.xz

修改交叉编译工具

1
2
3
修改Makefile,198行,199行
ARCH ?= arm
CROSS_COMPILE ?= arm-none-linux-gnueabi-
image-20240420110903156

生成默认配置

(配置文件放在 arch/arm/configs下)

1
make exynos_defconfig
image-20240420111239775

配置内核:

正常执行,会弹出一个菜单选项,我们可以去选择需要配置的内核;

1
make menuconfig
image-20240420111316895

在菜单界面选中 dm9000 网卡驱动

1
2
3
4
5
Device Drivers --->
[*] Network device support --->
[*] Ethernet driver support --->
<*> DM9000 support
回车键选择进入, 空格键改变选择, 上下左右方向键改变选择
1
2
3
4
5
6
7
内核中选配必要的网络协议栈支持
[*] Networking support --->
Networking options --->
<*> Packet socket
<*>Unix domain sockets
[*] TCP/IP networking
[*] IP: kernel level autoconfiguration
1
2
3
4
5
6
7
选择NFS支持
File systems --->
[*] Network File Systems (NEW) --->
<*> NFS client support
[*] NFS client support for NFS version 3
[*] NFS client support for the NFSv3 ACL protocol extension
[*] Root file system on NFS
1
2
3
4
5
6
7
8
9
10
11
12
13
选择USB支持
Device Drivers --->
[*] USB support --->
<*> EHCI HCD (USB 2.0) support
<*>EHCI support for Samsung S5P/EXYNOS SoC Series
<*> USB Mass Storage support
<*> USB3503 HSIC to USB20 Driver
USB Physical Layer drivers --->
<*> Samsung USB 2.0 PHY controller Driver
SCSI device support --->
<*> SCSI device support
<*> SCSI disk support
<*> SCSI generic support

编译生成内核镜像

编译内核镜像会用到"mkimage"命令, 需要提前配置一下, 这个工具在 u-boot 文件夹下 首先将u-boot-2013.01文件夹下的mkimage命令复制到用户系统命令文件夹下

1
sudo cp ../u-boot-2013.01/tools/mkimage /usr/local/bin/

编译内核

1
make uImage

编译成功会生成一个经过压缩后的镜像文件uImage,

其生成的文件路径为:arch/arm/boot/uImage

将生成的 uImage 移动到 tftp 共享 路径下

1
cp arch/arm/boot/uImage /home/hqyj/tftp/my_uImage

启动镜像

image-20240420114131499

内核移植.pdf

image-20240421082027484
1
2
3
4
5
Image:原始镜像
zImage:压缩镜像
uImage:在zImage的基础上多补充了【格式头】

Image -> 压缩 -> zImage -> 添加u-boot能解析的格式头 -> uImage

设备树移植

image-20240421090313912

复制一份为exynos4412-fs412.dts

修改527行后面,添加网卡驱动

image-20240421091312045

格式不对,选中全部行,按一下"=",格式即可对齐

image-20240421091359487

修改makefile文件

image-20240421091853047

编译设备树文件:

1
make dtbs
image-20240421091932551

拷贝编译的设备树到tftp共享文件中:

1
cp arch/arm/boot/dts/exynos4412-fs4412.dtb /home/hqyj/tftp/my_exynos4412-fs4412.dtb

挂载启动

image-20240421092414811

拓展:添加USB驱动

1
vim arch/arm/boot/dts/exynos4412-fs4412.dts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
usbphy: usbphy@125B0000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "samsung,exynos4x12-usb2phy";
reg = <0x125B0000 0x100>;
ranges;
clocks = <&clock 2>, <&clock 305>;
clock-names = "xusbxti", "otg";
usbphy-sys {
reg = <0x10020704 0x8 0x1001021c 0x4>;
};
};
ehci@12580000 {
status = "okay";
usbphy = <&usbphy>;
};
usb3503@08 {
compatible = "smsc,usb3503";
reg = <0x08 0x4>;
connect-gpios = <&gpm3 3 1>;
intn-gpios = <&gpx2 3 1>;
reset-gpios = <&gpm2 4 1>;
initial-mode = <1>;
};
1
make dtbs
1
cp arch/arm/boot/dts/exynos4412-fs4412.dtb /home/hqyj/tftp/my_exynos4412-fs4412.dtb

插入USB设备,

image-20240421093222897

字符设备

image-20240421102926332

主(组)设备号,用于定义同一类设备

次设备号用于定位具体设备

修改Makefile

image-20240421111004155

生成驱动代码.ko文件

板子通过insmod myled.ko安装驱动

通过应用程序开关灯

image-20240421111723254

卸载驱动文件

image-20240421112006653

根文件系统制作

我们选择的版本是busybox-1.22.1.tar.bz2, 将文件移动到Ubuntu内, 进行解压:

进入源码目录, 在 busybox-1.22.1 文件夹内进行操作:

1
make menuconfig 
image-20240422160754543
1
2
3
4
5
6
Busybox Settings --->
Build Options --->
[*] Build BusyBox as a static binary (no shared libs)
[ ] Force NOMMU build
[ ] Build with Large File Support (for accessing files > 2 GB)
(arm-linux-) Cross Compiler prefix //采用的编译器是arm-linux-,敲回车输入
image-20240422160843827

配置好保存后, 进行编译:

1
make

编译好后, 安装busybox, 生成根文件夹:

1
make install

安装完成后默认生成 _install 文件夹, 这就是我们制作的根文件夹, 将所有文件拷贝到nfs共享文件夹下, 切换路径:

1
2
3
sudo cp -rf _install /home/hqyj/nfs/my_rootfs
cd /home/hqyj/nfs/my_rootfs
ls
image-20240422161124379

创建缺少的目录

1
sudo mkdir etc dev tmp mnt proc sys var lib
image-20240422161809231

添加所需要的库代码

1
sudo   cp  -a  /home/hqyj/Downloads/gcc-4.6.4/arm-arm1176jzfssf-linux-gnueabi/sysroot/lib/*    ./lib/

删除无用的库,用来保证rootfs足够小8M以内;

1
2
3
sudo rm lib/*.a     
sudo cp /home/hqyj/Downloads/gcc-4.6.4/bin/arm-linux-strip /usr/local/bin/
sudo arm-linux-strip lib/*
image-20240422161930999

添加系统启动文件

在etc下添加文件inittab,文件内容如下 sudo vi etc/inittab

1
2
3
4
5
6
7
8
9
#this is run first except when booting in single-user mode.
::sysinit:/etc/init.d/rcS
# /bin/sh invocations on selected ttys
# start an "askfirst" shell on the console (whatever that may be)
::askfirst:-/bin/sh
# stuff to do when restarting the init process
::restart:/sbin/init
# stuff to do before rebooting
::ctrlaltdel:/sbin/reboot

在etc下添加文件fstab,文件内容如下,

1
2
3
4
5
#device mount-point type options dump fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0

在etc下创建init.d目录,并在init.d下创建rcS文件,rcS文件内容为:

1
2
3
4
5
#!/bin/sh
# This is the first script called by init process
/bin/mount -a
echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -s

为rcS添加可执行权限:

1
sudo chmod +x etc/init.d/rcS

在etc下添加profile文件,文件内容为:

1
2
3
4
5
6
7
8
#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH
export HOSTNAME=Group3
export USER=Vicczyq
export HOME=root
export PS1="[$USER@$HOSTNAME \W]\# "

复制文件系统, 修改挂载镜像

在nfs服务器的配置文件中说明 /home/hqyj/nfs/my_rootfs 需要共享出去

1
sudo vi /etc/exports  
1
2
3
4
将原来的挂载信息屏蔽 - 前面加#:
# /home/hqyj/nfs/rootfs *(rw,sync,no_root_squash,no_subtree_check)
尾部加入, 添加新的一行:
/home/hqyj/nfs/my_rootfs *(rw,sync,no_root_squash,no_subtree_check)
1
2
重启nfs
sudo service nfs-kernel-server restart

开发板设置启动参数

1
2
set bootargs "root=/dev/nfs nfsroot=192.168.2.222:/home/hqyj/nfs/my_rootfs,v3 rw console=ttySAC2,115200 clk_ignore_unused init=/linuxrc ip=192.168.2.111"
save
image-20240422163406444

打包为img镜像文件

1
cd /home/hqyj/nfs

创建一个8M的空磁盘(ramdisk)

1
dd if=/dev/zero of=ramdisk bs=1k count=8192 
image-20240422171712115

把ramdisk制作成ext2格式的文件

1
mkfs.ext2 -F ramdisk  
image-20240422171736733

创建mymnt目录作为挂载点

1
mkdir  mymnt 

把ramdisk挂载到mymnt/

1
sudo mount -t ext2 ramdisk mymnt/ 

将测试好的文件系统里的内容全部拷贝到 mymnt/ 目录下面

1
sudo cp -a my_rootfs/* mymnt/

取消挂载

1
sudo  umount  mymnt/

压缩ramdisk为ramdisk.gz

1
gzip  --best  -c  ramdisk  >  ramdisk.gz

格式化为uboot识别的格式

1
mkimage -n "ramdisk" -A arm -O linux -T ramdisk -C gzip -d ramdisk.gz ramdisk.img
image-20240422172254713

拷贝到tftp目录下,方便下载

1
cp  ramdisk.img  /home/hqyj/tftp/my_ramdisk.img

板子设置

1
set bootcmd "tftp 41000000 my_uImage;tftp 42000000 my_exynos4412-fs4412.dtb;tftp 43000000 my_ramdisk.img;bootm 41000000 43000000 42000000"
image-20240422173216187

整个打包

创建一个img镜像文件

1
sudo dd if=/dev/zero of=fs4412.img bs=1M count=300

安装工具

1
sudo apt install kpartx qemu-utils fdisk

建立分区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sudo fdisk ./fs4412.img
1.使用m可以查看帮助
2.使用n快速创建分区 这里第一分区是16m
3.第二分区剩下的全部(需再按一次n重新分区)
4.记得保存 使用w进行保存
5.最后按q退出
一般都选择默认 分区大小写 +16m 表示增加16m的分区如下:

Command (m for help): n //创建分区
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p //创建主分区
Partition number (1-4, default 1): 1 //第一分区
First sector (2048-614399, default 2048): 2048 //默认 也可直接按回车
Last sector, +sectors or +size{K,M,G,T,P} (2048-614399, default 614399): +16m //表示增加16m 若直接回车表示后面的全部为该分区的内容 所以第二分区可以直接全按回车

Created a new partition 1 of type 'Linux' and of size 16 MiB.

加载img文件

1
2
3
4
5
6
7
sudo kpartx -av ./fs4412.img
加载成功会出现以下位置:
sudo kpartx -av ./fs4412.img
add map loop28p1 (253:0): 0 32768 linear 7:28 2048
add map loop28p2 (253:1): 0 579584 linear 7:28 34816
说明在设备加载在/dev/loop28
而两个分区是/dev/mapper/loop28p1 和loop28p2

格式化两个分区

1
2
3
4
第一分区为fat16(按需求 v3s是fat16)
sudo mkfs -t fat /dev/mapper/loop28p1
第二分区为ext4
sudo mkfs.ext4 /dev/mapper/loop28p2 -L rootfs

挂载两个分区

1
2
3
4
5
6
7
创建两个文件夹
mkdir -p ./boot
mkdir -p ./rootfs
挂载两个分区到两个文件夹中
sudo mount /dev/mapper/loop28p1 ./boot/
sudo mount /dev/mapper/loop28p2 ./rootfs/
加载完后可以用 df -h命令查看是否挂载下面图有挂载成功的图
image-20240424112658286

将boot,内核,设备树文件拷贝进boot分区中

PhraseEdit.txt