GR-SAKURA
GR-KURUMI
GR-COTTON
GR-CITRUS
GR-PEACH
GR-KAEDE
GR-ADZUKI
GR-LYCHEE
GR-ROSE
GR-MANGO(*)
SNShield
Web Compiler
IDE for GR
TOPPERS関連
女子美コラボ
その他
※プロデューサミーティング中
作り方使い方資料
イベント関連
作品記事
体験記事
ライブラリ
ツール
その他・過去ファイル
setup時にrtc_set_time(&t);をスキップすれば、前回セットした時刻を元にRTCがカウントアップし続けている仕様だとの思っていたのですが、リセットして直ぐにrtc_get_time(&t);してみるとすべて0に初期化され、秒のカウントアップも始まらないようです。リセットボタンを押しても、前回セットした時刻に基づく現在時刻が得られるような方法はありませんか?
RTCのレジスタはリセットで初期化されるようです。すみません、EEPROMでに保存すればいいと思いましたが、EEPROMはまだ検証していませんでした。。とはいえ、いつ初期化をするかは課題としてありますね。
EEPROMを使うのは大袈裟すぎますね。GR-CARRYには電池が付いているのでRAMのデータは保持されると思うのですが、初期化されない変数を作る方法はないでしょうか?RTCの時刻情報を定期的にそちらにコピーしておいてリセット後のsetup時にrtc_set_time(&t);で再設定すればよいかと考えています(数秒はずれるでしょうが)。アセンブラを使わないと無理ですかね?第2案ですが、あきらめてスマホのアプリ側で時刻をBLE経由で送信して時刻再設定する方法です。サンプルプログラムを提供いただけるなら、それでもいいかなと思います。
maenoh!さん
RL78のRAMの細かい仕様がわからないのでもしかしたら値を保持しているかもしれませんが、リセット後には基本的には値不定となると考えた方がいいかと思います。(例えば、RAMへの書き込み中にリセットボタンが押されると、値がおかしくなる可能性もあるので)
リセットボタンを使われたい何か特別な理由があるのでしょうか?
例えばタッチセンサをリセット機能用スイッチ(RL78はリセットされないが、指定した初期化ルーチンを実行するようにプログラムしておく)といった使い方で代用できないでしょうか?
機器に組み込んでしまえば、リセットボタンを使うことはないので問題ないのですが、デバッグ時に時刻設定をやり直すのが面倒なので何かよい方法はないかと考えていました。RL78/G1Dのマニュアルを見ると確かにリセット後はデータ・メモリは不定と書かれていますので仕方ないですね。時刻再設定に関しては別の方法を考えてみることにします。Fujimotoさん、ありがとうございました。
「初期化されない変数を作る方法はないでしょうか?」
map出力を見てみて、セクションに割り当てられていない領域を探すとか、リンカースクリプトをちょっと書き換えるとかすれば、crtで初期化されない領域が作れる筈です。
そこへのアクセスはCソースで直接アドレスを指定すれば可能です。
@chobichanさん、ありがとうございます。アセンブラやリンカー等の知識がないので、今すぐには試せないのですが、可能性が残されているという点で非常にありがたいです。たぶん、データメモリも仕様上は不定ですが、保持されているはず。無保証の動作になりますが、裏ワザとしてはアリかなと思います。
GRカレーがどんな物か判りませんが、コンパイル時に出力されるメモリへの割付レポートであるmapでRAM上の使われていない領域を探し出して、アドレスにポインタ型のキャストするだけで普通に扱える様になります。
例えばルネサスの開発環境には必ず入っているiodefine.hですが、KURUMIのそれの一部を抜き出すと、ポート0の定義は以下の様になっています。
#define P0 (*(volatile union un_p0 *)0xFFF00)
型はunion un_p0ですが、byte単位で扱いたいならならbyte *、word単位ならword *でキャストすれば良いという事です。
volatileは要らないかな。
C言語では割と普通に使います。
EEPROM を使わないのであれば、現状のリンカスクリプトでは 0xfaf00~0xfaf8f は初期化されないので、たとえば下記のようなテストで
bool test(void) { const uint8_t deadbeef[] = {0xde, 0xed, 0xbe, 0xef}; for (unsigned i = 0xaf00; i <= 0xaf8f; i++) { if (*(volatile uint8_t*)i != deadbeef[i % sizeof(deadbeef)]) { for (unsigned j = 0xaf00; j <= 0xaf8f; j++) { *(volatile uint8_t*)j = deadbeef[j % sizeof(deadbeef)]; } return true; } } return false; }
true: 起動直後で RAM が未初期化
false: 起動直後でない
判定はできるんじゃないかと思います(未確認)。
> GRカレーがどんな物か判りませんが、
またインドか…。
GR-カレーを持ってないので KURUMI で確認してみましたが、
/*GR-KURUMI Sketch Template Version: V1.11*/ #include <Arduino.h> // Pin 22,23,24 are assigned to RGB LEDs. int led_red = 22; // LOW active int led_green = 23; // LOW active int led_blue = 24; // LOW active bool test(void) { const uint8_t deadbeef[] = {0xde, 0xed, 0xbe, 0xef}; for (unsigned i = 0xaf00; i <= 0xaf8f; i++) { if (*(volatile uint8_t*)i != deadbeef[i % sizeof(deadbeef)]) { for (unsigned j = 0xaf00; j <= 0xaf8f; j++) { *(volatile uint8_t*)j = deadbeef[j % sizeof(deadbeef)]; } return true; } } return false; } void setup() { int pin = test() ? led_red : led_green; pinMode(pin, OUTPUT); digitalWrite(pin, LOW); } void loop() { }
起動直後 → 赤 LED が点灯
RESET を押下 → 緑 LED が点灯
の動作は確認できました。
EEPROM を使用するのであれば、リンカスクリプト(gr_common/RLduino78/portable/e2studio/RL78/rl78_R5F100GJAFB.ld)の 82行目、
.data 0xfaf90 : { /* used for FDL(EEPROM) from 0xfaf00 to 0xfaf87*/
を変更すればおkです。例えば、
.data 0xfb000 : { /* used for FDL(EEPROM) from 0xfaf00 to 0xfaf87*/
と変更すれば、0xfaf88~0xfafff が初期化されず使用されない領域となります。
fujitaさん、ありがとうございます。時刻情報を初期化されないアドレスに格納しておいて、リセット直後にRTCに再設定することも可能になりそうですね。KURUMIでの作品作りでも役立ちそうです。正に裏ワザですね。
訂正です。
const uint8_t deadbeef[] = {0xde, 0xed, 0xbe, 0xef};
↑ は ↓ が正しい。
const uint8_t deadbeef[] = {0xde, 0xad, 0xbe, 0xef};
現状のリンカスクリプトでは EEPROM を使おうが使うまいが 0xfaf88~0xfaf8f は初期化されずに使用もされない領域なので、8バイトで足りる用途であればリンカスクリプトをいじる必要はありません。
RTCで必要なのは7バイトなので、ちょうど良かったです。GR-CARRYで0xfaf88~0xfaf8feを使って動作を確認できました。fujitaさん、ありがとうございました。
パワーオンリセットで RTC を設定、以降 RTC の内容が更新されるたびに初期化されない未使用領域の RAM に RTC の内容を記録し、リセット時にはその値で RTC を設定するスケッチの例。
/*GR-KURUMI Sketch Template Version: V1.11*/ #include <RLduino78.h> #include <RLduino78_RTC.h> #define latestTime ((RTC_TIMETYPE*)0xfaf00) #define validLatestTime *((int*)0xfaf20) void rtcConstantPeriodInterruptHandler(void) { int modifyLatestTime = (validLatestTime < 0) ? 0 : 1 - validLatestTime; rtc_get_time(&latestTime[modifyLatestTime]); validLatestTime = modifyLatestTime; } static const uint8_t deadbeef[] = {0xde, 0xad, 0xbe, 0xef}; bool isPowerOnReset(void) { for (unsigned i = 0xaf30; i < 0xaf8f; i++) { if (*(uint8_t*)i != deadbeef[i % sizeof(deadbeef)]) { return true; } } return false; } void releasePowerOnReset(void) { for (unsigned i = 0xaf30; i < 0xaf8f; i++) { *(uint8_t*)i = deadbeef[i % sizeof(deadbeef)]; } } void setup() { Serial.begin(9600); rtc_init(); if (isPowerOnReset() || validLatestTime < 0) { validLatestTime = -1; static /*const*/ RTC_TIMETYPE initTime = {97, 8, 29, RTC_WEEK_FRIDAY, 2, 14, 0}; rtc_set_time(&initTime); releasePowerOnReset(); } else { rtc_set_time(&latestTime[validLatestTime]); } rtc_attach_constant_period_interrupt_handler(rtcConstantPeriodInterruptHandler); rtc_set_constant_period_interrupt_time(RTC_CONSTANT_PERIOD_TIME_1SECOND); } void loop() { static RTC_TIMETYPE lastTime; RTC_TIMETYPE currentTime; noInterrupts(); rtc_get_time(¤tTime); interrupts(); if (memcmp(¤tTime, &lastTime, sizeof(RTC_TIMETYPE))) { char buf[100]; static const char dayOfWeek[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; sprintf(buf, "%4d/%2d/%2d(%s) %2d:%2d:%2d", currentTime.year + (currentTime.year >= 70 ? 1900 : 2000), currentTime.mon, currentTime.day, dayOfWeek[currentTime.weekday], currentTime.hour, currentTime.min, currentTime.second); Serial.println(buf); lastTime = currentTime; } }
fujitaさん、ありがとうございます。GR-CARRYでもそのまま動きました。リセットを押しても1秒程度しか遅れません。いいですね。KURUMIでも使えるので嬉しいです。