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

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

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

Пока остановился на такой реализации периферии: класс с минимально-необходимым интерфейсом.
Код
class Uart1
{
public:
    enum Baudrate
    {
      ...
    };


    Uart1();
    void setBaudrate(Baudrate b);
    void write(uint8_t * data, uint32_t size);
...
private:
    DMA_HandleTypeDef mDmaTx;
    UART_HandleTypeDef mUart;
...
};


Реализация по месту, без особых обобщений.
Код
void Uart1::write(uint8_t * data, uint32_t size)
{
    __HAL_DMA_DISABLE(&mDmaTx);
    
    mUart.Instance->CR3 &= ~USART_CR3_DMAT;

    mDmaTx.Instance->CPAR = reinterpret_cast<uint32_t>(&mUart.Instance->TDR);

    mDmaTx.Instance->CMAR = reinterpret_cast<uint32_t>(data);
    
    const uint32_t dataLength = size;
    mDmaTx.Instance->CNDTR = dataLength;
    
    mUart.Instance->CR3 |= USART_CR3_DMAT;
    __HAL_DMA_ENABLE(&mDmaTx);
}


Если нужна другая инициализация модуля - меняю *cpp файл модуля.

Пока думаю, что проект для всех вариантов ПО должен быть один и все версии файлов должны быть в нем.

Так вот, что делать с файлами периферии?

1. Можно раскинуть по папкам
version1/uart1.cpp
version2/uart1.cpp
Но не компилируется - объектные файлы с одинаковыми именами.

2. Можно менять им имена в зависимости от версии
uart1_ver1.cpp
uart1_ver2.cpp
И тогда придется еще вводить для каждой версии свое пространство имен, если хочу сохранить имя класса единое.
Не эстетично rolleyes.gif

3. Как-то организовать на уровне системы контроля версий. Пока не понимаю как, при условии, что все версии нужно вести параллельно.

4. Сделать header only файлы периферии. Не очень красиво, не рекомендуют.
Сергей Борщ
QUOTE (Slash @ Dec 20 2016, 00:55) *
1. Можно раскинуть по папкам
version1/uart1.cpp
version2/uart1.cpp
Но не компилируется - объектные файлы с одинаковыми именами.
Не включайте в проект не относящиеся к нему директории. Ибо даже если вы дадите файлам разные имена и оно у вас скомпилируется - не пройдет линковка, ведь у вас в этих файлах функции с одинаковыми названиями.
QUOTE (Slash @ Dec 20 2016, 00:55) *
3. Как-то организовать на уровне системы контроля версий. Пока не понимаю как, при условии, что все версии нужно вести параллельно.
Я совсем недавно пришел к такой системе - в одном репозитории хранится общий для многих проектов код - заголовочные файлы CMSIS, исходники scmRTOS, lwIP, реализация AES-декодирования для загрузчика, какие-то специфичные файлы, использующиеся более чем в одном проекте. Проекты хранятся в других репозиториях, каждый проект состоит из директорий common (общие для этого железа файлы), bootloader, application. В application может быть несколько директорий для разных вариантов ПО. Общий репозиторий я подключаю как внешний (svn:externals) в директорию common. А дальше уже в makefile подключаю к проекту только те директории, которые мне нужны в этом проекте. При этом в общем репозитории у меня лежит generic_uart.cpp с реализацией неизменных функций, а на уровне проекта у меня есть файл uart.cpp с реализацией недостающих функций под конкретный проект. И если у меня УАСПП во всех исполнениях ПО инициализируются одинаково, то я делаю один uart.cpp с функцией uart::init(), кладу его в common/uart и подключаю ее к проекту. Если в каком-то одном исполнении или в загрузчике мне нужна другая инициализация - то я кладу другой uart.cpp в директорию bootloader или application/variant1 и убираю из makefile этой прошивки подключение common/uart.
Еще вариант - в общем репозитории хранится класс generic_uart, а в проекте - отнаследованный от него uart, у которого добавлена функция init.
Третий вариант - в общем репозитории класс generic_uart делается шаблоном, параметр шаблона используется как базовый класс. А уже этот базовый класс реализуется в каждом конкретном проекте - таким образом я использую два варианта dma (потоки и каналы) в исходниках для разных stm32.

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

При фиксации стабильной версии в tags я делаю правку в svn:externals, указывая там текущую на момент фиксации версию внешнего общего репозитория.
jcxz
Цитата(Сергей Борщ @ Dec 20 2016, 10:06) *
Я совсем недавно пришел к такой системе -
...

Легко Вам - пишете всё под один МК.
HardEgor
Цитата(Slash @ Dec 20 2016, 05:55) *
Сделана плата на основе микроконтроллера. Нужно одновременно поддерживать несколько версий встроенного ПО.
Помимо логики работы, версии отличаются инициализацией периферийных модулей.

Если у вас всё такое разное - то не вижу смысла усложнять, делайте отдельные каталоги для каждого проекта и всё.
А так вы усложняете код множеством условных директив и запутываете поддержку.
Возможно какие-то общие алгоритмы стоит вынести в отдельные файлы и всё.
Dog Pawlowa
Цитата(jcxz @ Dec 20 2016, 14:08) *
Легко Вам - пишете всё под один МК.

Какая разница?
У меня есть в одном воркспейсе два проекта под разные контроллеры одного семейства, есть в двух воркспейсах два проекта, использующие общие файлы, для разных контроллеров разных семейств.
Что касается директив условной компиляции, то стараюсь не злоупотреблять, если зашкаливает, делаю разные файлы.
zltigo
Цитата(jcxz @ Dec 20 2016, 13:08) *
Легко Вам - пишете всё под один МК.


Какая разница? У меня достаточно похоже, на то, что описал Сергей. Но, например, проект над которым вот прямо сейчас работаю, собирается из достаточно большого количества общих исходников и заголовков на:
1) Cortex-M3
1) ARM7
2) BA2
3) M8C
4) PC/Win
5) PC/Lin

При этом ARM7 - две железки
BA2 - 2 железки и 6 (пока только)вариантов софта
M8C - два варианта софта
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.