Не может мигать светодиод на микроконтроллере STM32F4 - PullRequest
2 голосов
/ 27 апреля 2020

Я хочу убедиться, что правильно настроил свой первый проект встроенного программного обеспечения и поэтому пытаюсь мигать светодиодом на плате NUCLEO-F411RE (микроконтроллер STM32F411RE). Я не использую никаких 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 для аппаратной абстракции фактического ядра процессора и периферийных устройств (я думаю).

Основной. c исходный файл должен содержать код для мигания светодиода на плате каждую секунду.

#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 fla sh, которая также успешно завершается. Однако ни один из светодиодов не мигает каждую секунду. У меня нет знаний, чтобы понять, в чем проблема, тем более что сообщения об ошибке нет, поэтому мне сложно отлаживать. Я чувствую, что он связан со скриптом Makefile или компоновщиком, поэтому я включу их ниже.

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

Скрипт компоновщика:

/* 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 и использовал их сгенерированный код. Однако мигающий светодиод все еще не виден.

Вот мой основной метод в основном файле. 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);
  }
}

Я предполагаю, что сгенерированный код работает правильно, поэтому ошибка либо в моей основной. c, либо просто аппаратная проблема.

Ответы [ 3 ]

3 голосов
/ 27 апреля 2020

Вы не переключаете правильный ввод / вывод. Из руководства пользователя Nucleo-F411RE:

User LD2: зеленый светодиод - это пользовательский светодиод, подключенный к сигналу D13 Arduino, соответствующему входу / выходу STM32 PA5 (контакт 21) или PB13 (контакт 34), в зависимости от на цели STM32.

D13 heare относится к выводу D13 разъема Arduino - имя для совместимости с Arduino Shields и не связано с именем контакта GPIO STM32. В вашем случае это PA5 (Таблица 16 в руководстве пользователя).

Ваша (оригинальная) функция задержки в корне ошибочна. Задержка занятости l oop будет варьироваться в зависимости от тактовой частоты процессора, используемого компилятора и даже используемых опций компилятора. Но в особенности потому, что уменьшение 1000 формы не займет заметного промежутка времени, так что «мигание» будет слишком быстрым для восприятия человеческим глазом и, возможно, даже превысит время включения / выключения самого светодиода.

Вместо этого следует использовать аппаратный таймер или источник синхронизации. Все устройства 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);
  }

Результатом будет 1 Гц fla sh rate.

Более сложное решение заключается в том, чтобы SYSCLK ISR увеличивал счетчик тиков с интервалами в 1 мс, а функция задержки считала истекшие интервалы между тиками. Вот как работает реализация HAL_delay() по умолчанию, например.

2 голосов
/ 28 апреля 2020

Из комментариев ... это 10 строк (больше, например, 20 или больше, зависит от того, как вы считаете) программы сборки кода.

NUCLEO-F411RE, которая использует STM32F411RE.

.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

скопируйте fla sh .bin на вашу карту, и светодиод должен мигать, как на моей.

В соответствии с документацией, которую вы должны были прочитать в первую очередь. Индикатор на Arduino D1, то есть PA5, где D13 подключен для плат F411RE и F401RE NUCLEO. (Это PB13 на других продуктах NUCLEO, которые используют эту печатную плату). Если вы прочитали только то, что в do c указано PB13 или PA5, то, по крайней мере, попробуйте одно, затем другое. И, как указано в комментариях или ответах, ваша задержка должна быть достаточно большой между изменениями состояния gpio, чтобы человеческий глаз мог ее видеть, поэтому поместите туда задержку хорошего размера.

mov r3,#0x00100000

Изменение этих строк r3 (если оно жалуется, измените его на ldr r3, # 0xwhwhat_you_want), чтобы увидеть изменение частоты миганий при следующей сборке, например

mov r3,#0x00400000
0 голосов
/ 27 апреля 2020

Если это ваш первый проект - не используйте SPL (Стандартная периферийная библиотека). Он больше не поддерживается STM и нет библиотек для более новых STM32 UC. Установите cubeMX и используйте автозагрузку, сгенерированную этим инструментом для проектов.

В вашем исправленном коде вам нужно

HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13); вместо HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);

...