:::: MENU ::::

RTOS SMX, 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 и выводит принятое значение на дисплей (на дисплее считается время в секундах).

Данная статья не предусматривает тестового проекта примера (хотя у меня он есть в целях изучения данной RTOS) т.к. данная  RTOS SMX Proprietary и не подлежит распространению через третьи лица. Для изучения данной RTOS можно скачать проект с сайта данной RTOS http://www.smxrtos.com/eval/ek_armm.htm#stmicro.

 

SMX4

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

Задачи

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

TCB_PTR p_task_1;
p_task_1 = smx_TaskCreate((FUN_PTR)func_task_1, 
                          PRI_LO,                   // приоритет 
                          128,                      // размер стека
                          SMX_FL_NONE,              // стартует не заблок.
                          "task_1");
status = smx_TaskStart(p_task_1);

void func_task_1(void)
{
    while(1)
    {
    }
}

main :

int main(void)
{
    sb_INT_DISABLE();
    if (!StartupChecks())
    {
        sb_Exit(SMXE_ABORT);
    }
    smx_exit = aexit;
#if !defined(SB_CPU_ARMM)  /* already called in startup code for ARM-M */
    sb_IntCtrlInit();          /* must be before unmask interrupts */
#endif
    sb_TickInit();             /* init tick used for all smx timing and ptime <2> <3> */
    sb_IRQsMask();             /* mask all interrupts and save current mask, until ainit() */
    sb_TM_INIT();              /* init precise time measurement routines */
    smx_Go();                  /* initialize smx and enter scheduler */
    return(0);                 /* should never reach here; keeps compiler happy */
}

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

smx_DelaySec(2); // заснуть на 2 сек 

Работа с mutex

Создание:

MUCB_PTR  p_mutex_1;
p_mutex_1 = smx_MutexCreate(1, // наследование приоритета
                            2, // потолок приоритета (при наследование не важен)
                            "mutex_1");

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

smx_MutexGet(p_mutex_1, SMX_TMO_INF); // захватываем mutex

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

smx_MutexRel(p_mutex_1); // освобождаем mutex

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

Создание:

SCB_PTR   p_sem_1;
p_sem_1 = smx_SemCreate(SMX_SEM_RSRC, // режим простого семафора (разделяемый ресурс)
                        2,            // max value 
                        "sem_1");   

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

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

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

smx_SemTest(p_sem_1, SMX_TMO_INF); // захватываем ресурс семафором

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

smx_SemSignal(p_sem_1); // освобождаем  ресурс семафором 

Работа с msg

Создание:

#define SIZE_QUE_PIPE 10
#define SIZE_VAL_ONE_PIPE 2 // uint16_t - 2 byte

PICB_PTR  p_pipe_1;
char p_pipe_buf[SIZE_VAL_ONE_PIPE * SIZE_QUE_PIPE]; // for pipe

p_pipe_1 = smx_PipeCreate(p_pipe_buf, 
                          SIZE_VAL_ONE_PIPE,
                          SIZE_QUE_PIPE,
                          "pipe_1");

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

Передача:

uint16_t tx_data;
uint16_t data;

tx_data = data;
smx_PipePutWait(p_pipe_1, (void*)&tx_data, SMX_TMO_INF);

Прием:

uint16_t rx_data;
bool res;

smx_PipeGetWait(p_pipe_1, (void*)&rx_data, SMX_TMO_INF);
if(res == TRUE)
{
    // code
}

Работа с event

Создание:

EGCB_PTR  p_ev_1;
p_ev_1 = smx_EventGroupCreate( 1,       // начальное значение флагов evt
                               "ev_1");

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

Отправка:

smx_EventFlagsSet(p_ev_1,
                  4,      // устанавливает 3 фллаг (4 = 0b100)
                  1);     // сбрасывает 1 бит (pre_clear) 

Прием:

f_event = smx_EventFlagsTest(p_ev_1, 
                             SMX_EF_OR+8+4, // ожиданмые флаги evt
                             8+4,           // очищаем флаги после прихода нужного evt(post_clear)
                             SMX_TMO_INF);  // время ожидания

if(f_event & 4)
{
    // code
}