MSP430 / eZ430-F2013
過去の活動収録 PART1
最新情報はこちら
進捗報告(2006年7月19日から9月9日分)
初めての完結プロジェクト( sample_0 project )
変更履歴
2006年9月10日 構成変更
2006年9月2,3,5,6,8,9日 追加
2006年8月19,20,22,26,29日 追加
2006年8月14日 新規作成
記述内容には、思い込みによる記述や十分な検証をしていない部分が存在する可能性があります。十分に注意してください。
誤り等ありましたら、ご指摘いただけると幸いです。
MSP430関連の開発を再開しました(2011年4月4日)
進捗報告(過去分)
9月9日
IAR Embedded Workbench にて、100%再現するハングアップを経験。ソースコードの大修正を実施している時には致命的な問題となる。
私の環境条件による私だけの問題なのか、IDEに内在する一般的な問題なのかは不明だが、作業する際には下記症状を確認してから作業を進めること提案する。同じ問題が発生する場合には、頻繁にセーブする癖をつけておかないと作業努力が水泡と帰する危険性大。
<症状>
------ セミコロンのみの空文行を作るとハングする ------
テキストエディターで下記の操作を実施する。
void abc_func ()
{
とキー入力し、
void abc_func ()
{
;
とセミコロンを打ち込みエンターキーを押すと、エディターが自動的に段下げを実施して、下記のようになる。
void abc_func ()
{
;
ここで、更にエンターキーを押すと下記画面が現れて、その後はOKを押すしかなくIDEが終了する。
別に上記条件だけでなく、空文行を挿入すると発生する模様。
<IDE環境>
IDE Version:
IAR Text Editor 4.6 (4.6.0.0)
2005/11/29 12:03:56, 413696 bytes
IAR Embedded Workbench IDE 4.6 (4.6.0.0)
2005/11/24 17:45:40, 741376 bytes
<PC>
Microsoft Windows XP Home Edition Version 2002 Sevice Pack 2
9月8日
ここで少しわき道に行くことに決定。
加速度センサーを使いこなす前に、今までの成果をひとつの形にしておきたい。
下記のコンセプトにて達成予定(あくまでも予定)。
基本コンセプト → sample_0 Project
1.HW
eZ430-F2013のTI出荷状態のままで動作すること
すなわち、HWに関しては何も変更しないで動作すること
2.SW
内蔵温度センサーの測定値をLEDにモールス信号として表示する
電源電圧の測定値をLEDにモールス信号として表示する
上記、2つのデータ表示を定期的に切り替える
ソフトウェアは、今までの成果と新規作成との組合せとする。
①温度、電圧の正規化ルーチン → 新規作成
②LED表示の切り替えルーチン → 現在のルーチンに追加修正
③初期化ルーチン → 現在のルーチンの修正
④RTMルーチン → 何も変更しないで動くと思うが・・・
で実施予定。週末の2日間で出来るのか?どの位の時間が確保出来るのか?
今までの内容は断片的な情報で、ソースコードをそのまま使用できる形で紹介していないが、出来ればダウンロードしてそのまま使用できる形を目指す。
9月6日
内蔵温度センサーの正規化を試みる。
値は、昨日の測定結果 adc_temp = 21446 (直ぐ下の9003ではなく、もうひとつ下)をベースとする。計算結果を下記に示す。
残念ながら、TCsenの値をMinからMaxまで変化させると、-4℃から59.8℃まで変化してしまう事になる。従って、補正をしなければ実用的利用は無理だろう。またオフセットだけでなく、感度(TCsen)が変わるので、2点の温度データで補正するしかない。
DCOの場合のように、補正値を持っていてくれればありがたいのだが、メーカーとして、そこまで行うには温度測定して補正値を計測しなければならず、手間と時間がかかる(何せ2点測定が必須と思われるため)ので採算が合わないのか? その点は、周波数測定の方が管理しやすいだろう。
昨日の室温は、およそ24.5℃+3℃、-0℃の間にあると思われる。ちなみに、ADCのオフセットを加味すると、
25.3℃
となる。ほとんどのチップが中心値付近にばらついていれば、そこそこ使えるのかな?
n増しして測定できるほどチップを持っていない。3個では統計的なコメントは無理だろう。
9月5日
悩みが尽きない。ADCデータが安定して測定できるようになったので、正規化(物理値への変換)を試み始めたが、どうも正規化データが実測値と合わない!
上記Debug画面で、Vccが8435の値になっているが、電源電圧との関係を説明できない。更に不思議なのが、オフセット電圧の値が-23764という数字になっている点である。
元々、2の16乗しかない変化幅の30%以上の値であり、オフセットというにはあまりにも大きな数値だ。
そこで、色々と初期設定を動かして見ると、ADC変換の回数を4回変換後の割込み発生とするSD16INTDLY_0とすると、オフセットの電圧が2桁の数字となった。どうも、それらしい値に近づいた感じである。
設定を改めて載せるとこの様になる。
// Main routine
void main( void )
{
/********** Hardware ******************************************************/
BCSCTL1 = CALBC1_8MHZ; // DCO set to 8MHz
// 省略
P1OUT = 0; // All P1.x reset
// Use for ADC from P1.0 to P1.5
// A2- A2+ A1- A1+ A0- A0+
SD16AE = SD16AE5 + SD16AE4 + SD16AE3 + SD16AE2 + SD16AE1 + SD16AE0;
// 1/16 1.2V ref on
SD16CTL = SD16XDIV_2 + SD16REFON;
// MCLK=8M -> No1 Div = 1/1,No2 Div=1/16 -> f=500KHz,OSR=1024
// Buf disabl Bip. 1024OSR Single conv. 2's comp.
SD16CCTL0 = SD16BUF_0 + 0 + SD16OSR_1024 + SD16SNGL + SD16DF;
// Interrupt Delay(none) Gain x1 channel 0
SD16INCTL0 = SD16INTDLY_0 + SD16GAIN_1 + SD16INCH_0;
// Continue next other steps まだ初期化は続きますが・・・・
電源電圧のADCデータとその正規化:
上記変更結果、変換データをWatchリストで見ると、下記のようになった。
adc_vccに17783(十進数)の値が読み取れる。ADCの電源電圧モニターは、
マニュアル(http://focus.ti.com/lit/ug/slau144b/slau144b.pdf)の391/409ページの記述から、
ADC入力電圧 = (電源電圧)/11
となる。Reference電圧が1.2Vである点を考慮するとデータ変換式は下記のようになる。
(電源電圧) = (ADC変換値) x 201.416 [μV]
従って、ADC変換値からの電源電圧は、
17783 x 201.416 = 35817807.28 [μV] = 3.582 [V]
となる。手持ちの電圧計での実測値は、
3.639 [V]
であった。
電圧計は校正していないので、残念ながらこの時点では真の電源電圧とどの程度の誤差で測定できているかの判断は出来ない。
また、他の入力電圧adc_acc_z=-58とoffset=-59から、adc_acc_z=-58-(-59)=+1 (200μV)という測定結果となる。
実は、PIN6とPIN7はショートしてあるので、これで正解だろう。
電源電圧もこのオフセットを加味すると、
3.594 [V]
となる。
変換式の導出:
ADCの電圧範囲は、
VFSR+ = +(VREF/2)/GAIN から VFSR− = −(VREF/2)/GAIN
までの範囲となる。
電圧範囲は、int形式(Bipolar Output: 2's complement)の場合には、2の16乗の数の分解能なので、内部Ref電圧=1.2V 、GAIN=1の場合には、
(1Bit当たりの電圧値) = 1.2/(2の16乗) = 1.2/65536 = 18.311 [μV]
となる。
(ADC入力電圧) = R/(5R+R+5R) x (電源電圧) = 1/11 x (電源電圧)
(ADC入力電圧) = (ADC変換値) x (1Bit当たりの電圧値)
の関係から、(電源電圧) = (ADC変換値)x 11 x 18.311 = (ADC変換値)x 201.416 [μV]
が導きだされる。
9月3日
2時間くらい色々と試したが芳しくない。もう一度、8月29日のレジスタ設定を原点に戻って再考する。
そして、表の作り方に起因する原因を見つける。SD16CTLの値を0x0402としたが、SR16REFON=1に相当するビットは、何とBit2で0x0404としなければならなかった!
早速、この設定でDebugを再開して、動作が正しそうな感触を掴む。結局のところ、下記のような設定とした、
// Main routine
void main( void )
{
/********** Hardware ******************************************************/
BCSCTL1 = CALBC1_8MHZ; // DCO set to 8MHz
DCOCTL = CALDCO_8MHZ;
BCSCTL1 |= DIVA_0; // ACLK/1
// SD16INTDLY_3MCLK=DCO,Div=x/1,SMCLK=DCO,Div=x/1,Internal
//BCSCTL2 = 0; // as of reset condition
BCSCTL3 |= LFXT1S_2; // VLOCLK=10 selected
WDTCTL = WDT_ADLY_1_9; // WDT 1.9mS(@32KHz) interval timer
P2SEL = 0; // Use as input or output
P2DIR = 0xbf; // P2.6 is input, others are outputs
P2OUT = 0; // All P2.x reset, LED off
P1DIR = 0xff; // all port1.x are outputs
P1OUT = 0; // All P1.x reset
// Use for ADC from P1.0 to P1.5
// A2- A2+ A1- A1+ A0- A0+
SD16AE = SD16AE5 + SD16AE4 + SD16AE3 + SD16AE2 + SD16AE1 + SD16AE0;
// 1/16 1.2V ref on
SD16CTL = SD16XDIV_2 + SD16REFON;
// MCLK=8M -> No1 Div = 1/1,No2 Div=1/16 -> f=500KHz,OSR=1024
// Buf disabl Bip. 1024OSR Single conv. 2's comp.
SD16CCTL0 = SD16BUF_0 + 0 + SD16OSR_1024 + SD16SNGL + SD16DF;
// Interrupt Delay(none) Gain x1 channel 0
SD16INCTL0 = SD16INTDLY_3 + SD16GAIN_1 + SD16INCH_0; 9月5日の設定参照要。
// Continue next other steps まだ初期化は続きますが・・・・
反省点:
(1)表を作成する際に、RESERVED BITを省略して作らないこと。結局、表は正しくてもHEX値に変換する時に間違いを発生する要因を作ってしまった。
(2)Cソースコード内の表現を最初からHEX値でなく、上記のように各ビットの名称で記述するほうが間違いが少なくなったはず。
IDE Tips:
今回のDebug作業で、色々と「IAR Embedded Workbench IDE」の使い方を学んだ。
(1)Watchに変数を追加する方法
ソースコードのチェックしたい変数にカーソルを置き、右クリックすると上記表示が現れるので、簡単にWatchリストへ追加可能。
(2)Watchの中で表示している変数値をHEXやDECの好みで表示
Watchリストの変数にカーソールを合わせて、右クリックすると上記画面が現れて、表示形式を変更可能。
9月2日
実機でのDebug開始。先ずはモールス信号表示の4桁連続表示の部分をこのように、固定値表示で色々な数字列で実行。ブレークポイント設定で、幾つかの値を確認後、単純にGOして確認。上手く動いている様子。
次に本命のADC部分のDebugに入る。先ずは、ADC変換チャンネルをCh6に固定して、Vccの変換データを眺める。ADCのEOC(ADC変換完了割込み)ルーチン内にブレークポイントを設定して値を確認。値が安定していない!
もう一度設定内容と各レジスタの実際の値を確認する。問題なさそうだが、値のばらつきから変換データの下位を取り出す設定を疑う。マニュアルを読むとやはりSD16LSBACCの設定で下位を読んでいるが、上位を読むのが正しいと思われる。8月29日の情報も更新する。
値は安定して読めるようになったが、どうもADC変換値と電卓を使って計算した物理値が違うように思える。まだ、何か問題ありそうだ。
本日はここまで。時間切れ。
8月29日
--- 本日の内容は全くの未確認情報です。今週末Debug終了後の修正内容を確認してから参考にしてください。
ADCのDebugを始める前に、プログラムのコードチェックを兼ねて、
1.RTMと各制御ルーチンの関係を省電力モードの関係から再チェック
2.ADCの割込み、クロックソース等々の設定条件を再チェック
を行う。
先ず、省電力モードと制御の関係だが、このように整理してみた。
下記(1)から(6)は、上記タイミング図の各数字に対応。
(1)WDTの割込みで、LPMxからACTIVEモードへ遷移させる。更にRTMを起動させる。
// Watchdog timer interrupt
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer (void)
{
LPM3_EXIT; // Clear LPM3 bits from 0(SR)
req_cyctsk(); // Request to start RTM
}
疑問点/問題点:
(a)WDTの起動周期が内部VLOCLKの発振周期に依存しているが、正確に周期を把握していない。
勿論、個別にテストプログラムを走らせて、P1.0にACLKの信号を出力すればわかるのだが、それを一々補正値として反映するしかないのだろうか?この問題の解決には、少し時間がかかりそうである。
(b)今回は、RTMが終了後もADC変換が続くのでLPM3だけでなく変換中はLPM0に設定する。しかし、制御プログラムでは、LPM3_EXITと記述しているが、当然直すべきだろう。コンパイラの吐き出したアッセンブラコードを見ると、
// LPM3_EXIT; // Clear LPM3 bits from 0(SR)
000008 B1C0D0000800 BIC.W #0xd0, 0x8(SP)
となっている。
LPMx中に割込みが発生すると(割込み許可設定が前提)、SRレジスタをLPMxの状態を保持したままでスタックに積んで、割込み中は自分でSRレジスタをACTIVEモードにして処理を行う。そこで上記のように、スタックに積まれたほうのSRレジスタ内容を割込みからの復帰に備えてACTIVEモードにする必要がある。
LPM3_EXITは、msp430x20x3.hの中で、
#define LPM3_EXIT _BIC_SR_IRQ(LPM3_bits) /* Exit Low Power Mode 3 */
と定義されており、_BIC_SR_IRQはIntrinsic functionsとしてコンパイラが提供しているlow-level processor operationsということになる。従ってやっていることは、SRレジスタのビットクリアなので、初めからクリアされているビットは変化しないとなれば、LPM4_EXITとしておけば、LPMxのどの状態からでもACTIVEモードへ移行できることになる。
(2)WDTにより、ACTIVEモードに戻ったCPUは、RTM(rtm_core())を実行する。ADCは、cy2_main()として起動される。
ADCの変換時間中、ACTIVEモードはもったいないので、LPM0に移行することにする。そのためにはRTM終了後にADC変換中であることをFlagで判断し、LPMxのエントリ条件を層別した。
/*********** Main loop *****************************************/
while(1)
{
rtm_core(); // Start dispatch routine
if ( ADC_RUN_FLG == AD_BSY ){
LPM0; // Enter LPM0, ADC is working
} else {
LPM3; // Enter LPM3, Only ACLK is running
}
_NOP();
}
(3)ADC変換中(ADC_RUN_FLG==1)には、WDTの割り込みや今後の色々な割込みが発生しても問題ないようにしておかなければならない。rtm_core()は上記while(1)内で割込み発生後は必ず起動されてしまうので、WDTの割込みと確実に区別する必要がある。
/********** Basic routine ***************************************/
void rtm_core( void )
{
/* event driven task dispatch */
if( status.ed0_req ){
/* event driven task no.0 check and go */
status.ed0_req = RTM_OFF;
ed0_main();
} else if ( status.ed1_req ){
............
ed3_main();
}
if( status.cyc_req != 0 ){
status.cyc_req = 0;
rtm_msp430();
if( r.request != 0 ){
.....................
赤字部分がrtm_core()の中で、WDT内での起動要求か否かをチェックして対応している部分である。
(4)(5)(6)ADC変換完了時の割込みでed0()を起動する。
上記のように、rtm_core()内でedxはどんな割込みでも通過する部分に記述されているので、
// Analog to Digital Converter interrupt
#pragma vector=SD16_VECTOR
__interrupt void SD16ISR(void)
{
LPM4_EXIT; // Clear LPMx bits from 0(SR)
reqed0();
adc_last_val = SD16MEM0; // Store value
}
が終了後にed0()が直ぐに起動されることになる。
次にADCの割込み、クロックソース等々の設定条件の再チェックを実施。
ADCの動作は、下記の各レジスタの設定のよる。
SD16_A Control SD16CTL クロック等の基本条件設定 下記参照 SD16_A
Channel 0 ControlSD16CCTL0 サンプリング条件等の設定 下記参照 SD16_A Input Control SD16INCTL0 変換チャンネルの設定、プリアンプのゲイン設定等 下記参照 SD16_A Analog Enable SD16AE 各ポートの端子をアナログ信号用に使用する(=1)か否か(=0)の設定 今回はCh0からCh3を外部端子と接続とする SD16_A Conversion Memory SD16MEM0 ADC変換結果を格納している16bitのレジスタ 設定不要。結果の読出しのみ SD16_A Interrupt Vector SD16IV 割込み要因が①オーバーフロー発生か②変換終了(正常)かをビット条件で判断可能 当面は無視する
個別レジスタの詳細
SD16CTL
Bit Name RSV SD16XDIVx SD16LP SD16DIVx SD16SSELx SD16VMIDON SD16REFON SD16OVIE RSV Bit 15,14,13,12 11-9 8 7,6 5,4 3 2 1 0 設定値 0000 010 0 00 00 0 1 0 0 機能 / No2
分周器低消費電力
有効・無効No1
分周器クロック
ソースVrefの外部出力 Vref有効・無効 OV割込み / コメント / 注意2) 無効 注意2) MCLK 出力せず 有効 無効 / SD16CTL = 0x0402
SD16CTL = 0x0404
SD16CCTL0
Bit Name RSV SD16BUFx SD16UNI SD16XOSR SD16SNGL SD16OSRx SD16LSBTOG Bit 15 14,13 12 11 10 9,8 7 設定値 0 00 0 1 1 01 0 機能 / バッファ データ形式 オーバー
サンプリング連続・単発 オーバー
サンプリング自動トグル コメント / 2013には無し 注意1) 注意2) 単発 注意2) 無効 Bit Name SD16LSBACC SD16OVIFG SD16DF SD16IE SD16IFG SD16SC RSV Bit 6 5 4 3 2 1 0 設定値 0 0 1 0もしくは1 0 0もしくは1 0 機能 結果上位/下位 オーバーフロー有無 データ形式 割込み許可 割込み完了 変換起動 / コメント 上位固定 書込みは常に0 注意1) 初期値0 読出し 初期値0 / SD16CCTL0 = 0x0d50SD16CCTL0 = 0x0d10 9月3日Debug結果反映。
注意1) SD16UNI = 0, SD16DF = 1 によって、Bipolar Output: 2's complement 形式を選択
注意2) MCLK=8MHz -> No1=1/1, No2=1/16 -> fM=500KHz,OSR=1024
SD16INCTL0
Bit Name SD16INTDLYx SD16GAINx SD16INCHx Bit 7,6 5-3 2-0 設定値 00 000 Ch0,1,2,5,6,7 機能 割込みタイミング プリアンプ利得 変換対象チャンネル コメント 変換開始後4回目の変換
完了後x1
±Vfsr=1.2/2/1=0.6V変換開始前に毎回変更要 SD16INCTL0 = 0xc0 ~ 0xc7 (初期設定値 = 0xc0)
SD16INCTL0 = 0x00 ~ 0x07 (初期設定値 = 0x00) 9月5日Debug結果反映。
SD16AE
AD16AE = 0x3f
Bit Name SD16AE7 SD16AE6 SD16AE5 SD16AE4 SD16AE3 SD16AE2 SD16AE1 SD16AE0 Bit 7 6 5 4 3 2 1 0 設定値 0 0 1 1 1 1 1 1 入力 未使用 未使用 Acc-Z/- Acc-Z/+ Acc-Y/- Acc-Y/+ Acc-X/- Acc-X/+
ここまで来ると、DCOの設定もしておく必要あり。
RSELx = 13, DCOx = 3, MODx = 0
で発振周波数レンジが、
6.00MHz ~ 9.60 MHz
となる。
補正値を下記条件で設定すると、
BCSCTL1= CALBC1_8MHZ; // Compiler can compile this format
DCOCTL = CALDCO_8MHZ; // Compiler can compile this format
発振周波数の誤差は、
7.920MHz(min.) - 8MHz(Typ.) - 8.080MHz(max.) 条件25℃, 3V
7.760 8 8.400 0−85℃, 2.2V
7.800 8 8.200 0−85℃, 3.0V
7.600 8 8.240 0−85℃, 3.6V
となる。従って、こちらを採用とする。
ちなみに、コンパイラは下記のコードを生成する。
// BCSCTL1= CALBC1_8MHZ; // DCO set to 8MHz
000000 D242FD105700 MOV.B &0x10fd, &0x57
// DCOCTL = CALDCO_8MHZ;
000006 D242FC105600 MOV.B &0x10fc, &0x56
8月26日
Debugを開始したが、P1.0からP2.7へ接続を変えたLEDの点滅が上手く行かない。仕方なく、F2013のData SheetでP2.7の詳細を確認する。
MSP430x20x1, MSP430x20x2, MSP430x20x3 Mixed Signal Microcontroller (Rev. C)
(msp430f2013.pdf, 2022 KB) 10 Apr 2006
<SLAS491C − AUGUST 2005 − REVISED MAY 2006>
http://focus.ti.com/lit/ds/symlink/msp430f2013.pdf
動作しなかったのは、P2SEL..xの設定を怠っていたため(56/86ページ参照)、Xtal発振回路が動作していたことに因る。但し、気になる記述を発見。P2.7の記述(57/86ページ)に、
NOTES:
3. If the pin P2.7/XOUT is used as an input a current can flow until P2SEL.7 is cleared due to the oscillator output driver connection to this pin after reset.
とあり、P2.7をスイッチ入力とした場合には、P2SELを初期設定をするまでは、最悪はXOUT端子としての出力が出っ放しでスイッチがONの時に短絡状態となりえるとの事。
これを回避するため8月20日に決めたピン配置を、このように変更。P2.7とP2.6の接続を交換する。P2.7のLEDは、上手く動作することを確認完了。
これで、ADCの動作確認に専念出来るのだが、先ずはCh0の電位差をボリューム設定で固定電圧に設定して行うことにする。またCh1とCh2は、±の端子をショートして出力値がゼロ(オフセットのみ)になるようにしておく。Debugが簡単に終了できれば良いのだが。
8月22日
プログラム作成中、Linkerが下記エラーメッセージを発する。
Error[e16]: Segment CSTACK (size: 0x50 align: 0x1) is too long for segment definition. At least 0x2 more bytes needed. The problem occurred while processing the segment placement command "-Z(DATA)CSTACK+_STACK_SIZE#", where at the moment of placement the available memory ranges were "CODE:232-280"
Reserved ranges relevant to this placement:
200-231 DATA16_Z
232-280 CSTACK
原因は、RAMエリアのスタックサイズを80バイトに設定していたが、データ領域が大きくなってスタックを減らさなくてはならない状況になった模様。忠告に従って2バイト減少させるとエラーはなくなった。
改めて128バイトしかないRAMエリアを再認識する。
そこで、先ず行った事は、2バイトデータを1バイトデータで表現すること。H8では、フラグやカウンターなどのRAMデータはほとんど2バイト表現を基本にしていたので、その癖でMSP430でも2バイトにしていた。
改良結果の詳しいデータはここを参照のこと(2ページ有り)。
スタックサイズをオーバーフローさせたRAMサイズ
1バイトデータを多用した改良タイプ
1294 bytes of CODE memory
110 bytes of DATA memory (+ 17 absolute )
133 bytes of CONST memory1290 bytes of CODE memory
97 bytes of DATA memory (+ 17 absolute )
133 bytes of CONST memoryこの情報は、IAR Embedded Wrkbench IDEにおいて、<Project>-><Options>で <Linker>を左端から選び、
<List>を選択しリストを吐き出すように設定します。
Linkerが吐き出す*.mapファイルには、上記以外に色々な情報が入っているので、メモリーサイズが厳しくなったらよく眺めるとよい。例えばmapファイル内には、<CALL GRAPH>という項目があり、スタックの深さを計算している。それに因ると現在は0x28とのこと(どのように計算しているのか、ちゃんとチェックしないと信用できるかは不明ですが)。
STACKサイズは、とりあえず50バイトとした。
8月20日
今日は午前中に、ADCを起動するための割り込み処理とEvent Driven Task及びCyclic Taskの役割分担検討と骨子となるプログラムを作成。午後には、高校野球の決勝戦を見ながら、はんだ付けを実施。
ハードウェアのピン配置を、このように決定。これは、秋月で入手したKXM52-1050モジュールを接続して、3軸の加速度測定をする為の構成で、他にI2Cインターフェイスを拡張できる(本当にインプリメントできるか否かは現時点で不明)ように準備する。先日は、外付けXtal(32.768KHz)をはんだ付けしたPIN13,12は、ADCの入力確保で使えなくなったLED駆動と、新しくスイッチ入力の端子とした。
ソフトウェアの構成は、下記のようにすることに決定。
(1)Cyclic Task (void cy1_main( void ))にて、Ch0、1、2の外部入力と温度センサー、電源電圧、及びADCの差動入力オフセット(以上3つは内蔵信号)の測定を起動するルーチンとする。起動順序は、スケジュール用テーブルをROM上に置き、それによって実施。
起動は、CY1の起動周期時間を決定すれば、任意に設定可能(今回の設定は20mS毎とする)。尚、起動周期を早めた際に、以前のADCが完了していないことを前提に、Busyフラグで起動出来る状態か否かを判断する。
(2)Interruptルーチンでは、ADCの終了時に割り込みが発生するように初期設定しておき、データの一時セーブとEvent Driven Taskを起動。
(3)Event Driven Task(void ed0_main( void ))では、変換の終えたチャンネルを識別して、前回の測定データと加重平均を取りながら、データをRAMに格納する。
(4)上記のような構成とすると、必ず処理がRTMのコアルーチンを介して行われるため、パワーダウン制御も一元管理できることになる。すなわち、RTMを終了した際にADC変換が継続している場合には、LPM0にして処理は中断するがADC終了まではMCLKを休ませない。ADCがBusyでなければ、RTM終了時にLPM3にすればよい。MSP430の使用では間欠起動が重要であり、そのリコメンドを忠実に守る事が出来る。
ソフトは、デバッグが終了していないので、デバック完了後に公開予定。
ハードウェア製作は、下記のようなところまで終了。高校野球観戦のながら作業にしては誤配線なく完了。
電源SW(左上)
KXM52加速度センサー(左)
中間点電圧調整用VR(下3つ)
I2C(EEPROM予定)ソケット(右下)
SW(右)のそれぞれを追加。
Xtalは取り除いた新作電源基板
3.3V電源(48M033)(右)
3.3V電源(MAX987)(左)裏面
インダクタンスもありあわせ
左端は負荷の500オーム
秋月で大量に購入した100KオームのVRを3つ使用して、ADCの差動入力のAx-の基準電圧とした。100Kオームは決してよい値ではないので、抵抗2本を中点と両端子の間に入れて抵抗値調整とした(下記”悩み”参照)。
電源回路は、ACから5Vの小型DC-DCコンを介して、48M033で3.3Vとした。これは、実験確認用の電源専用で、最終的にはもう少しリーク電流を抑えた物を使用したい。その候補として、秋月のMAX987を購入して、3.3V入力で3.3V出力という一見無駄な実験を開始する。それで写真のような状態となっている。
これで、ソフトウェア開発に専念できるか・・・?
悩み:
(1)ADC入力は差動タイプのみ(もちろん片方GNDの差動も1つの選択肢)で、±500mVが最大のように読み取れる。これでは、KXM52の±660mV/gで±2gの計測はオーバーフローしてしまう。1Vの入力範囲に出力を調整しないと・・・・・・・
(2)本来、かなりの部品を持っており不良在庫になっているのだが、それが埼玉の実家にあり、今年6月の異動で移り住んでいる横浜の借家が狭く、持ち込めなかったことが、このような手段をとる要因となっている。
小容量のコンデンサはアマチュア無線しか使わないと判断して置き去り、VRは全部忘れて来る(特に半固定の多回転タイプ)、インダクタンス20uHも持ってこなかった。他にも色々と・・・
8月19日
何を作るか?色々なアイデアがあるが、なかなか最終的な形としてまとまらない。14PINに機能を凝縮するのは、結構大変な作業と感じる。
しかし、MSP430を良く知らないことも事実で、先ずは各機能の確認を優先することにした。確認すべき機能の一番目をSD_16AのADCモジュールとする。
これに伴い、AD変換値やその他のデータをDebugerなしで確認する方法を確立しておきたいと思い、以前にも作ったモールス信号表示器を使い、LED一個での点滅表示として試みる。モールス信号は、公の場からは姿を消したが、アマチュア無線では今も使われており、数値の表示に限定すれば初めての人でも直ぐに覚えられと思う。符合は、長点と短点の組合せで表され、それをLEDの点滅で表示する。たった一個のLEDで数字表示が出来るので、究極の表示器といえるかも知れない。
モールス信号での数字の表現は、下記のようになる。
1 ・---- 長点の長さ=短点3つ
各点の間=短点1つ
文字の間=短点3つ
単語の間=短点7つ2 ・・--- 3 ・・・-- 4 ・・・・- 5 ・・・・・ 6 -・・・・ 7 --・・・ 8 ---・・ 9 ----・ 0 -----
プログラムとしては、Cyclic Task2を250mS毎に起動し、この起動時間を短点の長さとして割り付けた。表示の速い遅いは、RTMの起動周期時間を変えれば簡単に変更可能なので、モールス信号初体験の場合には短点表示時間を長くするため、RTMの起動周期を長くするのが良い。
表示の基本的な考え方は、この図のようになる。すなわち、長短を短点をベースに1と0に分割して、それをmorse_onoff のデータとし、ON/OFFの回数を最初のLEDをONとする場所として表わす。数字1の場合には、
morse_onoff = 0x2eee
morse_num = 0x2000
となる。morse_numは、2で割りながらゼロとなった場合に終了と判断(右に1bit毎にシフト)。残念ながら2バイトに収まりきれないので、unsigned longで割付けた。4バイトを有効に使うために、次の数字までの消灯時間も含めてデータ化したので、最終的には下記のようなROM内テーブルを用意した。文字間を短点3つと規定しているが、短点4つとなってしまうが、むしろ可読性は悪くならないと思われる。
// Morse Code data
const unsigned long morse_onoff[10] = {
0xeeeee0, /* no.0 */
0x2eeee0, /* no.1 */
0xaeee0, /* no.2 */
0x2aee0, /* no.3 */
0xaae0, /* no.4 */
0x2aa0, /* no.5 */
0xeaa0, /* no.6 */
0x3baa0, /* no.7 */
0xeeea0, /* no.8 */
0x3bbba0 /* no.9 */
};
const unsigned long morse_num[10] = {
0x8000000, /* no.0 */
0x200000, /* no.1 */
0x80000, /* no.2 */
0x20000, /* no.3 */
0x8000, /* no.4 */
0x2000, /* no.5 */
0x8000, /* no.6 */
0x20000, /* no.7 */
0x80000, /* no.8 */
0x200000 /* no.9 */
};
ひとつの数字を表示できるところまでは、動作確認完了。
8月14日
公開を開始しました。
昨日、秋葉原で購入してきた部品と在庫部品から下記のような基板を作り、とりあえずDebugerからのFASHへの書き込みと、先に紹介したRTM上で動く一秒毎のLED点滅のプログラムの動作確認が終了しました。
回路はUSBスティックに付属している回路と基本的には同じもの。
購入してきた部品で組み立てたバラックセット
サンハヤトの基板は半分に切って使いました。
電源には、タンタルコンとセラミックコンを入れています
別の角度から。
32.765KHzのXtalを付けていますが、未だプログラムは内蔵の発振器を使用
8月13日
初歩的な動作確認が済んだことにより、次はもう少し実用的な物を作りたいと思ったのですが、
① Chipが入手しにくい。
② 430F2013は、キットに入っている1個だけでバックアップがない。
③ 430F2013は、使用できるI/Oが少ない。
等々の悩みが発生しました。千石電商でChipが入手出来ることをトラ技の広告で知ったのですが、430F2013は書かれていません。仕方なく、430F2101を購入しようと決めて調査を始めたのですが、問題点として、今回のキットでは、書き込めないことが判りました。
そこで、本末転倒ですがパラレルI/F用JTAG製作を前提に、部品集めをすべく秋葉原に出かけました。
しかし、千石通商では430F2013を販売しており、結局それを買って来たところです。
帰宅後、USBスティックから線を引出し、ここにあるような準備を完了しました。更に、今後の製作の基本となるMPU基板のはんだ付けを行いました。
はんだ付け前
基板サンハヤトSSP-63はんだ付け完了
隣とのブリッジを気にしないといけない!
慣れないときついと思います
8月6日、7日
H8で使用していた自作のRTMを改造して、インプリメント完了。
考え方:
2mS毎にWatchdog timerからの割り込みを発生させ、LPM3のスタンバイ状態からシステムを再起動させます。ユーザープログラムは、「条件待ちのループを作らない」を原則に作成します。ユーザープログラムを終了すると、再びLPM3の状態に入ります。
このRTMは、MSP430のスタンバイモードとアクティブモードをうまく使い分けるのに都合がよい方式と思っています。
ソースコードのPDFファイルを下記に置きます。研究してみてください。
rtm_msp430.c
rtm_msp430.h
task.c
動作のポイント:
Watchdog timer interruptは、task.c内の下記の部分にあります。
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer (void)
{
LPM3_EXIT; // Clear LPM3 bits from 0(SR)
req_cyctsk(); // Request to start RTM
}
インターラプト処理は、①LPM3からアクティブモードへの切替、②RTM起動フラグの設定を行います。
2mS毎の設定は、mainルーチン内のイニシャライズルーチンで実行します。
LPM3とは、下記の状態を言います。
Low-power mode 3;
(a) CPU is disabled
(b) MCLK and SMCLK are disabled
(c) DCO’s dc-generator is disabled
(d) ACLK remains active
下記がmainルーチンです。
void main( void )
{
rtm_msp430_init();
general_init();
/********** Initialize each task ******************************************/
cy0_init(); cy1_init(); cy2_init(); cy3_init(); cy4_init();
/********** Hardware related initialize ***********************************/
BCSCTL1 |= DIVA_0; // ACLK/1
BCSCTL3 |= LFXT1S_2; // VLOCLK=10 selected
WDTCTL = WDT_ADLY_1_9; // WDT 1.9mS(@32KHz) interval timer
IE1 |= WDTIE; // Enable WDT interrupt
port_init(); // Port initialize
/********** Interrupt *****************************************************/
__enable_interrupt(); // Enable interrupts
/*********** Main loop ****************************************************/
while(1)
{
rtm_core(); // Start dispatch routine
LPM3; // Enter LPM3
_NOP();
}
}
各種初期設定終了後にRTMを呼び出します。その後は、スタンバイモードに入り次の2mSインターバルや他の割り込みを待ちます。
RTMの起動は、整理すると次のようになります。
① Watchdogタイマーで割込み発生(2mS毎)。スタンバイモードの解除とRTM起動フラグを設定。
② メインルーチンの無限ループ内で、スタンバイモードが解除されたことにより、rtm_core()が呼ばれる。
③ rtm_core()内では、Event Driven Taskの起動要求を調べ、何らかの割込みルーチンによって起動すべきタスクがあればそれを処理します。その後、2mSの割込みから起動されたのであれば、あらかじめ決められた起動周期に達すれば、Cyclic Taskを起動します。
はまった点:
Watchdogタイマーは、通常Auxiliary clock (ACLK)によって駆動されるように設定しますが、そのクロックソースは①外部接続された32.769KHzのような時計用クリスタルか、②内蔵されているLF発振器が利用出来ます。
当初は、クリスタルを付けずに外部クリスタル駆動回路からのクロックを選択してしまいました。BCSCTL2, Basic Clock System Control Register 2の設定を正しくする必要があります。
具体的には、
BCSCTL3 |= LFXT1S_2; // VLOCLK=10 selected
の部分です。しかし、外部クリスタルモードのままでもノイズを拾って動作してしているように見えたため、起動周期が思ったような値にならない原因究明に1時間以上費やしてしまいました。
更に、内部発振は、下記のような仕様になっていますので、最終的には外部37.768KHzクリスタルを設定する予定です。
電源電圧=1.8 V − 3.6 V
最小発振周波数 10,000Hz
最大 50,000Hz
Typ値は、15KHz程度か?
7月23日
各種ドキュメントを読んで勉強。
Chip:MSP430F2013
http://focus.ti.com/docs/prod/folders/print/msp430f2013.html
USB Stick: eZ430-F2013
http://technobase.plala.jp/eclib/OTHER/DATASHEET/ez430f2013.pdf
IDE: User's Manual, C compiler, etc
http://focus.ti.com/docs/toolsw/folders/print/iar-kickstart.html
7月22日
開発環境をインストールする。
① 「IAR Workbench Kickstart」と呼ばれるIDE(統合開発環境)
② eZ430-F2013のUSBドライバー
③ 各種ドキュメント及びCサンプルコード
インストール後、サンプルプログラム(LED点滅)の動作確認完了。
7月19日
映画のDVDのようなパッケージに入った、
「MSP430 Ultra-Low-Power MCUs eZ430-F2013 Development Tool」
を入手する。
私の入手したものは、
Made in Germany: Lot GERMANY026 0908300PD4
となっています。
中は、簡単な説明書とCD-ROM、そしてUSBポートに接続するハードウェアが入っていました。