На Хабре уже было много статей, в которых описывалось применение FreeRTOS или портирование на широко распространенные архитектуры процессоров. В этой статье я хочу поделиться опытом портирования FreeRTOS на российскую архитектуру «Мультиклет» и показать как справляется процессор Multiclet P1 с несколькими параллельными задачами. В качестве примера будет создан GPS трекер с возможностью записи координат на SD, оболочкой через UART, небольшим текстовым редактором и возможностью работы с файловой системой FAT32.Шаг 1. Портирование.
В качестве примера был использован порт FreeRTOS для ATMega323, т. к. с архитектурой данного процессора я был давно знаком. После изучения файлов стало понятно, что в лоб эту задачу не решить, т. к. для FreeRTOS рекомендуется использовать набор компиляторов GCC (для конкретной архитектуры) с его __attribute__ и asm вставками, а в текущем компиляторе LCC от Multiclet данная возможность отсутствует. Это не стало большой проблемой, единственный атрибут, который был использован в порте для ATMega323, это __attribute__ ((naked)), который говорит компилятору не создавать пролог и эпилог функции. Этот атрибут приписан к функции, которая отвечает за смену контекста задачи и уход на выполнение новой, поэтому важно, чтобы при её вызове не создавался пролог и эпилог (иначе стек\память быстро закончится). Данную функцию и все функции с asm вставками пришлось писать на ассемблере Multiclet.
Следующая проблема, с которой я столкнулся, портируя ОС, это стек. Дело в том, что в процессорах Multiclet нет команд push и pop из-за особенностей архитектуры. Архитектура порта получилась, возможно, слегка мудрёной, но на данный момент я не вижу более
элегантного решения. Идея заключается в следующем: у каждой задачи в ОС своя область памяти, в которой располагаются значения её регистров и стек вызовов, и имеется общий стек ОС, в котором располагаются вызовы функций во время обработки прерываний. Подмена значений регистров #SP и #BP (указатели на базу и фрейм функции) осуществляется в первичном обработчике прерываний (файл crt0.s).
Пример смены задачи в момент прерывания.
Имеются 2 задачи с одинаковым приоритетом. После того, как задачи созданы и добавлены ядром ОС в очередь, будет вызвана функция xPortStartScheduler(void), которая запустит системный таймер и вызовет функцию первичной смены контекста PRS(). В функции PRS() через указатель pxCurrentTCB (pxCurrentTCB — указатель ОС на контекст задачи) устанавливаются значение всех регистров, в том числе #SP и #BP (значение глобальных #SP и #BP сохраняются в переменных gSP и gBP соответственно), отвечающих за стек текущей задачи и переход на её выполнение.
PRS: jmp PRS_fin PXCTCB:= rdl pxCurrentTCB pxTopOfStack:= rdl @PXCTCB setl #DI, @pxTopOfStack complete PRS_fin: reg7 := rdl #DI, pStack reg6 := rdl #DI, pStack + 4 reg5 := rdl #DI, pStack + 8 reg4 := rdl #DI, pStack + 12 reg3 := rdl #DI, pStack + 16 reg2 := rdl #DI, pStack + 20 reg1 := rdl #DI, pStack + 24 reg0:= rdl #DI, pStack + 28 pvp := rdl #DI, pStack + 32 pxCode := rdl #DI, pStack + 36 taskSP := rdl #DI, pStack + 40 taskBP := rdl #DI, pStack + 44 saveSP := getl #SP saveBP := getl #BP setl #R7,@reg7 setl #R6,@reg6 setl #R5,@reg5 setl #R4,@reg4 setl #R3,@reg3 setl #R2,@reg2 setl #R1,@reg1 setl #R0,@reg0 wrl @saveSP, gSP wrl @saveBP, gBP setl #SP, @taskSP setl #BP, @taskBP jmp @pxCode complete
В момент возникновения прерывания от системного таймера происходит передача управления на первичный обработчик прерываний.
master.isr: jmp mi.hendler saveSP := getl #SP saveBP := getl #BP loadSP := rdl gSP loadBP := rdl gBP reta := getl #IRETADDR wrl @saveSP, iSP </code> wrl @saveBP, iBP setl #SP, @loadSP setl #BP, @loadBP wrl @reta, master.isr.retaddr complete
В первичном обработчике прерываний (master.isr) заменяются указатели на стек и сохраняется адрес возврата из прерывания, затем вызывается функция смены контекста RTOS.
mi.hendler: getl #SP getl mi.stop getl #INTNUMR getl irq.desc.tbl mull @2, sizeof.I</code> DT.item addl @1, @2 rdl @1 jmp @1 subl @8, sizeof.ptr wrl @8, @1 setl #SP, @2 complete
Во время смены контекста вызывается функция сохранения контекста текущей задачи, затем планировщик OC установит указатель pxCurrentTCB на задачу, которую необходимо восстановить, и вызывается функция восстановления контекста с передачей управления на эпилог первичного обработчика прерываний.
mi.stop: jmp mi.PF getl #SP addl @1, sizeof.ptr setl #SP, @1 complete mi.PF: rdl master.isr.retaddr jmp @1 getq #PSW or @1, PSW.ONIRQS setq #PSW, @1 saveSP := getl #SP saveBP := getl #BP loadSP := rdl iSP loadBP := rdl iBP wrl @saveSP, gSP wrl @saveBP, gBP setl #SP, @loadSP setl #BP, @loadBP complete
Так работает смена задач и стеков FreeRTOS Multiclet P1.
Шаг 2. Пример использования.
В качестве примера реального использования ОС на демонстрационной плате был собран небольшой макет GPS трекера.

Плата сверху это Pinboard II. Она была использована только в качестве разъёма для SD карты.
Основной задачей с наивысшим приоритетом был эмулятор терминала, реализованный через COM порт.

Параллельно выполняемые задачи: запись на SD карту, чтение SD карты, получение данных c GPS приёмника, запись и чтение координатного трека в\из файл(а).


Полученные данные не достоверны (т. к. GPS приёмник лежал на столе) и демонстрируют только работу с файловой системой. Поместив демонстрационную плату на окно получаем почти верные результаты.

Работа ОС с картой памяти осуществлялась при помощи библиотеки FatFS товарища Сhan’a [ elm-chan.org/fsw/ff/00index_e.html ].
Заключение
В данной статье я хотел показать, что процессоры Multiclet способны выполнять программы широко распространенные на других архитектурах, а с учётом низкого энергопотребления и аппаратного распараллеливания ещё и гораздо эффективнее.
ссылка на оригинал статьи http://habrahabr.ru/post/209732/
Добавить комментарий