:::: MENU ::::

RTOS FreeRTOS, STM32F429i-disco, IAR quick start

В данной серии статей будут приведены примеры использования основных features (таких как semaphore, mutex, event и msg) различных RTOS и вложены проекты для быстрого начала работы с ними.

Список используемых RTOS:

NOTE:

  • mutex – используют для доступа к разделяемому ресурсу несколькими задачами. Когда одна задача захватила mutex и использует разделяемый ресурс, вторая не может захватить mutex и использовать разделяемый ресурс. Вторая задача будет находиться в ожидании освобождения mutex первой задачей. И как только mutex будет освобожден, вторая задача сможет его захватить и использовать разделяемый ресурс.
  • msg — используют для обмена данными между задачами. Note: Глобальные переменные не используют т.к. несколько задач одновременно могут получить доступ к ним, что может привести к ошибке. Либо доступ к этим глобальным переменным нужно выносить в критическую секцию, в которой планирование задач запрещено.
  • event – используют для того чтобы сообщить задаче, что произошло какое-то событие. Note: использование похоже на семафоры в режиме оповещения (сигнала) о том, что произошло событие.
  • semaphore – существует два варианта использования семафора:

Первый: Семафор для одновременного доступа к разделяемом ресурсу более чем 1 задачей (для 1 задачи обычно используют mutex).

При каждом занимание ресурса задачей значение семафора будет уменьшаться, пока не достигнет 0. При нулевом значение семафора разделяемый ресурс больше не может быть занят новой задачей, пока существующая задача его не оставит. При оставлении разделяемого ресурса задачей, значение семафора увеличивается на 1, что приводит к возможности другой задаче занять разделяемый ресурс.

Второй: семафор сигналит о том, что что-то произошло – например, прерывание. Например, из прерывание, сигналить задаче-обработчику этого прерывания о том, что надо запуститься.

Note: Проблема сигналов из двоичного семафора – если у вас двоичный семафор, то если произошло сразу нескольких быстрых прерываний (быстрых настолько, что их задача-обработчик, которой мы хотим просигналить, не успела вызваться), то двоичный семафор просигналит только один раз. И если нам точно нужно знать, сколько прерываний произошло и для всех их вызвать обработчик, то возникнет ошибка. Поэтому, для этого нужно использовать счетные (не бинарные) семафоры с глубиной счета, на столько большой на сколько вы рассчитываете быстро будут идти прерывания, которые вы хотите обрабатывать в задаче-обработчика.

Во всех приложенных проектах-примерах RTOS делает одно и тоже (скачать пример можно в конце статьи):

  • Задача 1 и задача 2 тестируют mutex. Они имеют одинаковый приоритет и пытаются одновременно захватить mutex(использовать разделяемый ресурс — строчку дисплея). Первая захватившая mutex задача выводит на дисплей свое имя и уходит в сон на 2 или 3 секунды (в зависимости 1 или 2 задача). В это время планировщик переключается на вторую задачу (т.к. первая с этим же приоритетом заснула) — вторая задача пытается захватить mutex, но он уже захвачен первой. Тогда, вторая задача блокируется до момента освобождения mutex. Mutex освободится когда первая задача проснется и освободит его (mutex) — тогда вторая задача захватывает mutex и так-же выводит на дисплей свое имя и уходит в сон. Далее все повторяется по такому же сценарию. Таким образом, мы можем протестировать mutex (более подробно — см. код в примере).
  • Задачи 3, 4 и 5 тестируют semaphore (для доступа к разделяемому ресурсу). Они имеют одинаковый приоритет и пытаются одновременно захватывать семафоры (использовать разделяемый ресурс — 2 строчки дисплея — для 1 строчки дисплея достаточно mutex). Принцип работы этих задач такой-же как и mutex задач 1 и 2, описных выше (более подробно — см. код в примере).
  • Задачи 6, 7 и 8 тестируют event. Задачи 6 и 7 отправляют event, а задача 8 принимает его и в зависимости от принятого event выводит различный текст на дисплей. Задача 6 и 7 имеют одинаковый приоритет, а задача 8 имеет повышенный приоритет — для того, чтобы по принятию event сразу проснуться и выполнить необходимое действие. По выполнению этого действия задача 8 опять уходит в режим блокировки до момента отправки следующего event от задач 6 или 7. Задача 6 отправляет event по нажатию кнопки на плате STM32F429i-Disco. А задача 7 отправляет event каждые 8 секунд.
  • Задачи 9 и 10 тестируют msg. Для этого задача 9 каждую секунду просыпается, инкрементирует переменную (считает секунды) и отправляет данную переменную через msg задачи 10. Задача 10 принимает данный msg и выводит принятое значение на дисплей (на дисплее считается время в секундах).

FreeRTOS

Ссылка на сайт разработчика: http://www.freertos.org/ .

Задачи

Создание задач:

xTaskCreate( &Task_1,
             "Task 1",
             256,      // размер стека
             NULL,     // параметры задачи-функции
             4,        // приоритет
             NULL );   // указатель на созданную задачу

void Task_1( void *pvParametrs ) 
{
    while(1)
    {
    }
}

В main, RTOS запускается вызовом функции vTaskStartScheduler.

int main(void)
{
   xTaskCreate( &Task_1,
               "Task 1",
               256, 
               NULL,
               4,
               NULL );
    ...
    // code
    ...

    vTaskStartScheduler();
    while(1);
}

Отправка задачи в сон:

vTaskDelay( 3000 / portTICK_RATE_MS ); // заснуть на 3000 мсек 

Работа с mutex

Создание:

xSemaphoreHandle mutex_1;
mutex_1 = xSemaphoreCreateMutex();

Использование:

xSemaphoreTake( mutex_1, portMAX_DELAY ); // захватываем mutex

// code
// делаем что либо с разделяемым ресурсом

xSemaphoreGive( mutex_1 ); // освобождаем mutex

Работа с семафорами

Создание:

xSemaphoreHandle sem_1;
sem_1 = xSemaphoreCreateCounting( 2,    // Max value
                                  2 );  // Start value

Max value – максимальное значение семафора.

Если вы используете семафор для одновременного доступа к разделяемом ресурсу, то Max value указывает какое число задач могут иметь одновременный доступ к разделяемому ресурсу.

Если вы используете семафор для оповещения что произошло некое событие, тоMax value показывает глубину очереди сигналов. Max value == 1 — двоичный семафор. Выбирайте Max value на столько большим на сколько вы рассчитываете быстро будут идти прерывания, которые вы хотите обрабатывать в задаче-обработчика.

Start value – начальное значение семафора. Если вы используете семафор для одновременного доступа к разделяемом ресурсу более чем 1 задачей, то данное значение должно быть равно Max_value.

Если вы используете семафоры для того, чтобы сигналить о чем-либо, то Start value должно быть равно 0.

Использование:

xSemaphoreTake(sem_1, portMAX_DELAY); // захватываем ресурс семафором (или ждем события)

// code
// делаем что либо с разделяемым ресурсом

xSemaphoreGive(sem_1); // освобождаем  ресурс семафором (или сигналим о событии)

Работа с msg

Создание:

QueueHandle_t msg_1;
msg_1 = xQueueCreate( 10,                        // глубина очереди msg
                      sizeof( uint32_t ) );      // размер одного элемента

Использование:

Передача:

uint32_t tx_data;
unit32_t data;

tx_data = cnt;
xQueueSend( msg_1, &tx_data, portMAX_DELAY);

Прием:

uint32_t rx_data;
xQueueReceive( msg_1, &rx_data, portMAX_DELAY);

Работа с event

Создание:

EventGroupHandle_t event_1;
event_1 = xEventGroupCreate();

Использование:

Отправка:

// отправляем флаг - 0b 0000 0001
xEventGroupSetBits(event_1, 1);

Прием:

f_event = xEventGroupWaitBits(
            event_1,          /* The event group being tested. */
            1 | 2,            /* The bits within the event group to wait for. */
            pdTRUE,           /* flags should be cleared before returning. */
            pdFALSE,          /* Don't wait for both bits, either bit will do. */
            portMAX_DELAY );  /* Infinity wait. */ 

if(f_event & 0x01)
{
    // code
}

Пример для скачивания — stm32f429 IAR FreeRTOS example. Пример сделан в IAR 7, заархивирован 7ZIP.