esp-open-rtosを使ってみる

OTA Update over TFTP

examples/ota_basicにotaのサンプルが有りますが、実行しても延々とエラーメッセージを表示するだけで何も起こりません。
ソースを見ると、192.168.1.23のTFTPサーバーからデータをダウンロードしようと試みますが、
そのようなサーバーはいないので、何も起こりません。

色々調べたら、こ ちらにOTA Updateに関する資料が有りました。
いつものようにGoogle翻訳君の出番です。



出展:https://github.com/SuperHouse/esp-open-rtos/wiki/OTA-Update- Configuration

Steps to support OTA updates

1. Build and flash an OTA-enabled firmware


Makefileにextras / rboot-otaコンポーネントを含めると、すべてのesp-open-rtosファームウェアをOTA対応にできます。
そしてota_tftp_init_server(TFTP_PORT);でTFTPサーバータスクを実行します。
始めたばかりの場合は、esp-open-rtosソースツリーのota_basicの例を試してください。

cd examples/ota_basic
make flash

... ESP8266をリセットすると、ota_basicの例では、現在スロット0/2、オフセット0x2000で実行されていることを示すメッセージが表示 されます。

OTA Basic demo.
Currently running on flash slot 0 / 2.

Image addresses in flash:
*0: offset 0x00002000
 1: offset 0x00102000
Starting TFTP server...

2. OTA Updating over TFTP


ota_basicの例では、組み込みのOTA TFTPサーバタスクを使用して更新します。
新しいイメージをフラッシュするには、ESP 8266のIP(シリアルに表示されている)を探し、TFTPコマンドラインツールを使用してイメージをアップロードします。

tftp -v -m octet 192.168.0.20 -c put firmware/ota_basic.bin firmware.bin

... IPをESP8266のIPに置き換えます。

繰り返しflashさせると、ブートオフセットがスロット0とスロット1の間で入れ替わります(つまり、0x2000と0x102000)。



要するにota_tftp_init_server()でTFTPサーバーを実行して、コマンドラインからtftpを実行すれば良さそうです。
そこで、機能を分かりやすくするために、ota_basic.cを以下のように変更しました。
タスクを1つ起動していますが、何もしないダミーのタスクです。
/* The example of esp-free-rtos
 *
 * This sample code is in the public domain.
 */
#include <string.h>
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "ssid_config.h"

#include "ota-tftp.h"
#include "rboot-api.h"

void dummy_task(void *pvParameters)
{
    while(1) {
        vTaskDelay(5000 / portTICK_PERIOD_MS);
    }
}

void user_init(void)
{
    uart_set_baud(0, 115200);

    rboot_config conf = rboot_get_config();
    printf("\r\n\r\nOTA Basic demo.\r\nCurrently running on flash slot %d / %d.\r\n\r\n",
           conf.current_rom, conf.count);

    printf("Image addresses in flash:\r\n");
    for(int i = 0; i <conf.count; i++) {
        printf("%c%d: offset 0x%08x\r\n", i == conf.current_rom ? '*':' ', i, conf.roms[i]);
    }

    //printf("This is NEW FIRMWARE\n");

    struct sdk_station_config config = {
        .ssid = WIFI_SSID,
        .password = WIFI_PASS,
    };
    sdk_wifi_set_opmode(STATION_MODE);
    sdk_wifi_station_set_config(&config);

    printf("Starting TFTP server...");
    ota_tftp_init_server(TFTP_PORT);

    xTaskCreate(&dummy_task, "dummy", 512, NULL, 2, NULL);
}

まずはこれをビルドして書き込みます。


IPアドレスが表示されるだけです。



次に、ソースの
//printf("This is NEW FIRMWARE\n");
のコメントを外してmakeだけします。

新しいファームができたら、以下のコマンドを実行します。IPアドレスはそれぞれの環境に置き換えてください。
$ tftp 192.168.10.154
tftp> mode octet
tftp> put firmware/ota_basic.bin firmware.bin
Transfer timed out.

本当はここで自動的にリセットが掛かって再起動するはずなんですが、NodeMCUやWeMosでは
以下の様に止まってしまうことが有ります。(止まらないボードも有ります)


NodeMCUやWeMosの様に、自動リセット回路を持っているボードは、
ファーム書き込み時のDTRとRTSの信号を元に、
自動的にUART Downloadモード(GPIO0がLOW)で再起動し、Flashへの書き込みを行いますが、
Flashへの書き込みが終わると、再度UART Downloadモードで起動してしまうためです。
これを回避するためには、Flashへの書き込み後に、一度強制的にリセットしてやると
今度は、Flash Bootモード(GPIO0がHIGH)で起動してリセットが正常に動くようになります。

リセット後に起動すると、アクティブなスロットが1になって、コメントを外したコードが有効になっています。




こちら
にESP8266のMemory Mapが公開されています。
SPI Flash ROM Layout (with OTA upgrades)を見ると、
User application, slot 1 と User application, slot 2 の2つのSLOTがあり、
Bootloaderがこれを切り替える仕組みの様です。
でも、ESP8266のIPアドレスが分からないと、OTAでのファーム書き換えは使えないです。

続く....