当前位置: 首页 > news >正文

重庆南坪网站建设公司wordpress 图片备份

重庆南坪网站建设公司,wordpress 图片备份,siren wordpress,厦门外贸商城网站建设MCU 启动和向量表 当 STM32F429 MCU 启动时#xff0c;它会从 flash 存储区最前面的位置读取一个叫作“向量表”的东西。“向量表”的概念所有 ARM MCU 都通用#xff0c;它是一个包含 32 位中断处理程序地址的数组。对于所有 ARM MCU#xff0c;向量表前 16 个地址由 ARM … MCU 启动和向量表 当 STM32F429 MCU 启动时它会从 flash 存储区最前面的位置读取一个叫作“向量表”的东西。“向量表”的概念所有 ARM MCU 都通用它是一个包含 32 位中断处理程序地址的数组。对于所有 ARM MCU向量表前 16 个地址由 ARM 保留其余的作为外设中断处理程序入口由 MCU 厂商定义。越简单的 MCU 中断处理程序入口越少越复杂的 MCU 中断处理程序入口则会更多。 STM32F429 的向量表在数据手册表 62 中描述我们可以看到它在 16 个 ARM 保留的标准中断处理程序入口外还有 91 个外设中断处理程序入口。 在向量表中我们当前对前两个入口点比较感兴趣它们在 MCU 启动过程中扮演了关键角色。这两个值是初始堆栈指针和执行启动函数的地址固件程序入口点。 所以现在我们知道我们必须确保固件中第 2 个 32 位值包含启动函数的地址当 MCU 启动时它会从 flash 读取这个地址然后跳转到我们的启动函数。 最小固件 现在我们创建一个 main.c 文件指定一个初始进入无限循环什么都不做的启动函数并把包含 16 个标准入口和 91 个 STM32 入口的向量表放进去。用你常用的编辑器创建 main.c 文件并写入下面的内容 // Startup code __attribute__((naked, noreturn)) void _reset(void) {for (;;) (void) 0;  // Infinite loop }extern void _estack(void);  // Defined in link.ld// 16 standard and 91 STM32-specific handlers __attribute__((section(.vectors))) void (*tab[16  91])(void)  {_estack, _reset };对于 _reset() 函数我们使用了 GCC 编译器特定的 naked 和 noreturn 属性这意味着标准函数的进入和退出不会被编译器创建这个函数永远不会返回。 void (*tab[16 91])(void) 这个表达式的意思是定义一个 1691 个指向没有返回也没有参数的函数的指针数组每个这样的函数都是一个中断处理程序这个指针数组就是向量表。 我们把 tab 向量表放到一个独立的叫作 .vectors 的区段后面需要告诉链接器把这个区段放到固件最开始的地址也就是 flash 存储区最开始的地方。前 2 个入口分别是堆栈指针和固件入口目前先把向量表其它值用 0 填充。 编译 我们来编译下代码打开终端并执行 $ arm-none-eabi-gcc -mcpucortex-m4 main.c -c成功了编译器生成了 main.o 文件包含了最小固件虽然这个固件程序什么都没做。这个 main.o 文件是 ELF 二进制格式的包含了多个区段我们来具体看一下 $ arm-none-eabi-objdump -h main.o ... Sections: Idx Name          Size      VMA       LMA       File off  Algn0 .text         00000002  00000000  00000000  00000034  2**1CONTENTS, ALLOC, LOAD, READONLY, CODE1 .data         00000000  00000000  00000000  00000036  2**0CONTENTS, ALLOC, LOAD, DATA2 .bss          00000000  00000000  00000000  00000036  2**0ALLOC3 .vectors      000001ac  00000000  00000000  00000038  2**2CONTENTS, ALLOC, LOAD, RELOC, DATA4 .comment      0000004a  00000000  00000000  000001e4  2**0CONTENTS, READONLY5 .ARM.attributes 0000002e  00000000  00000000  0000022e  2**0CONTENTS, READONLY注意现在所有区段的 VMA/LMA 地址都是 0这表示 main.o 还不是一个完整的固件因为它没有包含各个区段从哪个地址空间载入的信息。我们需要链接器从 main.o 生成一个完整的固件 firmware.elf。 .text 区段包含固件代码在上面的例子中只有一个 _reset() 函数2 个字节长是跳转到自身地址的 jump 指令。.data 和 .bss(初始化为 0 的数据) 区段都是空的。我们的固件将被拷贝到偏移 0x8000000 的 flash 区但是数据区段应该被放到 RAM 里因此 _reset() 函数应该把 .data 区段拷贝到 RAM并把整个 .bss 区段写入 0。现在 .data 和 .bss 区段是空的我们修改下 _reset() 函数让它处理好这些。 为了做到这一点我们必须知道堆栈从哪开始也需要知道 .data 和 .bss 区段从哪开始。这些可以通过“链接脚本”指定链接脚本是一个带有链接器指令的文件这个文件里存有各个区段的地址空间以及对应的符号。 链接脚本 创建一个链接脚本文件 link.ld然后把一下内容拷进去 ENTRY(_reset); MEMORY {flash(rx)  : ORIGIN  0x08000000, LENGTH  2048ksram(rwx) : ORIGIN  0x20000000, LENGTH  192k  /* remaining 64k in a separate address space */ } _estack      ORIGIN(sram)  LENGTH(sram);    /* stack points to end of SRAM */SECTIONS {.vectors  : { KEEP(*(.vectors)) }    flash.text     : { *(.text*) }            flash.rodata   : { *(.rodata*) }          flash.data : {_sdata  .;   /* .data section start */*(.first_data)*(.data SORT(.data.*))_edata  .;  /* .data section end */}  sram AT  flash_sidata  LOADADDR(.data);.bss : {_sbss  .;              /* .bss section start */*(.bss SORT(.bss.*) COMMON)_ebss  .;              /* .bss section end */}  sram.  ALIGN(8);_end  .;     /* for cmsis_gcc.h  */ }下面分段解释下 ENTRY(_reset);这行是告诉链接器在生成的 ELF 文件头中 entry point 属性的值。没错这跟向量表重复了这个的目的是为像 Ozone 这样的调试器设置固件起始的断点。调试器是不知道向量表的所以只能依赖 ELF 文件头。 MEMORY {flash(rx)  : ORIGIN  0x08000000, LENGTH  2048ksram(rwx) : ORIGIN  0x20000000, LENGTH  192k  /* remaining 64k in a separate address space */ }这是告诉链接器有 2 个存储区空间以及它们的起始地址和大小。 _estack      ORIGIN(sram)  LENGTH(sram);    /* stack points to end of SRAM */这行告诉链接器创建一个 _estack 符号它的值是 RAM 区的最后这也是初始化堆栈指针的值。 .vectors  : { KEEP(*(.vectors)) }    flash.text     : { *(.text*) }            flash.rodata   : { *(.rodata*) }          flash这是告诉链接器把向量表放在 flash 区最前然后是 .text 区段固件代码再然后是只读数据 .rodata。 .data : {_sdata  .;   /* .data section start */*(.first_data)*(.data SORT(.data.*))_edata  .;  /* .data section end */}  sram AT  flash_sidata  LOADADDR(.data);这是 .data 区段告诉链接器创建 _sdata 和 _edata 两个符号我们将在 _reset() 函数中使用它们将数据拷贝到 RAM。 .bss : {_sbss  .;              /* .bss section start */*(.bss SORT(.bss.*) COMMON)_ebss  .;              /* .bss section end */}  sram.bss 区段也是一样。 启动代码 现在我们来更新下 _reset 函数把 .data 区段拷贝到 RAM然后把 .bss 区段初始化为 0再然后调用 main() 函数在 main() 函数有返回的情况下进入无限循环 int main(void) {return 0; // Do nothing so far }// Startup code __attribute__((naked, noreturn)) void _reset(void) {// memset .bss to zero, and copy .data section to RAM regionextern long _sbss, _ebss, _sdata, _edata, _sidata;for (long *src  _sbss; src  _ebss; src) *src  0;for (long *src  _sdata, *dst  _sidata; src  _edata;) *src  *dst;main();             // Call main()for (;;) (void) 0;  // Infinite loop in the case if main() returns }下面的框图演示了 _reset() 如何初始化 .data 和 .bss 初始化 firmware.bin 文件由 3 部分组成.vectors(中断向量表)、.text(代码)、.data(数据)。这些部分根据链接脚本被分配到不同的存储空间.vectors 在 flash 的最前面.text 紧随其后.data 则在那之后很远的地方。.text 中的地址在 flash 区.data 在 RAM 区。例如一个函数的地址是 0x8000100则它位于 flash 中。而如果代码要访问 .data 中的变量比如位于 0x20000200那里将什么也没有因为在启动时 firmware.bin 中 .data 还在 flash 里这就是为什么必须要在启动代码中将 .data 区段拷贝到 RAM。 现在我们可以生成完整的 firmware.elf 固件了 $ arm-none-eabi-gcc -T link.ld -nostdlib main.o -o firmware.elf再次检验 firmware.elf 中的区段 $ arm-none-eabi-objdump -h firmware.elf ... Sections: Idx Name          Size      VMA       LMA       File off  Algn0 .vectors      000001ac  08000000  08000000  00010000  2**2CONTENTS, ALLOC, LOAD, DATA1 .text         00000058  080001ac  080001ac  000101ac  2**2CONTENTS, ALLOC, LOAD, READONLY, CODE ...可以看到.vectors 区段在 flash 的起始地址 0x8000000.text 紧随其后。我们在代码中没有创建任何变量所以没有 .data 区段。 烧写固件 现在可以把这个固件烧写到板子上了 先把 firmware.elf 中各个区段抽取到一个连续二进制文件中 $ arm-none-eabi-objcopy -O binary firmware.elf firmware.bin然后使用 st-link 工具将 firmware.bin 烧入板子连接好板子然后执行 $ st-flash --reset write firmware.bin 0x8000000这样就把固件烧写到板子上了。
http://www.yingshimen.cn/news/107386/

相关文章:

  • 交换链接适合哪些网站南宁网站建设seo
  • 医疗教育的网站建设网站建设案例精粹 电子书
  • 养老网站建设 中企动力白山市住房和建设局网站
  • 镇江网站搜索排名天猫优惠券网站怎么做
  • 都有什么网站wordpress外网
  • 广西翔路建设有限责任公司网站wordpress如何撤销301
  • 河北省建设网站首页个人做网站怎么备案
  • 做代练去什么网站安全吗网站logo下载
  • 赣州做网站的公司哪家好上海企业网上公示
  • 一个服务器上有两个网站 要备案两次吗自己做的网站打开是乱码
  • 网站开发设计实训 报告公司网站建设行业怎么样
  • 电子商务网站建设公服装公司简介
  • 营销型网站的评价标准qq空间破解版
  • 各大网站下载品牌建设金点子
  • 静态企业网站模板下载网站要怎么备案
  • 城乡建设厅官方网站办事大厅学计算机出来能干什么
  • 关于网站的毕业设计网站首页制作方案
  • 家政公司响应式网站建设案例so域名的网站有哪些
  • 彩票网站开发dadi163电子商务网站建设详细策划
  • 做网站用到的单词html旅游网页完整代码
  • 合肥网站推广哪家好受欢迎的句容网站建设
  • 怎么做卖东西的网站聊城市住房和城乡建设局网站
  • 建设微网站项目报告百度关键词排名批量查询
  • 为什么上传网站模板网站上没有文字和图片免费室内设计素材网站
  • 怎么做网站弄网盟免费网站系统
  • 网站开发协议书由谁来写最好看免费观看高清大全大江大河
  • 公司的网站推广费怎么做分录网站推广培训机构
  • 网站注册域名微信网站欣赏
  • 口碑好的秦皇岛网站建设价格晋城网站建设费用
  • 什么做电子书下载网站国内买机票的网站建设