ctr_mcu/trunk/adc.c
N2232 bcefe4d511 ■0.21
いつの間にか使われ方が変わって長手意を表していない変数などを一部名前変更
一部エラーコードで0を返しなどしてた。ERR_SUCCESSなどを返すように修正
ADCのノイズフィルタを改良
ヒステリシス+四捨五入を追加
Volテーブルを更新。最大音量を-10dbに
TWLからの音量設定を無視→反映、スライダの設定と後着優先になるように修正
 Volのポーリング書き込み廃止、CODECリセット時のために強制セットコマンド追加(command.4)
 そのつもりがなかったので修正量が割とあった。
Vol書き込み時、ベリファイ、一度だけリトライするようにした。発生頻度からすれば良かろう。評価中
バッテリー補正パラメータ更新
I2C_mにライトコマンドがきた直後に次の通信が来ると対応出来ずにバスが衝突(ウェイトコンディション理解してくれないから...)してしまっていた。
 結果:一瞬BL消えや突然の電源断
 一時的にスレーブアドレスを変えてNAKを返し、リトライしてもらうことにした。評価中。
電池残量ゼロ時のパターンをとりあえず高速点滅をプリセットにした。
 交換した電池が0や、完全放電などでMCUがリセットされてSoCからパターンをもらってない場合にLEDが青赤とも消灯になりユーザーが心配するため
お知らせLEDのフルカラー化の両対応コードが間違えていてめちゃめちゃになっていたのを修正
お知らせLEDフルカラー判定を誤ることがあった。マージンを増やした。
白箱を実機と誤判定していた。(FPGAの準備がまだ)判定方法を変更
本体設定や無線スイッチでWiFiを切ったときはフェードなしに。すぱっと変化した方がかっこいい
電源OFFにするとき、3DとWiFiはすぱっと消す。電源とお知らせはフェード(以前のまま)
スリープ期間が極短いとSoC.SLP_OのH期間を取り逃す事があった。
 症状:スリープに入ると電源断以外受け付けなくなる
 I2Cで予告してもらう。
歩数計のログポインタ進めるタイミング、秒レジスタ追加。
割り込み禁止区間の調整
電池残量ICとの通信・通信後のケアなど修正
電池残量0での強制電源断復活
.bin,.hexをリポジトリに追加

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_mcu@198 013db118-44a6-b54f-8bf7-843cb86687b1
2010-06-30 05:50:16 +00:00

476 lines
11 KiB
C
Raw 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.

/* ========================================================
藤田@開技
nintendo
'09 Apr
======================================================== */
#include "incs.h"
#include "adc.h"
#include "pm.h"
#include "led.h"
//#define _4db_
//#define _15db_
#define _10db_
#include "voltable.h"
// ===================================================== //
bit adc_updated;
u8 adc_raw_vol;
u8 adc_raw_dep;
typedef struct filter_work
{
u8* value_used;
s8 diffs; // KIKAN中の偏り具合
s8 kikan;
}filter_work;
filter_work work_vr_3d = {
&vreg_ctr[ VREG_C_TUNE ]
};
u8 vol_data_ctr;
filter_work work_vr_vol = {
&vol_data_ctr
};
u8 vol_data;
// ===================================================== //
extern void nop8();
static void adc_filter( u8 new_val, filter_work* work );
// ===================================================== //
#define INTERVAL_TSK_ADC 15
/* ========================================================
ADC設定と、開始
以下のピンは主にここで操作・監視されます。
・BT_TEMP,_P
・ADIN1
・VOL
関係ありそうですが別のところで管理しています
・PM_BT_DET,_P BT_init
・8tics毎に呼ばれ、チャンネル分取り込むとADCを停止します。
 タスク起動時、レジスタには前回の取り込み値が入っています。
======================================================== */
void tsk_adc( )
{
static u8 task_interval = 0;
static u8 old_tune;
static u8 sndvol_codec;
static u8 bt_temp_old;
#ifdef _DEBUG_PM_BOMB_VOL_
if( system_status.pwr_state == ON )
{
renge_task_immed_add( tski_vol_update );
}
#endif
if( task_interval-- != 0 )
{
return;
}
else
{
task_interval = (u8)( INTERVAL_TSK_ADC / SYS_INTERVAL_TICK );
}
if( adc_updated )
{
adc_updated = 0;
if( system_status.pwr_state == ON )
{
// 3D /////////////////////////////////////////
adc_filter( adc_raw_dep, &work_vr_3d );
// Volume /////////////////////////////////////
if(( vreg_ctr[ VREG_C_VOL_DIGITAL ] & 0x80 ) != 0 )
{
// レジスタから強制セット
adc_raw_vol = ( vreg_ctr[ VREG_C_VOL_DIGITAL ] * 4 );
}
{
static u8 vol_old;
adc_filter( adc_raw_vol, &work_vr_vol );
if( vol_old != vol_data_ctr )
{
vol_old = vol_data_ctr;
vol_data = vol_data_ctr;
renge_task_immed_add( tski_vol_update );
}
}
// バッテリ識別 ///////////////////////////
/* 呼ばれません */
}
}
ADCEN = 1;
ADM = 0b00001011; // セレクトモード、昇圧、fCLK/6 ///ここから ↓
ADPC = 0x06; // ADCポートのセレクト
ADS = ADC_SEL_TUNE;
nop8();
ADCS = 1; // AD開始。 /// ここまで  までに1us=8clk以上開ける
ADIF = 0;
ADMK = 0;
}
/* ========================================================
 Volを更新します。
 こんな時に登録されます。
  ・ユーザーがVolスライダを動かした
  ・Horizonに強制更新を指示された codecリセット時
  ・TWLアプリがVolをいじった
======================================================== */
task_status_immed tski_vol_update()
{
u8 vol_scaled;
u8 temp;
vol_scaled = ( vol_data / 4 ) & 0x3F;
// レジスタ更新
vreg_twl[ REG_TWL_INT_ADRS_VOL ] = vol_data / ( 256 / 32 ); // ←adc値でよい
vreg_ctr[ VREG_C_SND_VOL ] = vol_scaled; // 64段
// codecに伝える
temp = slider_to_codec[ vol_scaled ];
iic_mcu_write_a_byte( IIC_SLA_CODEC, CODEC_REG_VOL, temp );
// ベリファイ
if( iic_mcu_read_a_byte( IIC_SLA_CODEC, CODEC_REG_VOL ) != temp )
{
iic_mcu_write_a_byte( IIC_SLA_CODEC, CODEC_REG_VOL, temp );
NOP();
}
#ifndef _MODEL_CTR_
iic_mcu_write_a_byte( IIC_SLA_DCP, 0, slider_to_codec[ ( 255 - vol_data ) / 4 ] );
#endif
// set_irq( VREG_C_IRQ0, REG_BIT_VR_SNDVOL_CHANGE ); // 割り込み廃止
return( ERR_FINISED );
}
/* ========================================================
 過去つのminでもMAXでもない値を返す
 突発的なノイズを除く。
 運が悪いと振動するよ
======================================================== */
static u8 getmean3( u8 * hist )
{
if( *hist > *( hist + 1 ) )
{
if( *hist > *( hist + 2 ) )
{
return( ( *( hist + 1 ) > *( hist + 2 ) ) ? *( hist + 1 ) : *( hist + 2 ) );
}
else
{
return( *hist );
}
}else{
if( *hist > *( hist + 2 ) )
{
return( *hist );
}
else
{
return( ( *( hist + 1 ) < *( hist + 2 ) ) ? *( hist + 1 ) : *( hist + 2 ) );
}
}
}
/* ========================================================
 自前で次のチャンネル
  一通り終わったら止める
======================================================== */
__interrupt void int_adc( )
{
static u8 hist_tune[3];
static u8 hist_snd_vol[3];
static u8 hist_bt_temp[3];
static u8 index;
volatile u8 adc_data;
adc_data = ADCRH;
switch ( ADS )
{
/*
case ( ADC_SEL_AMB_BRIT ): // 環境明るさ
vreg_ctr[ VREG_C_AMBIENT_BRIGHTNESS ] = adc_data;
break;
*/
case ( ADC_SEL_TUNE ):
EI();
#ifdef _MODEL_WM0_
adc_raw_dep = 255 - adc_data;
#else
adc_raw_dep = adc_data;
#endif
break;
case ( ADC_SEL_VOL ):
EI();
#ifdef _MODEL_CTR_
if( system_status.model == MODEL_TS_BOARD )
{
adc_raw_vol = adc_data;
}
else
{
adc_raw_vol = 255 - adc_data;
}
#else
adc_raw_vol = adc_data;
#endif
break;
case ( ADC_SEL_BATT_TEMP ):
EI();
raw_adc_temperature = adc_data;
#ifdef _DEBUG_BT_TEMP_
if( vreg_ctr[ VREG_C_COMMAND3 ] == 't' )
{
raw_adc_temperature = vreg_ctr[ VREG_C_DBG01 ];
}
#endif
if( (( vreg_ctr[ VREG_C_STATUS_1 ] & REG_BIT_GASGAUGE_ERR ) == 0 ) &&
(( system_status.pwr_state == ON ) ||
( system_status.pwr_state == SLEEP )
)
)
{
renge_task_immed_add( tski_BT_temp_update );
}
break;
/* 呼ばれません
case ( ADC_SEL_BATT_DET ):
break;
*/
}
// もっとまともな書き方がありそうだ
if( ADS < ADC_SEL_BATT_DET )
{
ADS += 1; // 次のチャンネル
ADIF = 0; // ←これをしないと、いっこ前のチャンネルのデータの完了で直後に割り込む可能性がある
}
else
{
ADCEN = 0; // 止めてしまう
adc_updated = 1;
index = ( index == 2 ) ? 0 : ( index + 1 ); // ノイズ取りの配列インデックス
}
}
/* ========================================================
tsk_adcと競合することを考慮していません。
======================================================== */
u8 get_adc( u8 ch )
{
u8 temp;
ADMK = 1;
ADIF = 0;
ADCEN = 1;
ADM = 0b00001011; // セレクトモード、昇圧、fCLK/6 ///ここから↓
ADPC = 0x06; // ADCポートのセレクト
ADS = ch;
nop8();
ADCS = 1; // AD開始。 /// ここまで↑ に、1us以上開ける
ADIF = 0;
while( ADIF == 0 ){;}
temp = ADCRH;
ADCEN = 0;
ADMK = 0;
return ( temp );
}
/* ========================================================
似非ヒステリシス V2
四捨五入的な動きします
======================================================== */
#define KIKAN 16
static void adc_filter( u8 new_val, filter_work *work )
{
u8 temp;
volatile u8 hoge;
// if( abs( new_val - *( work -> value_used )) >= 2 )
if( abs( new_val - *( work -> value_used )) > 2 )
{
// 大きく離れた
*( work -> value_used ) = new_val;
work -> diffs = 0;
work -> kikan = KIKAN;
}
else
{
// 近所の値でも、ある期間でいっぱい偏っていたらそっちに寄せる
if( *( work -> value_used ) < new_val )
{
work -> diffs += 1;
}
else if( *( work -> value_used ) > new_val )
{
work -> diffs -= 1;
}
if( --( work -> kikan ) == 0 )
{
if( work -> diffs > (s8)( KIKAN * 0.8 ) )
{
*( work -> value_used ) += 1;
}
else if( work -> diffs < (s8)( -1 * KIKAN * 0.8 ) )
{
*( work -> value_used ) -= 1;
}
work -> kikan = KIKAN;
work -> diffs = 0;
}
}
}
#if 0
// getmean使用 //
__interrupt void int_adc( )
{
static u8 hist_tune[3];
static u8 hist_snd_vol[3];
static u8 hist_bt_temp[3];
static u8 index;
volatile u8 adc_data;
adc_data = ADCRH;
switch ( ADS )
{
/*
case ( ADC_SEL_AMB_BRIT ): // 環境明るさ
vreg_ctr[ VREG_C_AMBIENT_BRIGHTNESS ] = adc_data;
break;
*/
case ( ADC_SEL_TUNE ):
hist_tune[index] = adc_data;
EI();
#ifdef _MODEL_WM0_
adc_raw_dep = 255 - getmean3( hist_tune );
#else
adc_raw_dep = getmean3( hist_tune );
#endif
break;
case ( ADC_SEL_VOL ):
hist_snd_vol[index] = adc_data;
EI();
#ifdef _MODEL_CTR_
if( system_status.model == MODEL_TS_BOARD )
{
adc_raw_vol = getmean3( hist_snd_vol );
}
else
{
adc_raw_vol = ( 255 - getmean3( hist_snd_vol ));
}
#else
adc_raw_vol = getmean3( hist_snd_vol );
#endif
break;
case ( ADC_SEL_BATT_TEMP ):
hist_bt_temp[index] = adc_data;
EI();
raw_adc_temperature = getmean3( hist_bt_temp );
if( (( vreg_ctr[ VREG_C_STATUS_1 ] & REG_BIT_GASGAUGE_ERR ) == 0 ) &&
(( system_status.pwr_state == ON ) ||
( system_status.pwr_state == SLEEP )
)
)
{
renge_task_immed_add( tski_BT_temp_update );
}
break;
/* 呼ばれません
case ( ADC_SEL_BATT_DET ):
break;
*/
}
// もっとまともな書き方がありそうだ
if( ADS < ADC_SEL_BATT_DET )
{
ADS += 1; // 次のチャンネル
ADIF = 0; // ←これをしないと、いっこ前のチャンネルのデータの完了で直後に割り込む可能性がある
}
else
{
ADCEN = 0; // 止めてしまう
adc_updated = 1;
index = ( index == 2 ) ? 0 : ( index + 1 ); // ノイズ取りの配列インデックス
}
}
#endif