Embedded 用于裸机嵌入式系统的Pin配置器和数据库

Embedded 用于裸机嵌入式系统的Pin配置器和数据库,embedded,microcontroller,hal,bare-metal,Embedded,Microcontroller,Hal,Bare Metal,探索构建、编码和测试裸机嵌入式系统(约80MHz,~64kRAM)的多个管脚配置的最佳方法。我认为这段代码(/层)的一个方面是一个很小的databasecor数据结构,而另一个方面是使用数据库(通过Set/Get)通过一个很薄的抽象层来执行引脚(输出/输入) 嵌入式裸机系统工具和技术似乎落后于其他计算领域。因此,如果可以的话,我想阅读其他国家人民在这方面的经验 主题1:通过使用数据结构(/数据库)管理(/配置)一个位置(/模块)中的所有管脚。 引脚在启动后不会经常改变“模式”(如果有的话)。对我

探索构建、编码和测试裸机嵌入式系统(约80MHz,~64kRAM)的多个管脚配置的最佳方法。我认为这段代码(/层)的一个方面是一个很小的databasecor数据结构,而另一个方面是使用数据库(通过Set/Get)通过一个很薄的抽象层来执行引脚(输出/输入)

嵌入式裸机系统工具和技术似乎落后于其他计算领域。因此,如果可以的话,我想阅读其他国家人民在这方面的经验

主题1:通过使用数据结构(/数据库)管理(/配置)一个位置(/模块)中的所有管脚。 引脚在启动后不会经常改变“模式”(如果有的话)。对我来说,有一个文件(/模块)是有意义的,其中所有64-100个管脚(嵌入式ARM uC通用)都配置有各自的端口名称、管脚编号、拉入方向、速度、管脚模式(输入、输出或模拟)、管脚功能(UART、ADC、DAC、比较器等)。最后,一个pin_ID可以作为每个pin的标识符,或者一个pin名称(如果愿意)

主题2:适合嵌入式裸机应用程序的非常小的数据库。 通过数据库管理所有这些PIN。例如,在运行期间的任何给定时刻,所有这些pin也可以具有pin_值。我想从(/到)数据结构(/数据库)写入和读取这些pin_值更改。 扩展上述关于管脚配置和管脚值存储的概念,我们将得到虚拟管脚。 虚拟管脚的行为与物理管脚类似。它将有一个pin_ID、pin_模式和pin_值。例如,我们有一个观察信号过零点的uC。过零检测只能从零变为一并返回,即数字输入。我们可以说它有一个ZC_ID的管脚ID,一个输入_模式的管脚模式和一个新的管脚类型的管脚类别值类别虚拟数字

主题3:数据库接口-一层薄薄的抽象层。 我们应用程序的其他模块可以通过数据库访问物理或虚拟pin值更改。 我们的应用程序应该能够通过简单的pin_ID知识读取和写入物理或虚拟pin。例如:

获取值(uint32针ID,uint32针ID值)

设置值(uint32引脚ID,uint32引脚ID)

然后,底层代码决定此pin_ID是对gpio pin还是虚拟pin的简单写入/读取。 类似地,在现代互联世界中,我需要读取和写入外部设备或服务器。我想使用相同的数据库接口来做到这一点。Ie服务器向uC模块发送带有更新值的消息,在uC模块中,数据库使用新值进行更新。然后,我们的应用程序可以从数据库中读取新值

谢谢

主题1:通过使用数据结构管理(/配置)一个位置(/模块)中的所有管脚

这应该是完全可行的;实际上,我(和我认为的其他程序员)就是这样做的:在SystemInit上,所有的管脚都是从默认状态(输入)配置为具有上拉功能的输入或输出,或者与一些特殊的内部硬件(例如UART)相关联

主题2:适合嵌入式裸机应用程序的小型数据库。通过数据库管理所有这些PIN。例如,在运行期间的任何给定时刻,所有这些pin也可以具有pin_值。我想从(/到)数据库中写入和读取这些pin_值更改。扩展上述关于管脚配置和管脚值存储的概念,我们将得到虚拟管脚

同样,这是可行的,实际上是以一种非常简单的方式。有时我在ram中使用单个整数,其中每个位都反映管脚的状态或其他状态。中断处理程序更新这些位,前台进程将查看它们。对于输出,它是相同的,相反的:前台写入这些位,中断使用这些位修改实际引脚。 因此,我最终得到了两个变量(输入\ U状态和输出\ U状态),例如,可以通过串行、蓝牙或以太网远程读取和写入

但从这一点到数据库,还有很长的距离。通常,为了性能和低成本,嵌入式应用程序靠近硬件,没有太多的虚拟化。但是谁知道你的要求是什么呢?也许您的预算很大,处理器功能强大,对速度的需求很少。

在GPIO的特定情况下,最好的办法是尽可能少地使用抽象层

您需要一个功能来设置端口或管脚,可能还需要一些时钟和管脚布线设置。然而,端口访问最好通过直接写入数据寄存器直接完成。为什么?因为如果你做这样的HAL:

pin_t pin_allocate (port, pin);
void pin_set (pin_t* p);
如果
pin\t
是某种抽象、不透明的类型,那么您可能会遇到非常微妙的重入错误,这是由于应用程序程序员无法跟踪代码中发生的事情造成的

考虑这种情况:

// BAD DESIGN, don't do this

static pin_t* led;
statci pin_t* relay;

void main (void)
{
  led = pin_allocate(PORTA, 0);
  relay = pin_allocate(PORTA, 1);
  ...

  pin_set(led);  
}

...

void PORTA_ISR (void)
{
  pin_set(relay);
}
这段代码中有一个竞争条件bug,但它被抽象层完全隐藏了起来

  • 某些代码在用于驱动继电器的同一端口上分配了一个引脚。即将设置LED
  • pin_set()
    可能存储端口寄存器的值,并准备执行按位或
  • ISR攻击。端口寄存器被写入,其值用于设置继电器
  • 从子程序返回。完成对端口寄存器的LED写入,并清除继电器输出
  • 这将表现为一种罕见的间歇性现象,继电器无法设置,相反,我们在线圈上遇到一个短故障,太短而无法驱动它
  • 如果程序员最终错误地发现了一个竞争条件错误,他们可能会开始调查对
    中继
    变量的访问。但是这个变量本身可能受到保护并且是线程安全的——问题在于