JZ2440裸ボードの開発と異常な割り込みプラクティス#7(2)

割り込み

割り込みコントローラ

割り込みについてBenpian話、第I部では、治療は、また他の異常、割り込みコントローラ、その役割の存在との主な違い似ているので、割り込みが、異常で、例外と例外処理について言われています。

>割り込みコントローラ - - 割り込み処理は、割り込みソースです>ハンドラ、ソース割り込みは多くの種類があり、割り込みは、シリアルポート、タイマ割り込みまたは外部割り込みかもしれません。割り込みがマスクされているかどうかをコントローラ制御し、割り込みステータスの割り込み優先レベル。ハンドラと例外ハンドラは、限り、あなたは自分のニーズに応じて書くことができるよう、違いはありません。

 画像が示す割り込みコントローラのブロック図は、割り込み要因は、その唯一の方法二つのサブソースレジスタとSUBSRCPNDサブマスク制御割り込みを除き、二つのソースに分かれ、ほとんど残っています。種類割り込みソースの帰属持っているものS3C2440は、表に記載されています:

 ここではソース割り込み議論の主な供給源である、あなたが自分のニーズ一から一によると、説明したソース割り込み特定の説明を見ることができますが、最も重要なことは、グループ化アービターに理解するために、ソース割り込みソースは5つのグループに分かれています、各超えない6つの割り込み要因、以下に示す最終割当結果は、この割り当ては、割り込み優先レベルアービタの存在を実現するために、主に、各グループ2つの制御信号:1bitARB_mode、2bitsARB_SEL、前記選択ARB_SEL用優先順位付けの方法を中断。優先順位の4種類の2 ARB_SELの4つの組み合わせが最高の優先順位が固定されREQ0、対応する固定REQ5最も低い優先順位を表して、次の図に見られる、そしてREQ1-4 ARB_SELとすることができます回転するには、優先順位ARB_modeをさらにARB_modeが0である場合、我々は変更することができない限り、我々は永久に、ARBS_SELは、優先順位によって決まる固定されている影響を受ける我々は直接優先順位を決定するARB_SELを設定することができ、増加を残し。ARB_mode 1、各割り込み応答時間、および作るARB_SELは、このように優先順位の低い割り込みが応答を取得する機会を持って確保し、最も低い優先度となり、割り込み優先順位が最も高い結果として、1サイクルを左に1を増加させたときので、ここで、ARB_modeラウンドロビンスケジューリングをOSと同様のスケジュール、また、ラウンドロビンスケジューリングとして知られている飢餓を防ぐため、スイッチの言うことができます。

 割り込みコントローラ5は、割り込みソースのソースレジスタの制御を有している:ソースペンディングレジスタ、モードレジスタ割り込みは、マスク
レジスタ、優先ペンディングレジスタと割り込みレジスタを
ウェン最初の対応は、上の図を遮断することができます。

対応する割込みビットがセットされているソースペンディングレジスタと同様の登録保留中の割り込み、割り込みがトリガされたとき、割込みがトリガされたかを示すために使用される、差異はすべてSRCPND割り込みがアサートされたトリガが、唯一の現在のニーズに合わせていることであろうINTPNDセットを処理する割り込み優先順位が最も高いが、SRCPNDはINTPND後に割込み処理に最も高い優先度の割り込みにスクリーニングし、INTPNDシールドと優先レジスタマスクを介して受信しました。それ以外の場合は、繰り返し割り込みを処理された応答であったであろう、これらの二つのレジスタは、プロセスが完了した後にクリアする必要があることに留意すべきです。そして、それはINTPND SRCPNDをクリアした後に再設定されないように、ソースSRCPND-> INTPNDから起動する必要があります。モード設定は、対応するビットが1に設定されています。

 MASKレジスタは割り込み、対応するビットがセットされ、割り込みソースをマスクするために使用され、その後、システムの割り込みは受け付けられません、そしてビットがセットされている割り込みにもSRCPND来る、応答していませんが、セットINTPNDは、直接、または応答処理を必要とする場合(MASK、MASKない制御後INTPND)。

 モードレジスタは、割り込みや通常の割り込み速攻を制御するために使用され、1にすでに彼らはもっと自分自身の排他的レジスタのを持っているので、FIQを説明し、そのためのシーンを維持し、より小さなフィールドのコストを回収することが言われているので、応答速度は、高速であります速攻のため。ここではデフォルト値は0、デフォルトでそのビット通常の割り込みです。

 リコールは、優先度レジスタで、かつ唯一の割り込み優先順位を設定するために、必要に応じて、ロータリースイッチをオンにする必要があること。

 

 コントローラに加えて、割り込みに応答するシステム必要がある場合、また、システムマスタースイッチ割り込み処理またはIビットであるIビットCPSR前記セクションFビットまたは開放を、必要F-ビットはクリア。

ソースレジスタセットINTOFFSET割り込みハンドラ割り込みS3C2440解像度を容易にするために、以下の点を追加し、別の割り込み要因が異なるオフセット値を持って、レジスタ値は直接、標準と比較することができます。

 

外部中断

構成する割り込みコントローラのニーズに加えて、割り込みソースも構成する必要があります。外部割り込みは、外部割り込みスイッチは、所望のボタンのボタンが押されている例では、割り込みは、LEDライトがトリガされます。

https://blog.csdn.net/G_METHOD/article/details/104271762もキーの状態検出、CPUリソースをより消費、および外部割り込みの使用を実施するためのポーリング方法でコンテンツキーを、書かれましたイベントフリーのアプローチは、他のものを処理するCPUが発生することができ、そしてイベントがトリガされたときに、かつタイムリーな治療。概略図をコピーして、キーの足テーブルに対応するボタンをクリックしてください。

EINT0 EINT2 EINT11 EINT19
GPF0 GPF2 GPG3 GPG11

 私たちは、入力ピンに設定し、最後の時間は、キーの状態のためのピンを読むことができ、外部割込みを使用する必要性は、あなたが対応する外部割込みモードに設定する必要があります。図から分かる。限り対応GPxCONピンが外部割り込みピンに設定されます。

 GPIO以外に設定する必要を登録するだけでなく、外部割り込みを設定する必要があります。以下のように、提供さEXTINTトリガは、外部割り込みが低い、高い、上昇、下降、またはダブルエッジトリガで指定することができます。ここでは、選択することができ、自分のニーズや好みに応じて、トリガーダブルエッジを使用することにしました。

 いくつかの外部割り込みピンは外部割込み32を果たしフィルタリング存在するか51、レベルキーがないディザ処理は、割込みトリガボタンの押下操作があってもよい場合、ジッタが存在するであろう押された知ることができることに留意すべきですこのような照明用のボタンなどのイベントが、手ブレ割り込みのトリガ、複数のライトが点滅している一度ボタンを押すたびので、複数回トリガ。アンチシェイクモードは、粗道をフィルタリングし、フィルタリングすることができ、これは、チップの助け私たちは、フィルタリングを行うには、もちろん、あなたが時計の時間とのconfigureフィルタリングに他のレジスタがあり、機能レジスタをフィルタリングオフに書くことができ安定したレベル、待っている遅延の期間があります。

 

 割り込みコントローラは、同様に比較し、外部割込みマスクレジスタ及びレジスタは、同様に、マスクする割り込みマスク本PENDレジスタであり、PENDは、その1つの外部割込みトリガを示します。同様に、割り込みを処理した後、対応するビットPENDをクリアします。

 割り込みコントローラを使用してPNDが割り込みの特定のソースを特定できない場合は、割り込みソースの上記割り込みレジスタが、割り込み要因の割り込みハンドラの制御は、判定された(例えば、いくつかの外部割り込みはEINTフラグを共有あります)この場合には、割り込みの特定のソースを区別PNDに外部割込みレジスタによって必要です。

次のように上記出力コードによれば:

.text
.global _start

_start:
	B RESET	
	LDR pc,UNDEFIE
	LDR pc,SW_INTERRUPT
	B ABORT_PREFETCH
	B ABORT_DATA
	B halt				//reserve
	LDR pc,INTERRUPT
	B FIQ_HANDLE

UNDEFIE:
	.word DO_UND	
	
SW_INTERRUPT:
	.word DO_SWI

INTERRUPT:
	.word DO_INTERRUPT
	

ABORT_PREFETCH:
ABORT_DATA:	
IRQ_HANDLE:
FIQ_HANDLE:
	B halt

DO_UND:
	//1.设置栈
	LDR SP,=0x34000000
	//2.保存现场
	STMDB SP!,{R0-R12,LR}

	//处理函数
	MRS R0,CPSR
	LDR R1,=UND_TEST_STRING
    BL ExecptionHandle
	
	//3.恢复现场,跳转回原来的位置
	LDMIA SP!,{R0-R12,PC}^  //^ 表示将SPSR恢复到CPSR中
	
DO_SWI:
	//1.设置栈
	LDR SP,=0x33e00000
	//2.保存现场
	STMDB SP!,{R0-R12,LR}
	
	//处理函数
	MRS R0,CPSR
	LDR R1,=SWI_TEST_STRING
	SUB R2,LR,#4
    BL SWIHandler
	
	//3.恢复现场,跳转回原来的位置
	LDMIA SP!,{R0-R12,PC}^  //^ 表示将SPSR恢复到CPSR中

DO_INTERRUPT:
	//1.设置栈
	LDR SP,=0x33d00000
	//2.保存现场
	SUBS LR, LR, #4
	STMDB SP!,{R0-R12,LR}
	
	//处理函数
    BL InterruptHandler
    bl testPrint1
	
	//3.恢复现场,跳转回原来的位置
	LDMIA SP!,{R0-R12,PC}^  //^ 表示将SPSR恢复到CPSR中

UND_TEST_STRING:
	.string "enter undefin mode!\n"
	
SWI_TEST_STRING:
	.string "enter swi mode!\n"

.align 4
RESET:
	MOV R0,#0
	LDR R1,[R0]
	
	STR R0,[R0]
	LDR R2,[R0]
	
	CMP R2,R0
	LDR SP,=0x40000000+4096
	MOVEQ SP,#4096
	STREQ R1,[R0]
	
	BL HardwareInitAll
	BL UartInit
	
TEST_UND:
	bl testPrint
	.word 0xdeadc0de
	//bl testPrint
TEST_SWI:
	MRS R0,CPSR
	BIC R0,R0,#0x0F
	MSR CPSR,R0
	SWI 0x123
	
	LDR pc,=main
halt:
    B halt
interrupt.h
----------------------
#ifndef __INTERRUPT_H
#define __INTERRUPT_H


void AllInterruptInit(void);
void InterruptHandler(void);


#endif


 

interrupt.c
-------------------------------

#include "interrupt.h"
#include <stdint.h>

#include "led.h"
#include "s3c2440.h"


static void InterruptControllerInit(void)
{
	//开启全局中断开关
	asm(
		"MRS R0,CPSR \n\t"
		"BIC R0,R0,#0x80 \n\t"
		"MSR CPSR,R0 \n\t"
	);

	//关闭相关中断的屏蔽
	INTMSK &= ~((1<<0) | (1<<2) | (1<<5)); 

}

static void ExternInterruptInit(void)
{
	//设置为外部中断引脚
	GPFCON &= ~((3<<0)|(3<<4));
	GPFCON |= (2<<0)|(2<<4);
	
	GPGCON &= ~((3<<6)|(3<<22));
	GPGCON |= (2<<6)|(2<<22);

	EXTINT0 |= (7<<0) | (7<<8);     /* S2,S3 */
	EXTINT1 |= (7<<12);             /* S4 */
	EXTINT2 |= (7<<12);
	
	/* 设置EINTMASK使能eint11,19 */
	EINTMASK &= ~((1<<11) | (1<<19));
}


void AllInterruptInit(void)
{
	InterruptControllerInit();
	ExternInterruptInit();
}

void ExtInterruptHandler(uint32_t irq)
{
	uint32_t ext_interrupt_bit = EINTPEND;
	
	switch(irq)
	{
		case 0:
		{
			ToggleLed(kLed1);
			break;
		}

		case 2:
		{		
			ToggleLed(kLed2);
			break;
		}
		
		case 5:
		{
			if(ext_interrupt_bit &( 1 << 9 ))
			{		
				ToggleLed(kLed3);
			}
			else if(ext_interrupt_bit &( 1 << 11 ))
			{			
				ToggleLed(kLed1);
				ToggleLed(kLed2);
				ToggleLed(kLed3);
			}
			
			break;
		}
		default:
			break;
	}
	
	EINTPEND = ext_interrupt_bit;
}

void InterruptHandler(void)
{
	uint32_t interrupt_bit = INTOFFSET;

	if(interrupt_bit>=0 && interrupt_bit <=5)
	{
		ExtInterruptHandler(interrupt_bit);
	}

	SRCPND = 1<< interrupt_bit;
	INTPND = 1<< interrupt_bit;
}


このコードは、実際に書き込みワークロード、直接主に割り込み機能を実行するためのボタンを押した後、は常に何らかの形で暴走や不可解な再起動を変更せずにデフォルト値を使用して、それでもカード私を長い間、いくつかのレジスタ、最後の外観ではありませんDISが挙げ異常リターンの異なる値のいずれかをこの時点の異なる処理を必要と発見され、マイナス4の戻り値を中断する必要がプログラムの通常の流れに戻ります。

 

タイマー

タイマーは、彼のために存在のそれをここに入れて、タイミングに使用される名前から言うことができる機能タイマ割り込みだけではなく、割り込み機能を中断。定期的に、または一時的にタスクを実行するために使用することができるPWM出力タイマピンイネーブルレジスタ所定時間発生される割込みタイマを設定した後、一方、タイマーを比較することによって、電力供給制御装置または他のエネルギーが必要周辺機器、呼吸光は、この機能によって達成することができ、それは、クロックソースの周辺機器としても出力することができます。

S3C2440は、5つの16ビットのクロックを持って、クロックが達成するために、コストのため、または困難の異なる理由から、機能的去勢または共有リソースの存在を推定します。TIMER0は、タイマーの最も完全です。

 左から右に、あなたは時計用タイマは、コンテンツが50MHzのPCLKてきた前に駆動するためにPCLKを使用して見ることができます。8ビットプリスケーラは、分割の使用を必要とし、すなわち、また、時間的に分周器を低減することができ、その後、使用されるクロック周波数を低減することができる、PCLKの後に存在する場合登録MUXを分周数を設定することにより、分周選択。TCMPBが出力するPWM波を現在のカウント値を比較するため、比較レジスタ前記タイマは、TCMPB、TCNTBレジスタが存在する、TCNTBは、タイマ値が0である場合、我々は、自動設定とタイマによる初期値のセットと比較しました負荷は、このTCNTBは自動的にカウントレジスタに割り当てられています。二つのレジスタは、いつでも変更可能であることも注目されるのが、次のタイミング・サイクルに必要な時間は、通常の動作に継続的な数を確保するので、有効にするために開始します有効になりません。セレクタが台形であり、続いて、デジタル回路がネゲートされ、続いて、波形の出力を制御するための一つ反転ビットが反転されます。モータを制御するために、古典的なHブリッジ回路のアプリケーションでPWM時間の保障措置ハイパワーモーター、デッド・ゾーンジェネレータデッドバンド・ジェネレータ。実質的にAにオン電圧、ゼロ電位にB、及び回路Aがオンされたときに三極増幅回路装置として、モータMのための中間体(ADは...に関する動画を描画する単純なを使用する必要はありません)下図後者の場合、モータは図2に対応する転送されると仮定。電圧が時間0にBとAに投入されると、B側の回路は、図1の第三の場合に対応し、モータ逆の場合にターンオンされます。場合モータは、それが可能で変異ない真のアナログ電圧で、時間A及びBの切り替え電圧を介して結合し、正からの周りに反転させるために必要な、またはその逆。このとき、デッドタイム期間が存在しない場合には、AとBは、場合に、オン電圧範囲で、電源とグランドに直接短絡、第四の図を引き起こす特に危険であるかもしれないが。私たちはこの問題を解決するため死んだ缶ヘルプは、コンクリートはもはや拡大されません。

S3C2440カウンタは、トリガされるタイマ割り込みのタイミングであると、カウンタが0に低減され、心配、比較的簡単ですが、また、増加または減少するために使用する前にカウンタ32を設定し、ここでしか低減することができ、また考えました。セクションの設定に加えて、タイマ割り込み、タイマ制御を使用したい、また、タイマーと開始を設定する必要があります。関連のレジスタ次のように:

第1の周波数が割り込みのみに使用され、私たちはタイマ1を使用し、8プリスケーラをカウントされ、0にしたがって、唯一のプリスケーラ。最終に従って、周波数分割を使用して複素除算例えば本明細書ライン上事実十分の値は、プリスケーラ99に直接提供適切な値にクロックダウンを作るために、これらの二つの数によって使用される因子、および16が必要もあります式クロックが50MHzの/((99 + 1)* 16)= 31250Hzです。

 クロックを決定した後、カウント値は、タイマ期間を得ることが決定されたいかなるPWM出力比較レジスタが用意されていないため、ここでは必要ありません、のみカウントTCMPB0に初期値を設定する必要があります。上記で得られたクロックに応じて、我々は0.5秒に一度中断期待すると仮定し、あなたが望む効果いったん中断0.5秒を取得することができ、我々は15625の初期値を設定する必要があることを知ることができます。

 どこチューブが反転することはできません最後には、それが出力クロックピンに不要であることから、0の初期値をリロードデフォルト値に自動的にクロック制御レジスタ、唯一の関連タイマーが0に同じ注意、タイマーセットを設定する必要がありますチップのマニュアルに従って初めて手動で手動で設定する手動更新を開始する必要がありますが、次の時間を書き込む前に、このビットをクリアする必要性について述べました。最後に、タイマーを起動します。

 次のようにすることにより、出力にマスク割り込みコードを、関連するタイマーを閉じているときに外部割り込み、唯一のプログラムに基づいて、外部割り込み、プラスタイマー上の他の同様のコンテンツは、ハンドラ割り込みタイマーを初期化されます。

interrupt.c
------------------------------------

#include "interrupt.h"
#include <stdint.h>

#include "led.h"
#include "s3c2440.h"

typedef void (*irq_func)(int);
irq_func irq_array[32];

static void register_irq(int irq, irq_func fp)
{
	irq_array[irq] = fp;
	INTMSK &= ~(1<<irq);
}

void Timer0InterruptHandler(int irq)
{
	ToggleLed(kLed1);
}

void ExtInterruptHandler(int irq)
{
	uint32_t ext_interrupt_bit = EINTPEND;
	
	switch(irq)
	{
		case 0:
		{
			ToggleLed(kLed1);
			break;
		}

		case 2:
		{		
			ToggleLed(kLed2);
			break;
		}
		
		case 5:
		{
			if(ext_interrupt_bit &( 1 << 9 ))
			{		
				ToggleLed(kLed3);
			}
			else if(ext_interrupt_bit &( 1 << 11 ))
			{			
				ToggleLed(kLed1);
				ToggleLed(kLed2);
				ToggleLed(kLed3);
			}
			
			break;
		}
		default:
			break;
	}
	
	EINTPEND = ext_interrupt_bit;
}


static void InterruptControllerInit(void)
{
	//开启全局中断开关
	asm(
		"MRS R0,CPSR \n\t"
		"BIC R0,R0,#0x80 \n\t"
		"MSR CPSR,R0 \n\t"
	);
}

static void ExternInterruptInit(void)
{
	//设置为外部中断引脚
	GPFCON &= ~((3<<0)|(3<<4));
	GPFCON |= (2<<0)|(2<<4);
	
	GPGCON &= ~((3<<6)|(3<<22));
	GPGCON |= (2<<6)|(2<<22);

	EXTINT0 |= (7<<0) | (7<<8);     /* S2,S3 */
	EXTINT1 |= (7<<12);             /* S4 */
	EXTINT2 |= (7<<12);
	
	/* 设置EINTMASK使能eint11,19 */
	EINTMASK &= ~((1<<11) | (1<<19));
	
	register_irq(0,ExtInterruptHandler);
	register_irq(2,ExtInterruptHandler);
	register_irq(5,ExtInterruptHandler);
}

static void Timer0InterruptInit(void)
{
	TCFG0 = 99;  
	TCFG1 &= ~0xf;
	TCFG1 |= 3;

	TCNTB0 = 15625;

	TCON |= (1<<1);

	TCON &= ~(1<<1);
	TCON |= (1<<0) | (1<<3);

	/* 设置中断 */
	register_irq(10, Timer0InterruptHandler);
}


void AllInterruptInit(void)
{
	InterruptControllerInit();
	ExternInterruptInit();
	Timer0InterruptInit();
}

void InterruptHandler(void)
{
	uint32_t interrupt_bit = INTOFFSET;

	irq_array[interrupt_bit](interrupt_bit);

	SRCPND = 1<< interrupt_bit;
	INTPND = 1<< interrupt_bit;
}


 予備的な作業では、タイマーは、関数ポインタの配列は、コードの構造を最適化し使用して正常な機能を削除するには非常に少ない、ここで行うためにここに中断したときに番号と割り込みハンドラ割り込み登録を必要とする割り込み初期化、ので、その合計中断ハンドラコードを減少させるためにカップリング、その後の高機能中に変更される必要はありません。コードの効果はハハ、視覚的に0.5秒、ライトをオフに導きました。

 

公開された19元の記事 ウォン称賛7 ビュー6918

おすすめ

転載: blog.csdn.net/G_METHOD/article/details/104620994