PSoC 3 で多重割り込みを試す [PSoC]
PSoC 3 は、 8051 という CPU を搭載しています。 他の CPU と同じように 8051 も割り込みという仕掛けをもっていて、 PSoC 3 の場合には、複数の割り込み要求に対して 8 レベルの優先順位を割り当てることができます。 この記事では、優先順位を設定することによって、多重割り込みの実験を行います。
実験プロジェクト
今回の実験では、このような回路を作成しました。 回路は、二つの周期割り込みと状態表示用の LED 出力と LCD 出力から構成されており、 CY8CKIT-030 でそのまま試すことができます。
周期割り込み ISR_slow は、 1Hz 周期のクロック Clock_slow の立ち上がりで駆動されます。 また、周期割り込み ISR_fast は、 10Hz 周期のクロック Clock_fast の立ち上がりで駆動されます。
クロックの設定
これらのクロックは、バスクロックに比べるとはるかに遅い周波数のクロックです。 デフォルトの設定にすると、 Internal Low-speed Oscillator (ILO) と呼ばれる 1kHz のクロックを使用することになりますが、 ILO クロックは精度が著しく低くなっています。 そこで、 Design-wide クロックと呼ばれる 60kHz のクロックを作成して、このクロックを分周して 1Hz と 10Hz のクロックとしています。 こうすると、比較的高精度な Internal Main Oscillator (IMO) をクロック源とするクロックを得ることができます。 クロックは、 CYDWR ファイルの Clock タグから設定することができます。
ソースコード
ソースコードは、二つの Interrupt Service Routine (ISR) と main 関数で構成されています。
/* ======================================== * * Copyright noritan.org, 2012 * All Rights Reserved * UNPUBLISHED, LICENSED SOFTWARE. * * CONFIDENTIAL AND PROPRIETARY INFORMATION * WHICH IS THE PROPERTY OF NORITAN.ORG. * * ======================================== */ #include <device.h> uint16 n_ISR_slow = 0; uint16 n_ISR_fast = 0; CY_ISR(ISR_slow_func) { n_ISR_slow++; LED4_Write(1); CyDelay(500); // Stay for 500msec LED4_Write(0); } CY_ISR(ISR_fast_func) { n_ISR_fast++; LED3_Write(1); CyDelay(10); // Stay for 10msec LED3_Write(0); } void main() { /* Place your initialization/startup code here (e.g. MyInst_Start()) */ ISR_slow_StartEx(ISR_slow_func); ISR_fast_StartEx(ISR_fast_func); LCD_Start(); CyGlobalIntEnable; /* Uncomment this line to enable global interrupts. */ for(;;) { /* Place your application code here. */ LCD_Position(0, 0); LCD_PrintDecUint16(n_ISR_slow); LCD_PrintString(" "); LCD_Position(1, 0); LCD_PrintDecUint16(n_ISR_fast); LCD_PrintString(" "); } } /* [] END OF FILE */
割り込み処理ルーチン ISR_slow_func と ISR_fast_func は、割り込みが受付られた時に呼び出されます。 割り込みが実行されると、変数 n_ISR_slow または n_ISR_fast がインクリメントされ、割り込みが受け付けられた回数を示します。 ISR では、特別な処理を行っていませんが、処理を行うかわりに CyDelay 関数を呼び出して、時間稼ぎをおこなっています。 ISR_slow_func の場合、 CyDelay の処理時間は 500ミリ秒に設定されていますので、 CPU の実行時間の 50% を消費するということになります。 同じように、 ISR_fast_func は 10ミリ秒に設定されていますので、 10% の CPU 時間を消費します。 さらに、これらの ISR では、処理中に LED3 または LED4 を点灯させる処理を行っています。 LED の点灯状態をみると、割り込み処理の状態を知ることができます。
main 関数では、初期設定を行った後は、延々と LCD に変数 n_ISR_slow と n_ISR_fast の値を表示しています。 main 関数に許された CPU 時間は全体の 40% ですが、 LCD に数値を表示するには、十分な時間です。
デフォルトの優先順位を使った場合
デフォルトの状態では、二つの割り込みの優先順位はどちらも "7" に設定されています。 これは、片方の割り込みが処理されているときには、もう片方の割り込みは受け付けられないということを意味します。
この状態での処理をシーケンス図に描くとこのようになります。 ISR_slow が処理されている 500ミリ秒の間、 ISR_fast は受け付けられません。 そのため、一秒間に10回、 ISR_fast 割り込みの要求があるにもかかわらず、実際に受け付けられるのは、5回だけです。
LCD の表示を見ると、下段の n_ISR_fast が上段の n_ISR_slow の5倍の値を示します。 これは、一秒間に5回分の割り込みが受け付けられなかったことを示しています。
LED の点灯状態を見ると、 LED4 が消灯している時にかぎり、 LED3 が点灯(点滅)することがわかります。 また、 LCD の表示は main 関数本体で行っているため、 LED4 が消灯している時に更新されています。
以上のように、 ISR_slow の処理時間が長くなると、 ISR_fast が受け付けられず、割り込み要求をとりこぼしてしまうことがわかりました。
ISR_fast の優先順位を上げた場合
このままでは、 ISR_fast が想定通りに実行されないので、 ISR_slow が処理されている間でも ISR_fast 割り込みが受け付けられるようにします。 そのためには、 ISR_fast の優先順位を ISR_slow よりも高くしてやります。
この優先順位の割り当ては、もちろん PSoC Creator の GUI から行います。 CYDWR ファイルの Interrupt タグを開くと、優先順位を設定するための画面が現れます。 デフォルトの状態では、優先順位は "7" になっています。 数字が小さいほうが優先順位が高くなりますので、ここでは ISR_fast の優先順位を一つ上げて "6" に設定します。
すると、 ISR_slow 割り込みの実行中でも、さらに ISR_fast 割り込みの処理が行われるようになります。 ISR_fast の処理は、一秒間に10回受け付けられます。
LCD の表示を見ると、下段の n_ISR_fast が上段の n_ISR_slow の10倍の値を示します。 これは、 ISR_fast 割り込みが 10Hz の周期で受け付けられたことを示しています。 また、 LED4 が点灯している間でも LED3 が点滅する様子がわかります。 ISR_slow 割り込みの処理中でも ISR_fast 割り込みが受け付けられているからです。
本日の結論
以上のように、割り込みの優先順位を変更することで、割り込み処理中でもほかの割り込みが受け付けられる様子が観測できました。
しかしながら、本来は、割り込み処理に今回の例のように重い処理を書くことは推奨されません。 それは、 ISR_slow が受けつけられている間、 LCD の表示が更新されなかったことからわかるように、割り込みが受け付けられると、メインループの処理が完全に止まってしまうからです。
こういった問題点を解決するための方法については、また、いずれ。
プロジェクト・アーカイブ
関連文献
トランジスタ技術増刊 シリーズ最強!PSoC (ピーソック) 3ボード+デバッグボード 2012年 05月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2012/04/19
- メディア: 雑誌
コメント 0