#c #embedded #freertos
#c #встроенный #freertos
Вопрос:
Я изучаю FreeRTOS на STM32F103C8T6 (на плате с синими таблетками). Я пытаюсь использовать очереди и задачи.
#include <FreeRTOS.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <queue.h>
#include <task.h>
static QueueHandle_t queue;
static void
task_receive(void *args __attribute__((unused)))
{
bool nothing;
while (1)
{
if (xQueueReceive(queue, amp;nothing, 10) == pdPASS)
gpio_set(GPIOC, GPIO13); // Turn off
else
taskYIELD(); // Yeld so that other taks can run
}
}
static void
task_send(void *args __attribute__((unused)))
{
bool nothing = false;
while (1)
{
gpio_clear(GPIOC, GPIO13); // Turn on
vTaskDelay(pdMS_TO_TICKS(100));
xQueueSendToBack(queue, amp;nothing, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int
main(void)
{
rcc_clock_setup_in_hse_8mhz_out_72mhz();
// Blue-Pill led
rcc_periph_clock_enable(RCC_GPIOC);
gpio_set_mode(
GPIOC,
GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL,
GPIO13);
gpio_set(GPIOC, GPIO13); // Turn off (polarity of the led is inversed!)
queue = xQueueCreate(32, sizeof(bool));
if (queue == 0)
{
while (1)
{
gpio_toggle(GPIOC, GPIO13);
for (uint32_t i = 0; i < 80000; i)
__asm__("nop");
};
}
xTaskCreate(task_receive, "RECEIVE", 200, NULL, configMAX_PRIORITIES-1, NULL);
xTaskCreate(task_send, "SEND", 200, NULL, configMAX_PRIORITIES-2, NULL);
vTaskStartScheduler();
while(1);
return 0;
}
Ожидаемое поведение:
-
main
- Настраивает часы
- Настраивает GPIO для синего светодиода Pill
- Отключает индикатор
- Создает очередь
- Проверяет правильность создания очереди: если нет, индикатор мигает быстро и навсегда.
- Запланируйте две задачи
- Запускает планировщик
-
task_send
(бесконечные циклы)- Включите индикатор
- Подождите 100 мс
- Отправить сообщение в очередь (содержимое здесь не имеет значения)
- Подождите 1 секунду
-
task_receive
(бесконечные циклы)- Проверьте, находится ли сообщение в очереди
- Да: выключите индикатор
- Нет: yeld
- Проверьте, находится ли сообщение в очереди
Я ожидаю, что индикатор будет включен на 100 мс, а затем выключен на 900 мс.
Реальное поведение: индикатор всегда горит, выполнение программы, похоже, блокируется xQueueSendToBack
.
Почему блокируется вызов?
FreeRTOSConfig.h
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 )
#define configSYSTICK_CLOCK_HZ ( configCPU_CLOCK_HZ / 8 ) /* fix for vTaskDelay() */
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY 255
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */
/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15. This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
Комментарии:
1. В вашем примере
task_receive
приоритет выше, чемtask_send
приоритет, поэтому уступка в задаче с более высоким приоритетом приведет к повторному вызову вызывающей задачи. Следовательно, вашsend_task
не будет выгружен вообще. Взгляните на это freertos.org/a00020.html#taskYIELD
Ответ №1:
Ваш task_receive
приоритет выше, чем task_send
приоритет. taskYIELD
будет выполняться одна и та же вызывающая задача снова и снова, если нет задач с более высоким приоритетом.
Чтобы достичь желаемого, попробуйте изменить task_receive
следующим образом.
static void
task_receive(void *args __attribute__((unused)))
{
bool nothing;
while (1)
{
if (xQueueReceive(queue, amp;nothing, portMAX_DELAY) == pdPASS)
gpio_set(GPIOC, GPIO13); // Turn off
}
}
Для получения дополнительной информации о taskYIELD, пожалуйста, обратитесь к следующему.
Комментарии:
1. Я пробовал это изменение, но оно не улучшает поведение индикатора (он включен и никогда не гаснет). Я также попытался сделать так, чтобы две задачи имели одинаковый приоритет: лучше не бывает.
2. Позвольте мне высказать обоснованное предположение здесь. Не застревает ли ваш код на
vTaskDelay
, а не вxQueueSendToBack
. Если это так, убедитесь, что ваш системный сервер ISR (я предполагаю, что системный сервер является источником тиков RTOS) правильно настроен для вызова функции тиков FreeRTOS. Посмотрите, какlibopencm3
выполняется обработка системного ISR.3. Я думаю, что это правильно настроено. Я создал пример для мигания светодиода с двумя задачами (одна задача включает светодиод, другая выключает светодиод), каждая из них вызывает
vTaskDelay
, и это работает нормально. gist.github.com/VictorLamoine/8bbb9caeaae32f0d3348ecdba060eae74. Есть ли у вас возможность пошагового просмотра исходного кода с помощью отладчика? Кажется, что вы нажимаете
configAssert
в коде FreeRTOS. Опять же, я надеюсь, что к этому времени вы уже проверили, достаточен ли размер стека200
слов для выполнения двух задач.5. @VictorLamoine Я не могу найти ничего неправильного в коде (с не
taskYIELD
одним). Я попробовал аналогичный код на другой плате и, похоже, работает совершенно нормально (я заменил ваши вызовы GPIO на UART-printfs). Может быть, вам лучше попробовать сделать то же самое с STM32Cube HAL в обход зависимостей libopencm3 — просто предложение. Для получения дополнительной помощи вам лучше воспользоваться дискуссионным форумом FreeRTOS.
Ответ №2:
Проблема была решена путем обновления компилятора до последней версии.
Kubuntu 18.04 поставляется с arm-none-eabi-gcc (15:6.3.1 svn253039-1build1) 6.3.1 20170620
, с этим компилятором код не работает.
memcpy
похоже, это проблемный вызов функции в коде, он вызывается FreeRTOS при добавлении элемента в очередь.
Если я использую Version 8-2018-q4-major Linux 64-bit
компилятор, то код выполняется нормально. Его можно загрузить здесь:https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads