嵌入式固件架构

奥图斯

我一直在编写越来越复杂的固件,并且开始注意到我对设计模式和体系结构的知识有点缺乏。我正在努力发展这些技能,并希望能提供一些意见。注意:这是用于嵌入式c的微控制器。

我现在正在将一个新项目的概念作为练习,它是这样的:

  1. 我们有一个带有用户I / O的电池管理模块
  2. 主控制器负责I / O(按钮,LCD,UART调试),检测充电器的插入/拔出以及管理高级操作。
  3. 子控制器是电池管理控制器(几乎是自定义PMIC),能够监视电池电量,运行充电/放电固件等。
  4. PMIC与电量计IC相连,用于从中读取电池信息
  5. 两个控制器,电量计和LCD之间的接口均为I2C

这是一个粗略的系统图:

在此处输入图片说明

现在,我要尝试的是提供一个良好的固件体系结构,该体系结构将具有可扩展性(添加多个电池,添加更多传感器,将LCD(或其他)接口从I2C更改为SPI等)并进行测试(通过UART模拟按钮按下,将电池读数替换为模拟值以测试PMIC充电固件等)。

What I would normally do is write a custom driver for each peripheral, and a firmware module for each block. I would implement a flagging module as well with a globally available get/set that would be used throughout the system. For example my timers would set 100Hz, 5Hz, 1Hz, flags, which the main loop would handle and call the individual modules at their desired rate. Then the modules themselves could set flags for the main loop to handle for events like I2C transaction complete, transaction timed out, temperature exceeded, etc.

What I am hoping to get from this is a few suggestions on a better way to architect the system to achieve my goals of scalability, encapsulation and abstraction. It seems like what I’m doing is sort of a pseudo event-driven system but one that’s been hacked together. In any case here’s my attempt at an architecture diagram:

在此处输入图片说明

在此处输入图片说明

supercat

The concept of an "event bus" is over-complicated. In many cases, the simplest approach is to minimize the number of things that need to happen asynchronously, but instead have a "main poll" routine which runs on an "as often as convenient" basis and calls polling routines for each subsystem. It may be helpful to have such routine in a compilation by itself, so that the essence of that file would simply be a list of all polling functions used by other subsystems, rather than anything with semantics of its own. If one has a "get button push" routine, one can have a loop within that routine which calls the main poll routine until a button is pushed, there's a keyboard timeout, or something else happens that the caller needs to deal with. That would then allow the main UI to be implemented using code like:

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状态,并且按下yesno按钮,则需要前进到STATE_START_DOING_SOMETHING_FUNSTATE_START_DOING_SOMETHING_BORING状态。

请注意,如果使用这种方法,则需要确保两次调用main_poll之间的最坏情况之间的时间始终满足通过处理的轮询操作的及时性要求main_poll,但是在可以满足该要求的情况下,可以采用这种方法比抢先调度多线程代码所需的一切,以及使其可靠运行所需的锁和其他防护措施,要方便和高效得多。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章