Cortex-M3的中断架构和以往的ARM7、ARM9、ARM11有了很大的区别,IRQ、FIQ的概念的已经消失,随之而来的是NVIC中断管理(支持最多256个中断优先级,128级抢断)及中断向量表。这个中断向量表似有相识之感,在当时大学时期学习DOS平台下的C语言开发的时候,在设置BIOS时钟中断的时候,就曾把中断函数的指针地址设置到时钟中断的入口地址区,以期中断发生的时候,执行指定的函数。当然不仅是时钟中断,其它的中断的处理方式也类似。在DOS那个时代,估计最高深一点的编程就是程序驻留和钩子函数(姑且把修改中断地址以截获信息的这一类函数为钩子函数吧),以此看来,Cortex-M3的中断架构倒是借鉴了BIOS的中断处理机制。

ARM公司大力推出Cortex-M3系列CPU核,一改往日的命名方式,并且内存映射、中断架构等以往因不同芯片厂商而多变的架构,变得统一起来。看来ARM其志不小,想要在嵌入式领域开发技术层面一统江湖。这种统一意义巨大,大大降低了嵌入式软件移植的难度,不知道今后这种改变,能否在嵌入式领域中催生出类似昔日PC领域的王者组合:操作系统(Microsoft)+CPU(Intel)。

.Net Micro Framework的整个底层架构是建立在ARM7和ARM9基础之上的,而Cortex-M3的出现,大大的冲击了这一架构,这也是在MF3.0源码中就已经出现了CortexM3的目录,而到现在官方无一款可支持的Cortex-M3开发板的原因。因为要改动的代码太多,要保持ARM7、ARM9和Cortex-M3的代码统一太难。

所以在这里我单立了一个目录,大力进行修改而不遗余力(所谓不破不立),我觉得,这也是我们在一个划时代事物出现的面前,所应持有的态度和立场。

在第4回<修改启动代码&重写向量表>中我们所写的中断向量表,我们要进行一番调整,以期支持动态加入中断函数的功能。

新的中断函数表,我们仅需预先填写前三项:(1) 堆栈TOP地址,(2)复位地址,(3)不可屏蔽中断函数地址(NMIException)。VectorsTrampolines.s修改后的代码如下(和以前的代码相比,是不是简化了很多):

 

   
   
   
   
  1. EXPORT  ARM_Vectors  
  2.  
  3.     IMPORT  StackTop  
  4.  
  5.     IMPORT  EntryPoint  
  6.  
  7.      IMPORT  NMIException  
  8.  
  9.       
  10.  
  11. ;********************************************************   
  12.  
  13.     AREA |.text|, CODE, READONLY  
  14.  
  15.    
  16.  
  17.     ;向量表   
  18.  
  19. ARM_Vectors  
  20.  
  21.          DCD  StackTop                   ; Top of Stack  栈顶  
  22.  
  23.          DCD  EntryPoint                                    ; 复位  
  24.  
  25.          DCD  NMIException  
  26.  
  27.     ;...                            ; 向量表定位在 RAM中,由程序动态生成  
  28.  
  29.     SPACE  384                     ; 预留空间 (76 - 3) * 4 = 292      
  30.  
  31.       
  32.  
  33. ;*********************************************************   
  34.  
  35.     END  
  36.  
  37.    
  38.  

其中SPACE 384的代码也可以不要,不过要确保Scatterfile_tools_mdk.xml文件中,如下项没有

 

   
   
   
   
  1. <ExecRegion Name="ER_RAM_RO" Base="0x20000000" Options="ABSOLUTE" Size=""> 
  2.  
  3.        <FileMapping Name="VectorsTrampolines.obj" Options="(+RO, +FIRST)" /> 
  4.  
  5.        <FileMapping Name="*" Options="(SectionForFlashOperations)" /> 
  6.  
  7.   ExecRegion> 
  8.  

此外还有一个改进就是删除我们原先在\DeviceCode\Targets\Native\CortexM3\DeviceCode目录下的建立的VectorsHandler_Temp库文件,这个库我们已经不需要了,我们随时根据需要,动态的在中断向量表中写入我们所需的中断函数地址。

好了,在\DeviceCode\Targets\Native\CortexM3\DeviceCode目录中建立NVIC目录(相当于以前体系的INTC),在写具体代码之前,我们现在写下如下代码(大概),这是对NVIC相关寄存器的描述。

   
   
   
   
  1. struct CortexM3_NVIC  
  2.  
  3. {     
  4.  
  5.     static const UINT32 c_Base = 0xE000E100;  
  6.  
  7.     //中断使能 置位复位  
  8.  
  9.     /****/ volatile UINT32 SETENA[2];  
  10.  
  11.     UINT32  RESERVED0[30];  
  12.  
  13.     /****/ volatile UINT32 CLRENA[2];  
  14.  
  15.     UINT32  RSERVED1[30];  
  16.  
  17.       
  18.  
  19.     //中断悬起 置位复位  
  20.  
  21.     /****/ volatile UINT32 SETPEN[2];  
  22.  
  23.     UINT32  RESERVED2[30];  
  24.  
  25.     /****/ volatile UINT32 CLRPEN[2];  
  26.  
  27.     UINT32  RESERVED3[30];  
  28.  
  29.       
  30.  
  31.     //中断活动状态  
  32.  
  33.     /****/ volatile UINT32 ACTIVE[2];  
  34.  
  35.     UINT32  RESERVED4[62];  
  36.  
  37.    
  38.  
  39.     //中断优先级  
  40.  
  41.     /****/ volatile UINT8 PRI[60];  
  42.  
  43.       
  44.  
  45.     static const UINT32 c_IRQ_MAX_INDEX = 16+60;  
  46.  
  47.       
  48.  
  49.     //IRQ Index Table      
  50.  
  51.     static const UINT32 c_IRQ_Index_NMI = 0x2;  
  52.  
  53.     static const UINT32 c_IRQ_Index_HardFault = 0x3;  
  54.  
  55.     static const UINT32 c_IRQ_Index_MemManage = 0x4;  
  56.  
  57.     static const UINT32 c_IRQ_Index_BusFault = 0x5;  
  58.  
  59.     static const UINT32 c_IRQ_Index_UsageFault = 0x6;  
  60.  
  61.     //7,8,9,A NULL  
  62.  
  63.     static const UINT32 c_IRQ_Index_SVC = 0xB;  
  64.  
  65.     static const UINT32 c_IRQ_Index_DebugMonitor = 0xC;  
  66.  
  67.          //D NULL  
  68.  
  69.     static const UINT32 c_IRQ_Index_PendSVC = 0xE;  
  70.  
  71.     static const UINT32 c_IRQ_Index_SysTick = 0xF;    
  72.  
  73.     //--  
  74.  
  75.     static const UINT32 c_IRQ_Index_WWDG = 0x10;    
  76.  
  77.     static const UINT32 c_IRQ_Index_PVD = 0x11;   
  78.  
  79.     static const UINT32 c_IRQ_Index_TAMPER = 0x12;    
  80.  
  81.      //略  
  82.  
  83.     static const UINT32 c_IRQ_Index_DMA2_Channel3 = 0x4A;  
  84.  
  85.     static const UINT32 c_IRQ_Index_DMA2_Channel4_5 = 0x4B;      
  86.  
  87.    
  88.  
  89.     //IRQ Priority index Table  
  90.  
  91.     static const UINT32 c_IRQ_Priority_NULL = 0xFF;  
  92.  
  93.     static const UINT32 c_IRQ_Priority_Leve0 = 0x00;  
  94.  
  95.     static const UINT32 c_IRQ_Priority_Leve1 = 0x10;  
  96.  
  97.     static const UINT32 c_IRQ_Priority_Leve2 = 0x20;  
  98.  
  99.      //略  
  100.  
  101.     static const UINT32 c_IRQ_Priority_Leve14 = 0xE0;  
  102.  
  103.     static const UINT32 c_IRQ_Priority_Leve15 = 0xF0;  
  104.  
  105. };  
  106.  
  107.    
  108.  
  109. 在NVIC目录下建立三个文件:NVIC.cpp、NVIC.h、doNetMF.proj  
  110.  
  111. NVIC.cpp的核心内容如下:  
  112.  
  113. void CortexM3_NVIC_Driver::Initialize()  
  114.  
  115. {  
  116.  
  117.    //外部中断  
  118.  
  119.    CortexM3_NVIC &NVIC = CortexM3::NVIC();  
  120.  
  121.    NVIC.CLRENA[0]=0xFFFFFFFF;   //清外部中断  
  122.  
  123.    NVIC.CLRENA[1]=0xFFFFFFFF;  
  124.  
  125.    NVIC.CLRPEN[0]=0xFFFFFFFF;  
  126.  
  127.    NVIC.CLRPEN[1]=0xFFFFFFFF;  
  128.  
  129.    
  130.  
  131.    //系统中断  
  132.  
  133.    CortexM3_SCB &SCB = CortexM3::SCB();     
  134.  
  135.    SCB.ICSR = 0x0A000000;  
  136.  
  137.    SCB.VTOR = (UINT32)&IMAGE_RAM_RO_BASE;   // 重定向中断向量表  
  138.  
  139.    SCB.AIRCR = CortexM3_SCB::AIRCR_VECTKEY_MASK | CortexM3_SCB::NVIC_PriorityGroup_1;  
  140.  
  141.    SCB.SCR = 0x00000000;  
  142.  
  143.    SCB.CCR = 0x00000000;  
  144.  
  145.    SCB.SHCSR = 0x00000000;  //系统中断使能位  
  146.  
  147.    SCB.CFSR = 0xFFFFFFFF;     
  148.  
  149.    SCB.HFSR = 0xFFFFFFFF;  
  150.  
  151.    SCB.DFSR = 0xFFFFFFFF;  
  152.  
  153.    
  154.  
  155.    //优先级设定  
  156.  
  157.    IRQ_VECTORING *IsrVector = s_IsrTable;  
  158.  
  159.    for(int i = 0; i < CortexM3_NVIC::c_IRQ_MAX_INDEX; i++)  
  160.  
  161.    {  
  162.  
  163.      //略  
  164.  
  165.    }  
  166.  
  167. }  
  168.  
  169. //激活中断  
  170.  
  171. BOOL CortexM3_NVIC_Driver::ActivateInterrupt(UINT32 Irq_Index,UINT32 ISR)  
  172.  
  173. {  
  174.  
  175.     InterruptEnable(Irq_Index);  
  176.  
  177.     UINT32 *p= (UINT32*)&IMAGE_RAM_RO_BASE + Irq_Index;  
  178.  
  179.          *p=ISR;          
  180.  
  181.     return TRUE;  
  182.  
  183. }  
  184.  
  185. //关闭中断  
  186.  
  187. BOOL CortexM3_NVIC_Driver::DeactivateInterrupt(UINT32 Irq_Index)  
  188.  
  189. {  
  190.  
  191.     InterruptDisable(Irq_Index);  
  192.  
  193.     return TRUE;  
  194.  
  195. }  
  196.  
  197.    
  198.  
  199. BOOL CortexM3_NVIC_Driver::InterruptEnable(UINT32 Irq_Index)  
  200.  
  201. {  
  202.  
  203.     if(Irq_Index<16)  
  204.  
  205.     {  
  206.  
  207.        CortexM3_SCB &SCB = CortexM3::SCB();    
  208.  
  209.              if(Irq_Index==CortexM3_NVIC::c_IRQ_Index_MemManage)  //4  
  210.  
  211.                            SCB.SHCSR |= 0x1<<16;  
  212.  
  213.              if(Irq_Index==CortexM3_NVIC::c_IRQ_Index_BusFault)   //5  
  214.  
  215.                            SCB.SHCSR |= 0x1<<17;  
  216.  
  217.         if(Irq_Index==CortexM3_NVIC::c_IRQ_Index_UsageFault) //6  
  218.  
  219.                            SCB.SHCSR |= 0x1<<18;   
  220.  
  221.                    if(Irq_Index==CortexM3_NVIC::c_IRQ_Index_SysTick)    //15  
  222.  
  223.                    {  
  224.  
  225.                       CortexM3_SysTick &SysTick= CortexM3::SysTick();      
  226.  
  227.                 SysTick.CTRL |= CortexM3_SysTick::CTRL_TICKINT | CortexM3_SysTick::CTRL_ENABLE;  
  228.  
  229.                    }  
  230.  
  231.              
  232.  
  233.     }  
  234.  
  235.          else 
  236.  
  237.          {  
  238.  
  239.             CortexM3_NVIC &NVIC = CortexM3::NVIC();  
  240.  
  241.             int irq=Irq_Index-16;  
  242.  
  243.             NVIC.SETENA[irq/32] = 0x1 << (irq % 32);  
  244.  
  245.          }  
  246.  
  247.     return TRUE;  
  248.  
  249. }  
  250.  
  251. BOOL CortexM3_NVIC_Driver::InterruptDisable(UINT32 Irq_Index)  
  252.  
  253. {  
  254.  
  255.     //略  
  256.  
  257.     return TRUE;  
  258.  
  259. }  
  260.  

在其中,我们为了适应新架构的需要,增加了一个中断函数连接接口,声明如下:

   
   
   
   
  1. BOOL CPU_INTC_ActivateInterruptEx(UINT32 Irq_Index, UINT32 ISR)  
  2.  
  3. {  
  4.  
  5.          return CortexM3_NVIC_Driver::ActivateInterrupt(Irq_Index, ISR);  
  6.  
  7. }  
  8.  

原先的(如下),已经废弃不用(暂保留)。

   
   
   
   
  1. BOOL CPU_INTC_ActivateInterrupt(UINT32 Irq_Index, HAL_CALLBACK_FPN ISR, void *ISR_Param)  
  2.  
  3. {  
  4.  
  5.     return FALSE;  
  6.  
  7. }  
  8.  

 

以上代码中最重要的莫过于“激活中断”函数中的如下代码

UINT32 *p= (UINT32*)&IMAGE_RAM_RO_BASE + Irq_Index;

*p=ISR;   

简单的两行代码,便实现了中断函数的动态注册(在GPIO和串口驱动中我们将详细讲这一点)。

此外,最后要记得在NativeSample.proj添加如下内容:

 

   
   
   
   
  1. <ItemGroup> 
  2.  
  3.    <RequiredProjects Include="$(SPOCLIENT)\DeviceCode\Targets\Native\CortexM3\DeviceCode\Nvic\dotNetMF.proj" /> 
  4.  
  5.    <DriverLibs Include="nvic.$(LIB_EXT)" /> 
  6.  
  7.  ItemGroup> 

前一两个礼拜没有写相关文章,是因为代码修改量很大,一直在调试相关功能。目前GPIO、串口等功能均已经调试通过,所以后续的几天,我便一一介绍它们的实现过程。