この記事は C++ Advent Calendar 2015 の 15日目の記事です.
前の日は amedama41 さんの「io_service の使い方」でした.
R8C/M120AN,R8C/M110AN の紹介
このマイコンは、秋月電子などで、1個100円で売られているマイコンで、それぞれ、DIP20、
DIP14パッケージになっています。
※DIP20、DIP14とは、以下のような物で、電子工作では、ユニバーサル基板に組んだり、
ブレッドボードに組んだりできるので、重宝するパッケージです。
(昔ながらのパッケージです)
このマイコンに注目するのは、大きな理由があります。
カタログスペックでは、ProgramFlash:2キロバイト(メインプログラムを格納する領域)、
RAM:256バイト(スタックやワーク領域)、でも実際には・・
ProgramFlash:64キロバイト、RAM:1280バイト
の容量を持っていて、制限なく使う事ができます。
このくらいあると、プログラムの幅が広がり、C++ でプログラミングして動作させるのにも
問題ありません。
※RAM が1280バイトでは、記憶割り当てが使えない為、大きな制限がある事はあるので
すが・・・
通常マイコンには、様々なバリエーションのデバイスがあり、基本的には、Flash、RAM、内部
機能の違いで、付加価値を変えており販売価格が違います。
しかしながら、内部のシリコンを個別に設計するのは莫大なコストがかかる為、多くは共通に
なっているものと思います。
通常では、デバイスの許す領域以外はアクセスしても、無効なエリアとなるような仕組みと専
用ヒューズが用意されている
ものと思いますが、このデバイスは安価なバリエーションに属するデバイスで、ツール側の対
応で、行う方針だったように推測します。
Flash へプログラムを書き込む場合、専用の書き込みツールを使う為、通常は、デバイスの範
囲を超えて書き込む事はできませんが、書き込みソフトも実装したので、全ての容量を使う事
が出来ます。
※書き込みツールは Mac や Linux(試していませんが・・)でも使えるはずです。
始め、この話を聞いた時、そんな「旨い」話があるはず無いとも思っていましたが、実際に試
したら、使えたので、小躍りした思い出がありますww
※最初は32Kまで(0x8000 ~ 0xffff)確認できましたが、その後の調査で、もう32Kあ
る事が発覚しました。(0x10000 ~ 0x17fff)
※R8C は基本、8ビットのマイコンで、基本的に64Kバイトを超える領域にアクセスするに
は、特別な方法が必要ですが割と簡潔な方法で、拡張されたエリアを使う事ができます。
開発環境の準備
ルネサスエレクトロニクスが、提供する、
IDE(無料版には制限があります)を使う事も出来ますが、
Windows だけなので、自分で開発環境を用意します。
と、言っても、gcc などのソースコードを取得してコンパイルするだけです。
R8C マイコンは、M32C マイコンのサブセットで、M32C のコンパイラを構築して、デバイスオプ
ションで切り替えます。
gcc の構築については、以下のリンクを参照下さい。
・m32c gcc の構築
※このバージョンで構築した gcc は、4.7.4 ですが、「-std=c++0x」でほぼ C++11 でプログラ
ム出来ます。
※ m32c のクロスコンパイラは、メンテナンスされていない為、最新の gcc ではコンパイルに失
敗するようです。
※ 時間とエンジニアリングがあれば、最新の gcc や、clang でコンパイル可能な物も作ってみた
いです。
※gcc-4.9.3 を使えます。
プログラムの書き込み
組み込みマイコンが、「組み込み」たる所以は、「プログラムを書き込んで、単独で動作する事」
です。
このマイコンには、モード端子があり、それを切り替える事で、内臓フラッシュへの書き込みモー
ドと、単独でブートするモードがあります。
内臓フラッシュの書き込みでは、データを入出力する為の簡単なプログラムが内臓されており、シ
リアル接続を使って、簡単なプロトコルを使い内臓フラッシュへデータを書き込めるようになって
います。
以下は、代表的な USB シリアル変換回路の回路図です。
※USB シリアル変換は、安価に入手出来るので、自分で作る必要はありませんが、上記の回路なら、500円くらいで作れます。
R8C のフラッシュライター(参考回路)
USB シリアル変換と、ゼロプレッシャーソケットを組み合わせた書き込み機
デバイスのプログラムは、通常、開発基板のソケットからデバイスを外して、ライターの
ソケットにセットして、プログラムを書き込み、ライターから、開発基板にデバイスを戻
す。
などの、サイクルで行うのですが、プログラムを変更する度に、ソケットから外して、戻
してだと非常に面倒です、そこで、開発基板にシリアル入出力用のコネクター(写真では
6ピン)を付けておき、スイッチ(白い小さなスライドスイッチ)で切り替えて、基板に
デバイスを乗せた状態でプログラム出来るように工夫してあります。
書き込みプログラムは、一応、Windows、Mac でコンパイルできるように実装してあります。
r8cprog
※Windows でコンパイルする為には、termios.h が必要です。(特定の環境に付属します)
r8c_prog -d R5F2M120 -s 57600 -e -w -v led_test.mot
この例では、「led_test.mot」ファイルを「R5F2M120」へ書き込んでいます。
その際、「-e」でイレース、「-w」で書き込み、「-v」でベリファイ、のオプションを
追加しています。
マイコンのフラッシュプログラムは、他にみ色々な機能がありますので、コマンドのヘルプ
などを参考にして下さい。
Windows 版の GUI 付き書き込みプログラムが、千秋ゼミで公開されています。
※登録が必要です。
I/O定義の構築
メーカーがサンプルで提供している、I/O定義ファイルは、非常にチープで、解りにくい代物
です。
そこで、R8C/M11Aグループ、R8C/M12Aグループ データシートに記述されているレジスター名に一致して、扱い易いようI/O定義
を C++ のテンプレートで作成しました。
このテンプレートは、以前にRXマイコンで養ったテクニックを盛り込んだ物ですが、まぁ60
点くらいの出来だと思います。
R8C I/O 定義ヘッダー集
GitHub に上げてあります。
組み込みマイコンで C++ ぽぃ書き方が出来ますww
メーカーがサンプルなどで提供するI/O定義は、C言語向けのもので、特定のコンパイラでしか
正しく機能しない物が多く、判りにくく、エラーに対する許容度が低く使う気になりませんでした。
ネットには、同じような組み込みマイコン向けのI/O定義をテンプレート化するコードはありま
したが、色々調べると、機能的に満足出来ない部分もあり、結局、学習も含めて自分で実装する事
にしました。
開発過程で、コンパイルされたアセンブリコードを眺めて、ある程度許容されたコードが出るよう
に工夫しました。
また、最適化無しでも、最適化しても、動作するコードが出るように工夫してあります。
たとえば、P1ポート・レジスターのB2を「1」にする場合は
P1.B2 = 1;
と書けます。
読み出す場合は
bool value = P1.B2();
とします。
「()」オペレーターを使って、「読み出し動作」を明確に分けています。
こうしないと、最適化した場合と、しない場合で、問題のあるコードがでてしまう場合があります。
他に、「enum class」でポートの機能切り替えを定義しておき、機能を切り替えるようにしてみま
した。
#include "common/port_map.hpp"
utils::PORT_MAP(utils::port_map::P10::AN0);
utils::PORT_MAP(utils::port_map::P11::AN1);
↑ P10、P11 をアナログ入力 AN0、AN1 に指定
utils::PORT_MAP(utils::port_map::P12::TRCIOB);
utils::PORT_MAP(utils::port_map::P13::TRCIOC);
↑ P12 を TRCIOB、P13 を TRCIOC に設定
デバイス操作クラス
組み込みマイコンには、色々なハードウェアーリソースがあり、これらを簡潔に使う為に、小さなク
ラスライブラリーを提供しています。
※C++ のテンプレートは、このような用途に最適で、非常に柔軟性のある判り易い実装ができ、最適
化にも有利です。
R8C/M120/M110 では以下のような機能があります。
(1) 入出力ポート:17本 (LED 駆動用ポート含む)
(2) 外部割り込み入力:8本
(3) 16ビット多機能タイマ(タイマ RJ2) ---> trj_io
(4) 8ビットプリスケーラ付8ビット多機能タイマ(タイマRB2 ):1 ---> trj_io
(5) 16ビットインプットキャプチャ/アウトプットコンペアタイマ(タイマRC ):1 ---> trc_io
(6) UART/クロック同期形シリアルインタフェース:1チャネル ---> uart_io
(7) 10ビットA/Dコンバータ:6チャネル ---> adc_io
(8) コンパレータ:2回路 ---> comp_io
(9) ウォッチドッグタイマ
(10) クロック発生回路:XINクロック発振回路、オンチップオシレータ(高速/低速)
(11) データフラッシュ:2KB ---> eeprom_io
他に、I2C インターフェースをソフトでエミュレーションするクラス。
特定のデバイス向けクラスなど色々実装してあります。
※GitHub 参照
拡張領域の利用法
リンクローダーに与えるローダースクリプトに、0x10000 ~ 0x17fff までのエリア
(セクション)を宣言しておき、プログラムソースで、
__attribute__ ((section (".exttext")))
※この場合、拡張エリアは「exttext」としてセクションを定義してあります。
セクションを切り替え、コードが格納される場所を分散すれば、後はコンパイラが
64K を超える領域への呼び出しを、R8C が持つ、20 ビットアドレスが可能な命令
に置き換えてくれます。
M120AN/m120an.ld ---> リンカースクリプト
ADC_test/main.cpp ---> main 関数が、exttext エリアに指定
アセンブリコード:
80a2: fd 00 00 01 jsr.a 10000 <_main>
Disassembly of section .exttext:
00010000 <_main>:
10000: 7c f2 d1 enter #0xd1
10003: 7e 9f 98 00 bset:g 0,0x13
サンプルプログラム
組み込みマイコンで、良く使われる機能に絞って、色々サンプルプロジェクトを開発しました。
ADC_test/ A/D コンバーターのテスト
COMP_test/ コンパレーター入力のテスト
ENCODER_test/ エンコーダースイッチを使うテスト
FLASH_test/ 内臓データ EEPROM を操作するテスト
I2C_EEPROM_test/ I2C 接続の EEPROM を操作するテスト
I2C_RTC_test/ I2C 接続の RTC を読み書きするテスト
LCD_test/ LCD(Bitmap Graphics)を描画するテスト
LED_test/ LED の点滅テスト(よく言う「Lチカ」)
PLUSE_INP_test/ パルス入力周期を測定するテスト
PLUSE_OUT_LCD/ 任意のパルス出力を行うテスト(エンコーダー入力、LCD 表示)
PLUSE_OUT_test/ 任意のパルス出力を行うテスト
PSG_test/ ※開発中
PWM_test/ PWM 出力を行うテスト
RC_SERVO_test/ ラジコン用サーボを動作させるテスト
RGB_LED_test/ ※開発中
SD_monitor/ SDカードの読み書きモニター
SD_test/ 簡単なSDカードの読み書きテスト
SD_WAV_play/ SDカードにあるWAVファイルを再生するテスト(PWM信号としてアナログ的に出力)
SWITCH_test/ スイッチ入力テスト
TIMER_test/ タイマー機能のテスト
UART_test/ UART を使った、シリアル入出力テスト
各プロジェクトには、Makefile があり、
make
とすれば、コンパイルが行われます、その際、従属規則も同時に生成するようにし
ています。
プログラムを書き込み際には
make run
とします。
※「Makefile」参照
まとめ
小さくて、機能豊富なマイコンなら、アイデア次第で、色々な「オリジナル電子小物」を作る事が
でき楽しいものです~
上記のクラスライブラリーを使えば、最低限の手間と理解で、簡潔にやりたい事が出来ると思いま
す。
興味があったら、何か作ってみてはいかがですか?
質問等あったら気軽にメールでも下さい。