《在proteus中使用arm处理器及uc-os-ii移植理解——lpc2124》由会员分享,可在线阅读,更多相关《在proteus中使用arm处理器及uc-os-ii移植理解——lpc2124(10页珍藏版)》请在金锄头文库上搜索。
1、在在 PROTEUSPROTEUS 中使用中使用 ARMARM 处理器及处理器及 uC-OS-IIuC-OS-II 移植理解移植理解LPC2124LPC2124在 PROTEUS 中使用 ARM 处理器及 uC-OS-II 移植理解LPC2124.txt在 PROTEUS 中使用 ARM 处理器及 uC/OS-II 移植理解LPC2124LPC2124 是基于一个支持实时仿真和跟踪的 16/32 位 ARM7TDMI-S CPU 的微处理器,并带有 256k 的嵌入的高速 Flash 存储器和 16k 的片那静态 RAM。128 位宽度的存储器接口和独特的加速结构使得 32位代码能够在最大的时
2、钟速率下运行。对代码规模有严格控制的应用可使用 16 位 Thumb 模式,将使得代码规模降低超过 30,而性能的损失却很小。LPC2124 片那 Boot 装载程序实现在系统编程(ISP)和在应用编程(IAP) 。1ms 可以编程 512 字节。整片擦除只需要 400ms。此外还有4 路 A/D 转换器,转换时间低于 2.24us;2 个 32 位定时器,6 路PWM 输出、RTC、看门狗和多个串行接口。LPC 系列微处理器的抗干扰能力强,在很多应用中得到了使用。 三软件分析1LPC 的 Memory Map、Remap 和 LPC2124 的 Bootblock 程序Memory Map
3、是把芯片中、芯片外的 Flash、RAM、外设、BootBlock等进行统一编址,用地址来表示对象。LPC 系列 ARM 处理器的这个地址是出厂时,由厂家规定的,用户只能访问,而不能进行更改。Remap 和 Boot,个人理解如下:在 Reset 信号周期内,LPC2124 运行芯片内部自带的 Bootblock 程序,复位信号过后才是运行用户的程序。LPC 系列 ARM 处理器的 Bootblock 被固化在最高的 Flash 块中,运行时是被映射到 0x7FFFE0000x7FFFFFFF 区域,这个程序是厂家写入的,它由任何复位硬件激活,在任何复位后都会先执行 Boot 装载程序。之所以
4、要把 BootBlock 程序放在 Flash 块的顶端,是因为各芯片的 Flash 大小不一致,厂家为了 BootBlock 在芯片中的位置固定,在编址的 2G 靠前的位置虚拟划分一个区域作为 BootBlock 区域。这就是 Remap。BootBlock 的工作如下:1 判断 P0.14 是否为低,如果为低,进入 ISP 模式。2 若 P0.14 不为低,要判断 Boot(1:0)这两个脚,如果为 11,要设置 MEMAP=1,即运行内部 Flash。否则设 MEMAP3,运行外部Flash。3 如果是运行外部 Flash,那需要把外部 Flash 的起始地址重新映射到 0x000000
5、00,以便复位信号过后就开始运行用户程序。个人理解 BootBlock 相当于 PC 中的 BIOS,由厂家固化,上电后首先完成映射,即把它的地址映射到 0x00000000 处,当初始化完成后,就运行内部 Flash 或者外部 Flash 的程序,通常要以向量表开头,这个过程就是 Remap,也就是把内部 ROM 或者外部 Flash 的地址映射到 0x00000000 处。2启动代码分析运行完 BootBlock 程序之后就是要运行用户自己编写的启动代码了。启动代码中最重要的是异常向量表。这个表包括复位、未定义指令、软中断、预取指中止、数据中止、IRQ 中断和 FIQ 中断。ResetLD
6、R PC, ResetAddrLDR PC, UndefinedAddrLDR PC, SWI_AddrLDR PC, PrefetchAddrLDR PC, DataAbortAddrDCD 0xb9205f80 ;插入用户代码有效签名LDR PC, PC, #-0xff0 ;从 VIC 处取得 IRQ 入口地址LDR PC, FIQ_AddrResetAddr DCD ResetInitUndefinedAddr DCD UndefinedSWI_Addr DCD SoftwareInterruptPrefetchAddr DCD PrefetchAbortDataAbortAddr DC
7、D DataAbortNouse DCD 0IRQ_Addr DCD 0FIQ_Addr DCD FIQ_HandlerUndefinedB Undefined ;未定义指令PrefetchAbortB PrefetchAbort ;取指令中止;取数据中止DataAbortB DataAbort ;快速中断未定义指令、取指令中止、快速中断使得 PC 不跳转,进入死循环,等待看门狗复位用户程序。对于 ARM9,有 MMU 单元,应该在PrefetchAbort 和 DataAbort 处进行处理,然后返回到发生异常的指令处重新执行一次。FIQ_HandlerSTMFD SP!, R0-R3, L
8、R ;ADS 编译器会自动保存 R4-R11IMPORT FIQ_Exception ;也可以在 startup.s 的开头引入BL FIQ_Exception ;调用 C 语言中的中断服务程序LDMFD SP!, R0-R3, LR ;出栈SUBS PC, LR, #4如果在 CPSR 中没有禁止中断,那么每执行一条指令,处理器会检查是否有 FIQ 或者 IRQ 中断发生。若有中断发生,当且仅当 PC 指更新后,即处理器对下一条指令进行取指发生后,处理器才会进入到中断的服务程序中。因此保存在 LR 中的指是 PC-4,此处的 PC 是更新后的 PC,由于 ARM 处理器是三级流水线的结构,因
9、此返回地址是LR-4,返回到的地址是将要执行,但是被中断了指令。LDR 只能实现当前 PC 4KB 范围内的跳转,而在 LDR 的不远处用 DCD定义一个字,而在这个字里存放最终的异常服务程序的入口地址,可以实现在 4GB 范围内的全范围跳转。要求整个向量表的累加和为0。_user_initial_stackheap 函数是对用户的堆栈进行初始化,对它的调用是在_main 中完成的,对编程人员不可见。_main 是 ADS 编译系统提供的一个库函数,使用_main 标号引导系统时,必须将应用程序的入口定义为 main()。_main 完成代码和数据的复制,并且把 ZI 数据区清零。这一步当代码
10、和数据区在存储和运行时处于不同的存储器位置时有意义。_main 保证了系统在进入用户的应用程序前自动完成了系统调用。但是如果所有的初始化过程都已经被用户代码显式地被完成,如堆栈初始化、加载映象、执行映象、RW、ZI数据的复制等,那么用户应用程序的入口函数可以任意定义any_name(),完成初始化后,直接 B any_name 即可。个人建议使用B _main 的方式,防止疏忽出现不必要的错误,比如出现程序中的全局变量没有被正确的初始化等错误。3.IRQ.S 分析通过定义宏:$IRQ_Label HANDLER $IRQ_Exception_Function 来实现 LPC 2124的多个中断
11、源共用一段异常处理代码的目的。SUB LR, LR, #4 ; 计算返回地址STMFD SP!, R0-R3, R12, LR ; 保存任务环境进入 IRQ 中断,首先计算中断的返回地址,将 LR 减 4,然后将 R0-R3,R12,LR 压入堆栈。由于进入了 IRQ 中断,因此堆栈指针是SP_IRQ,和用户代码运行的 SP_SYS 不是同一个寄存器。至于只保存R0-R3,R12,是因为程序在正常运行过程中,R4-R11 中装载的是局部变量,在中断跳转是 ADS 编译器会自动将 R4-R11 入栈保护。进行了堆栈保护后,要保存进入中断之前的 CPSR 寄存器,以保证完成中断处理后,使处理器状态
12、和没有发生中断一样。MRS R3, SPSR ; 保存状态STMFD SP, R3, SP, LR ; 保存用户状态的 R3,SP,LR,注意不能回写若 STM 的寄存器列表中不包含 PC,的作用是保存用户模式下的寄存器。此操作的目的是用于中断嵌套。通过定义 IRQ 模式的堆栈深度,可以控制中断嵌套的深度。分析整段代码,一次中断响应需要占用 8 个 32bit 的堆栈,定义堆栈深度为 n*8,可以允许 n 级中断嵌套。此处操作符不允许回写,经过 AXD 仿真验证,回写操作会写入sp_usr 而不是 sp_irq,此操作属于不安全的操作,并且编译之后,ADS 编译器会给出响应的警告。MSR CP
13、SR_c, #(NoInt | SYS32Mode) ; 切换到系统模式CMP R1, #1LDREQ SP, =StackUsrBL $IRQ_Exception_Function ; 调用 c 语言的中断处理程序堆栈操作完成之后,切换到系统模式下运行 C 语言中定义的中断复位函数,才能达到中断嵌套的目的。当中断服务函数执行完毕之后,退出中断。在 uC/OS-II 的环境下考虑,因为 IRQ 中断发生之后,会改变任务就绪列表,因此需要在中断退出时确定是否需要进行任务切换。这点在下面的 OS_cpu_a.s 中会涉及到。4OS_cpu_a.s 分析移植 uC/OS-II,需要改写os_cpu.
14、h,OS_cpu_a.s,OS_cpu_a.c,includes.h 几个文件。在LPC 系列的平台,任务级的任务切换和中断级的任务切换是通过软中断(SWI,Software Interrupt)来完成的。OS_CPU_A.S 中包括SoftwareInterrupt、OSIntCtxSw、OSIntCtxSw_1 和_OSStartHighRdy 四个函数。SoftwareInterrupt 定义了软件中断处理方法,OSIntCtxSw 对应于中断级任务切换和任务级任务切换。而_OSStartHighRdy 是 uC/OS-II 启动时调用的,调用新建的优先级最高的任务。这四个函数的编写需要
15、很好的了解 ARM7 的内核结构和完全了解 uC/OS-II 内核运行的原理。在 SoftwareInterrupt 主要完成寄存器 R0-R3,R12,LR 在 SVC 模式(Supervisor)的堆栈中的保存、取得软件中断号并调用相应的处理过程。在 OS_CPU.H 中可以找到关于几个函数的软件中断定义。_swi(0x00) void OS_TASK_SW(void); /*任务级任务切换函数*/_swi(0x01) void _OSStartHighRdy(void); /*运行优先级最高的任务*/_swi(0x02) void OS_ENTER_CRITICAL(void) /*关中断*/_swi(0x03) void OS_EXIT_CRITICAL(void); /*开中断*/由于 SWI 中断是由指令本身引起的,因此发生中断时,PC 值并没有更新,所以计算中断返回地址,并不需要将 LR 减 4,LR 指向的就是发生中断指令的下一条指令。SWI 中断下堆栈的操作如下指令所示:LDR SP, StackSvc ; 重新设置堆栈指针STMFD SP!, R0-R3, R12, LR