STM32L / Barometer (Bosch BMP180)
 on ( GCC + OpenOCD ) with PN2

IMAGE12.GIF - 2,801BYTES

2013年5月5日 全面書換え&ほぼ終了
2013年1月19日&20日 一部追加
2013年1月6日 新規作成

1 はじめに
2 HW構成
3 SW構成
4 プログラム
2.54mmピッチの基板に実装したBosch Sensortec製気圧センサーBMP180
パケージは、3.6x3.8mmで高さ0.93mmと小さくルーペを使用してもハンダ付けには苦労した
全体構成(クリックで拡大と構成説明あり)
上記数字の意味は左から、
3.34V(CPU電源電圧)、4.52V(電気二重層キャパ充電電圧)、4.37V(太陽電池発電電圧)
STOPモード時の電流測定



1 はじめに
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES

<BMP180>
トランジスタ技術(2012年12月号P79)にてBosch Sensortec製のBMP180 が紹介されていたので、早速Digi-Keyから入手してみました。
実際に手にしてみると、想像以上に小さく実装を心配したのですが、年末年始の休みを費やして何とか無事に動作させることが出来ました。

以前、秋月で入手して使用した2つのセンサーとの比較を勝手にしてみたので、参考にしてみてください。

Barometer Specification (私の)使用例 コメント
BMP180 Bosch Sensortec このページに記載 カタログを観ると解像度が高いので短時間での高度変化を検出出来そう
生データを工場出荷時のEEPROM情報で補正して正規化する必要あり
MPL115A2 Freescale プログラム完
(将来公開予定)
生データを工場出荷時の補正値で正規化する必要あり
SCP1000
-D01
VTI Technology STM32L GPS logger

MSP430 Barometer
SPIインターフェイスの製品が秋月で販売されている(製品としてはI2C用あり)
工場出荷時の補正値がチップ内に存在することは、
上記2つのチップと同じだが、補正済のデータが出力される。


<STM32Lの消費電力>
MSP430からSTM32Lに乗り換えたのは、ROM/RAMサイズを気にせず且つ省電力を保ちたいからでした。
先に、STM32L-DiscoveryやSTM32-P152を使いましたが、搭載されている回路や追加したセンサーなどでCPUが本来の省電力を達成しているか調査出来ず不安でした。
そこで今回は、ピッチ変換基板を使用してこちらもDigi-Keyで入手した裸の48Pin CPUを使って製作途中でも消費電流を測定してみました。

基板 電流 測定条件 コメント
STM32-P152 4mA前後 STOPモード時 内蔵RTC、GPS、大気圧センサー(SCP1000)などを接続して、スタンバイ状態としているが、何故4mAも流れているかを究明できず
今回の基板
(テストプログラム
での
初期測定結果)
MAX 1.98mA
MIN 1.13mA
AVE1.25mA
Barometerとして通常動作時
電源電圧 3.31V
CPU動作周波数 4MHz(MSIモード)
FreeRTOSでアイドル期間中は
"enter SLEEP mode with WFI instruction"に突入させている
FLUKE177での測定値

思ったより良くて一安心
50.8μA 電源電圧 3.3V
STOPモード時
この測定値は、殆どのI/Oは未接続の状態
Protek506での測定値
今回の基板
(最終に近いが
まだ未完成
1月14日)
MAX 1.31mA
MIN 1.04mA
AVE 1.08mA
電源電圧(Vdd)=3.297V
CPU動作周波数 4MHz(MSIモード)
コア電圧設定 1.5V
FreeRTOSでアイドル期間中は
"enter SLEEP mode with WFI instruction"に突入させている
FLUKE177での測定値
0.05mA 電源電圧(Vdd)=2.443V
STOPモードに突入中
  (電源電圧上昇で通常モードに復帰)
RTCは、動作
PVDは、動作
FLUKE177での測定値
今回の基板
(公開していた
プログラムで
1月19日)
MAX 0.21mA
MIN 0.19mA
AVE
0.20mA
電源電圧(Vdd)=3.306V
CPU動作周波数 
2MHz(MSIモード)
コア電圧設定 1.5V
FreeRTOSでアイドル期間中はスリープさせている
"enter SLEEP mode with WFI instruction"
FLUKE177での測定値
16.5μA 電源電圧(Vdd)=2.013V
STOPモードに突入中
  (電源電圧上昇で通常モードに復帰)
RTCは、動作継続
アナログ電流計(上記写真参照)

CPUの動作周波数を2MHzまで低下させたことにより、上記の様に動作電流が低減出来ました。
STOPモード時の電流もIOをアナログポートに設定して、今までより低減出来ました(2013年1月19日)。

今回もFreeRTOSを使用して、以前からの資産を生かして作業時間短縮を優先してソフト作成しました。
しかし省電力を優先するならRTOSを使用せずに、RTCの一秒毎の割込みでWake-upしてセンサー情報の取得、アナログ信号計測を行いLCDに表示してまたストップモードに入るプログラム構成がより有効と思われます。

<大気圧計としては>
一通りの動作が昨日まで(2013年1月19日時点)に確認できたので、ケースに入れてMSP430の場合と同じように太陽電池パネルと組み合わせて完成させたい。
と書いてから、既に4ヵ月たちましたが、なかなか上手く出来ません。当たり前の話ですが、充電が不足すると二日くらいで動作しなくなります。
勿論、こまめに太陽に当てれば動作し続けますが、まだ電源回路の改良が必要な状況です。
そうは言っても暫定版でお茶を濁して完了としてしまいました。
MSP430 Barometerは思ったより上手く動作しており、電気二重層キャパシタの蓄電を使いきって停止しても再度太陽光が当たり始めると動作を再開します(時計機能はさすがに動かないが)。
しかし、STM32L版は電源を自分でコントロールしている為にそれが出来ていません。
先ずは、太陽電池の電源電圧、CPU電源電圧の変化に応じてSTOPモードと通常動作モードを遷移するところまでは上手く動作していますが課題は多く残っています。

ちなみに、下記の写真は3種類のセンサーをそれぞれのシステムで並べて測定した際の一枚のスクリーンショットです。
これだけで性能を判定できるわけではありませんが、構造の違いや制御アルゴリズムの違いでも、最大0.4hPaの差なので制御プログラムはそこそこうまく動作していると思っています。
時計機能は、初期設定をしていなのので無視願います。


2 HW構成
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES

1.回路構成
 結線表はこれを参照下さい

CPU周辺の回路図はこれです
電源回路はまだ最終型にはなっていませんが、現在はこんな回路です

 ポイントは、

  1. BMP180の電源は、STM32LのPB14を出力としてON/OFF制御出来るように接続
  2. BMP180のSCL/SDAラインは、4.7K の抵抗でプルアップ
  3. I2C-LCDは、電源をPB0でON/OFF制御している
  4. I2C-LCDのRESET端子は、PB1で制御する
  5. I2C-LCDのSCL/SDAラインは、33Kの抵抗でプルアップ
  6. アナログ電圧は3つの入力、①太陽電池の電圧モニタ(PA5/ADC_IN5)、②電源電圧(電気二重層)(PA1/ADC_IN1)、③可変抵抗器(PA2/ADC_IN2)
  7. アナログ電圧非測定時に電流を減らすために、PA3、PA4でON/OFF制御している
  8. 太陽電池の出力をPA11でON/OFFして電気二重層へ蓄電
  9. RTC用に32.768KHzのクリスタルを接続(PC14,PC15)しているが、セラミックコンデンサはまだRTCの周波数精度を見極めて接続予定
  10. デバッグはJTAG端子使用(PA13,PA14,PA15,PB3,PB4)
  11. デバッグでPB12とBP13の端子にLEDを接続して使用。デバッグ以外では使用しない
  12. パソコンとUART接続(PA9/UART1_TX, PA10/UART1_RX)して、デバッグ目的で使用(モニタープログラムにて)
  13. リセット端子にスイッチを接続したが、これもWFI命令を実行してJTAGが上手く接続できない時に利用


2.使用部品

No. 部品 部品名称 コメント
CPU STM32L152CBT6 48Pinでピッチ変換基板に実装
2 Pressure sensor BMP180 手ハンダは難しいので覚悟して実装のこと
3 I2C LCD SB1602E 大型ですが、小型のモノも同じソフトで動作可能
4 USB-UART TTL-232R-3V3 USB-シリアル変換ケーブル(DEBUG用で無くても可)
5 Xtal 32.768KHz セラミックコンデンサも一緒に入手しておくとよい
6 +3.3V Reg. NJM2863F33 電源は他に電気二重層コンデンサや太陽電池モジュールも必要
7 その他 C,R,LED,Switch, Volume 一般的なものでOK


3.SWDでなくJTAG利用の訳
 STM32Lを今までは、STM32L-Discoveryのようなボード単位で使っていました。
 その為、何らかのプログラムが既に書き込まれた状態で再書き込みしていました。
 今回、未書込みのシリコンチップを購入して、STM32L-Discoveryを利用して書き込もうとしたが失敗しました。
 そこでJTAG接続に換えましたが、JTAGにしても初めは上手く接続出来ず、RESET端子をアサートしたままでタイミング良く立ち上げてやっと接続出来ました。
 例えば、FreeRTOSで実行するタスクがない時に呼ばれる下記ルーチンを実行すると、JTAGでも再書き込みで問題が起きます。

/* Idle hook */
void vApplicationIdleHook( void ){
  PWR_EnterSleepMode( PWR_Regulator_ON, PWR_SLEEPEntry_WFI );
}


 そこで思い出したのが、ねむいさんのぶろぐでのこのコメントでした。

 私の場合も、このWFI命令を実行し全てのクロックが止まりSWJ (Serial wire and JTAG)ポートが機能しなくなっている状況と思われます。
 但し、新品のCPUがどんな状況になっているのかはまだ詳しく見ていません。

 少し余裕が出来たら、SWDでの接続もトライしてみようと思います。
 今の様にJTAGが正常に動作している場合には、SWD(ST-Link)も上手く動作すると思われます。

4.現時点での残務
 ハードウェア関連の残務。




3 SW構成
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES

0.ソフトウェア構成
1.FreeRTOS
2.必要ファイル群
3.I2C制御
4.LCD制御
5.大気圧データの正規化
6.Monitorの紹介
7.ADCデータの正規化
8.電源電圧低下によるSTOPモード移行と復帰
9.現時点での残務


0.ソフトウェア構成 
 全体構成は、FreeRTOSを中心に、下記のタスクが動作しています。

 上記だけで大気圧計としての動作が可能だが、ソフトウェアのDebug目的で下記のタスクを走らせている。



1.FreeRTOS
 FreeRTOSは、最新バージョンV7.4.0(2013年2月20日時点)を使用しました。
 以前紹介したV7.2.0と殆ど変更がない為、モジュールをバージョンアップし、過去の変更ポイントを反映しました。


2.必要ファイル群
 FreeRTOS関連ファイル以外に、(すべてが必要なわけではないですが)このファイルが必要です。
 その後、stdby_wkup.cの関数はmain.cの中に取り込みファイルは存在しません。


3.I2C制御
 STM32LではI2C制御が思ったより難しいことを知りました。
 先ずは、BMP180の(結果として上手くいった)I2C制御波形を下記に示します。 

このコマンドは、BMP180のリセットコマンド
一つ判ったことはSDAラインがLowのままではリセットもかけられないこと
そこで、今回はBMP180no電源ON/OFFをシーケンスの前半に挿入した
BMP180のチップIDを取得
0x55がBMP180のChip ID
データ取得直後にCPUからD-NAKを出しているが、下記の赤字の位置に注意願いたい

static ErrorStatus i2c_Baro_rd_id_raw( void ){
 if ( i2c_Baro_rd_header( BARO_CHIP_ID_REG )== ERROR ){
  return ERROR;
 }
 /* Send NACK signal */
 I2C_AcknowledgeConfig( I2CBARO, DISABLE );

 /* Send I2CBARO slave address for read */
 I2C_Send7bitAddress( I2CBARO, BARO_SEN_ADDR, I2C_Direction_Receiver );
 if ( I2C_CheckAll( I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) == ERROR ){
  return ERROR;
 }
 /* Read data */
 if ( I2C_CheckAll( I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR ){
  return ERROR;
 }
 sensor_type = I2C_ReceiveData( I2CBARO );
 /* Send STOP Condition */
 I2C_GenerateSTOP( I2CBARO, ENABLE );

 /* Check SCL line normal(Hi) */
 Sda_line_check();
 /* Enable Acknowledgement again */
 I2C_AcknowledgeConfig( I2CBARO, ENABLE );
 return SUCCESS; /* okay */
}

レジスタ情報(この場合は、0x77(7bit表記で))を送る前に、NACKを送る準備をしている
STOPはデータ受信後で間に合う
BMP180内のEEPROMに176bitのキャリブレーションデータを読み出す為のコマンド
データはバイト単位で、22Byteを読み出すことになるが、上記の例では23Byteを読み出している
最初は、22Byteを読み出すプログラムを作成したが、最後の0x80が逆に読み出せない状態となった
もう少しスマートな方法があるのかも知れんないが、下記のプログラムで対応している

static ErrorStatus i2c_Baro_rd_coefficient_raw( void ){
uint32_t i;

 if ( i2c_Baro_rd_header( BARO_PROM_ADDR )== ERROR ){
  return ERROR;
 }
 /* Send I2CBARO slave address for read */
 I2C_Send7bitAddress( I2CBARO, BARO_SEN_ADDR, I2C_Direction_Receiver );
 if ( I2C_CheckAll( I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) == ERROR ){
  return ERROR;
 }
 for ( i = 0; i < BARO_PROM_DATA__LEN; i++ ){
   if ( I2C_CheckAll( I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR ){
    return ERROR;
   }
   if ( i == ( BARO_PROM_DATA__LEN - 3 ) ){/* Disable Acknowledgement */
    I2C_AcknowledgeConfig( I2CBARO, DISABLE );
   }
   if ( i == ( BARO_PROM_DATA__LEN - 1 ) ){/* Send STOP Condition */
    I2C_GenerateSTOP( I2CBARO, ENABLE );

   }
   i2c_eeprom_buf[i] = I2C_ReceiveData( I2CBARO );
 }
 /* Check SCL line normal(Hi) */
 Sda_line_check();
 /* Enable Acknowledgement again */
 I2C_AcknowledgeConfig( I2CBARO, ENABLE );
 return SUCCESS; /* okay */
}

NACKが2度送出されている
温度測定の開始コマンド
レジスタ0x77に温度測定開始の0x2eを書き込んでいる
この後、4.5mS以上待つ必要あり
温度データ読み込み
ここは2バイト(この例では、0x6cと0x52)だけ必要だが気圧データの読出しと共通ルーチンで読んでいる為にこのような状態となる

static ErrorStatus i2c_Baro_rd_dt_raw( void ){
 if ( i2c_Baro_rd_header( BARO_ADC_OUT_MSB_REG )== ERROR ){
  return ERROR;
 }
 /* Send I2CBARO slave address for read */
 I2C_Send7bitAddress( I2CBARO, BARO_SEN_ADDR, I2C_Direction_Receiver );
 if ( I2C_CheckAll( I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) == ERROR ){
  return ERROR;
 }
 /* Read data */
 if ( I2C_CheckAll( I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR ){
  return ERROR;
 }
 i2c_rcv_buf[0] = I2C_ReceiveData( I2CBARO );
 if ( I2C_CheckAll( I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR ){
  return ERROR;
 }
 /* Send NACK signal */
 I2C_AcknowledgeConfig( I2CBARO, DISABLE );

 i2c_rcv_buf[1] = I2C_ReceiveData( I2CBARO );
 if ( I2C_CheckAll( I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR ){
  return ERROR;
 }
 /* Send STOP Condition */
 I2C_GenerateSTOP( I2CBARO, ENABLE );

 i2c_rcv_buf[2] = I2C_ReceiveData( I2CBARO );
 /* Check SCL line normal(Hi) */
 Sda_line_check();
 /* Enable Acknowledgement again */
 I2C_AcknowledgeConfig( I2CBARO, ENABLE );
 return SUCCESS; /* okay */
}

温度データは、i2c_rcv_buf[0]と[1]の2バイトを取り出す
気圧測定の開始コマンド
レジスタ0x77に気圧測定開始の0xf4を書き込んでいるので、オーバーサンプリングを3としている
この後、25.5mS以上待つ必要あり
気圧データ読み込み
ここは3バイト(この例では、0xa2と0x7c及び0x00)を読出している

 
 NACKの送出とSTOPタイミングを最適化するために、まだやり残した感じがあるがそのままで何も出来ていない。


4.LCD制御
 LCDはBMP180とは別のI2Cインターフェイス(I2C2)で独占使用しています。
 ここでもまだ納得できない問題があり、コントラスト制御が上手くいきません。
 初期化ルーチンでは上手く設定出来ているので、コントラスト変更時には毎回初期設定ルーチンを呼び出して誤魔化して使っています。
 LCDは、2.7V~3.6Vが動作範囲電圧だが実力では2.3V以下でも動作する(n=1)ので、最適コントラストを下記の様に調査してみました。
 その結果を基に計算式を導きそれをプログラムで実行しています。

これを下記の様にプログラムに反映

/* Calculate Contrast value */
/*
  contrast value: 0 to 63 (5bit data)
  Vdd = 3.3V -> contrast=32
  Vdd = 2.4V -> contrast=63(Max)
  contast = -34.4 * ( Vdd - 2.4 ) + 63
  -> contast=(-344/10)*((Vdd*10000-24000)/10000)+630000/10000
   -> contast = ( 630000 - ( 344 * ( data_vdd - 24000 )/10 )) / 10000
*/
uint8_t cal_lcd_contrast( uint32_t vdd ){
uint8_t data;
uint32_t i;

 if ( vdd > VDD_3R3V ){
  data = MIN_CONTRAST;
 } else if ( vdd < VDD_2R4V ){
  data = MAX_CONTRAST;
 } else {
  i = ( ( vdd - 24000 ) * 344 ) / 10;
  data = (uint8_t)( ( 630000 - i ) / 10000 );

 }
 if ( data > lcd_contrast_dt ){
  if ( ( data - lcd_contrast_dt ) > 2 ){
   lcd_contrast_dt = data;
   return 1;
  }
 } else {
  if ( ( lcd_contrast_dt - data ) > 2 ){
   lcd_contrast_dt = data;
   return 1;
  }
 }
 return 0;
}

上記プログラムで全域ちょうど良いコントラストになって思ったより表示が綺麗になった
一秒回に一回の更新では、コントラスト変更時に初期設定し直しても違和感はない
コントラストデータは0~63の数値で上限が決まっているので電圧が2.4V以下ではかなり見ずらくなる



5.大気圧データの正規化
 先ずは結果を下記に示します。

 上記は、下記6で示すMonitor機能で表示した計算プロセスを含めた大気圧計算の流れです。
 Bosch SensortecのData SheetのPage15に正規化の方法が書かれています。
 書類番号は、
  Reference: Bosch Sensortec BMP180 Datasheet=BST-BMP180-DS000-08 Revision: 2.4 Date: 27 January 2012
 となっています。
 これを、忠実に実行したプログラムが下記になっています。
 但し、GCCが悪いのか下記赤字の部分を青字の様に直さないと桁落ちして精度が出ませんでした。
 検証には、P15ページの数値を代入して計算途中の値を比較しました。

void Cal_pressure( void ){
int32_t dt_x1, dt_x2, dt_x3, dt_b3, dt_b5, dt_b6;
uint32_t dt_b4, dt_b7;
long long int d;

  /* Cal_temperature */
  if ( sensor_type == BMP180_CHIP_ID ){
    dt_x1 = ( ( raw_temp - (int32_t)eep_ac6 ) * (int32_t)eep_ac5 ) >> 15;
    dt_x2 = ( (int32_t)eep_mc << 11 ) / ( dt_x1 + (int32_t)eep_md );
    dt_b5 = dt_x1 + dt_x2;
  }
  i2c_baro_temp_data = ( ( dt_b5 + 8 ) >> 4 );/* temperature in 0.1 degC */
  /* Cal_pressure */
  dt_b6 = dt_b5 - 4000;
  dt_x1 = ( dt_b6 * dt_b6 ) >> 12;
  dt_x1 *= eep_b2;
  dt_x1 >>= 11;
  dt_x2 = ( eep_ac2 * dt_b6 );
  dt_x2 >>= 11;
  dt_x3 = dt_x1 + dt_x2;
  dt_b3 = ( ((((long)eep_ac1) * 4 + dt_x3 ) << oss_setting ) + 2 ) >> 2;
  dt_x1 = ( eep_ac3 * dt_b6 ) >> 13;
  dt_x2 = ( eep_b1 * ( ( dt_b6 * dt_b6 ) >> 12 ) ) >> 16;
  dt_x3 = ( ( dt_x1 + dt_x2 ) + 2 ) >> 2;
  dt_b4 = ( eep_ac4 * (uint32_t)(dt_x3 + 32768)) >> 15;
  dt_b7 = ( (uint32_t)( raw_pres - dt_b3 ) * ( 50000>> oss_setting ) );
  if (dt_b7 < 0x80000000){
    i2c_baro_pres_data = (dt_b7 << 1) / dt_b4;
  } else {
    i2c_baro_pres_data = (dt_b7 / dt_b4) << 1;
  }
  /* Complier problem? */
  /* dt_x1 = i2c_baro_pres_data >> 8; */
  /* dt_x1 *= dt_x1; */

  d = (long long int)i2c_baro_pres_data;
  d *= d;
  dt_x1 = (int32_t)( d / 65536 );
  dt_x1 = ( dt_x1 * CONST_MG ) >> 16;

  /* Complier problem? */
  /* dt_x2 = ( -7357 * i2c_baro_pres_data ) >> 16; */

  dt_x2 = ( CONST_MH * i2c_baro_pres_data ) >> 16;
  dt_x2 *= -1;

  /* pressure in Pa*/
  i2c_baro_pres_data += ( dt_x1 + dt_x2 + CONST_MI ) >> 4;
}



6.Monitorの紹介
 モニター機能の一部を紹介します(ここにも原型があります)。
 新たに全てを作るのは大変でしょうが、追加修正だけで使いまわししていると、Debugには欠かせないツールになりました。


7.ADCデータの正規化
 ADCデータは下記の様に入力し、正規化しました。

項目 ADCチャンネル ポイント 正規化の方法
Vref
バンドギャップ電圧
ch17 基準電圧は、データシートによると
1.202(min),1.224(typ),1.242(max)[V]
で限定出来ない
しかし、工場出荷時のデータがCPU内に保存されており
Vdd=3.00Vのデータが読み出せる
Bangap = 3.0 * VREF / 4096 [V]
-> Bandgap = ( 3000 * VREF(Factory) / 4096 ) [mV]
-> Bandgap = ( 3000000 * VREF(Factory) / 4096 ) / 1000 [mV]
-> Bandgap = ( 300000000 * VREF(Factory) / 4096 ) / 100000 [mV]
-> Bandgap = 7342 * VREF(Factory) / ( 1000 * 100 ) [mV]
-> Vbandgap = Bandgap * 100

VREF(Factory)はCPU内蔵データ
Bandgapは、他の電圧正規化に使用
Vbandgapは、電圧表示→今回の電圧 1.220Vとの測定結果となった
Temp
CPU内温度
ch16 CPU内温度だがまだ上手く正規化出来ていない ?(まだ納得できる正規化が出来ない)
Vdd
電源電圧
ch5 このポート(PA5)に、抵抗分圧して電源電圧を入力したが
Vrefから計算出来ることから不要とした
Vdd = ( Vbandgap * 4096 / adcdt_vref)/100 [mV]
-> Vdd_act = Vdd * 100

ch5での測定ではない
バンドギャップから測定が出来る!
Vtrim
ボリューム電圧
ch2 外部ボリュームの電圧で将来は、何らかの外部入力として使用
(例えば、電圧範囲によりLCD表示内容を変えるなど)
Vtrim = ( Vdd_act * adcdt_trim / 4096 ) / 100 [mV]
Vbatt
バッテリー電圧
ch1 太陽電池の発電電圧を測定する予定 Vbatt = ( Vdd_act * adcdt_batt / 4096 ) / 100 [mV]



8.電源電圧低下によるSTOPモード移行と復帰

今回の電源回路では、3つの電源電圧がそれぞれに影響を与えています。

  1. 太陽電池の発生電圧→Vsolar
  2. 電気二重層(120F/2.5Vを2個直列にしている為、60F/5V耐圧)の端子電圧→Vcap
  3. CPUへ供給される電源電圧→Vdd


1.充電制御とSTOPモード移行と復帰
 太陽電池Vsolarの電圧は、CPUが動作中は電気二重層Vcapと比較して充電可能な電圧であればトランジスタをONして充電します。
 もしもVsolarがV_CHARGE_MAX(header file stm32l_48pin.h内で5Vに設定)に達すると充電は停止します(vCheck_Vddタスク内)。
 また、VsolarがVSOLAR_GOTO_STOP_MODE(header file stm32l_48pin.h内で2.3Vに設定)以下に下がると、STOPモードに移行します。
 今回使用した太陽電池は5V出力ですが、室内照明では表示が継続しています。

 STOPモードからの復帰には3つの方法があります。

  1. 下記に説明するVddの電圧回復による割込み発生
  2. VsolarをPB5に接続して、CPU内蔵のコンパレータに入力し、基準値(今回はVref)を上回った時に割込みを発生させて復帰
  3. RESET割り込み(強制復帰だが、その後の動作はSTOPモードへの移行条件により、即STOPモードへ再移行の可能性あり)

 Vsolarでは上記2項によって制御し、復帰させています。
 方法は、下記の様にSTOPモード移行前に設定している。

/*-------- COMP --------*/
/* Set Recovery condition level */
COMP_Config(); COMPのクロックをENABLEしてPB5とVref比較に設定
/* Keep Vref active */
PWR_UltraLowPowerCmd( DISABLE ); Vrefを生かしたまま
/* Set IRQ by COMP */
STM32_Set_COMP_IRQ(); 割込み起動


2.Vcap
 電気二重層がそのままDC-DCコンバータの入力に接続されています。
 DC-DCコンバータは、ストロベリーリナックスの「TPS61200 超低電圧DC-DCコンバータモジュール(3.3V/5V)」を使用しています。
 このICは、0.3Vまで動作するので電気二重層に蓄えられている電荷が残っている間は出力3.3vを維持していますが、当然電圧が低下すると大電流が流れます。
 そこで、ある程度Vcapが残っている段階でSTOPモードに移行させ、Vcapでのバックアップを維持できるようにします。
 STOPモードへの移行は、VcapがVBAT_GOTO_STOP_MODE(header file stm32l_48pin.h内で0.6Vに設定)以下で行われます。
 現実には、Vsolarの電圧でSTOPモードへ移行する頻度が多いと思われます。

3.Vdd
 vChkVdd_Task内でCPU電源電圧をPVD機能を使って監視しています。
 PVDは内部Vref(バンドギャップ電圧)と電源電圧を比較してステータスを返す機能を持っていますので動作範囲を細かく設定出来ます。
 しかし、このVdd低下でのSTOPモード移行は最悪のパターンで上記VsolarとVcapでの制御が上手く行われている場合には、殆どあり得ません。

 vChkVdd_Task内では100mS毎に電源低下をPVDで監視し、一定値(V_GOTO_STOP_MODE:今回は2.1Vに設定している)以下で、Standby_and_wakeupを呼び出します。
 Standby_and_wakeupでは下記の処理が行われます。

 もしもVddが復帰した場合には二つの方法のどちらかのモードに入り、再度大気圧計としての動作を再開します。
 勿論、先に説明した3つのSTOPモードからの復帰が現実には優先されます。 

 上記、二つ目の復帰には少し問題があります。無限ループで電源復帰を待つにはSTOP状態と違い消費電流が増えます。
 この状態を回避するには、BORレベルを変更して例えば、2.3V to 2.49VのBOR Level 3に設定することが一番良いように思えますが、これにも問題があります。
 今度は(設定値を変えても)STOPモードに入らないか、より高い電圧でSTOPモードに入れるしかありません。


9.現時点での残務
 ソフトウェア関連の残務。





4 プログラム
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES


2013年5月5日
改良版を公開します。
ここに入れました。
STM32L152_48pin_FreeRTOS_Baro_wrk0.zip


注意点
WFI命令を使用している関係で、JTAG接続が上手くいきません。
そこでCPUをリセット状態としたままプログラムを開始し下記のタイミングでリセット解除をする必要があります。


TOP02_001.PNG - 934BYTES














































































































2013/1/6=1
2013/5/4 501