2021年8月11日水曜日

MicroPython ESP32 Memo 〜Add micropython-ulab〜

■概要

MicroPythonで、FFTで周波数抽出したりしたい。
MicroPythonのデフォルトには、FFTを使ったりするモジュールは入っていないらしい。
調べると、ulabというモジュールが使えるらしい。

MicroPythonにulabを組み込んでビルドするまでの手順をまとめる。

■環境

  • PC : Mac OS Catalina
  • Board : ESP32-WROOM-32D 開発ボード ESP32-DevKitC-32
  • 開発環境 : ESP-IDF

■前提知識

■手順

基本的には、 micropython-ulab のREADMEに書いてある内容。(一部違う) とりあえず、できた手順を忘れないようにまとめる。

■ディレクトリ構成

MicroPython
    |- project
        |- esp-idf         // esp-idfのコードをクローンしたところ
        |- micropython     // micropythonのコードをクローンしたところ
        |- ulab            // ulabのコードをクローンしたところ
  

■ビルドディレクトリのexport

  1. 「project」ディレクトリを開く
    「cd project」
  2. ビルドディレクトリをexport
    「export BUILD_DIR=$(pwd)」

■micropython, esp-idfのclone

MicroPython ESP32 Memo 〜Build MicroPython〜 を参照。

■ulabのclone

  1. ビルドディレクトリを開く
    「cd $BUILD_DIR」
  2. ulab をcloneする。
    「git clone https://github.com/v923z/micropython-ulab.git ulab」

■esp-idfのビルドとパスを通す

  1. ビルドディレクトリを開く
    「cd $BUILD_DIR」
  2. esp-idfディレクトリに移動
    「cd esp-idf」
  3. esp-idfのインストールとパスを通す
    「./install.sh」
    「. ./export.sh」

■micropythonのクロスコンパイラとESP32のサブモジュールをビルドする

  1. ビルドディレクトリを開く
    「cd $BUILD_DIR」
  2. micropythonのクロスコンパイラをビルドする
    「cd $BUILD_DIR/micropython/mpy-cross」
    「make」
  3. ESP32のサブモジュールをビルドする
    「cd $BUILD_DIR/micropython/ports/esp32」
    「make submodules」

■micropythonのビルド設定を変更する

ulabモジュールをビルドに追加する

  1. makefileを開く
    「cd $BUILD_DIR/micropython/ports/esp32」
    「vi Makefile」
  2. ulabモジュールを追加する。
    「BOARD ?= GENERIC」となっているところを、以下のように変更する。
    # BOARD ?= GENERIC
    BOARD = GENERIC
    USER_C_MODULES = $(BUILD_DIR)/ulab/code/micropython.cmake
        
  3. Escを押してから、「:wq」を入力し、Enterを押して、ファイルを保存する。

パーティション(メモリ割り当て)の変更

ESP32のデフォルトのパーティション設定では、ulabを追加してビルドすると、サイズエラーが出る。
アプリケーション領域が小さいっぽい。そのため、パーティション設定を変更する。

パーティション設定は、デフォルトでは、partitions.csvが利用されている。
そのため、ulab用のパーティションファイル partition_ulab.csvを作成して、設定をpartition_ulab.csv に変更する。

ulab用パーティションファイルを作成する

  1. パーティションファイルを作成する。
    「cd $BUILD_DIR/micropython/ports/esp32」
    「vi partitions_ulab.csv」
  2. partitions_ulab.csv を以下のようにする。
    # Notes: the offset of the partition table itself is set in
    # $ESPIDF/components/partition_table/Kconfig.projbuild and the
    # offset of the factory/ota_0 partition is set in makeimg.py
    # Name,   Type, SubType, Offset,  Size, Flags
    nvs,      data, nvs,     0x9000,  0x6000,
    phy_init, data, phy,     0xf000,  0x1000,
    factory,  app,  factory, 0x10000, 0x200000,
    vfs,      data, fat,     0x220000, 0x180000,
        
  3. Escを押してから、「:wq」を入力し、Enterを押して、ファイルを保存する。
  4. パーティションファイルを作成する。

ulab用パーティションファイルを使用するように設定を変更する

  1. sdkconfig.base を開く
    「cd $BUILD_DIR/micropython/ports/esp32/boards」
    「vi sdkconfig.base」
  2. sdkconfig.base を変更する。
    「CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"」となっているところを、以下のように変更する。
    #CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
    CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_ulab.csv"
        
  3. Escを押してから、「:wq」を入力し、Enterを押して、ファイルを保存する。

■micropython(ulab入り)のビルド

  1. 「cd $BUILD_DIR/micropython/ports/esp32/」
  2. 「make clean」 (過去にmicropython のビルド等をしている場合、必要かも?エラーが出ることがある?)
  3. 「make」

■動作確認

ESP32にダウンロードして、REPLで動かし、 「import ulab」として、エラーが出なかったらOK! 「help(ulab)」で、numpyやscipyが使えるのがわかる。

ダウンロード

  1. 「cd $BUILD_DIR/micropython/ports/esp32」
  2. 「make erase PORT=/dev/tty.usbserial-xxxx」
  3. 「make deploy PORT=/dev/tty.usbserial-xxxx」

動作確認

  1. 「screen /dev/tty.usbserial-xxxx 115200」
  2. MicroPythonのREPLが実行されたら
    「import ulab」
    「help(ulab)」

■参考URL

2021年4月30日金曜日

ESP32 Memo 〜 LED Blink 〜

■概要

今まででMicroPythonをDL、Buildして、ESP32で動かすことはできた。
( URL:MicroPython ESP32 Memo 〜Run Python Script〜 )
今度は、ESP32の電源をONして、どんな処理が行われて、MicroPythonが動くようになるのかを知りたい。

公式HPによると、MicroPythonは、4種類のモジュールに分けて作られているらしい。
(MicroPython libraries)

  • 標準的なPythonサブセットを実装しており、ユーザーによって拡張されることを想定していないモジュール
    (Modules which implement a subset of standard Python functionality and are not intended to be extended by the user. )
  • Pythonのサブセットを実装しており、ユーザーによって拡張されることを想定しているモジュール
    (Modules which implement a subset of Python functionality, with a provision for extension by the user (via Python code).)
  • Python標準ライブラリにMicroPython拡張機能を実装しているモジュール
    (Modules which implement MicroPython extensions to the Python standard libraries.)
  • 特定のMicroPythonポートに固有であり、移植生のないモジュール
    (Modules specific to a particular MicroPython port and thus not portable.)

上記のうち、4つ目の、移植性のないモジュールのところで、MicroPythonが動くまでの処理を知りたい。 この部分は、マイコンに固有の処理を行うところで、ここを知れば、他のマイコンにMicroPythonを移植することも可能だと思う。

最終的には、他のマイコンにMicroPythonを移植できるようになりたい。

現在、ESP32でMicroPythonを動かすことはできたものの、中身がどうなってるのかは不明。 というか、プログラムがどこから始まるのかもわかっていない。

そこで、まずはESP32の基本的な知識を学ぶ必要がある!
というわけで、プロジェクトを初めから作成して、Lチカまでできるようになるぞー!

■環境

  • PC : Mac OS Catalina
  • Board : ESP32-WROOM-32D 開発ボード ESP32-DevKitC-32
  • 開発環境 : ESP-IDF

■前提知識

なし?

■手順

ESP-IDF Programming Guide を参考に作業を行う。
また、LEDの接続は、MicroPython ESP32 Memo 〜Run Python Script〜 と同じにする(32番ピンにLEDを接続)。 まずは開発環境の構築から。 と思ったけど、すでにやってたので、こちらを参照。
(URL: MicroPython ESP32 Memo 〜Build MicroPython〜)
環境変数の設定からはやっていないので、そこから始める。 ちなみに、ファイル構成は以下の通り。

MicroPython
    |- project
        |- esp-idf         // esp-idfのコードをクローンしたところ
        |- esp32_practice  // ここにLチカのプロジェクトを作る
        |- micropython     // micropythonのコードをクローンしたところ(今回は関係ない)
  

terminalでは、最初にMicroPythonフォルダにいるものとする。 というわけで、環境変数を設定する。

  1. 環境変数を設定する。
    「. $HOME/・・・/Micropython/project/esp-idf/export.sh」
    (※・・・ は割愛)
  2. エイリアスを設定する。(よく使う人向け)
    「alias get_idf='. $HOME/・・・/Micropython/project/esp-idf/export.sh'」
    これをすることで、「get_idf」だけで、環境変数の設定(esp-idf/export.sh)を実行できるようになるため、 esp-idfの環境の設定やリセットを簡単にできるようになる。

次に、プロジェクトを作成してビルドする。
(プロジェクトを作成すると言っても、サンプルプロジェクトをコピーするだけ。)

  1. プロジェクトを作成する。
    (サンプルのプロジェクト(hello_world)をコピーする)
    「cd project/esp32_practice」
    「cp -r ../esp-idf/examples/get-started/hello_world .」
  2. プロジェクトフォルダに移動する。
    「cd hello_world」
  3. ターゲットCPUを設定する。
    「idf.py set-target esp32」
    (※ この操作は、プロジェクトを作成してから1回だけ実行すべきらしい。)
  4. コンフィグレーションを設定する。
    「idf.py menuconfig」
    このmenuconfigで、Wifiの名前やパスワードなどを設定できるらしい。
    ただ、今回のhello_worldではデフォルトのままでいいので、何もいじらなくていいため、即閉じる。 (※ ESP32-DevKitC の ESP32-SOLO-1 が載っているのを使用している場合は、CONFIG_FREERTOS_UNICORE のパラメータを変更して、シングルコアモードをEnableにしないといけないらしい。)
  5. プロジェクトをビルドする。
    「idf.py build」

最後に、ビルドしたイメージをボードにダウンロード、動作を確認する。

  1. ボードをPCと接続する。
  2. ビルドしたイメージをボードにダウンロードする。
    「ls /dev/tty.usb*」
    (接続されたポートをチェックする。
     /dev/tty.usbserial-xxxx につながっていたと仮定する)
    「idf.py -p /dev/tty.usbserial-xxxx -b 460800 flash」
  3. 動作確認する。screenコマンドでシリアルをモニタする。
    カウントダウンと「Hello world!」が表示されれば成功!
    「screen /dev/tty.usbserial-xxxx 115200」

というわけで、プロジェクト作成(サンプルをコピーしただけ)とビルド、書き込みまではできたが、、、
LED、光らせてない。。。
というか知りたい情報はこれじゃない感。。。
とりあえず、LEDを光らせるまではやろうと思う。

サンプルの中に、LEDを点滅させるプロジェクトが実は用意されているので、これを利用する。

  1. LED点滅のプロジェクトをコピーする。 「cd ../」
    ( MicroPython/project/esp32_practice ディレクトリに移動)
    「cp -r ../esp-idf/examples/get-started/blink .」
  2. blinkプロジェクトフォルダに移動。
    「cd blink」
  3. ターゲットCPUを設定。 「idf.py set-target esp32」
  4. コンフィグレーションを設定する。
    今回は、LEDを点滅させるポートを変更するため、menuconfigを開く。
    「idf.py menuconfig」
  5. menuconfigが開いたら、LEDを点滅させるポートを変更する。 menuconfigの「Example Configuration」->「Blink GPIO number」を選択してEnter。
    LEDを接続しているポート(32番ピン)を入力してEnter。
    「S」を押して、Saveして、「Q」を押してQuit。
    menuconfigが閉じる。
  6. プロジェクトをビルドする。
    「idf.py build」
  7. ビルドしたイメージをボードにダウンロードする。
    「idf.py -p /dev/tty.usbserial-xxxx -b 460800 flash」
  8. LEDが1秒おきに点滅したら成功!
LEDの点滅までできた。
が、これではESP32の起動とか、どんなコード書いたらこうなるとか、全くわからん。

LED点滅のblink.cをみたが、void app_main(void) 関数のみが書いてあり、 その中で、FreeRTOSの vTaskDelay(1000 / portTICK_PERIOD_MS); を使って、1秒おきにGPIOのHigh/Lowを切り替えているだけだった。
一般的に、Bootloaderの実行が終わったら、main()関数が実行されるが、ESP32は、void app_main(void) 関数が実行されるようになっているらしい。
しかも、vTaskDelay()関数が実行されているということは、app_main()関数が実行されるまでに、 FreeRTOSの初期化関数等の実行もすでに完了されている。

知りたいのは、MicroPythonの実行のされ方。
ESP32の場合、MicroPythonは、FreeRTOSの上で動いているらしい。
つまり、FreeRTOSの初期設定が終わって、app_main()が実行されてから、MicroPythonの初期化を行って、REPLなどが実行されるようになっている?

とりあえず、ESP32は、bootloader実行後、app_main()関数が実行されることは分かったので、 MicroPythonのソースコードでapp_main()があるかどうかをみて、それを起点にMicroPythonのコードの中身を見ていきたい。
ちなみに、bootloaderで、ドライバやFreeRTOSなど、どんな設定をしているのかも知りたい。
・・・気が向いたら・・・。

2021年4月29日木曜日

MicroPython ESP32 Memo 〜Run Python Script〜

 ■概要

作成したMicroPythonファームウェアに、Python Scriptファイル(.pyファイル)をダウンロード、実行する。
やる内容は、main.pyファイルを作成し、ボードにダウンロード、main.pyを実行するまで。
main.pyには、LEDを点滅するコードを書く。

シリアルプロンプトによるREPL(Read Evaluate Print Loop)でのプログラム?はいろんなところに載っているので、書かなくてもいいかな。
ただ、作成したPython Script(.pyファイル)を実行するやり方はあんまり書かれてない気がするので、メモに残しておく。

■環境

  • PC : Mac OS Catalina
  • Board : ESP32-WROOM-32D 開発ボード ESP32-DevKitC-32

■前提知識

ESP32は、ESP8266と大体同じ使い方ができるらしいので。。。

デバイスが 1Mbyte 以上のストレージを持っているなら、ファイルシステムを含むように(最初の起動時に)設定されます。このファイルシステムは FAT フォーマットを使用し、MicroPython ファームウェアの後にフラッシュに保存されます。
ESP32にも同じことが言える。
ESP32-WROOM-32D 開発ボード ESP32-DevKitC-32の仕様は以下の通り。
  • Product Description
    • ESP32 general-purpose development board, embeds ESP32- WROOM-32D, 4 MB flash, with pin header
  • Flash Size
    • 4MB
  • Antenna Type
    • Internal PCB on- board antenna
  • Temperature
    • –40 °C ~ +85 °C
  • Dimensions (mm)
    • 54.4×27.9
Flash Sizeは4MBなので、ファイルシステムが構築される。

で、このファイルシステムの中に、実行するPython Script(.pyファイル)をおけば、実行することができる。ただ、どんな名前でも良いわけではない。
MicroPythonは、起動時、最初にboot.pyを実行する。
boot.pyの実行が終了すると、次にmain.pyを実行する。(なければ実行されない)
というようになっているので、boot.py or main.pyを作成すれば、とりあえず動かすことができる。

ただ、デフォルトでは、REPLがされるっぽいので、ソフトリセットをすることで、Python Scriptを実行するモードにしなければならない。

以上を踏まえて、
  • main.pyを作成する。
  • main.pyをボードにダウンロードする。
  • Python Scriptが実行されるモード?にする。
の手順を行えば、作成したPython Scriptが起動後実行されるようになる。

■手順

ボードにLEDと抵抗を配線をする。
以下のように配線する。
  • ESP32ボードの32番ピン - LEDのアノード
  • LEDのカソード - 抵抗 47Ωの片方
  • 抵抗47Ωのもう片方 - ESP32ボードのGNDピン

次に、事前準備として、ampyをインストールしておく。
ampyは、Adafruit社が開発したツールで、シリアル回線経由でPCとボードとの間でファイル転送ができる。(参考 : ampy: MicroPythonマイコンとPCとのファイル転送ツール)
  1. ターミナルで、以下のコマンドでampyをインストールする。
    「sudo pip install adafruit-ampy」

次に、Python Scriptファイル main.pyファイルを作成する。
main.pyはこんな感じ。

from machine import Pin
import time

p32 = Pin(32, Pin.OUT)

while True:
    print("LED ON")
    p32.on()                 # set pin to "on" (high) level
    time.sleep(1)
    print("LED OFF")
    p32.off()                # set pin to "off" (low) level
    time.sleep(1)

次に、作成したmain.pyをボードにダウンロードする。
先ほどインストールしたampyを使ってダウンロードする。
こちらのサイト(URL : ampy: MicroPythonマイコンとPCとのファイル転送ツール)を参考にした。
  1. PCとボードをUSBで接続する。
  2. ターミナルでmain.pyを保存した場所に移動する。
    (scriptsフォルダに保存している場合)
    「cd scripts」
  3. 接続されたポートをチェックする
    「ls -l /dev/tty.usb*」
    /dev/tty.usbserial-xxxx (xは数字?)が接続ポート。
  4. ボード(のFlash)に保存されているファイルを表示する。
    「ampy --port=/dev/tty.usbserial-xxxx ls」
    (※ デフォルトでは、boot.py だけが表示された。)
  5. 作成したmain.pyをボードにダウンロード(保存)する。
    「ampy --port=/dev/tty.usbserial-xxxx put main.py」
  6. main.pyがボードに保存されたかどうかを確認する。
    「ampy --port=/dev/tty.usbserial-xxxx ls」
    boot.pyに加えて、main.pyが追加されていれば成功!
ダウンロードしただけでは、ボードはREPLで動いている。
そのため、最後に、ソフトウェアリセットして、REPLで動くモードから、Scriptで動くモードにして、main.pyを実行させる。
LEDがチカチカするはず!
  1. ターミナルでREPLの画面を出す。
    「screen /dev/tty.usbserial-xxxx 115200」( ※ 115200bps )
    (※REPLが動いているので、Enterを押すと「>>>」が表示されるはず。)
  2. ボードをソフトウェアリセットする。
    screenで接続している時に、「Ctrl+D」でソフトウェアリセットできる。
    ソフトウェアリセットされて、REPLでなく、ただのシリアル通信として繋がり、
    「LED ON」「LED OFF」が表示されつづけ、LEDが点滅していれば成功!
ちなみに。。。
ampyでもリセットできるっぽい。
「ampy --port=/dev/tty.usbserial-xxxx reset」
これでも、ソフトウェアリセットがかかって、Scriptが実行されるはず。

終わり!

2021年4月11日日曜日

MicroPython ESP32 Memo 〜Build MicroPython〜

 ■概要

MicroPythonのbinaryファイルダウンロードしてを書き込んだら動いた!
ので、今度はMicroPythonをビルドしたい!

ので、MicroPythonをgitから持ってきて、ビルドして、binaryファイル作って、ボードで動かすまで。

■環境

  • PC : Mac OS Catalina
  • Board : ESP32-WROOM-32D 開発ボード ESP32-DevKitC-32

■手順

基本的に、MicroPythonの公式の通り。

まず、Gitからソースコードを取得する。
Git Hubのアカウントを持ってなかったら、作成しておく必要あり。
PCにgitをインストールしておく必要あり。
  1. 公式のmicropythonリポジトリをforkする。
    1. Git Hubにログイン(ブラウザから)
    2. ログインしたら、Search or Jump to... で「micropython/micropython」を検索して、公式のMicroPythonリポジトリにアクセス。
    3. 「fork」ボタンを押して、自分のリポジトリに公式のMicroPythonリポジトリをforkする。
    4. 自分のアカウントにmicropythonリポジトリができていることを確認する。
      自分のmicropythonリポジトリURL :
      「https://github.com/<your-user-name>/micropython」
  2.  ローカルにプロジェクト(ソースコード etc.)をcloneする。
    1. terminalでmicropythonのソースコードを保存するところに移動する。
      「cd project」(projectフォルダに入れる場合)
    2. 自分のmicropythonリポジトリからプロジェクトをcloneする。
      「git clone https://github.com/<your-user-name>/micropython」
  3. 公式のmicropythonリポジトリを自分のmicropythonリポジトリの上流ブランチに設定する
    (公式のMicroPythonリポジトリで更新された内容を、自分のmicropythonリポジトリが追従できるようにする設定)
    (※ 上流ブランチと追跡ブランチの説明)
    1. terminalで、cloneしたmicropythonフォルダに移動
      「cd micropython」
    2. 公式のMicroPythonリポジトリを自分のmicropythonリポジトリの上流ブランチに設定する
      「git remote add upstream https://github.com/micropython/micropython」
      (※ 多分、upstream xxxx で、xxxxが上流ブランチであることを教えてる?)
      (※ この設定で、「git pull」により公式のMicroPythonリポジトリの変更を反映できるようになる?気がする。ちなみに、pullは、fetchしてmergeするのと同じことらしい(fetchとpullの違い)。)
    3. 上流ブランチを設定できたか確認。
      「git remote -v」
      以下のような表示が出るはず。
      「origin       https://github.com/<your-user-name>/micropython (fetch)
      origin       https://github.com/<your-user-name>/micropython (push)
      upstream     https://github.com/micropython/micropython (fetch)
      upstream     https://github.com/micropython/micropython (push)」
  4. 作業用branchを作成する。
    1. terminalで、cloneしたmicropythonフォルダに移動
    2. 作業用branchを作成して、作業用branchに切り替える。
      (develop-branch というbranchを作成して、master→develop-branch に切り替え)
      「git checkout -b develop-branch」
次に、クロスコンパイルに必要なソフトウェアパッケージをインストールする。
公式のMicro Python on MacOSを参考にした。
  1. Xcodeが入ってなければ入れる。(clang コンパイラを入れるため)
  2. 必要なソフトウェアパッケージをインストール。
    「brew install libffi」
    「brew install pkgconfig」
    Pythonをインストールしてなければ、Python3.3以上をインストール。
    Gitもインストールしてなければインストール。
次に、クロスコンパイラをビルドする。
  1. terminalで、cloneしたmicropythonフォルダに移動。
    (すでにいる気がするなぁ)
    「cd micropython」
  2. クロスコンパイラをビルドする。
    「export PKG_CONFIG_PATH=/usr/local/Cellar/libffi/3.2.1/lib/pkgconfig/」
    「make -C mpy-cross」
    (※ home brewでlibffiを入れたので、export PKG_CONFIG・・・が必要。)
  3. クロスコンパイラのビルドが成功したら、
    micropython/mpy-crossフォルダの中に、
    mpy-cross.map, build, mpy-cross ができてる。
そしてついに、micropythonをビルドする!
が、まずは手始めに、unix用をビルドする。
Mac上で動かすことが可能なmicropythonが出来上がるはず。
  1. 「cd micropython/ports/unix」
  2. 「make axtls」
    (※ axtlsは、少量のメモリフットプリントの高度な設定インターフェイスで組み込みデバイス向けに設計されたTLSv1 SSLライブラリ。)
    結構時間かかる。
  3. micropython (unix用)をビルドする
    「make」
    結構時間かかる。
  4. ビルドが完了すると、micropython/ports/unix 以下に、build-standard, micropython フォルダなどが追加されている。
  5. micropython (unix用)を動かす。
    「./micropython」
    実行すると、以下のように、>>> が表示されて、おなじみのpythonっぽい表示が!

    「unix % ./micropython 

     MicroPython v1.14-152-g6f06dcaee on 2021-04-12; darwin version

     Use Ctrl-D to exit, Ctrl-E for paste mode

     >>>        」


ほんとについに!micropython ESP32用をビルドする。
が、今までのはunix用の環境設定+ビルド方法だったみたい。
ESP32用をビルドするためには、ESP32に合わせた環境設定からはじめないといけない。
公式のmicropython ESP32のREADMEにしたがって進める。

というわけで、micropython ESP32用の環境設定を行う。
まずは、esp32の開発環境のEspressif IDF version 4 をインストールする。
Espressif IDFを略して ESP-IDF と言ってるっぽい?
ESP-IDF のプログラミングガイドに、MacOSの場合のインストールの方法が書いてあったので、これ参考にする。micropython ESP32のREADMEよりも詳しく書かれてるし。
(pip, python, homebrew はインストールずみとする。)
  1. 事前準備として必要なパッケージをインストール
    「brew install cmake ninja dfu-util」
    「brew install ccache」
  2. ESP-IDFをclone
    (※ micropythonをcloneしたディレクトリと同じ階層にclone)
    (※ 2021/04/14現在、安定版の最新がv4.2)
    「git clone -b v4.2 --recursive htps://github.com/espressif/esp-idf.git」
  3. ESP-IDFをインストール
    「cd esp-idf」
    「./install.sh」
    → エラーが出た。。。Python2.7がカレントバージョンになってるのがダメらしい。
     Python3をカレントバージョンにして実行するとよい。(参考 : macOS Catalina zsh環境でpyenvを使ってPython 3.9.0をインストール)
    「source export.sh」
    (※ idf.py が使えるようになったよ!と表示されるが、よくわからん)
  4. micropythonをビルド
    1. cloneしたmicropythonフォルダに移動
      「cd ../micropython」
    2. クロスコンパイラをビルド
      「make -C mpy-cross」
    3. ESP32のソースコードが置いてあるところに移動
      「cd ports/esp32」
    4. サブモジュールをビルド
      (サブモジュールをアップデートしているだけ?)
      「make submodules」
    5. ESP32 micropythonをビルド
      「make」
    6. ESP32 micropythonがビルドてきたかどうかを確認する
      「ls」で、「build-GENERIC」フォルダができていることを確認。
      「ls build-GENERIC」で、firmware.bin ができていることを確認。
      できてればOK !!!
バイナリファイル ができたので、動作確認をする。
MicroPython ESP32 Memo 〜FW書き込み〜 に書いた方法で、作成したfirmware.bin を書き込むことができる。
MicroPythonの公式(MicroPython Internals Getting Started)には、idf.pyを使った書き込み方法が書かれているので、こちらの方法を試してみる。
(ただ、idf.pyは、中でesptool.pyを使って書き込んでいるだけなので、やっていることは同じはず?)
  1. cloneしたmicropythonフォルダのports/esp32に移動
    (上から続けてれば何も操作はいらないはず?)
  2. ESP32ボードをUSBでPCと繋ぎ、接続されたポートを調べる。
    「ls -l /dev/tty.usb*」
    (/dev/tty.usbserial-xxxx につながっていたと仮定する)
  3. ESP32ボードのflashをクリアする。
    「make erase PORT=/dev/tty.usbserial-xxxx」
    (※ 引数にPORT=xxxxをつけることで、ターゲットのポートを設定できる。
       デフォルトは/dev/ttyUSB0 となっているため、ちゃんとポート指定しないとエラーになる。)
  4. EPS32ボードにファームウェアを書き込む
    「make deploy PORT=/dev/tty.usbserial-xxxx」
    (※ make と実行すると、idf.pyが実行されるようになっている。
       idf.pyを直接使い方法もMicroPythonの公式HPに書かれている)
(※ [補足]
idf.pyで書き込む時、書き込まれるバイナリファイルは、build-GENERICフォルダ内の、partition_table/partition-table.bin(WriteAddress:0x8000〜)、bootloader/bootloader.bin(WriteAddress:0x1000〜)、micropython.bin(WriteAddress:0x10000〜)の3つ。
firmware.binはこの3つを合わせたバイナリファイルとなっている。 )

書き込んだら、「screen <USBport> 115200」で接続し、Pythonおなじみの
>>> 
が表示されることを確認した。

やった!できたよ!

2021年4月9日金曜日

MicroPython ESP32 Memo 〜FW書き込み〜

■概要

MicroPython を始める時の覚書。
ボードに出来上がりのMicroPythonを書き込んで動作確認するまで。

■環境

  • PC : Mac OS Catalina
  • Board : ESP32-WROOM-32D 開発ボード ESP32-DevKitC-32

■手順

基本的に、MicroPythonの公式ページの通り
公式はpipだが、brewでもできた気がする
  1. MicroPythonのFWをダウンロード
    (Firmware with ESP-IDF v3.x のSPIRAMじゃないほうの最新を使った)
    (URL : Firmware for Generic ESP32 module)
  2. PCとボードをUSBで接続する
  3. terminalを開き、FWを保存したディレクトリにcd コマンドで移動
  4. epstoolをインストールする
    「pip3 install esptool」
  5. 接続されたポートをチェックする
    「ls -l /dev/tty.usb*」
    /dev/tty.usbserial-xxxx (xは数字?)が接続ポート。
  6. フラッシュを消去する
    「esptool.py --port /dev/tty.usbserial-xxxx erase_flash」
  7. フラッシュにFWを書き込み
    「esptool.py --chip esp32 --port /dev/tty.usbserial-xxxx write_flash -z 0x1000 esp32-idf3-20210202-v1.14.bin」
    (esp32-idf3-20210202-v1.14.bin が最新でした @2021/04/09 )
  8. 終わり!

動作確認する。
デフォルトでは、シリアル通信でREPLを利用できる。
  1. PCとボードをUSBで接続する
  2. terminal を開く。
  3. 接続されたポートをチェックする
    「ls -l /dev/tty.usb*」
    /dev/tty.usbserial-xxxx (xは数字?)が接続ポート。
  4. 「screen /dev/tty.usbserial-xxxx 115200」( ※ 115200bps )
    適当にEnterを押すと、「>>>」が表示され、Pythonのインタプリタが使える。はず。

■参考

2018年11月25日日曜日

Raspberry Pi3 Redmine導入 エラーからの復活 まとめ

[背景]
https://chuchulabo.blogspot.com/2018/11/raspberry-pi3-redmine.html
でRedmine入れて,他のPCからRedmineのページが見れることを確認した。
浮かれた気分でRaspberry Pi3 を「sudo reboot」で再起動!

もう一度,Redmineのページが見れるかどうかを確認。
・・・見れなくなってた・・・
これが出るようになった。

We're sorry, but something went wrong.

We've been notified about this issue and we'll take a look at it shortly.
なーんーでーやー!

[目的]
Redmineのページを見れるように修復

[内容]
----- 現象 -----
いろいろいじってると,postgresqlにログインできないなくなっていることに気が付いた。
pi@raspberrypi:/ $ psql
psql: サーバに接続できませんでした: そのようなファイルやディレクトリはありません
ローカルにサーバが稼動していますか?
Unixドメインソケット"/var/run/postgresql/.s.PGSQL.5432"で通信を受け付けていますか?
----- 修正方法 -----
postgresqlを再インストールすれば直った。
再インストールの方法
  1. postgresqlを削除 「sudo apt-get --purge remove postgresql」
  2. postgresqlが削除できているか確認 「dpkg -l | grep postgres」
  3. 何も出てこなければOK。
    そうでなければ,
    「sudo apt-get --purge remove postgresql postgresql-doc postgresql-common」
    といった形で,出てきたものを一つずつスペースで区切って削除する。
  4. 「dpkg -l | grep postgres」で,何も表示されなくなるまで繰り返し。
  5. 再起動 「sudo reboot」 (別にいらないかも)
たとえば,「dpkg -l | grep postgres」で,つぎのように表示された場合,
pi@raspberrypi:/ $ dpkg -l | grep postgres
ii  postgresql-client-9.6                 9.6.10-0+deb9u1                   armhf        front-end programs for PostgreSQL 9.6
ii  postgresql-client-common              181+deb9u2                        all          manager for multiple PostgreSQL client versions
「sudo apt-get --purge remove postgresql postgresql-client-9.6 postgresql-client-common」
を実行して削除する。
最終的に,「dpkg -l | grep postgres」を実行して,何も表示されなくなればOK。
参考 : https://askubuntu.com/questions/32730/how-to-remove-postgres-from-my-installation

次に,postgresqlのインストールと初期設定を行う。 Redmineの公式の通りにしただけでは,おそらく同じようにRaspiを再起動したら使えなくなると思ったため。
  1. postgresqlをインストール 「sudo apt install postgresql」
  2. postgresqlサーバをインストール 「sudo apt install postgresql-server-dev-9.6」
  3. postgresqlユーザで,postgresqlのターミナルに入る。 「sudo -u postgres psql postgres」 ("postgres=#" が表示される。)     
    • 「CREATE ROLE redmine LOGIN ENCRYPTED PASSWORD 'your_password' NOINHERIT VALID UNTIL 'infinity'; CREATE ROLE」
    • 「CREATE DATABASE redmine WITH ENCODING='UTF8' OWNER=redmine;」
    • 「\q」(postgresqlからquit)
  4. postgresユーザのパスワード変更 「sudo passwd postgres」
  5. postgresユーザでログイン 「su - postgres」
    piユーザから,posgtresユーザに切り替わる。(postgres@raspberrypi:~$ が表示される。)
    • postgresqlのターミナルに入る。 「psql」
      • データベースロールの確認 「\du」
      • 「\q」(postgresqlからquit)
    • postgresユーザからログアウト 「exit」
  6. ディレクトリ移動 「cd /etc/postgresql/9.6/main/」
  7. pg_hba.confを編集 「sudo nano pg_hba.conf」
    ・・・(省略)・・・
    # Database administrative login by Unix domain socket
    # local   all             postgres                                peer
    local   all             postgres                                trust 
    
    # TYPE  DATABASE        USER            ADDRESS                 METHOD
    
    # "local" is for Unix domain socket connections only
    # local   all             all                                     peer
    local   all             all                                     trust
    ・・・(省略)・・・
    
  8. postgresqlを再起動 「sudo service postgresql reload」
  9. ここから先は,公式の操作の6.からを再度トレースする https://www.redmine.org/projects/redmine/wiki/HowTo_Install_Redmine_on_Debian_9
調べながらの作業では,実際に,上述の手順では行なっていないが,見直すと,こんな感じになっていた。

[結論]
大体の流れとして,psqlを再インストールして,postgresユーザの設定をして,公式の通りに操作すればOK。

[参考URL]

2018年11月20日火曜日

Raspberry Pi3 Redmine導入 仕切り直し


Raspberry Pi3 Redmine導入 仕切直し

[背景]
Redmineの導入に前失敗したし,
このままやと負けた気がするし,
とにかくRedmine入れたい!
いじりたい!

[目的]
Rasperry Pi3 Raspbian stretch にRedmineを入れる

[内容]
まず,前回で,設定がぐちゃぐちゃになっていたので,クリーンインストール。
NOOBで,Raspbianを入れて,クリーンな状態に。

  1. Raspbianの初期設定。
    https://chuchulabo.blogspot.com/2018/09/raspberry-pi-3.html
  2. Redmineのインストール。
    前回日本語で調べてたら出てこなかったけど,「redmine howto install」で調べたら,Redmineの公式のマニュアルが出てきた。
    RaspbianはDebian系なので,Debian Stretchへのインストール方法をそのまま実行。
    http://www.redmine.org/projects/redmine/wiki/HowTo_Install_Redmine_on_Debian_9
  3. 終わり!
「redmine howto install」でトップに出てくるリンク先は,上に貼ったリンクとは違う。
が出てくる。
このページに,
Redmine should run on most Unix, Linux, macOS, macOS Server and Windows systems as long as Ruby is available on this platform. See specific installation HowTos here.
と書いてある。
OS毎のインストール方法を見たい場合は,"here"のリンク先を参照してね。とのこと。
このリンク先から,Debian Stretchへのインストール方法のページに移動する。
ちなみに,"here"のリンク先は,以下。
http://www.redmine.org/projects/redmine/wiki/HowTos

[注意事項]
Redmineのインストールで,bundleをインストールするところがある。
"bundle install"コマンドを実行する前に,
"cd /opt/redmine/redmine-3.4.6/"コマンドで,ディレクトリを移動しておくこと。
理由としては,"bundle install"コマンドは,Gemfileがあるところでやらないと失敗するから。
できなくても,出てきたエラーでググったら簡単にどうすればいいかがわかる。
確か,GemFileがあるところをfindで探して,・・・的なHPがあるので,見たらわかる。

また,Redmineのインストールのマニュアルにある,
your_ip_addressとか,your_password とかは,適宜自分のraspberry piの設定に合わせる。

[まとめ]
公式あるなら,初めから見てればよかった・・・。
気づかなかった・・・そりゃ公式あるよね・・・。



2018年10月18日木曜日

Raspberry Pi3 Redmine導入(諦めました)

Raspberry Pi3 Raspbian Stretch redmineインストール覚書
(まだできてません)

[背景]
Raspberry Piをサーバー化してみたい
なんとなくredmineを使いたい

[目的]
Raspberry Pi でRedmineの設定を行う

[内容]
以下のコマンドを順番に実行する。

■ソフトウェアアップデート
  • sudo apt-get update
  • sudo apt-get upgrade 


■Apache, Imagemagick, Ruby, Gitをインストール
  • sudo apt-get install apache2 libapache2-mod-passenger
  • sudo apt-get install imagemagick libmagick++-dev
  • sudo apt-get install ruby-dev bundler
  • sudo apt-get install git subversion

■MySQLをインストール
  • sudo apt-get install mysql-server default-libmysqlclient-dev 



■MySQLのパスワード設定
SSHでインストールとかしてると,rootパスワード設定しろとか言ってくれないから,コマンドを叩いて設定する。

MySQLにログイン。

  • sudo mysql -u root

rootでログインしたら,「MariaDB [(none)]> 」みたいのが表示される。
その状態で,以下のコマンドを実行してrootのパスワードを変更する。
  • update mysql.user set password=password('XXXXXXXX') where user = 'root';
  • (XXXXXXXXは,パスワード。)
つぎに,パスワードの変更を適用して,MySQLのrootからログアウト。
  • flush privileges;
  • exit;
最後に,パスワードが反映されているかどうかをチェックする。
  • sudo mysql -u root -p
  • (この後,パスワードの入力が求められるので,XXXXXXXX(自分が設定したパスワード)を入力する)
多分,rootだけでなく,piについても,同様に設定するのが良いのだと思う。


■MySQLにRedmine用のデータベースを作成

MySQLにログイン。

  • sudo mysql -u root -p

MySQLにログイン後,以下のコマンドを実行。
  • create database redmine default character set utf8;
  • (redmineという名前のデータベースを作成)
  • grant all on redmine.* to redmine@localhost identified by 'redmine';
    (ユーザ名 : redmine, Pass : redmine のユーザを作成)
  • flush privileges;
    (適用!)
redmine用のデータベースが作成されるので,ログアウト。

  • exit;


■Redmineのインストール
  • sudo mkdir -p /var/www/redmine
  • sudo chown www-data /var/www/redmine
  • sudo -u www-data svn co http://svn.redmine.org/redmine/branches/3.3-stable /var/www/redmine
  • (Enter押した記憶ないけど,突然のチェックアウト開始だった)
チェックアウト成功の確認は,以下のコマンドで,なんか色々入ってたらOKだと思う。
  • ls /var/www/redmine

■RedmineとMySQLのRedmine用データベースの紐付け
ファイルを作成。
  • sudo nano /var/www/redmine/config/database.yml
nanoで,以下を入力して,保存。


production:
  adapter: mysql2
  host: localhost
# Redmine用のMySQLデータベース名
  databese: redmine
# Redmine用のMySQLユーザ名
  username: redmine
# Redmine用のMySQLパスワード
  password: redmine
  encoding: utf8


設定ファイルを作成(コピー)。
  • sudo cp /var/www/redmine/config/configuration.yml.example /var/www/redmine/config/configuration.yml


■gemパッケージインストール
  • cd /var/www/redmine
  • sudo -u www-data bundle install --without development test --path vendor/bundle

■gemパッケージの初期設定?
  • sudo -u www-data bundle exec rake generate_secret_token
  • sudo -u www-data RAILS_ENV=production bundle exec rake db:migrate
  • sudo -u www-data RAILS_ENV=production REDMINE_LANG=ja bundle exec rake redmine:load_default_data

■Apacheの設定
  • cd /etc/apache2/sites-enabled
  • sudo nano 000-default.conf
nanoで,以下のように変更して,保存。

DocumentRoot /var/www/html
↓
# DocumentRoot /var/www/html
DocumentRoot /var/www/redmine/public


■Raspberry Piの再起動

  • sudo reboot


■Redmineへアクセス

ブラウザから,Raspberry PiのIPアドレスを叩いて,アクセスしてみた。

We're sorry, but something went wrong.

We've been notified about this issue and we'll take a look at it shortly.

とか出てログインはおろか,ページすら表示されないぞ!

■Redmineへアクセスできない問題の調査

●MySQLへログインができなくなってる!
色々調べてみたら,Rubuy on RAILS の問題とか,MySQLとRedmineのリンクができてないとか書いてた。
RubyやMySQLの再インストールをやったりしてるうちに,
MySQLにログインできなくなってることに気付いた。

pi@raspberrypi:/ $ sudo mysql -u root -p

mysql: error while loading shared libraries: /lib/arm-linux-gnueabihf/libreadline.so.5: invalid ELF header

このエラーは,対象のファイルがリンクされてないのが原因らしい。
再インストールしたら治るとか書いてあったが,治らなかった。
そこで,とりあえず,MySQLを再起動しようとしても,失敗する。

pi@raspberrypi:/var/log/mysql $ sudo service mysqld restart
Job for mariadb.service failed because the control process exited with error code.

See "systemctl status mariadb.service" and "journalctl -xe" for details.

で,ステータスをみてみると,


pi@raspberrypi:/var/log/mysql $ systemctl status mariadb.service
・・・(略)・・・
10月 22 00:01:17 raspberrypi systemd[1]: Starting MariaDB database server...
10月 22 00:01:18 raspberrypi systemd[1]: mariadb.service: Main process exited, code=exited, status=127/n/a
10月 22 00:01:18 raspberrypi systemd[1]: Failed to start MariaDB database server.
10月 22 00:01:18 raspberrypi systemd[1]: mariadb.service: Unit entered failed state.

10月 22 00:01:18 raspberrypi systemd[1]: mariadb.service: Failed with result 'exit-code'.

そもそもスタートしてないっぽい。
そこで,とりあえず,スタートさせようとしても,できない。

pi@raspberrypi:/var/log/mysql $ sudo service mysqld start
Job for mariadb.service failed because the control process exited with error code.

See "systemctl status mariadb.service" and "journalctl -xe" for details.

そこで,エラーの詳細を表示する。

pi@raspberrypi:/var/log/mysql $ journalctl -xe
10月 22 00:01:17 raspberrypi sudo[1249]: pam_unix(sudo:session): session opened for user root by pi(uid=0)
10月 22 00:01:17 raspberrypi systemd[1]: Starting MariaDB database server...
-- Subject: Unit mariadb.service has begun start-up
-- Defined-By: systemd
-- Support: https://www.debian.org/support
-- 
-- Unit mariadb.service has begun starting up.
10月 22 00:01:18 raspberrypi mysqld[1356]: /usr/sbin/mysqld: error while loading shared libraries: /lib/arm-linux-gnueabihf/libaio.so.1: invalid ELF head
10月 22 00:01:18 raspberrypi systemd[1]: mariadb.service: Main process exited, code=exited, status=127/n/a
10月 22 00:01:18 raspberrypi systemd[1]: Failed to start MariaDB database server.
-- Subject: Unit mariadb.service has failed
-- Defined-By: systemd
-- Support: https://www.debian.org/support
-- 
-- Unit mariadb.service has failed.
-- 
-- The result is failed.

ここでも,リンクに失敗しているらしい。
「/usr/sbin/mysqld: error while loading shared libraries: /lib/arm-linux-gnueabihf/libaio.so.1: invalid ELF head」が,リンク失敗のところ。

解決法は,リンクを教えてやればいいとのこと。
以下のコマンドを実行し,.cfgファイルを編集する。

  • sudo vi /etc/ld.so.conf
以下の文を追記する。


/lib/arm-linux-gnueabihf


ld.so.confには,「include /etc/ld.so.conf.d/*.conf」が書かれている。
includeされるファイルの中に,同じ文が書かれているので,リンクされそうなものだが,されていないっぽい。

この後に,以下のコマンドを実行して,MySqlを実行する。

  • service mysql start
すると,問題なく,MySqlを開始することができた。
できなかった。エラーが出た。
そこで,Raspberry Pi自体を再起動したところ,
自動でmysqlがスタートされたらしく,
MySQLにrootでログインできた。

  • sudo reboot
    (再起動)
  • mysql -u root -p
    (rootでログイン)




[参考URL]







2018年10月1日月曜日

Raspberry Pi 3 SSH接続

Raspberry Pi3 Raspbian Stretch でSSH接続 覚書

[前提]
  • PC : Mac OS High Sierra
  • Raspberry Pi : Raspbian Stretch

[手順]
Raspberry Pi側の設定
  1. Raspberry PiのSSH接続を有効にする。(デフォは「無効」)
    1. スタート->設定->Raspberry Piの設定
    2. インターフェイスタブを選んで,SSHを「有効」にする
  2. Raspberry Piを再起動(いらんかも)
  3. ターミナルを立ち上げて,「ifconfig」を入力して,IPアドレスをチェック
Mac側の設定
  1. ターミナルを起動
  2. 「ssh pi@xxx.xxx.xxx.xxx」を入力
  3. パスワードが聞かれるので,Raspberry Piのpiユーザのパスワードを入力

[注意]
MacからSSH接続しようとしたら,ずっと

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
・・・
が表示されて接続拒否されてた。

これは,Mac側の問題らしい。
SSHのキーが古いよってことらしい。

  • ssh-keygen -R xxx.xxx.xxx.xxx
とコマンドをうって,再度ssh接続を試みたらつながった。
(xxx.xxx.xxx.xxxは,Raspberry Piに割り当てられてるIPアドレス)

参考URL : https://www.niandc.co.jp/sol/tech/date20150729_507.php


Raspberry Pi 3 デバイスドライバ作成 Part1

[前提]
  • HW : Raspberry pi 3
  • OS : Raspbian Stretch with Desktop

[やったこと]
gccでコンパイルとかできないといけない。
Linuxのデバイスドライバ開発では,Linuxのソースコードとヘッダが必要らしい。

メインで参考にしたURLは以下。

まずは,以下のコマンドを実行したい。
  1. sudo apt-get install build-essential
  2. sudo apt-get install git
  3. cd /usr/src
  4. sudo apt-get install linux-image-rpi-rpfv
  5. sudo apt-get install linux-headers-rpi-rpfv
しかし,4で失敗する。
エラー内容は,以下の通り。
  • ・・・へのハードリンクの作成に失敗しました : 許可されていない操作です
  • dpkg: パッケージ initramfs-tools の処理中にエラーが発生しました (--configure)
  • サブプロセス インストール済みの post-installation スクリプト はエラー終了ステータス 1 を返しました
  • etc.
調べたところ,BOOT領域が足りないのが原因っぽい。
以下のコマンドを実行した。
  1. sudo apt-get remove linux-image-4.9.0-6-rpi
    (4.9.0-6は,OSのバージョン。適宜変更のこと)
  2. sudo apt-get autoremove
  3. sudo apt-get dist-upgrade
その後,失敗していたコマンドを実行する。
  1. sudo apt-get install linux-image-rpi-rpfv
  2. sudo apt-get install linux-headers-rpi-rpfv
エラーを吐くことなく,正常に終了。

このエラーで参考にしたURLは以下。


つぎに,インストールした,linuxイメージをboot時に読み出すために,
/boot/config.txt に追加編集する。
  1. sudo vi /boot/config.txt
追加するのは,以下の文。
# Add chuchulabo : Parameters to boot on raspbian kernel(linux-image-rpi-rpfv package)
kernel=vmlinuz-4.9.0-6-rpi
initramfs initrd.img-4.9.0-6-rpi followkernel

そして,再起動。
  1. sudo reboot

そして・・・
SSHでRaspberry piに繋がらなくなりました!
うおーい!!!
間違いなく,config.txtをいじったのが悪いんやけど・・・


/********** 続く **********/


2018年9月30日日曜日

Raspberry pi 3 インストール+初期設定

Raspberry pi 3 のインストール + 初期設定の覚書

[前提]

  • PC : Mac Book Pro
  • OS : High Sierra
  • 使用SDカード容量 : 32GB
  • NOOBSでRaspbianをインストール
    "https://www.raspberrypi.org/downloads/"
  • NOOBS

    Offline and network installVersion:2.8.2Release date:2018-06-27

[インストール手順]
手順はいろんなところに載ってるので,それを参照のこと。


[インストール注意事項]

  • SDカードのファイルシステムはFAT32でなければならない。
  • 「DiskUtilityでフォーマットする場合は,MS-DOSを選択する」と書いているHPが多いが,実際は無理。
    DiskUtilityでSDカードのフォーマットはしないこと。
  • SDカードのフォーマットは,SD Card Formatter で行うこと。
    DL先 : https://www.sdcard.org/jp/downloads/formatter_4/
    シンプルなので,直感的に使える。ファイルシステムの選択はないが,デフォルトでFAT32でフォーマットしてくれる。

[初期設定]
いろんなところに載ってるので,調べる。
ただ,このサイトの「パッケージとOSの更新」くらいはやっといたほうが良い気がする。



2018年3月13日火曜日

STM32 Nucleo on mac memo

Cube MXで自動生成していくにあたり,覚書き。

・FreeRTOS リソースの自動生成は,タスクのみとする。
・ペリフェラルは,自動生成する。
 CubeMXで設定等を行う。
・タスク起動の引数で,使用するペリフェラルのポインタを全部渡す。
・タスク間通信を行うために,各タスクごとにメッセージキューを1個割りあてる。
・メッセージキューのIDとか,必要情報もタスク起動の引数で渡したらいい?

終わり?


2018年2月28日水曜日

STM32 Nucleo FreeRTOS SW割り込み on mac memo

[目標]

・スイッチで,LEDをON/OFFする。
  ・最初 : LED OFF
  ・1回目 : LED ON
  ・2回目 : LED Blink(500ms)
  ・3回目 : LED OFF
・スイッチのON/OFFには,IRQ割り込みを用いる
 (ポーリングは面白くないよね)

[前提]

・NucleoL152RE を使用
・NucleoにデフォルトでのってるLED(LD2) をLチカ
・開発環境 SW4STM32(AC6)
・コード生成ツールSTM32CubeMX を使用
・http://chuchulabo.blogspot.jp/2018/02/stm32-nucleo-freertos-l-on-mac-memo.html
 で作ったプロジェクトを再利用。
 (めんどくさいから)
 (続きとして作るね)

[手順]

http://chuchulabo.blogspot.jp/2018/02/stm32-nucleo-freertos-l-on-mac-memo.html
の続き。

== Cube MXの設定 ==

CubeMXのプロジェクトを開く。
Nucleoに乗ってる青いスイッチを使用する。
で,それに繋がってるピンは,PC13。
「B1[Blue PushButton]」ってなってる。
ピンをクリックすると,そのピンに設定されている機能を設定/参照できる。
PC13をクリックして,「GPIO_EXTI13」であることを確認する。
さっき設定した「GPIO_EXTI13」は,
このPC13ピンは,GPIOで,割り込み使いますよって意味。
GPIO : 汎用入出力。General-purpose input/output の略。
EXTI : 外部割込み/イベントコントローラ。External Interrupt の略。

次に,GPIOの設定を行う。
「Configulation」タブ->「GPIO」ボタンをクリック。
Pin Configulationダイアログが立ち上がる。
「GPIO」タブを選択すると,設定されているGPIOピンが見れる。
今(Nucleoのデフォルト)は,LEDとSWの設定が見える。
「PC13-WKUP2」をクリックすると,下にどんな設定になっているかが表示される。
プルダウン形式で選択可能。
Nucleoのデフォルトは,
  ・立ち上がりエッジで割り込み
  ・プルアップ/プルダウン なし
になってる。
User Label は,自由に設定できる。
別にデフォルトでいい。
今回は,他の項目は確認しなくていい。
「OK」をクリックして,GPIOの設定は終了。

次に,割り込みの設定を行う。
さっきの立ち上がりエッジ割り込みとか,
割り込み設定じゃないのかというツッコミをしたくなったけど,
立ち上がりエッジ/立ち下がりエッジ/両エッジ とかは,汎用I/Oの割り込みだから必要なもの。
というわけで,やっぱりGPIOの設定になるのかな?

割り込みは,NVICで設定できる。
NVIC : ネスト型ベクタ割り込みコントローラ。Nested Vectored Interrupt Controllerの略。

「Configulation」タブ->「NVIC」ボタンをクリック。
NVIC Configulationダイアログが開く。
「NVIC」タブ->「EXTI line[15:10] interrupts」の「Enabled」にチェックを入れる。
「Preemption Priority」とか,「Sub Priority」とかは,とりあえずデフォルトで。
あと,FreeRTOSを使ってるので,とりあえず「Uses FreeRTOS functions」にチェックを入れておく。

「Enabled」にチェックを入れると,Code Generationの項目が勝手に設定される。
「Code Generation」タブ->「EXTI line[15:10] Interrupt」が勝手にできる。
「Generate IRQ handler」 にチェックが入っていることを確認する。
たぶん,これでNVICの設定は終わり。
「OK」をクリックする。

「Project」->「Generate Code」でコードを生成する。
生成したら,コード(もとい,プロジェクト)を開くか聞かれるので,とりあえず開く。


== 設計? ==


スイッチのON/OFFの時の割り込み(EXTI line[15:10] Interrupt)で,LEDのON/OFF/BLINKを切り替えるのもいいけど,それでは,FreeRTOS使わなくてもできる。
なので,少し回りくどいことをする。
せっかくLEDタスクを作っているので,LEDの制御は,全てLEDタスクから行うようにする。(と言っても,BLINKはタイマ機能使うけど。)
というわけで,シーケンス図。
スイッチの割り込みがかかったら,メッセージをLEDタスクに送る。
LEDタスクは,メッセージを受け取るごとに,
ON->OFF->BLINK->・・・
とLEDの光り方を変えていく。
ちなみに,これはSeq Diagで作った。
PowerPointで作ろうかとも思ったけど,線を引くのがいやだったので,Seq Diagを使用。
すごい便利。
参考 : http://blockdiag.com/ja/seqdiag/index.html

割り込みとタスクのメッセージのやりとりは,メッセージキューを使用する。
メッセージキューとメールキュー,用途どう違うのかわからんけど,
  ・メッセージキュー : int型/ポインタ のみを転送可能
  ・メールキュー : どんな型でも転送可能
って書いてある気がする。
ただ,メールキューは,メッセージキューのラッパーな気がする。
メッセージキューは,int型/ポインタ 以外の例えば構造体のデータとかを転送したい場合には,メモリプールを取得->メモリプール領域内にデータを保存->メモリプールのポインタを転送 としなければならない。
メールキューは,この一連の流れを,勝手にやってくれるものというイメージ。

メールキューの方が便利そうだが,
なんとなく,基本を知るために,メッセージキューを使う。

== 割り込みの作業準備(ただの説明) ==


今更やけど,main.cから呼ばれてるのは,
  ・HAL_Init() : stm32l1xx_hal.cに記述。
  ・SystemClock_Config() : main.cに記述。
  ・MX_GPIO_Init() : gpio.cに記述。
  ・MX_USART2_UART_Init() : usart.cに記述。
  ・MX_FREERTOS_Init() : freertos.cに記述。
  ・osKernelStart() : cmsis_os.cに記述。
で,このあと,while(1)でループ。

でも,このループにはこないはず。(たぶん)
なぜなら,タスクを起動して,そのタスクにディスパッチされるから。


今回,記述が必要なのは,LedTaskと,スイッチ割り込みがかかった時の処理。
で,これらをどこに書くかというと,
  ・LedTask -> freertos.c
  ・スイッチ割り込み -> stm32l1xx_it.c?

LedTaskに関しては,過去(https://chuchulabo.blogspot.jp/2018/02/stm32-nucleo-freertos-l-on-mac-memo.html)に記述した通り,void StartLedTask(void const * argument) 関数が,タスクの実体。

では,スイッチ割り込み(EXTI line[15:10] Interrupt)の処理の実体はどこにあるかというと,stm32l1xx_it.cにある,void EXTI15_10_IRQHandler(void) という関数がそう。
割り込みがかかると,この関数に飛んでくる。
さらに,中でHAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13); を実行している。

P13は,スイッチの繋がってるピン。
つまり,スイッチ押された時に,HAL_GPIO_EXTI_IRQHandler(); 内に書いてる処理が実行される!
じゃあ,そのHAL_GPIO_EXTI_IRQHandler() はどこに書かれているのか?
これは,stm32l1xx_hal_gpio.c に書かれている。

HAL_GPIO_EXTI_IRQHandler() の中で,さらにコールバック関数(HAL_GPIO_EXTI_Callback(GPIO_Pin);)が呼び出されている。

たぶん,自分で記述すべきは,このコールバック関数だと思う。

ちなみに,割り込みかかってから,ずっと,
全部の関数で,uint16_t GPIO_Pinを引数として渡している。
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);  こんな感じで。

EXTI line[15:10] Interruptは,みたらわかるけど,10〜15 の割り込みがかかった時,呼び出される。じゃあ,さらにわけた個別の処理(10なら10の,13なら13の異なる処理)を行いたい場合,どうするか?
これはユーザーがif文とかで分岐させてやらないといけない。
最後のコールバック関数まで分けてくれている様子はないので,コールバック関数内で自分たちで書かないといけないっぽい。

さらに,自動生成のコールバック関数のコメントに,こんなことが書いてある。

/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/

どういうことかといえば,コールバック関数が必要な場合,ここに定義してる関数は使用するな。別のとこで(ユーザーが作ったファイルで),HAL_GPIO_EXTICallback関数を定義して,その関数を使え。
ってこと。関数の最初に weak ってついてるから,もし,他の場所で同じ名前の関数があった場合には,そっちが使われるようになっている。

長くなったけど,
割り込みでやることは,
  ・ユーザーファイルを作成
  ・ユーザーファイルにHAL_GPIO_EXTICallback関数を定義
  ・定義した関数ないで,GPIO_PIN_13 の時の処理を記述(条件分岐)
  ・処理内容は,メッセージの送信
以上!

== タスクの作業準備(ほぼ割り込み)(ただの説明) ==

タスクは,何も考えずに,割り込みからメッセージが送られてきた時の処理を書けばいいんやけど,一つ問題が。

メッセージキューでメッセージを割り込みハンドラ -> タスク へ送るわけだが,メッセージキューのIDどうすんの?
extern使ったらいいのかもしれんけど,個人的にexternはあんまり好かん。
というわけで,割り込みかかった時の処理と,LEDタスクの処理は同じファイルに記述する。

でも,freertos.cにLEDの割り込みの処理書くのもなぁ・・・と思うので,
LED制御用のファイルを一個作って,そこに,割り込みの処理と,LEDタスクの処理を書くことに。
freertos.cのStartLedTask()関数からは,このLED制御用のファイルに書いた,LEDタスクの処理関数を呼び出す形にする。
図にするとこんな感じ。
気持ち悪いのが,LedCtrl.cの中に,HdrSwitch()関数が書かれていること。
SW制御ようのタスクを作って,タスク間通信をするのが正解なのかもしれない。
でも,今回はこのまま行く。(過去のログを変更するのが大変面倒だから)
次,いつかなおす!(たぶん直さない)

説明はこれくらいにしとこう。力尽きた。

== コーディング ==

書き始めたけど,すっごい書きづらいなぁ。
LED点滅用のタイマーをCubeMXで自動生成してるから,freertos.cにタイマーが書かれてるわけやけど,LedCtrl.cからタイマーの開始/停止をしたい。
freertos.cで生成してるリソースをLedCtrl.cからいじりたい場合,externするしかない気がする。
考え直した方がいいかなぁ。
CubeMXの自動生成,すごい便利やけど,FreeRTOSのリソースに関しては,自分で書いた方がいいかもしれない。タスクくらいは生成してもいいけど,その他のタイマー,メッセージキュー,メモリプールとかは自分で書いた方がいい。
externあまりしたくなければ,ユーザ作成ファイルに結局メッセージキューもメモリプールもタイマーも書くから。

・・・コーディングするのやめよっかな・・・。

コーディングやめる。
大体考えなあかんことはこれまでに書いたから,まぁ大丈夫でしょ。
何より,書きにくいし。

もっと設計ちゃんと考えなあかんなぁ・・・。




2018年2月25日日曜日

STM32 Nucleo FreeRTOS Lチカまで on Mac memo

[目標]
・FreeRTOSを使ってLチカ
  ・作成するタスクは1つ
  ・周期タイマで0.5秒周期で点滅させる

[前提]
・NucleoL152RE を使用
・NucleoにデフォルトでのってるLED(LD2) をLチカ
・開発環境 SW4STM32(AC6)
・コード生成ツールSTM32CubeMX を使用
・開発環境の構築,プロジェクトの作成は,
http://chuchulabo.blogspot.jp/2018/02/stm32-on-mac-memo.html
を参照。

[手順]

== タスクの追加 ==

http://chuchulabo.blogspot.jp/2018/02/stm32-on-mac-memo.html
で作成したプロジェクトをそのまま変更する(めんどいから)。
CubeMXのプロジェクトファイルを開く。
左サイドバーの FREERTOS->Enabled にチェックを入れる。
これだけで,FREERTOSをプロジェクトに入れてくれる。すごい!
タスクの設定をする。
まずは,LEDタスクを作成する。
これも,CubeMXで行う。
「Configuration」タブ -> 「FREERTOS」 をダブルクリック。
FREERTOS Configuration のダイアログが開くので,設定を変更する。
「Tasks and Queues」タブ -> Tasksの方の「Add」ボタンをクリック。


New Task ダイアログが開くので,LEDタスクを設定する。
以下のように設定して,「OK」を押す。
すると,LEDタスクが追加される。
追加されたのを確認したら,「Apply」をクリック -> 「OK」をクリック。

Project->generate Code で,コード生成を開始する。
すると,次のようなダイアログが出る。
よくわからんが,「Yes」を押す。
すると,CubeMXがよしなにコードを生成してくれる。
素晴らしい!

main.cでは,
MX_FREERTOS_Init();
が呼び出されているだけ。
中身は,freertos.c に書いてある。
ちゃんとvoid StartLedTask(void const * argument) ってのが生成されている。



== ちょっとFreeRTOSとCMSISについてメモ ==
使うとチェックを入れたのはFree RTOS。
だが,実際には,Free RTOSのAPIをラッパーしたCMSISのAPIを使用して,
タスクの生成は行われている。

osThreadDef とか,osThreadCreate というのは,CMSISのAPI。

FreeRTOSについて
https://www.freertos.org/index.html

CMSISについて
http://www.keil.com/pack/doc/CMSIS/RTOS/html/index.html

CMSISは,FreeRTOSや,その他のRTOSであっても,共通して使用できるように
策定されたもの。
CMSISのAPIを使っていれば,FreeRTOSから他のRTOS(ThreadXとか?)に変えても,
CMSISの部分が吸収してくれて,移行が簡単になる。

だから,今回は,CMSISのAPIをなるべく使うようにする。
(CubeMXが勝手にやってくれるんだろうけど)

== 周期ハンドラの追加 ==
タイマー機能を使用して,周期ハンドラを作る。
まず,CubeMXで設定を行う。
タイマー機能を使用するため,ソフトウェアタイマを有効にする。
「Configuration」タブ -> 「FREERTOS」 をダブルクリック。
FREERTOS Configuration ダイアログが開く。
「Config parameters」タブ->「Software timer definitions」->「USE_TIMERS」を「Enabled」に変更。
次に,タイマーを作成する設定を行う。
「Timers and Semaphores」タブ->「Timers」の「Add」ボタンをクリック。
NewTimerダイアログが開くので,以下のように設定して,「OK」をクリック。
LEDの点滅用のタイマーなので,名前をLedTimerにした。
Callbackは,タイマーで一定時間たった時に呼ばれるコールバック関数の事。

「Apply」->「OK」をクリックして,FREERTOSの設定終了。
と思ったけど,なんか,「Free RTOS Heap Usage」タブで,「×」が表示されててだめっぽいところがある。読むと,Heapサイズが足りてないっぽい。
タイマーをEnableにしたせいで,使用するHeapサイズが足りなくなったらしい。
とりあえず,Heapサイズを多くとるようにする。
「Config parameters」タブ->「Memory management settings」->「TOTAL_HEAP_SIZE」を3072→4096に変更。
すると,「Free RTOS Heap Usage」タブの「×」が「✔︎」に変わる。

これでOK!多分。
「Apply」->「OK」を押して,FREE RTOSの設定を完了する。

コード生成をしてみる。
「Project」->「Generate Code」で,コードを生成する。

freertos.cをみると,タイマが追加されていることがわかる。




== コーディング ==
MX_FREERTOS_Init(void) でタスクもタイマも作成されている。
タスクに関しては,osThreadCreate() したら,始まるみたい。
ただ,タイマは,osTimerStart()しないと,始まらないっぽい。
というわけで,
LEDタスクからLEDタイマを開始して,
LEDタイマのコールバック関数内でLEDを点滅させる。
まず,タイマをスタートさせる。

以下,コード。
-------------------------------------------------
/* StartLedTask function */
void StartLedTask(void const * argument)
{
  /* USER CODE BEGIN StartLedTask */
  osTimerStart(LedTimerHandle, 500);
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END StartLedTask */
}

/* LedTimerCallback function */
void LedTimerCallback(void const * argument)
{
  /* USER CODE BEGIN LedTimerCallback */
  HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
  
  /* USER CODE END LedTimerCallback */

}
-------------------------------------------------


さらに,freertos.cは,HALライブラリをincludeしてないので,
HAL_GPIO_TogglePin()でエラーになる。
ので,HALをincludeする。
以下,コード。
-------------------------------------------------
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"

/* USER CODE BEGIN Includes */     
#include "stm32l1xx_hal.h"


/* USER CODE END Includes */
-------------------------------------------------

以上,コーディング終わり!
500ms周期でLEDが点滅するはず!

Build -> Debug -> Resumeで,実行すると,
LEDが500ms周期で点滅した!
成功!