ESP8266 NonOS SDK開発入門:環境構築からペリフェラル制御まで

開発環境の準備

ESP8266による開発を進めるため、以下のツール群を用意する。

  • 統合開発環境:AiThinkerIDE
  • ファームウェア書き込みツール:flash_download_tools
  • シリアル通信ツール:AiThinker Serial Tool
  • USBドライバ:CH341SER

プロジェクトテンプレートの作成

Espressifが提供するESP8266 NonOS SDKをベースに、不要なファイルを削除し自分専用のテンプレートを作成する。SDK(Software Development Kit)はソフトウェア開発用のパッケージであり、API(Application Programming Interface)はSDKが提供する機能を呼び出すためのインターフェースである。

SDKディレクトリの整理

SDKの圧縮ファイルを展開後、以下の手順でファイルを裁査する。

  1. driver_libフォルダ内のmakefile(拡張子なし)を削除する。
  2. third_partyフォルダを丸ごと削除する。
  3. examplesフォルダ内にあるwpsプロジェクトを一階層上に移動し、フォルダ名をappに変更する。その後、空になったexamplesフォルダを削除する。

IDEへのインポートとビルド

AiThinkerIDEを起動し、プロジェクトエクスプローラーから「Import」を選択。既存プロジェクトとして先ほど整理したフォルダを選択し、ツールチェーンに「Cygwin GCC」を指定してインポートを完了する。

インポート後、app/user/user_main.cを開き、不要なサンプルコード(特定の行範囲)を削除する。ファイルを保存したら、プロジェクトを右クリックして「Clean Project」を実行し、続けて「Build Project」を行う。コンパイルが成功すると、コンソールに以下の2つのバイナリファイルと書き込みアドレスが表示される。

  • eagle.flash.bin0x00000
  • eagle.irom0text.bin0x10000

ファームウェアの書き込みと動作確認

フラッシュツールの設定

ESP8266は外部フラッシュメモリ(W25Qシリーズ等)を使用するため、メモリ容量に応じた設定が必要である。一般的な開発ボード(32Mbit / 4MByte)の場合、以下の4つのバイナリファイルを対応するアドレスに書き込む。

  • eagle.flash.bin:必須ファームウェア
  • eagle.irom0text.bin:ユーザープログラム
  • esp_init_data_default.bin:デフォルトRFパラメータ
  • blank.bin:システムパラメータ(2箇所に書き込み)

シリアル通信による確認

シリアルモニタを開き、ポートとボーレートを設定して開発ボードのリセットボタンを押下すると、プログラム内の出力が確認できる。

ESP8266の機能概要

ESP8266はWi-Fi機能を内蔵したマイクロコントローラ(MCU)である。従来のマイコンがレジスタを直接操作するのに対し、ESP8266はSDKが提供するAPI関数を呼び出すことで周辺機能(IO、タイマー、PWM、UART、I2C等)を簡便に利用できる。

GPIOの制御とピンマルチプレクス

GPIO(General Purpose Input/Output)は汎用的な入出力インターフェースである。ESP8266には17のピンが存在するが、SDIO通信に6本(IO6〜11)、UART0通信に2本(IO1, IO3)が固定で使用されるため、ユーザーが自由に利用できるピンは8本に限定される。また、GPIO16はディープスリープからの復帰に使われる特殊なピンである。

LEDを点灯させるサンプルコード:

void user_init(void) {
    // GPIOピンを输出機能に設定
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);
    
    // LEDを点灯(Highレベルを出力)
    GPIO_OUTPUT_SET(GPIO_ID_PIN(5), 1);
}

コールバック関数

イベント駆動型プログラミングにおいて、特定のイベント発生時に呼び出される関数をコールバック関数と呼ぶ。割り込みハンドラもコールバック関数の一種である。例えば、システム初期化完了時に処理を実行したい場合、system_init_done_cb()にコールバック関数を登録する。

タイマーの利用

ソフトウェアタイマー

ソフトウェアタイマーは、一定周期で反復処理を行う際に使用する。ポーリングのためのwhileループはCPUを占有するため避けるべきである。主なAPIはos_timer_disarm(無効化)、os_timer_setfn(コールバック登録)、os_timer_arm(開始)である。

#include "osapi.h"
#include "user_interface.h"

os_timer_t interval_timer;

void timer_callback(void) {
    os_printf("Timer expired!\n");
}

void ICACHE_FLASH_ATTR user_init(void) {
    os_timer_disarm(&interval_timer);
    os_timer_setfn(&interval_timer, (os_timer_func_t *)timer_callback, NULL);
    os_timer_arm(&interval_timer, 3000, 1); // 3秒ごとに繰り返し
}

ハードウェアタイマー

ハードウェアタイマーは物理的なタイマーモジュールを使用し、マイクロ秒単位の高精度な処理に向いている。NMI(ノンマスカブル割り込み)またはFRC1を選択できる。基本的な手順は、hw_timer_initで初期化し、hw_timer_set_funcでコールバックを設定し、hw_timer_armで起動する。精度を要さない限り、ソフトウェアタイマーの使用が推奨される。

void hw_timeout_cb(void) {
    os_printf("HW Timer tick\n");
}

void ICACHE_FLASH_ATTR user_init(void) {
    hw_timer_init(0, 1); // FRC1ソース、リピート有効
    hw_timer_set_func(hw_timeout_cb);
    hw_timer_arm(1000000); // 1秒(マイクロ秒単位)
}

PWMによる呼吸灯制御

PWM(Pulse Width Modulation)は周期(Period)とデューティ比(Duty)で制御される。LEDの明暗やモータの回転速度を調整するために使用する。SDKではpwm_initpwm_set_dutypwm_startが主要なAPIである。

#include "osapi.h"
#include "user_interface.h"

os_timer_t breath_timer;
uint32_t current_duty = 0;
int16_t duty_step = 400;
uint32_t pwm_pin_info[1][3] = {
    {PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2, 2}
};

void breath_callback(void) {
    current_duty += duty_step;
    if (current_duty >= 20000) {
        duty_step = -400;
    } else if (current_duty == 0) {
        duty_step = 400;
    }
    
    pwm_set_duty(current_duty, 0);
    pwm_start();
}

void ICACHE_FLASH_ATTR user_init(void) {
    uint32_t init_duty[1] = {0};
    pwm_init(1000, init_duty, 1, pwm_pin_info);
    
    os_timer_disarm(&breath_timer);
    os_timer_setfn(&breath_timer, (os_timer_func_t *)breath_callback, NULL);
    os_timer_arm(&breath_timer, 20, 1);
}

UART通信

UART0はデフォルトで有効であり、40MHzクリスタル時のボーレートは115200、26MHz時は74880となる。uart_init関数を使用してUART0およびUART1のボーレートを個別に設定できる。通信を行うには、專用のドライバファイル(uart.c, uart.h, uart_register.h)をプロジェクトに追加する必要がある。

I2C通信と温湿度センサ(AHT10)

I2CはSDAとSCLの2本の線で構成される同期式シリアルバスである。スタートコンディション(SCLがHighの間にSDAがHigh→Low)、ストップコンディション(SCLがHighの間にSDAがLow→High)、ACK/NACK等のプロトコルによって通信が制御される。スレーブデバイスは7ビットのアドレスで識別される。

AHT10温湿度センサとの通信では、測定トリガ(0xAC)、ソフトリセット(0xBA)などのコマンドを使用する。データ取得は、測定トリガ発行→ステータス確認(測定完了待ち)→データ読み出し、という手順で行う。

#include "osapi.h"
#include "user_interface.h"
#include "driver/i2c_master.h"
#include "driver/AHT10.h"

os_timer_t sensor_timer;

void sensor_read_callback(void) {
    AHT10_Read_Data();
}

void ICACHE_FLASH_ATTR user_init(void) {
    i2c_master_gpio_init();
    AHT10_Init();
    
    os_timer_disarm(&sensor_timer);
    os_timer_setfn(&sensor_timer, (os_timer_func_t *)sensor_read_callback, NULL);
    os_timer_arm(&sensor_timer, 2000, 1);
}

タグ: ESP8266 NonOS-SDK IoT Embedded-Systems C言語

5月30日 11:36 投稿