---
# System prepended metadata

title: Lab 0
tags: [NCTU, MPSL]

---

# Lab 0

###### tags: `MPSL` `NCTU`

這次 lab 主要就是熟悉整個開發環境。
> 實驗 Report 主要紀錄自己實驗的過程，或是有甚麼想分享的經驗，也不需要**硬寫很多**。
> 把實驗 Report 當作是自己上過這門課的 footprint。
> 繳交方式為 pdf 或網址 (HackMD, Dropbox Paper...)
> 

## 建立開發環境

 * 使用 eclipse based STM32 IDE tool 做為開發工具。
 * 開發環境為 win10，可以由[官網](https://www.openstm32.org/Downloading+the+System+Workbench+for+STM32+installer)的[下載連結](http://www.ac6-tools.com/downloads/SW4STM32/install_sw4stm32_win_64bits-latest.exe)獲取安裝包。
     * 基本上按照流程就會完成所有的安裝，包括 ST-Link driver。
     * 安裝地點預設為：C:\Ac6\SystemWorkbench
 * 安裝完成後，即可點擊 **System Workbench for STM32** 開始寫第一份 code。
 * 這裡創了一個 MCSL (C:\Users\ieros\MCSL) 作為之後 lab 的 workspace，第一次開啟時，會自動安裝 arm 的 toolchain。
 * File -> New -> Other，選擇 C Project
     * ![](https://i.imgur.com/X6eVtPs.png)
 * 設定好新的 Project name，並選擇 Ac6 STM32 MCU Project 作為我們的 Project Type
     * ![](https://i.imgur.com/K32fJml.png)
 * 這裡預設就會把 Debug 打開。
     * ![](https://i.imgur.com/5nSgSJx.png)
 * 板子一定要選擇硬體對應的編號，才能在之後燒錄時，將程式放到記憶體中正確的位置。以我們的的板子來說，就要選擇 STM32L4 和 NUCLEO-L476RG。
     * ![](https://i.imgur.com/QJYDwl8.png)

## 第一支程式

 * File -> New -> Source File
     * Source file: main.s
 * Code
```cpp=
    .syntax unified
    .cpu cortex-m4
    .thumb
.text
.global main
.equ AA, 0x5566

main:
    movs r0, #AA
    movs r1, #20
    adds r2, r0, r1
L: B L
```
 * Project -> Build All
     * 這裡發生編譯問題，問題出在 ```movs r0, #AA```，但如果將 ```.equ AA, 0x5566``` 改成 ```.equ AA, 0x1100``` 就會成功了！
     * ![](https://i.imgur.com/RnFEqsb.png)
 * Run -> Run 即可在硬體執行程式。

### Debug

 * Run -> Debug 可以透過 IDE 進行 Debug，並觀察硬體上每個 Register 的變化。
     * 按下 Debug 之後，可以按 F5 進行單步執行，或是按兩下 F8 執行全部。
     * 觀察 Register 變化前，必須先按下暫停。在右上方的視窗中，我們可以看到 r0 已經變成 0x1100 了！
     * ![](https://i.imgur.com/u8WyECw.png)
 * Object Dump 可以協助我們瀏覽程式的 symbol table。
     * Run -> External Tools -> External Tools Configuration
     * New launch configuration
         * ![](https://i.imgur.com/rAjLzQ7.png)

## 第二支程式

 * Code
```cpp=
	.syntax unified
	.cpu cortex-m4
	.thumb
.data
	X: .word 100
	Y: .asciz "Hello World!"
.text
.global main
.equ AA, 0x55

main:
	ldr r1, =X
	ldr r0, [r1]
	movs r2, #AA
	adds r2, r2, r0
	str r2, [r1]
	ldr r1, =Y
	ldr r2, [r1]
L: B L
```
 * 這隻程式在 data section 的部分宣告了 X 與 Y 兩個變數。
 * 主程式的部分
     1. 先透過 ldr 將 X 的記憶體位置讀進 r1
         * 可以從右上角的 Register 看到，r1 的值為 0x20000000。
         * ![](https://i.imgur.com/RTqNTY2.png)
         * 透過下方的 Memory monitors，0x20000000 位置的值為 0x64，也就是 100。
         * ![](https://i.imgur.com/rwSCam5.png)
         > 每個記憶體位置都是一個 8 bits (1 byte) 的資料空間，
         > 因為宣告時是給 X 一個 word (4 bytes) 的大小 (從 0x20000000 到 0x20000004)，因此 Y 是從記憶體位置 0x20000004 開始放。
         * 也可以透過 New Renderings 來新增一個以 Signed Integer 為表示方式的 Monitor
         * ![](https://i.imgur.com/jxOFDHO.png)
     2. 將 r1 中記憶體位置的資料透過 ldr 讀進 r0
         * 這時候，r0 的值就會變成 100 了。
     3. 接下來兩行作了一個加法的運算，並將結果存在 r2 中，r2 為 185。
     * 再透過 str 將 r2 的值存進 r1 所記錄的記憶體位置之中
         * 此時 0x20000000 的值變為 185 了。
         * ![](https://i.imgur.com/1FAT5oi.png)
     4. 最後再將 Y 的值透過一樣的方式，存進 r2 中。
         * 我們也可以透過 memory monitor 看到，0x20000004 到 0x20000010 之間，存了 12 個 bytes。
         * ![](https://i.imgur.com/gPsCmfz.png)

## 第三支程式

 * 簡單的四則運算，並將計算結果存回記憶體之中。
 * Code
```cpp=
	.syntax unified
	.cpu cortex-m4
	.thumb
.data
	X: .word 5
	Y: .word 10
	Z: .word 0
.text
.global main

main:
	ldr r0, =X
	ldr r1, =Y
	ldr r2, =Z
	ldr r3, [r0]
	ldr r4, [r1]
	ldr r5, [r2]
	movs r6, #10
	muls r3, r3, r6  // X = X * 10
	adds r3, r3, r4  // X = X + Y
	subs r5, r4, r3  // Z = Y - X
	str r5, [r2]
L: B L
```
 * 執行結果
     * ![](https://i.imgur.com/tp51j5K.png)

## startup_stm32.s 與 LinkerScript.ld

 * 在 LinkerScript.ld 中定義了 entry point 為 Reset_Handler
     ```cpp=
     /* Entry Point */
    ENTRY(Reset_Handler)
    ```
 * 因此每次系統啟動時，都會透過 Reset_Handler 來對 data section 作初始化，從 flash 將資料搬進 SRAM 之中，並且對 bss section 作填零的動作。
     ```cpp=
    Reset_Handler:
        ldr   r0, =_estack
        mov   sp, r0          /* set stack pointer */

    /* Copy the data segment initializers from flash to SRAM */
        ldr r0, =_sdata
        ldr r1, =_edata
        ldr r2, =_sidata
        movs r3, #0
        b LoopCopyDataInit

    CopyDataInit:
        ldr r4, [r2, r3]
        str r4, [r0, r3]
        adds r3, r3, #4

    LoopCopyDataInit:
        adds r4, r0, r3
        cmp r4, r1
        bcc CopyDataInit

    /* Zero fill the bss segment. */
        ldr r2, =_sbss
        ldr r4, =_ebss
        movs r3, #0
        b LoopFillZerobss

    FillZerobss:
        str  r3, [r2]
        adds r2, r2, #4

    LoopFillZerobss:
        cmp r2, r4
        bcc FillZerobss
     ```
 * 最後再跳到 main 開始執行我們所寫的 code
     ```cpp=
     /* Call the application's entry point.*/
    bl main
     ```
 * 以第三個程式為例，由 Symbol Table 可以看到，X、Y 與 Z 會先被放在 data section 位置。
     * ![](https://i.imgur.com/tKZRVU1.png)
 * 接著開始執行 startup 後，再將資料從 flash 搬進 SRAM 之中。
     * ![](https://i.imgur.com/7bMg0dT.png)

## data section 與 text section

 * 最明顯的差異在於，data section 是可讀可寫的，而 text section 只可以讀不可以寫
 * text section 是儲存在 Rom 之中，而 data section 則是放在 Ram。
     * 紀錄在 linker script 之中
    ```cpp=
    /* Memories definition */
    MEMORY
    {
        RAM (xrw)		: ORIGIN = 0x20000000, LENGTH = 96K
        ROM (rx)		: ORIGIN = 0x8000000, LENGTH = 1024K
    }
    ```
    ```cpp=
    /* The program code and other data into ROM memory */
    .text :
    {
        . = ALIGN(8);
        *(.text)           /* .text sections (code) */
        *(.text*)          /* .text* sections (code) */
        *(.glue_7)         /* glue arm to thumb code */
        *(.glue_7t)        /* glue thumb to arm code */
        *(.eh_frame)

        KEEP (*(.init))
        KEEP (*(.fini))

        . = ALIGN(8);
        _etext = .;        /* define a global symbols at end of code */
      } >ROM
    ```
    ```cpp=
    /* Initialized data sections into RAM memory */
    .data : 
    {
        . = ALIGN(8);
        _sdata = .;        /* create a global symbol at data start */
        *(.data)           /* .data sections */
        *(.data*)          /* .data* sections */

        . = ALIGN(8);
        _edata = .;        /* define a global symbol at data end */
    } >RAM AT> ROM
    ```
 * 如果將 X 改宣告在 .text 之下，可以發現，X 的位置變成了 0x80001c8，這個位置是在 text section，並且執行到最後可以發現，0x80001c8 位置的值並不會因為 ldr 將 185 存回去而被改變。

## Little Endian

 * 可以觀察 ```Y: .asciz "Hello World!"``` 是怎麼被放入記憶體的：
     * 在 Register 中我們可以看到，r2 的值是 0x6c6c6548，也就是 ASCII 的 "lleH"，然而如果用 Hex 模式去看 memory monitor，可以發現 0x20000004 位置中的值為 0x48656C6C。
     * 這是因為 memory 是 Little Endian 系統，因此最低位元組會被擺在 memory 位址的最低位 (最左邊)，而最高位元組則被放在 memory 位址的最高位 (最右邊)。
     * ![](https://i.imgur.com/q6pPIZV.png)
     > 根據 ARM Cortex L4 technical reference manual，ARM 架構其實是支援 big/little endian，但意法半導體選擇使用 little endian。

## 字串的宣告方法

 * .asciz
     * 會自動的結尾補 '\0'
 * .ascii
     * 不會在結尾補 null byte