EasyARM2200开发板学习笔记:启动代码分析

 

;定义堆栈的大小

FIQ_STACK_LEGTH     EQU     0

IRQ_STACK_LEGTH     EQU     9*8     ;每层嵌套需要9个字堆栈,允许8层嵌套

ABT_STACK_LEGTH     EQU     0

UND_STACK_LEGTH     EQU     0

 

;处理器模式常量定义

NoInt       EQU 0x80           ;禁止IRQ中断

USR32Mode   EQU 0x10           ;用户模式

SVC32Mode   EQU 0x13           ;管理模式

SYS32Mode   EQU 0x1f           ;系统模式

IRQ32Mode   EQU 0x12           ;中断模式

FIQ32Mode   EQU 0x11           ;快速中断模式

 

PINSEL2     EQU 0xE002C014

BCFG0       EQU 0xFFE00000

BCFG1       EQU 0xFFE00004

BCFG2       EQU 0xFFE00008

BCFG3       EQU 0xFFE0000C

 

;引入的外部标号在这声明

 IMPORT  FIQ_Exception          ;快速中断异常处理程序

 IMPORT  __main                 ;C语言主程序入口

 IMPORT  TargetResetInit        ;目标板基本初始化

 IMPORT  StackUsr               ;用户模式栈

 IMPORT  bottom_of_heap         ;用户模式堆

 IMPORT  SoftwareInterrupt      ;软件中断处理程序

 

;给外部使用的标号在这声明

 EXPORT  Reset

 EXPORT  __rt_div0

 EXPORT  __user_initial_stackheap

 

       CODE32

 

        AREA  vectors,CODE,READONLY

        ENTRY

;中断向量表

Reset

        LDR     PC, ResetAddr        ;复位入口,程序在系统中执行的第一条指令

        LDR     PC, UndefinedAddr    ;未定义指令异常入口地址

        LDR     PC, SWI_Addr         ;软件中断入口地址

        LDR     PC, PrefetchAddr     ;取指令中止异常入口地址

        LDR     PC, DataAbortAddr    ;取数据中止异常入口地址

        DCD     0xb9205f80           ;保留向量,值是其它中断向量累加和的补码

        LDR     PC, [PC, #-0xff0]    ;中断请求IRQ入口地址

        LDR     PC, FIQ_Addr         ;快速中断请求FIQ入口地址

 

ResetAddr             DCD     ResetInit

UndefinedAddr         DCD     Undefined

SWI_Addr              DCD     SoftwareInterrupt

PrefetchAddr          DCD     PrefetchAbort

DataAbortAddr         DCD     DataAbort

Nouse                 DCD     0

IRQ_Addr              DCD     0

FIQ_Addr              DCD     FIQ_Handler

 

;未定义指令

Undefined

        B       Undefined            ;发生未定义指令异常时执行死循环

 

;取指令中止

PrefetchAbort

        B       PrefetchAbort        ;发生取指令中止异常时执行死循环

 

;取数据中止

DataAbort

        B       DataAbort            ;发生取数据中止异常时执行死循环

 

;快速中断

FIQ_Handler

        STMFD   SP!, {R0-R3, LR}     ;现场保护,将R0-R3, LR入栈

        BL      FIQ_Exception        ;调用快速中断异常处理程序

        LDMFD   SP!, {R0-R3, LR}     ;异常中断返回

        SUBS    PC,  LR,  #4         ;PC指向中断前没有被执行的指令

 

 

InitStack

;初始化堆栈

        MOV     R0, LR

 

;设置中断模式堆栈

        MSR     CPSR_c, #0xd2    ;IRQFIQ禁止, 中断模式

        LDR     SP, StackIrq     ;设置中断模式堆栈指针,指向StackIrq

;设置快速中断模式堆栈

        MSR     CPSR_c, #0xd1    ;IRQFIQ禁止, 快速中断模式

        LDR     SP, StackFiq     ;设置快速中断模式堆栈指针,指向StackFiq

;设置中止模式堆栈

        MSR     CPSR_c, #0xd7    ;IRQFIQ禁止, 中止模式

        LDR     SP, StackAbt     ;设置中止模式堆栈指针,指向StackAbt

;设置未定义模式堆栈

        MSR     CPSR_c, #0xdb    ;IRQFIQ禁止, 未定义模式

        LDR     SP, StackUnd     ;设置未定义模式堆栈指针,指向StackUnd

;设置系统模式堆栈

        MSR     CPSR_c, #0xdf    ;IRQFIQ禁止, 系统模式

        LDR     SP, =StackUsr    ;设置系统模式堆栈指针,指向StackUsr

 

        MOV     PC, R0           ;返回

 

ResetInit

;复位入口

;初始化外部总线控制器,根据目标板决定配置

 

        LDR     R0, =PINSEL2     ;PINSEL2的地址赋给RO

    IF :DEF: EN_CRP              ;判断是否有预定义EN_CRP

        LDR     R1, =0x0f814910  ;PINSEL2.20, 禁止JTAG调试

    ELSE

        LDR     R1, =0x0f814914  ;PINSEL2.21, 使能JTAG调试

    ENDIF

        STR     R1, [R0]

 

        LDR     R0, =BCFG0       ;初始化存储器组0的配置寄存器

        LDR     R1, =0x1000ffef

        STR     R1, [R0]

 

        LDR     R0, =BCFG1       ;初始化存储器组1的配置寄存器

        LDR     R1, =0x1000ffef

        STR     R1, [R0]

 

;       LDR     R0, =BCFG2       ;初始化存储器组2的配置寄存器

;       LDR     R1, =0x2000ffef

;       STR     R1, [R0]

 

;       LDR     R0, =BCFG3       ;初始化存储器组3的配置寄存器

;       LDR     R1, =0x2000ffef

;       STR     R1, [R0]

       

        BL      InitStack        ;跳转到初始化堆栈代码段

        BL      TargetResetInit  ;跳转到目标板基本初始化

       

        B       __main           ;跳转到c语言入口

 

__user_initial_stackheap         ;库函数初始化堆和栈

MOV   pc,lr

 

 

__rt_div0                        ;整数除法除数为0错误处理函数

B       __rt_div0

 

StackIrq           DCD     IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4

StackFiq           DCD     FiqStackSpace + (FIQ_STACK_LEGTH - 1)* 4

StackAbt           DCD     AbtStackSpace + (ABT_STACK_LEGTH - 1)* 4

StackUnd           DCD     UndtStackSpace + (UND_STACK_LEGTH - 1)* 4

 

 

    IF :DEF: EN_CRP

        IF  . >= 0x1fc           ;判断当前代码地址是否已超过0x1FC

        INFO    1,"/nThe data at 0x000001fc must be 0x87654321.

/nPlease delete some source before this line."

        ENDIF

CrpData

    WHILE . < 0x1fc              ;未到0x1FC则填充NOP指令

        NOP

    WEND

CrpData1

        DCD    0x87654321        ;0x1FC处放置0x87654321,启动加密功能

    ENDIF

 

;/* 分配堆栈空间 */

        AREA    MyStacks, DATA, NOINIT, ALIGN=2

IrqStackSpace       SPACE   IRQ_STACK_LEGTH * 4  ;中断模式堆栈空间

FiqStackSpace       SPACE   FIQ_STACK_LEGTH * 4  ;快速中断模式堆栈空间

AbtStackSpace       SPACE   ABT_STACK_LEGTH * 4  ;中止义模式堆栈空间

UndtStackSpace      SPACE   UND_STACK_LEGTH * 4  ;未定义模式堆栈

END

//

LDR     PC, [PC, #-0xff0] VICVectAddr寄存器的地址0xFFFFF030,PC当前位置是0x18,读出的值为0x18+8 = 0x20,0x20-0xff0 = 0xFFFFF030
 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于EasyARM1768开发板和相关硬件资源实现万年历的示例代码,其中数码管使用了TM1638驱动芯片: ```c #include <LPC17xx.h> #include <stdio.h> #include <stdlib.h> #include "TM1638.h" #define LED_PIN (1 << 22) // P1.22 #define KEY1_PIN (1 << 23) // P1.23 #define KEY2_PIN (1 << 24) // P1.24 #define KEY3_PIN (1 << 25) // P1.25 void delay_ms(uint32_t ms) { uint32_t i, j; for (i = 0; i < ms; i++) { for (j = 0; j < 6000; j++); } } void LED_On(void) { LPC_GPIO1->FIOSET |= LED_PIN; } void LED_Off(void) { LPC_GPIO1->FIOCLR |= LED_PIN; } void RTC_Init(void) { LPC_RTC->CCR = 0; // Disable RTC LPC_RTC->ILR = 3; // Clear interrupt flags LPC_RTC->CIIR = 0; // Disable all interrupts LPC_RTC->AMR = 0; // Enable all alarm matches LPC_RTC->CALIBRATION = 0x00000000; LPC_RTC->CCR = 1; // Enable RTC } void RTC_SetTime(uint32_t hour, uint32_t minute, uint32_t second) { LPC_RTC->CCR = 0; // Disable RTC LPC_RTC->SEC = second; LPC_RTC->MIN = minute; LPC_RTC->HOUR = hour; LPC_RTC->CCR = 1; // Enable RTC } void RTC_GetTime(uint32_t *hour, uint32_t *minute, uint32_t *second) { *hour = LPC_RTC->HOUR; *minute = LPC_RTC->MIN; *second = LPC_RTC->SEC; } void RTC_SetDate(uint32_t year, uint32_t month, uint32_t day) { LPC_RTC->CCR = 0; // Disable RTC LPC_RTC->DOM = day; LPC_RTC->MONTH = month; LPC_RTC->YEAR = year; LPC_RTC->CCR = 1; // Enable RTC } void RTC_GetDate(uint32_t *year, uint32_t *month, uint32_t *day) { *year = LPC_RTC->YEAR; *month = LPC_RTC->MONTH; *day = LPC_RTC->DOM; } void RTC_SetAlarm(uint32_t hour, uint32_t minute, uint32_t second) { LPC_RTC->CCR = 0; // Disable RTC LPC_RTC->ALSEC = second; LPC_RTC->ALMIN = minute; LPC_RTC->ALHOUR = hour; LPC_RTC->CIIR |= 1 << 1; // Enable alarm match for hours, minutes, and seconds LPC_RTC->CCR = 1; // Enable RTC } void RTC_ClearAlarm(void) { LPC_RTC->ILR |= 1 << 1; // Clear alarm interrupt flag } void RTC_IRQHandler(void) { if (LPC_RTC->ILR & (1 << 1)) { LED_On(); // Turn on LED TM1638_DisplayString("ALARM"); // Display "ALARM" on TM1638 while (1) { if (LPC_GPIO1->FIOPIN & KEY1_PIN) { // Check if button 1 is pressed LED_Off(); // Turn off LED TM1638_DisplayString(" "); // Clear display RTC_ClearAlarm(); // Clear alarm interrupt flag break; } delay_ms(100); // Wait for button debounce } } } int main(void) { uint32_t year, month, day, hour, minute, second; uint32_t alarm_hour = 12, alarm_minute = 0, alarm_second = 0; LPC_GPIO1->FIODIR |= LED_PIN; // Set LED pin to output LPC_GPIO1->FIODIR &= ~(KEY1_PIN | KEY2_PIN | KEY3_PIN); // Set button pins to input TM1638_Init(); // Initialize TM1638 RTC_Init(); // Initialize RTC RTC_SetTime(0, 0, 0); // Set initial time to 00:00:00 RTC_SetDate(2022, 1, 1); // Set initial date to 2022-01-01 RTC_SetAlarm(alarm_hour, alarm_minute, alarm_second); // Set initial alarm NVIC_EnableIRQ(RTC_IRQn); // Enable RTC interrupt while (1) { RTC_GetTime(&hour, &minute, &second); // Get current time RTC_GetDate(&year, &month, &day); // Get current date char str[10]; sprintf(str, "%02d%02d%02d", hour, minute, second); TM1638_DisplayString(str); // Display time on TM1638 delay_ms(1000); // Wait for 1 second if (LPC_GPIO1->FIOPIN & KEY2_PIN) { // Check if button 2 is pressed alarm_hour = (alarm_hour + 1) % 24; // Increment alarm hour RTC_SetAlarm(alarm_hour, alarm_minute, alarm_second); // Update alarm while (LPC_GPIO1->FIOPIN & KEY2_PIN); // Wait for button release } if (LPC_GPIO1->FIOPIN & KEY3_PIN) { // Check if button 3 is pressed alarm_minute = (alarm_minute + 1) % 60; // Increment alarm minute RTC_SetAlarm(alarm_hour, alarm_minute, alarm_second); // Update alarm while (LPC_GPIO1->FIOPIN & KEY3_PIN); // Wait for button release } } } ``` 该代码实现了万年历的基本功能,包括显示时间和日期、修改时间、设置闹钟、触发报警中断、手动关闭提醒。需要注意的是,该代码仅作为示例,实际应用中可能需要进一步优化和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值