3 DSのリアルタイムクロックに関する質問


最近のプロジェクトではちょうど取得時間が必要で、ちょうどDS内部にハードウェアクロックがあり、標準ライブラリのtime関連関数に統合されており、devkitproが持参したexampleではこのような取得時間のプレゼンテーションが行われています.OpenGLの表示クロックのデモがありますが、テストの結果、この時計は行かないのではなく、time関数を初めて呼び出して1回の時間を取得した後、以降何回呼び出しても同じ結果が得られることがわかりました.
テストを容易にするために、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されていなければいいと言っています.これは危険ですが、組み込みプログラムはハードウェアのアーキテクチャを理解している限り、すべてのリソースを自由に使用することができ、カーネル開発のように、オペレーティングシステムの保護下で慣性的な思考で自分を制限する必要はありません.