ペリフェラル入門¶
これらのチュートリアルは、SF32開発の始め方の直後から始まります。すでにSiFli-SDKのツールチェーンをインストールし、少なくとも一度はhello_worldを書き込み、シリアルコンソールの開き方を知っている状態を前提としています。各チュートリアルは意図的に小さく作られています。一つの概念、一つのペリフェラル、一つの明確な成功条件です。
サンプルは、sf32lb52-lcd_n16r8のようなSF32LB52-DevKit-LCDクラスのボードを前提としています。別のボードを使用している場合は、ビルドコマンド内のボード名を置き換え、そのボードのサポートファイルからピン名、ペリフェラルインスタンス、ストレージレイアウトを確認してください。
このシリーズを通じて、信頼できる習慣を身につけましょう。ボード上の動作を一つずつ検証し、明確な成功条件を定め、次のペリフェラルに進む前に動作確認済みの構成を残しておきます。組み込みCの経験があっても、SF32 SDKを初めて使う開発者が手を動かして学べる内容です。
始める前に¶
すべてのチュートリアルで、同じ基本的なループを使用します。
シリアルターミナルを開いたままにしておいてください。ほとんどの初心者のミスは、rt_kprintf()の出力とFinSHのmsh>プロンプトを確認できれば、解決しやすくなります。
以下のCコードは抜粋であり、そのままビルドできる完全なソースファイルではありません。プロジェクトやSDKのバージョンに応じて、必要なヘッダー、宣言、ボード固有の初期化、戻り値の確認、リソースの解放を追加してください。
| 項目 | 確認事項 |
|---|---|
| ボード名 | 対応するボード構成のいずれかと一致している。 |
| シリアルポート | 問題なく開き、ブート出力が表示される。 |
| 書き込みツール | ケーブルを変更せずに、ボードへ繰り返し書き込みできる。 |
| 回路図またはボードファイル | GPIO、ADC、PWM、RTCのリソースを選ぶ前に入手済み。 |
| 一度に一つの変更 | 小さな編集ごとにビルド、書き込み、検証を行う。 |
GPIOでLEDを点滅させる¶
目標: ファームウェアからGPIOピンを制御する。最初のビルド成功に相当する、組み込みならではの一歩です。
所要時間: 15分
開始点: example/hal/gpioまたはexample/rt_device/gpio
SF32のRT-ThreadベースのSDKは、標準的なRT-ThreadのPINデバイスAPIを通じてGPIOを公開しています。最小限の点滅ループは次のようになります。
#include <rtthread.h>
#include <rtdevice.h>
#define LED_PIN GET_PIN(1, 0) /* replace with your board's LED pin */
int main(void)
{
rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
while (1)
{
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}
- 最も近いGPIOサンプルを自分のプロジェクトディレクトリにコピーするか、学習しながらその場で編集してください。
- 回路図またはボードサポートファイルでLEDピンを見つけてください。ポートとピンの番号を推測しないでください。
hello_worldで使用したのと同じボード名でビルドして書き込んでください。- LEDが期待どおりの速さで点滅することを確認してください。
- 遅延を100 msに変更し、再ビルドして、点滅の速さが目に見えて変わることを確認してください。
成功基準: LEDが繰り返し切り替わり、シリアルコンソールは通常どおりのブート出力を表示し続け、遅延を変更すると点滅速度が変わる。
うまくいかない場合: アクティブ極性、LEDがトランジスタ経由で接続されているか、そのピンがすでに別の機能で使われていないか、ボード名が手元のハードウェアと一致しているかを確認してください。
学んだこと: PINデバイスの抽象化、ボード固有のピン定義、そして基本的な編集/ビルド/フラッシュのループ。
GPIO入力でボタンを読み取る¶
目標: デジタル入力を読み取り、ボタンの押下に反応する。
所要時間: 20分
開始点: example/rt_device/gpio
ボタンの読み取りには、入力モードにした同じPIN APIを使用します。まずは配線と論理レベルを確認するために、シンプルな読み取りから始めてください。
SiFli-SDKでは、RT-ThreadのPINデバイスAPIのrt_pin_mode()では、パッドのプルアップ/プルダウンは設定されません。アクティブLowのボタンを使う場合は、ボード上にプルアップ抵抗があることを確認するか、ボードのpinmux設定でHAL_PIN_Set(...)を使ってプルを設定してください。パッド、機能、CPUドメインはボードによって異なるため、ピン割り当てをそのまま流用せず、ボードのサポートファイルを確認してください。
rt_pin_mode(BUTTON_PIN, PIN_MODE_INPUT);
if (rt_pin_read(BUTTON_PIN) == PIN_LOW)
{
/* button pressed, active-low */
}
簡単なテストを超える用途では、タイトなループでポーリングを続けるのではなく、割り込みを使ってください。ファームウェアはピンを繰り返し読み取ることなく入力エッジに反応できます。また、設計全体としてイベント間にCPUをスリープさせられる場合は、消費電力の低減にもつながります。
rt_pin_attach_irq(BUTTON_PIN, PIN_IRQ_MODE_FALLING, button_isr, RT_NULL);
rt_pin_irq_enable(BUTTON_PIN, PIN_IRQ_ENABLE);
- ボード上で利用可能なボタンまたは入力ピンを特定してください。
- まずポーリングによる読み取りから始め、ボタンを押したり離したりしながら生の値を出力してください。
- ボタンがアクティブハイかアクティブローかを確認してください。
- 基本的な読み取りが動作したら、割り込みハンドラーに切り替えてください。
- ボタンが押されるたびに、チュートリアル1のLEDを切り替えてください。
- 短い間隔でイベントを無視するか、短い遅延の後にレベルを検証することで、簡単なデバウンス戦略を追加してください。
成功基準: 一回の物理的な押下が一回の意図したファームウェアの動作を引き起こし、バウンスによる繰り返しのトリガーが発生しない。
うまくいかない場合: 必要なプルアップ/プルダウン抵抗がボード上にあるか、pinmuxで設定されているかを確認してください。そのうえで、ボタンの極性、割り込みエッジの選択、そのピンがブートモード、デバッグ、または別のペリフェラルと共有されていないかを確認してください。
学んだこと: デジタル入力の設定、アクティブハイとアクティブローの論理の違い、割り込み駆動の入力、そしてポーリングを続けると電力を無駄に消費する理由。システムレベルの背景については低消費電力設計の概要を参照してください。
シェルを使ってデバッグ出力を表示する¶
目標: デバッグが難しくなる前に、FinSHコンソールとrt_kprintf()に慣れる。
所要時間: 15分
開始点: example/system/finsh
RT-ThreadのFinSHシェルは、ブートログに使われるのと同じUART経由で、対話型のmsh>プロンプトを提供します。次の習慣を早めに身につけましょう。
- 生のUART書き込みの代わりに、軽量なデバッグロギングには
rt_kprintf()を使用する。 list_thread、list_device、メモリー/ステータスコマンドなどの組み込みシェルコマンドを使って、実行中のシステムを検査する。-
ログは短く意味のあるものに保つ。過剰なロギングはタイミングと電力の挙動を変えてしまうことがある。
-
これまでのサンプルのいずれかを書き込み、シリアルターミナルを開き直してください。
- Enterを押して
msh>プロンプトを表示させてください。 list_threadとlist_deviceを実行してください。- チュートリアル2のボタンハンドラーに
rt_kprintf()呼び出しを追加してください。 - ボタンを押したときにログが表示されることを確認してください。
成功基準: シェルからスレッドとデバイスを検査でき、自分自身のログメッセージと物理的なイベントを関連付けられる。
うまくいかない場合: シリアルのボーレート、ポート選択、シェルコンポーネントが有効になっているか、そして別のツールがシリアルポートを保持していないかを確認してください。
学んだこと: デバッガーを接続せずに実行中のシステムを検査する方法、そして問題のたびにファームウェアを当てずっぽうで変更せずに済む、手軽なログ出力の使い方。
ADCでアナログセンサーを読み取る¶
目標: ポテンショメーター、簡単なセンサー、またはバッテリー検知入力からアナログ電圧をサンプリングする。
所要時間: 20分
開始点: example/rt_device/adc/channel
このRT-Thread例を使うには、BSP_USING_ADC、BSP_USING_ADC1、RT_USING_ADCを有効にしてください。無効の場合、SDKはbat1を登録しません。SF32LB52ではチャンネル7がチップ内部でVBATに接続されているため、汎用の外部センサー入力には使えません。使用するチップとボードで利用できるADCチャンネルを選び、ピンマルチプレクスを設定してください。SiFliのSF32LB52向け例では、チャンネル0にPA28を使います。現在のSiFli-SDK例でrt_adc_read()が返すのは0.1 mV単位に換算済みの電圧値であり、未換算のADC生カウントではありません。使用するチップとドライバーのバージョンについて、単位と換算方法を確認してください。
rt_adc_device_t adc = (rt_adc_device_t)rt_device_find("bat1");
rt_adc_enable(adc, channel);
rt_uint32_t voltage_0p1mV = rt_adc_read(adc, channel);
- ボード上でADC対応のピンとチャンネルを特定してください。
- 入力電圧の範囲と、分圧回路またはアナログフロントエンド回路の有無を確認してください。
- 登録済みのADCデバイスを見つけ、チャンネルを有効にして値を読み取ってください。
- 使用するドライバーの説明に従って換算してください。現在のSF32LB52例では、返された値を10で割るとmVになります。すでに電圧換算された値に、生カウント用の基準電圧/分解能の式を重ねて適用しないでください。外付け分圧器がある場合は、分圧前の電圧を求める際にその比率を考慮してください。
- チュートリアル3のシェル経由で結果を出力してください。
- 入力をゆっくり変化させ、読み取り値が滑らかに変わることを確認してください。
成功基準: 読み取り値が期待どおりに変化し、ドライバーで定められた単位とボード上の分圧比を考慮すると、妥当な入力電圧になる。
うまくいかない場合: ピンマルチプレクス、チャンネル番号、ドライバーで定められた単位と校正方法、入力範囲、入力がフローティングになっていないか、そしてセンサーがサンプリング前に電源または安定時間を必要としないかを確認してください。
学んだこと: RT-Threadのデバイスドライバー全体で使われるrt_device_find()パターン。このパターンはI2C、SPI、PWM、ストレージ、カスタムドライバーでも再利用することになります。
PWM出力を駆動する¶
目標: LEDを減光させたり、簡単なブザーを駆動したりするためのPWM信号を生成する。
所要時間: 20分
開始点: example/rt_device/pwm
PWMデバイス名は、ボードで有効にしたタイマードライバーによって異なります。SDKではpwm3、pwmlp1、pwma1などの名前が使われます。以下のpwm3は一例であり、すべてのボードで共通する名前ではありません。ボード設定で登録されているデバイス名とピンマルチプレクスを確認してください。
struct rt_device_pwm *pwm = (struct rt_device_pwm *)rt_device_find("pwm3");
rt_pwm_set(pwm, channel, period_ns, pulse_ns);
rt_pwm_enable(pwm, channel);
- PWM対応のチャンネルを選び、ピンマルチプレクスを確認してください。
- ペリフェラルに合った周期を選んでください。LEDのちらつきが見えなくなるほど高いか、ブザーであれば可聴域の範囲にしてください。
- デューティ比を掃引して、LEDを徐々に明るく/暗くしてください。
- 周期を変えることで、ブザーでいくつかの固定音を試してください。
- PWMを無効化し、出力が安全なアイドル状態に戻ることを確認してください。
成功基準: デューティ比の変更で明るさが変わる、または周期の変更で音程が変わり、PWMを無効化すると出力が期待どおりの状態になる。
うまくいかない場合: そのピンがPWMインスタンスにルーティングされているか、チャンネル番号が正しいか、周期とパルスがナノ秒単位になっているか、そして外部負荷にドライバートランジスタが必要ではないかを確認してください。
学んだこと: 周期/デューティ比の設定と、別のペリフェラルクラスに適用された、チュートリアル4と同じデバイスドライバーパターン。
RTCで時刻を管理する¶
目標: チップ内蔵のRTCを使って現在時刻を読み取り、設定する。
所要時間: 15分
開始点: example/rt_device/rtc
time_t now = time(RT_NULL);
struct tm *tm_now = localtime(&now);
rt_kprintf("%04d-%02d-%02d %02d:%02d:%02d\n",
tm_now->tm_year + 1900, tm_now->tm_mon + 1, tm_now->tm_mday,
tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);
- シェルコマンドなど、サポートされている方法でRTC時刻を一度設定してください。
- 現在時刻を定期的に出力してください。
- ボードの電源を入れ直し、時刻が保持されるかどうかを確認してください。
- 時刻が保持されない場合は、ファームウェアを変更する前にボードのバックアップ電源経路を確認してください。
保持動作を確認するときは、毎回の起動時にRTCを無条件で再設定しないでください。そうすると、前回の時刻が保持されたかどうかを判別できません。
成功基準: 電源が入っている間は時刻が正常に増加し、保持挙動がボードのハードウェアと一致している。
うまくいかない場合: RTCコンポーネントの有効化、クロックソース、バックアップ電源、そしてボードが起動時にRTCの状態をリセットしていないかを確認してください。
学んだこと: RT-ThreadのRTCデバイスの上に構築された標準的なC time API、そしてファームウェアの挙動がハードウェア設計にどう依存するかという早い段階での例。
ミニプロジェクト: ボタン制御式センサーロガー¶
六つの短いチュートリアルを終えたら、それらを一つの小さなプロジェクトに組み合わせてみましょう。
- 起動時にLEDを点滅させる。
- ボタンでサンプリングの開始/停止を行う。
- サンプリング中は毎秒一つのADC値を読み取る。
- FinSH経由でタイムスタンプ付きの読み取り値を出力する。
- サンプリング中かどうかを、PWMの明るさまたはブザーの音程で示す。
合格基準: ボタンの繰り返しトリガー、暴走するロギング、予期しないリセットなしに、プロジェクトが数分間動作し続ける。
基本ペリフェラルの動作確認チェックリスト¶
- ボード名、シリアルポート、書き込み手順が動作確認済みである。
- 実際のLEDまたは測定したピンでGPIO出力が動作する。
- 極性とデバウンスを確認したうえでGPIO入力が動作する。
- FinSHシェルが使用可能で、
list_thread/list_deviceが動作する。 - ADCの読み取り値が妥当で、工学単位に変換されている。
- PWMの周期/デューティ設定が期待どおりの物理出力を生む。
- 保持に関する制限も含め、RTCの挙動が理解できている。
次に進む先¶
これらが快適にこなせるようになったら、複数サブシステムの連携に進んでください。次の段階では、ペリフェラルとミドルウェア(I2Cセンサー、LVGL、BLE、オーディオ再生、ストレージ)を組み合わせ、意図的な共存テストも行います。
最終更新: