#pragma section @@CODE ROM_CODE #pragma nop #pragma ei #pragma di #pragma sfr /****************************************************************************** タスクシステム? なるほど、iTRONにはコンフィギュレータがあるはずだ。 →作りました ctr_mcu_config.rb 参照。 task_config.hが作成されます。 *****************************************************************************/ #include "renge.h" #include "renge_task_intval.h" #include "renge_task_immediate.h" #include "..\WDT.h" #include "..\config.h" #include "..\user_define.h" #define _renge_test_ //****************************************************************************** bit renge_flg_interval; bit renge_task_interval_run_force; bit renge_task_immediate_not_empty; u8 system_time; #include "..\bsr_system.h" extern system_status_ system_status; //****************************************************************************** static void renge_task_immed_init(); static void renge_task_immed_del(); //****************************************************************************** task_status_immed ( *tasks_immed[ TASK_IMMED_RUN_LIST_MAX ] )(); /****************************************************************************** 初期化 ・タスクシステムの動的部分の初期化 ・インターバルタイマ *****************************************************************************/ void renge_init(){ renge_task_immed_init(); /* イベントタイマのセットなど 今回はRTCを流用しているのでコメントアウト #define renge_tick 19xxxxxxx [ms] renge_interval_init(); → RTC_init(); */ } /****************************************************************************** システムチックを進める *****************************************************************************/ /* void renge_interval(){ // RTCがやってくれる →__interrupt void int_rtc_int(); } */ /****************************************************************************** コンパイル時に決まっている、インターバル起動のタスク そのうち、逐次起動と混ぜるかもしれない。 *****************************************************************************/ err renge_task_interval_run(){ u8 i; // インターバル起動 if(( renge_flg_interval == 1 ) || ( renge_task_interval_run_force != 0 )) // todo 統合 { renge_task_interval_run_force = 0; renge_flg_interval = 0; for( i = 0; i != TSK_LAST; i += 1 ) { tasks[ i ](); // 逐次起動タスクがあったら起動しておく renge_task_immed_run(); } } return( ERR_SUCCESS ); } /***************************************************************************** ■逐一起動タスク■ ●task_immed を返す関数。 ●システムtick、何らかの割り込み(I2C通信完了など)で スリープから復帰したタイミングで実行されます。 ■返値 ERR_FINISED タスクを削除     それ以外 次のタイミングでまた実行 *****************************************************************************/ /************************************** **************************************/ void renge_task_immed_init(){ u8 i; for( i = 0; i < TASK_IMMED_RUN_LIST_MAX; i++ ){ tasks_immed[ i ] = TSK_IMM_EMPTY_; } } /************************************** 逐次実行タスクの登録 割り込み禁止 36us → **************************************/ err renge_task_immed_add( task_status* new_task ){ u8 i; // リストの空きの先頭に登録 // 削除したばかりのタスクは、削除マーク(TSK_IMM_DELETED_)となり、空きとは明示的に区別される // 重複登録を避ける for( i = 0; i < TASK_IMMED_RUN_LIST_MAX; i += 1 ) { if( tasks_immed[ i ] != TSK_IMM_EMPTY_ ) { // 重複登録チェック if( tasks_immed[ i ] == new_task ) { // 重複登録はしない NOP(); return( ERR_ERR ); } } else { // 空きを見つけた // もたもたしているうちに割り込み等から割り込まれるのを考慮 // 滅多にないはずだが for( ; i < TASK_IMMED_RUN_LIST_MAX; i += 1 ) { if( tasks_immed[ i ] == TSK_IMM_EMPTY_ ) { tasks_immed[ i ] = new_task; return( ERR_SUCCESS ); } } // 割り込まれてタスク登録できなくなった return( ERR_ERR ); } } // タスク登録しすぎ(無いはず NOP(); // デバッガで捕まえるため return( ERR_ERR ); } /************************************** 逐次実行タスクの実行 **************************************/ err renge_task_immed_run(){ u8 list_id; u8 last_task_id; do{ last_task_id = 0xFF; for( list_id = 0; list_id < TASK_IMMED_RUN_LIST_MAX; list_id += 1 ){ if( tasks_immed[ list_id ] != TSK_IMM_EMPTY_ ){ #ifdef _renge_test_ if( tasks_immed[ list_id ] == TSK_IMM_DELETED_ ) { NOP(); // タスク管理の不備 // 存在しないタスクを実行しようとした // タスクの削除後の処理がまずい // 予期しないタイミングで immed_run が呼ばれた } else #endif { if( tasks_immed[ list_id ]() == ERR_SUCCESS ) { tasks_immed[ list_id ] = TSK_IMM_DELETED_; } last_task_id = list_id; } } #ifdef _renge_test_ else { list_id += 1; for( ; list_id < TASK_IMMED_RUN_LIST_MAX; list_id++ ) { if( tasks_immed[ list_id ] != TSK_IMM_EMPTY_ ) { NOP(); // ? } } break; } #endif } // タスク削除 { if( last_task_id != 0xFF ) { u8 i,j; #ifdef _renge_test_ if ( tasks_immed[ 1 ] != 0 ){ NOP(); } #endif // リスト前詰め i = 0; // 前詰め後リストの最後尾 j = 1; // リストの後ろの方のタスクを探す for( ; j < TASK_IMMED_RUN_LIST_MAX; j++ ) { DI(); if( tasks_immed[ i ] == TSK_IMM_DELETED_ ) { if( tasks_immed[ j ] == TSK_IMM_EMPTY_ ) { // リストの最後だった for( ; i < j ; i += 1 ) { tasks_immed[ i ] = TSK_IMM_EMPTY_; } #ifdef _renge_test_ /// ほんと? j += 1; for( ; j < TASK_IMMED_RUN_LIST_MAX; j++ ) { if( tasks_immed[ j ] != TSK_IMM_EMPTY_ ) { NOP(); // ? } } #endif EI(); break; } if( tasks_immed[ j ] != TSK_IMM_DELETED_ ) { // 探索隊が前詰めすべきタスクを見つけた tasks_immed[ i ] = tasks_immed[ j ]; tasks_immed[ j ] = TSK_IMM_DELETED_; i += 1; } } else { #ifdef _renge_test_ // タスクが滞留 if( tasks_immed[ i ] == TSK_IMM_EMPTY_ ) { NOP(); // そんなはずない } #endif i += 1; } EI(); if( tasks_immed[ i ] == TSK_IMM_EMPTY_ ) { #ifdef _renge_test_ NOP(); #endif break; // リストの最後だった } } DI(); // ここまでで完全に前詰めされている for( j = 0; j < TASK_IMMED_RUN_LIST_MAX; j++ ) { if( tasks_immed[ j ] == TSK_IMM_EMPTY_ ) { #ifdef _renge_test_ NOP(); j += 1; for( ; j < TASK_IMMED_RUN_LIST_MAX; j++ ) { if( tasks_immed[ j ] != TSK_IMM_EMPTY_ ) { NOP(); // ? } } #endif break; // リストの最後 } if( tasks_immed[ j ] == TSK_IMM_DELETED_ ) { tasks_immed[ j ] = TSK_IMM_EMPTY_; } } EI(); } } } #if 0 while( last_task_id != 0xFF ); // タスクが残っていたら延々再実行 #else while( 0 ); #endif if( last_task_id != 0xFF ) { // まだタスクが残ってる(また呼んでね) return( ERR_ERR ); } return( ERR_SUCCESS ); } /****************************************************************************** 単位は ms NOPを回すだけ、指定時間CPUを *占有します* 。 割り込みとか入るとその分遅れます。 少し誤差あります。 *****************************************************************************/ void wait_ms( u8 ms ){ u16 fine; WDT_Restart(); // まだ適当です! while( ms != 0 ){ ms--; #ifdef _OVERCLOCK_ fine = 860; #else fine = 430; #endif while( fine != 0 ){ fine -= 1; } } }