如何使用 STM32CubeMX 启动最小项目?

How do I start up a minimal project with STM32CubeMX?

我正在尝试学习嵌入式开发,目前正在使用 STM32F407G 开发板。

到目前为止,我已经能够使用 CubeMX 提供的高级驱动程序 API 根据用户按下按钮来切换 LED。

但是,我现在想在没有任何 API 帮助的情况下重新创建相同的功能。相反,使用参考手册中提供的基地址和寄存器,我想基本上重新创建 APIs.

到目前为止,我已经使用 GUI 禁用了所有外围设备:

但我觉得有更好的方法来做到这一点。我不完全确定我什至需要调试电路板上的代码的外围设备。

基本上,我需要足够的启动代码,以便能够将代码加载(闪存?)到微控制器中,然后进行调试 main()。其他一切(例如切换 LED、检测用户按钮中断等)都是我想要处理的事情。

您不需要重新创建 API。使用寄存器的 Jest 程序。我几乎在所有项目中都这样做(除非使用某种 HAL 是我的客户要求)

您需要:

  1. 带有向量 table 的启动代码。
  2. CMSIS headers 为了方便起见。

如何使用 CubeMx 将其存档。这实际上很容易。

  1. 创建项目
  2. 导入您喜欢的IDE。
  3. 在项目选项中删除USE_HAL_DRIVER定义
  4. 从构建中排除(或删除)/Driver/STMxxxxx_HAL_Driver
  5. 中的所有文件
  6. 删除 main.c 文件中的所有内容

添加:

#include "stm32f4xx.h" // CMSIS headers

int main(void)
{
}

尽情享受 :)

flash.s

.cpu cortex-m4
.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang

.thumb_func
reset:
    bl notmain
    b hang
.thumb_func
hang:   b .

.align

.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

.thumb_func
.globl dummy
dummy:
    bx lr

so.c

void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void dummy ( unsigned int );

int notmain ( void )
{
    unsigned int ra;

    for(ra=0;ra<1000;ra++) dummy(ra);

    return(0);
}

flash.ld

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

build(不需要 none-eabi,使用此代码您可以使用 arm-linux-gnueabi 或您想要的任何 arm-whatever-gcc/as/ld(在合理范围内))

arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mthumb -mcpu=cortex-m4 -c so.c -o so.o
arm-none-eabi-ld -o so.elf -T flash.ld flash.o so.o
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf so.bin -O binary

根据我前一段时间的笔记,您可以使用 dfu-util 编写您的二进制文件

dfu-util -d 0483:df11 -c 1 -i 0 -a 0 -s 0x08000000 -D myprogram.bin

以上内容并没有做太多,而是一个框架,供您添加 gpio 块的启用,使 led 引脚成为输出,然后使用一些代码将其关闭和打开以在循环中消磨时间。 and/or 轮询一个 gpio 引脚并驱动另一个匹配(使用按钮点亮或关闭 LED)。

openocd 使用 stlink 可以很好地连接到这个 board/family...

你一开始不需要中断或时钟配置(如果有的话)。

啊,对...在构建之后,无论您采用何种路径检查二进制文件并确保它有机会工作。

08000000 <_start>:
 8000000:   20001000    andcs   r1, r0, r0
 8000004:   08000041    stmdaeq r0, {r0, r6}
 8000008:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 800000c:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 8000010:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 8000014:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 8000018:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 800001c:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 8000020:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 8000024:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 8000028:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 800002c:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 8000030:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 8000034:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 8000038:   08000047    stmdaeq r0, {r0, r1, r2, r6}
 800003c:   08000047    stmdaeq r0, {r0, r1, r2, r6}

08000040 <reset>:
 8000040:   f000 f808   bl  8000054 <notmain>
 8000044:   e7ff        b.n 8000046 <hang>

08000046 <hang>:
 8000046:   e7fe        b.n 8000046 <hang>

vector table 在堆栈指针前面,这很好,不必使用它,忽略 stmdaeq 反汇编它只是试图反汇编向量条目,因为我使用 objdump 检查二进制文件。向量 table 需要奇数条目的地址与 1 或。从技术上讲,如果足够小,您可以在这些部件上使用 0x00000000,因为这确实是它在启动此代码时映射的位置,但因为它也被映射到 0x08000000,所以这些 ST 部件的全部闪存通常会看到它像这样完成这个。如果您从另一个系列(NXP、Atmel/Microchip 等)切换到另一个基于 cortex-m 的部件,那么您可能需要使用另一个地址,例如 0x00000000 或该部件系列使用的其他地址。

如果你没有看到二进制文件的开头看起来像这样,堆栈指针初始值和向量table,那么你不太可能在启动时运气好......无论如何library/software你走的路。

请注意,此问题的评论中给出了正确答案。它主要基于意见。有多种库解决方案,随着时间的推移,供应商会出于各种(通常是非技术性的)原因不断更改它们。从专业上讲,您应该能够走任何一条路,真正的裸机或一些沙箱或中间的某个地方。如果您不编写所有代码并使用其他人的代码,您仍然对该项目负责,因此您应该花时间深入研究并检查该代码的质量和准确性。你应该对你发现的东西感到惊讶,你拥有它如果你不喜欢它,你应该修复它 and/or 更换它。

没有一条路径会自动变得更简单、更快或更可靠。这个没有正确答案,所以你需要灵活。

文档和库代码都有错误,期待这个,期待处理这个。