1
MSP430 FR5739 LPM3.5 を RTC アラームで wake-up するデモシステム(Example2) -その2- LPM3.5 省電力モードを RTC アラームで wake-up して、ADC10 温度測定をするデモシステム2
Rev02 July.8.2013 Trout(ニックネーム)
1 概要とポイント デモシステム2は、LPM4 利用のデモシステム1を LPM3.5 に置き換えたバージョンです。 LPM3.5 はコア部分の 給電が停止しますので、LPM4 よりも省電力になります。 ただし RTC は継続動作していますので、wake-up した後 もカレンダは更新されています。 また、LPM3.5 では RAM 領域は内容が消えてしまいますが、FRAM 領域は不揮 発ですので、FRAM 上に設けた変数は保持できます。 RTC アラーム機能を使い5分間隔で wake-up して、温度測定をしてから LPM3.5で wait します。
Wake-up して active 中に、内蔵の温度センサーから ADC10B を使用して、10 秒間隔*6data を測定して最大 値、最小値、平均値の温度(℃)を計算し、その結果を PC の Tera-Term に表示します。
この active 中は、LED8 が1秒間隔で点滅します。
FRAM の不揮発メモリの性質(Power-off でも内容保持)を、アプリケーションでは下記2点に利用しています。 ① 測定期間中の最大、最小温度を FRAM へ記録
② TLV の温度補正係数を、初期スタート時に読み込み FRAM に記録
LPM3.5wait 中に EXP430FR5739 ボードの Reset(RST)スイッチを押した場合は、wake-up 後に SWBOR を発生し て初期スタートするようにしてあります。 (通常、RST は単なる LPM3.5 wake-up BOR イベントとなります) ペリフェラルの driver は、LPM3.5 サポート用に Example1から一部を修正しました。 (RTC,Clock)
2 デモシステムの操作 1) 必要なもの MSP-EXP430FR5739 ボード、CCSv5.3/v5.4、PC:Tera-Term 2) Project の移植 添付の FR5739_RTC_LPM35.zip を解凍して FR5739_RTC_LPM35 プロジェクトを新規 workspace にインポー ト(copy 指定)します。 必ずインポートを使い移植します。 Build してエラーがないことを確認します。 3) 操作手順 ボードと PC を、ボード付属の USB ケーブルで接続します。 Tera-Term は終了させます。
CCSv5 で project をボードに load して、main 先頭で止まったら、そのまま■Terminate します。 注 1 一旦 USB ケーブルを抜いて、ボード電源オフします。 10秒ぐらい時間を空けてから、再接続します。注 2
FR5739 は初期スタートして、LPM3.5 で wait になります。
20 秒ぐらい時間を空けてから、Tera-Term を起動してシリアルポート UART(Virtual-COM)に接続します。 (COM 番号は変化します。)
注1: CCSv5を terminate しないと、JTAG 信号が active なので LPM3.5 に入りません。 注 2: 一旦ボード電源オフしないと、LPM3.5 から wake-up しません。
2
ボードの赤 reset スイッチを押すと、SWBOR により初期起動され Tera-Term に表示されます。 表示が出ないときは、Tera-Term を再起動して、もう一度 reset スイッチを押します。
すぐに年(月日時)変わりが確認できるように RTC は設定されています。
5分間隔で RTC alarm イベントが起きて active になり、LED8 が 1 秒間隔で点滅開始します。 毎正時には、測定期間中の MAX、MIN 温度を表示します。
RTC_alarm と表示して、6data*10s 間隔=約 50 秒間を温度測定します、この間は LED7 が点灯します。 測定完了すると、温度計算してから Tera-Term に max, min, ave の温度測定結果を表示します。
LPM3.5 で wait します。 LPM3.5 wait 中 LED8 は消灯します。 5分後に RTC alarm で wake-up します。 4) 表示の説明 *1: RST スイッチにより wake-up すると表示されます。 RSTIV=8: LPM3.5 からの wake-up を示します。 この後、プログラムで SWBOR を発生して、システムを初期スタートさせます。 *2: RSTIV=6:SWBOR を示します。 初期スタートなので XT1 発振安定確認=123 サイクルかかっています。 *3: RTC alarm(毎5分間隔)で wake-up します。
RTCCTL=7:RTCIFG minute, alarm, ready が on していますが、RTC alarm だけが割り込み enable です。 XT1(RTC)は継続動作しているので、発振安定確認=0 サイクルです。
RTC alarm wake-up の後で、RTC から RTCRDYIFG の秒割り込みを使いカレンダを入力しているので 0 時 0 分 1 秒 となっています。
*4: RTC alarm 割込みマスクを enable にしたので、RTC alarm の割り込みが入りました。 このあと温度測定と計算をして max, min, ave を表示します。
*5: LPM3.5 wait に入ります。
3 補足 温度は確認のため小数点以下1桁まで表示していますが、ADC の1測定単位は 0.6~0.7℃程度ですので、± 1単位振れると max, min は 1.3℃ぐらいの開きが出ます。 小数点以下を四捨五入するのが適切と思います。 Tera-Term になにも表示されないときは、Tera-Term を何度か再起動・接続を繰り返してください。 4) 不揮発メモリの確認操作
LED7点灯中 ADC 測定しているときに FR5739 デバイスを手で触り温度を上昇させると温度 max が上昇し ます。 毎正時に測定期間中の MAX にこの温度が表示されます。 この MAX、MIN の data は FRAM に 保存されているので、LPM3.5 の core 給電 off でも不揮発で保存されます。 RAM だと消えます。
初期 start 時に TLV から読み込んだ温度補正計算用の data も、FRAM に保存していますので、LPM3.5 wake-up のあとも保存され、正しく温度計算がされます。
添付 project main_RTC_LPM3.5.c の下記 #pragma 部分をコメントアウトすると、上記の領域が RAM に 移ります。 これで build して動作させていただくと、MAX 値や温度計算が LPM3.5 の後ではおかしくなる のが分かります。 これは LPM3.5 の core 給電がオフするので RAM 内容が消えてしまうためです。 90 //#pragma DATA_SECTION ( SVdata,".infoA") ・・コメントアウト
91 struct St_SVdata SVdata;
3 プログラム構造 ヘッダ構造、主要な構造体、ドライバ(関数と ISR)について説明します。 各ペリフェラル(UCS、RTC、ADC など) の操作関数は各ヘッダにて定義されており、パラメータは構造体で受け渡しています。 最初に各ヘッダにある構 造体を参照していただくと、main のロジックが容易に理解できます。 3.1 Msub.h システム全体を定義するヘッダ Msub.h は各ドライバのヘッダを include しています。 その他に、システム定数を定義(define)しています。 これは Main とドライバが参照します。
#define TLV_ADC 0x1A1A ・・TLVにある温度補正の格納アドレス(ADC15T30、ADC15T85) #define DCO_MHz Dco_16MHz ・・DCO周波数を16MHzに指定、 Dco_16MHzはclock.hで定義 #define LPMX LPM4_bits ・・各ドライバ内部でwaitするLPMxモード
#define LPM_all LPM4_bits ・・各 ISR、ドライバ内部で wait 解除、active 復帰に使用
3.2 XT1 と DCO 制御
(1) Clock.h
DCO 周波数設定値と DCO レジスタ設定値の構造体を定義してあります。
#define Dco_16MHz 16 ・・DCO 設定周波数に対する数値を定義
使用例 delay(30*DCO_MHz) -> 30us wait #define Dco_16MHz_RG 0x0080 ・・DCO 周波数設定のレジスタ値-> CSCTL1 Struct Struct_Sclock ・・DCO 設定する構造体
4 int Set_XT1clk( int TimeOut );
・・DCO設定の前に呼びます。 XT1=32768Hz設定をして、数ms*TimeOut回数で発振を確認します。 正常発振が確認できないとエラー(-1)で戻ります。
void Off_XT1(void);
・・XT1OFFをonにします。 LPMx.5を使用するとき、wait前にcallします。 int Set_DCO( const struct Struct_Sclock* St_Sclk );
・・DCO周波数を設定します。未定義の周波数の場合は設定せずエラーで戻ります。
3.3 RTC 制御
(1) RTC.h
RTCの操作関数とRTC設定の構造体を定義しています。 RTCはバイナリモードで使います。
union U_caldr{ ・・カレンダをアプリ用と関数内部用16bitsで定義します。
struct St_RTC Sys_RTC; ・・アプリ用:年、月、日、時、分、秒でアクセスできます struct St_Caldr16 main_ca16; ・・関数内部用、レジスタ16bits表現
** 補足:MSP430はリトルエンデァンなのでSt_RTCの8bits表現では、メモリ先頭側に16bitsの下位8bitsが配置さ れます。 アクセスを間違わないようにunionとstructを組み合わせて、シンボルアクセスできるようにしています。 **デバッガのvariable表示画面で、decimalにして内容確認できます。
(2) RTC_driver.c RTC 制御ドライバ(関数と ISR)
システムカレンダ(RTC 入力エリア)格納領域は、不揮発メモリ(FRAM)の InfoA に割り当てています。 #pragma DATA_SECTION ( S_Ca16,".infoA")
struct St_Caldr16 S_Ca16;
void Get_HwRTC(union U_caldr* saveRTC);
・・reset後RTC hold中にRTCレジスタからカレンダを読み出しカレンダ保存メモリに記録します。 デバッグ用、LPM3.5 wake-upでは使用できません。
void Get_Scaldr(union U_caldr* caldr);
・・(RTCではなく!RTC_driver内部の)システムカレンダをユーザカレンダに読み出します。 void Get_ClipRTC(union U_caldr* caldr);
・・RTCRDY割込と同期して、RTCからカレンダを取り込み、システムカレンダとユーザカレンダに書きます。 void Set_RTC(const union U_caldr* caldr);
・・RTCに初期値をsetします。 RTCHOLDとなりRel_RTC()でRTCは動作開始します。Rev02修正 void Rel_RTChold(void);
・・RTCのHoldを解除して、動作させます。 Rev02追加 void Enable_RTC(const uint8_t En_bit, uint8_t Ifgclear);
・・RTC割り込みenableします。Ifgclear=0はRTCのIFGをクリアーします(LPM3.5用) Rev02修正 void clear_LOCKLPM5(void);
・・Enable_RTC(interrupt-enable+hold解除)の直後に呼びます。 これによりRTC内部で保持されていた 割り込み要因がレジスタに反映されます。 LPMx.5からwake-upしたケースでは必須です。
void Set_RTCalarm(struct St_Alarm* I_alarm);
・・RTCアラーム時刻を設定します。 本件では未使用ですが、X時Y分にwakeupする場合などに使えます。 void Renew_RTCalarm(int Plus_minute);
5
・・次のRTCアラーム分を設定します、本件では毎5分alarm(Plus_minute=5)を設定しています。 内部の設定計算: (現在のシステムカレンダの分/Plus_minute +1)* Plus_minute
uint8_t Read_RTCstatus();
・・現在のRTCイベント状態を読み出します。 デバッグ用です。 Rev02追加 uint8_t Check_RTCevent(uint8_t RTC_flag);
・・RTCイベント(アラーム、OSCフォルト、タイムイベント)の有無を通知します。
3.4 ADC制御
(1) ADCtemp_driver.h
温度測定(ADC10B、TimerA0、DMA0)の関数と、測定&記録を指定する構造体を定義しています。
struct Struct_temp ・・温度測定の条件を指定:間隔、測定回数、保存領域
struct St_SVdata ・・保存領域(FRAM):温度計算パラメータと統計処理用
変数シンボル(MAX,MIN,max,min,ave)でアクセスできます。 (1) ADCtemp_driver.c
int8_t Get_TLVtemp( const struct Struct_temp *St_temp );
・・TLVから温度測定キャリブレーションデータを取り込み、struct St_SVdataに保存します。 TLV内容がないと、return !=0 で戻ります。
void ADC_start( const struct Struct_temp *St_temp );
・・ADC10を使い温度センサーからデータを(指定の回数・間隔)取り込み、指定バッファに格納します。 void Calc_temp( const struct Struct_temp *St_temp );
・・指定バッファのデータを温度換算して max,min,ave と MAX,MIN を求め、St_SVdata に格納します。
3.5 UART 制御
デバッグ用に Tera-Term に各種情報を表示します。 表示情報は sprintf()の桁指定なしで編集しています。 実際のシステムデバッグ補助としても利用ができます。
(1) UART_driver.h
UART経由でPCに表示する関数とその構造体を定義しています。
struct St_setUART ・・UART 設定用、SMCLK ベースに 9600bps,8N1 設定を定義
struct St_UART ・・UART 入出力用バッファを指定(アドレス、サイズ)
サイズチェックはしていないので、アプリケーション責任です。 (2) UART_driver.c
void UART_start( const struct St_setUART* setUART ); ・・UARTの設定をしてRedyにします。
void UART_stop( void );
・・UARTを停止して、disableにします。 出力中ならば完了まで待ち(loop)ます。 void UART_send_WAIT( const struct St_UART *sendUART );
・・UARTに出力します。 ストップコードは0x00です。 void UART_recv_WAIT( struct St_UART *recvUART );
6 3.6 IO 関数の留意事項 ・ 温度測定のADC_start は、測定完了(DMA 完了)を LPM4 で待ち合わせます。 ・ RTC 時刻読み込みの Get_ClipRTC は RTCRDY を LPM4 で待ち合わせます。 ・ 特に ADC_start 処理中の LPM4wait を他の割り込みが解除すると正しい測定結果が得られません。 4 main()の構造 4.1 定数と変数 1) UART
・#define UART_dump ・・UART 経由で Tera-Term への表示を有効にします。
・setUART ・・SMCLK=1MHz で 9600bps にする設定値です。 SMCLK にあわせて変更が必要。
2) クロック
・St_Sclk ・・DCO 周波数設定は DCO_MHz <-Msub.h で定義 ACLK=XT1、MCLK=DCO,SMCLK=DC/8 3) RTC、カレンダ ・Caldr ・・ユーザカレンダ イベント発生時刻をシステムカレンダからコピーしてアプリケーションが利用します。 役割は、 システムカレンダはどんどん更新され、かつ RTC の更新と衝突するのを回避するためです。 ・Init_Caldr ・・初期設定するカレンダです。
・Enbit ・・active 中に RTC 割込 enable する bit を指定します。LED8 点滅に利用。 ・Enbit_35 ・・LPM3.5 wait から wake-up のため RTC alarm、OSC-fault を enable にします。
4) ADC
・SVdata ・・InfoA(FRAM)に保存する温度補正データや MAX,MIN データの領域です。 ・ADCbuf ・・ADC の入力データ格納領域です。 ・St_temp ・・ADC 測定の間隔(秒)と上記データ領域を指定します。 4.2 main の処理 詳細は、ソースコードを見てください。 ポイントのみ説明します。 1) LED ・LED8 ・・start、wake-up 時に3回点滅します。 active 中の温度測定期間中は1秒間隔で点滅します。 LPM3.5wait では点滅しません。 ・LED7 ・・ADC 測定中に点灯します。
7 2) 初期スタートと LPM3.5 wake-up BOR での初期設定
・TLV データは、初期スタート時に FRAM に格納します。 wake-up の時は FRAM 内容を使います。 ・XT1 の設定と発振確認、数 ms*N(max200)回チェックして OK なら N を戻します、NG は-1 が戻ります。 ・DCO を設定します。 ・XT1、DCO がエラーの場合は、そこで loop します。 3) Reset 要因に対応した RTC 設定 ・RSTIV=8(wake-up BOR) ・・RTC を継続利用します。 RST 起動の時は、SWBOR を発生して初期スタートします。 ・それ以外 ・・初期スタートとして、カレンダ(Init_Caldr)で RTC 初期設定します。 4) RTC 割込のチェック ・RTC の現在カレンダをユーザカレンダに取り込みます。 ・RTC アラームのとき 00 分 ・・ユーザカレンダ(年月日時分秒)を表示、現在までの温度 MAX、MIN を表示。 毎 5 分 ・・RTC alarm 時分を表示してから、ADC を動作させ 10s 間隔*6data で測定します。
測定後に max, min, ave を計算して表示し、次の RTC alarm を設定(毎 5 分間隔)します。 ・RTC フォルトのとき
・・RTC_fault と表示して動作は継続します。
5) LPM3.5 で wait
・PIO を初期状態(入力、pull-down)、XT1 を off、
RTC alarm、発振 fault の割り込み許可して LPM3.5 で wait します。
6) デモシステムの補足
・デバッグ用にレジスタ内容を確認するため、冗長部分がかなり多くなっています。 流用する場合は、必要な main 部分と IO 関数を切り出してください。
・LPM3.5 wait に入るとき、PIO 機能は止めています。
PIO 割り込み(wake-up)を使用する場合は、main 末尾の reset_PIO()の修正が必要です。
5 Tips(情報) 1) CCSv5 の設定 下記の2)を除き、CCSv5 の初期設定のままで、build しています。 2) CCSv5 の変数初期化を止める方法 自分で生成したプロジェクトに移植する場合は、リンカー起動 option として –zero_init=off と追加する必要 があります。 これをしないと、変数は(たとえ FRAM に置いても)0クリアーされます。 具体的な設定方法は、該当 project について下記操作をして
Properties->Build->MSP430 Linker ->Summary of Flags set-> Set Additional Flags 表示されたウインドウに –zero_init=off を書き込んで OK で設定できます。
8
初期値なしの全ての変数が初期化されなくなりますので、初期化必要な変数は初期値を指定する必要があ ることに留意してください。
3) 固定値
固定値は const 宣言することで、.const section(FRAM)に配置され RAM を使いません。 これにより RAM の 節約と初期化時間短縮ができます。
4) 温度換算計算式
27~28℃程度の室温を測定する場合、ユーザガイド SLAU272B 1.14.3.3 Temperature Sensor Calibration の式の(ADCraw – ADC15T30) この差分がかなり小さくなるので 計算精度を上げるために ADC15T85 を起 点にするように計算式を変形しています。 ADCtemp_driver.c の Calc_temp()を見てください。
5) FRAM 保存領域の変更
このデモシステムでは、FRAM の InfoA 領域に保存データを設けましたが、FRAM の main memory 領域に設 けることもできます。 具体的な変更例は下記です。
① 変数領域を main の FRAM:read・write group に追加します。 下記の Sdata です GROUP(READ_WRITE_MEMORY): ALIGN(0x0200) RUN_START(fram_rw_start)
{
Sdata : {} /* save data area */ 追加 .cio : {} /* C I/O BUFFER */ .sysmem : {} /* DYNAMIC MEMORY ALLOCATION AREA */
}
② データを保存する FRAM 領域を Sdata と指定します。
#pragma DATA_SECTION ( SVdata,"Sdata") 指定変更 //#pragma DATA_SECTION ( SVdata,".infoA")
struct St_SVdata SVdata;
ただし、program load 時に CCSv5 が main memory 領域を erase しますので、その時に 0xFF で初期化され ます。