公開日:2020/12/05
title.png

13th Season


#13-9 もっと小さくATtiny2313

 普段使っているArduino UNOに搭載されたATmega328というMCUは、旧ATMEL社のmegaシリーズ型番#328と言う意味です。

 ATmega328も28DIP(Dual Inline Package 28 pin)ということで、十分小さいのですが、328duinoの様に170穴ミニブレッドボード1枚に載せようとすると、ブレッドボード上17列しかない穴の14列をATmega328が占めてしまって、外部回路を構築するスペースが確保できず、苦労します(下図がその例)。

ar95_328duino_1.jpga137_remocon.jpg

 上左図はミニブレッドボードに押し込んだUNOの互換機(328duino(第一形態))で25MHzまでクロックアップ可能な機体、上右図はミニブレッドボードに押し込んだ赤外線リモコン化328duinoです。いずれも、ちょっとした外部回路しかついていないのですが、無理をしてギチギチに詰め込んでいます。

 もっと小さく🐜使えるMCUは無いものか?

小さいtiny

 ATmega328だって、28DIP、Flash 32Kバイト、RAM 2Kバイトと、十分小さいのですが、にもかかわらず、mega(巨大な)という名を冠しているわけです。mega(巨大な)があれば、対応するtiny(とても小さい)MCUシリーズも存在しています。
 今回入手したのは、そんなMCUシリーズの中からATtiny2313というMCUです(下図)。

a139_attiny2313.jpg

  ATtiny2313のデータシートを検索する(別ウインドウが開きます)

 簡単に仕様をまとめておきます(↓)。

ATtiny2313
項目 概要 備考
MCU ATtiny2313A-PU @4〜20[MHz] 内蔵RC発振器8MHzでの動作が基本。
外部発振器を接続すると、20MHz動作可能。
CPU 8ビットRISC AVRコア ATmega328と同じAVRコア。
いくつかサポートの無い命令が存在する。
Flash 2Kバイト 2Kバイトしかないので、ブートローダ領域は無い。
RAM 128バイト 128Kバイトではなくて、128バイト。とても小さい。
EEPROM 128バイト 同上、RAMと同じサイズって……。
RAMの方が小さすぎるのだけど……。
PKG 20DIP 端子機能表は後ほど掲載。
電源・I/O 1.8〜5.5[V] ATmega328と同様、電圧-fMAX規定がある。
I/Oユニット 8 bit Timer TC0
16 bit Timer TC1
Analog Comparator
USI (Universal Serial Interface)
USART
4本のPWM出力。
AD変換器は非搭載。
アナログ比較ユニットがある。
USIでSPI、I2C通信が可能。
USARTハードウェアシリアルも搭載。

 28DIPのATmega328P-PUに対して、こちらは20DIPなので、端子数にして8本、ブレッドボードの占有列数にして4列分コンパクトに使うことが出来ます。Flash 2Kバイトなので、ブート領域がありません(↓)。

  UNOのブートローダ:

 てな訳で、ATtiny2313への書き込みは、ISP(In System Programmer、書き込み装置)を使ったシリアルプログラミング(SPI通信)が基本です。Arduino UNO等をISPとして使い、ArduinoISP.ino等で書き込むことになります。後ほど、書き込み方を説明します。

Arduino IDEにATtinyボードを追加する

 シリアルプログラミング(ISP)という事は、Arduino IDEの「1発コンパイル&書き込み」ボタン(下図)では書き込むことが出来ないのだけど、とは言っても、ATtiny用のボードをIDEに追加しておかないと、コンパイルすらできないので、まずはボードを追加します。

a139_burn.png


 Arduino IDEを起動して、「ファイルメニュー ⇒ 環境設定」を選択すると、以下の様なウインドウ「環境設定」が表示されます。

a139_boardman.png

 「追加のボードマネージャのURL:」欄右端のボタンを押して、「追加のボードマネージャのURL」ウインドウが開いた状況が上図です。こっちのウインドウの「クリックして非公式〜」の文字列部分がクリックできるようになっているので、クリックしてください。
 WEBブラウザが開いて、非公式ボードの一覧が表示されるので、この中から「ATtiny」や「ATtiny2313」等のキーワードで適切なボードを調べて、そこに記載されたURL「http〜.json」をコピーし、「追加のURL」欄に貼り付けます。

 本ページではATTinyCoreというボードパッケージを使いました。URLは上図の通り。他のパッケージを使うと、以下の解説と異なる内容があるかもしれませんので、ご注意ください。

 これ(↑)だけだと、まだボードの追加は完了していません。
 「ツールメニュー ⇒ ボード ⇒ ボードマネージャ」を開き、「ATTinyCore」で検索すると、上で追加したボードが見つかるので、適切なバージョンを選択して「インストール」してください。これで追加完了です。要らなくなったら、ここで「削除」もできます。

試してみよう

 試しにUNO用に作った小さめのプログラムをコンパイルしてみたのですが、ほとんどのプログラムはコンパイル失敗でした……。

  試してみたこと:

 「失敗」と言うのは正しくないかな?コンパイル自体は、正常に終了します。素晴らしいです。しかし、ほとんどのプログラムが「スケッチが大きすぎます」と言うエラーになります(↓)。

Arduino:1.8.11 (Windows 10), ボード:"ATtiny2313(a)/4313 (No bootloader), Enabled, ATtiny2313/ATtiny2313A, 8 MHz (internal), EEPROM retained, B.O.D. Disabled (saves power), no, Enabled, Port A (pins 2,3,17)"

最大2048バイトのフラッシュメモリのうち、スケッチが3958バイト(193%)を使っています。
最大128バイトのRAMのうち、グローバル変数が317バイト(247%)を使っていて、ローカル変数で-189バイト使うことができます。
text section exceeds available space in board
スケッチが大きすぎます。http://www.arduino.cc/en/Guide/Troubleshooting#size には、小さくするコツが書いてあります。
ボードATtiny2313(a)/4313 (No bootloader)に対するコンパイル時にエラーが発生しました。

 上のエラーメッセージの例だと、Flash 2Kバイトに対して約4Kバイトになっているし、RAM 128バイトに対して317バイト必要、と言うことで、Flash/RAM共、全く足りていません。小さ目なプログラムを選んだつもりでしたが、ATtiny2313にとっては、まだまだ大きかった様です。

ライブラリの物量チェック

 そこで、ライブラリの物量をチェックしてみました。

 まず、中身が空っぽのプログラムを用意します(↓)。

  void setup (void)
  {  // empty
  }

  void loop (void)
  {  // empty
  }


 これをコンパイルして、メモリ(Flash/RAM)使用量をメモします。これをベースに、「ツールメニュー」のATtiny2313に関するオプションを変えてみたり、Serialライブラリを使用したり、Wireライブラリを使用したりするコードを追加して、Flash/RAMの物量を調べました。

condition Flash RAM memo
ATtiny2313_default 236 9 2313を選択したデフォルト状態
空のsetup()、loop()関数
init 2nd timer 240 9 ATtiny2313_defaultに対して2nd timerを有効化
millis disable 66 0 ATtiny2313_defaultに対してmillis()関数を無効化
Serial "hello, world" 1,096 92 ATtiny2313_defaultに対して
Serialライブラリを使った"hello, world"
Wire "hello, world" 964 64 ATtiny2313_defaultに対して
Wireライブラリを使った"hello, world"
sprintf "hello, world" 308 23 ATtiny2313_defaultに対して
sprintf()関数を使った"hello, world"

 評価に使用したプログラムをリンクしておきます。

  評価用プログラム:tiny_test.ino

 「hello, world」等のコードはプログラム先頭付近の「#define」マクロで選択可能にしてあります(↓)。

  //#define USE_SERIAL
  //#define USE_WIRE
  //#define USE_SPRINTF
  //#define APLI_FIREFLY


 4つの#defineの内、必要な物のコメントだけを外してコンパイルして、メモリ使用量をメモしました。

  雑感:

 判ったことは、Serialライブラリの物量が大きいという事です。Serialライブラリを使った時点で、Flash容量の半分以上、RAM容量の70%以上を持って行かれます。本HPのUNO用プログラムのほとんどはSerialライブラリを使い、デバッグ用のコマンドや表示をハンドリングしているので、コンパイルしても容量不足となってしまったのでしょう。

コアライブラリの解析

 解析と言っても、さらっとコードを眺めてみただけです(1^^;)。「ATTinyCoreで何ができるのだろう?」と言うのが興味の対象です。ATTinyCoreのインストールパッケージは以下の場所にあります。

  <User>\AppData\Local\Arduino15\packages\ATTinyCore\

 <User>は、Windowsのユーザディレクトリです。ユーザ名やWindowsエディションによって、若干パスが異なる場合があります。<User>\AppDataは通常、不可視ディレクトリなので、エクスプローラなどからは見えていません。不可視属性のファイル/ディレクトリを表示する設定に変更して辿ってください。

 以下の様なことが判りました。

Port DIP ATtiny2313 DIP Port
D17(PA2/PCINT10/RESET/dW) 1 20 VCC
D0(PD0/PCINT11/RXD) 2 19 D16(PB7/USCK/SCL/SCK/PCINT7)
D1(PD1/PCINT12/TXD) 3 18 D15(PB6/MISO/DO/PCINT6)
D2(PA1/PCINT9/XTAL2) 4 17 D14(PB5/MOSI/DI/SDA/PCINT5)
D3(PA0/PCINT8/CLKI/XTAL1) 5 16 D13(PB4/OC1B/PCINT4)
D4(PD2/PCINT13/CKOUT/XCK/INT0) 6 15 D12(PB3/OC1A/PCINT3)
D5(PD3/PCINT14/INT1) 7 14 D11(PB2/OC0A/PCINT2)
D6(PD4/PCINT15/T0) 8 13 D10(PB1/AIN1/PCINT1)
D7(PD5/PCINT16/OC0B/T1) 9 12 D9(PB0/AIN0/PCINT0)
GND 10 11 D8(PD6/ICPI/PCINT17)

※D#は、Arduino IDEのデジタル端子番号。
※1ピンはRESET端子として割り当てておかないと、シリアルプログラミングモードで書き込みできない。

お試しプログラム

 お試しにATtiny2313で実行できるような小さな(シリアルモニタを使わない)アプリケーションって、何かなかったかな?と過去記事を漁ったところ、「#4-6 LEDキャンドル」なんて良いんじゃないの?と、思ったのだけど、ダメ、でした。1/fゆらぎ乱数列4,096点分のデータが4Kバイトにもなり、ATtiny2313のFlashには半分も載りません。アララ……。
 1/fゆらぎ乱数列のデータ数を間引いて、ATtiny2313に載るように工夫することも可能だろうけど、それはまた別なテーマとします。

※「#14-6 暗くなったら蝋燭を灯して」にて、ATtiny2313を使ったLEDキャンドルを作りました。ご確認ください。

 今回は、ATtiny2313の内蔵プルアップ抵抗で明滅させる「蛍の様なLED」を作って見ようと思います。

 蛍の様な明滅をさせるためにsin()関数を使ったところ、Flashが足りなくなりました。float型の演算ルーチンと、float型数学関数のコードサイズがかなり大きいみたいです。止むを得ず、uint8配列128個を使った整数型のテーブル(uint8 sin_tab[128])を使いました。128個なら128バイトなので、float型の物量に比べればかわいいものです。

 あと、どうも16ビットタイマ(TC1)がToneライブラリ用に初期化されているみたいで、PWMが出力されませんでした。setup()関数に以下の記述を追加して、TC1をPWM出力可能な設定に変更しました。

  // TC1 setting
  // pwm phase correct 8 bit mode 1, fcpu/64
  TCCR1A=0x01;
  TCCR1B=0x03;


※「ツールメニュー ⇒ Initialize Secondary Timers」の設定が関係するのではないか?と思いましたが、yes/noどちらでもPWM出力できませんでした。

 setup()関数内で上の設定をしておきさえすれば、その後は普通にanalogWrite()関数でPWM出力を制御できます。TC1が出力するI/Oポートはこちらを参照して、D12(OC1A)とD13(OC1B)が対象です。


 完成したプログラムをリンクしておきます。

  完成プログラム:tiny_test.ino

 先頭付近の#defineを以下の様にしてコンパイル&書き込みしてください。コンパイル&書き込みの方法については、次節で解説します。

  //#define USE_SERIAL
  //#define USE_WIRE
  //#define USE_SPRINTF
  #define APLI_FIREFLY


 手元の環境では、Flash 1,262バイト、RAM 9バイトを要しました。大したプログラムでもないのに、Flashは半分以上を使っています。どのプログラムでも、ちょっとした関数を呼ぶとFlashの半分は埋まってしまうので、共通して使用される何らかのコードサイズが既に1Kバイト程度存在している、と考えるのが自然ですね。

ATtiny2313へのプログラム書き込み

 ATtiny2313へArduino IDEからプログラムを書き込むには、別途、Arduino UNO等の機体が必要です。例えばUNOを「Arduino as ISP」として使って、ATtiny2313へ書き込みます。以下に手順を示します。

 手元の環境では、「スケッチメニュー ⇒ 書込装置を使って書き込む」がエラーになって書き込みできませんでした。Arduino IDEの書き込みツール(avrdude)が「attiny2313aなんて知らないよ」ってエラーでした。理由は解りません(※)が、以下の様に修正したところ、正常に書き込み出来るようになりました。

  修正するファイル:
    <User>\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.4.1\
      boards.txt

  修正内容:
    attinyx313.menu.chip.2313.build.mcu=attiny2313a
      ↓
    attinyx313.menu.chip.2313.build.mcu=attiny2313

 最後の"a"を消してセーブしたら、Arduino IDEを一旦閉じて再度起動してください。

※使用中のArduino IDE 1.8.11に含まれる書き込みツールavrdudeのバージョンが古いのか?/合っていないのか?


 UNOからATtiny2313へ書き込む時の接続表を示します。

UNO 接続 ATtiny2313
5V 20 VCC
GND 10 GND
D10 1 RESET
D11(MOSI) 17 D14(MOSI)
D12(MISO) 18 D15(MISO)
D13(SCK) 19 D16(SCK)

※ATtiny2313端子名左の数字は20DIPのピン番号です。生のMCUをブレッドボードに挿して使うので、Arduinoのピン番号(D14等)よりも、20DIPのピン番号で記した方が使い易いと思います。


 UNOをISPとして使って、ATtiny2313へ書き込み中の様子は下図の様になります。

a139_isp_tiny.jpg

 「スケッチメニュー ⇒ 書込装置を使って書き込む」がボタンに割り当たっていないため、一々メニューから選ばないとならないのが難点ですが、それ以外はUNOでのプログラミングと変わりません。アプリケーションでSPI端子を使わないのであれば、上図の様に繋ぎっぱなしでデバッグすることができます。

ヒューズの設定

 ATtiny2313にも、ATmega328と同じ様にヒューズが入っています。購入したままのATtiny2313は、工場出荷時設定のままでクロックが1MHz動作になっているなど、ATTinyCoreの環境と合っていません。ATTinyCoreを使って開発を続けるためには、少なくとも1回、以下の手順に従ってヒューズの書き込みを実行する必要があります。

 ATtiny2313へのヒューズ書き込みは、Arduino IDEの「ツールメニュー ⇒ ブートローダを書き込む」で書き込むことが出来ます。書き込み可能なヒューズ値は、以下の通りです。

a139_tool.png

 3つの項目だけですが、実際、個別に書き込みが必要なパラメータは、この3つで充足しています。メニューから設定したい項目を選んで、「ツールメニュー ⇒ ブートローダを書き込む」を実行するだけです。何を設定して良いかわからない場合には、とりあえずデフォルトのまま(上図がデフォルト)で書き込みを実施してください。

 以下にヒューズ書き込み手順を示しておきます。

 なお、「ツールメニュー ⇒ ブートローダを書き込む」を実行すると、ATtiny2313のFlashに書き込まれていたプログラムは消去されます。たぶんChip Eraseなので、「EEPROM not retained」に設定されていた場合には、EEPROMの内容も消去されます(EEPROM未使用のため未確認)。

ATtiny2313を動かしてみよう

 前節の作業でプログラム(tiny_test.ino)を書き込んだATtiny2313を使って、以下の回路をブレッドボードに構築します。

a139_schem.png

 デバッグ中は、ISP端子(RES,SCK,MISO,MOSI)を繋ぎっぱなしにできるよう、リザーブしておきました。
 ATtiny2313の内蔵プルアップ抵抗で制限された電流を使って4つのLEDを明滅させるので、とても暗いです。データシートによると、プルアップ抵抗値Rpu=20〜50[kΩ]ですので、Vf≒2VのLEDとVcc=5Vで動作させたとして、流せる電流値=(Vcc−Vf)/Rpu≒60〜150[μA]であり、明るいはずがありません。
 ただ、LEDの発光色によって、同じ電流値でも明るさが異なりますので、なるべく明るく光るLEDを選ぶのが吉です。手持ちの部品では、緑色や白色の方が、赤色や青色LEDよりも明るく光りました。


 実験中の様子を下図に示します。

a139_expr.jpg

 4つのLEDが蛍の様に明滅するはずです。すべて異なる周期で明滅させているので、4匹の蛍がブレッドボードに止まっているみたいじゃありませんか?……ちょっと、色が蛍っぽくないかな……。

※本物の蛍が複数匹近くにいると、明滅のタイミングが揃っていくらしいです。今回のプログラムでは、4個の明滅周期をわざと変えているので、バラバラに明滅します。

 電源はeneloop(1.2V)×4本≒4.8Vを使いました。ちょうど良い感じの明るさで明滅しています。



 まずはめでたく、ATtiny2313にArduino IDEからプログラムを書き込んで、思い通りに動かせることを確かめられました。良かった。

 問題はメモリの少なさ、ですね。結局、Flash 2Kバイト、RAM 128バイトでどこまでできるのでしょうか?
 ATtiny2313は20ピンの内、電源(VCC,GND)で取られるのは2本だけなので、残り18本ものI/Oポートを使えるのですが、それを使いこなそうとすると、あまりにメモリが少ない。ちょっと、I/Oポート数とメモリ容量のバランスが取れていない様に感じます。

 限られたリソースを如何に効率よく使ってアプリケーションを成立させるか?って言うのもやりがいのあるテーマですので、機会を見つけて挑戦してみようと思います。

今回のお買い物

 今回のお買い物は、以下の通りです。

 追加購入したATmega328と一緒に購入しました。この金額だと、費用対効果は圧倒的にATmega328の方が優れていると思います。……I/Oポート数とメモリ容量のバランスも良いし、さすがUNOのメインMCUに選定されただけのことはあります。


 あまりにメモリが少なくてデバッグにシリアルモニタが(ほぼ)使えないなど、かなり制限される分、腕の見せ所ですね……。メモリが足りないことで大規模なシステムは作れないので、腕を見せる前にシステムが成立しないかもしれませんけれど(1^−^;)。


btn_arduino.png

btn_prev.png btn_next.png

home