微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

带有核 L432KC 板的 arm-none-eabi-gcc

如何解决带有核 L432KC 板的 arm-none-eabi-gcc

我正在寻找一个程序来从 linux 终端编译和上传我的 STM32L432KC 核电路板代码,就像我在 atmega328p Here} 中使用的程序一样

我有点喜欢使用 vim 和 gdb 调试器,我很高兴使用 avr-gcc 和 avra 为我的 avr atmega328p 这样做了一段时间但现在我想继续深入研究嵌入式系统所以我买了我的核板Documentation Page

所以我只需要一个像上面一样的小教程来编译、链接和烧写代码,而无需安装任何 IDE

解决方法

STM32 芯片都是基于 cortex-m(他们从 ARM 购买的核心)。并且到目前为止它们都支持 cortex-m0 指令集(armv6-m)。您可以按照 ST 文档查看它在武器网站 infocenter.arm.com 上的技术参考手册中具有的 cortex-m 核心,并在其中说明了哪种架构(armv6-m armv7-m armv8-m ...)和在那里你可以了解指令集和架构。如果没有最低限度的文件,您不应该开始这段旅程。 ARM TRM 和ARM ARM 为内核和架构。和 ST 的 REFERENCE 手册(不是他们的程序员手册)和 ST 的数据表。

cortex-ms 从向量表启动,在架构参考手册 (ARM) 中有所描述。第一个字被加载到堆栈指针中,第二个字是复位向量,它被定义为要求 lsbit 为 1(表示这是一个拇指函数地址)。你可以阅读其余的内容。做一个足够好的最小例子。

我使用过的所有 STM32 芯片(我使用过很多)都支持基于 0x08000000 的用户闪存和 0x20000000 的 SRAM,一些核板附带的较新固件将坚持正确的 0x08000000向量表中的地址(一些小百分比也支持 0x00200000 处的更快内存地址)。 ARM 文档基本上会说 0x00000000 或表示 VTOR 的事情,但实际上它通常是 0x00000000 作为逻辑寻找的地址,以便在复位时找到向量表。给这只猫剥皮的方法多种多样,但 ST 选择将 Flash 的百分比镜像到 0x00000000。

这是一个让您入门的非常简单的示例。

引导程序,flash.s

.thumb

.thumb_func
.global _start
_start:
.word 0x20001000
.word reset
.word loop
.word loop

.thumb_func
reset:
    bl notmain
    b loop
.thumb_func
loop:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

主/入口C代码notmain.c

extern void bounce ( unsigned int );
unsigned int x;
void notmain ( void )
{   
    unsigned int ra;
    
    x=5;
    for(ra=0;;ra++) bounce(ra);
}

包括 gnu 工具在内的一些工具会看到 main() 关键字并向二进制文件添加内容,这有时是我们不想要的。一些工具链比其他工具链更糟糕。这是打败它的一个微不足道的解决方案。天啊。

链接脚本 flash.ld

MEMORY
{
    rom : ORIGIN = 0x08000000,LENGTH = 0x1000
    ram : ORIGIN = 0x20000000,LENGTH = 0x1000
}
SECTIONS
{
    .text   : { *(.text*)   } > rom
    .bss    : { *(.bss*)    } > ram
}

虽然命令行 -Ttext= 和 -Tdata= 等存在于链接器中,但我建议不要使用它们,除非在懒惰时偶尔出现 Stack Overflow 答案。命令行选项存在一些令人不快的问题,包括一个他们仍未修复的长期存在的错误(这些工具神奇地与错误的结果一起工作,所以我猜没有人在乎)。

构建

arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=cortex-m0 -mthumb -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles -T flash.ld flash.o notmain.o -o notmain.elf
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy -O binary notmain.elf notmain.bin

现在我的代码被设计成不关心 arm-none-eabi- 与 arm-linux-gnueabi- 之类的事情,arm-whatever-whatever 的过去 10 年或 15 年应该可以工作。我只是将编译器用作编译器,将链接器用作链接器。尽可能接近零工具链特定的魔法。

始终检查输出以查看向量表是否看起来不错 notmain.list(我使用了反汇编器,因此例如该工具尝试反汇编向量,只需忽略那里的反汇编)。

notmain.elf:     file format elf32-littlearm


Disassembly of section .text:

08000000 <_start>:
 8000000:   20001000    andcs   r1,r0,r0
 8000004:   08000011    stmdaeq r0,{r0,r4}
 8000008:   08000017    stmdaeq r0,r1,r2,r4}
 800000c:   08000017    stmdaeq r0,r4}

08000010 <reset>:
 8000010:   f000 f804   bl  800001c <notmain>
 8000014:   e7ff        b.n 8000016 <loop>

08000016 <loop>:
 8000016:   e7fe        b.n 8000016 <loop>

08000018 <bounce>:
 8000018:   4770        bx  lr
    ...

0800001c <notmain>:
 800001c:   2205        movs    r2,#5
 800001e:   b510        push    {r4,lr}
 8000020:   2400        movs    r4,#0
 8000022:   4b03        ldr r3,[pc,#12]   ; (8000030 <notmain+0x14>)
 8000024:   601a        str r2,[r3,#0]
 8000026:   0020        movs    r0,r4
 8000028:   f7ff fff6   bl  8000018 <bounce>
 800002c:   3401        adds    r4,#1
 800002e:   e7fa        b.n 8000026 <notmain+0xa>
 8000030:   20000000    andcs   r0,r0

Disassembly of section .bss:

20000000 <x>:
20000000:   00000000    andeq   r0,r0

地址空间是对的 0x08000000

08000000 <_start>:
 8000000:   20001000
 8000004:   08000011
 8000008:   08000017
 800000c:   08000017

向量的地址是地址 ORRED 与 1,这是正确的。现在并非所有 STM32 都有 0x1000 字节的 ram,因此有时您会将其缩小。

minimal-ish 链接器脚本和最小引导程序仅在您不依赖 .data 初始化和 .bss 清零时才有效。

08000010 <reset>:
 8000010:   f000 f804   bl  800001c <notmain>
 8000014:   e7ff        b.n 8000016 <loop>

对于这个例子,它工作得很好。您可以像其他人一样使您的链接器脚本过于复杂。或者你可以保持简单。作为裸机,您已经想要牺牲 C 库,那么如果您必须初始化全局变量运行时怎么办?不应该在写入之前读取内存,因此 .bss 也不需要为零。

可以使用此解决方案来解决您第一次闪烁 LED 程序(裸机的 hello 世界)的微不足道的延迟。

for(ra=0;;ra++) bounce(ra);

因为bounce不在notmain.c的优化范围内,编译器不会像死代码那样尝试删除它

for(ra=0;ra<100000;ra++) continue;

如果试图以这种方式延迟。在您最初闪烁 LED 后,然后开始以轮询方式使用定时器,在熟悉处理器、芯片和外设并弄清楚中断如何以轮询方式为该芯片工作之前,不要接近中断。如果您不这样做,那么我们将再次与您在 SO 上见面,并提出问题。

CMSIS 标头如果您实际查看它们就非常难看,而且 CMSIS 部分采用了统一的语法,因为 ARM 的另一个伟大的想法已经变坏了。把握机会,就像把握机会使用他们的库一样。 (只要看看源代码,你就会明白我的意思。

NUCLEO 板是一个很好的起点,因为在目标 mcu 中“编程”闪存所需要做的就是复制 notmain.bin 二进制文件。 cp notmain.bin /media/user/something 和正在创建虚拟拇指驱动器的调试 mcu,当您插入电路板时,您会看到挂载的虚拟拇指驱动器,获取文件并通过 SWD 编程目标 mcu 并为您释放重置。

然后你可以自由地使用 openocd 和 flash write_image erase notmain.elf 将 flash 写入目标 mcu,或者 GDB,如果你敢的话,等等。但是简单的拖放或命令行复制就可以了。

我发现在编码会话过程中有时写入不起作用、设备已满或诸如此类。拔下并重新插入 NUCLEO 板,即可修复。

现在很难找到,所以从 st 寻找 stsw-link007,一个版本会从 ST 中提取自己的更新。对于每个新的 NUCLEO 板,我都会在板上进行固件更新,因为我运行 Linux 并且 NUCLEO 调试器固件和 Linux 的组合使虚拟驱动器的安装不太可靠,您可能会在编程时遇到问题,然后必须重新启动再试一次。它是一个 JAVA 程序,因此它可以在 Windows 或 Linux 或 Mac 上运行。

首先尝试使 LED 闪烁并从那里开始,需要为特定的 gpio 块(GPIOA、B、C,无论 NUCLEO 板文档中注明的内容)启用时钟,然后将该引脚设为输出并使用 BSRR设置/重置,每个之间有延迟。越过你正在路上的那个人。

您会发现的大多数示例要么是基于库的,要么是来自 ST 的不止一种类型的库。在某些情况下,电路板可以在 Arduino 世界中工作,并且 nucleos 可能适合 mbed 世界,因此如果您不想执行上述操作,则可以在该沙箱中进行游戏。但是在大多数情况下,外围设备都非常易于使用,ST 的文档处于更好的一面,不是最好的也不是最差的,而是最好的。 ARMs 文档也是如此。定期尝试所有这些,以便您知道那里有什么,然后定期选择您想要在其中进行项目的内容。这些事情会发展(而不是滚动您自己的总是已知的数量),所以看看他们必须提供什么.

gnu 工具比 llvm 工具更稳定,但两者工作得同样好,gnu 的编译器从 4.x.x 左右到现在甚至 3.x.x 都变得更糟。 llvm 你会认为会做得更好,但遗憾的是,它仍然是标准的,或者有时会产生更慢的代码。 clang 和其他工具的命令行选项几乎每个主要版本都会改​​变,因此尝试使用 llvm 工具维护您的 makefile 是一场噩梦,因此我多次放弃对它们的支持。

我现在为目标 gnu 风格构建了 llvm,这样我就不需要那些命令行选项了,而且已经做得更好了,gcc 在最近几次主要修订中变得越来越草率,在那里留下指令一般都是优化出来的。两者都有效。请注意,使用 clang 进行编译但使用 binutils 进行组装和链接并不罕见,如果您为目标构建 llvm(例如 armv6m),那么您也可以构建一个交叉链接器并使用它。遗憾的是,他们没有汇编程序,因此您必须将编译器用作汇编程序。

如果二进制文件未编程到目标 mcu 中,NUCLEO 上的虚拟驱动器将放置一个 FAIL.TXT 文件,其中没有任何有用的信息。像对向量表使用 0x00000000 之类的事情就可以做到这一点。除此之外,您只需要调试您的代码/构建。同样在检查列表文件时,如果您使用的是 cortex-m0 或 -m0+ 或 cortex-m8 的基本风格(那些不支持拇指 2 扩展的最大份额),那么您将出错。因此,从 cortex-m4 或 -m7 到 cortex-m0 的项目作为骨架起点时要小心,记住要以 m0 为目标,或者通常始终以 m0 为目标,然后利用额外的 thumb2 扩展,如果你代码有特定的性能问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?