ctr_mcu/branches/SDK0.14/led.c
n2232 2afd580bdd 1.16(仮)
AVATAR音量変化SEが鳴りまくるのを修正
 一部のソフトでスライダ値と画面上のアイコンがずれる確率が上がった(確認済み仕様)

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_mcu@307 013db118-44a6-b54f-8bf7-843cb86687b1
2011-02-01 00:24:54 +00:00

743 lines
19 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.

/* ========================================================
LED.c
======================================================== */
#pragma sfr
#include "incs.h"
#include "led.h"
// ========================================================
// TPS0
#define BIT_PRS012 ( 1 << 2 )
#define BIT_PRS002 ( 1 << 6 )
// TMR0
#define BIT_CKS0 15
#define BIT_CCS0 12
#define BIT_MASTER0 11
#define BIT_STS0 8
#define BIT_CIS0 6
#define BIT_MD123 1
#define BIT_MD0 0
// ========================================================
// スリープ中明滅のテーブル。マジか。
const u8 LED_PTN_SLEEP[] = {
25, 38, 52, 68, 83, 98, 110, 119,
125, 128, 128, 125, 119, 110, 98, 83,
68, 52, 38, 25, 16, 10, 8, 8,
8, 8, 8, 8, 8, 8, 10, 16
};
#define LED_SLEEP_FRAME_LEN 71
#define LED_SLEEP_DIM_LEN 71
#define LED_SLEEP_FRAME_NUM 32
// ========================================================
static void led_pow_normal( );
static void led_pow_sleep( );
static void led_pow_bt_empty();
static u8 led_pow_batt_low();
// ========================================================
// 赤LEDの電池残量LEDの点滅パターン
st_led_red_batt_empty led_red_batt_empty = { 0x55, 0x55, 0x55, 0x55 };
// お知らせLEDのパターンデータ
uni_info_LED info_LED;
// フルカラーとの自動判別のため、一時領域としてもっておく
bit LED_pow_red_Mirror;
bit info_led_off;
bit info_led_override;
bit cam_led_update;
// 電源LEDのスリープパターンのステータス類
u8 time_to_next_frame_sleep = LED_SLEEP_FRAME_LEN;
u8 frame_sleep;
st_LED_dim_status LED_dim_status_sleep;
// ========================================================
#define led_fade_to( now, goal ) now = fade_to( now, goal )
/* ========================================================
reg_ledをgoalになるまでグラデーションする
とりあえず、ステップ固定
====================================================== */
u8 fade_to( u8 now, u8 goal )
{
if( now != goal )
{
if( now > goal )
{
now -= 1;
}
else
{
now += 1;
}
}
return( now );
}
// ========================================================
#define led_fade_to2( led, status ) \
led = fade_to2( status )
u8 fade_to2( st_LED_dim_status* status )
{
if( status->now != status->to )
{
if( abs(( status->to - status->now )) > abs(status->delta) )
{
status->now += status->delta;
}
else
{
status->now = status->to;
}
}
return( status->now / 128 );
}
// ========================================================
// ========================================================
void LED_init( )
{
/**
PWMのセット、とりあえず全部消灯
マスタチャネル:0 (P01:/reset2) マスターは偶数チャネルしかできない
スレーブ    1 SLTO。( )
        2 カメラ
         WiFi
         (ピンは32kHz out に使用)
        5 充電
        6 電源
        7 電源
*/
INFO_LED_IS_FULLCOLOR_PU = 1; // お知らせLEDを識別 先に上げておく
INFO_LED_IS_FULLCOLOR_PM = 1;
TAU0EN = 1;
TPS0 = BIT_PRS012 | BIT_PRS002; // マスタークロックはCK01,8M/2 /2^4 = 250kHz
TMR00 =
1 << BIT_CKS0 | 0 << BIT_CCS0 | 1 << BIT_MASTER0 | 0 << BIT_STS0 | 0
<< BIT_CIS0 | 0 << BIT_MD123 | 1 << BIT_MD0;
TMR01 = TMR02 = TMR03 = TMR04 = TMR05 = TMR06 = TMR07 =
1 << BIT_CKS0 | 0 << BIT_CCS0 | 0 << BIT_MASTER0 | 4 << BIT_STS0 | 0
<< BIT_CIS0 | 4 << BIT_MD123 | 1 << BIT_MD0;
ISC = 0;
TOM0 = 0b0000000011111110; // 出力モード。4はPWM出力しないが1にしないとTO5以降にクロックが届かない
TOL0 = 0b0000000000000000; // 出力を反転させるかフラグ
TO0 = 0; // タイマー動作中で、タイマー出力にしてないときのピンのラッチ。タイマー出力を使わないなら0
TOE0 = 0b0000000011101110; // TOxをタイマーモジュールが制御
TS0 = 0b0000000011101111; // 動作開始
TDR00 = LED_BRIGHT_MAX - 1; // 周期 10bit
// お知らせLEDを識別 //
// INFO_LED_IS_FULLCOLOR_PU = 1; // もうちょっと前に上げておかないと…
system_status.info_fullcolor = 1;
if( system_status.model == MODEL_TS_BOARD )
{
#ifndef _DBG_FORCE_FULLCOLOR_
system_status.info_fullcolor = 0;
#endif
}
else
{
if( INFO_LED_IS_FULLCOLOR_n )
{
system_status.info_fullcolor = 0;
}
}
INFO_LED_IS_FULLCOLOR_n = 0;
INFO_LED_IS_FULLCOLOR_PM = 0;
LED_duty_notify_red = 0;
LED_duty_notify_blu = 0;
LED_duty_notify_grn = 0;
LED_pow_red = 0;
LED_CAM = 0;
LED_old_pow_red = 0;
if( system_status.reboot )
{
vreg_ctr[VREG_C_LED_POW] = LED_POW_ILM_AUTO;
LED_duty_pow_blu = LED_BRIGHT_MAX;
}
info_led_off = false;
}
void LED_stop( )
{
TT0 = 0b0000000011101111; // 一斉停止(しないとだめ)
TOE0 = 0b0000000000000000; // TOxをタイマーモジュールが制御(GPIOになる)
TAU0EN = 0;
LED_pow_red = 0;
LED_CAM = 0;
LED_old_pow_red = 0;
}
/* ========================================================
// 電源LED
LED_POW_B,R 6,7
TDR00 周期(0x03FF。TPS0で250kHzでカウントアップ。10bitなら250Hz位になる)
TDR0x Duty 0で消灯、TDR00(より大 =0x03FF以上)で点灯です。
enum pwr_state_{
OFF_TRIG = 0,
ON_CHECK,
ON_TRIG,
ON,
SLEEP
};
enum LED_ILUM_MODE{
LED_POW_ILM_AUTO,
LED_POW_ILM_ON,
LED_POW_ILM_SLEEP,
LED_POW_ILM_CEOFF
};
======================================================== */
void tsk_led_pow( )
{
info_led_override = false;
switch ( vreg_ctr[VREG_C_LED_POW] )
{
case ( LED_POW_ILM_AUTO ):
default:
led_pow_normal( );
break;
case ( LED_POW_ILM_SLEEP ):
led_pow_sleep( );
break;
case ( LED_POW_ILM_ON ):
led_fade_to( LED_duty_pow_blu, vreg_ctr[VREG_C_LED_BRIGHT] );
LED_pow_red_Mirror = 0;
break;
case ( LED_POW_ILM_OFF ):
led_fade_to( LED_duty_pow_blu, 0 );
LED_pow_red_Mirror = 0;
break;
case ( LED_POW_ILM_ONLY_RED ):
LED_duty_pow_blu = 0;
LED_pow_red_Mirror = 1;
break;
case ( LED_POW_ILM_ONLY_BLUE ):
LED_duty_pow_blu = LED_BRIGHT_MAX;
LED_pow_red_Mirror = 0;
break;
case ( LED_POW_ILM_FORCE_BT_EMPTY ):
led_pow_bt_empty();
break;
}
if( system_status.pwr_state == OFF || system_status.pwr_state == ON_CHECK )
{
LED_pow_red_Mirror = 0;
info_led_override = false;
}
// 実際にLEDの更新
if( system_status.info_fullcolor )
{
LED_pow_red = LED_pow_red_Mirror;
}
else
{
LED_old_pow_red = LED_pow_red_Mirror;
}
if( info_led_override )
{
if( system_status.info_fullcolor )
{
LED_duty_notify_blu = 0;
LED_duty_notify_grn = 0;
LED_duty_notify_red = LED_pow_red_Mirror ? 255: 0;
}
else
{
LED_duty_old_NOTIFY = LED_pow_red_Mirror ? 255: 0;
}
}
}
/* ========================================================
電池残量で、 青→赤→赤点滅
======================================================== */
static void led_pow_normal( )
{
time_to_next_frame_sleep = LED_SLEEP_FRAME_LEN;
frame_sleep = 0;
LED_dim_status_sleep.now = (sx16)LED_duty_pow_blu * 128;
if( led_pow_batt_low() != 0 ) // 赤の点灯も←でやっています
{
return;
// おしまい
}
// 青点灯
led_fade_to( LED_duty_pow_blu, vreg_ctr[VREG_C_LED_BRIGHT] );
}
/* ========================================================
ホタルパターン
電池残量で赤→赤点滅にする
======================================================== */
static void led_pow_sleep( )
{
if( led_pow_batt_low() != 0 ) // 赤の点灯も←でやっています
{
time_to_next_frame_sleep = LED_SLEEP_FRAME_LEN;
frame_sleep = 0;
LED_dim_status_sleep.now = (sx16)LED_duty_pow_blu * 128;
return;
// おしまい
}
LED_dim_status_sleep.to = LED_PTN_SLEEP[frame_sleep] * 128;
// グラデーションのデルタを計算
LED_dim_status_sleep.delta = (( LED_dim_status_sleep.to - LED_dim_status_sleep.now ) ) / LED_SLEEP_DIM_LEN;
led_fade_to2( LED_duty_pow_blu, &LED_dim_status_sleep );
// 次のフレームに進める?
time_to_next_frame_sleep -= 1;
if( time_to_next_frame_sleep == 0 )
{
time_to_next_frame_sleep = LED_SLEEP_FRAME_LEN;
frame_sleep += 1;
if( frame_sleep >= LED_SLEEP_FRAME_NUM -1 )
{
frame_sleep = 0;
}
}
}
/* ========================================================
電池が少ないときの共通
 返値 0 電池が少なくなかった
     1    少なかったので共通パターンにした
======================================================== */
static u8 led_pow_batt_low()
{
if( vreg_ctr[VREG_C_BT_REMAIN] > BATT_TH_LO )
{
LED_pow_red_Mirror = 0;
return 0;
// おしまい
}
if(( vreg_ctr[VREG_C_BT_REMAIN] > BATT_TH_EMPTY ) || !BT_IN_CHG_n )
{
// 赤点灯
led_fade_to( LED_duty_pow_blu, 0 );
LED_pow_red_Mirror = 1;
}
else
{
led_pow_bt_empty();
}
return 1;
}
/* ========================================================
 電池がないパターン
  指定パターンを流す
  お知らせを上書きしたりする
======================================================== */
static void led_pow_bt_empty()
{
static u8 delay;
static u8 red_blink_poi;
info_led_override = true;
// 赤点滅
led_fade_to( LED_duty_pow_blu, 0 );
// 赤の点滅パターンも指定できる
delay += 1;
if( delay < 64 ) // フレームの保持時間稼ぎ
{
return;
}
delay = 0;
if( led_red_batt_empty.dats[ red_blink_poi / 8 ] & ( 1 << ( red_blink_poi % 8 )) )
{
LED_pow_red_Mirror = 1;
}
else
{
LED_pow_red_Mirror = 0;
}
red_blink_poi += 1;
if( red_blink_poi >= 32 )
{
red_blink_poi = 0;
}
}
/* ========================================================
* 割り込みそのものは使いません *
LED_Wifi 3
======================================================== */
void tsk_led_wifi( )
{
static u8 task_interval;
static u8 state_wifi_tx;
static u8 flag_wifi_TX;
if( task_interval-- != 0 )
{
return;
}
// 送信パルスのラッチ
if( WIFI_txLatch ) // 割り込みフラグそのものを使ってしまう
{
WIFI_txLatch = 0;
flag_wifi_TX = 1;
}
if( flag_wifi_TX != 0 )
{
vreg_ctr[ VREG_C_STATUS_1 ] |= REG_BIT_WIFI_TX;
// 送信パターン
switch ( state_wifi_tx )
{
case ( 1 ):
case ( 3 ):
case ( 5 ):
LED_duty_WiFi = 0;
break;
default:
LED_duty_WiFi = vreg_ctr[VREG_C_LED_BRIGHT];
}
state_wifi_tx++;
if( state_wifi_tx == 32 ) // ←点滅後、点灯している期間の長さ
{
state_wifi_tx = 0;
flag_wifi_TX -= 1;
}
task_interval = 25;
return;
}
else
{
task_interval = 30;
// 送信フラグ待ち
vreg_ctr[ VREG_C_STATUS_1 ] &= ~REG_BIT_WIFI_TX;
if( vreg_ctr[VREG_C_LED_WIFI] == WIFI_LED_OFF )
{
LED_duty_WiFi = 0;
return;
}
else
{
if( LED_duty_WiFi == vreg_ctr[VREG_C_LED_BRIGHT] )
{
return;
}
else if( LED_duty_WiFi < vreg_ctr[VREG_C_LED_BRIGHT] )
{
LED_duty_WiFi += 1;
}
else
{
LED_duty_WiFi -= 1;
}
}
task_interval = 3;
return;
}
}
bit info_led_pattern_updated;
/* ========================================================
お知らせLED
======================================================== */
void tsk_led_notify( )
{
static u8 time_to_next_frame;
static u8 frame;
static u8 loops;
static st_LED_dim_status LED_dim_status_info_R, LED_dim_status_info_G, LED_dim_status_info_B;
if( info_led_override )
{
// 電池切れが優先する
return;
}
if( system_status.pwr_state == ON_TRIG )
{
LED_duty_notify_blu = 0;
LED_duty_notify_red = 0;
LED_duty_notify_grn = 0;
LED_dim_status_info_R.now = 0;
LED_dim_status_info_G.now = 0;
LED_dim_status_info_B.now = 0;
}
if( info_led_off ) // ←電源off時など強制off
{
// フェードアウトさせる
LED_dim_status_info_R.to = 0;
LED_dim_status_info_G.to = 0;
LED_dim_status_info_B.to = 0;
LED_dim_status_info_R.delta = ( 0 - LED_dim_status_info_R.now ) / 64;
LED_dim_status_info_G.delta = ( 0 - LED_dim_status_info_G.now ) / 64;
LED_dim_status_info_B.delta = ( 0 - LED_dim_status_info_B.now ) / 64;
}
else
{
// 通常運転
if( info_led_pattern_updated )
{
info_led_pattern_updated = false;
vreg_ctr[ VREG_C_LED_NOTIFY_FLAG ] &= ~REG_BIT_IN_LOOP;
frame = 0; // ちゃんと書こう
time_to_next_frame = 0;
}
else
{
// 次のフレームに進める?
if( time_to_next_frame == 0 )
{
time_to_next_frame = info_LED.info_LED.term;
if( frame >= NOTIFY_LED_TERM -1 )
{
vreg_ctr[ VREG_C_LED_NOTIFY_FLAG ] |= REG_BIT_IN_LOOP;
if( info_LED.info_LED.last_loop != 255 ) // 255:無限ループ
{
loops++;
if( loops > info_LED.info_LED.last_loop )
{
frame = 0;
}
}
}
else
{
frame = (( frame + 1 ) & 0x1F ); // ←ここでマスクをかけておかないと最終フレーム~先頭間のグラデが効かない
vreg_ctr[ VREG_C_LED_NOTIFY_FLAG ] &= ~REG_BIT_IN_LOOP;
loops = 0;
}
LED_dim_status_info_R.to = info_LED.info_LED.red[frame] * 128;
LED_dim_status_info_G.to = info_LED.info_LED.grn[frame] * 128;
LED_dim_status_info_B.to = info_LED.info_LED.blu[frame] * 128;
// グラデーションのデルタを計算
LED_dim_status_info_R.delta = (( LED_dim_status_info_R.to - LED_dim_status_info_R.now ) ) / info_LED.info_LED.fade_time;
LED_dim_status_info_G.delta = (( LED_dim_status_info_G.to - LED_dim_status_info_G.now ) ) / info_LED.info_LED.fade_time;
LED_dim_status_info_B.delta = (( LED_dim_status_info_B.to - LED_dim_status_info_B.now ) ) / info_LED.info_LED.fade_time;
}
time_to_next_frame -= 1;
}
}
if( system_status.info_fullcolor )
{
led_fade_to2( LED_duty_notify_blu, &LED_dim_status_info_B );
led_fade_to2( LED_duty_notify_red, &LED_dim_status_info_R );
led_fade_to2( LED_duty_notify_grn, &LED_dim_status_info_G );
}
else
{
led_fade_to2( LED_duty_old_NOTIFY, &LED_dim_status_info_B );
}
}
/******************************************************//**
LED_Cam TO02
\n BLINK,*_PLUSE の時は、1周期分は必ずその状態になります。
\n その間に OFF→BLINK などされると、OFFが無視されます。
*********************************************************/
void tsk_led_cam( )
{
static u8 state_led_cam = 0;
static u8 task_interval;
u8 LED_CAM_mirror;
if( !cam_led_update )
{
if( task_interval != 0 )
{
task_interval -= 1;
return;
}
}
cam_led_update = false; // TWL のブリンク設定(一発だけ点灯)のため
EI();
if( system_status.pwr_state == SLEEP ) // sleep中、強制消灯
{
LED_CAM_mirror = 0;
state_led_cam = 0;
}
else
{
// ブリンクのように待たせたいとき以外は毎週起動する
// (レジスタの変更にすぐに反応する)
switch ( vreg_ctr[VREG_C_LED_CAM] )
{
case ( CAM_LED_OFF ):
default:
LED_CAM_mirror = 0;
state_led_cam = 0;
break;
case ( CAM_LED_ON ):
LED_CAM_mirror = 1;
state_led_cam = 0;
break;
case ( CAM_LED_BLINK ):
if( state_led_cam == 0 )
{
LED_CAM_mirror = 1;
state_led_cam = 1;
}
else
{
LED_CAM_mirror = 0;
state_led_cam = 0;
}
task_interval = 250;
break;
case ( CAM_LED_ON_PLUSE ):
if( state_led_cam == 0 )
{
LED_CAM_mirror = 1;
state_led_cam = 1;
task_interval = 250;
}
else
{
vreg_ctr[VREG_C_LED_CAM] = CAM_LED_OFF;
}
break;
case ( CAM_LED_OFF_PLUSE ):
if( state_led_cam == 0 )
{
LED_CAM_mirror = 0;
state_led_cam = 1;
task_interval = 250;
}
else
{
vreg_ctr[VREG_C_LED_CAM] = CAM_LED_ON;
}
break;
case( CAM_LED_BY_TWL ):
switch ( vreg_twl[ REG_TWL_INT_ADRS_CAM ] ){ // switchのネストとか…
case( TWL_CAMLED_OFF ):
LED_CAM_mirror = 0;
state_led_cam = 0;
break;
case( TWL_CAMLED_BLINK ):
if( state_led_cam == 0 )
{
LED_CAM_mirror = 1;
state_led_cam = 1;
}
else
{
LED_CAM_mirror = 0;
state_led_cam = 0;
}
task_interval = 250;
break;
case( TWL_CAMLED_ON ):
case( TWL_CAMLED_DEF_ON ):
default:
LED_CAM_mirror = 1;
state_led_cam = 1;
break;
}
}
} // if( system_status.pwr_state == sleep ) ... else ...
// 輝度更新 //
if( system_status.info_fullcolor )
{
LED_CAM = LED_CAM_mirror;
}
else
{
LED_old_CAM = LED_CAM_mirror;
}
}