Embedded 如何最好地将遗留轮询嵌入式固件体系结构转换为事件驱动的体系结构?
我有一系列嵌入式产品运行典型的基于主循环的固件,有150+k行代码。通过硬件中断处理程序、计时器轮询和(想想协同例程)的组合,可以实现复杂的时序关键特性负载。实际上,protothreads轮询性能很好,“only”是模拟多线程伪并行调度(无止境循环)的语法糖。我一直在固件中添加错误修复和扩展。该领域大约有30k台设备,硬件类型和版本略有不同,约有7种 对于新产品系列成员,我只需要在新产品上集成一个基于FreeRTOS的外部项目,而所有旧产品都需要进一步的功能和改进 为了不必将整个复杂的遗留固件移植到FreeRTOS,而冒着破坏完美产品的风险,我计划让旧固件在FreeRTOS任务中运行。在旧产品上,固件在没有FreeRTOS的情况下仍不能运行。在FreeRTOS任务中,传统固件将消耗所有可用的处理器时间,因为其底层实现方案是基于轮询的。由于它使用prothreads(基于后台的计时器和硬件轮询)并在自由运行的处理器计数器寄存器上进行轮询,我希望能够将轮询转换为事件驱动行为 以下是两个例子:Embedded 如何最好地将遗留轮询嵌入式固件体系结构转换为事件驱动的体系结构?,embedded,polling,freertos,firmware,event-driven,Embedded,Polling,Freertos,Firmware,Event Driven,我有一系列嵌入式产品运行典型的基于主循环的固件,有150+k行代码。通过硬件中断处理程序、计时器轮询和(想想协同例程)的组合,可以实现复杂的时序关键特性负载。实际上,protothreads轮询性能很好,“only”是模拟多线程伪并行调度(无止境循环)的语法糖。我一直在固件中添加错误修复和扩展。该领域大约有30k台设备,硬件类型和版本略有不同,约有7种 对于新产品系列成员,我只需要在新产品上集成一个基于FreeRTOS的外部项目,而所有旧产品都需要进一步的功能和改进 为了不必将整个复杂的遗留固件
因此,我得到的印象是,我可以将这两种编程模式(例如,通过宏魔术和FreeRTOS功能)转换为一种基于事件的底层方案 那么现在我的问题是:有人已经做过这样的事情了吗?是否有模式和/或最佳实践可遵循 [更新] 感谢您的详细回复。让我评论一些细节:我需要结合“基于多线程模拟的遗留固件(使用coo例程实现protothreads)”和一个基于FreeRTOS的项目,该项目由两个相互作用的FreeRTOS任务组成。其想法是让完整的旧固件在其自己的RTOS任务中运行,而不是在其他新任务中运行。我了解RTOS原则和模式(抢占、资源共享、阻塞操作、信号、信号量、互斥、邮箱、任务优先级等)。我计划将新旧部件的交互完全建立在这些机制的基础上。我想要的是1)如何以半自动化的方式转换传统固件(150k+LOC),以便上面介绍的忙等待/轮询方案在RTOS任务内部运行时使用新机制,或者在构建和运行当前主循环类型的固件时使用旧方法。旧代码的完全重写/完整端口不是选项。2) 更多的想法如何教导旧的固件实现,该实现用于在RTOS任务的新牢笼中保持良好的性能,而不仅仅是消耗所有可用的CPU周期(当赋予最高优先级时)或在不以最高RTOS优先级运行时产生新的大实时延迟
我想这里没有人已经做过这么特别的助教了。因此,我只需要做艰苦的工作,一个接一个地解决所有描述的问题。您面临两大难题
最直接的方法是将所有的原线程放在一个任务中,并在该任务中继续轮询。您面临两个大难题
最直接的方法是将所有的原线程放在一个任务中,并在该任务中继续轮询。在RTOS中,您创建并运行任务。如果您没有运行多个任务,则使用RTOS没有什么优势 我不使用FreeRTOS(但已经使用),但以下内容适用于任何RTOS,并且是伪代码,而不是特定于FreeRTOS API的-许多细节(如任务优先级和堆栈分配)故意丢失 首先,在大多数简单的RTO(包括FreeRTO)中,
main()
用于硬件初始化、任务创建和计划程序启动:
int main( void )
{
// Necessary h/w & kernel initialisation
initHardware() ;
initKernel() ;
// Create tasks
createTask( task1 ) ;
createTask( task2 ) ;
// Start scheduling
schedulerStart() ;
// schedulerStart should not normally return
return 0 ;
}
现在,让我们假设您的第一个示例是在task1
中实现的。典型的RTO将同时具有计时器和延迟功能。最简单的使用方法是延迟,这适用于保证周期处理花费较少时间的情况
// second example: wait for hardware event
setup_hardware();
PT_WAIT_UNTIL(hardware_ready(), pt);
// hardware is ready, do something else
int main( void )
{
// Necessary h/w & kernel initialisation
initHardware() ;
initKernel() ;
// Create tasks
createTask( task1 ) ;
createTask( task2 ) ;
// Start scheduling
schedulerStart() ;
// schedulerStart should not normally return
return 0 ;
}
void task1()
{
// do something every 100 ms
for(;;)
{
delay( 100 ) ; // assuming 1ms tick period
// something
...
}
}
void task1()
{
// do something every 100 ms
TIMER timer = createTimer( 100 ) ; // assuming 1ms tick period
for(;;)
{
timerWait() ;
// something
...
}
}
createSemaphore( hardware_ready ) ;
// Init hardware
...
// Tell waiting task hardware ready
semaphoreGive( hardware_ready ) ;
void task2()
{
// wait for hardware ready
semaphoreTake( hardware_ready ) ;
// do something else
for(;;)
{
// This loop must block is any lower-priority task
// will run. Equal priority tasks may run is round-robin
// scheduling is implemented.
...
}
}