習慣寫 C/C++ 的, 一定會覺得奇怪, Arduino 的 main function 到哪去了,
為什麼可以只寫 setup() / loop()
Main function 在哪裡
其實 Arduino 是有 main() function 的. 定義在
cores/arduino/main.cpp
windows 會放在 :
C:/Users/<使用者名稱>/AppData/Local/Arduino15/packages/<平台安裝package名稱>/hardware/<硬體名稱>/<硬體版本>/cores/arduino/main.cpp
MAC OS 會放在 :
/Users/<使用者名稱>/Library/Arduino15/packages/<平台安裝package名稱>/hardware/<硬體名稱>/<硬體版本>/cores/arduino/main.cpp 下
int main( void ) |
| { |
| // Initialize watchdog |
| watchdogSetup(); |
| |
| init(); |
| |
| initVariant(); |
| |
| delay(1); |
| |
| #if defined(USBCON) |
| USBDevice.attach(); |
| #endif |
| |
| setup(); |
| |
| for (;;) |
| { |
| loop(); |
| if (serialEventRun) serialEventRun(); |
| } |
| |
| return 0; |
| } |
而 setup() / loop() 就從這邊呼叫.
另外, 在 hardware/xxx/arduino/varients/xxx/
variant.cpp 中, 定義了 init()
誰呼叫 main()
這和 ARM Cortex-M3 CPU 架構有關
我們找一個 CMSIS/device/..
startup.c 來看
(1) ARM Cortex-M vector table 向量表
/* Exception Table */ |
| __attribute__ ((section(".vectors"))) |
| const DeviceVectors exception_table = { |
| |
| /* Configure Initial Stack Pointer, using linker-generated symbols */ |
| (void*) (&_estack), |
| (void*) Reset_Handler, |
| |
| (void*) NMI_Handler, |
| (void*) HardFault_Handler, |
| (void*) MemManage_Handler, |
| (void*) BusFault_Handler, |
| (void*) UsageFault_Handler, |
| (void*) (0UL), /* Reserved */ |
| (void*) (0UL), /* Reserved */ |
| (void*) (0UL), /* Reserved */ |
| (void*) (0UL), /* Reserved */ |
| (void*) SVC_Handler, |
| (void*) DebugMon_Handler, |
| (void*) (0UL), /* Reserved */ |
| (void*) PendSV_Handler, |
| (void*) SysTick_Handler, |
|
|
譬如在 Ameba 系統啟動後, VTOR 會設定到 RAM 的開頭 (0x10000000)
我們可以用以下程式看到 VTOR 值.
void setup() {
// put your setup code here, to run once:
unsigned int *ptr = (unsigned int*)0xE000ED08;
Serial.print("VTOR:");
Serial.print((long)ptr, HEX);
Serial.print("=");
Serial.println((long)(*ptr), HEX);
for(;;);
}
void loop() {
// put your main code here, to run repeatedly:
}
執行結果 :
VTOR:E000ED08=10000000
重置時
當重置時, 系統會從 Reset Handler 向量表中, 取出該函式位置, 跳至該函式執行.
而在 Reset_Handler() 可以看到是在這邊呼叫 main()
/** |
| * \brief This is the code that gets called on processor reset. |
| * To initialize the device, and call the main() routine. |
| */ |
| void Reset_Handler(void) |
| { |
| uint32_t *pSrc, *pDest; |
| |
| /* Initialize the relocate segment */ |
| pSrc = &_etext; |
| pDest = &_srelocate; |
| |
| if (pSrc != pDest) { |
| for (; pDest < &_erelocate;) { |
| *pDest++ = *pSrc++; |
| } |
| } |
| |
| /* Clear the zero segment */ |
| for (pDest = &_szero; pDest < &_ezero;) { |
| *pDest++ = 0; |
| } |
| |
| /* Set the vector table base address */ |
| pSrc = (uint32_t *) & _sfixed; |
| SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk); |
| |
| if (((uint32_t) pSrc >= IRAM0_ADDR) && ((uint32_t) pSrc < NFC_RAM_ADDR)) { |
| SCB->VTOR |= (1UL) << SCB_VTOR_TBLBASE_Pos; |
| } |
| |
| /* Initialize the C library */ |
| __libc_init_array(); |
| |
| /* Branch to main function */ |
| main(); |
| |
| /* Infinite loop */ |
| while (1); |
| } |
|
|
留言
張貼留言