1

プラットフォーム: ARM9

プログラミング言語 C

要件 - プレーン C、外部ライブラリなし、ブーストなし。

OS - REX RTOS

組み込みプラットフォームで 2 つのスレッドを実行しています -

  1. 1 つは、ハードウェアとのすべての通信とデータ転送を処理するドライバー レベルです。
  2. 2 番目のスレッドは、ハードウェアとの間のデータを使用するアプリケーションを実行します。

アプリケーション スレッドをドライバー スレッドから切り離すことで、ハードウェアとハ​​ードウェア ドライバー スレッドの実装を変更できますが、アプリケーション スレッドへの影響は最小限に抑えることができます。

私の課題は、ハードウェアから受信したデータが動的である可能性があることです。つまり、実行時に決定されるため、アプリケーションスレッドがハードウェアへの/からの各要求に対してどれだけのメモリを確保する必要があるかが事前にわかりません。

私は、ドライバー スレッドがアプリケーション スレッドに、読み取るデータが非常に多いことを通知できると考えていました。次に、アプリケーション スレッドはメモリを割り当て、ドライバー スレッドにデータの読み取りを要求します。それに応じてデータを処理するのは、アプリケーション スレッド次第です。このように、すべてのメモリ管理はアプリケーション スレッド内で行われます。

4

4 に答える 4

3

いくつかのオプションが思い浮かびます:

1) ドライバーでメモリを malloc し、アプリで解放します。しかし...リアルタイム要件に近づくものでは、mallocの使用を避ける傾向があります。malloc/free にアクセスでき、「リアルタイム」の問題やメモリの断片化の問題がない (つまり、ヒープが十分に大きい) 場合、これはかなり簡単な方法です。ドライバーは、割り当てられたポインターをメッセージ キューを介してアプリ スレッドに送信するだけで、アプリは完了するとメモリを解放します。メモリリークに注意してください。

2) リングまたは循環バッファー。ドライバーは、固定サイズのリング バッファーを完全に管理し、バッファーの準備ができたときにアプリケーションにメッセージを送信するだけです。詳細については、こちらを参照してください: 循環バッファー。次に、アプリケーションは、ドライバー API を介してデータを再び「使用可能」とマークします。これにより、アプリ スレッドからリング バッファーの詳細を隠すことができます。このアプローチは、あなたが説明したように非常に類似した一連の要件を持つドライバーの 1 つに使用されます。この場合、リング バッファの「最適な」サイズの決定、ドライバでのオーバーフロー処理などに注意する必要があります。

幸運を!

于 2009-03-27T12:20:49.313 に答える
0

OSを指定しませんが、どういうわけか「スレッド」があります。それらの1つがドライバーレベル(割り込みハンドラー)であり、もう1つがアプリケーション(ユーザーランド/カーネル)のように聞こえることを除いて。ただし、データが処理される前にドライバーとアプリが通信しているため、これも一致しません。

あなたの用語は紛らわしく、勇気づけられません。これは自作(RT)OSですか?

実際のOSを使用している場合は、ドライバーを書き込んだり、ユーザーランドにデータを渡したりするための確立された方法があります。ドキュメントを読むか、既存のドライバの1つを参照として使用してください。

これがカスタムOSの場合でも、他のオープンソースドライバーを参照してアイデアを得ることができますが、明らかに便利な設定はできません。ドライバコード内のすべてのメモリを事前に割り当て、到着時にデータを入力して、アプリケーションコードに渡します。メモリの量は、アプリがデータを処理できる速度、受け入れる予定のデータの最大量、およびアプリをサポートするために必要な内部データキューの量の関数になります。

于 2009-03-27T13:14:24.130 に答える
0

これはCなので、アプリにドライバーにコールバックを登録させる必要がありました。コールバックの目的は、ドライバーがデバイスからデータを読み取った後にデータを処理することです。ドライバはメモリを管理します。つまり、メモリを割り当て、コールバックを呼び出し、最後にメモリを解放します。さらに、コールバックにはメモリに対する読み取り権限しかありません。したがって、アプリは理想的には、バッファの内容を独自のメモリにコピーし、すぐにコールバックを終了する必要があります。その後、必要なときに必要な方法でデータを自由に処理できます。

ドキュメントを更新して、アプリコールバックの使用法を明確にし、コールバックが戻ったときにメモリが有効であると見なされなくなるようにしました。コールバックが他の方法で使用される場合、動作は定義されていません。

于 2009-03-30T13:13:53.280 に答える
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 を処理する方法です。


上記のコードで動作するようになったら。ある時点で、ハードウェアからのすべての読み取りを切り替えて、プラットフォームのダイレクト メモリ アクセスAPIを使用することをお勧めします。

上記のコードは、ほとんどゼロ サイクルを使用する DMA に比べて多くのサイクルを使用するため、ダイレクト メモリ アクセスに切り替えることが重要です。

于 2009-03-30T15:10:39.893 に答える