首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

[原创]初学ARM-学习笔记(一)

[原创]初学ARM-学习笔记(一)

   初学ARM,犹如幼儿学步,蹒跚跌撞,始获得一点点站立的经验.
    深恐日后忘却,故做了一些日记.
    今日无事,整理一下,贴之于论坛,希望:
    1) 于我一样在入门时迷茫的朋友,希冀能提供一点帮助,少走点弯路.
    2) 于我理解的错误,希冀有高人指点一二.
    3) 没有第3了,我刚才明明想到3点的,忘了,呵呵.


【开发环境】keil for arm 2.40a
【arm 芯片】LPC2138
===========================================================================
2006/05/8
关于向量中断


Vectors:        LDR     PC,Reset_Addr        
                LDR     PC,Undef_Addr
                LDR     PC,SWI_Addr
                LDR     PC,PAbt_Addr
                LDR     PC,DAbt_Addr
                NOP                            /* Reserved Vector */
;               LDR     PC,IRQ_Addr
                LDR     PC,[PC, #-0x0FF0]      /* Vector from VicVectAddr */
                LDR     PC,FIQ_Addr


Reset_Addr:     DD      Reset_Handler
Undef_Addr:     DD      Undef_Handler?A
SWI_Addr:       DD      SWI_Handler?A
PAbt_Addr:      DD      PAbt_Handler?A
DAbt_Addr:      DD      DAbt_Handler?A
                DD      0                      /* Reserved Address */
IRQ_Addr:       DD      IRQ_Handler?A
FIQ_Addr:       DD      FIQ_Handler?A


    为什么是 LDR PC,[PC,#-0x0FF0]?
    irq的向量号是6,中断时的PC地址是0x18.
    基于ARM的机构,此指令<=>LDR PC,[0x20,#-0x0FF0] <=> LDR PC,[#-0x0FD0]
    对32位数, -0x0FD0 = 0xFFFF F030.
    这个就是向量中断地址寄存器的地址.
    当向量中断irq中有某个中断源发生中断,VICVectAddr中存放的是那个发生中断的中断源
    的ISR地址.
    这样,LDR PC,[PC,#-0x0FF0]将自动跳转到ISR处理程序.
 
VICVectAddr  0xFFFF F030
 ...    ...
VICVectAddr0 0xFFFF F100 
VICVectAddr0 0xFFFF F104
    ...    ...
===========================================================================
2006/05/9
中断嵌套的问题


对于采用VIC的芯片,有时候涉及到中断嵌套的问题.
比如我现在做的LED显示,VIC中断分配如下:
TIMER1: 用做ARTX操作系统的时钟源.
TIMER0: 用于LED显示扫描.
UART0:  用做通讯.
这里的关键是: TIMER0必须没大约1ms中断一次,而每次扫描的时间从100us-400us不等.
为了不至于使UART的数据丢失,在TIMER0进入中断后,必须"立即"使能UART0的中断.
但UART0和TIMER0都是使用的同一个中断irq.当TIMER0进入中断后,PSR中的I位是自动置'1'了的.
也就是irq已经禁止了.
我强行打开I如何?但如果TIMER0没执行完毕,而UART0中断发生,势必会破坏寄存器的内容.
所以此时涉及到中断嵌套的问题.


keil建议的解决方案如下:


void timer0_srv (void) __irq {
  T0IR        = 1;                            // Clear interrupt flag
  IENABLE;                                    // allow nested interrupts
  longtimerdelay ();                          // 这里处理一段花费比较长时间的任务
  IDISABLE;                                   // disable interrupt nesting
  VICVectAddr = 0;                            // Acknowledge Interrupt
}
// Macros for Interrupt Nesting
#define IENABLE                      /* Nested Interrupts Entry */   \
  __asm { MRS     LR, SPSR      }    /* Copy SPSR_irq to LR     */   \
  __asm { STMFD   SP!, {LR}     }    /* Save SPSR_irq           */   \
  __asm { MSR     CPSR_c, #0x1F }    /* Enable IRQ (Sys Mode)   */   \
  __asm { STMFD   SP!, {LR}     }    /* Save LR                 */   \


#define IDISABLE                      /* Nested Interrupts Exit */   \
  __asm { LDMFD   SP!, {LR}     }     /* Restore LR              */   \
  __asm { MSR     CPSR_c, #0x92 }     /* Disable IRQ (IRQ Mode)  */   \
  __asm { LDMFD   SP!, {LR}     }     /* Restore SPSR_irq to LR  */   \
  __asm { MSR     SPSR_cxsf, LR }     /* Copy LR to SPSR_irq     */   \


==============================================================

返回列表