Как создавать потоки в ChibiOS.

Создание нового потока является наиболее распространенной задачей при использовании ОС реального времени. Давайте рассмотрим как это делается в ChibiOS/RT.
После инициализации ChibiOS/RT, используя chSysInit() у нас появляются два потока по умолчанию: Idle thread — этот поток имеет самый низкий приоритет в системе, так как он работает только тогда, когда другие потоки не используются либо спят. Эти потоки обычно переключает систему в режим пониженного энергопотребления и больше ничего не делают; Main thread — это главный поток, он выполняет основную функцию main() при запуске. Основной поток создается на уровне NORMALPRIO и он может изменить свой приоритет, если требуется.
Есть два класса потоков в ChibiOS / RT:
Static Threads (Статические потоки) это класс потоков которые находятся в статической памяти во время компиляции.
Dynamic Threads (Динамические потоки) это потоки созданные путем выделения памяти во время компиляции.

Создание статического потока
Для того чтобы создать статический поток, рабочая зона должна быть объявлена с помощью макросов WORKING_AREA как показано ниже:

static WORKING_AREA(myThreadWorkingArea, 128);

Этот макрос резервирует 128 байт стека для потока и пространства всех необходимых и связанных с ним структур.
Статический поток может быть запущен вызовом chThdCreateStatic(), как показано в следующем примере:

Thread *tp = chThdCreateStatic(myThreadWorkingArea,
  sizeof(myThreadWorkingArea),
  NORMALPRIO,  /* приоритет  */
  myThread,  /* функция потока  */
  NULL);  /* параметры потока */

Переменная tp получает указатель на объект потока, этот указатель часто принимается в качестве параметра другими API. Теперь полный пример:

#include <ch.h>
/*
* Рабочее пространство
*/
static WORKING_AREA(myThreadWorkingArea, 128);
/*
*Поток(мигаем диодом)
*/
static msg_t myThread(void *arg) {
  while (TRUE) {
  LED_ON();
  chThdSleepMilliseconds(500);
  LED_OFF();
  chThdSleepMilliseconds(500);
  }
}
int main(int argc, char *argv[]) {
  /*стартуем поток*/
  (void)chThdCreateStatic(myThreadWorkingArea, sizeof(myThreadWorkingArea),
  NORMALPRIO, myThread, NULL);
  .
  .
  .
}

Следует отметить, что память, выделенная для MyThread(), статически определена и не может быть использована повторно. Статические потоки более безопасны, потому что нет никакого риска выхода из строя распределения памяти, от того, что происходит фрагментация стека.

Создание динамического потока при помощи распределения стека. Создание потока из HEAP

Thread *tp = chThdCreateFromHeap(NULL,  /* NULL = Default heap. */
  THD_WA_SIZE(128),/*размер стека */
  NORMALPRIO,  /* приоритет  */
  myThread,  /* функция потока  */
  NULL);  /* параметры потока  */

Память выделяется из указанного стека и поток выполняется. Обратите внимание, что память не освобождается, когда поток завершается. Например:

#include <ch.h>
/*
*мигаем светодиодом
*/
static msg_t myThread(void *arg) {
  unsigned i = 10;
  while (i > 0) {
    LED_ON();
    chThdSleepMilliseconds(500);
    LED_OFF();
    chThdSleepMilliseconds(500);
    i--;
  }
  return (msg_t)i;
}
int main(int argc, char *argv[]) {
  Thread *tp = chThdCreateFromHeap(NULL, THD_WA_SIZE(128), NORMALPRIO+1, myThread, NULL);
  if (tp == NULL)
    chSysHalt();    /* Memory exausted. */
  /* The main thread continues its normal execution.*/
  .
  .
  /*
   * Now waits for the spawned thread to terminate (if it has not terminated
   * already) then gets the thread exit message (msg) and returns the
   * terminated thread memory to the heap (default system heap in this
   * example).
   */
  msg_t msg = chThdWait(tp);
  .
  .
}

Создание динамического потока, используя распределение памяти(не стека)

/*
* My simple application.
*/
#include <ch.h>
/*
* LED flashing thread.
*/
static msg_t myThread(void *arg) {
  unsigned i = 10;
  while (i > 0) {
    LED_ON();
    chThdSleepMilliseconds(500);
    LED_OFF();
    chThdSleepMilliseconds(500);
    i--;
  }
  return (msg_t)i;
}
int main(int argc, char *argv[]) {
  Thread *tp = chThdCreateFromMemoryPool(myPool, NORMALPRIO+1, myThread, NULL);
  if (tp == NULL)
    chSysHalt();    /* Pool empty. */
  /* The main thread continues its normal execution.*/
  .
  .
  /*
   * Now waits for the spawned thread to terminate (if it has not terminated
   * already) then gets the thread exit message (msg) and returns the
   * terminated thread memory to the original memory pool.
   */
  msg_t msg = chThdWait(tp);
  .
  .
}