Category avr.

PROGMEM をつけると (const も必須)、その変数の示す先がプログラムメモリー領域になる。そのままだと使えないのでワーキングメモリ (SRAM) にコピーする必要がある、という話。大きい定数は SRAM に置けないので、基本的にプログラムメモリ (フラッシュメモリ) 上に置いて、必要なときだけコピーするようにする。

avr/pgmspace.h に byte やら word を読み出す関数は提供されているけど、long はない。どうするのが正しいのかなあと思ったけどよくわからなかった。

結局以下のように memcopy でうまくいった。

const uint32_t MORSE_CODES[] PROGMEM = {
    ...
};

uint32_t current_sign;
memcpy_P(¤t_sign, &MORSE_CODES[character], 4); 


progmem 調べていると prog_ が prefix された型を使え、って書いてあるのがよく検索ででてくるけど、それは obsolete で、使うとエラーになる。ヘッダを読んだほうが良い。const と PROGMEM をつけるのが正しい。

しかしヘッダ見ると far とか near とかよくわかんない関数がいっぱいあって混乱する。far は 64KB 以上のフラッシュがあるデバイスしか関係ないっぽいので気にしないほうがいいっぽい。つまり near_ だけ使っていれば良い (実際、 near も far もついていない関数は near のエイリアスになっている)

ヘッダファイルの冒頭部分の一部を訳してみた。

\note If possible, put your constant tables in the lower 64 KB and use
pgm_read_byte_near() or pgm_read_word_near() instead of
pgm_read_byte_far() or pgm_read_word_far() since it is more efficient that
way, and you can still use the upper 64K for executable code.
All functions that are suffixed with a \c _P \e require their
arguments to be in the lower 64 KB of the flash ROM, as they do
not use ELPM instructions. This is normally not a big concern as
the linker setup arranges any program space constants declared
using the macros from this header file so they are placed right after
the interrupt vectors, and in front of any executable code. However,
it can become a problem if there are too many of these constants, or
for bootloaders on devices with more than 64 KB of ROM.
All these functions will not work in that situation.

可能なら、定数テーブルは 64KB 以下に配置し、pgm_read_byte_far() や pgm_read_word_far() の代わりに pgm_read_byte_near() や pgm_read_word_near() を使ったほうが効率が良いし、なおかつ 64KB 以上は実行コードに使える。

プリフィックスに _P がついている全ての関数はELPM 命令を使わず、フラッシュROMの64KB 以下を引数にとる。これは大抵の場合、このヘッダファイルのマクロを使って定義されたプログラムスペース定数はリンカーが割込みベクターのすぐ後に配置するので、気にすることはない。

しかしながら、もしこのような定数が多すぎる場合や、デバイス上のブートローダーが 64KB 以上の場合問題をひきおこすかもしれない。これらの関数はこのような状況では一切動かないだろう。

  1. トップ
  2. avr
  3. AVR progmem に long を置く方法
  1. トップ
  2. arduino
  3. AVR progmem に long を置く方法

関連エントリー

なんかいろいろあって??ってなるので特徴を覚え書き。線は信号に関係するものだけ (普通は +VDD が必要)

名前 特徴 速度 備考
1-wire SIGNAL, GND 半二重 1対多 非同期 標準 15.4kbps, オーバードライブ125kbps SIGNAL が VDD を兼ねるので本当に2本だけでOK センサーとかで採用例がある。MAXIM の日本語スライド
I2C SDA, SCL, GND 半二重 多対多 同期 ロースピード 10kbps 標準 100kbps ファーストモード 400kbps 高速モード 3.4Mbps バス中のデバイスのどれでもマスターになれる。マイコンだと400kbpsまでが多い?ここに上げた中では唯一多対多のバスを作れる
SPI SCK, MISO, MOSI, SS, GND 全二重 1対多 同期 クロック依存最大 1Mbps〜2Mbps マスターはスレーブの数だけ SS が必要。1対1 なら SS は必要ない。
RS232 RxD, TxD, GND 全二重 1対1 非同期 9600bps などいろいろ PC でもよく使われていたインターフェイス。今でも USB 変換ケーブルは簡単に手に入る。フロー制御とかしないなら3本で使える
USB1.0 D+, D-, GND 半二重 1対多 非同期 1.5Mbsp, 12Mbps 使うの面倒。USB2.0 は高速化版、USB3.0 はさらに高速化して全二重に

AVR では

  • SPI はほぼどの AVR でも使える
  • I2C は AVR によっては専用ハード (TWI) が用意されてる。専用ハードでなくても USI があれば TWI をハンドリングできる (多少面倒だけどライブラリとして公開している人はいる)。
  • RS232 はロジックレベルをドライバ (MAX232系の) で変換すれば USART で直接扱えるので簡単。
  • USB は一部の AVR で組込み。V-USB を使えばソフトウェアだけでもいける。あるいは USB Serial 変換チップ (FTDIのが有名でクロスプラットフォーム) を使えば USART 経由で使える。変換チップ使うのが確実で汎用性があってよく使われていそう。

略語がいっぱい

  • UART (Universal Asynchronous Receiver Transmitter) は非同期なシリアルを扱う回路の名前。同期なのを統合したものを USART (Universal Synchronous Asynchronous Receiver Transmitter) というらしい
  • TWI (Two Wire Interface) はその名の通り2線式ってことなんだけど、AVR においては普通は I2Cのことを指しているっぽい。I2Cと名乗ってないのはなんか政治的な問題?
  1. トップ
  2. avr
  3. マイコン周りのシリアル通信プロトコルまとめ
  1. トップ
  2. tech
  3. マイコン周りのシリアル通信プロトコルまとめ
  1. トップ
  2. arduino
  3. マイコン周りのシリアル通信プロトコルまとめ

そういえばマイコンからカメラのレリーズができたらいいかもなーとなんとなく考えたのでやってみた。タイムラプス的なもの (インターバル撮影) とか、バルブとか自分で制御できたら楽しいかもしれない。

リモートレリーズ端子

リモートレリーズ端子 (有線) にはいくつか種類があるらしく、キヤノンの場合、Kiss とかではステレオミニと同じだけど、5Dとか7Dとかだと、N3型端子とかいう謎の端子になる。N3端子ってのはそこらへんで単体で簡単に手に入らないので、既存のを買って切るしかないっぽい。機能的には同じみたいだけど、なんでこんなことになってるのか謎

手元にあるのはN3型のものなので、別にレリーズ別途買ってまで試すまでのモチベーションはわかなかったので、とりあえずリモートレリーズ端子を使うのは諦めた。(ただのスイッチなので難しいことはなさそう)

赤外線リモコンのレリーズ

他にレリーズを切る方法としては、赤外線リモコンを使うほうほうがあって、これなら赤外線 LED チカらせるだけでよく、端子とか関係ないのでお手軽そうだった。赤外線は昔昔買ったLEDジャンク詰め合せに無駄にいっぱい入っていて腐っている。

ググるとリモコンの解析結果を公開している人がいるので、その通りやったらいけた。

あたり前だけどドライブモードをリモコンのモードにしないとシャッター切れない。解析結果をそのままコードにしただけだけど (PB0 に LED が接続されている前提)

void shutter () {
	int i;

	for (i = 0; i < 23; i++)  {
		set_bit(PORTB, PB0);
		_delay_us(13);
		clear_bit(PORTB, PB0);
		_delay_us(13);
	}
	_delay_us(7200);
	for (i = 0; i < 23; i++)  {
		set_bit(PORTB, PB0);
		_delay_us(13);
		clear_bit(PORTB, PB0);
		_delay_us(13);
	}
}

ただ、赤外線の場合、設定済みの露出でしかシャッターを切れないので、バルブとかはできない。インターバル撮影とか、センサー連動のシャッターとかはこれで十分できそう。花火の撮影とか自動化できそう。

  1. トップ
  2. avr
  3. キヤノンのカメラのリモートレリーズ (またはリモコンレリーズ)
  1. トップ
  2. tech
  3. キヤノンのカメラのリモートレリーズ (またはリモコンレリーズ)
  1. トップ
  2. arduino
  3. キヤノンのカメラのリモートレリーズ (またはリモコンレリーズ)

関連エントリー