簡體   English   中英

STM32F4 微控制器上的 LED 無法閃爍

[英]Can't blink LED on STM32F4 microcontroller

我想確保我已經正確設置了我的第一個嵌入式軟件項目,因此我試圖讓我的 NUCLEO-F411RE 板(STM32F411RE 微控制器)上的 LED 閃爍。 我沒有使用任何 IDE,因為我想從頭開始做所有事情。 我的項目結構如下。

├── build
│   ├── Buggy.bin
│   ├── Buggy.dis
│   ├── Buggy.elf
│   ├── Buggy.hex
│   ├── Buggy.map
│   ├── main.o
│   ├── startup_stm32f411xe.o
│   ├── stm32f4xx_it.o
│   └── system_stm32f4xx.o
├── lib
│   ├── cmsis
│   │   ├── include
│   │   │   ├── arm_common_tables.h
│   │   │   ├── arm_const_structs.h
│   │   │   ├── arm_math.h
│   │   │   ├── core_cm0.h
│   │   │   ├── core_cm0plus.h
│   │   │   ├── core_cm3.h
│   │   │   ├── core_cm4.h
│   │   │   ├── core_cm7.h
│   │   │   ├── core_cmFunc.h
│   │   │   ├── core_cmInstr.h
│   │   │   ├── core_cmSimd.h
│   │   │   ├── core_sc000.h
│   │   │   └── core_sc300.h
│   │   └── stm32f4xx
│   │       ├── stm32f4xx.h
│   │       └── system_stm32f4xx.h
│   ├── Makefile
│   └── STM32F4xx_StdPeriph_Driver
│       ├── include
│       │   ├── misc.h
│       │   ├── stm32f4xx_adc.h
│       │   ├── stm32f4xx_crc.h
│       │   ├── stm32f4xx_dbgmcu.h
│       │   ├── stm32f4xx_dma.h
│       │   ├── stm32f4xx_exti.h
│       │   ├── stm32f4xx_flash.h
│       │   ├── stm32f4xx_flash_ramfunc.h
│       │   ├── stm32f4xx_gpio.h
│       │   ├── stm32f4xx_i2c.h
│       │   ├── stm32f4xx_iwdg.h
│       │   ├── stm32f4xx_pwr.h
│       │   ├── stm32f4xx_rcc.h
│       │   ├── stm32f4xx_rtc.h
│       │   ├── stm32f4xx_sdio.h
│       │   ├── stm32f4xx_spi.h
│       │   ├── stm32f4xx_syscfg.h
│       │   ├── stm32f4xx_tim.h
│       │   ├── stm32f4xx_usart.h
│       │   └── stm32f4xx_wwdg.h
│       ├── libstdperiph.a
│       ├── Makefile
│       └── src
│           ├── misc.c
│           ├── misc.o
│           ├── stm32f4xx_adc.c
│           ├── stm32f4xx_adc.o
│           ├── stm32f4xx_crc.c
│           ├── stm32f4xx_crc.o
│           ├── stm32f4xx_dbgmcu.c
│           ├── stm32f4xx_dbgmcu.o
│           ├── stm32f4xx_dma.c
│           ├── stm32f4xx_dma.o
│           ├── stm32f4xx_exti.c
│           ├── stm32f4xx_exti.o
│           ├── stm32f4xx_flash.c
│           ├── stm32f4xx_flash.o
│           ├── stm32f4xx_flash_ramfunc.c
│           ├── stm32f4xx_flash_ramfunc.o
│           ├── stm32f4xx_gpio.c
│           ├── stm32f4xx_gpio.o
│           ├── stm32f4xx_i2c.c
│           ├── stm32f4xx_i2c.o
│           ├── stm32f4xx_iwdg.c
│           ├── stm32f4xx_iwdg.o
│           ├── stm32f4xx_pwr.c
│           ├── stm32f4xx_pwr.o
│           ├── stm32f4xx_rcc.c
│           ├── stm32f4xx_rcc.o
│           ├── stm32f4xx_rtc.c
│           ├── stm32f4xx_rtc.o
│           ├── stm32f4xx_sdio.c
│           ├── stm32f4xx_sdio.o
│           ├── stm32f4xx_spi.c
│           ├── stm32f4xx_spi.o
│           ├── stm32f4xx_syscfg.c
│           ├── stm32f4xx_syscfg.o
│           ├── stm32f4xx_tim.c
│           ├── stm32f4xx_tim.o
│           ├── stm32f4xx_usart.c
│           ├── stm32f4xx_usart.o
│           ├── stm32f4xx_wwdg.c
│           └── stm32f4xx_wwdg.o
├── main.c
├── main.h
├── Makefile
├── startup_stm32f411xe.s
├── stm32f4xx_conf.h
├── stm32f4xx_flash.ld
├── stm32f4xx_it.c
├── stm32f4xx_it.h
└── system_stm32f4xx.c

我正在使用 STD_Periph 庫來處理與實際硬件和 CMSIS 的接口,以實現實際處理器核心和外圍設備的硬件抽象(我認為)。

main.c 源文件應包含每秒閃爍板上 LED 的代碼。

#include "stm32f4xx.h"

void TimingDelay_Decrement(void);

static __IO uint32_t uwTimingDelay;
static void Delay(__IO uint32_t nTime);

int main(void) {

  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  while (1) {
      GPIO_ToggleBits(GPIOD, GPIO_Pin_13);
      Delay(1000);
  }

}

void Delay(__IO uint32_t nTime)
{ 
  uwTimingDelay = nTime;

  while(uwTimingDelay != 0x00) {
    uwTimingDelay--;
  }
}

void TimingDelay_Decrement(void)
{
  if (uwTimingDelay != 0x00)
  { 
    uwTimingDelay--;
  }
}

當我使用 Makefile 和make命令構建我的項目時,一切正常。 然后我運行 make flash,它也成功完成。 但是,沒有一個 LED 每秒閃爍一次。 我不知道問題是什么,特別是沒有錯誤消息,所以我很難調試。 我感覺它與 Makefile 或 linker 腳本有關,所以我將它們包含在下面。

Makefile:

# STM32F4-Discovery Makefile

C_SRC=$(wildcard *.c) \
$(wildcard src/*.c)
# Add assembly source files here or use $(wildcard *.s) for all .s files
S_SRC = $(wildcard *.s)

# Project name
PROJ_NAME = Buggy
OUTPATH = build

BINPATH = /usr/bin/
OUTPATH := $(abspath $(OUTPATH))
BASEDIR := $(abspath ./)
MKDIR_P = mkdir -p


###################################################

# Check for valid float argument
# NOTE that you have to run make clean after
# changing these as hardfloat and softfloat are not
# binary compatible
ifneq ($(FLOAT_TYPE), hard)
ifneq ($(FLOAT_TYPE), soft)
#override FLOAT_TYPE = hard
override FLOAT_TYPE = soft
endif
endif

###################################################

AS=$(BINPATH)arm-none-eabi-as
CC=$(BINPATH)arm-none-eabi-gcc
LD=$(BINPATH)arm-none-eabi-gcc
OBJCOPY=$(BINPATH)arm-none-eabi-objcopy
OBJDUMP=$(BINPATH)arm-none-eabi-objdump
SIZE=$(BINPATH)arm-none-eabi-size

LINKER_SCRIPT = stm32f4xx_flash.ld

CPU = -mcpu=cortex-m4 -mthumb

CFLAGS  = $(CPU) -c -std=gnu99 -g -O2 -Wall
LDFLAGS  = $(CPU) -mlittle-endian -mthumb-interwork -Wl,--gc-sections,-Map=$(OUTPATH)/$(PROJ_NAME).map,--cref --specs=nano.specs

ifeq ($(FLOAT_TYPE), hard)
CFLAGS += -fsingle-precision-constant -Wdouble-promotion
CFLAGS += -mfpu=fpv4-sp-d16 -mfloat-abi=hard
else
CFLAGS += -msoft-float
endif

# Default to STM32F411xE if no device is passed
ifeq ($(DEVICE_DEF), )
DEVICE_DEF = STM32F411xE
endif

CFLAGS += -D$(DEVICE_DEF)

vpath %.a lib

# Includes
INCLUDE_PATHS = -I$(BASEDIR)/lib/cmsis/stm32f4xx -I$(BASEDIR)/lib/cmsis/include -I$(BASEDIR)
INCLUDE_PATHS += -I$(BASEDIR)/lib/STM32F4xx_StdPeriph_Driver/include

# Library paths
LIBPATHS = -L$(BASEDIR)/lib/STM32F4xx_StdPeriph_Driver

# Libraries to link
LIBS = -lstdperiph -lc -lgcc -lnosys

OBJS = $(C_SRC:.c=.o)
OBJS += $(S_SRC:.s=.o)

###################################################

.PHONY: lib proj

all: dir lib proj
    $(SIZE) $(OUTPATH)/$(PROJ_NAME).elf

lib:
    $(MAKE) -C lib FLOAT_TYPE=$(FLOAT_TYPE) BINPATH=$(BINPATH) DEVICE_DEF=$(DEVICE_DEF) BASEDIR=$(BASEDIR)

proj: $(OUTPATH)/$(PROJ_NAME).elf

.s.o:
    $(AS) $(CPU) -o $(addprefix $(OUTPATH)/, $@) $<

.c.o:
    $(CC) $(CFLAGS) -std=gnu99 $(INCLUDE_PATHS) -o $(addprefix  $(OUTPATH)/, $@) $<

$(OUTPATH)/$(PROJ_NAME).elf: $(OBJS)
    $(LD) $(LDFLAGS) -T$(LINKER_SCRIPT) $(LIBPATHS) -o $@ $(addprefix $(OUTPATH)/, $^) $(LIBS) $(LD_SYS_LIBS)
    $(OBJCOPY) -O ihex $(OUTPATH)/$(PROJ_NAME).elf $(OUTPATH)/$(PROJ_NAME).hex
    $(OBJCOPY) -O binary $(OUTPATH)/$(PROJ_NAME).elf $(OUTPATH)/$(PROJ_NAME).bin
    $(OBJDUMP) -S --disassemble $(OUTPATH)/$(PROJ_NAME).elf > $(OUTPATH)/$(PROJ_NAME).dis

dir:
    $(MKDIR_P) $(OUTPATH)

clean:
    rm -f $(OUTPATH)/*.o
    rm -f $(OUTPATH)/$(PROJ_NAME).elf
    rm -f $(OUTPATH)/$(PROJ_NAME).hex
    rm -f $(OUTPATH)/$(PROJ_NAME).bin
    rm -f $(OUTPATH)/$(PROJ_NAME).dis
    rm -f $(OUTPATH)/$(PROJ_NAME).map
    # Remove the following line if you don't want to clean the Libraries as well
    $(MAKE) clean -C lib

flash:
    st-flash --reset write $(OUTPATH)/$(PROJ_NAME).bin 0x08000000

Linker 腳本:

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20020000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200;;      /* required amount of heap  */
_Min_Stack_Size = 0x400;; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 512K
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT> FLASH


  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM



  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

編輯:

我已經安裝了 cubeMX 並使用了他們生成的代碼。 然而,閃爍的 LED 仍然看不見。

這是我在 main.c 文件中的主要方法:

int main(void)
{
  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  while (1) {
    // write pin state
    // NOTE: You can in turn use HAL_GPIO_TogglePin
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
    // synchronous delay for 500 ms
    HAL_Delay(500);
  }
}

我假設生成的代碼工作正常,所以錯誤要么在我的 main.c 中,要么只是硬件問題。

您沒有切換正確的 I/O。 從 Nucleo-F411RE 用戶手冊:

用戶 LD2:綠色 LED 是連接到 Arduino 信號 D13 的用戶 LED,對應於 STM32 I/O PA5(引腳 21)或 PB13(引腳 34),具體取決於 STM32 目標。

D13 是指 Arduino 連接器 D13 引腳 - 該名稱是為了與 Arduino Shields 兼容,與 STM32 GPIO 引腳名稱無關。 在您的情況下,它是 PA5(用戶手冊中的表 16)。

您的(原始)延遲 function 存在根本缺陷。 繁忙循環延遲將根據處理器的時鍾速率、使用的編譯器甚至使用的編譯器選項而有所不同。 但更特別的是,因為從 1000 遞減不會花費明顯的時間,因此“閃爍”會太快而無法用人眼感知,甚至可能超過 LED 本身的開/關時間。

您應該改用硬件定時器或時鍾源。 所有 Cortex-M 設備都有一個 SYSCLK,默認情況下以系統時鍾頻率除以 8 運行。例如:

void delay_millisec(unsigned ms )
{
    unsigned ticks = (ms * (SystemCoreClock/ 8)) / 1000 ;

    SysTick->LOAD = ticks;
    SysTick->VAL = 0;
    SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;

    while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0);
    SysTick->CTRL = 0;
}

然后:

 while (1) 
  {
      GPIO_ToggleBits(GPIOD, GPIO_Pin_13);
      delay_millisec(500);
  }

將導致 1Hz flash 速率。

更復雜的解決方案是讓 SYSCLK ISR 以 1 毫秒的間隔增加一個滴答計數器,並讓延遲 function 計數經過的滴答間隔。 例如,默認的HAL_delay()實現就是這樣工作的。

從評論...這是匯編代碼程序的 10 行(更像是 20 行,或更多取決於您的計數)。

使用 STM32F411RE 的 NUCLEO-F411RE。

.cpu cortex-m7
.syntax unified
.thumb

stacktop: .word 0x20001000
.word reset

.thumb_func
reset:
/*
Address offset: 0x30
Reset value: 0x0000 0000
*/
    ldr r0,=0x40023830
    ldr r1,=0x00000001
    str r1,[r0]
/*
Address offset: 0x00
Reset value: 0xA800 0000 for port A
*/
    ldr r0,=0x40020000
    ldr r1,=0xA8000400
    str r1,[r0]

    add r0,#0x18
    ldr r1,=0x00000020
    ldr r2,=0x00200000

d0:
    str r1,[r0]
    mov r3,#0x00100000
d1:
    subs r3,#1
    bne d1

    str r2,[r0]
    mov r3,#0x00100000
d2:
    subs r3,#1
    bne d2

    b d0

我使用重置值而不是讀取-修改-寫入來保存一些指令/位置。

arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m7 flash.s -o flash.o
arm-none-eabi-ld -Ttext=0x08000000 flash.o -o flash.elf
arm-none-eabi-ld: warning: cannot find entry symbol _start; defaulting to 0000000008000000
arm-none-eabi-objdump -d flash.elf > flash.list
arm-none-eabi-objcopy -O binary flash.elf flash.bin

_start 沒關系可以添加兩行以使該注釋 go 消失。

flash.elf:     file format elf32-littlearm


Disassembly of section .text:

08000000 <stacktop>:
 8000000:   20001000    .word   0x20001000
 8000004:   08000009    .word   0x08000009

08000008 <reset>:
 8000008:   480b        ldr r0, [pc, #44]   ; (8000038 <d2+0x6>)
 800000a:   f04f 0101   mov.w   r1, #1
 800000e:   6001        str r1, [r0, #0]
 8000010:   480a        ldr r0, [pc, #40]   ; (800003c <d2+0xa>)
 8000012:   490b        ldr r1, [pc, #44]   ; (8000040 <d2+0xe>)
 8000014:   6001        str r1, [r0, #0]
 8000016:   f100 0018   add.w   r0, r0, #24
 800001a:   f04f 0120   mov.w   r1, #32
 800001e:   f44f 1200   mov.w   r2, #2097152    ; 0x200000

08000022 <d0>:
 8000022:   6001        str r1, [r0, #0]
 8000024:   f44f 1380   mov.w   r3, #1048576    ; 0x100000

08000028 <d1>:
 8000028:   3b01        subs    r3, #1
 800002a:   d1fd        bne.n   8000028 <d1>
 800002c:   6002        str r2, [r0, #0]
 800002e:   f44f 1380   mov.w   r3, #1048576    ; 0x100000

08000032 <d2>:
 8000032:   3b01        subs    r3, #1
 8000034:   d1fd        bne.n   8000032 <d2>
 8000036:   e7f4        b.n 8000022 <d0>
 8000038:   40023830    .word   0x40023830
 800003c:   40020000    .word   0x40020000
 8000040:   a8000400    .word   0xa8000400

將 flash.bin 復制到您的卡上,LED 應該像我的一樣閃爍。

根據文檔,LED 位於 Arduino D1 上,即 PA5 是連接 F411RE 和 F401RE NUCLEO 板的 D13 的位置。 (使用此 PCB 的其他 NUCLEO 產品上是 PB13)。 如果您只閱讀到文檔說 PB13 或 PA5,那么至少先嘗試一個,然后再嘗試另一個。 正如評論或答案中所涵蓋的那樣,您的延遲需要在 gpio state 變化之間足夠大,以便人眼看到,所以在其中放置一個合適的延遲。

mov r3,#0x00100000

更改這些 r3 行(如果它抱怨將其更改為 ldr r3,#0xwhatever_you_want)以查看下一個構建時的閃爍率變化,例如

mov r3,#0x00400000

如果這是您的第一個項目 - 不要使用 SPL(標准外設庫)。 STM 不再支持它,並且沒有用於更新的 STM32 uC 的庫。 安裝 cubeMX 並使用此工具項目生成的啟動。

在您修改后的代碼中,您需要

HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13); 而不是HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM