我一直在遵循本指南,https://github.com/cpq/bare-metal-programming-guide,开始使用 STM32 MCU 进行编程,而不使用 CubeMX,只是为了了解更多信息。我已经能够运行这些示例并让它们在我的核板上运行。现在我在使用 CMSIS 库时遇到了一个问题,我似乎无法查明该问题。我能够正确地刷新电路板,没有错误,但是,我无法打开 LED。我浏览了该库并将其与我的其他项目进行了比较,以确保寄存器的地址是正确的,而且它们是正确的。
以下代码是我的main.c:
#include "mcu.h"
static volatile uint32_t s_ticks;
void SysTick_Handler(void) {
s_ticks++;
}
uint32_t SystemCoreClock = FREQ;
void SystemInit(void) {
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // Enable SYSCFG
SysTick_Config(SystemCoreClock / 1000); // Tick every 1 ms
}
int main(void) {
uint16_t led = PIN('A', 5); // Blue LED
gpio_set_mode(led, GPIO_MODE_OUTPUT); // Set blue LED to output mode
volatile uint32_t timer = 0, period = 500; // Declare timers
for (;;) {
if (timer_expired(&timer, period, s_ticks)) {
static bool on; // This block is executed
gpio_write(led, on); // Every `period` milliseconds
on = !on; // Toggle LED state
}
}
return 0;
}
我已经在我的其他项目中对此进行了测试,这些项目没有使用 CMSIS 文件,并且它有效。 接下来是我的 mcu.h 标头:
#pragma once
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "stm32f401xe.h"
#define FREQ 16000000 // CPU frequency, 16 Mhz
#define BIT(x) (1UL << (x))
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
#define PINNO(pin) (pin & 255)
#define PINBANK(pin) (pin >> 8)
static inline void spin(volatile uint32_t count) {
while (count--) asm("nop");
}
#define GPIO(bank) ((GPIO_TypeDef *) (GPIOA_BASE + 0x400U * (bank)))
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };
static inline void gpio_set_mode(uint16_t pin, uint8_t mode) {
GPIO_TypeDef *gpio = GPIO(PINBANK(pin)); // GPIO bank
int n = PINNO(pin); // Pin number
RCC->AHB1ENR |= BIT(PINBANK(pin)); // Enable GPIO clock
gpio->MODER &= ~(3U << (n * 2)); // Clear existing setting
gpio->MODER |= (mode & 3U) << (n * 2); // Set new mode
}
static inline void gpio_set_af(uint16_t pin, uint8_t af_num) {
GPIO_TypeDef *gpio = GPIO(PINBANK(pin)); // GPIO bank
int n = PINNO(pin); // Pin number
gpio->AFR[n >> 3] &= ~(15UL << ((n & 7) * 4));
gpio->AFR[n >> 3] |= ((uint32_t) af_num) << ((n & 7) * 4);
}
static inline void gpio_write(uint16_t pin, bool val) {
GPIO_TypeDef *gpio = GPIO(PINBANK(pin));
gpio->BSRR = (1U << PINNO(pin)) << (val ? 0 : 16);
}
static inline bool timer_expired(volatile uint32_t *t, uint32_t prd,
uint32_t now) {
if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
if (*t == 0) *t = now + prd; // Firt poll? Set expiration
if (*t > now) return false; // Not expired yet, return
*t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time
return true; // Expired, return true
}
这里的功能也与我的其他项目非常相似,唯一的区别是使用 GPIO_TypeDef 而不是以前使用的 gpio 结构体。
最后一个文件是我的Makefile:
CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion \
-Wformat-truncation -fno-common -Wconversion \
-g3 -Os -ffunction-sections -fdata-sections \
-I. -Iinclude -Icmsis_core/CMSIS/Core/Include -Icmsis_f4/Include \
-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 $(EXTRA_CFLAGS)
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,[email protected]
SOURCES = main.c syscalls.c
SOURCES += cmsis_f4/Source/Templates/gcc/startup_stm32f401xe.s
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F
else
RM = rm -rf
endif
build: firmware.bin
firmware.elf: cmsis_core cmsis_f4 mcu.h link.ld Makefile $(SOURCES)
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@
flash: firmware.bin
st-flash --reset write $< 0x8000000
cmsis_core:
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
cmsis_f4:
git clone --depth 1 -b v2.6.9 https://github.com/STMicroelectronics/cmsis_device_f4 $@
clean:
$(RM) firmware.* cmsis_*
我还有一个startup.c和链接器文件,如下:
#include <sys/stat.h>
#include "mcu.h"
int _fstat(int fd, struct stat *st) {
if (fd < 0) return -1;
st->st_mode = S_IFCHR;
return 0;
}
void *_sbrk(int incr) {
extern char _end;
static unsigned char *heap = NULL;
unsigned char *prev_heap;
if (heap == NULL) heap = (unsigned char *) &_end;
prev_heap = heap;
heap += incr;
return prev_heap;
}
int _open(const char *path) {
(void) path;
return -1;
}
int _close(int fd) {
(void) fd;
return -1;
}
int _isatty(int fd) {
(void) fd;
return 1;
}
int _lseek(int fd, int ptr, int dir) {
(void) fd, (void) ptr, (void) dir;
return 0;
}
void _exit(int status) {
(void) status;
for (;;) asm volatile("BKPT #0");
}
void _kill(int pid, int sig) {
(void) pid, (void) sig;
}
int _getpid(void) {
return -1;
}
int _read(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
int _link(const char *a, const char *b) {
(void) a, (void) b;
return -1;
}
int _unlink(const char *a) {
(void) a;
return -1;
}
int _stat(const char *path, struct stat *st) {
(void) path, (void) st;
return -1;
}
int mkdir(const char *path, mode_t mode) {
(void) path, (void) mode;
return -1;
}
void _init(void) {
}
ENTRY(Reset_Handler);
MEMORY {
flash(rx) : ORIGIN = 0x08000000, LENGTH = 512k
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 96k
}
_estack = ORIGIN(sram) + LENGTH(sram);
SECTIONS {
.vectors : { KEEP(*(.vectors)) } > flash
.text : { *(.text*) } > flash
.rodata : { *(.rodata*) } > flash
.data : {
_sdata = .;
*(.first_data)
*(.data SORT(.data.*))
_edata = .;
} > sram AT > flash
_sidata = LOADADDR(.data);
.bss : {
_sbss = .;
*(.bss SORT(.bss.*) COMMON)
_ebss = .;
} > sram
. = ALIGN(8);
_end = .;
}
这些文件与我的其他项目大部分没有变化。唯一的不同是添加了 Reset_Handler,因为它也来自 CMSIS 库。
我一定在某个地方犯了一个错误,因为供应商库已经过尝试并且是真实的,但我似乎无法找到它。预先感谢您的阅读!
你尝试过
gpio_write(led, off);
吗?