RTOS - Jserv IoT 作業系統 - 前置學習 - vector table - hard fault handler


收錄於 : 關於Ameba的一百篇
前篇: Ameba assembly-2


剛好 Jserv 要來打造一套 cortex-M3 上的 IoT 作業系統.
這邊 RTOS 介紹來跟著這個進度前進.

--- Jserv 的 議程介紹

從無到有打造 IoT 作業系統
https://www.facebook.com/events/645044348986795/








"[Event] 6 月 27 日晚間,Jserv與他愉快的小夥伴 首度在台北透過 YouTube進行網路直播,主題是「從無到有打造 IoT 作業系統核心」,將以 ARM Cortex-M3 為例,探討具體而微的作業系統核心的設計與實做,從 Hello World 等級的程式開始,逐步演化為原始程式碼 400
行內、支援多執行緒、搶佔式 (preemptive) 多工作業系統核心。

有興趣的朋友,記得先閱讀相關材料:https://embedded2016.hackpad.com/-IoT--VzsIQuEJcbo"

** 直播網址: https://www.youtube.com/c/GUTS4tech/live **

無論人們對 Internet of Things (IoT) 抱持再大的幻想,IoT 本質上仍是嵌入式系統,自然高效率又富有彈性的作業系統就是箇中重要議題。本次直播將以 ARM Cortex-M3 為例,探討具體而微的作業系統核心的設計與實做,從 Hello World 等級的程式開始,逐步演化為原始程式碼 400 行內、支援多執行緒、搶佔式 (preemptive) 多工作業系統核心。

注意須知:
(a) 本議程後續會持續更新,建議預習各項材料:
http://hackfoldr.org/oscar/
(b) 聽眾需要 ARM 背景知識,直播過程中只會作重點提示

--- 
如果這篇只有上面敘述, 大概就變成廣告文了, 這篇來介紹一下 vector table 好了. 
上述筆記內提到的參考文件也有介紹 - http://wiki.csie.ncku.edu.tw/embedded/arm-exceptions.pdf

之前 在 main function 有稍微介紹了一下, 這篇再補充一下. 

- 有 general registers (R0~R12) 和 special registers 
- 用 MRS / MSR 指令集來搬 special registers

--
processor mode and privileged levels

operation mode : thread mode / handler mode
access level : privileged mode / non-privileged mode

access mode : 分成有權限和沒權限 狀態. 這邊權限指:
     - CPS , MSR/MRS
     - system timer, NVIC, system control block
     - MPU : memory access

handler mode : 是 interrupt / system exception 系統自動進入, 此時是在 privileged mode .

reset 時 一開始是在 thread mode,

--
vector table : 一開始是指在 0x0000 0000 位置
可以 透過 vector table offset register (VTOR) 來做改變

system control block : VTOR register 位置 是在 0xE000ED08

4.3. System control block

The System control block (SCB) provides system implementation information, and system control. This includes configuration, control, and reporting of the system exceptions. The system control block registers are:

Table 4.12. Summary of the system control block registers
AddressNameTypeRequired privilege
Reset value
Description
0xE000E008ACTLRRWPrivileged0x00000000Auxiliary Control Register
0xE000ED00CPUIDROPrivileged
0x412FC230
CPUID Base Register
0xE000ED04ICSRRW [a]Privileged0x00000000Interrupt Control and State Register
0xE000ED08VTORRWPrivileged0x00000000Vector Table Offset Register
0xE000ED0CAIRCRRW [a]Privileged
0xFA050000
Application Interrupt and Reset Control Register
0xE000ED10SCRRWPrivileged0x00000000System Control Register
0xE000ED14CCRRWPrivileged0x00000200Configuration and Control Register
0xE000ED18SHPR1RWPrivileged0x00000000System Handler Priority Register 1
0xE000ED1CSHPR2RWPrivileged0x00000000System Handler Priority Register 2
0xE000ED20SHPR3RWPrivileged0x00000000System Handler Priority Register 3
0xE000ED24SHCRSRWPrivileged0x00000000System Handler Control and State Register
0xE000ED28CFSRRWPrivileged0x00000000Configurable Fault Status Register
0xE000ED28MMSR [b]RWPrivileged0x00MemManage Fault Status Register
0xE000ED29BFSR [b]RWPrivileged0x00BusFault Status Register
0xE000ED2AUFSR [b]RWPrivileged0x0000UsageFault Status Register
0xE000ED2CHFSRRWPrivileged0x00000000HardFault Status Register
0xE000ED34MMARRWPrivilegedUnknown
0xE000ED38BFARRWPrivilegedUnknownBusFault Address Register
0xE000ED3CAFSRRWPrivileged0x00000000Auxiliary Fault Status Register
--- 
我們可以寫一段 簡單的   程式, 看 VTOR 設定

// the setup function runs once when you press reset or power the board
void setup() {
  uint32_t address;
  // initialize digital pin 13 as an output.
  Serial.begin(38400);

  address = *(uint32_t*)(0xE000ED08);
  Serial.print("VTOR address : ");
  Serial.print(address, HEX);

  while(1);
}

// the loop function runs over and over again forever
void loop() {
}

--
結果 在 Ameba 上顯示 0x1000 0000, 這是 Ameba RAM 一開始的位置. 

vector table 長相如下 : 在前一篇 RTOS, 我們在 variant.cpp 置換 SVC / PendSV / SysTick 成 RTOS 用的. 
在這篇, 我們簡單介紹一下 Hard Fault

Hard Fault 在向量表中位於 0xC 這個位置. 




可以把它印出來, 

void setup() {
  volatile uint32_t *ptr;  
  ... 

  ptr = (uint32_t*)(0x1000000C);

  address = *ptr;
  Serial.print("Hard fault function : ");
  Serial.println(address, HEX);

  ...
}

可以發現位置是在 0x0000 010D. 屬於 ROM function code. 看不到

--

來寫一個 hard fault 處理程式, 並把函式位置填入 中斷向量表, 換成我們寫的處理程式

typedef int (*FUNC_PTR)();

void test_hardfault(void)
{
  Serial.print("My hard fault");
  while(1);
}

void setup() {
  ... 

  ptr = (uint32_t*)(0x1000000C);
  *ptr = (uint32_t)(&test_hardfault);

  ...
}


執行結果 : 

Hard fault function : 10004ED

置換成功. 

PS: 如果把 while(1) 去掉, 會發現一直進去, 這是因為我們 hard fault function 還沒寫清除 status

--
我們來製造一個 除0 產生的 hard fault. 


  b = 0;
  a = 3/b;
  Serial.println(a);

執行結果 : 印出 0, 奇怪怎麼沒有 hard fault. 

其實會不會有 hard fault 決定在 SCB 中的 CCR : 0xE000ED14

The bit assignments are:

Table 4.20. CCR bit assignments
BitsNameFunction
[31:10]-Reserved.
[9]STKALIGN
Indicates stack alignment on exception entry:
0 = 4-byte aligned1 = 8-byte aligned.
On exception entry, the processor uses bit[9] of the stacked PSR to indicate the stack alignment. On return from the exception it uses this stacked bit to restore the correct stack alignment.
[8]BFHFNMIGN
Enables handlers with priority -1 or -2 to ignore data BusFaults caused by load and store instructions. This applies to the hard fault, NMI, and FAULTMASK escalated handlers:
0 = data bus faults caused by load and store instructions cause a lock-up
1 = handlers running at priority -1 and -2 ignore data bus faults caused by load and store instructions.
Set this bit to 1 only when the handler and its data are in absolutely safe memory. The normal use of this bit is to probe system devices and bridges to detect control path problems and fix them.
[7:5]-Reserved.
[4]DIV_0_TRP
Enables faulting or halting when the processor executes an SDIV or UDIV instruction with a divisor of 0:
0 = do not trap divide by 0
1 = trap divide by 0.
When this bit is set to 0, a divide by zero returns a quotient of 0.
[3]UNALIGN_TRP
Enables unaligned access traps:
0 = do not trap unaligned halfword and word accesses1 = trap unaligned halfword and word accesses.
If this bit is set to 1, an unaligned access generates a UsageFault.
Unaligned LDMSTMLDRD, and STRD instructions always fault irrespective of whether UNALIGN_TRP is set to 1.
[2]-Reserved.
[1]USERSETMPEND
Enables unprivileged software access to the STIR, see Software Trigger Interrupt Register:
0 = disable1 = enable.
[0]NONBASETHRDENA
Indicates how the processor enters Thread mode:
0 = processor can enter Thread mode only when no exception is active
1 = processor can enter Thread mode from any level under the control of an EXC_RETURN value, see Exception return.


程式加入 : 

//CCR 
  value = *(uint32_t*)(0xE000ED14);
  Serial.print("CCR : ");
  Serial.println(value, HEX);

值為 200 : 表示目前系統只有設定 stack alignment / 8-byte alignment

我們把 divide 0 trap 設定進去 : bit4

  ptr = (uint32_t*)(0xE000ED14);

  *ptr = *ptr | 0x10;

執行結果 : 
   印出 My hard fault
達成

PS: hard fault handler 製作 , 也是門學問, 
      這篇有介紹如何設定成 gdb 中斷, 和利用 ITM 
      https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/

     相關 register 介紹可以參考 ARM 這份文件
     http://www.keil.com/appnotes/files/apnt209.pdf






留言

熱門文章