16ビット拡張SFRの取り扱い
テクニカル・ノート 24209
アーキテクチャ:
AVR
コンポーネント:
compiler
更新日:
2018/08/08 5:22
はじめに
本テクニカルノートでは、AVRデバイスの特殊機能レジスタ(SFR)にアクセスする方法について説明します。
背景
AVRのマイクロコントローラでは、ますます多くのオンチップ周辺デバイスが実装されるようになってきているため、それらを扱うための特殊機能レジスタ(SFR)が増えてきています。AVRのオリジナルの命令セットでは、SFRにアクセスするための専用の命令が用意されていましたが、SFRはメモリマップでも見ることができました(アドレスは少し異なります)。
16ビットSFRの場合、正しくアクセスするにはしかるべき順序でアクセスする必要があります。コンパイラは、この点を理解しており、オリジナルのSRFエリアにあるSFRを専用のI/O命令を用いて扱う際、正しいバイト順序でアクセスできるように処理します。
オリジナルのSFRエリアの外にあるSFRは、拡張SFRと呼ばれ、通常のメモリマップド変数と同じようにアクセスする必要があります。コンパイラは、16ビットSFRに対するアクセス順序の制約が課せられていない通常の変数と同じ方法で16ビットSFRにアクセスします。そのため、残念ながら、コンパイラは自動的にアクセス順序の要件を満たすことができません。
提案
以下に、拡張SRFへ正しく16ビットアクセスするのに役立つマクロを示します。
#define __out_word(BaseName, value)\
{\
unsigned char _tH=(value) >> 8;\
unsigned char _tL=(value) & 0xFF;\
BaseName ## H = _tH;\
BaseName ## L = _tL;\
}
#define __out_word_atomic(BaseName, value)\
{\
unsigned char _t=__save_interrupt();\
__disable_interrupt();\
__out_word(BaseName,value);\
__restore_interrupt(_t);\
}
#define __in_word(BaseName, value)\
{ (value) = (BaseName ## L);\
(value) |= (unsigned short)BaseName ## H << 8;\
}
#define __in_word_atomic(BaseName, value)\
{\
unsigned char _t=__save_interrupt();\
__disable_interrupt();\
__in_word(BaseName, value);\
__restore_interrupt(_t);\
}
これは、例えば以下のように使用します。
#include <inavr.h>
#include <iom128.h>
void main ()
{
int value;
__in_word_atomic(TCNT3, value);
__out_word_atomic(OCR1C, value);
}
このマクロでは、SFRの名前に「L」と「H」が自動的に追加されるため、ユーザは、16ビットSFRのベース名だけ指定すれば済みます。
このマクロのアトミックバージョンでは、割り込みを無効にすることでアクセスが保護されています。割り込みがオフの状態でこのマクロが実行されることが分かっている場合、コード空間と実行時間を節約するために、同じ機能を実現している_atomicがついていないバージョンのマクロを使用しても構いません。
全ての製品名は、それぞれの所有者の商標または登録商標です。