打印
[综合信息]

(分享)【深入浅出Cortex M4-SWM320】跑马灯与启动文件

[复制链接]
2036|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
无论是最简单的51单片机,还是复杂的ARM、DSP等,最简单的操作莫过于IO口的高、低电平控制了,本章以前面讲述的库函数为基础,通过一个经典的跑马灯程序,带大家开始SWM320的学习之旅,通过本章的学习,你将掌握SWM320的GPIO口作为输出使用的方法。在本章实现跑马灯时,我们加入了一个名为“system_SWM320.c”的汇编文件,这个文件起什么作用呢?这章将给出简单的讲述。
6.1跑马灯的实现过程
前面几章,讲述库函数的过程时,我们简单提到了点亮一个LED小灯的过程,但是没有说明为何是控制GPIOP端口的几个位,这里我们先上原理图,再来解释其原理。
6.1.1LED小灯的硬件电路设计
对于LED来说,总共两个引脚,在电路设计上没有难度,这里以FSSW32开发板上的原理图来做讲解。通常情况下,LED内部需要通过一定的电流且存在一定的压差(也即压降)才能使得其发光。通常使用的LED的工作电流为3~20mA左右,但二极管本身的内阻又比较小,所以不能直接将两端接电源和GND,而需要加一个限流电阻(阻值读者可通过欧姆定律计算得到),限制通过LED的电流不要太大,LED原理图如图6-1所示。D2在核心板上,LED标号接SWM320的GPIOP.22;D8在底板上,LED_R、LED_G、LED_B分别接GPIOM.5、GPIOM.0、GPIOP.12,由于FSSW32板载资源比较丰富,这些端口有复用,读者可以不用理会,以后项目中用到SDRAM、NorFlash等外设时,LED可能会出现不规则的闪烁,读者知道是怎么回事就好。
注意:电路设计中,标号相同,表示物理连接。
该方式的LED驱动电路是将正极接在3.3V(高电平)上,负极再串联一个47O欧姆的限流电阻,再接到单片机的I/O口上,只需给LED小灯所对应的I/O口上低电平,就可以点亮LED;还有一种接法是将LED的正极接单片机的I/O口,再通过一限流电阻,将负极接地,单片机输出高电平,就可以点亮LED,但是需要将I/O设置为强推挽输出模式,具体情况依设计者的爱好和需求而定。
                                                                                          
经上述分析,LED两端只要有一合适的压差和电流,就会点亮LED。那么单片机又是如何控制的呢。举个例子,要有水流,必须有水压差,同样,要有电流,就得有电压差,结合上图,LED的正极已经接了高电平,如果LED所对应的单片机端口也为高电平(LED小灯熄灭),则LED的左右两端电平都是高电平(3.3V),就没有压差,LED就不会亮,相反,若单片机端口为低电平,从而LED两端则会有压差,这样LED灯就会被点亮(LED小灯点亮)。接下来就是通过软件控制LED小灯对应的端口实现周期性的高、低电平变化,就可以实现LED小灯的跑马灯效果。
6.1.2跑马灯的软件设计
在设计之前,读者需要建立完整的跑马灯工程,这里我们建立了三个Group,分别为“CMSIS”、“USER”和“SWMLib”,CMSIS下包含两个文件,分别为“startup_SWM320.s”、“system_SWM320.c”,这两个文件是华芯微特官方提供的,至于来源前面有述;USER中就一个读者很熟悉main.c文件,里面的内容是我们实现跑马灯的源码,源码的内容稍后讲述;SWMLib中包括了“SWM320_gpio.c”、“SWM320_port.c”两个文件,同样是官方提供的库函数。工程的建立过程当然还包括文件路径的设置、下载算法RAM大小的修改等,详细的建立过程请读者参考3.2节的内容,建立好的工程如图6-2所示。

工程建立好之后,5个文件我们只需编写main.c文件,其源码如下,剩余的4个只需添加即可。

使用特权

评论回复

相关帖子

沙发
stormwind123|  楼主 | 2023-5-29 09:43 | 只看该作者

图6-2 跑马灯工程框架图
1.        #include "SWM320.h"
2.         
3.        void Delay(void)
4.        {
5.               for(uint16_ti = 0; i < 5000; i++)
6.               {
7.                      for(uint16_tj = 0; j < 1000; j++);
8.               }
9.        }
10.      
11.     intmain(void)
12.     {     
13.            SystemInit();
14.            
15.            GPIO_Init(GPIOM, PIN0, 1, 0, 0);                    // 输出, 接LED
16.            GPIO_Init(GPIOM, PIN5, 1, 0, 0);                    // 输出, 接LED
17.            GPIO_Init(GPIOP, PIN12, 1, 0, 0);                   // 输出, 接LED
18.            GPIO_Init(GPIOP, PIN22, 1, 0, 0);                   // 输出, 接LED
19.            
20.            while(1)
21.            {
22.                   GPIO_ClrBit(GPIOM, PIN0);                           // 点亮LED小灯
23.                   Delay();
24.                   GPIO_SetBit(GPIOM, PIN0);                           // 熄灭LED小灯
25.                   GPIO_ClrBit(GPIOM, PIN5);                           // 点亮LED小灯
26.                   Delay();
27.                   GPIO_SetBit(GPIOM, PIN5);                           // 熄灭LED小灯
28.                   GPIO_ClrBit(GPIOP, PIN12);                           // 点亮LED小灯
29.                   Delay();
30.                   GPIO_SetBit(GPIOP, PIN12);                           // 熄灭LED小灯         
31.                   GPIO_ClrBit(GPIOP, PIN22);                           // 点亮LED小灯
32.                   Delay();
33.                   GPIO_SetBit(GPIOP, PIN22);                           // 熄灭LED小灯  
34.            }
35. }
如果前面的内容读者都已经很好的掌握了,这几十行程序应该不难理解,如果读者没有掌握,那接下来笔者为读者简单分析一下这35行语句。
第1行,包含SWM320的头文件,只有包含了这个头文件,才能正确运用库函数,前面讲解库函数的时候和读者有讲述,其各个寄存器的映射地址、结构体指针等都包含在这个头文件中。还有“SWM320_gpio.c”、“SWM320_port.c”两个文件的头文件包含,都是在第1行这个头文件中被包含进来的,如果读者想深入研究,可以选中头文件,右键单击,再选中第二个选项打开该头文件,仔细研读这几千行代码,笔者不建议这么做哈。
第3~9行,是一个简单的延时函数,这个我们在学习51的时候经常用,原理这里不赘。
第13行,这是系统的时钟初始化函数,函数的原型在“system_SWM320.c”中,这个函数我们在后面为读者讲述,这里读者可理解为“空气”。
第15~18行,这个函数我们在5.4节做了详细的讲述,目的是将接LED小灯的4个端口设置为输出端口,而且不使能上、下拉电阻。
第22行,使GPIOM.0端口输出低电平,这样在LED小灯两端形成压差,即可点亮LED小灯。函数原型在“SWM320_gpio.c”中,具体内容后面再述。
第24行,使GPIOM.0端口输出高电平,这样LED小灯两端电平一样,没有压差,LED小灯熄灭。函数原型在“SWM320_gpio.c”中,细节后面再述,剩余行同理,读者自行理解。

使用特权

评论回复
板凳
stormwind123|  楼主 | 2023-5-29 09:43 | 只看该作者
6.1.3下载验证
待上面的程序编写好之后,编译、下载到FSSW32开发板上,这时可观察到开发板上的4颗LED小灯每隔一定的时间会轮流点亮、熄灭,看起来有点跑马的意思。
6.2启动代码
在上面的跑马灯实验中,我们加入了一个“startup_SWM320.s”文件,这个文件俗称启动代码,也即BootLoader。这个代码也是由IC官方编写的,我们只需应用即可,但是这里还是有必要为读者讲述一下,如果读者暂时觉得学起来有点吃力,可以暂时搁置,待学习一段时间的SWM320之后,再结合ARM公司的《M4权威指南》来理解这个启动代码。
6.2.1启动代码的作用概述
启动代码由汇编语言编写,是系统上电复位之后第一个执行的程序,主要的功能有以下几点。
(1)堆和栈的初始化
包括堆栈的大小,MSP(main stack pointer)值等,MSP的初始值在复位阶段取自存储区的第一个字(即0地址处的值)。
栈Stack:由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈,向低地址扩展。
堆Heap:一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于数据结构中的链表,向高地址扩展。
(2)向量表定义
定义MSP初值以及各个中断服务程序(ISR)的入口地址。
(3)中断服务程序
CPU根据中断号从向量表中获取入口地址后,跳转至对应的ISR中。
(4)设置系统时钟频率
SWM320的启动代码没有时钟设置,时钟设置在“system_SWM320.c”中。如果读者想把SystemInit()函数添加到服务程序中,可采用如下的方式来实现。
1.  Reset_Handler    PROC
2.                   EXPORT  Reset_Handler             [WEAK]
3.          IMPORT  SystemInit  
4.                   LDR     R0, =SystemInit
5.                   BLX     R0
6.                   ENDP
(5)中断寄存器的初始化
(6)跳转到C应用程序
在复位中断服务程序即Reset_Handler中实现进入C程序。
6.2.2启动代码的详解
双击跑马灯工程中的“startup_SWM320.s”文件,浏览发现,启动代码总共有500行左右,此时读者可能无从下手,这里按上面概述的几点将其分类,一点一滴为读者介绍,同时便于讲解,将其堆和栈分开讲述。
1. 栈Stack
1.        Stack_Size      EQU    0x00000400
2.         
3.                       AREA    STACK, NOINIT, READWRITE, ALIGN=3
4.        Stack_Mem     SPACE  Stack_Size
5.        __initial_sp
分配0x400(也即1K)个连续字节的栈,名称为STACK,NOINT即不初始化,可读可写,8(23)字节对齐,几个指令解释如下。
EQU:宏定义的伪指令,可理解为等于,和C语言中的define类似;
AREA:告诉汇编器汇编一个新的代码段或者数据段。STACK表示段名,这个可以任意命名;NOINIT表示不初始化;READWRITE表示可读可写,ALIGN=3,表示按照8(23)字节对齐。
SPACE:用于分配一定大小的内存空间,单位为字节。这里指定大小等于Stack_Size。标号__initial_sp紧挨着SPACE语句放置,表示栈的结束地址,即栈顶地址,栈是由高向低生长的。
栈的作用是用于局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部SRAM 的大小。如果编写的程序比较大,定义的局部变量很多,那么就需要修改栈的大小。如果某一天,读者写的程序出现了莫名奇妙的问题,并进入了硬件fault的时候,就需要考虑是不是栈不够大,已经溢出了。
2. 堆Heap
1.        Heap_Size       EQU    0x00000200
2.         
3.                        AREA    HEAP, NOINIT, READWRITE, ALIGN=3
4.        __heap_base
5.        Heap_Mem       SPACE  Heap_Size
6.        __heap_limit
7.         
8.                        PRESERVE8
9.                        THUMB
开辟0x200(512B)个字节的堆,名字为HEAP,NOINIT即不初始化,可读可写,8(23)字节对齐。__heap_base表示对的起始地址,__heap_limit表示堆的结束地址。堆是由低向高生长的,跟栈的生长方向相反。堆主要用来动态内存的分配,类似于malloc()函数申请的内存的过程。
PRESERVE8:指定当前文件的堆栈按照8字节对齐。
THUMB:表示后面指令兼容THUMB指令。THUBM是ARM以前的指令集,为16bit,现在 Cortex-M系列的都使用THUMB-2(这里的2可理解为2倍于THUBM指令集)指令集,THUMB-2是32位的,兼容16位和32位的指令,是THUMB的超级。
3. 中断向量表定义
1.        ; Vector Table Mapped toAddress 0 at Reset         
2.                        AREA    RESET, DATA, READONLY
3.                        EXPORT  __Vectors
4.                        EXPORT  __Vectors_End
5.                        EXPORT  __Vectors_Size
6.         
7.        __Vectors        DCD     __initial_sp               ; Top of Stack
8.                        DCD     Reset_Handler              ; Reset Handler
9.                        DCD     NMI_Handler                ; NMI Handler
10.                    DCD     HardFault_Handler          ; Hard Fault Handler
11.                    DCD     MemManage_Handler          ; MPU Fault Handler
12.                    DCD     BusFault_Handler           ; Bus Fault Handler
13.                    DCD     UsageFault_Handler         ; Usage Fault Handler
14.                    DCD     0                          ; Reserved
15.                    DCD     0                          ; Reserved
16.                    DCD     0                          ; Reserved
17.                    DCD     0                          ; Reserved
18.                    DCD     SVC_Handler                ; SVCall Handler
19.                    DCD     DebugMon_Handler           ; Debug Monitor Handler
20.                    DCD     0                          ; Reserved
21.                    DCD     PendSV_Handler             ; PendSV Handler
22.                    DCD     SysTick_Handler            ; SysTick Handler
23.     
24.                   ; External Interrupts
25.                    DCD     GPIOA0_Handler
26.                    DCD     GPIOA1_Handler
27.                    DCD     GPIOA2_Handler
28.                    DCD     GPIOA3_Handler
29.                    DCD     GPIOA4_Handler
30.                    DCD     GPIOA5_Handler
31.                    DCD     GPIOA6_Handler
32.                    DCD     GPIOA7_Handler
33.                                         DCD     GPIOB0_Handler
34.                    DCD     GPIOB1_Handler
35.                    DCD     GPIOB2_Handler
36.                    DCD     GPIOB3_Handler
37.                    DCD     GPIOB4_Handler
38.                    DCD     GPIOB5_Handler
39.                    DCD     GPIOB6_Handler
40.                    DCD     GPIOB7_Handler
41.                    DCD     GPIOC0_Handler
42.                    DCD     GPIOC1_Handler
43.                    DCD     GPIOC2_Handler
44.                    DCD     GPIOC3_Handler
45.                    DCD     GPIOC4_Handler
46.                    DCD     GPIOC5_Handler
47.                    DCD     GPIOC6_Handler
48.                    DCD     GPIOC7_Handler                                 
49.                    DCD     GPIOM0_Handler
50.                    DCD     GPIOM1_Handler
51.                    DCD     GPIOM2_Handler
52.                    DCD     GPIOM3_Handler
53.                    DCD     GPIOM4_Handler
54.                    DCD     GPIOM5_Handler
55.                    DCD     GPIOM6_Handler
56.                    DCD     GPIOM7_Handler                                            
57.                                         DCD     DMA_Handler
58.                    DCD     LCD_Handler
59.                    DCD     NORFLC_Handler
60.                                         DCD          CAN_Handler
61.                    DCD     PULSE_Handler
62.                    DCD     WDT_Handler
63.                    DCD     PWM_Handler
64.                    DCD     UART0_Handler
65.                                         DCD     UART1_Handler
66.                                         DCD     UART2_Handler
67.                                         DCD     UART3_Handler
68.                                         DCD     0
69.                                         DCD     I2C0_Handler
70.                    DCD     I2C1_Handler
71.                    DCD     SPI0_Handler
72.                    DCD     ADC0_Handler
73.                    DCD     RTC_Handler
74.                    DCD     ANAC_Handler
75.                    DCD     SDIO_Handler
76.                    DCD     GPIOA_Handler
77.                    DCD     GPIOB_Handler
78.                    DCD     GPIOC_Handler
79.                    DCD     GPIOM_Handler
80.                    DCD     GPION_Handler
81.                    DCD     GPIOP_Handler
82.                    DCD     ADC1_Handler
83.                    DCD     FPU_Handler
84.                                         DCD     SPI1_Handler
85.                                         DCD     TIMR0_Handler
86.                                         DCD     TIMR1_Handler
87.                                         DCD     TIMR2_Handler
88.                                         DCD     TIMR3_Handler
89.                                         DCD     TIMR4_Handler
90.                                         DCD     TIMR5_Handler
91.                             
92.    __Vectors_End
93.     
94.    __Vectors_Size  EQU __Vectors_End - __Vectors
第1行为注释,汇编的注释有别于C语言。
第2行定义一个复位向量段,名字为RESET,只读。
第3~5并声明__Vectors_Size、__Vectors_End和__Vectors三个标号具有全局属性,可供外部的文件调用。EXPORT:声明一个标号可被外部的文件使用,使标号具有全局属性。
当内核响应了一个发生的异常后,对应的异常服务例程(ESR)就会执行。为了决定ESR的入口地址,内核使用了―向量表查表机制。这里使用一张向量表。向量表其实是一个WORD(32位整数)数组,每个下标对应一种异常,该下标元素的值则是该ESR的入口地址。向量表在地址空间中的位置是可以设置的,通过NVIC中的一个重定位寄存器来指出向量表的地址。在复位后,该寄存器的值为0。因此,在地址0(即FLASH地址0)处必须包含一张向量表,用于初始时的异常分配。要注意的是这里有个另类:0号类型并不是什么入口地址,而是给出了复位后MSP的初值。
第7~90行,都定义了中断向量的地址。DCD:分配一个或者多个以字为单位的内存,以四字节对齐,并要求初始化这些内存。在向量表中,DCD分配了一堆内存,并且以ESR的入口地址初始化它们。向量表从FLASH的0地址开始放置,以4个字节为一个单位,地址0存放的是栈顶地址,0X04存放的是复位程序的地址,以此类推。从代码上看,向量表中存放的都是中断服务函数的函数名,可我们知道C语言中的函数名就是一个地址。
第94行,__Vectors为向量表起始地址,__Vectors_End为向量表结束地址,两个相减即可算出向量表大小。

使用特权

评论回复
地板
stormwind123|  楼主 | 2023-5-29 09:44 | 只看该作者
4. 复位程序
1.                        AREA    |.text|, CODE, READONLY
2.         
3.        Reset_Handler    PROC
4.                         EXPORT  Reset_Handler             [WEAK]
5.                IMPORT __main
6.                         LDR     R0, =__main
7.                         BX      R0
8.                   ENDP
第1行,定义一个名称为.text的代码段,可读。
第3~8,复位子程序是系统上电后第一个执行的程序,调用C库函数_mian,最终调用main函数去到C的世界里。除了代码外,笔者再为读者解释一下这些陌生的命令。
WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部文件没有声明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,这里并不是唯一的。
IMPORT:表示该标号来自外部文件,其作用和C语言中的“extern”关键字类似。这里表示__main函数来自外部的文件。
__main是一个标准的C库函数,主要作用是初始化用户堆栈,最终调用main函数去到C的世界里。这就是为什么我们写的程序都有一个main函数的原因。读者此时可能会问到,能不能不调用__main,用SWM_main呢?答案当然是肯定的。我们只需修改主函数的名称,然后在IMPORT里写自己的主函数名称即可,实例代码如下。
1.                        AREA    |.text|, CODE, READONLY
2.         
3.        Reset_Handler    PROC
4.                         EXPORT  Reset_Handler             [WEAK]
5.                IMPORT SWM_main
6.                         LDR     R0, = SWM_main
7.                         BX      R0
8.                   ENDP
那么C世界里的代码就如下:
1.        int SWM_main(void)
2.        {        
3.                 SystemInit();
4.                 
5.                 while(1)
6.                 {
7.                 }
8.  }
其中LDR、BLX、BX等内核的指令,请读者参阅《M4权威指南》。
5. 中断服务程序
1.        NMI_Handler     PROC
2.                        EXPORT  NMI_Handler                [WEAK]
3.                        B       .
4.                        ENDP
5.         
6.        HardFault_Handler PROC
7.                        EXPORT  HardFault_Handler          [WEAK]
8.                        B       .
9.                        ENDP
10.     
11.    MemManage_Handler PROC
12.                    EXPORT  MemManage_Handler          [WEAK]
13.                    B       .
14.                    ENDP
15.     
16.    BusFault_Handler PROC
17.                    EXPORT  BusFault_Handler           [WEAK]
18.                    B       .
19.                    ENDP
20.     
21.    UsageFault_Handler PROC
22.                    EXPORT  UsageFault_Handler         [WEAK]
23.                    B       .
24.                    ENDP
25.     
26.    SVC_Handler     PROC
27.                    EXPORT  SVC_Handler                [WEAK]
28.                    B       .
29.                    ENDP
30.     
31.    DebugMon_Handler PROC
32.                    EXPORT  DebugMon_Handler           [WEAK]
33.                    B       .
34.                    ENDP
35.     
36.    PendSV_Handler  PROC
37.                    EXPORT  PendSV_Handler             [WEAK]
38.                    B       .
39.                    ENDP
40.     
41.    SysTick_Handler PROC
42.                    EXPORT  SysTick_Handler            [WEAK]
43.                    B       .
44.                    ENDP
45.     
46.    GPIOA0_IRQHandler PROC
47.                    EXPORT  GPIOA0_IRQHandler            [WEAK]
48.                    B       .
49.                    ENDP
50.     
51.    GPIOA1_IRQHandler PROC
52.                    EXPORT  GPIOA1_IRQHandler            [WEAK]
53.                    B       .
54.                    ENDP
55.     
56.    GPIOA2_IRQHandler PROC
57.                    EXPORT  GPIOA2_IRQHandler            [WEAK]
58.                    B       .
59.                    ENDP
60.     
61.    GPIOA3_IRQHandler PROC
62.                    EXPORT  GPIOA3_IRQHandler            [WEAK]
63.                    B       .
64.                    ENDP
65.     
66.    GPIOA4_IRQHandler PROC
67.                    EXPORT  GPIOA4_IRQHandler            [WEAK]
68.                    B       .
69.                    ENDP
70.     
71.    GPIOA5_IRQHandler PROC
72.                    EXPORT  GPIOA5_IRQHandler            [WEAK]
73.                    B       .
74.                    ENDP
75.     
76.    GPIOA6_IRQHandler PROC
77.                    EXPORT  GPIOA6_IRQHandler            [WEAK]
78.                    B       .
79.                    ENDP
80.     
81.    GPIOA7_IRQHandler PROC
82.                    EXPORT  GPIOA7_IRQHandler            [WEAK]
83.                    B       .
84.                    ENDP
85.     
86.    GPIOB0_IRQHandler PROC
87.                    EXPORT  GPIOB0_IRQHandler            [WEAK]
88.                    B       .
89.                    ENDP
90.     
91.    GPIOB1_IRQHandler PROC
92.                    EXPORT  GPIOB1_IRQHandler            [WEAK]
93.                    B       .
94.                    ENDP
95.     
96.    GPIOB2_IRQHandler PROC
97.                    EXPORT  GPIOB2_IRQHandler            [WEAK]
98.                    B       .
99.                    ENDP
100.   
101.  GPIOB3_IRQHandler PROC
102.                  EXPORT  GPIOB3_IRQHandler            [WEAK]
103.                  B       .
104.                  ENDP
105.   
106.  GPIOB4_IRQHandler PROC
107.                  EXPORT  GPIOB4_IRQHandler            [WEAK]
108.                  B       .
109.                  ENDP
110.   
111.  GPIOB5_IRQHandler PROC
112.                  EXPORT  GPIOB5_IRQHandler            [WEAK]
113.                  B       .
114.                  ENDP
115.   
116.  GPIOB6_IRQHandler PROC
117.                  EXPORT  GPIOB6_IRQHandler            [WEAK]
118.                  B       .
119.                  ENDP
120.   
121.  GPIOB7_IRQHandler PROC
122.                  EXPORT  GPIOB7_IRQHandler            [WEAK]
123.                  B       .
124.                  ENDP
125.   
126.  GPIOC0_IRQHandler PROC
127.                  EXPORT  GPIOC0_IRQHandler            [WEAK]
128.                  B       .
129.                  ENDP
130.   
131.  GPIOC1_IRQHandler PROC
132.                  EXPORT  GPIOC1_IRQHandler            [WEAK]
133.                  B       .
134.                  ENDP
135.   
136.  GPIOC2_IRQHandler PROC
137.                  EXPORT  GPIOC2_IRQHandler            [WEAK]
138.                  B       .
139.                  ENDP
140.   
141.  GPIOC3_IRQHandler PROC
142.                  EXPORT  GPIOC3_IRQHandler            [WEAK]
143.                  B      .
144.                  ENDP
145.   
146.  GPIOC4_IRQHandler PROC
147.                  EXPORT  GPIOC4_IRQHandler            [WEAK]
148.                  B       .
149.                  ENDP
150.   
151.  GPIOC5_IRQHandler PROC
152.                  EXPORT  GPIOC5_IRQHandler            [WEAK]
153.                  B       .
154.                  ENDP
155.   
156.  GPIOC6_IRQHandler PROC
157.                  EXPORT  GPIOC6_IRQHandler            [WEAK]
158.                  B       .
159.                  ENDP
160.   
161.  GPIOC7_IRQHandler PROC
162.                  EXPORT  GPIOC7_IRQHandler            [WEAK]
163.                  B       .
164.                  ENDP
165.   
166.  GPIOM0_IRQHandler PROC
167.                  EXPORT  GPIOM0_IRQHandler            [WEAK]
168.                  B       .
169.                  ENDP
170.   
171.  GPIOM1_IRQHandler PROC
172.                  EXPORT  GPIOM1_IRQHandler            [WEAK]
173.                  B       .
174.                  ENDP
175.   
176.  GPIOM2_IRQHandler PROC
177.                  EXPORT  GPIOM2_IRQHandler            [WEAK]
178.                  B       .
179.                  ENDP
180.   
181.  GPIOM3_IRQHandler PROC
182.                  EXPORT  GPIOM3_IRQHandler            [WEAK]
183.                  B       .
184.                  ENDP
185.   
186.  GPIOM4_IRQHandler PROC
187.                  EXPORT  GPIOM4_IRQHandler            [WEAK]
188.                  B       .
189.                  ENDP
190.   
191.  GPIOM5_IRQHandler PROC
192.                  EXPORT  GPIOM5_IRQHandler            [WEAK]
193.                  B       .
194.                  ENDP
195.   
196.  GPIOM6_IRQHandler PROC
197.                  EXPORT  GPIOM6_IRQHandler            [WEAK]
198.                  B       .
199.                  ENDP
200.   
201.  GPIOM7_IRQHandler PROC
202.                  EXPORT  GPIOM7_IRQHandler            [WEAK]
203.                  B       .
204.                  ENDP
205.   
206.  DMA_IRQHandler PROC
207.                  EXPORT  DMA_IRQHandler            [WEAK]
208.                  B       .
209.                  ENDP
210.   
211.  LCD_IRQHandler PROC
212.                  EXPORT  LCD_IRQHandler            [WEAK]
213.                  B       .
214.                  ENDP
215.   
216.  NORFLC_IRQHandler PROC
217.                  EXPORT  NORFLC_IRQHandler            [WEAK]
218.                  B       .
219.                  ENDP
220.   
221.  CAN_IRQHandler PROC
222.                  EXPORT  CAN_IRQHandler            [WEAK]
223.                  B       .
224.                  ENDP
225.   
226.  TIMR_IRQHandler PROC
227.                  EXPORT  TIMR_IRQHandler            [WEAK]
228.                  B       .
229.                  ENDP
230.   
231.  WDT_IRQHandler PROC
232.                  EXPORT  WDT_IRQHandler            [WEAK]
233.                  B       .
234.                  ENDP
235.   
236.  PWM_IRQHandler PROC
237.                  EXPORT  PWM_IRQHandler            [WEAK]
238.                  B       .
239.                  ENDP
240.   
241.  UART0_IRQHandler PROC
242.                  EXPORT  UART0_IRQHandler            [WEAK]
243.                  B       .
244.                  ENDP
245.   
246.  UART1_IRQHandler PROC
247.                  EXPORT  UART1_IRQHandler            [WEAK]
248.                  B       .
249.                  ENDP
250.   
251.  UART2_IRQHandler PROC
252.                  EXPORT  UART2_IRQHandler            [WEAK]
253.                  B       .
254.                  ENDP
255.   
256.  UART3_IRQHandler PROC
257.                  EXPORT  UART3_IRQHandler            [WEAK]
258.                  B       .
259.                  ENDP
260.   
261.  I2C0_IRQHandler PROC
262.                  EXPORT  I2C0_IRQHandler            [WEAK]
263.                  B       .
264.                  ENDP
265.   
266.  I2C1_IRQHandler PROC
267.                  EXPORT  I2C1_IRQHandler            [WEAK]
268.                  B       .
269.                  ENDP
270.   
271.  SPI0_IRQHandler PROC
272.                  EXPORT  SPI0_IRQHandler            [WEAK]
273.                  B       .
274.                  ENDP
275.   
276.  ADC0_IRQHandler PROC
277.                  EXPORT  ADC0_IRQHandler            [WEAK]
278.                  B       .
279.                  ENDP
280.   
281.  RTC_IRQHandler PROC
282.                  EXPORT  RTC_IRQHandler            [WEAK]
283.                  B       .
284.                  ENDP
285.   
286.  ANAC_IRQHandler PROC
287.                  EXPORT  ANAC_IRQHandler            [WEAK]
288.                  B       .
289.                  ENDP
290.   
291.  SDIO_IRQHandler PROC
292.                  EXPORT  SDIO_IRQHandler            [WEAK]
293.                  B       .
294.                  ENDP
295.   
296.  GPIOA_IRQHandler PROC
297.                  EXPORT  GPIOA_IRQHandler            [WEAK]
298.                  B       .
299.                  ENDP
300.   
301.  GPIOB_IRQHandler PROC
302.                  EXPORT  GPIOB_IRQHandler            [WEAK]
303.                  B       .
304.                  ENDP
305.   
306.  GPIOC_IRQHandler PROC
307.                  EXPORT  GPIOC_IRQHandler            [WEAK]
308.                  B       .
309.                  ENDP
310.   
311.  GPIOM_IRQHandler PROC
312.                  EXPORT  GPIOM_IRQHandler            [WEAK]
313.                  B       .
314.                  ENDP
315.   
316.  GPION_IRQHandler PROC
317.                  EXPORT  GPION_IRQHandler            [WEAK]
318.                  B       .
319.                  ENDP
320.   
321.  GPIOP_IRQHandler PROC
322.                  EXPORT  GPIOP_IRQHandler            [WEAK]
323.                  B       .
324.                  ENDP
325.   
326.  ADC1_IRQHandler PROC
327.                  EXPORT  ADC1_IRQHandler            [WEAK]
328.                  B       .
329.                  ENDP
330.   
331.  FPU_IRQHandler PROC
332.                  EXPORT  FPU_IRQHandler            [WEAK]
333.                  B       .
334.                  ENDP
335.   
336.  SPI1_IRQHandler PROC
337.                  EXPORT  SPI1_IRQHandler            [WEAK]
338.                  B       .
339.                  ENDP
在启动文件里面已经帮我们写好了所有中断的中断服务函数,跟我们平时写的中断服务函数不一样的就是这些函数都是空的,真正的中断复服务程序需要我们在外部的C文件里面重新实现,这里只是提前抢占了一个位置而已。如果我们在使用某个外设的时候,开启了某个中断,但是又忘记编写配套的中断服务程序或者函数名写错,那当中断来临的时,程序就会跳转到启动代码中预先写好空的中断服务程序里,并且在这个空函数中无线循环,这样程序就会死在这里。
B:跳转到一个标号。这里跳转到一个‘.’,即表示无线循环,有点类似于C语言中的while(1)。
6. 用户堆栈初始化
1.                        ALIGN
2.         
3.        ;**************************************************************************
4.        ; User Stack and Heapinitialization
5.        ;**************************************************************************
6.                       IF     :DEF:__MICROLIB
7.                        
8.                        EXPORT  __initial_sp
9.                        EXPORT  __heap_base
10.                    EXPORT  __heap_limit
11.                    
12.                    ELSE
13.                    
14.                    IMPORT  __use_two_region_memory
15.                    EXPORT  __user_initial_stackheap
16.                     
17.    __user_initial_stackheap
18.     
19.                    LDR     R0, = Heap_Mem
20.                    LDR     R1, =(Stack_Mem + Stack_Size)
21.                    LDR     R2, = (Heap_Mem +  Heap_Size)
22.                    LDR    R3, = Stack_Mem
23.                    BX      LR
24.     
25.                    ALIGN
26.     
27.                    ENDIF
28.     
29.                 END
第1行,ALIGN:对指令或者数据存放的地址进行对齐,后面会跟一个立即数。缺省表示4字节对齐。
第6~27行,判断是否定义了__MICROLIB,如果定义了则赋予标号__initial_sp(栈顶地址)、__heap_base(堆起始地址)、__heap_limit(堆结束地址)全局属性,可供外部文件调用。如果没有定义(实际的情况就是我们没定义__MICROLIB)则使用默认的C库,然后初始化用户堆栈大小,这部分由C库函数__main来完成,当初始化完堆栈之后,就调用main函数去到C的世界。

DEF:XXX,表示XXX定了则为真,否则为假。类似于C语言中的“#define”。

使用特权

评论回复
5
lulugl| | 2023-5-30 06:26 | 只看该作者
楼主的汇编基础那是相当的强呀!

使用特权

评论回复
6
lulugl| | 2023-5-30 06:29 | 只看该作者
我发现这个芯片的中断非常丰富呀,特别是对GPIO的每一个中断都定义了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

293

主题

1191

帖子

1

粉丝