關於 Arduino Ameba 的 100 篇 - main function (3/100)



習慣寫 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,





通常 一開始的向量表是放在 0 的起頭位置. 
但有一個 VTOR ( 向量表偏移量寄存器 )
譬如在 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);
}



留言

熱門文章