平台:ARM9
编程语言C
要求 - 普通C,没有外部库,也没有提升。
OS - REX RTOS
我在嵌入式平台上运行了两个线程 -
这个想法是将app线程与驱动程序线程分离,这样我们就可以在硬件驱动程序线程中更改硬件和实现,但对应用程序线程的影响最小。
我的挑战是从硬件接收的数据可能是动态的,即我们不知道应用程序线程应该为每个硬件请求留出多少内存,因为这是在运行时确定的。
我在想驱动程序线程可以通知应用程序线程有很多数据要读取。然后,应用程序线程分配内存并请求驱动程序线程读取数据。然后由应用程序线程来相应地处理数据。这样,所有内存管理都在应用程序线程中。
答案 0 :(得分:3)
想到了夫妻选择:
1)malloc驱动程序中的内存,在应用程序中释放它。但是......我们倾向于避免在接近实时要求的任何事物中使用malloc。如果您可以访问malloc / free,并且没有“实时”问题或内存碎片问题(即您的堆足够大),那么这是一种相当简单的方法。驱动程序只是通过消息队列将分配的指针发送到应用程序线程,完成后应用程序释放内存。注意内存泄漏。
2)环形或循环缓冲区。驱动程序完全管理固定大小的环形缓冲区,并在缓冲区就绪时向应用程序发送消息。有关详细信息,请参阅此处:Circular buffer。然后,应用程序通过驱动程序API再次标记数据“可用”,这有助于从应用程序线程隐藏环形缓冲区详细信息。我们将这种方法用于我们的一个驱动程序,它们具有您所描述的非常类似的一组要求。在这种情况下,您需要关注确定环形缓冲区的“最佳”大小,驱动程序中的溢出处理等。
祝你好运!答案 1 :(得分:0)
您没有指定操作系统,但您有某种“线程”。除了其中一个是驱动程序级别(中断处理程序)而另一个听起来像应用程序(用户区/内核)。但这也不匹配,因为您的驱动程序和应用程序在数据处理之前正在进行通信。
您的术语令人困惑,并不令人鼓舞。这是一个自制(RT)操作系统吗?
如果您有真正的操作系统,则可以使用已建立的方法编写驱动程序并将数据交给用户空间。阅读文档或使用现有的驱动程序作为参考。
如果这是一个自定义操作系统,你仍然可以参考其他开源驱动程序的想法,但你显然不会设置方便的东西。预分配驱动程序代码中的所有内存,在数据到达时填充数据,然后将其移交给应用程序代码。内存量取决于您的应用程序处理数据的速度,您计划接受的最大数据量以及支持您的应用程序需要多少内部数据排队。
答案 2 :(得分:0)
这是C,我最终不得不让应用程序注册与驱动程序的回调。回调的目的是在驱动程序从设备读取数据后处理数据。驱动程序管理内存,即分配内存,调用回调并最终释放内存。此外,回调仅对内存具有读取权限。因此,理想情况下,app应该只是将缓冲区的内容复制到自己的内存中,然后立即从回调中退出。然后可以随时随地处理数据。
我更新了文档以明确使用应用程序回调,假设回调返回时,内存不应再被视为有效。如果以任何其他方式使用回调,则行为未定义。
答案 3 :(得分:0)
我的第一个想法是使用循环缓冲区。这是一些示例代码。随意适应您自己的用途。你可能不想要全局变量。你可能不想要#defines:
#define LENGTH (1024)
#define MASK (LENGTH-1)
uint8 circularBuffer[ LENGTH ];
int circularBuffer_add = 0;
int circularBuffer_rmv = 0;
void copyIn( uint8 * circularBuffer, uint8 * inputBuffer, int n ) {
int i;
for( i = 0; i < n; i++ ) {
circularBuffer[ circularBuffer_add ] = inputBuffer[ i ];
circularBuffer_add = ( circularBuffer_add + 1 ) & MASK;
}
}
void copyOut( uint8 * circularBuffer, uint8 * outputBuffer, int n ) {
int i;
for( i = 0; i < n; i++ ) {
outputBuffer[ i ] = circularBuffer[ circularBuffer_rmv ];
circularBuffer_rmv = ( circularBuffer_rmv + 1 ) & MASK;
}
}
此外,上述代码假定您的数据单位是数据类型“uint8”。您可以更改它以使其使用其他一些数据类型。或者你甚至可以使它成为通用的,并使用memcpy()来复制到circularBuffer。
此代码的主要功能是它如何处理add和rmv ptr。
使用上述代码完成后。 我建议您在某些时候将所有读取内容从硬件切换为使用平台的direct-memory-access API 。
切换到直接内存访问非常重要,因为上面的代码相对于使用几乎零周期的DMA 使用了很多周期。