Программирование ARM FreeRTOS: практическое применение, дополнения, словарик Thu, April 18 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

FreeRTOS: практическое применение, дополнения, словарик Печать
Добавил(а) microsin   

В этом разделе собраны дополнения - сборка примеров, демонстрационные приложения (демо), папки и файлы FreeRTOS, создание проекта FreeRTOS, типы данных и руководство по стилю кодирования, информация о лицензировании, словарик, индекс, ссылки.

[Предыдущая часть FreeRTOS: практическое применение, часть 6 (устранение проблем)]

[Дополнение 1: сборка примеров]

Эта книга предоставляет многочисленные примеры кода, исходный код которых предоставляется в файле .zip наряду файлами проекта, которые могут быть открыты и скомпилированы в среде Open Watcom IDE. Полученный исполняемый код может быть выполнен через окно команд Windows (интерпретатор команд cmd), либо альтернативно под управлением DOS-эмулятора DOSBox. Для загрузки необходимого инструментария см. [2, 3].

Внимание: убедитесь, что подключены опции 16-битной целевой DOS, когда устанавливаете компилятор Open Watcom!

Все файлы проекта Open Watcom называются RTOSDemo.wpj, они могут быть найдены в папках Examples\Example0nn, где 'nn' указывает на номер примера.

DOS далека от идеальной цели (target) для FreeRTOS, и примеры приложений не будут работать со своими реальными временнЫми характеристиками. DOS используется просто потому, что это может позволить многим пользователям экспериментировать с примерами, не инвестируя финансовые средства в покупку специальной аппаратуры или инструментария разработки.

Пожалуйста имейте в виду, что отладчик Open Watcom будет разрешать прерывания между пошаговыми операциями - даже если делается пошаговое выполнение внутри критической секции. Это, к сожалению, делает невозможной пошаговую отладку процесса переключения контекста.

Лучший метод запуска исполняемого кода - прямо из командной строки, а не под управлением Open Watcom IDE.

[Дополнение 2: демонстрационные приложения (демо)]

Каждый официальный порт FreeRTOS поставляется с демо-приложениями, которые должны компилироваться без ошибок и генерации предупреждений компилятора (примечание: это конечно идеальный случай, однако зависит от версии используемого компилятора, которым компилируется демо. Обновленные компиляторы могут иногда генерировать предупреждения, которые их предшественники не делали). Демо-приложения предназначены для нескольких целей:

1. Предоставить пример рабочего и предварительно сконфигурированного проекта с корректно подключаемыми файлами и корректно установленными опциями компилятора.
2. Позволить экспериментировать с кодом 'прямо из коробки', с минимальными телодвижениями по настройке и с минимальными приобретенными знаниями.
3. Продемонстрировать API FreeRTOS.
4. Как база - образец для реальных создаваемых приложений.

Каждый демо-проект размещен в уникальной поддиректории внутри директории Demo (см. Дополнение 3). Имя директории будет показывать порт FreeRTOS, к которому относится проект.

Каждое демо-приложение также поставляется со страница документации, которая размещена на WEB-сайте FreeRTOS.org. Страница документации включает информацию по размещению индивидуальных демо-приложений в структуре директорий FreeRTOS.

Все демо-проекты создают задачи, которые определены в файлах исходного кода, которые размещены дереве директорий Demo\Common. Многие проекты используют файлы из директории Demo\Common\Minimal.

Файл с именем main.c включен в каждый проект. Он содержит функцию main(), из которой создаются все задачи демо-приложений. См. комментарии внутри каждого отдельного файла main.c для подробностей о том, что делает каждое специфическое демо-приложение.

FreeRTOS-pict44-demos.PNG

Рис. 44. Где находится документация по демо-приложениям в фрейме меню WEB-сайта FreeRTOS.org

[Дополнение 3: папки и файлы FreeRTOS]

Структура папок, описанная в этом Дополнении, относится только к файлу .zip, который можно загрузить с WEB-сайта FreeRTOS.org. Примеры, которые предоставлены с этой книгой, используют немного другую организацию.

Система FreeRTOS, загруженная как один файл .zip, содержит:

· Исходный код FreeRTOS. Этот код общий для всех портов FreeRTOS.
· Слой порта для каждой поддерживаемой комбинации микроконтроллера и компилятора.
· Файл проекта или makefile для сборки демо-приложения для каждой поддерживаемой комбинации микроконтроллера и компилятора.
· Набор демонстрационных задач, которые являются общими для всех демо-приложений. К этим демонстрационным задачам есть ссылки их демо-проектов, специфичных для отдельного порта FreeRTOS.

Файл .zip имеет две директории верхнего уровня под именами Source и Demo. Дерево директорий папки Source содержит всю реализацию ядра FreeRTOS - как общие компоненты, так и компоненты, специфические для каждого порта. Дерево директорий папки Demo содержит только проекты демо-приложений и файлы исходного кода, которые реализуют демонстрационные задачи.

FreeRTOS
   ¦
   +- Demo (исходный код демо-приложений и проекты)
   ¦
   +- Source (реализация ядра реального времени)

Рис. 45. Директории верхнего уровня - Source (исходный код) и Demo (демонстрационные приложения и задачи)

Исходный код ядра FreeRTOS содержится только в трех C-файлах, которые являются общими для всех портов микроконтроллеров. Они называются queue.c, tasks.c и list.c, и находятся прямо в папке Source. Файлы, специфичные для определенного порта, находятся в дереве папки Portable, которая также расположена в папке Source.

Четвертый опциональный файл исходного кода под названием croutine.c реализует функционал дополнительных подпрограмм FreeRTOS. Он должен быть подключен по необходимости в сборки, если эти дополнительные подпрограммы используются.

FreeRTOS
   ¦
   +- Demo (исходный код демо-приложений и проекты)
   ¦
   +- Source (реализация ядра реального времени)
   ¦
   +- tasks.c (один из трех файлов ядра)
   +- queue.c (один из трех файлов ядра)
   +- list.c (один из трех файлов ядра)
   +- portable (подкаталог для всех специфичных для порта файлов)

Рис. 46. Основное дерево файлов, на котором реализовано ядро FreeRTOS

Удаление неиспользуемых файлов. Главный файл .zip пакета FreeRTOS включает файлы для всех портов и всех демо-приложений, так что он содержит намного больше файлов, чем требуется для использования только одного порта. Используемый проект демо-приложения или makefile, сопровождающие порт, могут быть использованы как ссылка на файлы, которые нужны, и может позволить определить, какие файлы можно удалить.

Слой портирования - это код части FreeRTOS, относящийся к отдельной комбинации компилятора и архитектуры микроконтроллера. Файлы исходного кода слоя портирования размещены в папке FreeRTOS\Source\Portable\[compiler]\[architecture], где [compiler] - используемый набор средств проектирования (tool chain), и [architecture] - вариант используемого микроконтроллера.

· Все поддиректории в папке FreeRTOS\Source\Portable, которые не относятся к используемому компилятору, могут быть удалены, за исключением папки FreeRTOS\Source\Portable\MemMang.
· Все поддиректории в папке FreeRTOS\Source\Portable\[compiler], которые не относятся к используемому варианту микроконтроллера, может быть удалены.
· Все поддиректории в папке FreeRTOS\Demo, которые не относятся к используемому варианту демо-приложения, могут быть удалены, за исключением папки FreeRTOS\Demo\Common, которая содержит файлы используемые из всех демо-приложений.

Папка FreeRTOS\Demo\Common содержит намного больше файлов, чем те, которые используются только из одного демо-приложения, поэтому содержимое этой папки также может быть подчищено, если это необходимо.

[Дополнение 4: создание проекта FreeRTOS]

Адаптирование под приложение одного из предложенных демо-проектов. Каждый официальный порт FreeRTOS поставляется с предварительно сконфигурированными демо-приложениями, которые должны быть собраны без каких-либо ошибок или предупреждений компилятора (см. Дополнение 2). Новые проекты рекомендуется создавать, адаптируя один из этих существующих проектов. Таким способом можно получить проект, включающий корректный набор файлов и установок компилятора.

Чтобы начать новое приложение из существующего демо-проекта, нужно:

1. Открыть предоставленный демо-проект, и убедиться, что он нормально компилируется и выполняется, как и ожидалось.
2. Выбросите неиспользуемые файлы исходного кода, которые содержат демонстрационные задачи. Любой из файлов, находящийся в дереве папок Demo\Common, может быть удален из проекта или makefile.
3. Удалите все функции в файле main.c, кроме prvSetupHardware().
4. Проверьте, что все макро-константы configUSE_IDLE_HOOK, configUSE_TICK_HOOK и configCHECK_FOR_STACK_OVERFLOW файла FreeRTOSConfig.h установлены в 0. Это устранит поиск линкером всех функций хука. Функции хука могут быть при необходимости добавлены позже.
5. Создайте новую функцию main() по шаблону, показанному в листинге 77.
6. Проверьте, что проект все еще компилируются.

Выполнение этих шагов предоставит проект, который включает все файлы исходного кода FreeRTOS, но не задает никакой функциональности.

int main( void )
{
  /* Выполните любую необходимую настройку аппаратуры. */
  prvSetupHardware();
 
  /* --- ЗДЕСЬ МОГУТ БЫТЬ СОЗДАНЫ ЗАДАЧИ ПРИЛОЖЕНИЯ --- */
 
  /* Запуск на выполнение созданных задач. */
  vTaskStartScheduler();
 
  /* Выполнение дойдет до этого места только тогда, когда
     недостаточно памяти в куче для старта шедулера. */
  for( ;; );
  return 0;
}

Создание нового проекта с нуля. Как уже упоминалось, рекомендуется создавать новые проекты на основе существующих демонстрационных проектов. Если по некоторым причинам это нежелательно, то новый проект можно создать, выполнив следующие шаги:

1. Создайте новый пустой файл проекта или makefile, используя Вашу выбранную среду проектирования (tool chain).
2. Добавьте файлы, описанные в таблице 21 в новый созданный проект или makefile.
3. Скопируйте имеющийся готовый файл FreeRTOSConfig.h в папку проекта.
4. Добавьте и директорию проекта, и папку FreeRTOS\Source\include в пути проекта, по которым компилятор будет искать заголовочные файлы.
5. Скопируйте настройки компилятора из соответствующих (похожих по используемой среде проектирования и архитектуре микроконтроллера) демо-проекта или makefile. В частности, каждый порт требует установки макроса, который проверяет корректное подключение файлов заголовка в сборке. Например, сборки, предназначенные для MegaAVR и использующие компилятор IAR, требуют определения макроса IAR_MEGA_AVR, и сборки для ARM Cortex M3, использующие компилятор GCC, требуют определения макроса GCC_ARMCM3. Эти определения используются в файле FreeRTOS\Source\include\portable.h, который может быть просмотрен, когда не очевидно - какое макроопределение надо использовать.

Таблица 21. Исходные файлы FreeRTOS для включения в проект

Файл
Размещение
tasks.c FreeRTOS\Source
queue.c FreeRTOS\Source
list.c FreeRTOS\Source
port.c FreeRTOS\Source\portable\[compiler]\[architecture], где [compiler] - используемый набор средств проектирования (tool chain), и [architecture] - вариант используемого микроконтроллера.
port.x Некоторые порты также требуют, чтобы к проекту был подключен файл ассемблера. Этот файл находится в той же папке, что и port.c. Расширение имени файла зависит от используемого tool chain, так что расширение .x должно быть заменено реальным расширением имени ассемблерного файла.

Заголовочные файлы. Файлы исходного кода, которые используют FreeRTOS API, должны подключить заголовочный файл FreeRTOS.h, содержащий прототипы используемых API функций - “task.h”, “queue.h” или “semphr.h”.

[Дополнение 5: типы данных и руководство по стилю кодирования]

Типы данных. Каждый порт FreeRTOS имеет уникальный файл заголовка portable.h, в котором определен набор макросов, который детально описывает используемые типы данных. Весь исходный код FreeRTOS и демо-приложения используют эти макроопределения, а не прямое использование типов данных C - однако нет никаких причин, чтобы приложения, которые используют FreeRTOS, должны делать то же самое. Разработчики приложения могут подставить реальные типы данных для каждого макроса, определенного в таблице 22.

Таблица 22. Типы данных, используемые FreeRTOS

Макрос или typedef
Действительный используемый тип
portCHAR char
portSHORT short
portLONG long
portTickType Используется для сохранения счетчика тиков и указания времени блокировки.
portTickType может быть либо беззнаковым (unsigned) 16-битным чипом, либо беззнаковым 32-битным, в зависимости от установки configUSE_16_BIT_TICKS в файле FreeRTOSConfig.h.
Использование 16-битного типа может значительно повысить эффективность кода для 8 и 16 разрядных архитектур микроконтроллеров, но при этом накладываются некоторые ограничения на диапазон времени блокировки, который можно задать. Нет смысла использовать 16-битный тип для 32-битных архитектур.
portBASE_TYPE Здесь определен самый эффективный тип для архитектуры микроконтроллера. Обычно это должен быть 32-битный тип для 32-разрядной архитектуры, 16-битный для 16-разрядной и соответственно 8-битный тип для 8-разрядной.
portBASE_TYPE используется главным образом для возвращаемых типов, которые могут иметь очень ограниченный диапазон, и для двоичного типа (bool).

Некоторые компиляторы считают char с не указанным знаком как unsigned (без знака), тогда как другие компиляторы - как signed (со знаком). По этой причине исходный код FreeRTOS явно указывает каждое использование portCHAR либо как signed, либо как unsigned.

Тип int не используется никогда - только long и short.

Имена переменных. Имена переменных имеют префикс, соответствующий их типу. Префикс 'c' применяется для char, 's' для short, 'l' для long и 'x' для portBASE_TYPE

и любого другого типа (структуры, хендлы задач, хендлы очередей и т. п.).
 
Если переменная беззнаковая (unsigned), она также имеет префикс 'u'. Если переменная является указателем, то она имеет префикс 'p'. Таким образом, переменная типа unsigned char будет иметь префикс 'uc', и переменная типа указателя на char будет иметь префикс 'pc'.

Имена функций. Функции имеют префикс для того же типа данных, который они возвращают. Префикс также включает в себя признак имени файла, где функция определена. Например:

· vTaskPrioritySet() возвращает void и определена в файле task.c.
· xQueueReceive() возвращает переменную типа portBASE_TYPE, и определена в файле queue.c.
· vSemaphoreCreateBinary() возвращает void и определена в файле semphr.h.

Файлы, действующие в пределах одного файла (private) имеют префикс 'prv'.

Форматирование. 1 таб (символ табуляции с ASCII кодом 09h) соответствует 4 символам пробела.

Имена макросов. Большинство макросов написаны заглавными буквами, и имеют префикс из маленьких букв, который показывает, где определен макрос. В таблице 23 предоставлен список префиксов.

Таблица 23. Префиксы макросов

Префикс
Размещение определения макроса
port (например, portMAX_DELAY) portable.h
task (например, taskENTER_CRITICAL()) task.h
pd (например, pdTRUE) projdefs.h
config (например, configUSE_PREEMPTION) FreeRTOSConfig.h
err (например, errQUEUE_FULL) projdefs.h

Имейте в виду, что API семафоров написано почти полностью как набор макросов, однако оно следует стилю именования функций, а не стилю именования макросов.

Макросы, определенные в таблице 24, используются повсюду в исходном коде FreeRTOS.

Таблица 24. Общие макроопределения

Макрос
Значение
pdTRUE 1
pdFALSE 0
pdPASS 1
pdFAIL 0

Рациональность излишних преобразований типов (type casting). Исходный код FreeRTOS может быть скомпилирован несколькими разными компиляторами, каждый из который имеет свои причуды - как и когда генерировать предупреждения. В частности, разные компиляторы хотят видеть приведение типов, реализованное разными способами. В результате исходный код FreeRTOS содержит больше приведений, чем обычно необходимо.

[Дополнение 6: информация о лицензировании]

FreeRTOS лицензируется под защитой модифицированной версии GNU General Public License (GPL), и может использоваться в коммерческих приложениях под этой лицензией. Альтернативно и дополнительно доступна коммерческая лицензия, если:

· Вы не можете выполнить требования, установленные в столбце "Open Source Modified GPL license" таблицы 25.
· Вы хотите получить прямую техподдержку.
· Вы хотите получить помощь в Вашей разработке.
· Вам нужны гарантии и возмещение убытков.

Таблица 25. Сравнение двух лицензий - Open Source (открытые исходники) и коммерческой

  "Open Source Modified GPL license"
Коммерческая лицензия
FreeRTOS открыт? да нет
Можно ли FreeRTOS использовать в коммерческом приложении? да да
Свободна ли FreeRTOS от требований выплат роялти? да да
Нужно ли мне открыть исходный код моего приложения? нет нет
Нужно ли мне открыть исходный код моих изменений ядра FreeRTOS? да нет
Нужно ли мне документировать, что мой продукт использует FreeRTOS? да нет
Должен ли я предложить обеспечивать предоставление исходного кода FreeRTOS пользователям моего приложения? да (достаточно WEB-ссылки на сайт FreeRTOS.org) нет
Могу ли я получить поддержку на коммерческой основе? нет да
Есть ли какие-нибудь законные гарантии? нет да

Подробное описание лицензии на открытый код. Исходный код FreeRTOS лицензируется под защитой версии 2 GNU General Public License (GPL), имеющей исключение. Полный текст GPL доступен по ссылке [4]. Текст исключения предоставлен ниже.

Исключение разрешает закрытие исходного кода для приложений, которые используют исходный код FreeRTOS исключительно через API, опубликованный на сайте FreeRTOS.org, чем разрешает использование FreeRTOS в коммерческих приложениях без требования открыть исходный код всего приложения. Исключение можно использовать только если Вы хотите скомбинировать FreeRTOS с проприетарным продуктом, и Вы выполняете требования, указанные в самом исключении.

Текст исключения из лицензии GPL. Имейте в виду, что текст исключения может быть изменен. Обратитесь на сайт FreeRTOS.org для получения его самой свежей версии.

[Словарик]

atomic, атомарная операция относится к такому действию, которое в многозадачной среде, если будет запущено, то обязательно завершится с успехом, и никакой посторонний код не может на повлиять на результат выполнения операции. Примером атомарной операции может служить любая элементарная команда на языке ассемблера - к примеру, инкремент 8-битного регистра на 8-битном процессоре. Если же на этом же процессоре мы попытаемся выполнить операцию по инкременту 32-битной переменной, то эта операция не всегда может считаться атомарной, так как её теоретически может прервать любой другой процесс, и повлиять на результат операции. Этим другим процессом может быть, к примеру, некорректно написанное прерывание. Чтобы добиться атомарности и этой операции - в нашем примере инкремент 32-битной переменной на 8-битной машине - то нужно обеспечить запрет любых посторонних действий на время выполнения операции (например, это может быть запрет прерывания в начале операции и разрешение прерываний по завершению операции).

callback, функция обратного вызова специально предусмотренная в коде функция, тело которой может предоставить пользователь. Предназначена для пользовательской модификации стандартного функционала чего-либо, например для обработки пользователем каких-то событий FreeRTOS. Обычно то же самое, что и хук (hook).

deferred отложенное выполнение (прерывания).

embedded встраиваемая система (электронная система с применением микроконтроллера).

GATEKEEPER, гейткипер привратник - специальная задача, которая имеет монопольный доступ к какому-то ресурсу (например, порт ввода/вывода или UART). Гейткипер применяется для устранения конфликтов совместного доступа разными задачами к одному и тому же ресурсу.

HWM high water mark величина, до которой наросло использование стека (по аналогии с ватерлинией - до какой самой верхней отметки корпуса дошла вода при загрузке корабля).

Idle ожидание.

Idle task специальная задача ожидания, которая всегда автоматически запускается в системе FreeRTOS. Имеет минимальный приоритет и несет специальные функции - она нужна для вытеснения другими задачами и для уборки мусора при удалении задач.

ISR, Interrupt Service Routine подпрограмма обработчика прерывания.

LCD ЖКИ, жидкокристаллический дисплей.

mutex, мьютекс специальный объект, помогающий при многозадачности реализовать взаимное исключение выполнения задач, что важно для исключения одновременного доступа к общему ресурсу (слово mutex образовалось как сокращение от mutual exclusion)

mutual exclusion взаимное исключение - термин, касающийся атомарных операций с ресурсами памяти.

Not Running не запущено - состояние задачи, когда она находится в неактивном состоянии (не выполняется). Состояние Not Running имеет подсостояния Blocked, Ready, Suspended.

pre-emption, вытеснение механизм поддержки приоритета выполнения, когда одна задача (с более высоким приоритетом) принудительно запускается, останавливая (вытесняя) другую задачу (с более низким приоритетом).

recurrent, рекуррентная функция - функция, которая может вызвать саму себя (почти) неограниченное количество раз для проведения каких-то вычислений. Хорошим примером рекуррентности могут служить действия по автоматизированному просмотру/поиску вложенных папок и файлов на диске.

reentrant, реентрантная функция термин относится к многозадачной среде выполнения, и применяется к функциям и подпрограммам. Функция или подпрограмма считается реентрантной, если она написана так, что если выполнение функции будет остановлено в любом месте (например, при прерывании или переключении контекста), и функция будет вызвана заново (сначала) уже в новом контексте, то это никак не повлияет на успешную работу функции. Т. е. функция всегда успешно завершит свою работу, будучи одновременно запущенной и/или приостановленной в разных контекстах. К реентерабельным нельзя отнести такие функции и подпрограммы, которые обращаются к глобальным переменным или имеют в своем теле статические переменные.

Running запущено - состояние задачи, когда она находится в активном состоянии (выполняется).

scheduling, шедулинг механизм управления задачами - смена состояния задач, переключение между задачами с целью организации их совместного выполнения.

sheduler, шедулер специальный код RTOS, который занимается перелючением контекста. Это означает, что в момент каждого тика системы RTOS шедулер принимает решение, какой задаче передать процессорное время. Шедулер работает по алгоритму, учитывающему приоритеты задач.

Task задача.

TCB task control block - блок управления задачей. Специальная структура в памяти, хранящая данные задачи.

tick, тик элементарный интервал (квант) времени, который определяет скорость реакции RTOS на различные события. Типичная длительность тика может составлять от 0.1 до 15 мс, в зависимости от требований приложения RTOS и мощности используемого процессора (или микроконтроллера). На каждом тике запускается планировщик RTOS, и в этот момент может произойти переключение контекста выполнения на другую задачу.

детерминированный (процесс, подпрограмма, алгоритм) означает, что время выполнения этого процесса (подпрограммы, алгоритма) остается неизменным от вызова к вызову.

исключение обычно специальное прерывание, которое срабатывает при ошибке выполнения кода микроконтроллером (например, недопустимая команда, переполнение стека или нарушение защиты памяти).

контекст (выполнения) место в коде, который выполняется микроконтроллером. Например, микроконтроллер выполняет задачу A, тогда говорят, что сейчас имеет место контекст задачи A. Если микроконтроллер сейчас обрабатывает прерывание (работает код ISR), то говорят, что сейчас активен контекст прерывания, или контекст ISR. Часто под контекстом также подразумевают состояние регистров микроконтроллера, сохраненное в стеке.

куча, heap пул (блок) свободной памяти, предназначенный для динамического выделения (т. е. во время выполнения приложения) под различные нужды приложения пользователя (в том числе и под нужды FreeRTOS).

порт FreeRTOS версия FreeRTOS, написанная и оптимизированная для какого-то специфичного микроконтроллера или семейства микроконтроллеров (учитывающая особенности архитектуры выбранного микроконтроллера). Например, может быть порт FreeRTOS для Atmel ARM7 или порт FreeRTOS для Analog Devices BlackFin DSP.

токен билетик, флажок, означающий что-то.

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

планировщик специальный код, который занимается переключением контекста (то же самое, что и шедулер).

цель, target имеется в виду среда исполнения приложения FreeRTOS - либо DOS, либо микроконтроллер.

хук, hook (переводится как крючок) привязка к какому то событию, например к началу выполнения задачи. Обычно то же самое, что и callback.

[Ссылки]

1. Обзор FreeRTOS на русском языке - Андрей Курниц, статья в журнале «Компоненты и технологии» (2..10 номера 2011 года).
2. http://www.openwatcom.org.
3. http://www.dosbox.com.
4. http://www.freertos.org/license.txt.
5. 150422FreeRTOS-API.pdf - документация по API FreeRTOS 8.2.х на английском языке.

 

Комментарии  

 
+1 #5 Дёня 08.03.2023 16:44
Огромное спасибо автору! 8)
Цитировать
 
 
+10 #4 Павел 16.12.2017 07:35
Буквально гора с плеч. Слов нет. Снимаю шляпу...
Цитировать
 
 
+12 #3 Разработчик 04.03.2017 15:41
Очень помогло в связи в освоении FREERTOS. Огромное спасибо ;-)
Цитировать
 
 
+7 #2 Banka_salidola 04.02.2016 13:39
Очень полезный цикл статеек! Уже закладках)
СПАСИБО!
Цитировать
 
 
+7 #1 Stari40k 28.05.2015 19:34
Спасибо огромное. Прочитал все даже добавил в закладки, доступно и ничего лишнего.
Цитировать
 

Добавить комментарий


Защитный код
Обновить

Top of Page