Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <<ディスパッチャについて>>
- 下記のサンプルはSW1を押すとLED1が点灯し、
- SW2を押すとLED2が点灯するタスク2個のプログラムです。
- (これはあくまでも「ただのサンプル」です)
- ディスパッチャ(タイマ割り込み)が無ければ、もちろんtask1しか実行できません。
- *実行権の切り替え
- たとえば、タスク1を実行中にタイマ割込みが掛かると、
- CPUは割込み処理終了後に実行を再開するタスク1のアドレスを
- スタックメモリ1にプッシュ(退避)してから
- 下記の内容の割込み処理を順に実行します。
- 1)タスク1用の汎用レジスタZLとZH、フラグレジスタSREGの内容をスタックメモリ1に
- プッシュ(退避)する
- 2)現在のスタックメモリ1用のスタックポインタを保存してあったスタックメモリ2用の
- スタックポインタと交換する
- 3)タスク2用の汎用レジスタZLとZH、フラグレジスタSREGの内容をスタックメモリ2から
- ポップ(復帰)する
- 4)RETI命令を実行して、中断していたタスク2の実行を再開する。
- 以上で、タスク1の実行を中断してタスク2へ移行します。
- 文章で説明すると分りにくいですが、下記サンプル1のリストのIRQ13処理を見れば
- すぐに分って貰えると思います。
- タスク2実行中にタイマ割込みが掛かると、同様にしてタスク2からタスク1に移行して、
- タスク1の続きを再開します。
- *初期設定
- タスク1の実行を開始する前に準備(初期設定)として、
- スタックメモリ2の内容を
- 「タスク2実行中に割り込みがかかって、タスク2からタスク1に切り替わり、
- 現在はタスク1を実行中」
- の状態にしておきます。
- つまり、あらかじめスタックメモリ2にはタスク2の実行開始アドレスをセットし、
- 汎用レジスタZH、ZLとフラグレジスタSREGをセットしておきます。
- この3個のレジスタはタスク2の実行を開始すると、
- プログラム中で必要に応じてプログラマによって、
- あるいは命令の実行結果に従って設定されるので、初期設定時は任意の値でかまいません。
- *保存レジスタ
- 各タスクで同じレジスタやメモリを別目的で使用していれば保存が必要です。
- どのレジスタやメモリをスタックに保存するかは、製作するプログラムの構造や
- 機能で決ります。
- したがってプログラム設計時に十分に検討する必要があります。
- 各タスクで、レジスタやメモリがどのような状態になっているのか、
- そしてどのような状態に変わるのか、変えたいのかで決めます。
- 本サンプル1ではZHレジスタを使用していないので、本来はZHを保存する必要がありません。
- しかしZレジスタペアとして使う事が多いので、私は常に保存しています。
- 私がこれまで作ってきたディスパッチャで最も保存数が多い場合でも
- ZL、ZH、YL、YHの4個でした。
- フラグレジスタSREGの保存は必須でしょう。
- *他にもいくつか注意すべきことがあります。
- ユーザー(ソフトウェア)ディスパッチ
- たとえばポーリングループなどで条件成立をひたすら待っていると実行効率が下がるので、
- 条件が成立しなければ、実行権を返して他のタスクを実行します。
- 下記サンプル1のタイマ割込み処理に1命令追加すると、ユーザーディスパッチャになります。
- 実行を中断されたくない時のディスパッチ禁止
- これはタイマ割込みが掛からないようにするだけです。
- リエントラントなサブルーチンの作り方
- サブルーチン内で使用しているレジスタ、メモリはスタックに退避・復帰します。
- などなど。
- *最後に
- これで1個の20MHzーtiny2313が2個の10MHzーtiny2313に変わります
- ・・・なんて甘い話があるわけも無くw
- AVRはマルチタスクなんて全く考慮されていないので、色々な苦労が待ち構えています。
- 私はAVRで大きくて複雑なプログラムを書くことは無いので、
- ディスパッチャを使う頻度はAVRのプログラミングの5回に1回程度の割合です。
- もちろん他のCPUでも応用できます。
- タスク分けの具体例はたとえばアナログデータ収集装置なら、
- 1)AD変換とバッファリング
- 2)操作パネルのSWやロータリエンコ-ダと液晶表示器の処理
- 3)PCとの通信によるファイル転送
- の3タスクなど。
- *サンプル tiny2313用ディスパッチャ プログラムリスト(コード生成部のみ)
- ;***** tiny2313 vectors ***************
- C:000000 c020 rjmp RESET ;00 RESET
- C:000001 9518 reti ;01 INT0
- C:000002 9518 reti ;02 INT1
- C:000003 9518 reti ;03 timer1 Capt
- C:000004 9518 reti ;04 CompA
- C:000005 9518 reti ;05 OVF1
- C:000006 9518 reti ;06 timer0 OVF0
- C:000007 9518 reti ;07 USART RX
- C:000008 9518 reti ;08 UDRE
- C:000009 9518 reti ;09 TX
- C:00000a 9518 reti ;10 ANA_COMP
- C:00000b 9518 reti ;11 PCINT0
- C:00000c 9518 reti ;12 timer1 CompB
- C:00000d c007 rjmp IRQ13 ;13 timer0 CompA
- C:00000e 9518 reti ;14 CompB
- C:00000f 9518 reti ;15 I2C Start Condition
- C:000010 9518 reti ;16 Over Flow
- C:000011 9518 reti ;17 EEPROM EEw_Rdy
- C:000012 9518 reti ;18 WDT
- C:000013 9518 reti ;19 PCINT1
- C:000014 9518 reti ;20 PCINT2
- ;
- ;===== timer0 for dispatch ============
- ; CompA:interval 1mS
- ; execute time about 1uS at 20MHz system clock
- IRQ13:
- C:000015 93ef push ZL ;save ZL,ZH & SREG to currrent stack
- C:000016 93ff push ZH
- C:000017 b7ef in ZL,SREG
- C:000018 93ef push ZL
- ;
- C:000019 2de1 mov ZL,sv_SPL ;exchange SP task1 <--> task2
- C:00001a b61d in sv_SPL,SPL
- C:00001b bfed out SPL,ZL
- ;
- C:00001c 91ef pop ZL ;restore ZL,ZH & SREG from next stack
- C:00001d bfef out SREG,ZL
- C:00001e 91ff pop ZH
- C:00001f 91ef pop ZL
- C:000020 9518 reti ;exec. next task
- ;
- ;***** system setup *******************
- RESET:
- ;----- Port_B
- C:000021 efef ldi ZL,0b11111111 ;b0/1:output_Hi for LED1/LED2
- C:000022 bbe8 out PortB,ZL ;b2/3:input_PullUp for SW1/SW2
- C:000023 e8e3 ldi ZL,0b10000011 ;bit7:output for check
- C:000024 bbe7 out DDRB,ZL
- ;
- ;----- stack2 for task dispatch
- C:000025 e8ef ldi ZL,stack2 ;set stack2($8F) to SPL
- C:000026 bfed out SPL,ZL
- C:000027 e4e1 ldi ZL,LOW(task2) ;push task2 strat adrs for PCL
- C:000028 93ef push ZL
- C:000029 e0e0 ldi ZL,HIGH(task2) ; PCH
- C:00002a 93ef push ZL
- C:00002b 93ef push ZL ; dumy ZL
- C:00002c 93ef push ZL ; ZH
- C:00002d 93ef push ZL ; SREG
- C:00002e b61d in sv_SPL,SPL ;save task2 SPL
- ;
- C:00002f e7ef ldi ZL,stack1 ;set stack1($7F) to SPL
- C:000030 bfed out SPL,ZL
- ;
- ;----- timer0 for 1mS interval
- C:000031 e0e2 ldi ZL,0b00000010 ;set simple-CTC mode
- C:000032 bfe0 out TCCR0A,ZL
- C:000033 e0e4 ldi ZL,0b00000100 ;prescale system clock by 256
- C:000034 bfe3 out TCCR0B,ZL
- C:000035 e4ed ldi ZL,77 ;count up for 1mS interval
- C:000036 bfe6 out OCR0A,ZL
- C:000037 27ee clr ZL ;clear TCNT=0
- C:000038 bfe2 out TCNT0,ZL
- C:000039 e0e1 ldi ZL,0b00000001 ;enable intrpt by comp_A
- C:00003a bfe9 out TIMSK,ZL
- ;
- C:00003b 9478 sei ;intrpt enable
- ;
- ;***** task1 **************************
- task1:
- C:00003c 99b2 sbic PinB,_SW1 ;SW1 pushed ?
- C:00003d 9ac0 sbi PortB,_LED1 ;No, then LED1 OFF
- C:00003e 9bb2 sbis PinB,_SW1 ;SW1 pushed ?
- C:00003f 98c0 cbi PortB,_LED1 ;Yes, then LED1 ON
- C:000040 cffb rjmp task1
- ;
- ;***** task2 **************************
- task2:
- C:000041 99b3 sbic PinB,_SW2 ;SW2 pushed ?
- C:000042 9ac1 sbi PortB,_LED2 ;No, then LED2 OFF
- C:000043 9bb3 sbis PinB,_SW2 ;SW2 pushed ?
- C:000044 98c1 cbi PortB,_LED2 ;Yes, then LED2 ON
- C:000045 cffb rjmp task2
- ;
- HEXファイル
- :020000020000FC
- :1000000020C0189518951895189518951895189555
- :100010001895189518951895189507C0189518955E
- :1000200018951895189518951895EF93FF93EFB7B5
- :10003000EF93E12D1DB6EDBFEF91EFBFFF91EF9173
- :100040001895EFEFE8BBE3E8E7BBEFE8EDBFE1E4CD
- :10005000EF93E0E0EF93EF93EF93EF931DB6EFE7AD
- :10006000EDBFE2E0E0BFE4E0E3BFEDE4E6BFEE2792
- :10007000E2BFE1E0E9BF7894B299C09AB29BC09820
- :0C008000FBCFB399C19AB39BC198FBCF92
- :00000001FF
- 少し具体的ななサンプルですが(といってもLチカですが)
- https://pastebin.com/hZ4EiF7m
- 通常時はスイッチ別にタスク8個で、ゲーム時はシングルタスクで動かしています。
- ソフトウェア(ループ)ディレイはリエントラントで、各タスクで共通して使っています。
- ユーザーディスパッチャは使用していません。
- プログラムリストは省略します。興味ある方は逆アセンブルしてください。
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement