3 DSのリアルタイムクロックに関する質問
最近のプロジェクトではちょうど取得時間が必要で、ちょうどDS内部にハードウェアクロックがあり、標準ライブラリのtime関連関数に統合されており、devkitproが持参したexampleではこのような取得時間のプレゼンテーションが行われています.OpenGLの表示クロックのデモがありますが、テストの結果、この時計は行かないのではなく、time関数を初めて呼び出して1回の時間を取得した後、以降何回呼び出しても同じ結果が得られることがわかりました.
テストを容易にするために、exampleの例に従って変更されたハードウェアクロックを定期的に取得時間を呼び出し、画面に定期的に表示するプログラムを設定しました.プログラムは以下の通りです.
このプログラムは1秒ごとに表示時間を更新して、このプログラムは私のところで正常に運行することができなくて、それはずっと1つの固定的な時間を表示して、このプログラムがロードする時に取得した時間です.
そのため、私はもう一つの方法を使いました.自分のメンテナンス時間の変更です.プログラムをロードするとすぐに時間を取得し、ハードウェアクロックで秒コールバック時間で関数を更新し、手動で時間を更新するのは醜いが、必要な機能を実現した.
その後、私はわざわざこの方面の開発をした友达に聞いて、彼は彼が標準ライブラリの中で普通のtime関数を使って、DSLの中で正常に運行できることを確定しました.この時、私たち二人が使っているハードウェアが違うのか、3 DSが時間カウントを処理する上で異なるメカニズムがあるかもしれないと思い出した.そこで私はDSLを使ってこのプログラムを実行して、プログラムは正常に実行して、正確に時間の変化を表示することができます.
libndsのarm 9部分のヘッダファイルでは、取得するリアルタイムクロックに関する内容は見つからず、逆にarm 7ディレクトリでclockが見つかった.h、このような関数があります.
この関数はハードウェアクロックを更新するために用意されていることが説明できる.彼はバックグラウンドで何らかのメカニズムで時間を更新してIPCでarm 9端を共有し、arm 9端が必要とするときに正確な時間を得ることができる.
clock.cのこの関数は同期クロックの機能を実現し、resync関数は初期化クロックの中断時に1回呼び出された.
これが電源を入れたときに初めて取得した時間が正しい理由かもしれません.
system.cでは、この関数も一度登場したが、意外にもpowerValueHandler関数の原型は以下の通りである.
カバーを閉めた後、つまりシステムSleep後にこの時計が動作し始めたようです.しかし、私たちに必要なのは蓋を開けている間に時計の動作を維持することですが、DSLで正常に動作する理由は説明できません.
現在、正確な時間を取得できないのは時間が正確に更新されていないため、arm 7側で手動でこの関数を呼び出し、結果を0 x 02 fff 800の位置に保存し、データのフォーマットは7つのunsigned charで、内容はそれぞれ:年(後2桁)、月、日、時、分、秒である.
arm 9からデータを読み込み、画面に表示します.
DSLと3 DSでテストが正しく実行され、リアルタイムクロックの時間を取得できます.
後でその友達になぜ0 x 02 fff 800という数字を選んだのかと聞いた.何か特別なところがありますか.彼は、2つのCPUがアクセスでき、cacheされていなければいいと言っています.これは危険ですが、組み込みプログラムはハードウェアのアーキテクチャを理解している限り、すべてのリソースを自由に使用することができ、カーネル開発のように、オペレーティングシステムの保護下で慣性的な思考で自分を制限する必要はありません.
テストを容易にするために、exampleの例に従って変更されたハードウェアクロックを定期的に取得時間を呼び出し、画面に定期的に表示するプログラムを設定しました.プログラムは以下の通りです.
#include
#include
#include
const char* months[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
const char* weekDays[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
const u16 daysAtStartOfMonthLUT[12] =
{
0 %7, //januari 31
31 %7, //februari 28+1(leap year)
59 %7, //maart 31
90 %7, //april 30
120 %7, //mei 31
151 %7, //juni 30
181 %7, //juli 31
212 %7, //augustus 31
243 %7, //september 30
273 %7, //oktober 31
304 %7, //november 30
334 %7 //december 31
};
#define isLeapYear(year) (((year)%4) == 0)
uint getDayOfWeek(uint day, uint month, uint year)
{
//http://en.wikipedia.org/wiki/Calculating_the_day_of_the_week
day += 2*(3-((year/100)%4));
year %= 100;
day += year + (year/4);
day += daysAtStartOfMonthLUT[month] - (isLeapYear(year) && (month <= 1));
return day % 7;
}
void update_clock()
{
int hours, seconds, minutes, day, month, year;
time_t unixTime = time(NULL);
time(&unixTime);
struct tm* timeStruct = gmtime((const time_t *)&unixTime);
hours = timeStruct->tm_hour;
minutes = timeStruct->tm_min;
seconds = timeStruct->tm_sec;
day = timeStruct->tm_mday;
month = timeStruct->tm_mon;
year = timeStruct->tm_year +1900;
printf("\x1b[2J%02i:%02i:%02i", hours, minutes, seconds);
printf("
%s %s %i %i", weekDays[getDayOfWeek(day, month, year)], months[month], day, year);
}
int main(void)
{
timerStart(0, ClockDivider_1024, TIMER_FREQ_1024(1), update_clock);
consoleDemoInit(); //setup the sub screen for printing
while(1) {
swiWaitForVBlank();
}
return 0;
}
このプログラムは1秒ごとに表示時間を更新して、このプログラムは私のところで正常に運行することができなくて、それはずっと1つの固定的な時間を表示して、このプログラムがロードする時に取得した時間です.
そのため、私はもう一つの方法を使いました.自分のメンテナンス時間の変更です.プログラムをロードするとすぐに時間を取得し、ハードウェアクロックで秒コールバック時間で関数を更新し、手動で時間を更新するのは醜いが、必要な機能を実現した.
その後、私はわざわざこの方面の開発をした友达に聞いて、彼は彼が標準ライブラリの中で普通のtime関数を使って、DSLの中で正常に運行できることを確定しました.この時、私たち二人が使っているハードウェアが違うのか、3 DSが時間カウントを処理する上で異なるメカニズムがあるかもしれないと思い出した.そこで私はDSLを使ってこのプログラムを実行して、プログラムは正常に実行して、正確に時間の変化を表示することができます.
libndsのarm 9部分のヘッダファイルでは、取得するリアルタイムクロックに関する内容は見つからず、逆にarm 7ディレクトリでclockが見つかった.h、このような関数があります.
//---------------------------------------------------------------------------------
void rtcGetTimeAndDate(uint8 * time) {
//---------------------------------------------------------------------------------
uint8 command, status;
command = READ_TIME_AND_DATE;
rtcTransaction(&command, 1, time, 7);
command = READ_STATUS_REG1;
rtcTransaction(&command, 1, &status, 1);
if ( status & STATUS_24HRS ) {
time[4] &= 0x3f;
} else {
}
BCDToInteger(time,7);
}
この関数はハードウェアクロックを更新するために用意されていることが説明できる.彼はバックグラウンドで何らかのメカニズムで時間を更新してIPCでarm 9端を共有し、arm 9端が必要とするときに正確な時間を得ることができる.
//---------------------------------------------------------------------------------
void resyncClock() {
//---------------------------------------------------------------------------------
RTCtime dstime;
rtcGetTimeAndDate((uint8 *)&dstime);
__transferRegion()->unixTime = __mktime(&dstime);
}
clock.cのこの関数は同期クロックの機能を実現し、resync関数は初期化クロックの中断時に1回呼び出された.
//---------------------------------------------------------------------------------
void initClockIRQ() {
//---------------------------------------------------------------------------------
REG_RCNT = 0x8100;
irqSet(IRQ_NETWORK, syncRTC);
// Reset the clock if needed
rtcReset();
uint8 command[4];
command[0] = READ_STATUS_REG2;
rtcTransaction(command, 1, &command[1], 1);
command[0] = WRITE_STATUS_REG2;
command[1] = 0x41;
rtcTransaction(command, 2, 0, 0);
command[0] = WRITE_INT_REG1;
command[1] = 0x01;
rtcTransaction(command, 2, 0, 0);
command[0] = WRITE_INT_REG2;
command[1] = 0x00;
command[2] = 0x21;
command[3] = 0x35;
rtcTransaction(command, 4, 0, 0);
// Read all time settings on first start
resyncClock();
}
これが電源を入れたときに初めて取得した時間が正しい理由かもしれません.
system.cでは、この関数も一度登場したが、意外にもpowerValueHandler関数の原型は以下の通りである.
void powerValueHandler(u32 value, void* user_data)
カバーを閉めた後、つまりシステムSleep後にこの時計が動作し始めたようです.しかし、私たちに必要なのは蓋を開けている間に時計の動作を維持することですが、DSLで正常に動作する理由は説明できません.
現在、正確な時間を取得できないのは時間が正確に更新されていないため、arm 7側で手動でこの関数を呼び出し、結果を0 x 02 fff 800の位置に保存し、データのフォーマットは7つのunsigned charで、内容はそれぞれ:年(後2桁)、月、日、時、分、秒である.
// Keep the ARM7 mostly idle
while (!exitflag) {
if ( 0 == (REG_KEYINPUT & (KEY_SELECT | KEY_START | KEY_L | KEY_R))) {
exitflag = true;
}
rtcGetTimeAndDate((uint8 *)0x02fff800);
swiWaitForVBlank();
}
arm 9からデータを読み込み、画面に表示します.
#include
#include
void update_clock()
{
vu8* data = (vu8*)0x02fff800;
iprintf("%d %d %d %d %d %d %d
",data[0],data[1],data[2],data[3],data[4],data[5],data[6]);
}
int main(void)
{
timerStart(0, ClockDivider_1024, TIMER_FREQ_1024(1), update_clock);
consoleDemoInit(); //setup the sub screen for printing
while(1) {
swiWaitForVBlank();
}
return 0;
}
DSLと3 DSでテストが正しく実行され、リアルタイムクロックの時間を取得できます.
後でその友達になぜ0 x 02 fff 800という数字を選んだのかと聞いた.何か特別なところがありますか.彼は、2つのCPUがアクセスでき、cacheされていなければいいと言っています.これは危険ですが、組み込みプログラムはハードウェアのアーキテクチャを理解している限り、すべてのリソースを自由に使用することができ、カーネル開発のように、オペレーティングシステムの保護下で慣性的な思考で自分を制限する必要はありません.