前回までは環境構築だけだったので、のんびりと概要から。
AT32AP7000のメモリ構成
NGWのCPUのAT32AP7000は内蔵Flashがありません。その代わり、NGWには一般的なCFIを持つNOR Flashを搭載しています。そんなわけで、基本的にプログラムはここに書き込みます。RAMは内蔵で32KB程度ありますが、基本的には外付けのSDRAMをアプリケーションが使うことが前提です。この手の内蔵RAMはCPUのディープスタンバイに入れたときに、最低限必要な情報だけいれておく場合や、特定の高速性が必要なコードを展開したいときに確実に1clock動作する場所として使うことが多いです。NGWの場合、この他にDataFlashというシリアルEEPROMを搭載しています。
NOR Flash 64MBit (Phy 00000000~)
SDRAM 256MBit (Phy 10000000~)
INRAM 256KBit (Phy 24000000~)
物理メモリ構成は、SH系に似ていて 0xa0000000~0xbfffffffまでが非キャッシュ領域、ミラーの0x80000000~0x9fffffffがキャッシュ領域です。基本的に初期設定や特定の特殊な処理をする時しか非キャッシュ領域では実行しません。例えば、DMAなどを使うとき、特定のポイントでキャッシュのデータをパージしたりライトバックしたりする場合などは、非キャッシュ領域で実行する必要があります。なお、MMUをEnableにすると0~0x7fffffffまでがTLBが聞くようになります。
リセット動作
AVR32はリセットがかかると0xA0000000にジャンプし、ここからコードが実行されます。AVR32-gccでは、crt0.sのスタートアップコードのエントリは.textセクションの先頭_stextですので、もしSDRAMをスタートアップ前にenableにするときは、リセット直後にそれようのコードを記述しておき、次に_stextへジャンプすれば、スタートアップコードに手を入れなくても対応できます。今回もそのような方法にて対応します。
スタートアップコードへ入るまでの初期化
今回はSDRAMの置き換えですので、PLLとSDRAMの初期化だけは最初に行っておきます。なお、これらはスタートアップ処理前ですから当然Cは使えませんので、全部この処理はアセンブラで書く必要があります。
さてAVR32のインストラクションですが、データシートをみてみるとわかりますが、8bit AVRと結構似てます。ただ、インストラクションが32ビット固定という関係上、結構無理な部分がありますが、16bit固定のSHよりはマシですw 注意なのは、AVR32では1ワード=32ビットということです。それに気がつかないで少々悩んだり・・・。まぁ、アーキテクチャ関連が書いてあるpdfには最初にしっかり書いてありますけどね。
<AVR32のインストラクションの一例>
st.w r0,r2 ; r2のデータを(r0)へ格納(32bit)
// 32bitのデータを設定するときはpc相対でメモリ上からロードするか、
// movとorhで2つにわけて設定
mov r0,0x4000 ; r0へ0x4000(21bit)を格納(bit21以上は0が入る)
orh r0,0xfff0 ; r0の上位16bitへ0xfff0をorする
// <注> インストラクション表には movhi という命令がありますが、AP7000では
// 使えません。これもavrではよくあること:)
// 加算処理
sub r0,-1 ; immな加算命令は伝統のごとくないので、-1を引きましょう。
PLLの初期化
NGWはOSC0に20MHz、OSC1に12MHzが繋がっています。OSC0がCPUなどのメインクロック用で、OSC1はぶっちゃけUSB用です(4てい倍して48MHzで使う)。AVR32では内部のブロックはCPU,HSB,PBA,PBBの4つの部分に分かれており、それぞれメインクロックでてい倍したクロックを分周して振り分けます。ただし、それぞれ動作上限のクロック周波数が異なりますので、設定時はそれを超えないようにしておかなければいけません。
CPU : MAX 150MHz
HSB : MAX 75MHz
PBA : MAX 37.5MHz
PBB : MAX 75MHz
取りあえず、PLLは6てい倍の120MHzで動作させることにしますので、CPUは120MHz、HSBは60MHz、PBAは30MHz、PBBは60MHzで動作させることにしましょう。なお、SDRAMコントローラはHSBのクロックで動作しますので、60MHz動作となります。本来はPLL1も動かして適切に割り当てるべきですが、取りあえずということで。
サンプルのPLLの初期化手順は以下の通りです。PLLは発振出力をループバックしたものを位相比較回路で元クロックと合わせますから、通常はてい倍率を変えたり、動作をONにしたあとは、切り替わるまで時間がかかります。切り替わって、周波数が安定している状態をLockされた状態と言いますが、その状態になるまで待機する必要があります。
1.PLLCTRL0の設定(6定倍、PLL動作許可、クロックソース=OSC0)
2.PLL0がロックするまで待機(ISRのLOCK0ビット)
3.CKSELでCPU,HSB.PBA,PBBの分周比を設定 (0x80818000をCKSELへ設定)
4.CKSELが反映されるまで待機(ISRのCKRDYビット)
5.MCCTRLをPLLへ切り替え
<SDRAMのCLK(HSB)の波形>
TDS3014(fc=100MHz)で見てるので、へろへろになってますが周波数は合ってますw
NORフラッシュのアクセスタイミングの再設定
さて、実は上記の設定をいきなりやると暴走してふっとびますw なぜかというと、AP7000の場合プログラムは外部のフラッシュROMに格納されますが、このクロックにもHSBのクロックを使っており、この周波数を上げることで、ROMのアクセスタイミング規定を守れなくなるからです。そうなるとプログラムコードをフェッチするためにROMからコードを読み出すときにデータ化けが発生して、正常な命令を読み出せなくなるからです。
NGWに載っているNORフラッシュはtRC=70nsのアクセスタイミングです。このNORフラッシュをAVR32はリセット時は4clk cycleでアクセスします。ブート時は20MHz(1Clk=50ns)動作ですから200nsまでのROMであれば十分に動作します。
ところがPLLを起動して、バスクロックを上記の60MHz動作にすると、計算上16.666*4=66.66nsとなりますので間に合いません。またセットアップ時間がリセット時は1clkですが、こちらも16.66nsとなりフラッシュROMのtDFが25nsであることを考えると、かなり危ないです。
そんなわけで、PLLを切り替える前にサイクルを各1clk分引き延ばします。これにより、十分タイミングに間に合うようになります。
このようなタイミング設定をするのがSMCという(Static Memory Control)部分ですが、設定が結構細かくできます。ただ、設定方法は注意が必要です。基本的には以下のパラメータとなります。↓はデータシートからコピペ。
NRD_CYCLE = NRD_SETUP + NRD_PULSE + NRD_HOLD
実際に設定するのはCYCLEとSETUPとPULSEで、HOLDはAVR32内部で勝手に決まります。例えば今回のようにサイクルを広げる場合、必ずCYCLEを先に設定しておく必要があります。そうしないと、SETUPやPULSE値を書き込んでも上記の式を超える値を設定しても反映されないからです。ちなみにレジスタの順番はSETUP、PULSE、CYCLEの順に並んでいますから、いかにも間違えてくれとも言わんばかりの順番だったりします・・・orz
長くなってきたので、SDRAMの設定は次に。
主にドールや電子工作関連を中心にしたブログです。