Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: С/C++ библиотека для embedded применений
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
dxp
Всем привет!

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

Для того, чтобы результат проделанной работы был полезен ещё кому-то, упомянутые библиотеки опубликованы на github.com. Реализовано всё это в виде коллекции git репозиториев под общим названием emb-lib: https://github.com/emb-lib

Проект этот открытый, если у кого-то есть наработки в виде библиотек для embedded применений и есть желание поделиться с коллегами, приглашаю к участию. Технически любая такая библиотека — просто отдельный git репозиторий в составе emb-lib. В рабочий проект можно подключить либо как подмодуль git, либо просто скачать файлы. Каждый репозиторий имеет свою Wiki страницу, на которой можно поместить краткую документацию по библиотеке (состав, использование и т.д.).

* * *

Собственно, библиотек на данный момент три:
  • библиотека форматированного ввода/вывода (по факту пока только вывод);
  • менеджер памяти;
  • библиотека поддержки режима bare-metal C++ для ADI GNU Toolchain (bfin-elf).

Первые две библиотеки являются кроссплатформенными.

* * *

Библиотекой форматированного вывода поделился Сергей Борщ. Мы с ним пытались найти авторов, но этого не удалось достичь, история появления этого кода уходит в прошлое и следы теряются. Удалось только найти несколько клонов с разным количеством изменений на открытых площадках (github.com, sourceforge.net) Надеюсь, авторы не будут в претензии, что их код предлагается к открытому использованию.

Библиотека поддерживает форматированный вывод целых, типов с плавающей точкой, строк. Для включения поддержки плавающей точки нужно определить макрос PRINTF_FLOAT (это удобно сделать через передачу макроса в командной строке - в большинстве компиляторов через опцию -D).

Библиотека не содержит функции printf, реализация которой предоставляется пользователю. И это правильно — конечная реализация этой функции зависит от требований целевого проекта (нужна ли потокобезопасность) и возможностей аппаратной платформы (порт для вывода). Пример такой функции приведён на странице библиотеки.

* * *

Менеджер памяти. Собственно сам менеджер heap_z был разработан и опубликован тут же на электрониксе zltigo лет пять-шесть назад, и, насколько понимаю, немало народу с этим кодом знакомо и успешно использует. Поделился этим опять Сергей Борщ в варианте C++-обёртки. Код претерпел некоторые изменения (настройка поддержки многопоточности, перевод комментариев, пользовательский интерфейс), но суть (идеология, алгоритм выделения/освобождения памяти) да и основой рабочий код остались без изменений. Добавления коснулись в основном интерфейса пользователя: С++ интерфейс (набор new/delete), параметризация с помощью шаблонов С++, простой и безопасный вариант объявления массива под heap. Добавлена краткая справка, она доступна на Wiki странице https://github.com/emb-lib/heap_z/wiki репозитория библиотеки. Библиотека публикуется с согласия автора.

Все объявления и определения менеджера памяти помещены в пространство имён heap. Использование менеджера памяти достаточно простое и сводится к двум действиям:
  • объявить массив памяти под пул;
  • объявить объект менеджера памяти.

CODE
heap::pool<4096> HeapPool;  // size in bytes

heap::manager<heap_guard> heap::Manager(HeapPool);

Поскольку библиотека может использоваться в многопоточных программах, там предусмотрено средство для защиты от одновременного доступа (heap_guard) — для RTOS это, как правило, mutex. Этот момент нуждается в конфигурации, но там всё достаточно просто. Подробнее — на Wiki странице.

* * *

Библиотека для bfin-elf возникла из-за того, что упомянутый тулчейн штатно не включает в себя всё необходимое для bare-metal режима с поддержкой С++, а реализация некоторых стандартных модулей не на высоте (подробности тут).

Библиотека содержит:
  • функцию для регистрации обработчиков исключений;
  • weak функцию _init, необходимую библиотечной функции, осуществляющей вызов конструкторов глобальных объектов;
  • минимальный стартап (crt.S);
  • несколько интринсиков;
  • низкоуровневые функции настройки pll/clock;
dxp
Добавлена библиотека arm-none-eabi-startup.

Библиотека содержит универсальный startup для C/C++ и таблицы векторов для популярных МК. Стартап очень простой:

CODE
void Reset_Handler()
{
    if( __low_level_init() )
    {
        memcpy(__data_start, __idata_start, __data_end - __data_start); // copy initialized variables
        memset(__bss_start, 0, __bss_end - __bss_start);                // zero-fill uninitialized variables
        __libc_init_array();                                            // low-level init & ctor loop
    }
    main();
}


и позволяет:
  • запускать пользовательский код до статической инициализации (могут потребоваться какие-то низкоуровневые манипуляции с аппаратурой) путём определения свой версии функции __low_level_init;
  • пропускать стандартную инициализацию вообще (например, работа при "тёплом" старте) - для этого вернуть 0 из __low_level_init;
  • выполнять пользовательский код между статической и динамической инициализацией (т.е. после инициализации глобальных переменных и перед вызовом конструкторов) - определить свою функцию _init (void _init(void) - эта функция вызывается из библиотечной __libc_init_array);

Всё это по желанию пользователя.

Для использования нужно определить несколько символов в линкерном скрипте:

CODE
__idata_start - начало секции с инициализаторами
__data_start  - начало секции инициализируемых данных (.data)
__data_end    - конец секции инициализируемых данных
__bss_start   - начало секции обнуляемых данных (.bss)
__bss_end     - конец секции обнуляемых данных


Таблицы векторов организованы в виде пары файлов на каждый МК. Два файла используются для удобства, чтобы не загромождать код. Каждая пара лежит в отельной директории по названию МК (с сохранением регистра букв), чтобы упростить подключение в makefile.

Для инициализации указателя стека необходимо в линкерном скрипте определить символ __top_of_stack, например:

CODE
...
MEMORY
{
    RAM (xrw)   : ORIGIN = 0x20000000, LENGTH =  112K
    FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 1024K
}
...
PROVIDE ( __top_of_stack = ALIGN(ORIGIN(RAM) + LENGTH(RAM) - 8 ,8) );
...


Используется значение макроса NDEBUG для конфигурирования (посоветовал Сергей Борщ) - в режиме дебага каждый вектор является отдельной функцией (хотя они все кроме одной одинаковы), чтобы можно было определить, в какой handler улетела программа, если такое случается. Без дебага все вектора ссылаются на одну и ту же функцию, что даёт экономию памяти программ.

Обработчик Hard Fault отличается от остальных умолчательных (тоже приём от Сергея Борща):

CODE
static void hf_handler()
{
    volatile int i = 0;         //  debug variable: set non-zero value to
    while(!i) { }               //  return from handler - this figures out
                                //  an address where HW fault raises
}


Если возникает исключение Hard Fault, то находясь в отладчике в режиме останова в этой функции, пользователь может модифицировать значение i, чтобы осуществить выход из обработчика, при этом программа окажется в том месте, где активировалось исключение.

В заключение. Файлы векторов писались не руками, они сгенерированы скриптом из ассемблерных файлов векторов в формате ARM. Т.ч. при необходимости перечень поддерживаемых МК может быть легко расширен. В настоящее время в библиотеку помещены те, которые попались под руку. sm.gif
x893
Под ARMCC будет компилироваться ?
dxp
QUOTE (x893 @ Apr 21 2016, 17:34) *
Под ARMCC будет компилироваться ?

Если это не GCC, то нет.
Make_Pic
Цитата(dxp @ Apr 21 2016, 11:15) *
Добавлена библиотека arm-none-eabi-startup.
...


А почему нет STM32F3 и не одного Kinetis?
dxp
QUOTE (Make_Pic @ Apr 22 2016, 04:54) *
А почему нет STM32F3 и не одного Kinetis?

Не попались под руку. sm.gif Подскажите ссылку, по которой скачать startup_xxx.s, и будет добавлено.
zltigo
В незапямятные времена, когда только начинал работать с ARM7, написал абсолютно минималистичную функцию-заменитель printf().
CODE
//---------------------------------------------------------------------------
// Very simple, but fast "printf" routine.
// Supported formats:
//         %u %1u...8u- Decimal  %u equ %4u  %1u...%8u  equ %01u...%08u
//         %X %1X...8X- Hex      %X equ %4X  %1X...%8X  equ %01X...%08X
//         %1*...8*   - Hex      ( * - any char ) equ %01X...%08X
//         %c - Character
//         %s - String
//---------------------------------------------------------------------------
void xprintf( const char *format, ... )
{

Все жестко оптимизировалось под ARM7 и IAR. Видимо уже что-то можно и нужно менять sm.gif, но у меня, как ни странно она с тех пор так и живет без всяких изменений под все, что попало Если кому интересно, могу выложить.
ViKo
Цитата(zltigo @ Apr 22 2016, 14:32) *
В незапямятные времена ... Если кому интересно, могу выложить.

http://electronix.ru/forum/index.php?showt...st&p=777223
Мы не злопамятные, просто память хорошая. laughing.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.