您的位置:首页 > 其它

Tiny4412中断介绍

2015-09-02 13:40 267 查看
  通过几天裸板驱动开发,今天对ARM的中断做一些简单总结,前面我们已经了解了ARM的7种异常模式,中断是异常模式的一种,在ARM中异常事件发生将会触发中断,但是,所有的中断都不能直接访问cpu,而是都统一由GIC(中断管理器)来管理;下面是samsung提供的模式图:



其中GIC管理的中断有分为:

 


  (1)SGI:一个cpu中断另一个cpu(cpu0 ->cpu1)

  (2)PPI:一个中断只能中断一个cpu

  (3)SPI:一个中断可以中断多个cpu

  处理一个中断大致需要三步:

  (1)cpu permit interrupt (cpu允许中断)

  (2)GIC enable (启用GIC)

  (3)SET Interrupt source (设置中断源)

  下面是用SGI实现的一个程序:

  头文件:

#ifndef __BUNFLY_H
#define __BUNFLY_H

#define ICCICR_CPU0    (*(volatile unsigned long *)0x10480000)
#define ICCPMR_CPU0    (*(volatile unsigned long *)0x10480004)
#define ICDDCR        (*(volatile unsigned long *)0x10490000)
#define ICDIPR2_CPU0    (*(volatile unsigned long *)0x10490408)
#define ICDIPTR2_CPU0    (*(volatile unsigned long *)0x10490808)
#define ICDISER0_CPU0    (*(volatile unsigned long *)0x10490100)
#define ICDSGIR        (*(volatile unsigned long *)0x10490f00)
#define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010)
#define ICCIAR_CPU0  (*(volatile unsigned long *)0x1048000c)

#endif    //__BUNFLY_H


#include "bunfly.h"

int (*printf)(char *, ...) = 0xc3e114d8;
void enable_mmu();
void init_table(unsigned long *addr);
void memcpy(unsigned char *dest, unsigned char *src, int len);
extern unsigned long  vector_start;
void do_irq();

int main()
{
memcpy(0x70000000, vector_start, 0x1000);
enable_mmu();

*(unsigned long *)0x47000000 = do_irq;

//step 1: set cpu permit interrupt
__asm__ __volatile__(
"mrs r0, cpsr\n"
"bic r0,r0, #0x80\n"
"msr cpsr, r0\n"
:::"r0"
);

//step 2: set GIC (cgi) enable
ICCICR_CPU0 = 1;//cpu接口控制寄存器(总开关)
ICCPMR_CPU0 =0xff;//中断总优先级(门槛)
ICDDCR = 1;//本中断开关
ICDIPR2_CPU0 = (3 << 9);//本中断优先级
ICDIPTR2_CPU0 = (1 << 9);//目标cpu
ICDISER0_CPU0 = (1 << 9);//启用本中断

//step 3: set interrupt source
ICDSGIR = 9 | (1 << 16);

printf("welcom back\n");
}

void do_irq()
{
unsigned long ack_id = 0;
unsigned long cpu_id = 0;
unsigned long data = ICCIAR_CPU0;

/*clean interrupt*/
ack_id = data & 0x3ff;
cpu_id = data & (0x7 << 10);
ICCEOIR_CPU0 = ack_id | cpu_id;

printf("this is interrupt\n");
printf("cup_id is %d\n", cpu_id >> 10);
printf("ack_id is %d\n", ack_id);

}

void memcpy(unsigned char *dest, unsigned char *src, int len)
{
int i = 0;
for(i = 0; i < len; i++) {
dest[i] = src[i];
}
}

void enable_mmu()
{
/*构建表*/
unsigned long addr = 0x50000000;
init_table(addr);
/*打开mmu*/
unsigned long mmu = 0;
mmu = 1 | (1 << 1) | (1 << 3) | (1 << 8);
__asm__ __volatile__ (
"mov r0, #3\n"
"MCR p15, 0, r0, c3, c0, 0\n"//设置为管理员
"MCR p15, 0, %0, c2, c0, 0\n"//设置表的地址
"MCR p15, 0, %1, c1, c0, 0\n"//开启mmu
:
:    "r" (addr), "r" (mmu)
:
);

}

__asm__(

"vector: \n"
"    b reset\n"
"    b und\n"
"    b swi\n"
"    b pre_abt\n"
"    b data_abt\n"
"    .word 0x0\n"
"    b irq\n"
"    b fiq\n"
"reset:\n"
"und:\n"
"    mov sp, #0x47000000\n"
"    stmdb sp!, {r0-r12, lr}\n"

"    ldr r3, =0x47000004\n"
"    ldr r2, [r3]\n"
"    blx r2\n"

"    mov sp, #0x47000000\n"
"    ldmdb sp, {r0-r12, pc}^    \n"

"swi:\n"
"    mov sp, #0x47000000\n"
"    stmdb sp!, {r0-r12, lr}^\n"

"    mov sp, #0x47000000\n"
"    ldmdb sp, {r0-r12, pc}^    \n"

"pre_abt:\n"

"data_abt:\n"
"    mov sp, #0x47000000\n"
"    sub lr, lr, #4\n"
"    stmdb sp!, {r0-r12, lr}\n"

"    ldr r3, =0x47000008\n"
"    ldr r2, [r3]\n"
"    blx r2\n"

"    mov sp, #0x47000000\n"
"    ldmdb sp, {r0-r12, pc}^    \n"
"irq:\n"

"    mov sp, #0x47000000\n"
"    sub lr, lr, #4\n"
"    stmdb sp!, {r0-r12, lr}\n"

"    ldr r3, =0x47000000\n"
"    ldr r2, [r3]\n"
"    blx r2\n"

"    mov sp, #0x47000000\n"
"    ldmdb sp, {r0-r12, pc}^    \n"

"fiq:\n"

".global vector_start\n"
"vector_start: \n"
".word vector \n "

);

void init_table(unsigned long *addr)
{
unsigned long va = 0;
unsigned long phys = 0;

//0x40000000-0x80000000 -> 0x40000000-0x80000000
for(va = 0x40000000; va < 0x80000000; va += 0x100000) {
phys = va;
addr[va >> 20] = phys | 2;
}

//0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x10000000; va < 0x14000000; va += 0x100000) {
phys = va;
addr[va >> 20] = phys | 2;
}
//0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x0; va < 0x10000000; va += 0x100000) {
phys = va + 0x70000000;
addr[va >> 20] = phys | 2;
}

}


运行结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: