Arduino IDE で pgmspace.h が No such file or directory

Arduino IDE でのラズパイPicoの開発は Mbed OS RP2040版［公式版］とearlephilhower版がありますが、以下の内容はMbed OS RP2040版［公式版］で起きたことです。OS は Windowsです。

# ［１］pgmspace.h が無い？
■ Arduino IDE 2.2.1 で半年前に作成して動作したラズパイPico のスケッチを流用してコンパイルしたところ pgmspace.h が無いというエラーが出ました。
```C++
c:\Users\user\Documents\Arduino\libraries\Adafruit_SSD1306\Adafruit_SSD1306.cpp:42:10: 
fatal error: pgmspace.h: No such file or directory
 #include <pgmspace.h>
          ^~~~~~~~~~~~
compilation terminated.

exit status 1

Compilation error: exit status 1
```
![Arduino-ERROR.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/17ede0c1-9d77-392c-04e4-c85edece3951.jpeg)

# ［２］pgmspace.h とは何か？

■ Arduino のCPU ATmega328P のメモリは ⓵Flash ⓶SRAM ⓷EEPROM の3種類があります。
大雑把にいうと、Flashメモリはプログラム格納用で容量（メモリサイズ）は大きい、SRAMは変数の読み書き、EEPROMは長期保存データの格納用です。

■ SRAMは容量が小さいので、大きな固定データの場合はFlashメモリに書いておいて必要になったらSRAMに読み込むようにします。

■ Flashメモリにデータを格納するには PROGMEM修飾子を使用した変数宣言をする必要があり、それにはpgmspace.hを使用します。

■ プログラム空間(program space)に関するヘッダーファイルということですね。

```C++: PROGMEMの使用例：　Adafruit SSD1306 のサンプルスケッチより
static const unsigned char PROGMEM logo_bmp[] =
{ B00000000, B11000000, B00000001, B11000000, B00000001, B11000000, B00000011, B11100000, 
  B11110011, B11100000, B11111110, B11111000, B01111110, B11111111, B00110011, B10011111, 
  B00011111, B11111100, B00001101, B01110000, B00011011, B10100000, B00111111, B11100000,
  B00111111, B11110000, B01111100, B11110000, B01110000, B01110000, B00000000, B00110000
};
```

［雑感］　ESP32やラズパイPico は、Arduino UNO R3に搭載のATmega328Pに比べるとメモリサイズが充分大きいので特殊な例を除きFlashメモリを使用する必要はなさそうですね。
|  | Flash |SRAM | EEPROM |
|:-:|:-:|:-:|:-:|
| ATmega328P (UNO R3)|  32KB | 2KB  | 1KB |
| R7FA4M1 (UNO R4)|  256KB | 32KB  | 8KB |
| ESP32  |  4MB | 520KB  |  FLASHを代用 |
| ラズパイPico  | 2MB  |  264KB |  無し |

PROGMEM 修飾子や pgmspace.h が必要な理由として「ハーバード・アーキテクチャ」が関係してます。これに関しては、最後に書きます。

# ［３］pgmspace.h は本当に無いの？　⇒ ⇒　沢山あるが・・
Explorerで c:\Users\user\Documents\Arduino\libraries\ を表示した状態で虫眼鏡の検索ボックスにpgmspace.hと入力すると一杯表示されました。

![Arduino-ERROR4-Explorer.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/352f338f-3d61-9687-3a63-906e20625b05.jpeg)

コマンドプロンプトで検索すると一覧が見易いです。
![Arduino-ERROR5-コマンドプロンプト.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/65102bad-46e7-a892-4c82-9c902adc98f2.jpeg)

こんなに沢山あるけどエラーメッセージが言ってるのは、Adafruit_SSD1306 ライブラリのディレクトリ内にpgmspace.h が無いのがNGということでしょうか。

（注）各行の末尾が全て /avr/pgmspace.h のように/avr/が前にあることに注目（後述）。

# ［４］エラーメッセージが表示される原因
以前は問題なかったのにコンパイルエラーが出るのは何故か？

考えられるのは Arduino IDE のバージョンアップとライブラリのバージョンアップです。Arduino IDE は半年前に1.8.19から2.0.4に、さらに最近2.2.1にアップしました。ライブラリは色々更新しました。よく分かりませんが、その際にファイル参照・依存の関係、PATHの設定が崩れてしまったのかな？・・・

Arduino IDE は何も考えず何も準備せずに1.8.19から2.0.4にアップデートしたのですが、旧バージョンのArduino IDE の「環境設定」と「基本設定」の設定値を保存しておき、アップデート後に設定値を調整するべきであることをアップデートが終わった後で知りました。まさに後の祭りでした。
事前に下記サイトをよく読んでおけばよかったと後悔してます。

https://karakuri-musha.com/inside-technology/arduino-ide2x-install-and-setting01/

# ［５］対策はどーする？
3つの方法を検討しました。

### （第１案）github など複数のサイトで見かけた対策
```C++
Adafruit_SSD1306.cppの 42行目

 #include <pgmspace.h>
```
これを下記のように置き換えるというものです。
```C++
#if defined(AVR)
#include <avr/pgmspace.h>
#else
#include <pgmspace.h>
#endif
```
（注）コマンドプロンプトで表示したpgmspace.hのある場所のリストを見ると全て /avr/pgmspace.h のようになってます。

Adafruit_SSD1306.cppは、下記のようになってました。
```C++
Adafruit_SSD1306.cpp の抜粋：39行目～

#ifdef __AVR__
#include <avr/pgmspace.h>
#elif defined(ESP8266) || defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
#include <pgmspace.h>
#else
#define pgm_read_byte(addr)                                                    \
  (*(const unsigned char *)(addr)) ///< PROGMEM workaround for non-AVR
#endif
```
う～む、既に #ifdef～ が入ってる・・・

### （第２案） ライブラリを削除して再インストールする

ライブラリをインストールすると「libraries」というフォルダ内にインストールしたライブラリのフォルダが作成されますが、そのライブラリのフォルダをまるごと削除します。

［手順］
⓵ Arduinoのスケッチ保存用フォルダをArduinoの環境設定／基本設定で確認します。
　Arduino IDE 1.8.x の場合「ファイル」⇒「環境設定」
　Arduino IDE 2.x.x の場合［ファイル］⇒［基本設定...］
　ポップアップしたウィンドウの［スケッチブックの場所］にPathが記載されています。

![Arduino-基本設定.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/38313aab-375b-bfa8-e14c-778e4f118396.jpeg)

そのPathの下の libraries フォルダの中にインストールしたライブラリのフォルダがあります。私の環境では　c:\Users\user\Documents\Arduino\libraries\  です。
（Windows エクスプローラでは　PC > ドキュメント > Arduino > libraries と表示されます）

![Arduino-librariesフォルダ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/92bb6164-cf98-3778-2afc-d5657580b101.jpeg)

⓶ アンインストールしたいライブラリ（今回はAdafruit_SSD1306）のフォルダを削除します。　
⓷ Arduinoを再起動するとアンインストールが反映されます。
⓸ 新たにライブラリをインストールする。

■ 上記手順でアンインストールして入れ直そうとしたのですが、タイムスタンプを見ると先日更新したばかりだったのでやめました。

### （第３案）　pgmspace.h をどこかからコピーしてきて、呼び出しているプログラム（Adafruit_SSD1306ライブラリのAdafruit_SSD1306.cpp）があるフォルダーにペーストする。

![Arduino-ERROR2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/55ac6cf8-aba4-a544-fa81-1c915dadfe57.jpeg)
［結果］　エラー無しでコンパイルできて、且つ正常に動作しました。

［問題点］　適当な（いい加減な）場所からpgmspace.hを持ってきたけど、ファイルのバージョンによっては依存関係に矛盾が起きる恐れがあるかも？

［感想］　かなり強引なやり方です。取り敢えず目的は達成できましたが、もっとスマートな真っ当な方法があるような気がします。どなたかアドバイス、ヒント、その他コメント頂けたら幸いです。

# ［６］ハーバード・アーキテクチャ

■ Alduino UNO R3 に搭載されているATmega328Pは、Atmel（2016年 Microchip Technology が買収）のAVRシリーズのマイコンです。

■ AVRシリーズの特徴としてハーバード・アーキテクチャというものがあります。これは、メモリ空間が2種類、プログラム空間（Flash）とデータ空間（SRAM）があるというものです。

ブロック図ではFlashとSRAMは別のバスに接続されてます。

![ATmega328P-MemoryBUs.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/2cf1b8ed-bf91-b871-04e0-249450c90e07.jpeg)

また、メモリマップでは別空間になってます。

![ATmega328P-MemoryMap.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/46cdc830-7998-6b55-0159-a1a0d14c2422.jpeg)

■ ハーバード・アーキテクチャは少数派で、多くのCPUはフォン・ノイマンという米国の学者が提唱した「フォン・ノイマン型のアーキテクチャ」を採用してます。メモリ空間は１種類だけで、プログラム用メモリ（Flash）もデータ（SRAM）も同じメモリ空間に存在します。
フォン・ノイマンは、ストアドプログラム方式（プログラム内蔵方式）を考案したことで知られています。

■ Raspberry Pi Pico はフォン・ノイマン・アーキテクチャです。
下記はPicoのメモリマップですが、Flash ROMもSRAMもレジスタも同じ空間です。

![RP2040メモリマップ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834831/ec003211-f44f-8cba-af18-518633a8cb8a.jpeg)

外部フラッシュは XIP(Excute In Place)ハードウェアを使用してQSPIインタフェース経由でアクセスされます。これにより外部フラッシュを内部メモリであるかのようにアドレス指定してアクセスできます。

■ 各アーキテクチャの特徴は省略します。詳細は検索して下さい。

# 【関連記事】
https://qiita.com/totuto/items/6a3ab3c5f888d49739b1

https://qiita.com/totuto/items/2a8db63abd1d3c82880f

https://qiita.com/totuto/items/81944426dc81ab4b7e57

https://qiita.com/totuto/items/d3bc435d3d2f545c1c02