---
# System prepended metadata

title: 嵌入式系統總整與實作 Raspberrypi 4 筆記
tags: [嵌入式系統]

---

# 嵌入式系統總整與實作 Raspberrypi 4 筆記

## PIN腳
![image](https://www.raspberrypi.com/documentation/computers/images/GPIO-Pinout-Diagram-2.png)

![image](https://hackmd.io/_uploads/SyfwfJcQR.png)


## GPIO PIN腳注意事項

1. 輸入信號不要超過3.3V
2. 接LED要再接470$\Omega$電阻
3. 若要供電樹莓派，不要大於5V
4. 若不接電供，3.3V的PIN的輸出電流最大只有500mA，接電供最大可以到1.5A
5. 不要用TTL線傳送程式檔案，因為TTL的buffer不夠大
6. **有控制GPIO的狀態的程式執行要加上```sudo```**

## 同時連接2個以上I2C device

> reference: https://medium.com/@mileperuma/enable-multiple-i2c-ports-on-raspberry-pi-5a8807471737

1. 修改```/boot/config.txt```檔案:
   ```
   dtparam=i2c_arm=on #add after this line 
   dtoverlay=i2c-gpio,bus=5,i2c_gpio_sda=12,i2c_gpio_scl=13
   ```
   每個設定以空白分隔，設定格式: ```dtoverlay=i2c-gpio,bus=<要以哪個bus與此I2C裝置連接，盡量與其他I2C裝置不同?>,i2c_gpio_sda=<I2C裝置要連接的SDA腳位的「GPIO腳位編號」 (非實體編號!!)>,i2c_gpio_scl=<I2C裝置要連接的SDA腳位的「GPIO腳位編號」 (非實體編號!!)>```
2. 重新啟動raspi: ```sudo reboot -h now```
3. 此時下指令: ```sudo i2cdetect -y <bus號碼>```應可看到連接的I2C裝置
4. I2C裝置若以python程式```smbus.SMBus(<bus號碼>)```指定要溝通的bus號碼，則記得要設對

## HC-SR04超音波測距

### 規格

![image](https://hackmd.io/_uploads/H1jKUEeCa.png)

### 接法

![20240314_161940](https://hackmd.io/_uploads/H1K5QVxRp.jpg)

:::warning
因為echo的高電位為5V，而樹莓派最高輸入訊號只能為3.3V，故做分壓
:::

麵包版範例: 
![image](https://hackmd.io/_uploads/H17p7VeCa.png)

### 訊號說明

![image](https://hackmd.io/_uploads/BJMZLElCT.png)

### 範例程式

[HC-SR04測距](https://github.com/ktpss97094/EmbeddedSystemsCapstone/blob/main/HC_SR04/HC_SR04.py)


## MPU-9250 九軸 加速度(acc) 陀螺儀(gyro) 磁力計(mag)

:::info
由於使用I2C協定，使用前可先[安裝及使用相關工具](https://hackmd.io/k8AGFVaZQfKuNsTwuukuFQ#I2C%E7%9B%B8%E9%97%9C%E5%B7%A5%E5%85%B7)
:::

### 規格

![image](https://hackmd.io/_uploads/BkIkNSx06.png)

![image](https://hackmd.io/_uploads/SJYXP8lRT.png)

**xyz方向:**
![image](https://hackmd.io/_uploads/rkdetLg0T.png)

register:
![image](https://hackmd.io/_uploads/BkT8UU_C6.png)


### 接法 (只用到VCC、GND、SCL、SDA (I2C協定))

VCC接3.3V、GND接GND、SCL接GPIO3 (SCL1, I2C)、SDA接GPIO2 (SDA1、I2C)

### 範例程式

[讀取加速度、陀螺儀及磁力計的資料](https://github.com/ktpss97094/EmbeddedSystemsCapstone/blob/main/MPU9250/read9axis.py)

## HMC5883L 磁力計

:::info
由於使用I2C協定，使用前可先[安裝及使用相關工具](https://hackmd.io/k8AGFVaZQfKuNsTwuukuFQ#I2C%E7%9B%B8%E9%97%9C%E5%B7%A5%E5%85%B7)
:::

### 規格

**xyz方向:**
![image](https://hackmd.io/_uploads/SJIZf9Wy0.png)

register:
![image](https://hackmd.io/_uploads/BysjZc-yA.png)

### 接法 (只用到VCC、GND、SCL、SDA (I2C協定))

VCC接3.3V、GND接GND、SCL接GPIO3 (SCL1, I2C)、SDA接GPIO2 (SDA1、I2C)

### 範例程式

[讀取磁力計資料](https://github.com/ktpss97094/EmbeddedSystemsCapstone/blob/main/HMC5883L/magQ.py)

## PI Camera (相機模組)

### 接法

1. ```sudo poweroff```將樹莓派關機
2. 拉起相機卡隼，插入相機排線，推回卡隼

### 環境建置及範例程式

#### 1. picamera2

在這裡使用bookwarm版debian作範例，先[下載映象檔](https://hackmd.io/@hQYRchWRTgWcNUvP97mutg/SydHnN-lR#%E4%BD%9C%E6%A5%AD%E7%B3%BB%E7%B5%B1%E7%89%88%E6%9C%AC)，並[建置基本樹莓派環境](https://hackmd.io/k8AGFVaZQfKuNsTwuukuFQ#%E7%92%B0%E5%A2%83%E5%BB%BA%E7%BD%AE)，再[進一步建置環境](https://hackmd.io/@hQYRchWRTgWcNUvP97mutg/SydHnN-lR#%E3%80%8A%E4%BB%8A%E6%97%A5%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9A%E3%80%8B)及[安裝軟體](https://hackmd.io/@hQYRchWRTgWcNUvP97mutg/SydHnN-lR#%E3%80%8A%E4%BB%8A%E6%97%A5%E5%AE%89%E8%A3%9D%E8%BB%9F%E9%AB%94%E3%80%8B)

##### 範例程式

https://github.com/ktpss97094/EmbeddedSystemsCapstone/tree/bookwarmOS

:::danger
1. 需在mdp virtual environment中執行程式
2. OpenCV preview視窗及picamera2 preview視窗需在VNC遠端桌面開啟，否則會error
:::

#### 2. raspi指令

1. ```raspistill -n -t 3000 -o test.png -e png -w 640 -h 480```拍照 (3秒後拍照、編碼成png格式、長640x寬480、無預覽)
2. ```raspivid -n -t 500'0 -w 640 -h 480 -o video.h264```錄影 (錄5秒的1080p30影片、長640x寬480、無預覽)

## 麥克風&耳機及Speech相關

### 環境建置

安裝套件: 
```
pip install SpeechRecognition
pip install gTTS
sudo apt install libasound2-dev
sudo apt install python3-pyaudio
sudo apt install flac
```

測試: 
```
aplay -l  # 列出所有可以播放音訊的裝置
arecord -l  # 列出所有可以錄製音訊的裝置

# 錄製音訊
arecord -f cd [-d <秒數>] Filename.wav

# 播放音訊
1. aplay Filename.wav  # 使用內建播放功能，只能播放wav檔
2. sudo apt-get install sox libsox-fmt-all; play Filename.wav  # 使用第三方播放軟體
```

### 範例程式

:::info
有使用到[pyAudioAnalysis repository](https://github.com/tyiannak/pyAudioAnalysis)
```
git clone https://github.com/tyiannak/pyAudioAnalysis.git
cd pyAudioAnalysis
pip install -r ./requirements.txt
pip install -e .
```
:::

[播放音訊檔](https://github.com/ktpss97094/EmbeddedSystemsCapstone/blob/bullseyeOS/Speech/1_playwav.py)

[音訊檔案轉文字](https://github.com/ktpss97094/EmbeddedSystemsCapstone/blob/bullseyeOS/Speech/2.stt_file.py)

[麥克風語音轉文字](https://github.com/ktpss97094/EmbeddedSystemsCapstone/blob/bullseyeOS/Speech/2.stt_microphone.py)

:::warning
**音訊檔案轉文字 及 麥克風語音轉文字 程式**

若遇到```AttributeError: 'Recognizer' object has no attribute 'recognize_google'```則執行指令```pip install SpeechRecognition --upgrade```即可解決
:::

[文字轉語音檔案 (需連網)](https://github.com/ktpss97094/EmbeddedSystemsCapstone/blob/bullseyeOS/Speech/3.tts_online.py)

[文字轉語音檔案 (不需連網)](https://github.com/ktpss97094/EmbeddedSystemsCapstone/blob/bullseyeOS/Speech/3.tts_offline.py)

## AI相關

### 環境建置

安裝套件:
```
sudo apt install python3-opencv
pip install imutils
pip install dlib
```

### 範例程式

#### Face & Contour Detection

[偵測一張圖片的人臉]()

[偵測camera的人臉]()

[使用OpenCV套件偵測一張圖片的人臉並用dlib套件繪出輪廓]()

[使用dlib套件偵測一張圖片的人臉並繪出輪廓]()

#### Object Detection

##### 使用Tensorflow

:::info
有使用到[TensorFlow Lite Object Detection on Android and Raspberry Pi repository](https://github.com/EdjeElectronics/TensorFlow-Lite-Object-Detection-on-Android-and-Raspberry-Pi)

```
git clone https://github.com/EdjeElectronics/TensorFlow-Lite-Object-Detection-on-Android-and-Raspberry-Pi.git
mv TensorFlow-Lite-Object-Detection-on-Android-and-Raspberry-Pi tflite
cd tflite/
bash get_pi_requirements.sh
wget https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip
unzip coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip -d Sample_TFLite_model
```
:::

[使用Tensorflow做Object Detection (執行: python TFLite_detection_webcam.py --modeldir=Sample_TFLite_model)]()

##### 使用YOLO

:::info
環境建置:

```
wget https://github.com/KumaTea/pytorch-arm/releases/download/v1.8.1/torch-1.8.1-cp39-cp39-linux_armv7l.whl
wget https://github.com/KumaTea/pytorch-arm/releases/download/v1.8.1/torchvision-0.9.1-cp39-cp39-linux_armv7l.whl
pip install torch-1.8.1-cp39-cp39-linux_armv7l.whl
pip install torchvision-0.9.1-cp39-cp39-linux_armv7l.whl
pip install ultralytics
```

:::danger
:::spoiler error
如果在執行```pip install ultralytics```時遇到error:![2024-05-09_220350](https://hackmd.io/_uploads/BkxmZY89MC.png)

則依照[此網頁說明](https://raspberrypi-guide.github.io/programming/install-opencv)安裝opencv，其中執行```pip install opencv-python==<版本號>```時，版本號選擇前述error訊息中黃框處的版本在[opencv有release的詳細版本號](https://github.com/opencv/opencv-python/releases)
:::

## Cross Compile

### 使用64bit Linux cross compile 32bit Linux kernel module for Raspberry Pi 4

1. 如果是使用未使用的SD卡來做，則先依照[建置基本樹莓派環境](https://hackmd.io/k8AGFVaZQfKuNsTwuukuFQ#%E7%92%B0%E5%A2%83%E5%BB%BA%E7%BD%AE)安裝好OS，之後kernel module會基於此OS安裝在上面

1. 
   ```sh
    sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev  # 安裝dependencies
    sudo apt install crossbuild-essential-armhf  # 安裝32bit的toolchain
    git clone --depth=1 https://github.com/raspberrypi/linux  # 取得32bit Linux的kernel source code
    
    cd linux
    KERNEL=kernel7l  # 若要使用在Raspberry Pi 4，要把KERNEL設成「kernel7l」
   ```
2. 使用預設kernel config編譯或是自己設定config
   + 使用預設kernel config
     ```sh
     make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig  #  指定使用預設kernel config編譯
     ```
   + 自己設定config
     ```sh
     sudo apt install libncurses5-dev  # 安裝dependencies
     make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig  # 指定自己設定config
     
     # 進入選項視窗
     自己設定config，並存檔離開
     ```
3. 
   ```sh
   make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs  # 編譯
   
   # 編譯完後，arch/arm/boot路徑下即會有一「Image」檔案
   ```
  
    :::danger
    :::spoiler error
    若在編譯時遇到Error: 
    ```
    arm-linux-gnueabihf-ld: drivers/i2c/busses/i2c-designware-master.o: in function `i2c_dw_probe_master':
    i2c-designware-master.c:(.text+0x14d8): undefined reference to `__aeabi_uldivmod'
    arm-linux-gnueabihf-ld: i2c-designware-master.c:(.text+0x14fc): undefined reference to `__aeabi_uldivmod'
    arm-linux-gnueabihf-ld: i2c-designware-master.c:(.text+0x1528): undefined reference to `__aeabi_uldivmod'
    arm-linux-gnueabihf-ld: i2c-designware-master.c:(.text+0x1544): undefined reference to `__aeabi_uldivmod'
    make[2]: *** [scripts/Makefile.vmlinux:37: vmlinux] Error 1
    make[1]: *** [/home/ktpss97094/linux/Makefile:1165: vmlinux] Error 2
    make: *** [Makefile:234: __sub-make] Error 2
    ```
    原因為樹莓派為32bit環境，而```i2c-designware-master.c```程式內使用```/``` (除法operator)做64bit除法。解決方法為把drivers/i2c/busses/i2c-designware-master.c內的clock_calc()函式計算```high_cycles```、```extra_high_cycles```、```extra_low_cycles```、```period```的除法改成用div_u64(被除數, 除數)計算 (已經define好的64bit除法函式)
    :::

4. 插入SD卡讀卡機，放入SD卡，掛載SD卡。掛載完後輸入指令```df -h```會看到/dev/sd*1及/dev/sd*2有被掛載 (如下範例，掛載點路徑分別為/media/xd/boot及/media/xd/rootfs **(需記得，在下面步驟會用到)**)
   ![image](https://hackmd.io/_uploads/BkNC8FnQ0.png)

    :::info
    1. 若使用Virtual Box作為Linux且讀卡機為USB連接，則在裝置 -> USB選單內選擇電腦上插入的讀卡機 (例如: 
       ![image](https://hackmd.io/_uploads/H1Ap53TQR.png)
    )，此時虛擬機會自動掛載SD卡
    2. 若使用Virtual Box作為Linux且**SD卡讀卡機使用電腦內建讀卡機** (例如: 裝置管理員 -> 記憶體技術裝置內有「Realtek PCIE CardReader」 (非使用USB連接))，此時再Virtual Box裝置 -> USB會沒有此裝置! (因為非USB設備)
    :::

5. 在SD卡內安裝kernel modules
   ```sh
   sudo env PATH=$PATH make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PAH=<rootfs的掛載點路徑> modules_install
   ```
6. 複製剛剛編譯好的kernel image及device tree至SD卡
   ```sh
   sudo cp <boot的掛載點路徑>/$KERNEL.img <boot的掛載點路徑>/$KERNEL-backup.img   # 備份原本的kernel image
   sudo cp arch/arm/boot/zImage <boot的掛載點路徑>/$KERNEL.img  # 複製剛剛編譯好的kernel image至SD卡
   
   # 複製device tree至SD卡
   sudo cp arch/arm/boot/dts/broadcom/*.dtb <boot的掛載點路徑>/
   sudo cp arch/arm/boot/dts/overlays/*.dtb* <boot的掛載點路徑>/overlays/
   sudo cp arch/arm/boot/dts/overlays/README <boot的掛載點路徑>/overlays/
   ```
7. 編輯boot config並安全移除SD卡的掛載
   ```sh
   在<boot的掛載點路徑>/config.txt內新增一行: kernel=kernel7l.img
   
   # 移除SD卡的掛載
   sudo umount /dev/sd*1
   sudo umount /dev/sd*2
   ```
8. 將SD卡插入樹莓派並開機即完成
    :::info
    若要切換回原本的kernel，將上一步在config.txt新增的那行移除即可
    :::
    :::danger
    此kernel module沒有wireless介面，不能使用WiFi
    :::

### 使用64bit Linux cross compile C程式至32bit Raspberry Pi 4

1. 在64bit Linux上編譯程式並複製到Raspberry Pi
   ```sh
   arm-linux-gnueabihf-gcc hello.c -o hello.arm  # 編譯
   sudo cp hello.arm /media/xd/rootfs/home/pi/  # 複製
   ```
2. 在Raspberry Pi修改執行權限並執行
   ```sh
   chmod +x hello.arm  # 修改執行權限
   ./hello.arm  # 執行
   ```

## 其他範例程式

[外接LED閃爍](https://github.com/ktpss97094/EmbeddedSystemsCapstone/blob/main/LED/LED.py)