extern “C”

Інформація, яку видає OpenOCD при звичайному завантаженні програми у flash-пам’ять мікроконтролера, деколи може допомогти так, як наче це був запущений зневаджувач.

Переписую на свій смак шматки, які вже працювали зі стандартною бібліотекою від NXP. При чергових змінах програми вона начисто перестає працювати. Знаходжу дрібну помилку (замість змінної часу повертається константа періоду), виправляю, перешиваю…

Знову висить.


І тут помічаю, що OpenOCD сповістив мене про те, що ядро перед програмуванням знаходилося не в стані Thread, тобто виконання програми, а в стані обробки переривання:

    TargetName         Type       Endian TapName            State      
--  ------------------ ---------- ------ ------------------ ------------
 0* lpc1766.cpu        cortex_m3  little lpc1766.cpu        running
target state: halted
target halted due to debug-request, current mode: Handler SysTick
xPSR: 0x6100000f pc: 0x00002628 msp: 0x10007f70

Але ж обробка SysTick складається у мене зараз зі скидання прапорця та інкременту змінної, кілька тактів при тактовій 100 МГц. Потрапити на неї — дуже низька імовірність.

void SysTick_Handler(void)
{
    SysTick->CTRL &= ~ST_CTRL_COUNTFLAG;
    ++systick_ticks;
}

Ще раз запускаю програматор і знову отримую «Handler SysTick», що вже зовсім неймовірно за нормальних умов.

О, точно!
Так я ж забув дописати extern "C" перед обробником переривання SysTick_Handler(), коли перетягував цей шматок з С-шного файлу у C++-овий.
«запускалка» startup.c, як будь-який С-шний код, очікує звичайні імена функцій імена без декорування імен (name mangling) C++. Оскільки лінкер не знайшов моєї «С-шної» функції SysTick_Handler(), у відповідне місце таблиці переривань було записано адресу функції Default_Handler, на яку weak-синонімом було направлене ім’я SysTick_Handler. І там, у нескінченому циклі обробника за умовчанням, програма і сиділа постійно.
Після того, як я за допомогою extern "C" функцію з C++ – файлу перетворив на «С-шну», з нормальним недекорованим іменем, все побігло куди треба.

Відразу написав файл lpc17xx_handlers.h, простіше буде включати його в усі файли з обробниками переривань і не думати, треба ставити extern "C" чи ні.
Хоча може краще було б зробити так:

#ifdef __cplusplus
#define CM3_HANDLER extern "C"
#else
#define CM3_HANDLER
#endif

І писати CM3_HANDLER перед кожним обробником переривання, аналогічно OS_INTERRUPT в програмах з scmRTOS.

Я ще подумаю 😉

Attached Files:

  • h lpc17xx_handlers

    lpc17xx handler prototypes for C/C++ programs (with extern "C" for C++)

Leave a Reply

[flagcounter image]