google-site-verification: google3bd66dd162ef54c7.html

Arduino よもやま話 -4 (コンパイラの設定など)

1.まえがき
 今回は Arduino IDE のコンパイラの設定など、私が普段やっていることについて書いてみます。なお、使っている IDE のバージョンは 1.8.1 なので少し古いものです。

2.コンパイラの警告
 バージョン1.8 あたりから「環境設定」のメニューの中に、「コンパイラの警告」というメニューが追加され、ここで、ワーニングを出すレベルを調整出来るようになりました。

▼コンパイラの警告
IDEの環境設定

 デフォルトは「初期値」で、普段はこの状態で使えば良いと思います。

 ブログなどでプログラムを公開する場合、私はこの設定を「全て」にしてコンパイルしています。こうしておくと、エラーではないけど、ちょっと変な書き方になっている個所を指摘してくれます。指摘された個所を修正すれば、プログラムの品質が上がるので、みっともないコードを世の中に晒さないで済みます。具体的には、のような点を指摘してくれます。(もっとあったはずですが思い出せません)
 ・定義されただけで、使われていない変数
 ・符号付きと符号無し変数間の比較
 ・型の定義の矛盾

 ちなみに、たとえコンパイラの警告を「無し」にしても、無しになるのは警告(ワーニング)だけで、コンパイルエラーは無しにはなりません。つまり、文法エラーがあればコンパイルは中断されます。

▼ワーニングの例
ワーニングの例
 小さくて読めないですが、こんな感じでワーニングが出ます。ちなみにこれは、EEPROMライブラリを使った時に出るワーニングで、たぶんライブラリ内部の問題だと思います。これはライブラリそのものを修正しないといけないので、そのまま放置しています。

3.ついでに
 プログラムの話なので似たような話をもう少し触れておきます。
1) スケッチファイルの命名方法
 いろいろな流儀があると思いますが、私は先頭に年月日を表す数字6桁を YYYYMMDD形式で付けています。プログラムを修正した場合は、その日の日付を先頭に付けるので、どんどんファイルが増えていきますが、気にしないことにしています。

▼スケッチ名の例
コンパイルエラー無し

 これは先日記事を書いた delayWDT2 のデモプログラムですが、ファイル名(スケッチ名)は_20180418_delayWDT2.ino にしています。当然ですが、このファイルが入っているフォルダ名も、_20180418_delayWDT2 です。なお、スケッチ名は数字で始まってはいけないというルールがあるので、先頭の _ は ArduinoIDE が勝手に付けてくれます。

 こうしておくと、ファイル名(フォルダ名)でソートすればプログラムの新旧がすぐに判って便利です。なお当然ですが、プログラムの保存フォルダは、「環境設定」で「スケッチブックの保存場所」として指定している場所です。

2)スケッチのファイルのエンコード
 Arduino IDE で作ったスケッチのファイル ( .ino ファイル) は UTF-8 でエンコードされています。これは普段は意識しなくても大丈夫です。でも、ブログの記事からスケッチのファイルにリンクを貼って、これをWebブラウザで読もうとすると、ほとんどのブラウザでコメントの日本語が文字化けします。

 もちろん、一旦ダウンロードして、そのファイルをしかるべきプログラムで開けば正常に読めます。でも、ブラウザでそのまま内容を見たい場合がほとんどなので、そんな面倒なことはやってられません。また、スマホで閲覧している場合は、そんなことまで出来ません。

 そういう問題を回避するには、ファイルのエンコードをUTF-8 からShift-JISに変換しておけば大丈夫です。変換方法はいろいろありますが、私はエディタ(秀丸)でやっています。

 あと、ブログの記事の中にプログラムを直接表示させたい場合は、半角の<などがタグとみなされてしまう問題がありますが、話が長くなるのでそのあたりの話は割愛します。

◆まとめ
 コンパイラの警告を「全て」にしておくと、きれいなプログラムを書くための支援機能になります。

 一方で、Arduino は細かいことは考えずに、とにかく作って動かしましょう、という文化なので、あれこれワーニングを出すと、思考の妨げになって良くないという考え方もあると思います。

 あと当然ですが、コンパイラのワーニングはアルゴリズムの間違いまで指摘してはくれないので、元がしっかりとしていないとダメなのは間違いありません。

ArduinoのCPUをスリープさせて消費電流を減らす関数 delayWDT2

 Arduinoのタイマーで、CPUを深いスリープ状態に入れて消費電流を減らすdelayWDT という関数を以前作りました。この関数を使うと、スリープ状態の消費電流を27μAまで減らすことが出来るので今でも便利に使っています。

 Arduinoではこれくらいが限界と思っていたのですが、もっと消費電流を減らすことが出来るという記事を見つけました。それは、
 tetsuaki baba さんのWebの、workshop/ArduinoBasis/sleep Arduino のSleep機能 という記事です。

 その記事には、ブラウンアウト検出(BOD)機能を止めることで、もっと省電流化する方法が書かれていて、何と 6.5μA まで減らすことが出来るそうです。なるほど、そういう手があったのかと感心しました。

 これはものすごい効果なので、delayWDT 関数にこの方法を組み込むことにしました。

 まずは仕組みのおさらいです。

▼ATmega328Pのスリープ機能一覧表(データーシートから抜粋)
ATmega328Pのスリープ機能一覧
 この表はCPUのスリープ機能の種類を表したものです。delayWDT関数では、いちばん消費電流が少なくなるパワーダウンモードを使っています。表の赤い横線部です。

 この表の右端にソフトウエアBOD禁止と言う欄がありますが、実は私、この意味が理解出来ていませんでした。調べてみると、ソフトウエアBOD禁止と言うのは、「ヒューズビットでBODを使うことが指定されていても、スリープ中はこの機能を解除するように、プログラムから指定出来ます」 という機能でした。

 深いスリープに入れた場合、クロックは止まっているので何も動いていません。ということは、たとえBODを検出したとしても、すぐに何かのアクションを起こさなくてもいいはずです。別の言い方をすると、クロック停止は安全側、つまりフェールセーフ設計にするのが定石なので、BOD状態になったとしてもすぐに何かしなくても大丈夫なずです。

 だったら、スリープ中はBODを止めても大丈夫。それに、BODを動かすためには20μAの電流が必要ですが、これがもったいない、ということなんだと思います。

 ちなみに、ソフトウエアBOD 禁止機能は ATmega328P など末尾(など)に P が入っている CPU に入っているようです。P は消費電流がピコアンペアオーダーになる、ということから付けられた記号だったと思いますが、なるほど、BODを有効にしていたのでは pA オーダーの消費電流にはなりません。ちなみに、ウォッチドッグタイマー (WDT) まで止めれば、消費電流はピコアンペアの領域に入るはずです。

▼ソフトウエアBOD禁止設定レジスタ
BOD設定
 MCUCR レジスタから操作するようです。但し、誤って設定されることを防止するためと思われますが、設定後 3クロック以内にスリープに入れないといけません。この条件を C 言語だけでクリアするのは難しいので、アセンブラ命令を併用する必要があるようです。

 具体的なやり方は、上記の tetsuaki baba さんのサイトで解説されていますが、その内容を delayWDT 関数に組み込んで使い易くしちゃいましょう、というのが今回の記事の目的です。

 なお、従来の関数 (delayWDT) との関係がややこしくなるので、新しい関数は、delayWDT2 という名前にしました。

 前置きが長くなりましたが、プログラムは以下の通りです。
/*
delayWDT2関数のデモプログラム。
パワーダウン中のCPUの消費電流は約6.5μA(Atmega328P@16MHz,5V)
このプログラムはdelayWDT関数にスリープ中はブラウンアウトを禁止することで
消費電流を更に下げたものです。勝手に使っていただいてかまいませんが、無保証です。
BODを無効化するための設定は下記を参考にさせていただきました。ありがとうございます
http://tetsuakibaba.jp/index.php?page=workshop/ArduinoBasis/sleep
fileName:_20180418_dalayWDT2.ino
2018/04/18 ラジオペンチ http://radiopench.blog96.fc2.com/
*/

#include <avr/sleep.h> // スリープライブラリ
#include <avr/wdt.h> // ウォッチドッグタイマー ライブラリ

int led = 13; // LEDピン
//volatile int wdt_cycle = 0; // 必要ならコメントアウトを削除

void setup() {
pinMode(led, OUTPUT);
}

void loop() {
digitalWrite(led, LOW); // LED off
// 低電流でスリープ
delayWDT2(7); // 引数でスリープ時間指定(詳細はdelayWDT_setup参照)
// 通常モードに復帰
digitalWrite(led, HIGH); // LED on
delay(2000); // 普通のdelay(比較用)
// delayWDT2(7);
}

// ここから下を全て使う
void delayWDT2(unsigned long t) { // パワーダウンモードでdelayを実行
Serial.flush(); // シリアルバッファが空になるまで待つ
delayWDT_setup(t); // ウォッチドッグタイマー割り込み条件設定

// ADCを停止(消費電流 147→27μA)
ADCSRA &= ~(1 << ADEN);

set_sleep_mode(SLEEP_MODE_PWR_DOWN); // パワーダウンモード指定
sleep_enable();

// BODを停止(消費電流 27→6.5μA)
MCUCR |= (1 << BODSE) | (1 << BODS); // MCUCRのBODSとBODSEに1をセット
MCUCR = (MCUCR & ~(1 << BODSE)) | (1 << BODS); // すぐに(4クロック以内)BODSSEを0, BODSを1に設定

asm("sleep"); // 3クロック以内にスリープ sleep_mode();では間に合わなかった

sleep_disable(); // WDTがタイムアップでここから動作再開
ADCSRA |= (1 << ADEN); // ADCの電源をON(BODはハードウエアで自動再開される)
}

void delayWDT_setup(unsigned int ii) { // ウォッチドッグタイマーをセット。
// 引数はWDTCSRにセットするWDP0-WDP3の値。設定値と動作時間は概略下記
// 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
// 6=1sec, 7=2sec, 8=4sec, 9=8sec
byte bb;
if (ii > 9 ) { // 変な値を排除
ii = 9;
}
bb = ii & 7; // 下位3ビットをbbに
if (ii > 7) { // 7以上(7.8,9)なら
bb |= (1 << 5); // bbの5ビット目(WDP3)を1にする
}
bb |= ( 1 << WDCE );

MCUSR &= ~(1 << WDRF); // MCU Status Reg. Watchdog Reset Flag ->0
// start timed sequence
WDTCSR |= (1 << WDCE) | (1 << WDE); // ウォッチドッグ変更許可(WDCEは4サイクルで自動リセット)
// set new watchdog timeout value
WDTCSR = bb; // 制御レジスタを設定
WDTCSR |= _BV(WDIE);
}

ISR(WDT_vect) { // WDTがタイムアップした時に実行される処理
// wdt_cycle++; // 必要ならコメントアウトを外す
}
 delayWDT2 関数を呼び出すサンプルプログラムの形になっています。Loop()の部分はLチカと同じ作りなので、説明は不要でしょう。

 何かに組み込む時は、ライブラリをインクルードしておいて、// ここから下を全て使う、以降をコピペしておけば、あとは delayWDT2(8); などと呼ぶだけで動くはずです。

 ポイントになるのは43から47行で、ここでBODを停止する設定を行った後で素早くスリープに入れています。なお、スリープから復帰する時に BOD は自動的に再起動するので、プログラムは何もしなくても良いようです。

 プログラムがうまく動いているか確認するために、デジタルマルチメーターで CPU の電源電流を測定しました。

▼CPU の消費電流測定
ArduinoのCPUの電流測定
 以前作った、ATmega328P の消費電流測定用のゲタを使って電流を測りました。このゲタには電源電流測定用の1Ωのシャント抵抗が入っているのですが、流れる電流が小さいので分解能が不足します。ということでシャント抵抗は使わず、DMMの電流レンジ (分解能10nA) で電流を直接測定しました。なお、使った基板はArduino UNO R3 です。

 以下、スリープ時の消費電流の値を見て行きます。

▼以前の delayWDT の場合
27μA
 以前作ったdelayWDT 関数では、スリープ中の消費電流は27.4μAでした。普通に動いている時は、3桁くらい上の16mAは流れるので、ものすごい省エネ効果ではあります。

▼今回作ったdelayWDT2の場合
6.5μA
 delayWDT2 関数を使うと消費電流は6.57μAまで減りました。delayWDT と比べると 1/4 以下の消費電流になっています。ここまで減ると、Arduino をコイン電池で動かすことも視野に入ってきそうです。

◆まとめ
 昔 delayWDT 関数を作った時の話ですが、CPUのデーターシートではもっと消費電流が減らせそうな感じなのですが、あと一歩追い込めなくて、妥協しました。そんなことで、ちょっと気になっていたことが、解決出来て良かったです。これからはdelayWDT2 を使って行こうと思います。また、貴重な情報を公開していただいた tetsuaki baba さんに感謝します。

◆ご注意
 この関数を使う場合、色々な注意事項があります。そのあたりは、冒頭に紹介した delayWDT関数の記事の末尾に書いておきましたので、一読して頂くと幸いです。
 なお、今回の関数はATmega328P用で、ATmega328では動かないはずなのでご注意下さい。

ArduinoのCPUのデーターを全部抜く(ダンプする)

 最近テレビで「池の水ぜんぶ抜く」、という番組をよくやってます。それに少し影響を受けて、Arduino の CPU の ATmega328P に入っている情報を全部抜くプログラムを作ってみました。まあ、抜くと言ってもデーターを、メモリーマップの形でシリアルにダンプするだけのものです。なお、この記事はArduino UNO で動作確認を行っています。

 普通のダンププログラムは、調べたい相手の状態を出来るだけ変えないで情報を出力します。それに対して、今回作ったプログラムは、ダンプ用のプログラムを書き込んで、その状態を出力しています。つまり、まるっきり相手を乗っ取った状態になっているので、あらためて調べなくても、ほとんどは事前に予想出来る情報のはずです。ということで、ちょっとインチキ臭い話です。

 そうは言っても、ダンプ出力を完全に予想するためには、システム全体に対する深い知識が必要ですが、簡単なことではありません。そういう意味では、このプログラムの存在意義はあると思います。

 ちなみに、CPU の内部構造の説明にメモリーマップがよく出てきますが、実データーが入った状態の解説はお目にかかったことがありません。本物のデーターを見ながら勉強すれば、より具体的にCPUを理解できるはずです。

 そんなことを考えて、CPU の情報を全部抜く(ダンプする)プログラムを作ってみました。

 先に実行した結果を示します。

▼CPUとダンプしたデータ
ダンプリストとCPUチップ
 これは、ダンプしたデータをプリントしたものです。小さな CPU の中に、A4 で14ページものデーターが入っているのは驚くばかりです。(両面印刷しています)

 以下、まずはプログラムです。
/* CPUの全レジスタとメモリーをダンプ
対象範囲(ATmega328P)
・IOメモリ領域:0x00-0x8FF(レジスタ、IOレジスタ、拡張IOレジスタ、RAM)
  8ビットx(2048+256) = 2304バイト
・EEPROM:0x00-0x1FF
 8ビットx512 = 512 バイト
・Flash Memory:0x00-0x3FFF
 16ビット×16384ワード = 32768バイト(32k)
2018/4/3 ラジオペンチ http://radiopench.blog96.fc2.com/
*/

#include <EEPROM.h>

char ascii[32]; // 文字列記録バッファ

void setup() {
Serial.begin(115200);
Serial.println("ATmega328P registers & memorys dump");
Serial.println();

Serial.println("REGISTER FILES"); // CPUレジスタ
IoDump(0, 0x001F);
Serial.println("I/O REGISTERS"); // IOレジスタ
IoDump(0x0020, 0x005F);
Serial.println("EXTENDED I/O REGISTERS"); // 拡張IOレジスタ
IoDump(0x0060, 0x00FF);
Serial.println("SRAM DATA MEMORY"); // SRAM
IoDump(0x100, 0x08FF);
Serial.println("EEPROM"); // EEPROM
eepromDump(0, 0x1FF);
Serial.println("FLASH PROGRAM MEMORY (2byte/word,Little Endian)"); // フラッシュメモリ
flashMemDump(0x0000, 0x3FFF);
}
void loop() {
}

void IoDump(unsigned int fromAdr, unsigned int toAdr) { // メモリ領域ダンプ
int p = 0;
unsigned int i;
byte data;
Serial.println("addr 0 1 2 3 4 5 6 7 8 9 A B C D E F <- ascii char ->");

for (i = fromAdr; i <= toAdr; i++) { // データーメモリ領域
if (( i & 0x0F) == 0) { // 行の先頭なら
printHex4chr(i); // アドレス表示
Serial.print(":");
clrAscii(15); // バッファを16文字分クリア
p = 0;
}
Serial.print(" "); // データ間にスペース入れる
data = _SFR_MEM8(i); // データメモリ読み出し
printHex2chr(data); // 16進2文字で表示
addAscii(data, p); // 文字コードなら記録
p++;

if ((i & 0x0F) == 0x0F) { // 行末だったら、
Serial.print(" ");
printAscii(15); // 該当文字を表示
Serial.println(); // 行末なので改行
}
if ((i & 0xFF) == 0xFF) { // 0x100間隔で1行開ける
Serial.println();
}
}
Serial.println();
}

void flashMemDump(unsigned int fromAdr, unsigned int toAdr) { // フラッシュメモリダンプ
int p = 0;
unsigned int i;
unsigned int data, dataH, dataL;
Serial.println("addr 0 1 2 3 4 5 6 7 8 9 A B C D E F <--------- ascii char --------->");

for (i = fromAdr; i <= toAdr; i++) { // 指定範囲をスキャン
if (( i & 0x0F) == 0) {
printHex4chr(i); // アドレス表示
Serial.print(":");
clrAscii(31); // 32文字分クリア
p = 0;
}
Serial.print(" "); // データ間にスペース入れる
dataL = pgm_read_byte(i * 2); // 1バイト目を下位
dataH = pgm_read_byte((i * 2) + 1); // 2バイト目を上位に(リトルエンディアンで格納)
data = (dataH << 8) + dataL; // 16ビットに結合

printHex4chr(data); // 16進4字で表示
addAscii(dataH, p); // 文字コードなら記録
p++;
addAscii(dataL, p); // 文字コードなら記録
p++;

if ((i & 0x0F) == 0x0F) { // 行末だったら、
Serial.print(" ");
printAscii(31); // 該当文字列を表示
Serial.println(); // 行末改行
}
if ((i & 0xFF) == 0xFF) { // 0x100間隔で1行開ける
Serial.println();
}
}
Serial.println();
}

void eepromDump(unsigned int fromAdr, unsigned int toAdr) { // EEPROMのダンプ
int p = 0;
unsigned int i;
unsigned int data;
Serial.println("addr 0 1 2 3 4 5 6 7 8 9 A B C D E F <- ascii char ->");

for (i = fromAdr; i <= toAdr; i++) { // 指定範囲をスキャンん
if (( i & 0x0F) == 0) { // 行の先頭だったら
printHex4chr(i); // アドレス表示
Serial.print(":");
clrAscii(15);
p = 0;
}
Serial.print(" "); // データ間にスペース入れる
data = EEPROM.read(i); // EEPROM 読み出し

printHex2chr(data); // 16進2文字で表示
addAscii(data, p); // 文字コードなら記録
p++;

if ((i & 0x0F) == 0x0F) { // 行末だったら、
Serial.print(" ");
printAscii(15); // 該当文字を表示
Serial.println(); // 行末を改行
}
if ((i & 0xFF) == 0xFF) { // 0x100間隔で1行開ける
Serial.println();
}
}
Serial.println();
}

void clrAscii(int n) { // 文字バッファを指定数クリア
for (int x = 0; x <= n; x++) {
ascii[x] = ' ';
}
}

void addAscii(byte d, int p) { // 文字コードだったら指定位置に記録
if ((d > 0x20) & (d < 0x7F)) { // キャラクタコードの範囲だったら
ascii[p] = d; // バッファの指定位置に記録
}
}

void printAscii(int n) { // 文字バッファの内容を指定数表示
for (int x = 0; x <= n; x++) {
Serial.print(ascii[x]); // バッファの文字を表示
}
}

void printHex2chr(byte x) { // 16進2桁で出力
Serial.print((x >> 4), HEX); // 上位
Serial.print((x & 0x0F), HEX); // 下位
}

void printHex4chr(unsigned int x) { // 16進4桁で出力
// x &= 0xFFFF;
Serial.print((x >> 12), HEX); // 最上位
Serial.print(((x & 0x0F00) >> 8), HEX);
Serial.print(((x & 0x00F0) >> 4), HEX);
Serial.print((x & 0x000F) , HEX); // 最下位
}
 
 吐き出す情報量が多いのでシリアルのビットレートを 115200bps と高くしています。あとは、細かい説明は省略しますが、下記がCPUからデーターを読み出している部分です。
・51行目の、
   data = _SFR_MEM8(i); // データメモリ読み出し
・82,83行目の
  dataL = pgm_read_byte(i * 2); // 1バイト目を下位
  dataH = pgm_read_byte((i * 2) + 1);
・118行目の
  data = EEPROM.read(i); // EEPROM 読み出し

 以下ダンプ出力を先頭から順に見て行きます。最初はデーターメモリー領域です。

▼CPU レジスタ、IO レジスタ、拡張 IO レジスタ
出力例1
 ここには、CPU レジスタ、IO レジスタ、拡張 IO レジスタの順に並んで始まります。

 0x00から0x1Fまでは CPU レジスタです。ここの内容は激しく変化しているので、ダンプ結果はある瞬間を捉えたものにすぎず、内容にほとんど意味は無いと思います。でもデーターメモリ領域の最初の32バイトが、CPU レジスタに割り当てられていることは良く判ると思います。

 0x20から0x5Fの範囲は IO レジスタで、ここでデジタル IO ポートなどの基本的な IO の制御を行っています。ちなみに、この領域はアセンブラの IO 命令からアクセス可能で、その場合のアドレスは0x00から始まります。なお、レジスタが存在しないアドレスもあり、その場所の値は不定になりますが、このダンプでは0xB8となっています。

 0x60から0xFFまでの領域は拡張 IO レジスタで、ここは ADコンバーターや I2C などの設定を行う領域です。

 IO レジスタはタイマーやADコンバーター、通信機能をコントロールする部分です。ここをいじっているだけで、相当遊んでいられると思います。

▼SRAM
出力例2

 0x100から0x8FFまでの2kバイトがSRAM領域で、プログラムの変数やスタックなどの保存に使われています。

 右のアスキーキャラクタ欄を見ると、プログラムで入力した文字列がそのまま入っている部分があります。これらは固定されたデーターなので途中で変更されることはありません。それにもかかわらずRAM領域に置かれているのはもったいないです。

 ここまでがデーターメモリ領域で、次はEEPROM領域です。

▼EEPROM
出力例3

 EEPROM領域は0x000から0x1FFまでの512バイトです。
 過去に EEPROM に書き込みを行ったことがあれば、その内容が残っています。まっさらな CPU ならデーターは全部 0xFF になっているはずです。

 次はフラッシュメモリ領域です。この領域は32kバイトの容量がありますが、1ワードが2バイトの構成になっているので、ワードアドレスとしては16kまでの範囲です。

▼フラッシュ プログラム メモリー領域
出力例4

 アドレスは0x0000から0x3FFFまでの16kワードの範囲です。上の画像は先頭部分で、データーはこのまま10ページ以上続きます。

 なお、この領域をバイト単位で表現することもあるようで、上記のプログラムの pgm_read_byte() 関数はバイトアドレスでアクセスしています。でも話がややこしくなるので、ここではワード単位の表現に変換しています。

 2バイトで1ワードを構成する時のバイトオーダーは、AVR の作法に合わせて、リトルエンディアンにしています。こうするとマシン語が読み易くなります。一方でアスキー文字が読み難くなりますが、まあこれは仕方ないでしょう。

 ダンプリストを見ると、先頭アドレス付近にリセットや割込み処理へのジャンプルーチンがまとめて置かれていることがよく判ります。ちなみに、先頭の、0x940C, 0x0035 というのは、リセットがかかったら0x0035番地へジャンプというマシン語だと思います。

 フラッシュメモリの領域は、過去に書かれたプログラムの痕跡ががそのまま残っているため、どこまでが今回書き込んだプログラムの範囲なのかは、はっきりとは判りません。

 フラッシュメモリ領域の末尾にブートローダーが書かれているはずなのですが、残念ながら今回作ったプログラムでは内容を見ることが出来ませんでした。たぶん、何かのおまじないが必要なんでしょう。

◆まとめ
 ダンプ結果を見ると、CPU の内部構造が良く判ります。マイコンのアーキの勉強をやりたい人には、良い教材になると思います。なお、このプログラムは Arduino の IDE と UNOが動いていれば他に何も無くても動きます。

 実は最初は、IO レジスタの範囲だけをダンプするプログラムを作ろうと持っていました。でも、「池の水ぜんぶ抜く」のコピーが気に入ったので、全メモリー領域の情報を抜くことにしました。

 実はヒューズビットとシグネチャの情報もダンプしたかったのですが、今回はそこまで手が回りませんでした。ただ、例えば Arduino UNO で動いているということは、ヒューズやシグネチャの値ははぼ決まるはず、というか変な値になっていたら Arduino のIDE が動かないはずなので、これらを詳しくチェックしても、あまり意味が無いかも知れません。

 フラッシュの内容を逆アセンブルしてアセンブラに戻すと面白いかも知れません。でもそんなことはHEXファイルから遡った方が手っ取り早いですね。
カレンダー
05 | 2018/06 | 07
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード