我们为ARM Cortex-M3编写了最简单的程序

图片 下午好 今天,我想告诉您如何编写一个在ARM Cortex-M3上运行并显示“ Hello,World!”的最小程序。 我们将尝试逐步确定为此所需的最低要求。 我们将在QEMU仿真器上运行。 因此,即使手头没有一块铁,任何人都可以繁殖。

所以走吧!

QEMU仿真器支持Cortex-M3内核,并在此基础上仿真来自Texas Instruments的Stellaris LM3S811平台。 我们将在此平台上运行。 我们需要arm-none-eabi-工具链(您可以在此处下载)。 接下来,我们需要编写程序的主要逻辑,将控制权转移到程序的开始代码和链接脚本。

在habr上已经有相当不错的 文章,内容涉及如何从头开始使铁片上的二极管闪烁。 因此,在这里我不会深入研究它的作用和工作方式,而只会给出开始所需的最少知识。

我们在test.c文件中的世界:

static volatile unsigned int * const UART_DR = (unsigned int *)0x4000c000; static void uart_print(const char *s) { while (*s != '\0') { *UART_DR = *s; s++; } } void c_entry(void) { uart_print("Hello, World!\n"); while (1) ; } 

此地址0x4000c000从文档中获取,其中DR寄存器零为零。 我们不会参与设置UART (这需要在硬件上完成),但是我们将尝试立即将符号直接放入其中。

现在,我们需要以某种方式将控制权转移到文件test.c中的with_entry函数。 为此,请创建以下代码(startup.S文件),然后将其放在最后的最终ELF映像中。

 .type start, %function .word stack_top /*     */ .word start /*    PC */ .global start start: ldr r1, =c_entry bx r1 

0x0处的第一个字应为指向堆栈顶部(SP)的指针。 在0x4处有一台PC,该PC与SP一样被加载到寄存器中。 请注意,因为Cortex-M代码是在Thumb模式下执行的(这是一组简化的ARM命令),所以start被精确地声明为一个函数,而不是作为一个标签声明,并且要求中断向量中函数的地址应采用以下形式: 0x1)-即 地址的最后一位必须为1。

接下来,启动函数仅从test.c文件中加载c_entry()函数的地址,然后通过“ bx r1”传递控制权。

仅保留成功链接我们的程序。 为此,您需要设置我们微控制器的存储卡。 在文档中,您可以找到闪存(ROM)和RAM(RAM)的地址和大小。 这是test.ld链接描述文件:

 SECTIONS { . = 0x0; /*   (ROM) */ .text : { startup.o(.text) test.o(.text) } . = 0x20000000; /*     RAM */ .data : { *(.data) } .bss : { *(.bss) } . = ALIGN(8); . = . + 0x1000; /*    4 */ stack_top = .; } 

注意地址很重要。 “。” 链接描述文件中的表示当前位置。 我们将.text节放在ROM的开头(地址0x0),遵循以下顺序-startup.o(.text)首先。 接下来,转到RAM(。= 0x20000000;)并将数据(初始化的全局数据)和bss(未初始化的全局数据)放在那里。 在下面我们看到ALIGN(8)-ARM需要将SP(堆栈指针)对准8。由于堆栈变小,因此堆栈下方的空间分配只是一个补充。” =。 + 0x1000”。 我们很了解我们的程序,因此4kB堆栈足够大。

仅此而已,将所有内容放在一起。 我带来了build.sh:

 #!/bin/sh arm-none-eabi-as -c -mthumb -mlittle-endian -march=armv7-m -mcpu=cortex-m3 startup.S -o startup.o arm-none-eabi-gcc -c -mthumb -ffreestanding -mlittle-endian -march=armv7-m -mcpu=cortex-m3 test.c -o test.o arm-none-eabi-ld -T test.ld test.o startup.o -o test.elf 

除了标志-ffreestanding以外,这里的所有内容都应或多或少被理解。 在这种情况下,您不必添加它(可以检查它),但是由于我们是从头开始准备裸机映像,因此最好告诉编译器,使其不要关注main()之类的函数。

结果,我们得到了ELF文件test.elf。 在QEMU上运行它:

 $ qemu-system-arm -M lm3s811evb -kernel test.elf -nographic Hello, World! 

可以用

当然,这是一个案例研究,旨在了解正在发生的事情。 如果需要更有意义的功能,则应使用现成的东西。 我们在Embox中添加了对该平台的支持 。 该模板称为platform / stellaris / lm3s811evb。 因此,如果有人想尝试运行稍微严重的事情(控制台,计时器,中断),则可以收集并尝试。 我再说一次,在这种情况下,您不需要一块硬件板。

而那些仍然没有足够模拟器的人,或者想问我们问题并玩弄铁片的人,我们将在星期六和星期日在圣彼得堡的IT节techtrain.ru上等待。 我们将在架子上放各种铁,在演示区中,我们将尝试告诉他们如何编程。

Source: https://habr.com/ru/post/zh-CN421833/


All Articles