--- tags: MCU --- # ARM Cortex-M slide: https://hackmd.io/@SquirrelPanda/r1lT9LkQ_ {%hackmd ryr9Ug6sd %} --- > 本篇紀錄以 ARM Cortex-M0 及公司 firmware source code 用到的為主. > [name=Nick Xiao] [time=Feb, 2021] [color=#907bf7] ## NVIC (Nested vectored interrupt controller) ## CMSIS ![](https://i.imgur.com/yfyUoKS.png) ## 中斷 - 啟用/關閉中斷 ``` 中斷寄存器是可編程的,用於控制中斷請求(異常編號16以上)的使能(SETENA)和禁止(CLRENA) ``` ```c= void NVIC_EnableIRQ(IRQn_Type_IRQn); //使能中斷#IRQn; void NVIC_DisableIRQ(IRQn_Type_IRQn); //禁止中斷#IRQn; ``` - 中斷掛起和清除掛起: ``` 可以通過操作中斷掛起(SETPEND)和清除掛起(CLRPEND),這兩個寄存器來訪問和修改中斷掛起狀態。 ``` ```c= void NVIC_SetPendingIRQ(IRQn_Type_IRQn) ; //設置一個中斷掛起 void NVIC_ClearPendingIRQ(IRQn_Type_IRQn); //清除中斷掛起 void NVIC_GetPendingIRQ(IRQn_Type_IRQn) ; //讀取中斷掛起狀態 ``` - 中斷優先級:(0xE000E400~0xE000E41C) ``` 1. 每個外部中斷都有一個對應的中斷有先級寄存器,每個優先級都是只有一個字節且只有最高2Bit有效 2. NVIC支持字傳輸,所以每次訪問都會涉及4個中斷優先級寄存器。 ``` ```c= void NVIC_SetPriority(IRQn_Type_IRQn, uint32_t priority) ; //設置中斷優先級 uint32_t NVIC_GetPriority(IRQn_Type_IRQn); //讀取中斷優先級 void NVIC_SetPriority(2, 3) ; //設置#2中斷的優先級為0xC0 ``` :::info 這裡的priority是0,1,2,3.函數內部會自動移位到對應的優先級最高2位: ::: - 異常屏蔽寄存器(PRIMASK) ``` 1.對時間敏感的應用,需要用PRIMASK來屏蔽掉除NMI和硬件錯誤異常以外的其他所有中斷和異常。 2.PRIMASK只有1Bit有效,默認為0,為1時起屏蔽作用。 ``` ```c= void _enable_irq(void) ; //清除PRIMASK值 void _disable_irq(void) ; //設置PRIMASK值 ``` ## Compiler-specific Features 官方文件[^ref1]中條列了許多編譯器支援的功能, 除了大多編譯器都支援的功能以外, 也包含ARM對C/C++的延伸功能, 下面將列出我認為重要或者在爬程式碼時看到的部分 ### Stack use in C and C++ 參考章節[^ref2] ### Variable attribute ``` __attribute__ ``` 在GNU或是ARM編譯器都有支援, 不過不同 *attribute* 的實作可能有異, 甚至有部分是 ARM 編譯器才有支援, 詳細請查看官方文件. - ``` __attribute__((at(address))) ``` : - 用於指定絕對位址, 也等同於輸出 firmware BIN檔中的位址. - 實例: ```c= typedef struct _FW_VERSION_INFO { uint16_t minor_version; uint16_t major_version; } FW_VERSION_INFO; const FW_VERSION_INFO fw_version __attribute__((at(0x1000))) = { .minor_version = 0x2330, // 30 23 .major_version = 119, // 77 00 }; ``` 設定 firmware 版號, 並指定在 0x1000 的位址. - 結果: 可以發現輸出的 firmware BIN 檔在 0x1000 的地方為所設的值 ![](https://hackmd.io/_uploads/SJ2AcUJQ_.png) 另外, 如果去查看 map 檔的話也能看到 .ARM.__AT 的字樣 ![](https://hackmd.io/_uploads/rkmkjLkXO.png) - ``` __attribute__((aligned)) ``` : - 用於對該變數或結構進行最小單位(byte)對齊 - 實例: ```c= void testFunc() { struct test { uint8_t a __attribute__((aligned (8))); uint16_t b __attribute__((aligned (8))); uint32_t c __attribute__((aligned (8))); }; struct test test1; DPRINTF("size of uint8_t a = %d\n", sizeof(test1.a)); DPRINTF("size of uint16_t b = %d\n", sizeof(test1.b)); DPRINTF("size of uint32_t c = %d\n", sizeof(test1.c)); DPRINTF("size of struct test = %d\n", sizeof(test1)); } ``` 宣告一個成員記憶體大小不同的 structure, 並印出成員及 structure 本身的記憶體大小 - 結果: ``` size of uint8_t a = 1 size of uint16_t b = 2 size of uint32_t c = 4 size of struct test = 24 ``` :::info 如果仔細看官方文件會發現 $__attribute__((aligned))$ 有分 type attribute 以及 variable attribute, 我的理解是, 除了針對"變數"以外對於 struct 這類"型別"的也適用. ::: - ``` __attribute__((section("name"))) ``` : 將該函數/變數放入指定的區段 ## 參考資料 http://mcu.eetrend.com/content/2016/100002783.html https://www.cnblogs.com/ollie-lin/p/10934604.html [^ref1]: [Arm KEIL - Compiler User Guide](https://www.keil.com/support/man/docs/armcc/armcc_chr1359124965789.htm) [^ref2]: [Arm KEIL - Stack use in C and C++](https://www.keil.com/support/man/docs/armcc/armcc_chr1359124223721.htm)