传统计算机采用冯·诺依曼(Von Neumann)结构,也称普林斯顿结构,是一种将程序指令存储器和数据存储器并在一起的存储器结构。冯·诺依曼结构的计算机其程序和数据公用一个存储空间,程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置;采用单一的地址及数据总线,程序指令和数据的宽度相同。处理器执行指令时,先从储存器中取出指令解码,再取操作数执行运算,即使单条指令也要耗费几个甚至几十个周期,在高速运算时,在传输通道上会出现瓶颈效应。
也就是一共要包含5个部分,
哈佛(Harvard)结构是一种将程序指令存储和数据存储分开的存储器结构。哈佛结构是一种并行体系结构,它的主要特点是将程序和数据存储在不同的存储空间中,即程序存储器和数据存储器是两个相互独立的存储器,每个存储器独立编址、独立访问。与两个存储器相对应的是系统中的4套总线:程序的数据总线与地址总线,数据的数据总线与地址总线。这种分离的程序总线和数据总线可允许在一个机器周期内同时获取指令字(来自程序存储器)和操作数(来自数据存储器),从而提高了执行速度,是数据的吞吐率提高了1倍。又由于程序和数据存储器在两个分开的物理空间中,因此取指和执行能完全重叠。
数字信号处理一般需要较大的运算量和较高的运算速度,为了提高数据吞吐量,在数字信号处理器中大多采用哈佛结构。
程序存储器和数据存储器是各自独立的存储器。处理器只有一套总线,分时访问程序存储器和数据存储器,但是在处理器中有icache和dcache将程序和数据分开,所以处理器仍然可以并步执行取指令和取数据。
这种结构总是被人所遗忘,然而从ARM9开始以后所有的ARM处理器内核都是改进型的哈佛结构。ARM的逻辑代码和变量都是存放在RAM中的,但是,它在内存中划分了两部分的空间,其中一部分放逻辑代码,另一部分存放变量,之间不会相互干扰。
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体
就是程序运行中的程序内部,储存器,运算器,控制器的变化的过程。
程序文件是在质量管理体系中质量手册的下一级文件层次,规定某项工作的一般过程。再下一级文件层次是作业指导书。程序文件存储的是程序,包括源程序和可执行程序。这里的程序与计算机技术中的程序并不相同,程序在这里指是为完成某项活动所规定的方法。
这个来自百度的定义显然不好,我们来重新定义一下
我们先把我们所谓的程序文件换个名字,叫芯片层面的可执行文件
然后我们就可以解释成:
芯片层面的可执行文件:是编译后生成的可执行文件(比如.bin .hex文件等)
当让我们这个定义是有问题,比如如果你有java虚拟机,python解释器,那么一个即使芯片无法直接运行但是,微控制器可以通过类似解释器,虚拟机这种机制来运行。这种方法如果之后有机会我在详细讨论,此处不管了。
如果用过mdk5活着iar的伙伴们编译过后应该会产生这么一个字段
Code:即代码域,它指的是编译器生成的机器指令。
RO_data:ReadOnly data,即只读数据域,它指程序中用到的只读数据,全局变量,例如C语言中const关键字定义的全局变量就是典型的RO-data。
RW_data:ReadWrite data,即可读写数据域,它指初始化为“非0值”的可读写数据,程序刚运行时,这些数据具有非0的初始值,且运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。例如全局变量或者静态变量,且定义时赋予“非0值”给该变量进行初始化。
ZI_data:ZeroInitialie data,即0初始化数据,它指初始化为“0值”的可读写数据域,它与RW_data的区别是程序刚运行时这些数据初始值全都为0,而后续运行过程与RW-data的性质一样,它们也常驻在RAM区,因而应用程序可以更改其内容。包括未初始化的全局变量,和初始化为0的全局变量。
RO:只读区域,包括RO_data和code。
相关概念:堆(heap),栈(stack),BSS段,数据段(data),代码段(code /text),全局静态区,文字常量区,程序代码区。
BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。
代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。
栈(stack):栈又称堆栈,用户存放程序临时创建的局部变量。在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的后进先出特点,所以栈特别方便用来保存/恢复调用现场。
全局静态区,文字常量区,程序代码区是从内存地址分配的角度来描述的。
全局区(静态区)(static): 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
文字常量区: 常量字符串就是放在这里的。
程序代码区: 存放函数体的二进制代码。
所谓启动,一般来说就是指我们下好程序后,复位活着上电时,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存。用户可以通过设置BOOT1和BOOT0引脚的状态,来选择在复位后的启动模式。
STM32上电或者复位后,代码区始终从0x00000000开始,三种启动模式其实就是将各自存储空间的地址映射到0x00000000中。
(1)从Flash启动,将主Flash地址0x08000000映射到0x00000000,这样代码启动之后就相当于从0x08000000开始。
(2)从RAM启动,将RAM地址0x20000000映射到0x00000000,这样代码启动之后就相当于从0x20000000开始。
(3)从系统存储器启动。首先控制BOOT0 BOOT1管脚,复位后,STM32与上述两种方式类似,从系统存储器地址0x1FFF F000开始执行代码。系统存储器存储的其实就是STM32自带的bootloader代码,在bootloader中提供了UART1的接口,通过此接口可以将用户所需的程序代码下载到主Flash中,下载完毕后,此时程序代码已经存储在主Flash当中,这时切换启动模式(从主Flash启动),复位后所执行的就是刚刚下载到Flash中的代码了。
(1)用户闪存 : 芯片内置的Flash。正常的工作模式。
(2)系统存储器: 芯片内部一块特定的区域,芯片出厂时在这个区域预置了一段Bootloader,就是通常说的ISP程序。这个区域的内容在芯片出厂后没有人能够修改或擦除,即它是一个ROM区。启动的程序功能由厂家设置。也就是串口烧录程序要从这里启动,所以如果要串口烧录程序请将boot设置为01,运行时在调回原第一种启动模式
(3)SRAM: 芯片内置的RAM区,就是内存。可以用于调试,不建议用这种模式,适用于厂家模块调试,大神请自便。
这里多嘴一句,有些人用的是正点原子的开发板,发现下载的时候冰需要boot 01 ,直接就可以下载,这里特此说明,此处采用的硬件dtr复位一键进入bootleader从而使得用户不需要来回拔插跳帽,从而减轻用户负担,但是需要配套相应的下载软件及硬件电路
注:此处的选择
http://www.openedv.com/posts/list/1060.htm相关技术说明如上
其次附上Flash锁死解决办法:
开发调试过程中,由于某种原因导致内部Flash锁死,无法连接SWD以及Jtag调试,无法读到设备,可以通过修改BOOT模式重新刷写代码。
修改为BOOT0=1,BOOT1=0即可从系统存储器启动,ST出厂时自带Bootloader程序,SWD以及JTAG调试接口都是专用的。重新烧写程序后,可将BOOT模式重新更换到BOOT0=0,BOOT1=X即可正常使用。
STM32有两个存储空间,一个是片上的FLASH,—个是片上的RAM,一般是sram。RAM相当于内存,FLASH相当于硬盘。
我们都知道,在烧写程序的时候,需要烧写bin文件或者hex文件到STM32的flash当中,被烧写的文件称为映像文件image。Image的内容包含三部分:code,RO-data和RW-data。
为什么Image不包含ZI数据呢,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域(这一区域在RAM中)一律清零即可。包含进去反而浪费flash存储空间。
STM32上电启动以后,根据boot0和boot1的硬件引脚决定从flash还是ram中启动,默认是从flash中启动;启动之后会搬运到ram,但是不会搬运code;也就是说执行的代码是在flash中读取的,而不是在ram中。
具体请看技术手册,此处只简单叙述