2015年1月10日土曜日

SparkFun Geiger CounterのArduino化

先日設計上の不具合を何とか改修する事が出来たSparkFunのGeiger Counter SEN-09848だが、software(firmware)も製品購入時には非常に単純な物しか入っておらず、時間線量の算出・表示すら出来ない。

折角直したので、これを機会にいろいろprogramを書いて遊んでみたいので、ひとまずArduino化することにした。

ICSP pinheadersの取り付け

本品にはご覧のようにprocessorとしてATmega328P(flat package)、USB-TTL変換としてFT232RLが使われている。買った状態ではICSP端子にpin headersはついていないので、まず下図のように取り付けた。1番pinには細い線でmarkingされている。
ATmega328Pには外部発振子が付いていないので、内部RC発振を利用しているようだ。

さて、ICSP端子からbootloaderやfirmwareを書き込むには、ISP用のprogrammerが必要である。専用で安価なAVRISP mkII3,200円@秋月電子)をお勧めしたいが、持っていなければ別のArduinoにISP用のsketch(Arduino IDEに付属)を入れてprogrammerにする方法や、FT232Rから必要な端子が出ていればFT232R Bit Bangingという方法でprogrammingする事も出来る。詳しいやり方は他所で解説されているので、「Arduino ブートローダ 書き込み」等で検索してみてください。

本品はFT232RLを使用してはいるものの、Bit Bangingに必要なCTS、DSR、DCD、RIが結線されていないので、本品のFT232RLを使ってのBit Bangingは出来ないと考えた方が良いだろう。やるならCTS、DSR、DCD、RI端子が出ている別のFT232R搭載Arduino等を持ってきて、本品のICSP端子に接続して使う形になる。

なおICSP端子にはVCC/GND線も有りますが、AVRISP mkIIはここからtargetに電源を供給しません。逆にtargetが通電しているかどうかの検出に使っているようです。従って、targetには別途(本品の場合USB端子から)電源を供給して下さい。

Fuseの設定

早速programmerを繋いで、SEN-09848の購入時のfuseの状態を調べてみたところ、次のようだった。

 Extended   0xF8 (0x00) 
 High    0xDF 
 Low   0xE2 
なお拡張byteの3~7 bit目は使用されていないので、そこが1と見れば0xF8、0ならば0x00という事である。書き込みsoftwareにより、未使用bitsの表現が異なっている事がある。
AVR processorのfusesは「ONが0、OFFが1」と、通常とは逆になっているので、設定変更時十分注意しよう。間違ったfuse設定を書き込んでしまうと、AVR processorが2度と使用できなくなる恐れがある。

こちらの便利なsiteで上記bitsを解釈すると、fuseの状態は次の様になっていることが判る。
  • 内蔵 RC回路 8MHz 発振、起動遅延時間 65msec
  • Boot用flash領域 256words、Boot Reset Vector OFF
  • 電圧降下検出 VCC=4.3V (*)
(*) なおここの拡張byteにある電圧降下検出(BODLEVEL)のbitsは間違っていて、本来有り得ない組み合わせになっている。
さて、bootloaderを使用するため、fusesを書き換えてみよう。筆者はAtmel Studio 6.2(旧AVR Studio)とAVRISP mkIIの組み合わせで行った。
Optibootを使用する予定なので、BOOTSZ = 256W(512bytes)のままとし、clockの設定(SUT_CKSEL)も変更しない。変更するのは、下記2箇所のみとした。
  • BOOTRSTをON(0)に(bootloaderを使用するのだから当然)
  • BODLEVELを2.7Vに(変更しなくても良いが、正しい値にしておく。他の値でも良い)
他のbootloaderを使用する場合は、sizeに合わせてBOOTSZを調節して下さい。そのbootloaderを使用しているboards.txtの項目を参照し、fuseの設定やupload.maximum_sizeの値からbootloaderのsizeが推測できます。(32768や16384といった値からupload.maximum_sizeを引いてみます。)

先程も述べたように、絶対に間違ったfuse設定を書き込まない事。特に、外部発振の設定にしてしまうと、Ceralockや水晶発振子を(flat packageに!)外付しないと動作しなくなり、programmerによるaccessも出来なくなります。またRSTDISBL、SPIENも絶対に変更してはいけません

間違いが無い事をしっかり確認できたら、上記fusesの値を書き込み(Programし)ます。

Bootloaderの書き込み

Fusesの次はいよいよbootloader本体の書き込みです。まず、Optibootの開発siteから最新版v5.0aをdownloadしてきます。Desktopに解凍し、その中の「optiboot_atmega328.hex」というのをFlashに書き込み(Programし)ます。
以上で書き込み作業は終了です。ProgrammerからSparkFun Geiger Counterを取り外します。

Arduino IDEの設定

Arduino IDEの個人用Sketchbook location(Preferencesを見ると判ります。通常はDocuments folderのArduino配下)に「hardware」というsub folderが無ければ作って、その下にこのzip fileを解凍して出来た「SparkFun Geiger Counter」というfolderをそのまま置きます。

中に入っているのはboards.txtだけで、その中身はこれです。
##############################################################
# Sparkfun Geiger Counter w/optiboot
#  ATmega328P, Int RC Osc 8MHz
##############################################################
sfgeigero.name=[Optiboot] Sparkfun Geiger Counter (8MHz Internal)
sfgeigero.upload.protocol=arduino
sfgeigero.upload.maximum_size=32256
sfgeigero.upload.speed=57600
sfgeigero.bootloader.low_fuses=0xE2
sfgeigero.bootloader.high_fuses=0xDE
sfgeigero.bootloader.extended_fuses=0x05
sfgeigero.bootloader.path=optiboot
sfgeigero.bootloader.file=optiboot_atmega328.hex
sfgeigero.bootloader.unlock_bits=0x3F
sfgeigero.bootloader.lock_bits=0x0F
sfgeigero.build.mcu=atmega328p
sfgeigero.build.f_cpu=8000000L
sfgeigero.build.core=arduino:arduino
sfgeigero.build.variant=arduino:standard
##############################################################
この後、Arduino IDEを起動すると、Tools -> Board menuに追加した項目が現れます。

13番pin LEDの追加

さて早速Blink sketchをuploadしてみたいところなのですが、SparkFun Geiger CounterはPB5、つまりArduino 13番pinにLEDが結線されていません。ですが幸い、このpin(PB5)はSPI clock用としてICSP端子に出ていますので、それを利用します。
つまり上図のようになっていますので、SCK pinとGND pinとの間にLED(と抵抗)を入れればOKです。
このようにすればBlink sketchの動作確認が出来る他、13番pin LEDはRESET buttonを押下した時にもbootloaderの動作で点滅するようになっているので、bootloaderが正しく書き込まれているかの確認にも使用出来ます。

Sketchのupload

さていよいよsketchのuploadです。しかしここにちょっと問題があって、筆者の所有しているSparkfun Geiger CounterのSEN-09848というversionにはauto-reset回路が無いのです。後継のSEN-10742SEN-11345(現行)にはauto-reset回路が付いています。

Auto-reset回路というのは、FT232RLのDTR端子から0.1uFを介してATmega328PのRESET端子に結線されているだけなのですが、これを追加するのは両ICsともflat packageのため面倒かつかなり見た目が悪くなります。

そこで筆者は手動resetで我慢することにしました。

ところがこのreset button押下のtimingがかなり微妙で、慣れが必要です。

Arduino bootloaderはresetされると、ごく短時間serial通信を待機します。このtimingに丁度うまくArduino IDEから通信の試行が行われるようにしなければなりません。

まず、通信のやりとりを見えるようにするため、Arduino IDEの「環境設定(Preferences)」で書き込み時の詳細表示を選択します。
コンパイル(compilation)の方は詳細表示にしなくても良いでしょう。

Sketchをuploadしようとすると、「Uploading...」の終盤になって次のような橙色文字の表示が現れます。ここがresetのtimingです。
うまくやるためには「Uploading...」の途中からreset buttonを押したままにして、上の橙色文字が見えたらすかさず指を離して下さい。上図のようにmessage領域を大きく広げておくと見易いです。

成功するとdataのやりとりが行われ、uploadが無事完了します。
これがuploadが成功した時の表示です。またuploadしたsketchに従ってLEDがblinkしていると思います。

Blink sketchのloop内のdelay()値をその都度変更すれば、新しいsketchが動作しているかどうかが判ると思います。またsketch内の「13」pin指定を「A5」に変更する事により、先ほどわざわざ外付したLEDではなく、本体上の「Counter」のLEDをblinkさせる事が出来ます。外付けLEDでの動作が確認できたら、blink sketchをそのように変更し、外付けLEDは外してしまいましょう。

Arduino IDEのserial通信とreset button押下のtimingが合わないとuploadに失敗し、以下の様な表示となります。
stk500_getsync(): not in sync: resp=0x00」というのが通信の同期に失敗した事を示しています。失敗していても、「Thank you.」「Done uploading.」等成功した時と同じような表示も出る事には注意して下さい。

筆者はbaud rateを他に色々変えて試しましたが、何故か57600bps以外では成功していません。また他のOptibootの.hex filesも用いてみましたが、成功したのはこの「optiboot_atmega328.hex」だけでした。

実際のresetのtimingはかなり微妙(体感では200~300msec位の範囲)ですが、慣れればわりと確実にupload出来るようになります。練習して下さい。

現行のArduinoは殆どauto-resetになっているので、通信待機時間を長く取る必要が無くなり、現行のbootloaderではそれが極端に短くなっているようです。本機のような手動reset用には、きっとbootloaderを再compileして待機時間を長く取るようにすれば良いのかもしれませんが、筆者にはまだその方法が判らないところです。

また先も述べたように後継機種であるSEN-10742SEN-11345をお持ちの方は、auto-resetに対応していますので、reset buttonのtimingで苦労することは無い筈です。

他のbootloaderを用いる

Optiboot以外でも実はやってみました。本家TutorialのこちらからBreadboard.zipをdownload、展開し、前述の個人用Sketchbook locationのhardware folder配下に置きます。

Programmerを用いて、fusesとbootloaderをそれぞれ書き込みます。
  • Fuse設定は、Low 0xE2、High 0xDA、Extended 0x05(0xFD)
    • bootloaderのsizeは1024W(2048 bytes)
  • bootloaderはArduino IDEに付属の「ATmegaBOOT_168_atmega328_pro_8MHz.hex
IDEのTools -> Board menuには「ATmega328 on a breadboard (8 MHz internal clock)」という名称で現れます。

試してみたところ、こちらのbootloaderの方がOptibootよりもややtimingに余裕がある感じでした。Optibootでどうしてもtimingが掴めない方にはお勧めかもしれません。なお通信速度はやはり57600bps以外では動作しませんでした。

Arduino化完了!

何とかSparkFun Geiger CounterをArduino IDEで簡単に扱えるように出来ました。

製品版のfirmwareのsourcesはGitHubにあります。取り敢えず、製品に入っていた検知間隔に応じて0と1を出力するだけの非常に単純なfirmware(v12)を、Arduinoのsketchに書き直してみました。
/*
  SparkFun Geiger Counter
  Official v12 firmware on Arduino
  
 created 10 Jan 2015
 by Rin FUKUDA 
 jg1vgx@jarl.com
 */

// Constants
#define LEDPIN A5  // Counter LED (green)

// Variables
volatile long j=0;      // Interval since the last count
volatile long jlast;    // previous interval
byte cbit;     // '0' or '1' for char output on terminal

void setup() { 
  // pin I/O settings
  pinMode(LEDPIN, OUTPUT);
  
  // Interrupts on INT0 (OUT)
  attachInterrupt(0, onCount, RISING);

  //Initialize serial and wait for port to open:
  Serial.begin(9600); 

  // Wait to settle
  delay(1200);
  interrupts();


void loop() { 
  // turn off the LED (HIGH is the voltage level)
  digitalWrite(LEDPIN, HIGH);
  // wait for a short while for counting
  delay(30);
  j++;


void onCount() {
  // blink LED
  digitalWrite(LEDPIN, LOW);
  delay(10);

  // check intervals  
  if(jlast < j) cbit = 0;
  if(jlast > j) cbit = 1;
  
  // send byte char to console
  Serial.print(cbit);
  
  // reset intervals
  jlast = j;
  j = 0;
}
たったこれだけです。こちらにも置きました。Sketchをuploadしたところ、ちゃんとArduino化以前と全く同じ動作で検出~countする事を確認しました。Arduino IDEにはSerial Monitor機能が付いているので、別のsoftwareを起動せずに動作確認が出来、大変便利です。
さらに、dotによる簡易bar graphで時間線量(CPM, counts per minute)をserial出力するsketchを書いてみたのでここに置きます。

0 件のコメント:

コメントを投稿