2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ESP32学習 PlatformIOでESP IDFを使ってみる。GPIOを操作したが、ROMサイズ変更の設定が反映されなくて、大変だった話。

Last updated at Posted at 2024-03-10

IMG_4427.JPG
※スイッチの基板は、FETを3つ使って、ヒステリシスを作ったチャタリング対策回路になっています。

学習中なので、この方法で不具合があった場合、変更する可能性があります。

ESP-IDFで開発学習を始めました。GPIOの入出力を制御することから始めました。

開発環境:vsCode+platformIO
board:esp32dev
platform:ESP-IDF

スイッチ割込みでLEDを点滅させるようにしました。そこまでは、順調でした。ビルドの結果を見たら、PSRAMが有効になっていません。ROMも1MBまでしか使えません。PSRAMを有効にして、ROMのサイズも大きくしようとしたら、見事にハマりました。

ROMサイズの変更で、相当手こずりながら作業したので、これでいいのか、まだよくわかっていません。
FlashROMサイズは、boardの設定がリミッターになっている感じです。

・platformioのnewPojectで、新しくプロジェクトを立ち上げます。その際に選択したboardが、Espressif ESP32 Dev Moudule。このボードの初期設定は、ROMが4MB。RAMが300kB強。 そのままでは、WROVER-EのROM 8MB、RAM 8MBをフルに使用できません。 ボード設定(esp32dev.json)を変更したファイルを用意する必要がありました。

・menuConfigとパーティションテーブルを使用してビルドします。ROMの使用量が4MBを超えるとエラーになります。 boardの設定4MBの範囲内ならOKです。

・最終的に、esp32dev.jsonファイルを書き換えることで、ビルドエラーを回避できるようになりました。詳細は、以下で説明していきます。

PSRAMの有効化は、platformio.iniまたは、menuConfigで設定。

・オリジナルのboardファイルを書き換えたくないので、それを参考にしながら、ESP32-WROVER-E用のmyboard.jsonを自作して、プロジェクト作成時に指定する方法をとっています。

platformIOの掲示板でも、同様の質問がされていました。


ESP32-WROVER-E用に自作したboard.jsonファイル。

myBoard.json
{
  "build": {
    "arduino":{
      "ldscript": "esp32_out.ld"
    },
    "core": "esp32",
    "extra_flags": "-DARDUINO_ESP32_DEV",
    "f_cpu": "240000000L",
    "f_flash": "40000000L",
    "flash_mode": "dio",
    "mcu": "esp32",
    "variant": "esp32"
  },
  "connectivity": [
    "wifi",
    "bluetooth",
    "ethernet",
    "can"
  ],
  "debug": {
    "openocd_board": "esp-wroom-32.cfg"
  },
  "frameworks": [
    "arduino",
    "espidf"
  ],
  "name": "my ESP32 dev", <=====ここを書き換えた。
  "upload": {
    "flash_size": "8MB",  <=====ここを書き換えた。
    "maximum_ram_size": 327680,
    "maximum_size": 8000000, <=====ここを書き換えた。
    "require_upload_port": true,
    "speed": 460800
  },
  "url": "https://en.wikipedia.org/wiki/ESP32",
  "vendor": "Espressif"
}

<参考>GPIOの操作関連 Application exampleにあるgitレポジトリが、分かりやすいです。

<参考>パーティションテーブル

設定に必要なファイル

ESP-IDFで、プロジェクトをビルドしていきます。その際、必要になるファイルが4つあります。

1.kconfig.projbuild
2.sdkconfig.esp32dev
3.partition table.csv
4.platformio.ini

上記4つのファイルを必要に応じて、変更していきます。

1.kconfigファイル 

srcフォルダにkconfig.projbuidファイルを置きます。このファイルで、GPIOのピン設定を行っています。

Kconfig.projbuild
menu "Example Configuration"

    config GPIO_OUTPUT_0
        int "GPIO output pin 0"
        range 0 39
        default 32
        help
            GPIO pin number to be used as GPIO_OUTPUT_IO_0.

    config GPIO_OUTPUT_1
        int "GPIO output pin 1"
        range 0 39
        default 33
        help
            GPIO pin number to be used as GPIO_OUTPUT_IO_1.

    config GPIO_INPUT_0
        int "GPIO input pin 0"
        range 0 39
        default 34
        help
            GPIO pin number to be used as GPIO_INPUT_IO_0.

    config GPIO_INPUT_1
        int "GPIO input pin 1"
        range 0 39
        default 35
        help
            GPIO pin number to be used as GPIO_INPUT_IO_1.

endmenu

2.sdkcofigファイルとmenuConfig

platformIOでRun Menuconfigをクリックすると、esp-idfの開発設定画面が、ターミナルに表示されます。
Run_menuConfig.png

下の画面が、platformIO のターミナルに表示されます。
menuConfig_FrameworkConfigration.png
ここで、各種設定を行います。kconfigファイルをsrcに置くと、
kconfigファイルの先頭に書いてあるExample Configrationが選択肢に追加されています。
kconfigファイルを編集せずに、menuConfigで再設定ができます。
各種の設定をここで行うと、変更内容が、sdkcofigファイルに反映されます。Serial flasher configでROMサイズをWROVER用に8MBに変更しました。ROMサイズを広げるには、パーティションテーブル作成が必要になります。

3.パーティションテーブルを作成

my_no_ota.csv
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x5000,
otadata,  data, ota,     0xe000,  0x2000,
app0,     app,  ota_0,   0x10000, 0x700000,
spiffs,   data, spiffs,  0x710000,0xE0000,
coredump, data, coredump,0x7F0000,0x10000,

WROVER-EのROMサイズを変更し、拡大させるため、パーティションテーブルをCSV形式で作成します。このファイルを、Pojectフォルダのルートの置きました。otaは"On the air"の略で、無線経由でROMを書き換えることを意味しています。SPIFFS は "SPI Flash File System "の略で、ROMにフォントなどを保存できる領域です。

4.platformIO iniファイル

※boardがesp32devだと、WROVER-EのROM,RAM領域が制限されます。
platformIO_INIの内容.png

ESP32-WROVER-Eは、ROMが8MB、RAMは8MB あります。それにあわせて、boardファイルのjsonフォーマットをみながら、iniファイルに設定を追加していきます。
boardは、esp32devになっています。このボード設定では、WROVER-Eのスペックをフルに使用することはできません。ワーニングとエラーがでます。project作成時に、オリジナルboard.jsonを読み込ませる方法が、現状のベストです。
PSRAMの有効化は、menuConfigまたは、platformio.iniで設定します。最初は双方で設定していました。

<改変した自作ボードファイル>
my_esp32dev(これで、ROM,RAMの容量を拡張できるようになりました。)
platformIO_INIの内容2.png


menuConfigでsdkConfigの内容を変更、iniファイルと、パーティションテーブルを作成したので、ビルドします。

RAM:   [          ]   0.2% (used 10932 bytes from 4536000 bytes)
Flash: [          ]   3.2% (used 234041 bytes from 7340032 bytes)

PSRAMが反映されて、4.5MBに、ROMは、7.3MBに拡がりました。

Board:esp32dev.jsonを書き換えてたboarファイルを使用。 最初に書いた通り、menuConfigとplatformio.iniの設定だけでは、ROMサイズの拡大ができませんでした。BoardはJSONフォーマットで書かれており、そこでのサイズは、4MBが最大と設定されています。menuConfigでWROVER用に、Flashサイズを8MBに変更するとビルド時にwarningが表示されます。パーティションテーブルを作成し、それが4MBを超えるとエラーになります。エラーを回避するため、boradJSONを変更しました。オリジナルを変更するよりは、新規にmyboard.jsonをかいて、project作成時にそれを選択する方法をとっています。

GPIO割込みのコード

main.cpp
//**********************************//
//GPIO割込み
//**********************************//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"

//自分で追加したヘッダー
//gpioレジスタの直打ち用。
#include "soc/gpio_reg.h"
//gpio_isr_func_tのサイズを求めるため。
#include "hal/gpio_types.h"

//OUTPUTピン Kconfig.projbuildに詳細設定
#define GPIO_OUTPUT_IO_0    CONFIG_GPIO_OUTPUT_0
#define GPIO_OUTPUT_IO_1    CONFIG_GPIO_OUTPUT_1
#define GPIO_OUTPUT_PIN_SEL  ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1))
//INPUTピン   Kconfig.projbuildに詳細設定
#define GPIO_INPUT_IO_0     CONFIG_GPIO_INPUT_0
#define GPIO_INPUT_IO_1     CONFIG_GPIO_INPUT_1
#define GPIO_INPUT_PIN_SEL  ((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))
//GPIO_IN1_REGレジスタの値
#define GPIO_IN1_REG_VALUE  (*(volatile uint32_t*)GPIO_IN1_REG)
//GPIO割込み RAMの指定値
#define ESP_INTR_FLAG_DEFAULT 0

#define HIGH 1
#define LOW  0

//gpio.cにあるgpio_isr_func_tのサイズを求める。
//hal/gpio_types.hを読み込む。
//gpio_isr_func_tはCファイル内の記述。
typedef struct {
    gpio_isr_t fn;   /*!< isr function */
    void *args;      /*!< isr function args */
} m_gpio_isr_func_t;

//GPIO個別処理割込み関数
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    static bool val1=true,val2=true;
    uint32_t gpio_num = (uint32_t)arg;

    if(gpio_num==GPIO_INPUT_IO_0)
    {
        gpio_set_level(GPIO_OUTPUT_IO_0,val1);
        val1 = !val1;
    }
    
    if(gpio_num==GPIO_INPUT_IO_1)
    {
        gpio_set_level(GPIO_OUTPUT_IO_1,val2);
        val2= !val2;
    }
}

void app_main() 
{
    //Output mode pin----------------------------
    //zero-initialize the config structure.
    gpio_config_t io_conf = {};
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set,e.g.GPIO32/33
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);

    //Input mode pin------------------------------
    io_conf.intr_type = GPIO_INTR_POSEDGE; //GPIO割込みエッジ指定
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; 
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pull_down_en = 1;
    io_conf.pull_up_en = 0;
    gpio_config(&io_conf);
    
    //gpio_isr_func_tについて
    //GPIO0..39用 割込み関数ポインタ と デフォルト引数を格納する。
    uint32_t size = sizeof(m_gpio_isr_func_t);
    printf("gpio_isr_func_t size:%"PRIu32"bytes\n",size);
    printf("install size:%"PRIu32"bytes\n",size*GPIO_NUM_MAX);

    //GPIO割込みを設定。
    uint32_t size0= esp_get_minimum_free_heap_size();
    printf("Minimum free heap size: %"PRIu32" bytes\n", size0);
    //install gpio isr service
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void*) GPIO_INPUT_IO_1);
    uint32_t size1 = esp_get_minimum_free_heap_size();
    printf("Minimum free heap size: %"PRIu32" bytes\n", size1);
    printf("Minumum free heap consumption size:%"PRIu32"bytes\n", size0-size1);
    
    
    int cnt = 0;
    //portTICK_PERIOD_MS デフォルトは100なので、menuConfigで1000で再設定。
    printf("portTICK_PERIOD_MS:%"PRIu32"\n",portTICK_PERIOD_MS);
    while(1)
    {
        printf("cnt: %d\n",cnt++);
        
        vTaskDelay(1000/ portTICK_PERIOD_MS);
    }

}

学習中なので、この方法で不具合があった場合、変更する可能性があります。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?