/* ======================================================== LED.c $Id: LED.c 418 2011-09-22 01:35:37Z n2232 $ ======================================================== */ #ifndef _WIN32 #pragma sfr #endif #include "incs.h" #include "led.h" // ======================================================== static void LED_oshirase_init(); // ======================================================== // 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 // ======================================================== bit ledInitialized; // お知らせLED uni_info_LED info_LED; // パターンデータ bit info_led_off; // 電源off時など、強制消灯フラグ bit info_led_override; // 電池残量僅少強制点滅上書きビット // wifi led ステート static u8 state_wifi_tx; static u8 flag_wifi_TX; // ======================================================== #define led_fade_to( now, goal ) now = fade_to( now, goal ) /********************************************//** now を goal になるまで inc / dec する。何度も呼ぶとグラデーション とりあえず、ステップ固定 ***********************************************/ u8 fade_to( u8 now, u8 goal ) { if( now != goal ) { if( now > goal ) { now --; } else { now ++; } } 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 { // delta が小さいときは to の値にぶつけてしまう status->now = status->to; } } return( status->now / 128 ); } /********************************************//** LEDの初期化 HWタイマーを使うのでそれらの初期化を行う ***********************************************/ void LED_init( ) { /** PWMのセット、とりあえず全部消灯 マスタチャネル:0 (P01:/reset2) マスターは偶数チャネルしかできない スレーブ    1 SLTO。(3D LED?)         2 カメラ         3 WiFi         4 (ピンはRTC32kHz out に使用)         5 充電         6 電源 L         7 電源 H */ // LED_oshirase_init(); // お知らせパターン初期化 /// ペリフェラル初期化 /// 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 = 0x00FE; // 出力モード。4はPWM出力しないが1にしないとTO5以降にクロックが届かない TOL0 = 0x0000; // 出力を反転させるかフラグ TO0 = 0x0000; // タイマー動作中で、タイマー出力にしてないときのピンのラッチ。タイマー出力を使わないなら0 TOE0 = 0x00EE; // TOxをタイマーモジュールが制御? TS0 = 0x00EF; // 動作開始 TDR00 = LED_BRIGHT_MAX - 1; // 周期 10bit // アップデートなどでマイコンのみリブートしたとき if( system_status.reboot ) { // SoC からのコマンドを待たず、自動で電源 LED をつける vreg_ctr[VREG_C_LED_POW] = LED_POW_ILM_AUTO; LED_duty_pow_blu = LED_BRIGHT_MAX; } info_led_off = false; // 強制消灯 解除 ledInitialized = true; } static void LED_oshirase_init() { char* p_tgt = &info_LED; int i; for( i = 0; i < sizeof(info_LED); i++ ) { *p_tgt = 0; p_tgt++; } } /********************************************//** LEDの停止。 HWタイマーの停止 ***********************************************/ void LED_stop( ) { TT0 = 0x00EF; // 一斉停止(しないとだめ) TOE0 = 0x0000; // TOxをタイマーモジュールが制御?(GPIOになる) TAU0EN = 0; LED_pow_red = 0; LED_CAM = 0; LED_duty_notify_red = 0; LED_duty_notify_blu = 0; LED_duty_notify_grn = 0; LED_pow_red = 0; LED_CAM = 0; WIFI_txLatch = 0; flag_wifi_TX = 0; state_wifi_tx = 0; ledInitialized = false; } /********************************************//** WiFi LED の更新 - レジスタの設定で on / off - off であってもモジュールからの送信パルスで -_-_-_--------_-_-_-------のパターン点滅 ***********************************************/ void tsk_led_wifi( ) { static u8 task_interval; 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 = 0; } 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 ++; } else { LED_duty_WiFi --; } } task_interval = 3; return; } } bit info_led_pattern_updated; /********************************************//** お知らせLED フェードアウト計算 ***********************************************/ static void calc_info_led_fade_out( st_LED_dim_status* tgt_led ) { tgt_led -> to = 0; tgt_led -> delta = ( 0 - tgt_led -> now ) / 64; // フェードアウト限定(ゼロに向かっていく。符号の向きを想定してしまう。) if(( tgt_led -> now != 0 ) && ( tgt_led -> delta == 0 )) { tgt_led -> delta = (sx16)-1; } } /********************************************//** お知らせLED グラデーション計算 ***********************************************/ static void calc_info_led_next_frame( st_LED_dim_status* tgt_led, u8 color ) { tgt_led -> to = color * 128; // グラデーションのデルタを計算 tgt_led -> delta = (( tgt_led -> to - tgt_led -> now ) ) / info_LED.info_LED.fade_time; } /********************************************//** お知らせ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 { // フェードアウトさせる calc_info_led_fade_out( &LED_dim_status_info_R ); calc_info_led_fade_out( &LED_dim_status_info_G ); calc_info_led_fade_out( &LED_dim_status_info_B ); } 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; } // グラデーション計算 calc_info_led_next_frame( &LED_dim_status_info_R, info_LED.info_LED.red[frame] ); calc_info_led_next_frame( &LED_dim_status_info_G, info_LED.info_LED.grn[frame] ); calc_info_led_next_frame( &LED_dim_status_info_B, info_LED.info_LED.blu[frame] ); } time_to_next_frame --; } } led_fade_to2( LED_duty_notify_red, &LED_dim_status_info_R ); led_fade_to2( LED_duty_notify_grn, &LED_dim_status_info_G ); led_fade_to2( LED_duty_notify_blu, &LED_dim_status_info_B ); }