Встроенная архитектура прошивки - PullRequest
0 голосов
/ 04 сентября 2018

Я пишу все более сложные прошивки и начинаю замечать, что мне немного не хватает знаний о шаблонах проектирования и архитектуре. Я пытаюсь работать над развитием этих навыков и надеюсь на какой-то вклад. Примечание: это для встроенного c для микроконтроллеров.

Сейчас я работаю с концепцией для нового проекта в качестве упражнения, которое выглядит примерно так:

  1. У нас есть модуль управления батареями с пользовательским вводом / выводом
  2. Главный контроллер отвечает за ввод / вывод (кнопка, ЖК-дисплей, отладка UART), обнаружение таких вещей, как зарядное устройство, подключенное / отключенное, и управление операциями высокого уровня.
  3. Субконтроллер представляет собой контроллер управления батареями (в значительной степени пользовательский PMIC), способный контролировать уровни заряда батареи, запускать зарядку / разрядку встроенного программного обеспечения и т. Д.
  4. PMIC взаимодействует с ИС датчика уровня топлива, которую он использует для считывания информации о батарее из
  5. Интерфейс между двумя контроллерами, указателем уровня топлива и ЖК-дисплеем, все I2C

Вот примерная схема системы:

enter image description here

Теперь я пытаюсь придумать хорошую архитектуру прошивки, которая позволит расширить возможности (добавление нескольких батарей, добавление дополнительных датчиков, изменение интерфейса LCD (или другого) с I2C на SPI и т. Д.), и для тестирования (смоделируйте нажатия кнопок через UART, замените показания батареи на смоделированные значения для проверки встроенного ПО заряда PMIC и т. д.).

Обычно я пишу собственный драйвер для каждого периферийного устройства и модуль прошивки для каждого блока. Я бы также внедрил модуль пометки с глобально доступным get / set, который будет использоваться во всей системе. Например, мои таймеры установят флаги 100 Гц, 5 Гц, 1 Гц, которые будет обрабатывать основной цикл и вызывать отдельные модули с желаемой частотой. Затем сами модули могут установить флаги для основного цикла для обработки таких событий, как завершение транзакции I2C, тайм-аут транзакции, превышение температуры и т. Д.

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

enter image description here

enter image description here

1 Ответ

0 голосов
/ 04 сентября 2018

Концепция «шины событий» слишком сложна. Во многих случаях самый простой подход состоит в том, чтобы минимизировать количество вещей, которые должны происходить асинхронно, но вместо этого использовать подпрограмму «основного опроса», которая выполняется «так часто, как это удобно» и вызывает подпрограммы опроса для каждой подсистемы. Может быть полезно иметь такую ​​подпрограмму в самой компиляции, чтобы сущность этого файла была просто списком всех опрашивающих функций, используемых другими подсистемами, а не чем-либо с собственной семантикой. Если у кого-то есть процедура «получить нажатие кнопки», у нее может быть цикл внутри этой процедуры, который вызывает основную процедуру опроса до тех пор, пока не будет нажата кнопка, не произойдет таймаут клавиатуры или произойдет что-то еще, с чем нужно иметь дело вызывающей стороне. Это позволило бы реализовать основной пользовательский интерфейс с использованием кода, подобного следующему:

void maybe_do_something_fun(void)
{
  while(1)
  {
    show_message("Do something fun?");
    wait_for_button();
    if (button_hit(YES_BUTTON))
    {
      ... do something fun
      return;
    }
    else if (button_hit(NO_BUTTON))
    {
      ... do something boring
      return;
    }
  } while(1);
}

Это часто намного удобнее, чем пытаться создать гигантский конечный автомат и сказать, что если код находится в состоянии STATE_MAYBE_DO_SOMETHING_FUN и нажата кнопка yes или no, ему нужно перейти к STATE_START_DOING_SOMETHING_FUN или STATE_START_DOING_SOMETHING_BORING гос.

Обратите внимание, что если кто-то использует этот подход, он должен будет гарантировать, что наихудшее время между вызовами main_poll всегда будет удовлетворять требованиям своевременности операций опроса, обработанных через main_poll, но в тех случаях, когда это требование может быть Этот подход может оказаться гораздо более удобным и эффективным, чем выполнение всего необходимого для приоритетного планирования многопоточного кода вместе с блокировками и другими средствами защиты, необходимыми для его надежной работы.

...