---
# System prepended metadata

title: BeagleBone Black

---


## UART
![圖片](https://hackmd.io/_uploads/SyKnD9zU1x.png =x400) ![圖片](https://hackmd.io/_uploads/rJOwOqf8kx.png =x400)
![圖片](https://hackmd.io/_uploads/Hymw7SSckx.png =x300)

可以使用 mini usb 供電，不用另外買 DC supply!!
如果要在開機時從sd card，請上電前長按 S2 按鈕



## 編譯的準備
我是使用 Virtualbox + ubuntu 22.04

編譯相關 toolchain
```bash=
liang@ubuntu:~/Desktop/beagle_black$ uname -a
Linux ubuntu 6.8.0-49-generic #49~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Nov  6 17:42:15 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
```

其他編譯工具安裝指令
```bash=
sudo apt install make git gcc-arm-none-eabi gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf gcc bison flex libssl-dev dpkg-dev lzop libncurses5-dev
```
再有遇到問題就直接裝吧 ( sudo apt install xxx )
[arm交叉編譯器gnueabi、none-eabi、arm-eabi、gnueabihf、gnueabi區別](https://github.com/jasonblog/note/blob/master/toolchain/173.md)
### u-boot
```bash=
git clone https://github.com/u-boot/u-boot
cd u-boot/
export CC=arm-linux-gnueabihf-
make ARCH=arm CROSS_COMPILE=${CC} distclean
make ARCH=arm CROSS_COMPILE=${CC} am335x_evm_defconfig
make menuconfig
make ARCH=arm CROSS_COMPILE=${CC}
```
這邊在 menuconfig 需要先修改成 am335x_boneblack
![Snipaste_20250301_2318](https://hackmd.io/_uploads/r1wsHolsye.png =x300)
![圖片](https://hackmd.io/_uploads/HyTG8jlikl.png =x200)

這邊要關注2個檔案。`MLO` and `u-boot.img` (編譯完會產生)
另外 export 只會在這一次開機中加入而已，要永久需要下
`vim ~/.bashrc` 再最後加入 `CC=arm-linux-gnueabi-`

```javascript=
  (以上省略)
  AR      spl/net/built-in.o
  LDS     spl/u-boot-spl.lds
  LD      spl/u-boot-spl
  OBJCOPY spl/u-boot-spl-nodtb.bin
  COPY    spl/u-boot-spl.bin
  MKIMAGE MLO
  MKIMAGE MLO.byteswap
  SYM     spl/u-boot-spl.sym
  COPY    u-boot.dtb
  MKIMAGE u-boot-dtb.img
  OFCHK   .config
```



## SD Card 的準備
先談談 sd 卡分幾個區域，一共兩個

```txt=
格式：FAT32
大小：至少 64MB or 128MB 應該就夠了
用途：存放開機文件 (MLO, u-boot.img)
```
```txt=
格式：ext4
大小：剩餘空間
用途：Linux 根文件系統 (rootfs)，我也把 zImage dtb 放到這邊 /boot/
```
操作

```bash=
export DISK=/dev/sdb

# 查看 blk
lsblk

# 0.完全清除 10M
sudo dd if=/dev/zero of=${DISK} bs=1M count=10

# 1. 進入 fdisk
sudo fdisk /dev/sdb

# 2. 建立第一個分區 (FAT32)
n    # 新分區
p    # primary
1    # 分區號碼 1
Enter # 預設起始位置
+64M  # 分配 64MB

# 3. 建立第二個分區 (ext4)
n    # 新分區
p    # primary
2    # 分區號碼 2
Enter # 預設起始位置
Enter # 使用剩餘所有空間

# 4. 更改第一個分區類型為 FAT32
t    # 改變分區類型
1    # 選擇第一個分區
c    # FAT32 類型代碼

# 5. 寫入並退出
w

# 6. 格式化分區
sudo mkfs.vfat -F 32 -n "BOOT" /dev/sdb1
sudo mkfs.ext4 -L "rootfs" /dev/sdb2

# 查看 lsblk 會出現如下
#sdb      8:16   1  14.5G  0 disk 
#├─sdb1   8:17   1    64M  0 part 
#└─sdb2   8:18   1  14.4G  0 part /media/liang/rootfs


# 7. 燒入 MLO u-boot.img
sudo dd if=./u-boot/MLO of=${DISK} count=1 seek=1 bs=128k
sudo dd if=./u-boot/u-boot.img of=${DISK} count=4 seek=1 bs=384k

// seek = 1 的 384KB 位置開始，每次寫入 384KB 的資料
// 總共寫入 4 次，所以會寫入 384KB × 4 = 1536KB 的空間
// u-boot.img = 1461412 bytes ≈ 1.46 MB ≈ 1.4 MB
// 要寫入的區塊數計算：1461412 bytes / (384 * 1024) bytes ≈ 3.7 區塊
// 設為 count=4 比較安全

// 其它指令
sync  //強制同步
lsblk //後方就會出現mountpoints
sudo mount /dev/sdb1 /media/liang/rootfs   //掛載
sudo umount /dev/sdb1                      //移除掛載
hexdump ./u-boot/MLO
sudo dd if=/dev/sdb bs=128k count=2 | hexdump -C -n 160
sudo dd if=/dev/sdb bs=128k skip=3 count=5 | hexdump -C -n 160
```
:::info
建議使用 dd 指令來操作，這樣可以 dump 記憶體方便觀察，如果使用 mount + cp 複製檔案，address 會由檔案系統來管理，較難觀察
:::
> [!NOTE]說明一下 linux 中的 dd 指令
> dd [if=input_file] [of=output_file] [options]
> if=: 輸入文件或設備（如 /dev/sda）。
> of=: 輸出文件或設備。
> bs=: 塊大小（單位如 KB、MB），影響每次讀寫的數據量。
> count=: 複製的塊數。
> skip=: 跳過輸入文件中的塊數。
> seek=: 跳過輸出文件中的塊數。
```
sdb      8:16   1  14.5G  0 disk 
├─sdb1   8:17   1    64M  0 part 
└─sdb2   8:18   1  14.4G  0 part /media/liang/rootfs

sudo dd if=/dev/sdb bs=128k count=2 | hexdump -C -n 160
sudo dd if=/dev/sdb1 bs=128k count=2 | hexdump -C -n 160
這兩者差異?
在您的系統中：
/dev/sdb 是一個 14.5GB 的完整磁盤
/dev/sdb1 是其上的 64MB 分區
所以這兩個命令會顯示完全不同的內容：
第一個命令會顯示磁盤的引導扇區和分區表信息，MBR（主引導記錄）或 GPT（GUID 分區表）

```

檔案大小概念(才發現其實linux編完也沒有很大，精華中的精華)
```markdown=
MLO: 約 100KB
u-boot.img: 約 400KB-1.46 MB
uImage: 約 4MB-8MB,功能更多可以到25MB之類的
dtb: 約 30KB-50KB
```
假設你只有燒入 MLO u-boot.img 應該可以開到 uboot 的 cmd狀態（uboot 會自己倒數，按下任意見進入 shell 交談）
![圖片](https://hackmd.io/_uploads/SkbtAB4I1g.png =x800)
uboot 開起來後最後是 "=>" 的樣子
![圖片](https://hackmd.io/_uploads/rkFw1IN81l.png)


這邊另外多提一下 rootfs 這件事
> Question 
請問 sd card boot 起來帶進 linux kernel 後，他所使用的 rootfs 其實是 sd card 中 rootfs mount 上去的嗎 ?  所以如果再 shell 中操作mkdir 其實會存在 sd card 上 ?

是。當 BeagleBone Black 從 SD 卡啟動後：
1. 開機流程：
```
MLO -> u-boot.img -> uImage (Linux kernel) -> mount rootfs
```
2. rootfs 掛載：
- Kernel 會將 SD 卡上的第二個分區（ext4）掛載為根文件系統
- 這個分區就變成了系統的 `/` 目錄
3. 文件操作：
```bash=
mkdir /test    # 這個目錄會被創建在 SD 卡的第二個分區上
touch /file    # 這個文件也會被保存在 SD 卡上
```
4. 持久性：
- 所有的文件操作都會直接寫入到 SD 卡
- 關機後這些更改會被保留
- 下次開機時這些文件還會存在

所以，你在==shell 中的所有操作實際上都是在操作 SD 卡上的文件系統==。這邊也呼應sdb2 之所以框比較大就是儲存用 (==)


## rootfs 的製作
當我們在一台 linux 主機上 cd 到 / 會看到好多熟悉的資料夾，主要是這些事已經製作好的 rootfs檔案結構，可以自己一個資料夾自己做，並且設定權限，或載其它 linux 發行好的 rootfs 來應用

```bash=
// https://rcn-ee.com/rootfs/eewiki/minfs/ 裡面可以找到別人做好的 rootfs
sudo tar xfvp ./armhf-rootfs-ubuntu-focal.tar -C /media/liang/rootfs/
sync
sudo chown root:root /media/liang/rootfs/
sudo chmod 755 /media/liang/rootfs/

# 切到 linux 資料夾中
cd linux
kernel_version=`make kernelversion`
echo $kernel_version
sudo sh -c "echo 'uname_r=${kernel_version}' >> /media/liang/rootfs/boot/uEnv.txt"
```
:::info
* tar 指令請背
* sync 指令確保 linux 在緩衝區的資料都會寫入硬碟，通常要等很久
可以使用指令監看 watch -n 1 "cat /proc/meminfo | grep -i dirty"
它會 1s 查看 dirty 一次，數值為 0 代表處理完了
![圖片](https://hackmd.io/_uploads/ByGrNlEc1l.png)

* "sudo chown root:root" 這行有必要嗎 ?
有必要因為一般 / 的owner 以及 group 都應該是 root
![圖片](https://hackmd.io/_uploads/rkcoGlVqJx.png)
* "sudo chmod " 有必要嗎 ?
有必要很多系統目錄使用 755
    ls -l /
    drwxr-xr-x   2 root root  4096 Jan  1 00:00 bin
    drwxr-xr-x   2 root root  4096 Jan  1 00:00 etc
    只有 root 可以 rwx ，其它 group 跟 other 只能 r-x
:::


```
liang@ubuntu:/$ ll
total 2097248
drwxr-xr-x  20 root root       4096  三  11  2023 ./
drwxr-xr-x  20 root root       4096  三  11  2023 ../
lrwxrwxrwx   1 root root          7  三  11  2023 bin -> usr/bin/
drwxr-xr-x   4 root root       4096  二  18 23:10 boot/
drwxrwxr-x   2 root root       4096  三  11  2023 cdrom/
drwxr-xr-x  19 root root       4440  二  20 07:33 dev/
drwxr-xr-x 133 root root      12288  二  20 07:37 etc/
drwxr-xr-x   3 root root       4096  三  11  2023 home/
lrwxrwxrwx   1 root root          7  三  11  2023 lib -> usr/lib/
lrwxrwxrwx   1 root root          9  三  11  2023 lib32 -> usr/lib32/
lrwxrwxrwx   1 root root          9  三  11  2023 lib64 -> usr/lib64/
lrwxrwxrwx   1 root root         10  三  11  2023 libx32 -> usr/libx32/
drwx------   2 root root      16384  三  11  2023 lost+found/
drwxr-xr-x   3 root root       4096  三   6  2024 media/
drwxr-xr-x   3 root root       4096  一   1 17:28 mnt/
drwxr-xr-x   3 root root       4096  三  11  2023 opt/
dr-xr-xr-x 331 root root          0  二  20 07:32 proc/
drwx------   6 root root       4096  一   1 16:44 root/
drwxr-xr-x  34 root root       1000  二  20 07:37 run/
lrwxrwxrwx   1 root root          8  三  11  2023 sbin -> usr/sbin/
drwxr-xr-x  15 root root       4096  五  24  2023 snap/
drwxr-xr-x   2 root root       4096  八   9  2022 srv/
-rw-------   1 root root 2147483648  三  11  2023 swapfile
dr-xr-xr-x  13 root root          0  二  20 07:32 sys/
drwxrwxrwt  18 root root      12288  二  20 07:42 tmp/
drwxr-xr-x  15 root root       4096  一   1 16:36 usr/
drwxr-xr-x  14 root root       4096  八   9  2022 var/
liang@ubuntu:/$ 
```


## Linux 編譯與安裝到 rootfs

```bash=
git clone https://github.com/torvalds/linux
cd linux
export CC=arm-linux-gnueabi-
make ARCH=arm multi_v7_defconfig
make -j6 ARCH=arm CROSS_COMPILE=${CC} zImage
make ARCH=arm dtbs
make -j6 ARCH=arm CROSS_COMPILE=${CC} modules

#開始安裝複製到 rootfs
kernel_version=`make kernelversion`
sudo sh -c "echo 'uname_r=${kernel_version}' >> /media/liang/rootfs/boot/uEnv.txt"
sudo cp -v arch/arm/boot/zImage /media/liang/rootfs/boot/vmlinuz-${kernel_version}
sudo mkdir -p /media/liang/rootfs/boot/dtbs/${kernel_version}
sudo cp -v arch/arm/boot/dts/ti/omap/am3
35x-boneblack.dtb /media/liang/rootfs/boot/dtbs/${kernel_version}
sudo make -j6 ARCH=arm CROSS_COMPILE=${CC} INSTALL_MOD_PATH=/media/liang/rootfs modules_install

# 設定系統檔案表 (?)
sudo sh -c "echo '/dev/mmcblk0p1  /  auto  errors=remount-ro  0  1' >> /media/liang/rootfs/etc/fstab"

# 新增加網路設定
sudo nano /media/liang/rootfs/etc/network/interfaces
> auto lo
> iface lo inet loopback
>  
> auto eth0
> iface eth0 inet dhcp

# 到這邊可以先啟動到 u-boot 畫面，剩下部分會在 u-boot裡面介紹

```
:::info
Image: vmlinux的二進位檔案。
zImage: 壓縮過的映像檔，並自帶解壓縮。
uImage: 加了64位元U-boot標頭檔的zImage。
:::
:::info
關於 dtbs 那一行 sudo cp -v arch/arm/boot/dts/*.dtb /media/liang/rootfs/boot/dtbs/${kernel_version}

發現會出現錯誤，原因是在新的 linux 版本中存放位置已經更動，先查詢
liang@ubuntu:~/Desktop/beagle_black/linux$ find ./ -name am335x-boneblack.dtb
./arch/arm/boot/dts/ti/omap/am335x-boneblack.dtb
重新複製要的 dtb 進 sd card
:::
> Question 
先編譯 zImage 再編譯 modules ?

是。模組可以在系統運行時動態載入/卸載，不會被包含在 zImage 中。
```bash=
# 1. 編譯核心映像
make ARCH=arm CROSS_COMPILE=${CC} zImage

# 2. 分開編譯模組
make ARCH=arm CROSS_COMPILE=${CC} modules

# 3. 安裝模組（到指定目錄）
make ARCH=arm CROSS_COMPILE=${CC} INSTALL_MOD_PATH=/path/to/rootfs modules_install
```

編譯 dts
`make ARCH=arm dtbs`
![圖片](https://hackmd.io/_uploads/SJuwuRMLyx.png =x200)
這是 Linux 內核配置選單中關於記憶體初始化的選項：
三個選項代表不同的堆疊（stack）變數初始化策略：
no automatic stack variable initialization：
* 最弱的保護
* 不會自動初始化堆疊變數
* 性能最好但最不安全

pattern-init everything：
* 使用特定模式初始化所有堆疊變數
* 可以幫助偵測未初始化的變數使用
* 適合除錯

zero-init everything：
* 最強且最安全的選項
* 將所有堆疊變數初始化為零
* 可以預防一些安全漏洞
* 性能開銷最大

選擇建議：

開發/除錯時可以選 2 或 3
生產環境如果性能重要可以選 1
安全性要求高的系統建議選 3

> Question 
dts 用途跟他到底要在哪邊選擇跟執行 ?
最重要的就是

1. 相同的 SoC 但不同開發板：
```
AM335x SoC：
- BeagleBone Black (am335x-boneblack.dtb)
- BeagleBone Green (am335x-bonegreen.dtb)
- Custom Board (am335x-custom.dtb)

都可以使用相同的 zImage，只需要更換對應的 .dtb 文件
```

2. 啟動參數設定：
參考 https://hackmd.io/@waterdog/SkHjns_Xyg


優點：
- 同一個核心支援多種硬體配置
- 不需要重新編譯核心
- 降低維護成本
- 方便硬體擴展

這就是為什麼 Device Tree 在嵌入式 Linux 開發中如此重要的原因之一。所以在編譯的時候幾本上會針對這個 arch/arm 整個 dts 全部都編譯進去，畢竟檔案大概也才約 30KB-50KB



## 參考連結
文件
* [datasheet](https://docs.beagleboard.org/beaglebone-black.pdf)
* [AM335x and AMIC110 Sitara™ Processors](https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf?ts=1735692016626&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FAM3358)
* [Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)](https://e-mailky.github.io/2019-01-14-dts-1)
* [BeagleBone Black 从零到一 (2 MLO、U-Boot)](https://blog.csdn.net/yuntongsf/article/details/78087717)

影片
* [Building Linux Kernel and Preparing bootable SD CARD for Beaglebone Board](https://www.youtube.com/watch?v=l0746JYroOg)
* [Embedded Linux Booting Process (Multi-Stage Bootloaders, Kernel, Filesystem)](https://www.youtube.com/watch?v=DV5S_ZSdK0s)

## 學習歷程建議(滾動式調整)