読み取り失敗が最後の正常値を上書きした
一言でいうと
ドライバーは、正常な温度を返す関数ではなく、失敗したときに何を変えないかも決める境界です。
なぜ必要なのか
転送関数が失敗したのに、バッファーの先頭バイトは変わっていました。以前の値と新しい値が混ざると、もっともらしいけれど存在したことのない温度になります。エラーコードだけを検査することと、失敗した結果をユーザーに公開しないことは、別の話です。作業用のバッファーで変換と検証を終え、成功パスの最後でサンプルを更新します。
今回のラボは、実際のCコンパイラーであなたのドライバーを実行しますが、I2Cの線に電圧をかけるわけではありません。ハードウェア抽象化レイヤーであるHALを、関数ポインターの組として提供します。ctxはモデルの状態を指し、transfer・now_ms・recoverがその状態を使います。学習者はモデルの内部を直さず、この公開インターフェースだけで通信します。
どう動くのか
アドレスは、0x48–0x4bの7ビットの値として渡します。R/Wビットを付けるために、さらに左へ1つシフトするのは、このHALの契約では誤りです。実際のドライバーライブラリを移植するときも、引数が7ビットのアドレスなのか、転送用のアドレスバイトなのかを、先にドキュメントで確認しなければなりません。
1回のtransfer呼び出しに、ポインター0x00の1バイトの書き込みと、2バイトの読み取りを一緒に渡します。実際のバスの繰り返しSTART・最後の読み取りのNACK・STOPは、HALの責任とします。このクラスの検査ツールは、結合した呼び出しのアドレス・長さ・ポインター・期限を検証するだけで、電気的な波形を測定するわけではありません。センサーのデータシートとHAL APIの契約は、別々のドキュメントです。
エラーのポリシーも明示します。SENSOR_NACKは転送失敗の状態であり、最後の読み取りバイトにコントローラーが送る正常なNACK信号と同じ意味では使いません。SENSOR_SHORTは、必要なバイトをすべて得られなかったという意味です。この2つの状態と、形式エラーは、リトライしません。SENSOR_BUSだけ、1回recoverしてから、もう1回読み直します。リトライも失敗したら、そのまま終了します。すべてのエラーを無限にリトライする実装は、誤ったアドレスを直すこともできないまま、呼び出し側を引き止めます。
モデルのrecoverは、引っかかった状態を初期化します。SCLを9回トグルしたり、電源を切って入れ直したりする動作を代わりに行ったと主張することはできません。実物の復旧は、バスの構成と部品の規格に合わせて、別に設計しなければなりません。ここでは、復旧が実際に状態を変えて初めて次の転送が成功するようにモデルを作り、関数名だけを呼んで結果を無視する間違いを区別します。
温度と時刻をセットにして、失敗を追跡する
進入時の公開サンプルがmicro_c=25000000, observed_ms=100だったとします。新しい転送は、先頭バイトの0x1aだけを書いて、SENSOR_SHORTを返します。公開サンプルのメモリを受信バッファーとして使うと、エラーを確認する前に、以前の値が壊れてしまうことがあります。関数内の2バイトの作業用バッファーで受け取り、変換した整数もローカル変数に置きます。失敗パスは、エラーだけを返し、公開サンプルには触れません。成功パスでだけ、新しい温度と完了確認の時刻を移します。
| 呼び出しの状況 | 返すステータス | 呼び出し後の公開温度 | 呼び出し後の公開時刻 |
|---|---|---|---|
| 以前の正常な値で開始 | 該当なし | 25000000 | 100 |
| 1バイトだけ受け取った読み取り | SENSOR_SHORT | 25000000 | 100 |
| 次の読み取りは26°Cで正常に完了 | SENSOR_OK | 26000000 | 新しい完了確認の時刻 |
温度だけを保存して、時刻を現在に変える実装も間違いです。画面には、古い測定が最新のサンプルのように見えるからです。逆に、一度失敗した後、永遠に以前の値を返す実装も間違いです。保存は失敗した呼び出しにだけ適用し、次の正常な呼び出しでは、2つのフィールドを更新します。この表の順序を実際の呼び出し順序でテストして初めて、「保存」と「永続キャッシュ」を区別できます。
ここで一緒に更新するというのは、1回の関数呼び出しの成功/失敗の契約です。2つのフィールドへの代入が、他のスレッドからアトミックに見えるという意味ではありません。このモデルは、同時に読む側を実行しません。実際のRTOSやマルチスレッドのプログラムでは、サンプルを読む側まで、ロックやメッセージ受け渡しなどの一貫性のルールを決めなければなりません。ローカルバッファーを作っただけで、データ競合まで解決したと書かないでください。
復旧の記録は、전송 BUS → 복구 OK → 재전송 OKのように、状態を順に残します(韓国語の語は、順に「転送」「復旧」「再転送」を意味する語です)。最後の結果だけをSENSOR_OKと書くと、復旧なしに偶然通った実装を区別できません。전송 BUS → 복구 NACKなら、復旧のエラーを返して終わらなければならず、その後に転送の呼び出しがあってはいけません。전송 BUS → 복구 OK → 재전송 BUSでも、復旧を2回目として開始しません。それぞれの矢印がなぜ許可され、あるいは禁止されるのかを説明できて初めて、制限付きのリトライポリシーを実装したことになります。
現場での姿
2026-09-10に確認したOrion Sleepの公式の組み込みエンジニア求人には、C/C++、ハードウェアインターフェース、限られたリソースでのデバッグと試験体制が、一緒に挙げられています。今回のコースは、そのうちドライバーの契約と再現試験を練習します。1件の海外シニア求人を、韓国国内の採用需要全体に一般化することはなく、このコースだけでRTOS・ボードbring-upの経験の代わりにすることもできません。求人が現在応募を受け付けているかどうかも、別に確認する必要があります。
実務のポートフォリオには、正常な事例と、故障を注入した事例を、一緒に残してください。部分読み取りの前に保存した温度と時刻が、エラーの後も同じかどうか、復旧の回数が本当に1回なのかが、観察できる根拠です。その証拠なしに「安定したドライバー」とだけ書くと、何を確認したのか分かりません。
続けて確認すること
すぐ続くクイズでアドレス・エラー・復旧の違いを確認し、時間バジェットの理論を読みます。最後のモジュールの累積ラボのうち、ステップ4–6で、正常な転送をつないだ後、サンプルの保存と制限付きの復旧を加えます。最初は正常パスだけを扱うので、各中間バージョンは、まだ製品用のドライバーではありません。以前の実装を維持しながら、現在のステップの契約を追加してください。