組み込み機器・ハードウェアの設計開発から装置製作まで社内一貫対応!

組み込み機器・ハードウェア設計製作.com
組み込み機器・ハードウェア設計製作.com

produced by株式会社アイディアイ

設計のポイント

リングバッファで受信データを取りこぼさない

設計内容分類組み込みソフトウェアにおけるC言語記述

実現したい仕様・課題

UART受信のように、割り込みで断続的に届くデータをメイン処理が読み出す構成では、メイン側の処理が一時的に重くなった瞬間にデータを取りこぼす危険があります。割り込み側とメイン側の処理速度の差を吸収し、データを失わずに受け渡したいというのが課題です。

設計のポイント

割り込みとメイン処理のデータ受け渡しには、リングバッファ(循環バッファ)を使用します。固定長の配列を用意し、書き込み位置(ヘッド)と読み出し位置(テール)の2つのインデックスで管理する構造で、割り込みハンドラはヘッド位置へデータを書いてヘッドを進め、メイン処理はテール位置から読んでテールを進めます。インデックスが配列の末尾に達したら先頭へ戻る(循環する)ことで、固定メモリのまま連続的なデータ流を扱えます。バッファに溜めておけるぶん、メイン側の読み出しが一時的に遅れてもデータは失われず、処理速度の瞬間的な差を吸収できます。実装のポイントとして、(1) バッファサイズを2のべき乗にすると、インデックスの循環が「& (SIZE-1)」のマスク1回で書け、剰余計算が不要になります。(2) 空の判定はヘッドとテールの一致、満杯の判定は「ヘッドの次がテール」とする方式が簡潔で、割り込み側とメイン側が互いに相手のインデックスを更新しない(書く側はヘッドのみ、読む側はテールのみ更新する)構造にすることで、排他制御を最小限にできます。(3) 共有するインデックスにはvolatileを付けます。(4) 満杯時に新データを捨てるか古いデータを上書きするかは仕様として決め、取りこぼしの発生をカウンタで記録しておくと、バッファサイズの妥当性を実測で確認できます。必要サイズは「受信レート×メイン側の最大応答遅れ」から見積もり、余裕を持たせて設計します。

【コード例】

#define RB_SIZE 256                 // 2のべき乗
static volatile uint8_t  rb[RB_SIZE];
static volatile uint16_t head = 0, tail = 0;

void rx_isr(void) {                 // 書く側:headのみ更新
  uint16_t next = (head + 1) & (RB_SIZE - 1);
  if (next != tail) { rb[head] = UART_DR; head = next; }
  // 満杯時は捨てる(必要なら取りこぼしカウンタを加算)
}

int rb_read(uint8_t *d) {           // 読む側:tailのみ更新
  if (head == tail) return 0;       // 空
  *d = rb[tail];
  tail = (tail + 1) & (RB_SIZE - 1);
  return 1;
}

補足情報

当事例のような、マイコンのファームウェアにおけるC言語記述のポイントをまとめた冊子の無料DLが可能です。
是非以下よりご確認ください。

マイコンのファームウェア C言語記述のポイント

>>ダウンロードはこちら!

お問い合わせ

組み込み機器・ハードウェア 設計製作.comを運営する株式会社アイディアイは、組み込み機器・ハードウェアの設計開発代行サービスを提供しています。
試験装置や制御機器、組み込みボードなど、設計・開発委託先をお探しの皆様、お気軽に当社に御相談ください。

技術資料のダウンロードはこちらから 技術資料ダウンロ―ド メールフォームでのお問い合わせはこちらから ご相談・お問合せ