三种Boot模式的差异
所谓启动,一般来说就是指我们下好程序后,重启芯片时,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存。用户可以通过设置BOOT1和BOOT0引脚的状态,来选择在复位后的启动模式。
Main Flash memory
是STM32内置的Flash,一般我们使用JTAG或者SWD模式下载程序时,就是下载到这个里面,重启后也直接从这启动程序。
System memory
从系统存储器启动,这种模式启动的程序功能是由厂家设置的。一般来说,这种启动方式用的比较少。系统存储器是芯片内部一块特定的区域,STM32在出厂时,由ST在这个区域内部预置了一段BootLoader, 也就是我们常说的ISP程序, 这是一块ROM,
出厂后无法修改。一般来说,我们选用这种启动模式时,是为了从串口下载程序,因为在厂家提供的BootLoader中,提供了串口下载程序的固件,可以通过这个BootLoader将程序下载到系统的Flash中。但是这个下载方式需要以下步骤:
Step1:将BOOT0设置为1,BOOT1设置为0,然后按下复位键,这样才能从系统存储器启动BootLoader
Step2:最后在BootLoader的帮助下,通过串口下载程序到Flash中
Step3:程序下载完成后,又有需要将BOOT0设置为GND,手动复位,这样,STM32才可以从Flash中启动可以看到, 利用串口下载程序还是比较的麻烦, 需要跳帽跳来跳去的,非常的不注重用户体验。
Embedded Memory
内置SRAM,既然是SRAM,自然也就没有程序存储的能力了,这个模式一般用于程序调试。假如我只修改了代码中一个小小的地方,然后就需要重新擦除整个Flash,比较的费时,可以考虑从这个模式启动代码(也就是STM32的内存中),用于快速的程序调试,等程序调试完成后,在将程序下载到SRAM中。
二、开发BOOT模式选择。
1、通常使用程序代码存储在主闪存存储器,配置方式:BOOT0=0,BOOT1=X;
2、Flash锁死解决办法:
开发调试过程中,由于某种原因导致内部Flash锁死,无法连接SWD以及Jtag调试,无法读到设备,可以通过修改BOOT模式重新刷写代码。
修改为BOOT0=1,BOOT1=0即可从系统存储器启动,ST出厂时自带Bootloader程序,SWD以及JTAG调试接口都是专用的。重新烧写程序后,可将BOOT模式重新更换到BOOT0=0,BOOT1=X即可正常使用。
参考:
链接: link.
3.内置SRAM(Embedded Memory)
内置SRAM这个模式一般用于程序调试。
4.三种模式的访问地址
主闪存存储器:访问地址为0x00000000或0x08000000
系统存储器:访问地址为0x00000000或0x1FF00000
内置SRAM:启动时地址为0x00000000或0x20000000
5.中断向量表
主闪存存储器
中断向量表从Flash的起始地址(0x08000000)开始存放。同时映射到0x00000000处。向量表偏移寄存器的值为0x00000000(实际映射到0x08000000)。
内置SRAM
中断向量表还是存放在Flash中(Flash才能固化存储,SRAM只能加电才有效),只不过拷贝到SRAM的首地址0x20000000处。此时向量表偏移寄存器的值也是0x00000000(实际映射到0x20000000)。
无论用哪种模式启动,复位时栈顶指针总能在0x00000000(或0x08000000)处找到,而复位向量总能在0x00000004(或0x08000004)处找到。
在STM32上创建一个汇编工程
:
选择一个目录,然后选择芯片:
输入代码:
AREA MYDATA, DATA
AREA MYCODE, CODE
ENTRY
EXPORT __main
__main
MOV R0, #10
MOV R1, #11
MOV R2, #12
MOV R3, #13
;LDR R0, =func01
BL func01
;LDR R1, =func02
BL func02
BL func03
LDR LR, =func01
LDR PC, =func03
B .
func01
MOV R5, #05
BX LR
func02
MOV R6, #06
BX LR
func03
MOV R7, #07
MOV R8, #08
BX LR
编译:
然后点击魔法棒
生成hex文件:
开始调试
选择ST-LINK
点击旁边的settings
:020000040800F2
:100000001806002031010008390100083B010008F2
:100010003D0100083F010008410100080000000008
:100020000000000000000000000000004301000884
:1000300045010008000000004701000849010008D0
:100040004B0100084B0100084B0100084B01000860
:100050004B0100084B0100084B0100084B01000850
:100060004B0100084B0100084B0100084B01000840
:100070004B0100084B0100084B0100084B01000830
:100080004B0100084B0100084B0100084B01000820
:100090004B0100084B0100084B0100084B01000810
:1000A0004B0100084B0100084B0100084B01000800
:1000B0004B0100084B0100084B0100084B010008F0
:1000C0004B0100084B0100084B0100084B010008E0
:1000D0004B0100084B0100084B0100084B010008D0
:1000E0004B0100084B0100084B0100084B010008C0
:1000F0004B0100084B0100084B0100084B010008B0
:100100004B0100084B0100084B0100084B0100089F
:100110004B0100084B0100084B0100084B0100088F
:100120004B0100084B0100084B0100084B0100087F
:100130000948804709480047FEE7FEE7FEE7FEE77B
:10014000FEE7FEE7FEE7FEE7FEE7FEE704480549B7
:10015000054A064B704700004F020008590300088B
:1001600018000020180600201802002018020020A5
:100170000CB50020019000906C48006840F480307D
:100180006A49086000BF6948006800F400300090C8
:100190000198401C0190009818B90198B0F5A06F23
:1001A000F1D16248006800F4003010B101200090E5
:1001B00001E0002000900098012843D15C480068CD
:1001C00040F010005A4908600846006820F003001B
:1001D00008600846006840F0020008605348406824
:1001E000524948600846406848600846406840F404
:1001F000806048600846406820F47C1048600846EB
:10020000406840F4E81048600846006840F080709C
:10021000086000BF4548006800F000700028F9D071
:100220004248406820F00300404948600846406862
:1002300040F00200486000BF3C48406800F00C00FD
:100240000828F9D10CBD10B5FFF792FF10BD10B50D
:100250003648006840F001003449086008464068AC
:10026000344908403149486008460068324908402E
:100270002E4908600846006820F48020086008467F
:10028000406820F4FE0048604FF41F008860FFF7CC
:10029000DAFF4FF000602949086010BD10B5002159
:1002A00000200022214B5B6803F00C0121B10429DE
:1002B00006D0082928D107E0214B224C236027E0F3
:1002C0001F4B204C236023E0184B5B6803F4701035
:1002D000164B5B6803F48032022303EB904022B993
:1002E000194B4343174C23600DE0104B5B6803F43C
:1002F000003323B1144B4343124C236003E0104BF3
:100300004343104C236003E00D4B0E4C236000BFB1
:1003100000BF064B5B68C3F303130C4CE15C094B55
:100320001B68CB40074C236010BD0000001002404A
:10033000002002400000FFF8FFFFF6FE08ED00E09D
:1003400000127A000000002000093D000400002097
:1003500070477047704700004FF00A004FF00B01E4
:100360004FF00C024FF00D0300F009F800F00AF80E
:1003700000F00BF8DFF81CE0DFF81CF0FEE74FF0B0
:10038000050570474FF0060670474FF007074FF01E
:10039000080870477F0300088B03000800A24A0486
:1003A0000000000000000000010203040607080925
:040000050800035993
:00000001FF
第一个字节表示本行数据的长度;
第二、三字节表示本行数据的起始地址;
第四字节 表示数据类型;
hex文件的格式:
:(冒号)每个Intel HEX 记录都由冒号开头; LL 是数据长度域, 它代表记录当中数据字节 (D…D) 的数量; aaaa
是地址域, 它代表记录当中数据的起始地址; TT是代表HEX 记录类型的域 , 它可能是以下数据当中的一 个: 00:数据记录(Data
Record),用来记录数据,HEX文件的大部分记录都是数据记录。 01:文件结束记录(End of
FileRecord),用来标识文件结束,放在文件的最后,标识HEX文件的结尾。 02:扩展段地址记录(ExtendedSegment
Address
Record),用来标识扩展段地址的记录,扩展段地址记录(HEX86),它包含4~19位数据地址段。由于普通的Intel的HEX记录文件只能记录64K的地址范围,所以大于64K的地址数据要靠扩展段地址记录。
03:开始段地址记录(Start Segment Address Record) 04:扩展线性地址记录(Extended Linear
Address
Record),用来标识扩展线性地址的记录,扩展线性地址记录也叫32位地址记录或者HEX386记录,这些记录包含了数据在存储器里真实地址的高16位。
当一个扩展线性地址记录被读取后,将一直保持有效,直到它被另一个扩展地址记录改变。因为它记录的是后面数据在存储器里存放的真实起始地址,所以它的起始地址偏移量(Load
offset)总是0000。 05:开始线性地址记录(Start Linear Address
Record),32位机(80386或更高的CPU)的EIP寄存器里存放的地址(main函数的入口地址)。
D…D是数据域,它代表一个字节的数据。一个记录可以有许多数据字节。记录当中数据字节的数量必须和数据长度域(LL)中指定的数字相符。
CC是校验和域,它表示这个记录的校验和。校验和的计算是通过将记录当中所有十六进制编码数字对的值相加,以256为模进行以下补足。
各种进制数的后缀字母分别为:
B :二进制数。
Q :八进制数。
D :十进制数。
H :十六进制数。
关于%是取余和取模:
在JAVA、C、C++里,%是取余运算,英文remainder;
在Python里,%号是取模运算,英文modulus;
取余运算的除法是向零舍入,取模运算的除法是向小值舍入;
取余运算结果的符号与被除数相同,取模运算结果的符号与除数相同。
参考资料:
链接: link.
led汇编闪烁灯
创建一个新工程,芯片和上面一样,选择如下:
将代码输入:
LED0 EQU 0x40011004;定义引脚PC2
RCC_APB2ENR EQU 0x40021018;配置RCC寄存器,时钟
GPIOC_CRL EQU 0x40011000;配置CRL寄存器
Stack_Size EQU 0x00000400;栈的大小
;分配一个STACK段,该段不初始化,可读写,按8字节对齐。分配一个大小为Stack_Size的存储空间,并使栈顶的地址为__initial_sp。
AREA STACK, NOINIT, READWRITE, ALIGN=3;NOINIT: = NO Init,不初始化。READWRITE : 可读,可写。ALIGN =3 : 2^3 对齐,即8字节对齐。
Stack_Mem SPACE Stack_Size
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
AREA |.text|, CODE, READONLY;开始代码段
THUMB
REQUIRE8
PRESERVE8
ENTRY
Reset_Handler
BL LED_Init;BL:带链接的跳转指令。当使用该指令跳转时,当前地址(PC)会自动送入LR寄存器
MainLoop BL LED_ON
BL Delay
BL LED_OFF
BL Delay
B MainLoop;B:无条件跳转。
LED_Init;LED初始化
PUSH {R0,R1, LR};R0,R1,LR中的值放入堆栈
LDR R0,=RCC_APB2ENR;LDR是把地址装载到寄存器中(比如R0)。
ORR R0,R0,#0x04;ORR 按位或操作,将将R0的第二位置1,其他位不变
LDR R1,=RCC_APB2ENR
STR R0,[R1];STR是把值存储到寄存器所指的地址中。
LDR R0,=GPIOC_CRL
BIC R0,R0,#0x0F;BIC 先把立即数取反,再按位与
LDR R1,=GPIOC_CRL
STR R0,[R1]
LDR R0,=GPIOC_CRL
ORR R0,R0,#0x03
LDR R1,=GPIOC_CRL
STR R0,[R1]
;将PC2置1
MOV R0,#1
LDR R1,=LED0
STR R0,[R1]
POP {R0,R1,PC};将栈中之前存的R0,R1,LR的值返还给R0,R1,PC
LED_ON
PUSH {R0,R1, LR}
MOV R0,#0
LDR R1,=LED0
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF
PUSH {R0,R1, LR}
MOV R0,#1
LDR R1,=LED0
STR R0,[R1]
POP {R0,R1,PC}
Delay
PUSH {R0,R1, LR}
MOVS R0,#0
MOVS R1,#0
MOVS R2,#0
DelayLoop0
ADDS R0,R0,#1
CMP R0,#330
BCC DelayLoop0
MOVS R0,#0
ADDS R1,R1,#1
CMP R1,#330
BCC DelayLoop0
MOVS R0,#0
MOVS R1,#0
ADDS R2,R2,#1
CMP R2,#15
BCC DelayLoop0
POP {R0,R1,PC}
; NOP
END
编译
生成hex文件:
打开串口下载:
将hex文件烧录进去,核心板的闪烁灯间断闪烁:
总结
以上就是全部内容