При сборке проекта содержащего FreeRTOS компилятором GCC с активной опцией "Link-time optimization" появляется ошибка undefined reference to `vTaskSwitchContext' в функции xPortPendSVHandler файла port.c.
Код функции.
Кликните здесь для просмотра всего текста
| C | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| void xPortPendSVHandler(void)
{
/* This is a naked function. */
__asm volatile
(
" mrs r0, psp \n"
" isb \n"
" \n"
" ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */
" ldr r2, [r3] \n"
" \n"
" stmdb r0!, {r4-r11} \n" /* Save the remaining registers. */
" str r0, [r2] \n" /* Save the new top of stack into the first member of the TCB. */
" \n"
" stmdb sp!, {r3, r14} \n"
" mov r0, %0 \n"
" msr basepri, r0 \n"
" bl vTaskSwitchContext \n"
" mov r0, #0 \n"
" msr basepri, r0 \n"
" ldmia sp!, {r3, r14} \n"
" \n" /* Restore the context, including the critical nesting count. */
" ldr r1, [r3] \n"
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */
" ldmia r0!, {r4-r11} \n" /* Pop the registers. */
" msr psp, r0 \n"
" isb \n"
" bx r14 \n"
" \n"
" .align 4 \n"
"pxCurrentTCBConst: .word pxCurrentTCB \n"
::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)
);
} |
|
Она представляет собой асм. вставку из которой вызывается функция vTaskSwitchContext, на отсутствие которой ругается компилятор. Подчеркну, что это происходит только при компиляции с опцией "Link-time optimization", позволяющей выполнять оптимизацию на этапе линковки.
Кроме этой асм. вставки, функция vTaskSwitchContext вызывается еще из одной, находящейся в функции xPortPendSVHandler также из port.c и из кода - функции xPortStartScheduler файла port.c. Там предпринята попытка исправить упомянутую ошибку, поскольку перед вызовом есть комментарий. | C | 1
2
3
4
5
6
| /* Should never get here as the tasks will now be executing! Call the task
exit error function to prevent compiler warnings about a static function
not being called in the case that the application writer overrides this
functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the
symbol. */ |
|
Но поскольку вызов только один, то оптимизатор при уровне выше -O0, по видимому вместо вызова функции производит ее непосредственную вставку в код, т. е. поступает как с inline функцией.
Исправить ошибку довольно просто. Нужно найти реализацию функции vTaskSwitchContext (она в файле tasks.c) и сообщить оптимизатору что функция используется добавив __attribute__((used)) перед началом функции.
После этого проект нормально собирается.
Тестовый проект с одной задачей.| C | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| #include "stm32f10x_conf.h"
#include "FreeRTOS.h"
#include "task.h"
TaskHandle_t hTask_Blink;
void TaskBlink(void const *argument)
{
while(1)
{
GPIO_SetBits(GPIOC, GPIO_Pin_13);
vTaskDelay(400);
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
vTaskDelay(400);
}
}
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// Создание задач.
xTaskCreate((TaskFunction_t) TaskBlink, "Blink",
configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, hTask_Blink);
vTaskStartScheduler(); // Запуск планировщика задач.
while(1)
{
}
} |
|
Но если залить прошивку в МК то выяснится что она не работает. Необходимо в проект (например FreeRTOSConfig.h) добавить строки, производящие ассоциацию вызовов прерываний с функциями FreeRTOS. | C | 1
2
3
| #define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler |
|
|