LoginSignup
0
0

modernAVRファミリーの定義済マクロ判別

Posted at

ひとつのC/C++ソースコードで複数種類のMCU別にバイナリを作り分けたい場合はよくある。そんな時は定義済マクロで場合分けするのだが、ではどんな定義済マクロでどんな分岐ができるのか?というのがこの記事の主題だ。

  • この記事は 2023/10時点では tinyAVR-0系統 から AVR_EB系統までに対応する。
  • AVR 8bit MCU系統の中でも<avr/io.h>の様式が変更され、UPDI対応となった系列をまとめて modernAVR と仮称する。周辺機能の制御様式が大幅に変更されており、AVR命令セットを使っている事実以外の、旧来製品との共通性は薄い。

まず確認

まずコンパイラがどんな定義済マクロを認識しているのかの調べ方を紹介しておこう。ソースコードなしの単純な基本形はこうだ。

# 素のgccの定義ずみマクロだけ
echo | gcc -dM -E -

これで#define行が全て抽出されるので、その標準出力結果をsortgrepに通すなりしてテキストファイルに保存し、エディタでじっくり眺めることになる。

Arduino IDEを使用している場合は、Windowsでも他のOSでも次のようにすると良い。

  1. 設定で「より詳細な情報を表示する」の「コンパイル」にチェックをつけておく
  2. 適当なスケッチを開いて「検証」する(Ctrl+R あるいは Command+R キー)
  3. ログウィンドウの「スケッチをコンパイルしています...」の次行を選んでコピー
  4. 「-c」オプションを探して「-dM -E -x c++」に書き換え
  5. 最後の「-o」オプション以降を削る
  6. 編集できたコマンド行を、ターミナルやコマンドプロンプトで実行
# 例えば
/path/to/avr-g++ -dM -E -x c++ -g -Os -std=gnu++17 \
  -fpermissive -fno-exceptions -fno-threadsafe-statics \
  -Wno-error=narrowing -ffunction-sections 
  -fdata-sections -MMD -flto -mrelax \
  -DF_CPU=20000000L -DARDUINO=10819 \
  -DARDUINO_AVR_AVR64EA32 -mmcu=avr64ea32 \
  -I/Users/askn/Library/Arduino15/packages/MultiX-Zinnia/hardware/modernAVR/0.2.7/cores/modernAVR \
  -I/Users/askn/Library/Arduino15/packages/MultiX-Zinnia/hardware/modernAVR/0.2.7/variants/avr_ea32 \
  /var/folders/mz/_z9vt_y13rdf9tt_4qkvv0k40000gn/T/arduino_build_426011/sketch/Blink.ino.cpp


AVRであることの証明

avr-gcc でソースコードをビルドしたなら必ず現れるマクロ定義は以下のようなものだ。これらが存在しないならAVR-LIBC以外のビルド環境だとわかる。特に明記していなければ定義値は1だ。

定義名 存在
__AVR AVR基盤であることの証明
__AVR_ARCH__ AVRアーキテクチャ番号
__AVR_AVR64EA32__ など ビルド行の-mmcuに対応した名前
__AVR_DEVICE_NAME__ -mmcu=の指定値(文字列)が入っている
__AVR_LIBC_VERSION__ AVR-LIBCのバージョン番号。20000ULなど
__BUILTIN_AVR_CLI など 使用可能なavr-gccのビルトイン拡張命令
__AVR_MEGA__ AVR命令セットが MEGA系列互換(AVRe+)
__AVR_XMEGA__ AVR命令セットが XMEGA系列互換(AVRxm、AVRxt)
_AVR_IOXXX_H_ <avr/io.h>で実際に選択されたヘッダファイル名文字列が入っている
_VECTOR_SIZE 割込テーブルの粒度。フラッシュ容量が 2=8KiB以下、4=16KiB以上
SIGNATURE_1 後述
  • __AVR_DEVICE_NAME__ の持つ文字列はダブルクォートされていないのでそのままでは使えない。プリプロセッサ条件式は文字列比較ができないので、条件判断にも使えない。
  • _AVR_IOXXX_H_ はダブルクォートされた文字列値を持っているので、print に直接書ける。逆アセンブル時の手掛かりとして埋め込んだりするのに使う。

個別のMCUは普通、__AVR_AVR64EA32__ や __AVR_ATmega328P__ といった製品名を含む定義名で振り分けるが「メモリ容量が違うだけの同族」などを纏めたい場合は多数の条件を連ねることになるので面倒だ。

SIGNATURE_1 は、modernAVRの場合 0x92 から 0x98 が存在し、これはフラッシュ容量の 2KiB から 128KiB に対応する。例外的に megaAVR-0系統での 48KiB品種は、64KiB品種と同じ値を示す。

0x92 0x93 0x94 0x95 0x96 0x97 0x98
2KiB 4KiB 8KiB 16KiB 32KiB 64KiB or 48KiB 128KiB

modernAVRの系統判定

ここからは modernAVR つまりUPDI対応世代以後に特化した話になる。それらより旧世代の<avr/io.h>ヘッダファイルは記載情報量に乏しいので、以下で述べているほど簡単に品種を切り分けることは難しい。

まず __AVR_ARCH__ の定義値についてだが、これはフラッシュ容量で異なり、103=64KiB未満、102=64KiB、104=128KiB を示す。100未満なら旧世代AVR(非UPDI世代)と見做してほとんど構わない。

各品種の違いは周辺機能の有無に強く現れるので、それを判断基準にする。パッケージpin数の違いは、USART[1-5]の存在や特定のPORT[x]の有無から判断できる。

定義名 存在
__AVR_ARCH__ AVRアーキテクチャ番号。102、103、104ならUPDI世代
RSTCTRL_RSTFR UPDI世代全品種(modernAVR)に固有。なければ旧世代
MAPPED_PROGMEM_START UPDI世代では、megaAVR-0系統だけが0x4000U、その他は0x8000U
PROGMEM_SIZE バイト単位でのフラッシュ容量。2048Uから131072Uまで
NVMCTRL_ADDRH tinyAVR-0/1/2系統とmegaAVR-0系統固有(NVMCTRLv0系列)
NVMCTRL_ADDR2 AVR_DA/DB/DD/EA/EB系統固有(NVMCTRLv2/3系列)
EVSYS_ASYNCCH0_gm tinyAVR-0/1系統固有
EVSYS_ASYNCCH2_gm tinyAVR-1系統固有
ADC_TIMEBASE_gm tinyAVR-2系統固有
EVSYS_GENERATOR_gm megaAVR-0系統固有
CLKCTRL_AUTOTUNE_bm AVR_DA/DB/DD系統固有(RSTCTRL_SWRST_bmに同等)
RSTCTRL_SWRST_bm AVR_DA/DB/DD系統固有(RSTCTRL_SWRE_bmの逆)(F_CPU=24MHz系列)
RSTCTRL_SWRE_bm tinyAVR/megaAVR世代と、AVR_EA/EB系統固有(RSTCTRL_SWRST_bmの逆)(F_CPU=20MHz/16MHz系列)
OPAMP_TIMEBASE_gm AVR_DB系統固有
ZCD3_ZCD_vect_num AVR_DD系統固有
MVIO_MVIO_vect_num AVR_DB/DD系統固有
FUSE_UPDIPINCFG_bm AVR_DD/EA/EB系統固有(HV=8.2V制御系列)
CLKCTRL_TIMEBASE_gm AVR_EA/EB系統固有(NVMCTRLv3系列)
BOOTROW_START AVR_EB系統固有
NVMCTRL_EE_vect_num 後述
NVMCTRL_NVMREADY_vect_num 後述
ZCD0_ZCD_vect_num 後述
  • NVMCTRL_ADDRH は NVMCTRL version 0 採用品種に固有。
  • NVMCTRL_ADDR2 は NVMCTRL version 2/3 採用品種に固有。
  • NVMCTRL version 1 は欠番。
  • NVMCTRL version 3 採用品種は現在 AVR_EA/EB のみなので CLKCTRL_TIMEBASE_gm で判別可能。
  • tinyAVR-0/1/2 系統のみ HV=12V制御系列。つまり NVMCTRLv0 かつ megaAVR-0 以外。

特定品種のベクタ番号判定

NVMCTRL_NVMREADY_vect_numZCD0_ZCD_vect_numなどの数少ない品種にしか定義がないものは、その値を調べれば容易に絞り込むことができる。

Symbol Num Target
NVMCTRL_EE_vect_num 25 ATtiny202/402/404/406 ATtiny212/214/412/414/416/816/817
29 tinyAVR-2
30 megaAVR-0 ATtiny804/806/807/1604/1606/1607 ATtiny1614/1616/1617/3216/3217
35 AVR_DA/DD
36 AVR_DB
- other
NVMCTRL_NVMREADY_vect_num 30 AVR_EB
33 AVR_EA
- other
ZCD0_ZCD_vect_num 26 AVR_DA
28 AVR_DB
- other

系統別分岐例

// 
// AVR 世代の大まかな分類
//

#if defined(RSTCTRL_RSTFR)
  /* found modernAVR */
#else
  #error This ARCHITECTURE not supported
#endif

//
// modernAVR 世代の大まかな分類
//

#if defined(NVMCTRL_ADDRL)
  /* tinyAVR-0/1/2 and megaAVR-0 */
  /* NVMCTRL version 0 */
#endif

#if defined(NVMCTRL_ADDR2)
  /* AVR_DA/DB/DD/EA/EB */
  /* NVMCTRL version 2/3 */
#endif

#if defined(RSTCTRL_SWRE_bm)
  /* tinyAVR-0/1/2 , megaAVR-0 and AVR_EA/EB */
  /* F_CPU = 20MHz/16MHz */
#endif

#if defined(RSTCTRL_SWRST_bm)
  /* AVR_DA/DB/DD */
  /* F_CPU = 24MHz */
#endif

//
// modernAVR ファミリー別
//

#if defined(EVSYS_ASYNCCH0_gm) && !defined(EVSYS_ASYNCCH2_gm)
  /* tinyAVR-0 only */
#endif

#if defined(EVSYS_ASYNCCH2_gm)
  /* tinyAVR-1 only */
#endif

#if defined(ADC_TIMEBASE_gm)
  /* tinyAVR-2 only */
#endif

#if defined(EVSYS_GENERATOR_gm)
  /* megaAVR-0 only */
#endif

#if (SPI1_INT_vect_num == 36)
  /* AVR_DA only */
#endif

#if defined(OPAMP_TIMEBASE_gm)
  /* AVR_DB only */
#endif

#if defined(ZCD3_ZCD_vect_num)
  /* AVR_DD only */
#endif

#if (NVMCTRL_NVMREADY_vect_num == 33)
  /* AVR_EA only */
#endif

#if defined(BOOTROW_START)
  /* AVR_EB only */
#endif
  • EVSYS_STROBE を調べると、megaAVR-0系統だけに絞り込める。
  • tinyAVR-0系統には独自の機能がないため、判別に複数条件が必要。
  • GPIOの本数を直接示すマクロ定義はないので、パッケージpin数規模を見分けるには、USART割込の有無を調べると容易。

関連リンク

Copyright and Contact

Twitter(X): @askn37
BlueSky Social: @multix.jp
GitHub: https://github.com/askn37/
Product: https://askn37.github.io/

Copyright (c) askn (K.Sato) multix.jp
Released under the MIT license
https://opensource.org/licenses/mit-license.php
https://www.oshwa.org/

0
0
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
0
0