ctr_mcu/trunk/pm.c
n2232 cb2d809248 PM_sys_pow_off 異常終了時の不要なチェックコードの抜き忘れ
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_mcu@599 013db118-44a6-b54f-8bf7-843cb86687b1
2014-01-21 04:48:49 +00:00

1522 lines
41 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ========================================================
対PMIC
藤田@開技
nintendo
'08 Dec
$Id: pm.c 418 2011-09-22 01:35:37Z n2232 $
======================================================== */
#ifndef _WIN32
#pragma nop
#endif
#include "incs.h"
#include "adc.h"
#include "led.h"
#include "pm.h"
#include "renge\renge.h"
#include "batt_params.h"
#include <fsl.h>
#include "fsl_user.h"
#include "vreg_twl.h"
#include "i2c_mcu.h"
// ========================================================
u8 raw_adc_temperature;
BT_VENDER battery_manufacturer = BT_VENDER_NOT_CHECKED;
static u8 ntr_pm_reg_shadow; // NTR PMIC レジスタミラー
bit bt_authorized; // バッテリパラメータ送信済。充電開始許可
u8 chg_led_override; // アダプタ差したとき、充電するしないに関わらずしばらく点灯させる
static u16 bt_volt16;
static bit ntr_pm_bt_low_old;
bit BT_IN_CHG_delayed_n;
bit temp_zone_charge_disable; // 温度で充電停止する時にヒステリシスを付けるため
u8 pmic_version;
u8 mgic_version[2];
u8 pm_reg_bit_vddlcd;
static bt_param_* p_bt_param;
extern const bt_param_ bt_param[];
bit pm_extdc_old; // 前回アダプタチェックしたとき刺さっていたか?
u8 pmreg_v_core; // SoCのコア電圧設定。SNAKE(LAGER)で変更があるため。
// 充電停止温度関係
static u8 raw_temp_lh;
static u8 raw_temp_ll;
#define RAW_TEMP_HL 184 // 1
#define RAW_TEMP_HH 189 // -1
#define RAW_TEMP_LH_CTR 75 // 50 [degC]
#define RAW_TEMP_LL_CTR 61 // 59
#define RAW_TEMP_LH_SNAKE 84 // 45
#define RAW_TEMP_LL_SNAKE 68 // 54
// ========================================================
static void BT_model_detect();
static void BT_mgic_quick_start();
static void BT_mgic_init();
static void bt_chk_temparature();
static void bt_get_charge_status();
static void bt_param_select();
static void bt_batt_update_twl();
static void bt_batt_update_ntr();
static void update_chg_led();
// ラッパー
static err send_cmd_mgic_2B( u8 reg, u16 dat );
static err read_mgic_2B( u8 reg, u8* dat );
static err read_BT_SOC( u8* dest );
static err read_BT_voltage( u8* dest );
static u8 conv_ctr_bt_to_twl_bt();
// ========================================================
#define swap_endian_16( x ) (unsigned int)(( x << 8 ) | ( x >> 8 ))
// ========================================================
const u8 BT_MANUF_BORDER[] = {
5, 33, 79, 123, 158, 197, 233
};
/********************************************//**
電池の管理
以下のピンは主にここで操作・監視されます。
- PM_BT_AUTH 現状、GPI in
- PM_CHARGE_n CCIC /CHG in
- PM_EXTDC_n /DOK INTP4 in
- PM_CHARGE_EN_n /CEN out
以下の物は関係ありそうですが別のところで監視されています。
- LED Charge tsk_LED
- BT_TEMP,_P tsk_ADC
PM_EXTDCは割り込みメインにするかも
***********************************************/
#define INTERVAL_TSK_BATT 60
// ↑100だと充電エラー時にうまく点滅しないので
/********************************************//**
電源周りの監視
- アダプタの監視
- 充電制御、LED更新
- 残量取得、LED更新
***********************************************/
void tsk_batt( )
{
static u8 task_interval;
if( task_interval -- != 0 )
{
return;
}
else
{
task_interval = (u8)( INTERVAL_TSK_BATT / SYS_INTERVAL_TICK );
}
// アダプタステータス更新 //
pm_chk_adapter();
// 充電 //
bt_chk_temparature(); // 温度チェック
if( !temp_zone_charge_disable && bt_authorized && !PM_EXTDC_n )
{
BT_CHG_ENABLE(); // 温度範囲OKで充電再開
}
else
{
BT_CHG_DISABLE(); // 温度危険! 充電停止
}
bt_get_charge_status(); // 充電状況チェック
update_chg_led(); // chg led更新
// 電池残量 //
BT_get_left();
}
/********************************************//**
充電LED更新
- CCICが充電中といえば点灯する。
- でなくても、アダプタ刺したばかりなら5秒点灯する
- ただし、ヘタレ電池対応で嘘充電中の時、ヒューズ切れMGICがNAKなら消灯
***********************************************/
static void update_chg_led()
{
static bit temp_led_chg; // static つけないとコンパイル通らず
temp_led_chg = false;
// アダプタつないだ瞬間、満充電でも数秒わざと点灯させる。給電してることをわからせるため。
if( chg_led_override != 0 )
{
chg_led_override --;
temp_led_chg = true;
}
// CCIC は充電中と言っているか?
if( ! BT_IN_CHG_delayed_n // bt_get_charge_status()で更新されます。
&& ! PM_EXTDC_n )
{
temp_led_chg = true;
}
LED_CHARGE = temp_led_chg;
// レジスタの充電中ビットはLEDに同期する
set_bit_if( LED_CHARGE, vreg_ctr[VREG_C_STATUS], REG_BIT_BATT_CHARGE ); // set_bit_ifのみ。
/// 割り込みはtask_status()で行う
}
/********************************************//**
温度チェック
温度付きヒステリシス有り
***********************************************/
#define AVG_COUNT 40
void bt_chk_temparature()
{
static u8 heikinka_h,heikinka_l;
if(( raw_temp_lh <= raw_adc_temperature )
&& ( raw_adc_temperature <= RAW_TEMP_HL ))
{
if( heikinka_h < AVG_COUNT )
{
heikinka_h++;
}
else
{
temp_zone_charge_disable = false; // 充電許可
}
}
else if(( raw_adc_temperature <= raw_temp_ll )
|| ( RAW_TEMP_HH <= raw_adc_temperature ))
{
if( heikinka_l < AVG_COUNT )
{
heikinka_l++;
}
else
{
temp_zone_charge_disable = true; // 充電禁止
}
}
else
{
// temp_zone_charge_disable そのまま
heikinka_h = 0;
heikinka_l = 0;
}
}
/********************************************//**
充電中かのチェック
充電ICのバグ対策も行う。
***********************************************/
#define TIME_DENOIZE (u8)( 1000 / INTERVAL_TSK_BATT )
void bt_get_charge_status()
{
// CCICの不具合回避のため、/CHGのネゲートをちょっと丁寧に遅延させる
static u8 anti_chatter;
if( !BT_IN_CHG_n )
{
// さらにチャタリング除去
if( anti_chatter < 2 ) // 電池無しでアダプタさして、電極をさわさわ
{ // すると充電LEDががさがさするので
anti_chatter++;
}
else
{
BT_IN_CHG_delayed_n = 0; // 充電中
}
}
else
{
if( !BT_CHG_Ena_n
&& ( vreg_ctr[ VREG_C_BT_REMAIN ] < 60 )
&& !( is_mgic_error )
)
{
BT_IN_CHG_delayed_n = 0; // 充電中と扱う。充電が終わっているはずがない
}
else
{
BT_IN_CHG_delayed_n = 1;
anti_chatter = 0;
}
}
}
/********************************************//**
アダプタの有無チェック
***********************************************/
void pm_chk_adapter()
{
set_bit_if( !PM_EXTDC_n, vreg_ctr[VREG_C_STATUS], REG_BIT_POW_SUPPLY );
if( pm_extdc_old != PM_EXTDC_n ) // HAL を通すため、 PM_EXTDC_n の volatile にする心配なし
{
pm_extdc_old = PM_EXTDC_n;
if( !PM_EXTDC_n )
{
// 刺さった
set_irq( VREG_C_IRQ1, REG_BIT_BT_DC_CONNECT );
chg_led_override = (u8)( 2500 / INTERVAL_TSK_BATT ); // bt_chckのwait_ms(5)のせいで伸ばされる。
}
else
{
u8 temp_v[2];
// 抜けた
set_irq( VREG_C_IRQ1, REG_BIT_BT_DC_DISC );
chg_led_override = 0;
// 電池残量が1%台で、アダプタ有りの時には本体が起動し、ゲームが動くが
// 1%台に回復する前にアダプタが抜けたとき、割り込みを入れないと期待通りの
// 動作でない。特別対応のためここで対応
if( read_mgic_2B( BT_GAUGE_REG_VCELL, temp_v ) == ERR_SUCCESS )
{
bt_volt16 = ( temp_v[0] * 256 + temp_v[1] );
}
if(( bt_volt16 < V_TH_ZERO ) || ( vreg_ctr[ VREG_C_BT_REMAIN ] == 0 ))
{
set_irq( VREG_C_IRQ1, REG_BIT_BT_REMAIN );
}
}
}
}
/********************************************************
電池関係の初期化
   ゲージ  | 有り     | 無し
  ーーーーーーーーーーーーーーーーーーーーーーー
   電池 有り| 実機     | ?
  ーーーーーーーーーーーーーーーーーーーーーーー
      無し| 白箱     | TS
        | 実機電池無し |
  ーーーーーーーーーーーーーーーーーーーーーーー
  ゲージ有り、電池無し の白箱/実機判別は、
 電池温度で判定する
返値: 電池無し 0xFF
電池変わってない 0
電池変わった 1
***********************************************************/
bit bt_force_update;
/********************************************//**
バッテリのチェック、と、本体種別識別(ピンを共用のため)
***********************************************/
void BT_chk()
{
static BT_VENDER battery_manufacturer_old;
battery_manufacturer_old = battery_manufacturer;
BT_model_detect();
bt_param_select(); // バッテリ残量補正パラメータなどセット 非実機でも、とりあえずの値(パナ)指定にしておく。
if( system_status.model != MODEL_JIKKI )
{
bt_authorized = false;
return;
// おしまい
}
if(( battery_manufacturer_old != battery_manufacturer ) ||
bt_force_update )
{
bt_force_update = false;
iic_mcu_start( ); // 中で初期化フラグをもってるので呼びまくって良い こんなところに…orz
if( (( battery_manufacturer_old == BT_VENDER_OPEN ) ||
( battery_manufacturer_old == BT_VENDER_NOT_CHECKED )) &&
!system_status.reboot )
{
BT_mgic_quick_start();
}
BT_mgic_init(); // 機種判定も行います
}
bt_authorized = true;
renge_task_immed_add( tski_BT_temp_update ); // 電池温度監視
}
/********************************************//**
本体種別識別
***********************************************/
void BT_model_detect()
{
u8 temp;
BT_DET_P = 1;
BT_TEMP_P = 1;
wait_ms( 3 ); // 電圧が上がるのに時間が掛かる
raw_adc_temperature = get_adc( ADC_SEL_BATT_TEMP );
temp = get_adc( ADC_SEL_BATT_DET );
BT_DET_P = 0;
system_status.captureBox = false;
// プラットフォーム判定 //
if( raw_adc_temperature > 0xF0 )
{
// TS //
system_status.model = MODEL_TS_BOARD;
system_status.family = FAMILY_CTR; // 旧回路での誤判定を上書き
pm_reg_bit_vddlcd = PM_REG_BIT_VDDLCD_CGS;
// set_voltages( system_status.family ); 不要?
}
else if( raw_adc_temperature < 4 )
{
// 白箱 //
system_status.model = MODEL_SHIROBAKO;
// もしかして:キャプチャボード //
if( iic_mcu_read_a_byte( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_VERSION ) == 0x01 )
{
if( iic_mcu_result == I2C_ERR_OK ) // バラに書かないと評価順が処理系依存
{
system_status.captureBox = true;
}
}
}
else
{
// 実機、残量IC NACK( バッテリ無しまたは残量IC故障 )
system_status.model = MODEL_JIKKI; // バッテリ無しの時は↓で上書きする
}
// TSのhomeボタン、実機は未接続なので要端子処理 /// gndにしとけばよかった…
if( system_status.model == MODEL_TS_BOARD )
{
PM_SW_HOME_n_TSBOARD = 1;
}
else
{
PM_SW_HOME_n_TSBOARD = 0;
SW_HOME_n_TSBOARD_RAW = 0; /// 実機open どっちでもいいんだけど
}
// 電池メーカーの識別 //
{
u8 i;
battery_manufacturer = BT_VENDER_OPEN; // デフォルト値
for(i=0; i<=7; i++)
{
if( temp <= BT_MANUF_BORDER[ i ] )
{
battery_manufacturer = (BT_VENDER)i;
break;
/*
BT_VENDER_MAXELL; // = 0
BT_VENDER_1;
BT_VENDER_2;
BT_VENDER_3;
BT_VENDER_4;
BT_VENDER_PANA;
BT_VENDER_6;
BT_VENDER_OPEN;
*/
}
}
}
if( ( battery_manufacturer == BT_VENDER_OPEN ) &&
( system_status.model == MODEL_JIKKI ) )
{
system_status.model = MODEL_JIKKI_NOBATT;
}
}
#define MGIC_CMD_QUICKSTART 0x4000
/********************************************//**
MGICクイックスタート主にバグ対策
***********************************************/
static void BT_mgic_quick_start()
{
wait_ms( 10 ); // MGICの起動に掛かる
// 0. バッテリ残量IC クイックスタート
send_cmd_mgic_2B( BT_GAUGE_REG_MODE, swap_endian_16( MGIC_CMD_QUICKSTART ) );
wait_ms( 150 );
}
/********************************************//**
電池残量測定初期化
電池パラメータなども転送する
***********************************************/
#define MGIC_CMD_UNLOCK_KEY 0x4A57
#define MGIC_CMD_RESET 0x5400
#define K_RCOMP_SEG 0x0080
#define RCOMP_SIZE 16
static void BT_mgic_init()
{
u8 origParam[4];
/*
// -1. リセットをかけてみる
かけちゃだめ!
i2c_send_buff_2B._u16 = swap_endian_16( MGIC_CMD_RESET );
send_cmd_mgic_2B( BT_GAUGE_REG_COMMAND ); // こいつはNACKを返す
*/
if( system_status.model != MODEL_JIKKI )
{
return;
// おしまい
}
// 1. ロック解除
if( send_cmd_mgic_2B( BT_GAUGE_REG_LOCK, swap_endian_16( MGIC_CMD_UNLOCK_KEY ) ) != ERR_SUCCESS )
{
// 残量IC NACK
vreg_set_mgic_error;
return;
// おしまい
}
vreg_clear_mgic_error;
// wait_ms( 5 + 1 ); 前にウェイト入れてるので不要
// 2. 初期パラメータを一時保存
iic_mcu_read( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 4, origParam );
// 3. 一時的にOCVを変更
send_cmd_mgic_2B( BT_GAUGE_REG_OCV, swap_endian_16( p_bt_param->ocv )); // マジックナンバー的なもの。メーカー指定
// 4. 一時的にRCOMPを変更
send_cmd_mgic_2B( BT_GAUGE_REG_RCOMP, swap_endian_16( 0xFF00 ) );
// 5.メーカー別パラメータのロード
{
u8 loop;
// 16バイトごとに区切れとのこと イズ対策とか言うんだけど、意味あるんか
for( loop = 0; loop < 4; loop ++ )
{
iic_mcu_set_wo_dma( );
iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_BT_PARAM + loop*16, 16, p_bt_param->mg_param + loop*16 );
}
}
{
// 5.1 拡張 RCOMP を更新しておく。
// 基本不要だが、不意に書き換わってしまったときのため、規定値を書く。
// 17048 で必要。17040CTR) に書いてしまっても不具合なし。
u8 loop;
short param[RCOMP_SIZE];
for( loop=0; loop < RCOMP_SIZE; loop++ )
{
param[loop] = swap_endian_16(K_RCOMP_SEG);
}
iic_mcu_set_wo_dma( );
iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP_EXT, sizeof(param), param );
}
// 6. 150ms以上待つ
wait_ms( 150 + 15 );
// 7. OCVに「とある値」を書く
send_cmd_mgic_2B( BT_GAUGE_REG_OCV, swap_endian_16( p_bt_param->ocv ) ); // マジックナンバー的なもの。メーカー指定
// 8. 150600ms待つ。600msは厳守
wait_ms( 150 + 15 );
// 9. SOCを読む。ベリファイのため。
{
u8 temp;
temp = iic_mcu_read_a_byte( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_SOC );
if(( p_bt_param->verify.low <= temp ) && ( temp <= p_bt_param->verify.hi ))
{
// カスタムモデル書き込みOK
}else{
// 失敗だったらリトライするのか?
// dbg_nop();
}
}
// 10.元のRCOMPとOCVを書き戻す
iic_mcu_write( IIC_SLA_BT_GAUGE, BT_GAUGE_REG_RCOMP, 4, origParam );
// 11. ロック
send_cmd_mgic_2B( BT_GAUGE_REG_LOCK, swap_endian_16( 0x0000 ) ); // lock key
}
extern u16 _dbg_rcomp;
/********************************************//**
raw_adc_temperatureに入っている値を℃に変換するとともに、
- レジスタにセット
- 残量ICにセット
***********************************************/
task_status_immed tski_BT_temp_update( )
{
static u8 rawdat_old;
static s8 temperature;
s16 newrcomp;
static u8 heikinka;
/*
サーミスタ - 10kΩ分圧点の時、
常用温度では分圧比のカーブがほぼリニアで、
村田 T[℃] = 81.48 - 111.97 x ratio
TDK T = 81.406 - 111.81 x ratio
*/
if( rawdat_old != raw_adc_temperature )
{
if( heikinka < 40 )
{
heikinka ++;
}
else
{
heikinka = 0;
rawdat_old = raw_adc_temperature;
// temperature = 81.45 - 111.9 * raw_adc_temperature/256.0;
// それぞれ256倍してある
temperature = (u8)(( 20851 - 112 * raw_adc_temperature + (256/2) ) /256);
vreg_ctr[VREG_C_BT_TEMP] = temperature;
newrcomp = 0;
if( temperature > 20 )
{
newrcomp = ( ( temperature - 20 ) * p_bt_param->rcomp.up )/256;
}
else
{
newrcomp = ( ( temperature - 20 ) * p_bt_param->rcomp.down )/256;
}
newrcomp = p_bt_param->rcomp.rcomp + newrcomp;
if( newrcomp > 255 )
{
newrcomp = 255;
}
if( newrcomp < 0 )
{
newrcomp = 0;
}
_dbg_rcomp = newrcomp;
if( send_cmd_mgic_2B( BT_GAUGE_REG_RCOMP, newrcomp ) == ERR_SUCCESS ) // swap不要
{
rawdat_old = raw_adc_temperature;
}
else
{
vreg_set_mgic_error;
}
}
}
return ( TSKI_FINISHED );
}
/********************************************//**
電池残量ICから残量を取得し、レジスタに書き込む。
 電池残量ICが無い・故障などの時はとりあえず残量99%とする。
        ↑は status_1で確認可能。電源投入時にチェックしています。
 BT_chk()が実行されている必要があります。
***********************************************/
void BT_get_left(){
u8 temp[2];
u8 reg_volatile_temp_bt_remain,reg_volatile_temp_bt_remain_fine; // I2Cの非同期読み込みでのちらつき防止 キャップ処理の所為
u8 fuel_cap_by_voltage; // 電圧でキャップに使う
// 電池残量
if( system_status.model == MODEL_TS_BOARD
|| system_status.model == MODEL_SHIROBAKO )
{
// TS & 白箱 //
if( read_BT_SOC( temp ) == ERR_SUCCESS )
{
reg_volatile_temp_bt_remain = temp[0];
reg_volatile_temp_bt_remain_fine = temp[1];
}
else
{
// エミュレーション機能がおかしい
//  それで電源断は不便すぎるだろう
reg_volatile_temp_bt_remain = 99;
reg_volatile_temp_bt_remain_fine = 0;
}
}
else
{
// 実機 //
// 残量リード
if( read_BT_SOC( temp ) != ERR_SUCCESS )
{
// 残量ICがNACK …バッテリはずれた
vreg_set_mgic_error;
bt_authorized = false;
reg_volatile_temp_bt_remain = 0;
force_off = true;
}
else
{
u16 temp_u16;
vreg_clear_mgic_error;
// バッテリパラメータの関係でビットシフトが必要
temp_u16 = temp[0] * 256 + temp[1];
temp_u16 /= p_bt_param->v_scale;
reg_volatile_temp_bt_remain = (u8)(( temp_u16 >> 8 ) & 0xFF );
if( reg_volatile_temp_bt_remain == 0 )
{
// 0%台の時は1.00%に上げ底
// 充電開始後もしばらくは電池残量が減るので
// 0%に到達してしまうことがあるのだ
reg_volatile_temp_bt_remain = 1;
reg_volatile_temp_bt_remain_fine = 0;
}
else
{
reg_volatile_temp_bt_remain_fine = (u8)(temp_u16 & 0xFF);
}
#ifdef _DBG_BT_FULL_
reg_volatile_temp_bt_remain = 100;
reg_volatile_temp_bt_remain_fine = 0;
#endif
}
}
// 電池電圧
{
if( read_BT_voltage( temp ) != ERR_SUCCESS ) // 2byte read
{
temp[0] = (u8)( V_BT_4000MV / 256 ); // 電池電圧読めなかったら4000mVだったことにしておく。
temp[1] = 0;
}
vreg_ctr[ VREG_C_BT_VOLTAGE ] = temp[0];
bt_volt16 = ( temp[0] * 256 + temp[1] );
}
// 電圧でキャップ...の準備
{
static u16 hysteresis;
if( bt_volt16 > V_TH_30 )
{
fuel_cap_by_voltage = 100;
hysteresis = 0;
}
else if( bt_volt16 - hysteresis > V_TH_LO ) // 測定値からヒステリシス分引いてる。読むとき注意。
{
fuel_cap_by_voltage = 30;
hysteresis = 0;
}
else if( bt_volt16 > V_TH_EMPTY )
{
fuel_cap_by_voltage = BATT_TH_LO; // ここから赤
hysteresis = 500;
}
else if( bt_volt16 > V_TH_ZERO )
{
fuel_cap_by_voltage = BATT_TH_EMPTY;
hysteresis = 500;
}
else if( bt_volt16 > V_TH_FORCE_OFF )
{
fuel_cap_by_voltage = 0;
hysteresis = 500;
}
else
{
force_off = true;
hysteresis = 500;
}
}
// 充電許可(=アダプタも刺さってる)のに充電してない
// かつ、少なくとも素の電池残量が60%以上CCICバグ回避、BT_IN_CHG_delayed_nに織り込み済み
// = 充電完了。電池がへたってくるとMGICが100%を返さない
if( !BT_CHG_Ena_n && BT_IN_CHG_delayed_n ){
reg_volatile_temp_bt_remain = 100;
reg_volatile_temp_bt_remain_fine = 0;
}
else
{ // 電圧でのキャップを掛けるか?
if( fuel_cap_by_voltage < reg_volatile_temp_bt_remain )
{
reg_volatile_temp_bt_remain = fuel_cap_by_voltage;
reg_volatile_temp_bt_remain_fine = 0;
}
}
/*
十分に問題ない電圧が供給されてるらしいのでケアせずでよし
if( system_status.taikendai_nbd && system_status.model != MODEL_TS_BOARD ) // 電池端子に電源がつながってて値が不正なため上書き。
{
reg_volatile_temp_bt_remain = 100;
}
*/
vreg_ctr[ VREG_C_BT_REMAIN ] = reg_volatile_temp_bt_remain;
vreg_ctr[ VREG_C_BT_REMAIN_FINE ] = reg_volatile_temp_bt_remain_fine;
// twlのレジスタ更新 (CTRに割り込み入れる前に更新しないと割り込みのタイミングがまずいかもしれない)
bt_batt_update_twl();
// 残量で割り込み。急激に減ると飛ぶことがある //
{
static u8 bt_remain_old_ctr;
if( bt_remain_old_ctr != reg_volatile_temp_bt_remain )
// CTRに通知
{
if( (( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_LO ) && ( BATT_TH_LO < bt_remain_old_ctr ))||
(( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_EMPTY ) && ( BATT_TH_EMPTY < bt_remain_old_ctr ))||
(( vreg_ctr[ VREG_C_BT_REMAIN ] == 0 ) && ( bt_remain_old_ctr != 0 )) )
{
set_irq( VREG_C_IRQ1, REG_BIT_BT_REMAIN );
}
}
bt_remain_old_ctr = vreg_ctr[ VREG_C_BT_REMAIN ];
}
// PMIC-NTRに電池残量を教えてあげる
bt_batt_update_ntr();
}
/********************************************//**
液晶系の電源制御
 ステータスフラグはすぐに立ててしまう。
 不感応時間があるし、
起動失敗であれば電源が落ちる
別のタスクで電源落ちは監視していて、ステータスもクリアする
***********************************************/
err PM_LCD_on( )
{
err rv = ERR_ERR;
PM_VDDLCD_on( ); // 内部で CGS と AMO 切り替えてます
if( system_status.LCD_is_CGS == true )
{
// CTR 時
wait_ms( DELAY_PM_TSS_50B_AND_TCOM );
}
else
{
// SPFL/SNAKE ならアモルファスHV on を間に挟む
wait_ms( 10 );
LCD_AMOL_HV_CTRL = 1;
wait_ms( DELAY_PM_TSS_50B_AND_TCOM - 10 );
}
PM_TCOM_on( );
wait_ms( DELAY_PM_TCOM_TO_VCS );
PM_VCS_on( );
wait_ms( DELAY_PM_VCS_TO_BL );
if( PM_chk_LDSW() != 0 ) // 正常パス
{
// 電源起動エラーなら電源も切れてしまう。ここではケアしない
vreg_ctr[VREG_C_STATUS] |= REG_BIT_LCD_POW;
set_irq( VREG_C_IRQ3, REG_BIT_LCD_ON );
rv = ERR_SUCCESS;
}
return rv;
}
void PM_LCD_off()
{
// BLついてたら消す。// チェックするのは割り込みの関係
if( ( read_pmic( PM_REG_ADRS_BL ) & 0x03 ) != 0 )
{
u8 tot;
PM_BL_set( REG_BIT_CMD_BL_U_OFF | REG_BIT_CMD_BL_L_OFF );
vreg_ctr[VREG_C_STATUS] &= bits8(1,0,0,1, 1,1,1,1);
if( (( REG_BIT_BL_U_OFF | REG_BIT_BL_L_OFF ) & ~vreg_ctr[ VREG_C_IRQ_MASK3 ] ) != 0 )
{
vreg_ctr[ VREG_C_IRQ3 ] |= ( ( REG_BIT_BL_U_OFF | REG_BIT_BL_L_OFF ) & ~vreg_ctr[ VREG_C_IRQ_MASK3 ] );
IRQ0_neg;
tot = 0;
while( !IRQ0 && ( ++tot != 0 ) ){;}
IRQ0_ast;
}
vreg_ctr[VREG_C_COMMAND2] &= ~( REG_BIT_CMD_BL_U_OFF | REG_BIT_CMD_BL_L_OFF );
}
// 50msとか待つし、確認しましょうかね…
if( read_pmic( PM_REG_ADRS_VDD_LCD ) != 0 )
{
PM_TCOM_off();
wait_ms( 1 );
PM_TCOM_VCS_off( );
wait_ms( DELAY_PM_LCD_OFF );
if( system_status.LCD_is_CGS == false )
{
// アモルファスならポート操作
LCD_AMOL_HV_CTRL = 0; // 他のファミリでもL縛りなので弊害なし
wait_ms( 10 ); // アモルファス15Vを切ったときのウェイト。
}
PM_VDDLCD_off( ); // 残ってたの全部止めます。
vreg_ctr[VREG_C_STATUS] &= ~REG_BIT_LCD_POW;
}
set_irq( VREG_C_IRQ3, REG_BIT_LCD_OFF ); // 無条件に発生。マスク無ければ。
}
/********************************************//**
 バックライトの個別on/off
 現状から on/off/維持 のフラグなので面倒
 BL on/on の状態で、on/onにしろと言われても、on/on割り込みを入れます。
***********************************************/
err PM_BL_set( u8 dat )
{
u8 blset; // PMIC レジスタに書き込む値
u8 intset = 0; // 割り込みレジスタに反映する値
// RMWを行う
// Read
blset = read_pmic( PM_REG_ADRS_BL );
// Modify
// 上画面
if(( dat & REG_BIT_CMD_BL_U_ON ) != 0 )
{
blset |= PM_REG_BIT_BL_U;
intset |= REG_BIT_BL_U_ON;
}
else if(( dat & REG_BIT_CMD_BL_U_OFF ) != 0 )
{
blset &= ~PM_REG_BIT_BL_U;
intset |= REG_BIT_BL_U_OFF;
}
// 下画面
if(( dat & REG_BIT_CMD_BL_L_ON ) != 0 )
{
blset |= PM_REG_BIT_BL_L;
intset |= REG_BIT_BL_L_ON;
}
else if(( dat & REG_BIT_CMD_BL_L_OFF ) != 0 )
{
blset &= ~PM_REG_BIT_BL_L;
intset |= REG_BIT_BL_L_OFF;
}
if( system_status.family == FAMILY_FLOWER )
{
// パネルが一枚なので、off/off でなければ点灯、LX1未接続側を立ち上げない
// ただし、割り込みは嘘をついて SoC が設定したと思い込んだ値にする。
// todo: 要周知。
if( blset != 0 )
{
blset = PM_REG_BIT_BL_L;
}
}
// write
if( blset != 0 ) // BLを付ける場合はウェイトを挟まないとPWMが来ておらず
// シャットダウンすることがある
{
wait_ms( 16 + 10 );
}
send_cmd_pmic( PM_REG_ADRS_BL, blset );
// SoCがPWMを出すようレジスタをセットしてから遅延が有るため、ステータスを先に
// 更新してしまう。してほしいとの要求。
// PMICのBLのビットと、MCUのSTATUSレジスタのビット位置が逆なため入れ替え
vreg_ctr[VREG_C_STATUS] = (( vreg_ctr[VREG_C_STATUS] & bits8(1,0,0,1, 1,1,1,1) )
| ( (( blset << 6 ) | ( blset << 4 )) & bits8(0,1,1,0, 0,0,0,0) ));
// 割り込み
/// 複数ビットまとめて行うので、set_irq()使わない方が無難
{
u8 tot;
if( ( intset & ~vreg_ctr[ VREG_C_IRQ_MASK3 ] ) != 0 )
{
vreg_ctr[ VREG_C_IRQ3 ] |= ( intset & ~vreg_ctr[ VREG_C_IRQ_MASK3 ] );
IRQ0_neg;
tot = 0;
while( !IRQ0 && ( ++tot != 0 ) ){;}
IRQ0_ast;
}
}
return( ERR_SUCCESS ); // ここでは異常チェック不要
}
/********************************************//**
液晶の対向電圧の設定を行います。
仮想レジスタの内容を送るだけ
***********************************************/
void PM_LCD_vcom_set( )
{
send_cmd_pmic( PM_REG_ADRS_POW_DAC1, vreg_ctr[VREG_C_VCOM_T] ); // がっかりなことに、PMICはバースト書き込み不可
send_cmd_pmic( PM_REG_ADRS_POW_DAC2, vreg_ctr[VREG_C_VCOM_B] );
return;
}
/********************************************//**
↑で、レジスタ書き込みから呼び出される時のため
 I2Cの取り合いの関係でここから呼ぶ
***********************************************/
task_status_immed tski_vcom_set( )
{
PM_LCD_vcom_set( );
return ( TSKI_FINISHED );
}
void set_vdd_voltages( enum family_ family )
{
if(( family == FAMILY_SNAKE ) || ( family == FAMILY_CLOSER ))
{
// SNAKE
pmreg_v_core = PM_REG_BIT_VDD1P_1R00;
}
else
{
// NORMAL
pmreg_v_core = PM_REG_BIT_VDD1P_1R15;
}
}
/********************************************//**
シーケンスの通り電源を立ち上げてゆきます。
- 返値 0 最後まで正常に完了した。
- 1 ショートなどで電源があがりきらなかった
***********************************************/
err PM_sys_pow_on( )
{
// 電源順次立ち上げ
// PM_reset_ast( ); 不要 PM_LDSW_onまかせ
RESET2_ast;
FCRAM_RST_ast;
GYRO_DISABLE();
PM_LDSW_on( );
wait_ms( 1 + DELAY_PM_TW_PWUP );
PM_VDD_normMode();
PM_VDD_on( );
// wait_ms( DELAY_PM_TW_PWUP ); // GYROを挟むため
wait_ms( 10 );
GYRO_ENABLE();
wait_ms( DELAY_PM_TW_PWUP - 10 );
PM_VDD50A_on( ); // 液晶電源ではなく、ledに使う
wait_ms( DELAY_PM_TW_PWUP );
// 無事電源が起動したかチェック。
if( !PM_chk_LDSW() )
{
return ( ERR_ERR ); // reset1はほっといて良い
}
// 電源周りIC情報
pmic_version = read_pmic( PM_REG_ADRS_VER );
read_mgic_2B( BT_GAUGE_REG_VERSION, mgic_version );
return ( ERR_SUCCESS );
}
void reset_release()
{
// リセット解除など。システム起動!
PM_reset_neg();
FCRAM_RST_neg;
RESET2_neg;
codec_reg_init(); // CODEC 不定レジスタ初期化(reset2の後でないといけないので)
ntr_pm_reg_shadow = 0; //  〃 こんなところで...
}
/********************************************//**
電源OFFシーケンス
***********************************************/
void PM_sys_pow_off( )
{
// 一応 LCD 関係消すのを試みる。
PM_BL_set( REG_BIT_CMD_BL_U_OFF | REG_BIT_CMD_BL_L_OFF );
PM_LCD_off(); // 消えてれば何もしない
wait_ms( 20 );
PM_reset_ast();
RESET2_ast;
FCRAM_RST_ast;
wait_ms( 20 );
PM_off( );
PM_LDSW_off( );
}
/********************************************//**
extDC割り込み
電源OFFから起こす充電の温度監視のためのみ
普段はポーリング(pm)
***********************************************/
__interrupt void intp4_extdc( )
{
}
/********************************************//**
フタ開け閉め割り込み
普段はポーング(misc)
***********************************************/
__interrupt void intp5_shell( )
{
;
}
/********************************************//**
旧PMICへのコマンド書き込み
***********************************************/
__interrupt void intp6_PM_irq( )
{
EI();
if( system_status.pwr_state == ON )
{
renge_task_immed_add( tski_ntr_pmic_comm );
}
}
/********************************************//**
CODECからの割り込みを受けて、NTR PMIC互換レジスタからリード
***********************************************/
task_status_immed tski_ntr_pmic_comm( )
{
u8 reg1_old;
u8 irq_work = 0;
reg1_old = ntr_pm_reg_shadow;
ntr_pm_reg_shadow = iic_mcu_read_a_byte( IIC_SLA_CODEC, CODEC_REG_PM );
if( iic_mcu_result != ERR_SUCCESS )
{
return ( TSKI_FINISHED );
}
// DI( );
// バックライト 上 ////////////////////////////////////
if( ( ( reg1_old ^ ntr_pm_reg_shadow ) & REG_BIT_TWL_REQ_BL_U ) != 0 )
{
if( ( ntr_pm_reg_shadow & REG_BIT_TWL_REQ_BL_U ) == 0 ) // 消えた
{
irq_work = REG_BIT_TWL_BL_U_OFF;
}
else
{
irq_work = REG_BIT_TWL_BL_U_ON;
}
}
// バックライト 下
if( ( ( reg1_old ^ ntr_pm_reg_shadow ) & REG_BIT_TWL_REQ_BL_L ) != 0 )
{
if( ( ntr_pm_reg_shadow & REG_BIT_TWL_REQ_BL_L ) == 0 ) // 消えた
{
irq_work |= REG_BIT_TWL_BL_L_OFF;
}
else
{
irq_work |= REG_BIT_TWL_BL_L_ON;
}
}
// EI();
vreg_ctr[ VREG_C_STATUS_1 ] = ( vreg_ctr[ VREG_C_STATUS_1 ] & ~REG_BIT_MASK_STATUS1_NTR_PM_REG )
| ( ntr_pm_reg_shadow & REG_BIT_MASK_STATUS1_NTR_PM_REG ); // TWLバックライト情報のミラー
irq_work &= ~vreg_ctr[ VREG_C_IRQ_MASK2 ];
// set_irq 相当品
if( irq_work != 0 )
{
u8 tot;
vreg_ctr[ VREG_C_IRQ2 ] |= irq_work;
IRQ0_neg; // 一瞬上げてパルスを送り直す
tot = 0;
while( !IRQ0 && ( ++tot != 0 ) ){;} // O.Dなのでちゃんとあがるのを待つ IRQ_mcu がLに縛られてると困る(基板不良)
IRQ0_ast;
}
/// バックライト、気を利かせて消したりしません。
// offリクエスト //////////////////////////////////////
if( ( ntr_pm_reg_shadow & REG_BIT_TWL_REQ_OFF_REQ ) != 0 )
{
set_irq( VREG_C_IRQ2, REG_BIT_TWL_OFF_REQ );
}
// リセットリクエスト /////////////////////////////////
if( ( ntr_pm_reg_shadow & REG_BIT_TWL_REQ_RST_REQ ) != 0 )
{
set_irq( VREG_C_IRQ2, REG_BIT_TWL_RESET_REQ );
}
// バックライトをマスクして書き戻す
EI( );
if( ( ntr_pm_reg_shadow & ( REG_BIT_TWL_REQ_OFF_REQ | REG_BIT_TWL_REQ_RST_REQ )) != 0 )
{
ntr_pm_reg_shadow &= ~( REG_BIT_TWL_REQ_OFF_REQ | REG_BIT_TWL_REQ_RST_REQ );
iic_mcu_write_a_byte_codec( CODEC_REG_PM, ntr_pm_reg_shadow );
}
return ( TSKI_FINISHED );
}
/********************************************//**
command2 液晶系
  ラッパー的な物。ERR_SUCCESSしか返さないが…
***********************************************/
task_status_immed tski_PM_LCD_on()
{
PM_LCD_on();
return( TSKI_FINISHED );
}
task_status_immed tski_PM_LCD_off()
{
PM_LCD_off();
return( TSKI_FINISHED );
}
task_status_immed tski_PM_BL_set()
{
u8 cmd_BL; // ↓volatileとか付けなくても大丈夫みたい
do
{
cmd_BL = vreg_ctr[VREG_C_COMMAND2];
PM_BL_set( cmd_BL ); // マスク済み
}
while( cmd_BL != vreg_ctr[VREG_C_COMMAND2] ); // <- PM_BL_setが更新する
vreg_ctr[VREG_C_COMMAND2] = 0;
return( TSKI_FINISHED );
}
/********************************************//**
 reset2 で CODEC にリセットがかかり、レジスタが不定になるため
***********************************************/
void codec_reg_init()
{
wait_ms( 100 );
ntr_pm_bt_low_old = conv_ctr_bt_to_twl_bt();
iic_mcu_write_a_byte_codec( CODEC_REG_BT, (u8)ntr_pm_bt_low_old ); // SoC から書けず
vol_reset();
// renge_task_immed_add( tski_vol_update ); ポーリングするので。
vol_polling = 3;
}
/********************************************//**
ヘルパーというかラッパーというか?
ROM節約のため
***********************************************/
err send_cmd_mgic_2B( u8 reg, u16 dat )
{
u16 temp = dat; // 送信バッファ
return iic_mcu_write( IIC_SLA_BT_GAUGE, reg, 2, &temp ); // DMA転送するので送信データバッファのポインタがどうせ必要
}
err read_mgic_2B( u8 reg, u8* dat ) // 送信バッファは固定
{
return iic_mcu_read( IIC_SLA_BT_GAUGE, reg, 2, dat );
}
err send_cmd_pmic( u8 reg, u8 dat )
{
return iic_mcu_write_a_byte( IIC_SLA_PMIC, reg, dat );
}
u8 read_pmic( u8 reg )
{
return iic_mcu_read_a_byte( IIC_SLA_PMIC, reg );
}
/********************************************//**
電池メーカーとモデルから、使う電池パラメータの決定
***********************************************/
void bt_param_select()
{
BT_TYPE bt_type_temp;
// バッテリメーカー識別
if( battery_manufacturer <= BT_VENDER_3 ) // 余裕を持って中間に閾値をとる
{
bt_type_temp = BT_PARAM_CTR_MAXELL;
}
else
{
bt_type_temp = BT_PARAM_CTR_PANA;
}
// モデル識別
switch( system_status.family )
{
case( FAMILY_SPFL ): bt_type_temp += BT_PARAM_SPFL_MAXELL; break; // オフセット 残念な実装で…。
case( FAMILY_SNAKE ): bt_type_temp += BT_PARAM_SNAKE_MAXELL; break;
case( FAMILY_CLOSER ): bt_type_temp += BT_PARAM_SPFL_MAXELL; break;
case( FAMILY_CTR ):
case( FAMILY_FLOWER ): // CTR と同じ
default: /* bt_type_temp そのまま */ break;
}
p_bt_param = &bt_param[ bt_type_temp ];
// 充電停止温度の設定
/// 後付けなのと、分岐が少ないのでこういう実装
if(( system_status.family == FAMILY_SNAKE ) ||
( system_status.family == FAMILY_CLOSER ))
{
raw_temp_lh = RAW_TEMP_LH_SNAKE;
raw_temp_ll = RAW_TEMP_LL_SNAKE;
}
else
{
raw_temp_lh = RAW_TEMP_LH_CTR;
raw_temp_ll = RAW_TEMP_LL_CTR;
}
}
#define TWL_BT_LEVEL_THREASH_F 60
#define TWL_BT_LEVEL_THREASH_B 30
#define TWL_BT_LEVEL_THREASH_1 0
/********************************************//**
TWLに電池残量を教えてあげる
***********************************************/
static void bt_batt_update_twl()
{
if (vreg_ctr[VREG_C_BT_REMAIN] > TWL_BT_LEVEL_THREASH_F )
{
vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x0F;
}
else if (vreg_ctr[VREG_C_BT_REMAIN] > TWL_BT_LEVEL_THREASH_B )
{
vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x0B;
}
else if (vreg_ctr[VREG_C_BT_REMAIN] > BATT_TH_LO)
{
vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x07;
}
else if (( vreg_ctr[ VREG_C_BT_REMAIN ] > BATT_TH_EMPTY )||
!BT_CHG_Ena_n )
{ // アダプタの有無で底上げ
vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x03;
}
else if (vreg_ctr[VREG_C_BT_REMAIN] > TWL_BT_LEVEL_THREASH_1 )
{
vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x01;
}
else
{
vreg_twl[REG_TWL_INT_ADRS_POWER_INFO] = 0x00;
}
}
/********************************************//**
NTRに電池残量を教えてあげる
***********************************************/
static void bt_batt_update_ntr()
{
static bit initialized;
static bit flag; // あれstaticでないとコンパイラに怒られる
if( system_status.pwr_state == OFF_TRIG )
{
initialized = false;
}
else
{
flag = conv_ctr_bt_to_twl_bt();
if(( ntr_pm_bt_low_old != flag ) || !initialized )
{
initialized = true;
ntr_pm_bt_low_old = flag;
iic_mcu_write_a_byte_codec( CODEC_REG_BT, (u8)flag );
}
}
}
/********************************************//**
電池残量を読んでくる
***********************************************/
static err read_BT_SOC( u8* dest )
{
#ifdef _ENABLE_HAL_
if( vreg_ctr[ VREG_C_HAL_OVW_BT_FUEL ] != 0xFF ) // trueならHAL有効
#else
if( 0 )
#endif
{
*dest = vreg_ctr[ VREG_C_HAL_OVW_BT_FUEL ];
*(dest+1) = 0x00;
return ERR_SUCCESS;
}
else
{
return( read_mgic_2B( BT_GAUGE_REG_SOC, dest ) );
}
}
/********************************************//**
電池電圧を読んでくる
***********************************************/
static err read_BT_voltage( u8* dest )
{
#ifdef _ENABLE_HAL_
if( vreg_ctr[ VREG_C_HAL_OVW_BT_VOLTAGE ] != 0xFF ) // trueならHAL有効
#else
if( 0 )
#endif
{
*dest = vreg_ctr[ VREG_C_HAL_OVW_BT_VOLTAGE ];
// *(dest+1) = 0x00; // 使わないよ けど2バイトリード関数しか用意してないのです
return ERR_SUCCESS;
}
else
{
return( read_mgic_2B( BT_GAUGE_REG_VCELL, dest ) );
}
}
/********************************************//**
電池残量をtwlにフラグに変換する
***********************************************/
static u8 conv_ctr_bt_to_twl_bt()
{
// ntr_pm_bt_low_old = ( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_LO )? NTR_PM_BT_EMPTY: NTR_PM_BT_ENOUGH; // 1で電池切れ
if( vreg_ctr[ VREG_C_BT_REMAIN ] <= BATT_TH_LO )
{
return NTR_PM_BT_EMPTY;
}
else
{
return NTR_PM_BT_ENOUGH;
}
}