Перейти к содержанию
    

Как организовать проект: одна плата - много версий embedded ПО?

Здравствуйте!

 

Сделана плата на основе микроконтроллера. Нужно одновременно поддерживать несколько версий встроенного ПО.

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

 

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

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

И не всегда получается хорошо абстрагировать модуль, чтобы охватывались все варианты.

 

Пока остановился на такой реализации периферии: класс с минимально-необходимым интерфейсом.

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:

 

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

 

4. Сделать header only файлы периферии. Не очень красиво, не рекомендуют.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. Можно раскинуть по папкам

version1/uart1.cpp

version2/uart1.cpp

Но не компилируется - объектные файлы с одинаковыми именами.

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

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, указывая там текущую на момент фиксации версию внешнего общего репозитория.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я совсем недавно пришел к такой системе -

...

Легко Вам - пишете всё под один МК.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сделана плата на основе микроконтроллера. Нужно одновременно поддерживать несколько версий встроенного ПО.

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

Если у вас всё такое разное - то не вижу смысла усложнять, делайте отдельные каталоги для каждого проекта и всё.

А так вы усложняете код множеством условных директив и запутываете поддержку.

Возможно какие-то общие алгоритмы стоит вынести в отдельные файлы и всё.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Легко Вам - пишете всё под один МК.

Какая разница?

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

Что касается директив условной компиляции, то стараюсь не злоупотреблять, если зашкаливает, делаю разные файлы.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Легко Вам - пишете всё под один МК.

 

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

1) Cortex-M3

1) ARM7

2) BA2

3) M8C

4) PC/Win

5) PC/Lin

 

При этом ARM7 - две железки

BA2 - 2 железки и 6 (пока только)вариантов софта

M8C - два варианта софта

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...