ポケモンシリーズなどに存在する時計機能。この仕組みはどうなっているのだろうかとふと疑問に思ったことはないでしょうか。基板にはRTCと呼ばれるチップが別途乗っていて、さらにボタン電池も内蔵しています。GBA本体の電源を落としたり、カードリッジを素の状態でおいたままでもボタン電池に残量がある限り動き続けるという仕組みです。ここではもう少し踏む混んで時計を読み込んで表示したり、書き込んだりする方法を解説します。
まずはGBATEK、チップのデータシートそれぞれ覗いてみることです。
GBA Cart I/O Port (GPIO) 4bit General Purpose I/O Port (GPIO) - contained in the ROM-chip The I/O registers are mapped to a 6-byte region in the ROM-area at 80000C4h, the 6-byte region should be zero-filled in the ROM-image. In Boktai, the size of the zero-filled region is 0E0h bytes - that probably due to an incorrect definition (the additional bytes do not contain any extra ports, nor mirrors of the ports in the 6-byte region). Observe that ROM-bus writes are limited to 16bit/32bit access (STRB opcodes are ignored; that, only in DS mode?). 80000C4h - I/O Port Data (selectable W or R/W) bit0-3 Data Bits 0..3 (0=Low, 1=High) bit4-15 not used (0) 80000C6h - I/O Port Direction (for above Data Port) (selectable W or R/W) bit0-3 Direction for Data Port Bits 0..3 (0=In, 1=Out) bit4-15 not used (0) 80000C8h - I/O Port Control (selectable W or R/W) bit0 Register 80000C4h..80000C8h Control (0=Write-Only, 1=Read/Write) bit1-15 not used (0) In write-only mode, reads return 00h (or possible other data, if the rom contains non-zero data at that location). Connection Examples GPIO | Boktai | Wario Bit Pin | RTC SOL | GYR RBL -----------+---------+--------- 0 ROM.1 | SCK CLK | RES - 1 ROM.2 | SIO RST | CLK - 2 ROM.21 | CS - | DTA - 3 ROM.22 | - FLG | - MOT -----------+---------+--------- IRQ ROM.43 | IRQ - | - -
適当翻訳しますと、GPIOは80000C4hからの6バイト、0x00で書き込まれているということがわかります。また、ボクらの太陽の場合は0E0hで書き込まれているという蛇足情報もあります。表のConnection Examplesを読むと、GPIOピンはカードリッジ上の1,2,21,22で、RTCチップへの配線はSCK, SIO, CSに接続されている、ということがわかります。えーと・・・この辺りでおなかいっぱいになる方もいるかもしれません。考え方を変えましょう。たとえばraspberry piやArduinoでLEDチカチカしていた方ならピンとくると思いますが、結局この3本の線がそれぞれ3つのLEDに繋がっており、HIGH(ON), LOW(OFF)しているだけということです。点滅には一定のルールを設けて、それで時計を読んだり、書いたりしています。3本の線の名前をSCK, SIO, CSとしているので気負いする必要もありません。
S3511はセイコーインスツルメンツ株式会社が製作したリアルタイムクロックチップです。データシートが日本語で読めるというレアケースですので練習だと思って軽く全体を読んでみてください。さて、プログラマが必要なページは10ページ目からの動作説明です。このビット操作によって情報のやりとりを行います。1.1 通信データ構成、1.2 コマンド構成、1.3 データ読み出し、項目は一読してもらわないと先に進めません・・・。それらを理解したものが次の11ページ目の図です。
先の初期値をソースコードレベルで実装してみまます。まずはdefineを定義します。REG_RTC_DATAの下位3ビットがそれぞれCS, SIO, SCKです。0x3の場合はCS=0, IO=1, SCK=1となりCS=ON, SIO=OFF, SCK=OFF状態となります。
#define REG_RTC_DATA *(vu16*)(0x080000C4) // I/O Port Data(ビット配列 例: 0x3 : CS=0, SIO=1, SCK=1) #define REG_RTC_RW *(vu16*)(0x080000C6) // I/O Port Direction #define REG_RTC_ENABLE *(vu16*)(0x080000C8) // I/O Port Control (selectable W or R/W)
時計のステータスを読み出して時計がカードリッジ内に存在するかチェックをしてみましょう。けっこう混乱するので紙にかいて脳内トレースするのが良いと思います。結果、ステータスレジスタの24時間表示フラグをチェックできるまで進められればS3511は理解したも同然になります。
EWRAM_CODE void RtcInit(void) { REG_RTC_ENABLE = 0x1; // ステータスレジスタの24時間表示フラグをチェックします // Bit6 0:12時間、1:24時間 RtcOutCmd(0x63); bool isEnable = (RtcIn() & 0x40) ? TRUE : FALSE; } EWRAM_CODE void RtcOutCmd(u32 cmd) { REG_RTC_RW = 0x7; REG_RTC_DATA = 0x1; REG_RTC_DATA = 0x5; s32 i; cmd <<= 1; for(i=7; i>=0; i--) { REG_RTC_DATA = ((cmd >> i) & 0x2) | 0x4; REG_RTC_DATA = ((cmd >> i) & 0x2) | 0x5; } } EWRAM_CODE u32 RtcIn(void) { REG_RTC_RW = 0x5; s32 i; u32 ret = 0; for(i=0; i<8; i++) { REG_RTC_DATA = 0x4; REG_RTC_DATA = 0x5; ret |= ((REG_RTC_DATA & 0x2) >> 1) << i; } return ret; }
最後に時計読み込み、時計書き込みは・・・仕様書をペタペタ張るのも面倒ですしgithubのソースコードを読んでいけばわかると思います。なお、このコードはGBA SP+M3 MiniSDで動作確認済みです。エミュレータの場合は「Options -> Emulator -> Real Time Clock」をチェックすることで読み込み(現在時刻表示)のみできます。書き込みはどうも実装していないようでエラーになりました。