7. AVR メモリ

7.1 概要

 この節では、ATmega48/88/168の各メモリについて説明します。 AVRアーキテクチャには、データメモリとプログラムメモリという二つのメインメモリ空間が存在します。 さらに、ATmega48/88/168はEEPROMをデータ保存用に備えています。どのメモリ空間も、リニアで標準的な構造になっています。

7.2 ISPにより再プログラム可能なフラッシュ・プログラムメモリ

 ATmega48/88/168 には、ISPにより再プログラム可能な4/8/16Kバイトの内蔵フラッシュ・メモリが実行プログラム格納用に備わっています。 すべてのAVRの命令は16または32ビット幅であるため、フラッシュメモリは 2/4/8K x 16ビットになっています。 ソフトウェアのセキュリティのため、ATmega88とATmega168では、フラッシュメモリ空間がブートローダー領域とアプリケーション・プログラム領域に分割されています。 ATmega48では、ブートローダー領域とアプリケーション・プログラム領域が分割されておらず、SPM命令はフラッシュメモリ領域のどこでも実効可能です。 詳細については、"SPMCSR Store Program Memory Control and Status Register"(p.266, およびp.282)にあるSELFPRGENの説明をご覧ください。

 フラッシュメモリは10,000回以上の書き込み/消去サイクルが可能な耐久性をもっています。 ATmega48/88/168のプログラム・カウンタ(PC)は11/12/13ビット幅をもち、2/4/8Kのプログラム・メモリ・アドレスを指定することができます。 ブート・プログラム領域および、それに関連してソフトウェア・プロテクトのために用いるブート・ロック・ビットの詳細については「フラッシュ・メモリの自己プログラミング ATmega48」(p.261)、および「ブートローダーのサポート、読み書き並行自己プログラミング ATmega88/168」(p.268) を参照してください。 「メモリーのプログラミング」(p.284)にはSPI、またはパラレル・プログラミング・モードについての詳細な説明があります。

 プログラム・メモリ空間のアドレスには、どこにでも定数テーブルを配置しておくことができます(LPM ロード・プログラムメモリ命令の説明を参照してください)。

 命令フェッチと実行のタイミングについては、「命令の実行タイミング」(p.13)に説明があります。

Figure 7-1. プログラム領域のメモリマップ ATmega48
Figure 7-2. プログラム領域のメモリマップ ATmega88 および ATmega168

7.3 SRAM データメモリ

 Figure 7-3に、ATmega48/88/168 のSRAMメモリの構成を示します。

 ATmega48/88/168 はIN、OUT命令で指定できる64個以内のアドレスで対応可能な範囲よりも多くの周辺機能を持つ複雑なマイクロ・コントローラーです。SRAMの0x60 - 0xFFにある拡張I/O領域には、ST/STS/STD および LD/LDS/LDD 命令が使用できます。

 低位の768/1280/1280バイトのデータメモリ・アドレスには、レジスタ・ファイル、I/Oメモリアドレス、拡張I/Oメモリアドレス、および内蔵データRAMが含まれます。最初の32個のアドレス位置にはレジスタ・ファイルがあり、次に64個の標準I/Oメモリ、そして160個の拡張I/Oメモリ、そしてそれにつづく512/1024/1024個のアドレスに内蔵データSRAMが位置します。

 5つのアドレッシング・モードがデータ・メモリのアドレスを指定するために使用できます:絶対アドレス指定、ディスプレースメントつき間接指定、間接指定、プレ・デクリメントつき間接指定、ポスト・インクリメントつき間接指定です。レジスタ・ファイルのうち、R26からR31は間接アドレッシングのためのポインタレジスタとしての機能を備えています。

 直接指定では、データ・メモリ空間すべてを指定可能です。

 ディスプレースメントつき間接指定では、ベースアドレスYまたはZの位置から63個のアドレス位置を指定可能です。

 レジスタ間接アドレッシング・モードを自動プレ・デクリメントやポスト・インクリメントとともに使用すると、X、Y、およびZレジスタが増加または減少します。

 ATmega48/88/168の、32個の汎用レジスタ、64個のI/Oレジスタ、160個の拡張I/Oレジスタ、および、512/1024/1024バイトの内蔵データSRAMの各アドレスは、全てこれらのアドレッシング・モードによって指定することが出来ます。レジスタ・ファイルについての説明は、「汎用レジスタ・ファイル」(p.11)を参照してください。

Figure 7-3. データ・メモリのメモリマップ
データ・メモリ
32 レジスタ 0x000 - 0x001F
64 I/Oレジスタ 0x020 - 0x005F
160 拡張I/Oレジスタ 0x060 - 0x00FF
0x0100
内蔵SRAM
(512/1024/1024 x 8)
0x02FF/0x04FF/0x04FF

7.3.1 データ・メモリのアクセス時間

 この節では、内蔵メモリの一般的なアクセスタイミングについて説明します。内蔵データSRAMへのアクセスは、Figure 7-4にあるように、clkCPU 2クロック期間で実行されます。


Figure 7-4. 内蔵データSRAMアクセス・サイクル

7.4 EEPROM データ・メモリ

 ATmega48/88/168には、256/512/512バイトのEEPROMが搭載されています。分離されたデータ空間として構成されており、そこでは1バイトごとに読み出しと書き込みができます。EEPROMは100,000回以上の書き込み/消去サイクルの耐久性能があります。EEPROMとCPUのアクセスは、後述のように、EEPROMのアドレス・レジスタ、EEPROMのデータ・レジスタ、そして、EEPROMのコントロール・レジスタを指定する必要があります。

 「メモリーのプログラミング」(p.284)に、SPIまたはパラレル・プログラミング・モードによるEEPROMのプログラミングについての詳細があります。

7.4.1 EEPROM リード/ライト・アクセス

 EEPROMのアクセス・レジスタには、I/O空間からアクセス可能です。

 EEPROMのライト・アクセス時間はTable 7-2に記載されているとおりです。ただし、セルフ・タイミング機能により、ユーザー・ソフトウェアが次のバイト書き込みが可能になるタイミングを検出することが出来ます。ユーザー・プログラムがEPROMへの書き込みを行う命令を含んでいる場合、いくつか注意が必要な事項があります。供給電源に大きな定数のフィルタが接続されている場合、VCC端子の電圧は電力消費の増加/減少において、ゆっくりと立ち上がる、または立ち下がる傾向があります。この現象は、デバイスが、その動作クロック周波数において供給すべき最小電圧値を下回る時間帯を作る原因となります。このような状況における問題を回避する方法については、「EEPROMのデータ破壊を防止する」(p.19)を参照してください。

 意図しないEEPROMへの書き込みを防止するために、指定された手順にしたがって書き込みを行う必要があります。詳細は、EEPROMコントロール・レジスタの説明を参照してください。

 EEPROMを読み込む場合、CPUは次の命令を実行する前に4クロック停止します。EEPROMに書き込む場合、CPUは次の命令を実行する前に2クロック停止します。

7.4.2 EEPROMのデータ破壊を防止する

 VCCの電圧が低くなっている時間帯において、CPUとEEPROMの正常動作に必要な電圧が供給されていないと、EEPROMのデータが破壊される場合があります。この問題は、EEPROMを使用したボード上でおこるシステム・レベルの問題と同様のものであり、したがって、同様のソリューションにより解決することができます。

 EEPROMデータの破壊は、供給電圧が低い場合に生じる二つのケースで発生する可能性があります。一つは、定められたEEPROMへの書き込みシーケンスが正しく動作するための最低電圧を下回る場合です。そしてつぎに、CPU自体が供給電圧が低すぎて正しく動作しない場合です。

 EEPROMのデータ破壊は次のような推奨事項にしたがって設計を行うことで容易に回避できます。

 それは、十分な供給電圧がない時間帯において、確実にAVRのRESETをアクティブ状態(Low)にすることです。これは、内蔵のブラウン・アウト検出回路(BOD)を有効にすることで実現できます。内蔵BODの検出電圧レベルが必要とされるレベルに適合していない場合には、外部に低電圧リセット保護回路を使用することで実現できます。書き込み動作実行中にリセットが発生した場合でも、その書き込み動作は十分な供給電圧がある間に完了します。

7.5 I/Oメモリ

 ATmega48/88/168のI/O空間の定義内容は、「各レジスタについて」(p.342)に記載されています。

 ATmega48/88/168の入出力ポートおよび周辺回路は、全てI/O空間に配置されています。I/O空間の全アドレスに対して、LD/LDS/LDDおよびST/STS/STD命令でアクセスすることができ、32個の汎用レジスタとI/O空間との間でのデータのやりとりができます。

 0x00-0x1Fの範囲のアドレスのI/Oレジスタには、SBIおよびCBI命令を使って直接ビットアクセスを行うことが可能です。これらのレジスタでは、単一のビットの値をSBISおよびSBIC命令を使って調べることができます。詳細については、命令セットの節を参照してください。I/O固有の命令であるINおよびOUTは、I/Oアドレスの0x00-0x3Fに対してのみ使用できます。I/Oレジスタへのアドレス指定をLDおよびST命令を使用してデータ空間としてアクセスする場合、0x20をそのアドレスに加算する必要があります。ATmega48/88/168は、INおよびOUT命令のオペコードで指定できる64個のアドレスで対応可能な範囲よりも多くの周辺機能をもっている複雑なマイクロコントローラーです。SRAM領域上の0x60-0xFFアドレスを通して拡張I/O空間にアクセスするために、ST/STS/STDおよびLD/LDS/LDD命令を使用することができます。

 将来のデバイスとの互換性を保持するため、予約となっているビットにアクセスする場合はゼロを書き込んでください。予約となっているI/Oメモリアドレスには書き込みを行うべきではありません。

 ステータス・フラグには、論理値1を書き込むことによってクリアされるものがあります。他のほとんどのAVRと異なり、CBIおよびSBI命令は指定されたビットに対してのみ実行され、そのため、上記のようなステータス・フラグを含んでいるレジスタにおいて使用することが可能です。CBIおよびSBI命令は0x00から0x1Fのレジスタでのみ動作します。

 入出力ポートおよび周辺機能のコントロール・レジスタについては、後の各節において説明を記載します。

7.5.1 汎用I/Oレジスタ

 ATmega48/88/168には3つの汎用I/Oレジスタがあります。これらのレジスタには、どのような値でも格納することができ、特にグローバル変数やステータス・フラグを保存するのに便利です。0x00-0x1Fのアドレス範囲にある汎用I/Oレジスタには、SBI、CBI、SBIS、SBIC命令を使用して直接ビットアクセスすることが可能です。

7.6 各レジスタについて

7.6.1 EEARH および EEARL EEPROM アドレス・レジスタ

ビット 7 6 5 4 3 2 1 0
0x22(0x42) - - - - - - - EEAR8 EEARH
0x22(0x41) EEAR7 EEAR6 EEAR5 EEAR4 EEAR3 EEAR2 EEAR1 EEAR0 EEARL
7 6 5 4 3 2 1 0
Read/Write R R R R R R R R/W
R/W R/W R/W R/W R/W R/W R/W R/W
初期値 0 0 0 0 0 0 0 X
X X X X X X X X

7.6.2 EEDR EEPROM データ・レジスタ

ビット 7 6 5 4 3 2 1 0
0x20(0x40) MSB LSB EEDR
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
初期値 0 0 0 0 0 0 0 0

7.6.3 EECR EEPROM コントロール・レジスタ

ビット 7 6 5 4 3 2 1 0
0x1F(0x3F) - - EEPM1 EEPM0 EERIE EEMPE EEPE EERE EECR
Read/Write R R R/W R/W R/W R/W R/W R/W
初期値 0 0 X X 0 0 X 0

 EEPROMへのアクセス時間を計測するために、調整済み発振器が使用されます。Table 7-2 にCPUからEEPROMへのプログラミングに必要な通常値が記載されています。

Table 7-2. EEPROM プログラミング時間

記号 調整済みRC発振器のクロック数 プログラミング時間(Typ)
EEPROM write (from CPU) 26,368 3.3ms

 以下のプログラム例で、アセンブリ言語とC言語によるEEPROMの書き込みを例示します。この例では割込みは(例えば、グローバル割込み許可ビットにより)全て抑制されており、この関数を実行する期間では割込みが発生しないものと仮定しています。また、この例ではソフトウェアにはブートローダーによるフラッシュ書き込みは無い、という前提です。そういったコードが存在する場合には、EEPROMへの書き込み関数は、進行中のSPM命令が完了するまで待機する必要があります。

アセンブリ言語での例

 EEPROM_write:
	 ; 前回の書き込み動作が完了するまで待機
	 sbic EECR,EEPE
	 rjmp EEPROM_write
	 ; アドレス・レジスタに、アドレス値 (r18:r17) をセット
	 out EEARH, r18
	 out EEARL, r17
	 ; データ値 (r16) をデータ・レジスタに書き込み
	 out EEDR,r16
	 ; EEMPEに論理値1を書き込み
	 sbi EECR,EEMPE
	 ; EEPROM書き込み動作をEEPEをセットして開始する
	 sbi EECR,EEPE
	 ret
C言語での例

void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
	 /* 前回の書き込み動作が完了するまで待機 */
	 while(EECR & (1<<EEPE));
	 /* アドレスとデータレジスタを設定 */
	 EEAR = uiAddress;
	 EEDR = ucData;
	 /* EEMPEに論理値1を書き込み */
	 EECR |= (1<<EEMPE);
	 /* EEPROM書き込み動作をEEPEをセットして開始する */
	 EECR |= (1<<EEPE);
}

 次のプログラム例は、アセンブリ言語とC言語でのEEPROM読み出し関数の例を示しています。この例では、割込みは抑制されており、関数実行中に割込みが発生することはないものと仮定しています。

アセンブリ言語での例

EEPROM_read:
	; 前回の書き込み動作が完了するまで待つ
	sbic EECR,EEPE
	rjmp EEPROM_read
	; アドレス・レジスタに、アドレス値 (r18:r17) をセット
	out EEARH, r18
	out EEARL, r17
	; EEREをセットして、EEPROM読み出しを開始
	sbi EECR,EERE
	; データレジスタからデータを読み込む
	in r16,EEDR
	ret
C言語での例

unsigned char EEPROM_read(unsigned int uiAddress)
{
	/* 前回の書き込み動作が完了するまで待つ */
	while(EECR & (1<<EEPE));
	/* アドレス・レジスタをセット */
	EEAR = uiAddress;
	/* EEREをセットしてEEPROM読み出しを開始 */
	EECR |= (1<<EERE);
	/* データ・レジスタからの値を返値とする */
	return EEDR;
}

7.6.4 GPIOR2 汎用I/Oレジスタ 2

ビット 7 6 5 4 3 2 1 0
0x2B(0x4B) MSB LSB GPIOR2
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
初期値 0 0 0 0 0 0 0 0

7.6.5 GPIOR1 汎用I/Oレジスタ 1

ビット 7 6 5 4 3 2 1 0
0x2A(0x4A) MSB LSB GPIOR1
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
初期値 0 0 0 0 0 0 0 0

7.6.6 GPIOR0 汎用I/Oレジスタ 0

ビット 7 6 5 4 3 2 1 0
0x1E(0x3E) MSB LSB GPIOR0
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
初期値 0 0 0 0 0 0 0 0

目次に戻る