キーボード制御LED——S 3 C 44 B 0 XのIRQプログラミング
「簡単なS 3 C 44 B 0 X Bootloader」で説明したBootloaderには異常な処理はありません.これは明らかに実用的ではありません.次に、キーボード制御LEDの例と組み合わせて、このBootloaderでIRQの処理を実現します.
まず基本的な情報を明確にします.原理図によると、私のボードには、1 x 4キーボードの4つのボタンがそれぞれS 3 C 44 B 0 XのEXTINT 4~7の4つのピンに接続されており、これらの外部割り込み信号によってボタンの押下を処理することができます.PGIOの詳細は後述しませんが、参照コードは問題ないはずです.LEDの詳細については、「最初のランニングランププログラム」を参照してください.
『簡単なS 3 C 44 B 0 X Bootloader』のheadを思い出す.sでは,カーネル異常ベクトルテーブルを予約し,処理はいずれもデッドサイクルに入った.もう二度とそんなことはできません実際の内容を記入する必要がありますすなわち、ISR(Interrupt Service Routine、割り込みサービスルーチン)である.また、ARM 7アーキテクチャの特性のため、ISRに陥る前にIRQモード(irq mode)およびそのモードでのスタックを初期化する必要がある(ISRは、一般的にはC関数を呼び出すなどのスタック操作を多く有するため、このステップは少なくない).改善されたコードは以下の通りである.
head.s
.equ KERNEL_STACK, 0x0c002000 @ ( )
.equ KERNEL_LIMIT, 0x0c001000 @
.equ IRQ_STACK, 0x0c002200 @ IRQ
.text
vectors:
@ 0x0c000000(RAM)
b undef_handler @ 0
b swi_handler @ 1
b pabort_handler @ 2
b dabort_handler @ 3
b irq_handler @ 4
b fiq_handler @ 5
.space 0x100 - 6 * 4
@ 0x0c000100
start:
@
ldr sp, = KERNEL_STACK @ svc
ldr sl, = KERNEL_LIMIT @ svc
@ IRQ
mrs r0, cpsr @ ( )
msr cpsr_all, #0x000000d2 @ IRQ FIQ,ARM , irq
ldr sp, = IRQ_STACK @ IRQ
msr cpsr_all, r0 @ ( )
@ C
bl entry @ C
mov pc, #0 @
undef_handler:
swi_handler:
pabort_handler:
dabort_handler:
fiq_handler:
b . @
irq_handler:
stmfd sp!, {r0-r12, lr} @ C ,
bl on_irq @ ISR C
ldmfd sp!, {r0-r12, lr} @
subs pc, lr, #4 @ IRQ
これでISR全体をon_に置くことができますIRqというC関数に対応していて便利ですね.アプリの部分を見るとmain.c里:
main.c
#define PORT(addr) (*(volatile int *)(addr))
#define PCONC PORT(0x01d20010)
#define PDATC PORT(0x01d20014)
#define PCONG PORT(0x01d20040)
#define PDATG PORT(0x01d20044)
#define EXTINT PORT(0x01d20050)
#define EXTINTPND PORT(0x01d20054)
#define INTCON PORT(0x01e00000)
#define INTPND PORT(0x01e00004)
#define INTMOD PORT(0x01e00008)
#define INTMSK PORT(0x01e0000c)
#define I_ISPR PORT(0x01e00020)
#define I_ISPC PORT(0x01e00024)
static void init(void)
{
PCONC = 0xaaaaaa56; /* PC1~3=output */
PCONG = 0xff00; /* PG4~7=EINT4~7 */
PDATC = 0x0000; /* LED */
#ifdef LOW_LEVEL
EXTINT = 0x00000000; /* EINT4~7= */
#else
EXTINT = 0x22220000; /* EINT4~7= */
#endif
INTCON = 0x5; /* ,IRQ */
INTMOD = 0x000000; /* EINT4~7=IRQ mode */
INTMSK = 0x03dfffff; /* EINT4~7=IRQ */
}
static void led(int num, int light)
{
if (light)
PDATC |= 1 << num;
else
PDATC &= ~(1 << num);
}
static void key(void) /* */
{
static int stat[3]; /* LED */
int i;
for (i = 0; i < 3; i++) {
if (!(EXTINTPND & (1 << i)))
continue; /* , */
if (!stat[i]) { /* LED */
led(i + 1, 1); /* LED */
stat[i] = 1;
#ifdef LOW_LEVEL
/* */
EXTINT &= ~(0x6 << (16 + (i << 2)));
EXTINT |= 0x1 << (16 + (i << 2));
#endif
} else { /* LED */
led(i + 1, 0); /* LED */
stat[i] = 0;
#ifdef LOW_LEVEL
/* */
EXTINT &= ~(0x7 << (16 + (i << 2)));
#endif
}
EXTINTPND |= 1 << i; /* */
}
}
void entry(void)
{
init();
while (1); /* ISR , */
}
void on_irq(void) /* ISR */
{
if (!(I_ISPR & 0x200000))
return; /* EXTINT4~7 */
if (!(INTPND & 0x200000))
return; /* EXTINT4~7 */
key(); /* */
I_ISPC |= 0x200000; /* EXTINT4~7 */
}
最後に、boot.sのresetサブルーチンの先頭に、svcモードのCPSR制御ビットのIビット(IRQ割り込み制御ビット)を開くことを忘れないでください.
reset:
@ initialize s3c44b0x
mov r0, #0x00000053 @ enable IRQ, disable FIQ, ARM state, svc mode
msr cpsr_all, r0 @ set CPSR
...
特に言うことはありませんが、注釈は全部書いてあります.注意gccコンパイルオプションはLOW_を定義していますLEVELはレベルトリガ方式を採用し、そうでなければ下降エッジトリガを採用する.キー0~2はLED 1~3に対応します.レベルトリガモードでは、押すとランプが点灯し、放すとランプが消灯する.エッジトリガモードで、ランプを押して点灯し、もう一度押すと消灯します.
この雛形があれば,種々のIRQをプログラミング処理することができる.