PowerPC VxWorks BSP分析(3.2)——POWERQUICC硬件

简介:
1.2 内存管理单元MMU
clip_image018
clip_image020
1.3 MPC860 中断
clip_image022
MPC860的整个中断体系结构有3个模块:PowerPC 核、SIU 中断控制器SIU IC(SIU Interrupt Controller)和CPM 中断控制器CPMIC(CPM Interrupt Controller)。
PowerPC Core 是指令执行单元,使用异常(Exception)的目的就是要打断它的正常执行,使它转入处理紧急事件的异常处理程序中执行。对于每一类异常,异常发生后PowerPC跳转执行的位置是不同的。这些不同的位置组成了一个表——异常向量表。不同类型的异常在异常向量表中的偏移量不同。例如系统重启异常在异常向量表中的偏移量是0x100,机器自检异常的偏移量是0x200,而外部中断在异常向量表中的偏移量是0x500等等。
clip_image024
SIU 中断控制器负责管理8 个外部中断源(IRQ0 ~7 )和8 个内部中断源(Level0~7)。其中IRQ0一般用作不可屏蔽中断,通过NMI 向PowerPC 内核请求中断,其余15个通过IREQ请求中断。对于8 个内部中断源,包括周期性的中断时钟(PIT)、实时时钟(RTC)、PCMCIA以及CPM等,用户可以通过对寄存器的操作,把它们设定为Level 0~7中的任何一级。这16个中断源之间的优先级SIU IC 已经设定了。其中IRQ0的优先级最高,Level0 其次,IRQ1 再次,依此类推,Level7的优先级最低。
clip_image026
在SIU IC进行SIU中断处理时,有几个重要的寄存器与之相关。它们是中断悬挂寄存器SIPEND、中断屏蔽寄存器SIMASK和中断向量寄存器SIVEC。
CPM中断控制器是对SIU中断控制器的下一级扩展。它管理通信处理模块的各个中断源,并向SIU IC申请中断处理。CPIC接收12个外部中断源和17个内部中断源的中断请求,经过屏蔽和判优处理后,把中断请求送往SIU中断控制器。通过设置CPIC的配置寄存器,CPM在SIU IC中的优先级可以是Level0~7中的任何一级,并且所有的CPM中断源都将以这个优先级向SIU 申请中断。在CPM IC内部,它也为每个中断源分配了一个中断向量号,并且分配了不同的优先级,还可以编程设定哪个中断源为最高优先级。
在CPM的中断源中,如果一个中断源有多个子功能可以产生中断请求,并且每一项子功能的中断请求都可以屏蔽,那么这个中断源称为子块可屏蔽中断。例如,对串行管理通道SMC(Serial Management Channels),每一个SMC有一个事件寄存器SMCE和一个屏蔽寄存器SMCM。用户可以通过对SMCM进行编程,屏蔽掉某项子功能的中断请求功能。假如用户要使用中断接收功能,就应该置位SMCM的RX位以打开接收中断。在中断服务程序中还要读取SMCE,以判断是哪个子功能产生的中断。如果SMCE的RX位已被置位,就表明产生了接收中断,应进入接收中断处理函数。
clip_image028
CPM IC中提供了一些可编程寄存器。通过对这些寄存器进行设置,可以设定CPM IC的工作方式。这些寄存器分别是CPM中断配置寄存器CICR、CPM中断屏蔽寄存器CIMR、CPM中断向量寄存器CIVR、CPM中断悬挂寄存器CIPR和CPM中断服务寄存器CISR。
编写MPC860中断应用程序主要有两个方面的内容:一个是中断初始化程序,另一个是中断服务程序。中断初始化程序首要的工作是初始化中断寄存器,包括打开SIMASK对应的屏蔽位、使能外部中断。如果要使用SIU的外部中断,应该初始化SIEL寄存器,以设定中断是低电平触发还是低跳变触发。如果使用了CPM中断,还应该初始化CICR、CIMR寄存器,以设定CPM在SIUIC中的中断优先级,以及它自身内部的最高优先级中断源。对于子块可屏蔽中断源,还应该打开对应的事件屏蔽寄存器。只有在初始化这些寄存器后,中断源产生的中断才能得到响应。
对于外部中断,PowerPC内核接收到中断请求信号后,会转入异常向量表中的外部中断偏移地址处(0x500)执行。这一段最大长度为256个字节的代码,也可以说是SIU中断的服务程序。在中断初始化程序中,还必须把SIU中断服务程序放到正确的位置。中断服务程序是中断产生后自动跳转执行的程序,它对中断进行处理。对于其中比较复杂的CPM中断,它有两级处理程序,分别是SIU中断服务程序和CPM中断服务程序。
clip_image030
在SIU中断服务程序中,要读取产生SIU中断的中断向量号,根据中断向量号判断中断源,然后跳转到对各个中断源处理的服务程序中执行。如果读到的中断向量号对应的是CPM,要转入CPM中断服务程序中执行。
CPM又有29个中断源,每个中断源对应不同CPM中断向量号。在CPM中断服务程序中,也要读取CPM中断向量号,然后根据中断向量号调用对应的中断处理程序。这样,所有的CPM中断源,在进入中断处理程序之前,都经过了SIU IC和CPM IC两级处理。另外,由于MPC860是RISC处理器,它有许多通用寄存器,在中断服务程序中应该把影响到的寄存器压入到堆栈中,在退出中断服务程序之前再恢复。
下面以CPM的SMC1用作串口,使用中断接收数据为例,说明MPC860的中断应用程序编写过程。
本程序的主函数是main()。它调用smc_init()进行smc初始化,然后循环等待接收数据。smc_init()是初始化函数。它设定smc1的工作方式,初始化接收描述字,然后初始化中断寄存器,并且把SIU中断服务程序拷贝到异常向量表的0x500处。Initbrn()是SIU中断服务程序,也就是外部中断产生后的入口程序。它读取SIU的中断向量号,如果是CPM中断,就调用CPM中断处理程序CPMHandler(),在这个程序中再读取CPM中断向量号,如果是CPM中断,就调用CPM中断处理程序CPMHandler(),在这个程序中再读取CPM中断向量号,处理SMC1发送过来的数据。
另外,函数getimmr()的作用是用汇编指令得到芯片内端口寄存器的基址,getmsr()的作用是读取机器状态字(MSR)的值,getevt()利用MSR的值得到的异常向量表的基址。整个程序代码如下:
#include "pc860.h" /*MPC860寄存器宏定义头文件*/
struct dprbase *pdpr; /*指向双端口内存基址的地址*/
void smc_init() /*初始化SMC函数*/
{
void intbrn(); /*定义SIU中断服务程序*/
int *ptrs,*ptrd; /*SIU中断服务程序搬移的源和目的地址*/
char intlv1=4;/*CPM中断级别*/
pdpr=(struct dprbase *)(getimmr() & 0xFFFF0000); /*得到端口寄存器的基址*/
…… /*初始化SMC的寄存器和工作参数,如工作模式,波特率等*/
…… /*初始化串口数据收发缓冲区的描述字,注意要把接收缓冲区描述字RxBD的中断位置为1*/
ptrs=(int *)intbrn; /*需要搬移的SIU中断服务程序源地址*/
ptrd=(int *)(getevt()+0x500);/*目标地址*/
do /*把SIU中断服务程序搬移到外部中断入口处*/
*ptrd++=*ptrs;
while(*ptrs++!=0x4c000064);/*0x4c000064是SIU中断服务程序返回指令RFI指令的二进制代码*/
pdpr->CICR.IRL2=(unsigned)(intlv1);/*设定CPM的中断级别为4*/
pdpr->CICR.HP0_HP4=0x1F; /*设定PC15为最高优先级中断*/
pdpr->CIMR.SMC1=1;/*打开CPM IC的SMC1中断屏蔽位*/
pdpr->SIMASK.ASTRUCT.LVM4=1;/*打开SIU IC的CPM中断屏蔽位*/
pdpr->CICR.IEN=1;/*使能CPM中断*/
pdpr->SMCE1=0xFF;/*清除SMC1的事件寄存器*/
pimm->SMCM1=1;/*打开子模块可屏蔽的接收中断*/
asm("mtspr 80,0");/*使能中断*/
…… /*使能SMC1的发送和接收功能*/
}
main() /*主函数*/
{
smc_init() /*初始化SMC1*/
while(1);/*等待接收*/
}
#pragma interrupt intbrn /*SIU中断服务程序
void intbrn()
{
void CPMHandler();/*定义CPM中断服务程序*/
asm("stwu r9,-4(r1");/*把GRR9压入堆栈*/
switch(pdpr->SIVEC.IC)/*读取SIU的中断向量号,转入相应处理程序*/
{
case 0x24;/*为CPM对应的中断向量号*/
asm("mfspr r9,8");/*把LR压入堆栈*/
asm("mfspr r9,8");/*把LR压入堆栈*/
asm("mfspr r9,8");/*把LR压入堆栈*/
asm("stwu r9,-4(r1)");
asm("bla CPMHandler")/*调用CPM中断处理函数*/
asm("lwz r9,0(r1)");/*把LR从堆栈中弹出*/
asm("addi r1,r1,4");/*恢复堆栈指针*/
asm("mtspr8,r9");
break;
default:;
}
asm("lwz r9,0(r1); /*把GPR9从堆栈中弹出/*
asm("addi r1,r1,4");/*恢复堆栈指针*/
}
void CPMHandler() /*CPM中断处理程序*/
{
unsigned v1;
pdpr->CIVR.IACK=1;/*把CIVR的IACK位置为1,以读取CIVR中的中断向量号*/
v1=pdpr->CIVR.VN;/*读取中断向量号*/
switch(pimm->CIVR.VN)/*根据中断向量号进行处理*/
{
case 4: /*SMC1的中断向量*/
…… /*SMC1中断处理程序,对接收到的数据进行处理*/
pimm->CISR=1<<(31-11);/*清除IN-SRVCE位*/
break;
default:;
}
}
getimmr() /*得到双端口寄存器的基址*/
{ asm("mfspr3,638");
}
getevt() /*得到中断入口的基址*/
{
if((getmsr() & 0x40)==0)/*如果MSR.IP等于0*/
return(0); /*中断入口在低位*/
else
return(0xFFF00000);/*中断入口在高位*/
}
getmsr() /*得到机器状态寄存器MSR的值*/
{
asm(mfmsr 3; /*把MSR的值读到r3中*/


 本文转自 21cnbao 51CTO博客,原文链接:http://blog.51cto.com/21cnbao/134669,如需转载请自行联系原作者



相关文章
|
7月前
|
Linux 存储控制器
微处理器移植Linxu
微处理器移植Linxu
30 0
|
缓存 内存技术
E500 MMU 架构及VxWorks 下的优化
E500 MMU 架构及VxWorks 下的优化
236 0
E500 MMU 架构及VxWorks 下的优化
|
Linux 芯片
zynq操作系统: Linux驱动开发Gpio中断篇
Linux内核中有一套GPIO框架,管理和控制芯片上的GPIO管教,包括配置输入输出,配置电平高低(输出)和获取电平高低(输入),中断管理。只需要通过读取/sys/class/gpio/gpioN/value的值来获取中断。当然也不是简单的read,而是通过epoll、poll、select等这些IO复用函数来控制,对于epoll或者poll,需要监听的事件是EPOLLPRI或POLLPRI,而不是EPOLLIN或POLLIN,对于select,需要将文件描述符放在exceptfds中,而且文件描述符被触发时需要通过调用read读取数据,还要通过lseek将文件流指针置回文件开头。
1228 0