總網頁瀏覽量

顯示具有 KEIL 標籤的文章。 顯示所有文章
顯示具有 KEIL 標籤的文章。 顯示所有文章

2023年1月7日 星期六

近期接受韌體工程師學員的諮詢,各廠牌的嵌入式晶片/軟硬體平台都可諮詢合作!

近期接受韌體工程師學員的諮詢,以MCU大廠 瑞薩 ( Renesas ) 的 網路/多媒體產品類型的核心單元 ARM-Cortex Ax based系統晶片(System on Chip, SoC)/較大型的MCU 為實際解說目標範例。

連帶順帶介紹與討論到了Memory Mapped I/O、各式Boot Mode、linker script的一些相關觀念。


圖片來源: Renesas datasheet & website


圖片來源: Renesas datasheet & website

圖片來源: Renesas datasheet & website

本區接受工程師的顧問諮詢,可客製化諮詢內容針對工程師在自己的工作/公司中所使用的各家嵌入式系統晶片平台軟硬體作為諮詢/授課/教學目標。

瑞薩官網資訊: https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rz-mpus/rza2m-image-processing-rtos-mpu-drp-and-4mb-chip-ram


-----

個人簡歷: https://sites.google.com/view/wenliangsun/


‼本園區開設之技術課程進一步詳情請參見下方blog網頁的課程介紹👇:
本學習區之Facebook粉絲頁如下:

--------------------------

孫文良 (阿良的嵌入式系統技術學習區)

【若需要嵌入式系統技術輔導課程 可來信洽談合作方式: iws6645@gmail.com,亦可先點擊參考這篇介紹文章



2022年12月14日 星期三

【 嵌入式系統(Embedded System) 到底是什麼? 】

【 嵌入式系統(Embedded System) 到底是什麼? 】

關於這方面,許多台灣的大學學術界資深老師(無論名校或者非名校)、產業界資深主管/工程師,常會誤以為嵌入式系統就是指有嵌入Linux的系統,其實這是個明顯的認知錯誤。個人應該已經不只十次在企業職缺或者大學校院內的論文看到這個問題,直到今年(2022)我還是有在國內的研討會論文中看到這個錯誤。

這情況類似之前提過的微處理機/微控制器的名詞常被混用的狀況,而許多歐美的相關技術書籍對此名詞有較嚴謹的說明。如果大家很重視「學術」,那就應該要對這些名詞的基本定義有一定的嚴謹程度。

同時讓我們看一下 Wikipedia英文版頁面內容(較詳細)對於嵌入式系統(Embedded system)的基本定義[1]:  「An embedded system is a computer system—a combination of a computer processorcomputer memory, and input/output peripheral devices—that has a dedicated function within a larger mechanical or electronic system.  It is embedded as part of a complete device often including electrical or electronic hardware and mechanical parts. 

簡單來說,嵌入式系統就是被嵌入到電子/機械/機電硬體系統內、具備特定/專用功能的 計算機(電腦)系統。 這個「嵌入」並不是 在指Linux OS軟體被嵌入到一個系統。

就算是跑non-OS類型的軟韌體的MCU為核心的系統產品,基本上也都是嵌入式系統。並不是只有那些有跑(執行)嵌入式Linux或Android的系統才叫做嵌入式系統。

對於專業名詞定義認知落差,有時候就是造成工程開發過程中的溝通問題的來源。

Ref: 

[1] Wikipedia, Embedded system, https://en.wikipedia.org/wiki/Embedded_system .


-----

個人簡歷: https://sites.google.com/view/wenliangsun/


‼本園區開設之技術課程進一步詳情請參見下方blog網頁的課程介紹👇:
本學習區之Facebook粉絲頁如下:

--------------------------

孫文良 (阿良的嵌入式系統技術學習區)

【若需要嵌入式系統技術輔導課程 可來信洽談合作方式: iws6645@gmail.com,亦可先點擊參考這篇介紹文章

2021年9月4日 星期六

適合初學者的【嵌入式系統基礎原理與實務課程】

‼ 在此推廣一下 適合初學者的【嵌入式系統基礎原理與實務課程】‼

👉 本po文的影片內容為一個簡易的小範例,由8051 MCU GPIO之Output(輸出)驅動LED完成簡易跑馬燈功能。

影片內容包含從操作KEIL C51 IDE的免費評估版對程式碼進行編譯,並且藉由 ISP (In System Programming) 燒錄方式(便宜又好用) 對8051 MCU進行燒錄並觀察執行結果。


.

❓ 看完這篇po文的demo影片,或許有些學員會感到疑惑,這影片的跑馬燈功能,豈不是在學校課程裡面就看過/做過了? 這不是都很簡單嗎? 

 

不用擔心 🥸,其實這些表面上簡單的demo功能的背後,其實有著許多深入的學問和需要學習的基礎觀念,在業界做深入的技術問題時很可能會需要這些觀念,而許多大學學校課程不一定會詳細教背後詳細原理,也可能是學員過去從來沒有仔細思考過的較深入的基礎內容。

.

以這個po文的demo影片內容來舉例背後涵蓋的基礎內容,例如: 

👉 以8051實際實作範例說明低階語言 (組合語言,Assembly Language)與C語言(高階語言)的實際差異介紹

👉 介紹8051 指令集 (組合語言 其實即為對應指令集 的 助憶符號)

👉 MCU的原廠官方Datasheet技術手冊的基本閱讀能力

👉 MCU內部架構、GPIO架構原理(例如Port0的open drain是指什麼)、暫存器存取、記憶體組織架構

👉 MCU外部介面電子電路原理(與基礎,包含數位電路和類比電路及訊號的基本觀念)

👉 C語言的各種技巧與重點(包含8051基礎應用以外的平台的韌體開發常見內容和觀念),韌體程式流程追蹤與撰寫

👉 整合開發環境(IDE)操作

👉 ISP燒錄韌體之方式,以及燒錄器所對應軟體之操作 


上述內容在本學習區所開設的課程內容中都會詳細講述,

.

許多學校課程會講的內容,本課程當然會涵蓋到;而就連許多學校課程裡面沒講到的(詳細細節原理與實務開發經驗),在本課程內還是會學到。

.

註: 這門課的核心並不只是教你8051 Microcontroller,而是關於嵌入式系統(Embedded System)的軟硬體入門理論觀念與技術基礎,

同時也會補充許多「真正的計算機概論」的重要內容,不要懷疑,多數人不一定真的有理解過,包含: 

👉 何謂電腦?

👉 何謂嵌入式系統? 

👉 何謂跑non-OS及何謂有跑OS的電腦(計算機)系統

👉 何謂CPU? 何謂MCU(微控制器)? 何謂微處理機? 何謂SoC(系統晶片)? 

👉 產業相關職缺類別與實際可能的工作內容情況(講師分享自身的產業工作經驗與曾經輔導多位學員的經驗)

👉 以8051 MCU作為範例實作的目標教材,目標是希望學員能打下紮實的嵌入式系統基礎,課程內容中會有一系列的基礎實作教學

.


本園區之FB粉絲專頁如下:

--------------------

孫文良 (阿良的嵌入式系統技術學習區)

個人簡介: https://sites.google.com/view/wenliangsun/

【若需要嵌入式系統技術輔導課程 可來信洽談合作方式: iws6645@gmail.com,亦可先參考 課程招生網頁連結


2021年8月16日 星期一

【阿良的嵌入式系統技術學習區】STM32系列MCU韌體程式設計基礎實務 課程內容介紹

課程涵蓋內容如下:

  • 韌體程式常用程式語言
    • 組合語言指令集與MCU架構簡介
      • 以架構簡潔清晰的Intel MCS51指令集為教材範例
    • C語言基礎複習
    • 高階與低階語言(C語言 與 組合語言Assembly)差異介紹與實驗驗證

  • STM32 MCU常見開發環境操作教學
    • ARM KEILC 評估版 整合開發環境(IDE)操作教學
    • STM32CubeMX工具與STM32Cube IDE操作教學
    • 其它IDE簡介(如 IAR)

  • 中斷(Interrupt)機制
    • ARM Cortex-Mx系列搭配之NVIC (嵌套式向量中斷控制器)介紹
    • 中斷優先權實驗

  • 周邊裝置驅動原理與實作
    • GPIO(通用輸入/輸出介面)
      • GPIO架構與驅動原理
        • IO Port結構原理、Open-drain(開汲極)、Push-Pull output(推挽式輸出)、Pull-up、Pull-down等相關硬體電路原理
      • 外部簡易電路整合應用設計原理
      • 輸出驅動實驗(GPO, General Purpose Output)
      • 輸入驅動實驗(GPI, General Purpose Input)
    • Timer/Counter(計時器/計數器
      • 計時器
      • 計數器
      • 輪詢與中斷應用實驗
    • UART (通用非同步串列傳輸通訊介面
      • UART之協定原理
      • 輪詢與中斷應用實驗 (與其它具備UART介面之設備進行通訊實驗
      • RS232與RS485纜線介紹
        • 電氣位準轉換原理
        • 相關IC介紹
    • ADC(類比轉數位轉換器
      • 輪詢與中斷機制  搭配 亮度感測器 進行實驗
    • I²C串列通訊介面
    • SPI串列通訊介面
    • 其它各種周邊裝置、I/O介面或協定(PWM、1-wire、DAC、DMA...)

  • 基礎電子電路與元件應用
      • 類比電子電路 與 數位電子電路 基礎原理觀念
      • 基本電壓、電流量測
      • 二極體
      • 電晶體
        • 如: BJT開關應用、MOSFET (如level shift電路應用)
      • OPA(運算放大器)基本應用
      • 穩壓IC應用介紹
        • 光耦合IC
          • Relay繼電器驅動

        • 進階選修
          • GPIO進階應用之 矩陣多按鈕鍵盤 掃描輸入演算法
          • GPIO進階應用之 多合一七段顯示器 掃描輸出演算法
          • LCD顯示驅動
          • 各式無線通訊模組應用(藍牙、ZigBee、LoRa、Wifi等等)
          • 各式感測器應用(如: 溫度、溼度、三軸加速度感測器、陀螺儀、電流感測、pH酸鹼值、ORP氧化還原...等等)
          • 步進馬達驅動
          • 直流馬達驅動
          • 應用專題
            • 物聯網IoT (如 智慧家庭、智慧農業、自動化系統...)
            • 穿戴式裝置(慣性感測、生醫訊號處理應用...)


         


        2020年12月11日 星期五

        【STM32】【ARM 】ARM Cortex-M3 CPU bit-banding功能機制講解,以STM32F103之GPIO範例程式為例

        【若需要嵌入式系統技術輔導課程 可來信洽談合作方式: iws6645@gmail.com,亦可先點擊參考這篇介紹文章

        歡迎透過合法的方式分享此文內容,若要轉載/轉貼,請明確貼出此原始連結並標示作者基本資訊請勿抄襲及非法轉貼(例如擷取內文但並未註明出處)

        < 簡介 >

        這篇文章以市面上很流行的俗稱STM32F103C8T6 MCU最小系統開發板隨附的簡易GPIO驅動範例程式為例,因為這是一個淺顯的應用範例,所以適合寫成文章分享。相信許多初學者都曾以此範例來測試板子以及開發環境,但是許多人可能對於內容細節的方面沒有較深入的探討及了解,這邊會針對一些重點部分的細節做些說明

        (註: ARM Cortex-M3 CPU2004年就被推出了。而本文所講的ARM Cortex-M3 CPU basedSTM32F103這款MCU2007年推出,但至今現在市場上似乎還是供不應求)

        STM32F103C8T6 MCU最小系統開發板

        這個板子隨附的應用範例是個以MDK-ARM(KEILC)為開發環境的範例專案,我們這邊主要以編輯器將程式碼開起來並搭配官方硬體手冊資料來trace其流程和重點細節。專案裡面的主程式流程是屬於non-OS類的程式(沒有跑作業系統)

        觀察main.c的main function不難看出其主要應用流程(目的/功能),該流程是要驅動/控制STM32 MCUGPIO,以驅動開發板上面的LED,達到一般肉眼可見的亮/滅閃爍的功能。

        程式碼的註解是我加上去方便讀者觀看


        雖然它這個範例main function的回傳值型態寫int,然後其實沒有return,這方面不太標準

        這篇文章主要針對PCout()的內容原理進行詳細的追蹤與分析探討


        < 主要內容探討 >

        PCout()從表面上看起來是一支函式(function),但其實是個macro(巨集),內容在GPIOLIKE51.h這支檔案裡面,其主要內容為BIT_ADDR(GPIOC_ODR_Addr,n)


        (: C語言之中,巨集和一般函式各有其特性,須看場合挑選合適的方式來應用。若以相同使用量的狀況下來比較兩者,則簡單來說,前者相對較省執行時間但是較耗費儲存空間;而後者相對較省儲存空間但較耗費執行時間。使用量越多則各自的特性所帶來的結果和差異也越顯著)

        #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))

        #define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))

        #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))

        (volatile unsigned long  *)(addr)是將addr整數數值轉型為位址(address),以利存取(定址)記憶體空間或周邊裝置的暫存器(這屬於memory-map IO的方式去存取周邊,後面會說明)。而PCout()的狀況來說,addr就是會被代入GPIOC的暫存器(register)address(位址)數值,也就是0x4001100C

        --------------------------

        補充: 關於volatile關鍵字

        C語言中的volatile關鍵字用來提醒編譯器,避免編譯器過度最佳化的狀況在所修飾的變數上發生

        我們用GPIO input應用當例子來說明,如果GPIO外接一個按鈕,這個按鈕被按下的時機是由user按壓按鈕的狀況而定。所以,如果我們上面談到的這指標((volatile unsigned long  *)(addr))指向放置GPIO input digital signal的暫存器的位址,也就是將addr這個欄位代入正確對應的暫存器的位址,而該暫存器的內容()會隨user對按鈕的按壓狀況而改變(從單一bit來看就是10,下面再進一步解釋),所以這指標((volatile unsigned long  *)(addr))須使用volatile關鍵字修飾

        user對按鈕的按壓狀況而改變的狀況,以下面這個電路為例(截取自範例中的部分電路來說明),按鈕按下就是0(low level),沒按的就是1(high level)。當然可能有些按鈕的機械彈跳狀況須要透過軟體或硬體的方式去避免(debounce,因為不是這篇文章的重點,所以這部分就不在此贅述)

        按鈕電路

        再額外補充一個指標指向I/O周邊時可能會使用到volatile關鍵字的例子,特別是在嵌入式系統上面常見到的狀況。

        ADC(Analog to Digital Converter)轉換由感測器輸出的類比訊號進而轉換為數位訊號(數位值)之後,依照現在許多ADC的設計,這個數位值通常會被硬體自動放置在某個暫存器(舉個別款MCU的例子,例如Arduino uno/nano/mini/fio等板子上面的Atmega328這顆同樣有內含ADCMCU的狀況,這個數位值就會被放在ADC Result Registers,因為是轉成10bits的數位值,所以因為一個byte長度的暫存器放不下,所以就放在兩個暫存器內,ADCH的和ADCL),而這個暫存器內的數位值就會因為感測器感測的環境變化而跟著改變),現在為了方便說明,我們假設這個暫存器只有一個,而我們宣告一個指標變數指向這個暫存器,那這個指標變數在宣告時通常也須要加上volatile關鍵字以防止編譯器做了過度的最佳化導致非預期的後果(告知編譯器,在程式裡面指定要讀取的時候就真的是須要從ADCregister(暫存器)去讀值,不可因優化而簡化掉)

        所以addr被轉型為unsigned long的address(為了對硬體做存取),也須用volatile關鍵字修飾,以避免非預期的狀況發生

        --------------------------

        補充: 關於memory-map I/O port-mapped I/O

        STM32F103 MCU內的ARM Cortex-M3 CPU是使用memory-map I/O的方式[4][5],簡單來說也就是CPU透過nativeload/store指令去存取記憶體(SRAM空間)與周邊裝置(GPIOUARTI2CSPIADC…等等,更嚴格精確來說就是存取這些周邊裝置的控制或讀取相關功能的暫存器),如同將這些周邊裝置的暫存器當成記憶體空間來存取。至今ARM Cortex-M系列CPU應該都是屬於使用memory-map I/O的方式去存取周邊(有沒有特殊的例外不清楚)

        另一種出現在其它平台(x86)的方式為port-mapped I/O,可以讓I/O周邊和記憶體空間獨立區分開來,也就是表面上同一個address號碼,可以是存取記憶體空間的address,也可以是存取周邊裝置暫存器的address,雖然表面上是同一個address位址數字號碼,但是在兩邊是獨立不同的實體硬體空間。而既然要獨立區分兩種空間這種port-mapped I/O方式要使用特定的CPU指令去存取I/O周邊(而不是一般的load/store指令),而以CPU架構設計的角度,設計這些特定的CPU指令就要耗費相對的電晶體資源。

        --------------------------


        回到主題,多了一個'*'字號的 *((volatile unsigned long  *)(addr)) 的意思就是這個指標所指向的位址的硬體(記憶體或暫存器)的內容值(以這邊的例子來說就是GPIO暫存器的內容值)。多嘮叨補充一下,這內容值以實際硬體的角度來看,其實就是數位訊號。

        所以綜上所述,如果有仔細理解上述內容的讀者應該可以得知為何我們在main function之中去寫PCout(13)=1就得以直接驅動GPIO輸出high level(邏輯1)的數位訊號。因為在上述巨集的實作方面,就已經讓PCout(13)=1直接對應存取GPIO之對應暫存器的內容值

        #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))這個BITBAND(addr, bitnum)這個macro的功能/目的就是要將addr和bitnum轉化對應到正確的暫存器位址並且可以atomic operation完成對暫存器的存取(後續會說明),可先參考這支GPIOLIKE51.h:

        #define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C

        我們可以從STSTM32F103x8 Datasheet[1]memory map以及RM0008 Reference manual[2]GPIO registers的說明內容得知,0x4001100C是這顆STM32 MCUGPIOCODR(Output Data Register)暫存器的位址,並且可在STM32F10x_StdPeriph_Driver之中的stm32f10x.h裡看到對應的GPIOC_BASEAPB2PERIPH_BASE#define值。

        Ref:[1]

        Ref:[2]

        而一大串的((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))主要是為了能正確存取Bit-banding功能方面的alias region的位址,這邊先針對Bit-banding功能機制作些說明。

        Bit-bandingSTM32F103 MCU內的ARM Cortex-M3 CPU的一種功能特性(ARM Cortex-M系列的其他款式CPU應該也有,詳情請參照對應的ARM官方手冊確認),當CPU(執行我們寫的程式碼)alias region之中的word做存取(STM32word長度是32bits),就會對應存取到bit-band regionSRAM記憶體空間 周邊裝置暫存器的某個對應的bit,如下ARM Cortex-M3 Technical Reference Manual官方手冊[3]的圖所示(這個圖是以存取SRAM空間為例)。而在這個STM32F103C8小板子的範例程式之中就是要存取GPIOC_ODR暫存器的bit13


        Ref:[3]

        STM32F103 MCU的規劃(搭配ARM Cortex-M3功能特性),在SRAMPeripheral的方面都有這種Bit-banding機制/功能各有1MBbit-band region範圍,如下方的ARM Cortex-M3 Technical Reference Manual[3]的System address map圖。而因為alias region的一個word對應bit-band region1bit,一個word長度是32bits,所以對應的存取設定區域也就是的alias region的長度範圍為32MB(SRAMPeripheral各有32MBalias region對應各自的1MBbit-band region)

        (提醒:前述已有提到ARM Cortex-M系列CPU basedSTM32 MCU是以memory-map I/O式的方式去存取Peripheral周邊裝置)

        Ref:[3]


        在寫入的方面,對
        alias regionword寫入0x01或者0xff(其實就是必須針對對應的wordbit0寫入1)都會讓bit-band region的對應bitset1,另外這個寫的過程其實會被轉換成atomic(操作過程不會被打斷)
        read-modify-write operation
        ;而在讀取的方面,將會從alias region所讀到的wordbit0讀回所要讀取的bit-band regionbitstatus(1 or 0)

        Bit-Banding機制/功能的優點就是讓CPU能透過使用一般的Load/Store指令即可完成bit的讀/寫,這和過往只能先透過執行read(load相關指令)、modify(通常是邏輯運算相關指令)、write(store相關指令)流程的一連串相關獨立指令來完成bit讀/寫的傳統方式不同。所以Bit-Banding機制/功能也有助於節省code size

        另外官方手冊[2]也有提到CPU在進行bit-band operations時,除了特殊狀況之外,基本上是不會停頓(stall)

        對於BITBAND這個macroARM官方的Cortex-M3 Technical Reference Manual[3]有直接給出公式如下,本文的後續內容也會針對這些公式內容的由來進行詳細解說

        Ref:[3](紅色框起的是我認為命名不直覺的部分)

        回頭來看我們範例程式內的macro,前面內容提過addr0x4001100C

        關於#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))之中的(addr & 0xF0000000):

        0x4001100C(addr)0xF0000000AND運算的目的是為了取出/取得結果為0x40000000也就是peripheral的起始位址或稱peripheral base address(由上面官方手冊內的Ref:[1]memory map圖可得知)

        接下來的+0x2000000(加上0x2000000)之目的就是為了得到我們peripheralalias regionstarting address,也就是公式中的bit_band_base(Cortex-M3 Technical Reference Manual官方手冊[3]裡面的內容: bit_band_base is the starting address of the alias region.),也就是0x42000000

        ARM Cortex-M3官方手冊[3]這個公式裡面的bit_band_base我認為在命名的方面有些不直覺的問題(因為會讓人導致誤解以為是bit-band regionstarting address,但其實是alias regionstarting address)。所以我認為應該要將公式內的此項目名稱改叫作bit_band_alias_base或者alias_base才對,畢竟是alias regionstarting address!才剛想完,我就上網google搜尋了一下,在加拿大有間大學Ryerson University的電機與電腦工程系2019年開設的Embedded System Design課程[7]Lab 2: Exploring Cortex-M3 Features for Performance Efficiency講義內容[6]就真的在他們的講義內將bit_band_base改以Bit Band Alias Base Address表示,如下圖:

        Ref:[6]


        :其實0x2000000就是十進制的33,554,432,也就是32M(32*1024*1024)alias region的起始位址就是bit-band region起始位址加上32M之後的address

        ((addr &0xFFFFF)<<5)+(bitnum<<2)也就是bit_word_offset也就是(byte_offset x 32) + (bit_number × 4)。其中(addr &0xFFFFF)取出0x0001100C0x1100CGPIOC_ODR暫存器的offset位址偏移量,左移5位等於乘以32(公式中的*32),等於0x220180

        (如果不想了解上面公式原理的讀者可直接參照公式,跳過這個註解): 為何要左移5(等同乘以32)?細心的讀者如果搭配上面內容的Ref:[3]的官方例圖來觀察就應該可以發現,因為每一個word32 bits也就是4bytes也就是會占掉4address號碼(每一個byte的資料會對應存放於一個address,這是電腦的基本rulebyte-addressable。暫存器和其位址的對應也是一樣),而alias region的一個word是對應到bit-band region的一個bit,換句話說,在bit-band region差了1bit就等同在alias region差了4address號碼的距離(1word)的位址距離。而如果是在bit-band region差了1byte(8bits)的位址距離,就等同在alias region差了32address號碼(8word)的位址距離(8*4=32),但這只能知道這個長度為32bitsGPIOC_ODR暫存器的位址(bit-band region)對應到alias region的一段空間的32word的開頭的位址(對應暫存器的32個位元,一個位元對應一個word)

        但實際上我們所希望存取的暫存器的bit,是哪個word(其位於alias region的位址到底是哪個),就還要加上bitnum*4也就是bitnum<<2 (左移兩位),例如如果我們想存取暫存器的bit00*4=0,代表的就是該word就是從上述alias region的一段空間的32word(包含128個位址)的開頭的位址(對應暫存器的32個位元)的開頭(+0)的這個word去存取;如果是想存取暫存器的bit11*4=4,代表的就是該word就是從上述alias region的一段空間的32word(對應暫存器的32個位元)的開頭的位址去加上4(+4)的這個位址(這個word)去存取,所以到此也已經說明為何macro內容的最後要加上(bitnum<<2)。而在我們這個範例的例子中就是bitnum13,故bitnum<<2(乘以4)的結果就是52(十六進制的0x34)

        (2020/12/13更正,原先我誤將13<<2的結果看成24,其實是十進制的52,也就是十六進制的0x34)

        所以最後我們將公式內的各項結果相加: 0x42000000 + 0x220180 + 0x34 = 0x422201B4

        這個0x422201B4就是GPIOC_ODR暫存器的bit13alias region所對應的word的位址

        上面關於bit-banding的這部分比較複雜,初學者可能要多花點耐心才比較能看懂。如果想進一步閱讀關於Bit-banding功能機制(alias regionbit-band region)的官方說明資料,可參考ARM官方的Cortex-M3 Technical Reference Manual[3]或者STRM0008 Reference manual[2]3.3.2章節。或者如果有對上述內容不清楚的朋友,我的課程內容(未來預計將會陸續開設STM32 MCU應用開發實務基礎的相關課程)會有相關的引導。

        另外,我手上的範例程式中的stm32f10x.h中的某些巨集的註解將alias regionbit-band region給寫反了,看日期得知這應該是2010年code

        範例程式專案中的stm32f10x.h有錯誤的部分


        < 結語 >

        雖然這篇文章是用一個淺顯的應用範例(控制GPIO以驅動LED閃爍)來作為說明對象,寫這篇文章的用意有二: 

        (一) 為協助初學者與有興趣了解相關專業內容的人

        (二) 希望讓一些習慣看技術表面的族群不要只看到表面,雖然這只是個LED閃爍的範例,但內容包含的學問可不少,光是看了上面的細節內容我想就可以讓更多人理解,工程實務不是簡單的事情,不要以為驅動GPIO沒什麼。如果覺得簡單,通常是有以下兩個原因

        (1)只看到表面功能,只看到東西功能會動即滿足,但沒有去思考這背後要作多少事情及其原理,才會有眼下的這個應用功能

        (2)因為用的是現成的東西,有人幫你做好太多事情,如果都要自己從頭來,恐怕沒幾個人有能力在短時間內做好,因為這絕對不是call現成的APIOK的事

        何況這文章的內容這還只是這範例專案中一個部分而已,事實上如果要細說細節真的講不完,例如booting flow、進入main()之前還有一系列的初始流程(如將stack初始化)、clock init、GPIO init等等,只是太多東西都是廠家在事先所做好的(前人的累積)。

        我想還是希望能藉由這類文章,讓一些比較少親自動手或長年來基本上沒從事過開發的族群,特別像是多數的資深專任大學老師或者已經很久沒動手的公司高層大咖們了解實際真實的工程實務的難度和重要性。


        如果因為對於這些內容的本質不夠深入了解,可能會有些誤解,例如誤以為什麼這些範例程式的寫法過時了。而其實基本上根本就沒有這個問題,原因如下:

        1. 除了本文所探討的bit-banding方式,以及傳統的直接對GPIO_ODR暫存器做讀(read)-(modify)-(write)的存取之外,STM32F103 MCU存取GPIO_ODR暫存器確實也其它方式。例如去設定GPIOx_BSRR對應GPIOx_ODRbit set/clear(而另一個暫存器GPIOx_BRR只能做clear),但是也是只能一次寫32bits也就是一個word(設定GPIO_BSRRGPIO_BRR)去對應控制GPIOx_ODR的狀態(按照[2]針對GPIOx_BSRR的說明所述的:These bits are write-only and can be accessed in Word mode only)

        上述這使用GPIOx_BSRR的例子,和本文所探討的bit-banding是不同的方式,而且bit-banding機制不是只有針對周邊裝置,還可以針對SRAM空間做存取,SRAM有什麼BSRR可用嗎?何況bit-banding本來就也是一種ARM Cortex-M3 CPU所提供的方式/機制,讓開發者可以獨立去set/clear registerSRAM的單一bit。這機制有它合適的應用場合,只要不是被官方公開宣稱其功能必須被完全取代的狀況下,機制/方法的選擇沒有什麼絕對的優劣好壞之分,只有開發者自己會不會用的問題,而沒有什麼過時不過時的問題,畢竟這顆MCU的硬體特性/功能提供的選擇就是如此(就是有這些方式),既然這個功能特性仍存在,那就不會失去探討的意義

        如前面提到的,ARM Cortex-M3 CPU2004年就被推出了。而本文所講的ARM Cortex-M3 CPU basedSTM32F103這款MCU是在2007年被推出的,但至今現在市場上似乎還是供不應求。

        另外,bit-banding功能機制在ARM Cortex-M4 CPU是個optional feature [8]。

        2. 有用的知識就是有用(有核心重點知識/觀念上的通用性和可延伸性),例如C語言就是C語言,C語言已經被用了好幾十年了,C語言的指標也被用了好幾十年了,暫存器的觀念也好幾十年了,所以這和過時不過時有何相關如前所述,只有開發者自己會不會用的問題,而沒有什麼過時不過時的問題。

         

        < 參考資料 >

        Ref:

        [1] STM32F103x8 STM32F103xB Datasheet - production data, https://www.st.com/resource/en/datasheet/cd00161566.pdf

        [2] ST RM0008 Reference manual - STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced Arm®-based 32-bit MCUs, https://www.st.com/resource/en/reference_manual/cd00171190-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf

        [3] ARM Cortex-M3 Technical Reference Manual, https://developer.arm.com/documentation/ddi0337/h/programmers-model/bit-banding?fbclid=IwAR1OuCvOHza3oUnJK68PiIX9ytKBJhsTwatgI6Jg_zF6D9GfMZVvTmesI5o

        [4] Memory-mapped I/O, https://en.wikipedia.org/wiki/Memory-mapped_I/O

        [5] Lecture 5: Memory Mapped I/O, https://www.youtube.com/watch?v=aT5XMOrid7Y

        [6] Ryerson University Dept. of Electrical and Computer Engineering - Embedded System Design course - Lab 2: Exploring Cortex-M3 Features for Performance Efficiency, https://www.ee.ryerson.ca/~courses/coe718/labs/Lab2.pdf

        [7] Ryerson University Dept. of Electrical and Computer Engineering - Embedded System Design course, https://www.ee.ryerson.ca/~courses/coe718/

        [8] ARM Cortex-M4 Processor Technical Reference Manual, https://developer.arm.com/documentation/100166/0001


        --------------------------

        孫文良 (阿良的嵌入式系統技術學習區)

        【若需要嵌入式系統技術輔導課程 可來信洽談合作方式: iws6645@gmail.com,亦可先點擊參考這篇介紹文章