【发布时间】:2017-12-11 21:51:55
【问题描述】:
我是 STM32 的新手,不是嵌入式开发的新手(有 PIC、dsPIC、MSP430 的经验)。
环境
- CooCox CoIDE
- arm-none-eabi-gcc
- ST-LINK V2(与 Segger J-Link 相同)通过 SWD
问题描述
我正在尝试使用直接寄存器操作编写一个基本库(STMCube HAL 很酷,但我发现无论如何我都必须阅读数据表,因此首选寄存器操作)。本质上,我只是想让Blue Pill 开发板上的一个LED 闪烁,它是引脚C13。
我可以编译、刷写和调试,但是当我调试时,LED 不闪烁,寄存器也没有变化。寄存器值本身实际上并没有那么重要,因此您不需要出去查看数据表。我只需要能够操纵它们!
单步调试调试器工作正常,variables 监视窗口也适当更新。
我尝试过的事情
虽然这并不详尽(已经过了几个小时,所以我可能忘了包括一些),但这些是我尝试过的一些事情:
- 更改
BOOTx引脚配置 - 更改调试器配置(减速、加速、重置策略)。
- 将调试器更改为 SEGGER J-Link
- 锁定/解锁 GPIO 引脚
所有人都有相同的结果。我怀疑我可能缺少 CMSIS 中的某些内容或必要的包含文件,但我似乎找不到它。
我可能遗漏的另一点涉及振荡器设置。据我了解,启动时有一个默认配置,除非我想更改它,否则我不必担心。也许这是有缺陷的?
编辑:适用于 STM32CubeMX HAL
当我尝试使用 STM32CUBEMX HAL 进行基本切换时,它可以工作。这让我觉得我在包含、项目设置、振荡器设置...中缺少一些基本的东西?
代码
main.c
#include "gpio.h"
#define LED_PIN 13
int main(void)
{
uint32_t i;
// initialize the peripherals
GPIO_init();
GPIOC_setupOutput(LED_PIN, PUSH_PULL, PIN_SPEED_50MHz);
while(1)
{
GPIOC_setPin(LED_PIN);
for(i=0; i<4000000; i++);
GPIOC_clearPin(LED_PIN);
for(i=0; i<4000000; i++);
}
}
gpio.h
#ifndef _GPIO_H
#define _GPIO_H
#include <stdint.h>
#include <stdbool.h>
typedef enum{
ANALOG=0b00, FLOATING=0b01, PULL_UP_PULL_DOWN=0b10
}InputPinMode;
typedef enum{
PUSH_PULL=0b00, OPEN_DRAIN=0b01, AF_PUSH_PULL=0b10, AF_OPEN_DRAIN=0b11
}OutputPinMode;
typedef enum{
PIN_SPEED_2MHz=0b10, PIN_SPEED_10MHz=0b01, PIN_SPEED_50MHz=0b11
}PinSpeed;
void GPIO_init(void);
void GPIOA_setupInput(uint8_t pinNumber, InputPinMode mode);
void GPIOC_setupInput(uint8_t pinNumber, InputPinMode mode);
void GPIOA_setupOutput(uint8_t pinNumber, OutputPinMode mode, PinSpeed speed);
void GPIOC_setupOutput(uint8_t pinNumber, OutputPinMode mode, PinSpeed speed);
bool GPIOA_readPin(uint8_t pinNumber);
void GPIOA_setPin(uint8_t pinNumber);
void GPIOC_setPin(uint8_t pinNumber);
void GPIOA_clearPin(uint8_t pinNumber);
void GPIOC_clearPin(uint8_t pinNumber);
#endif
gpio.c
#include "stm32f1xx.h"
#include "gpio.h"
/**
* @brief Initialize GPIO
*/
void GPIO_init(void){
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPDEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPEEN;
}
/**
* @brief Setup pin as an input
* @param pinNumber the pin number
* @param mode the input mode
*/
void GPIOA_setupInput(uint8_t pinNumber, InputPinMode mode){
uint32_t pinNumberLocation, regValue;
if(pinNumber < 8){
pinNumberLocation = pinNumber << 2; // bit location
regValue = (mode << 2) << pinNumberLocation;
GPIOA->CRL &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOA->CRL = regValue;
}else{
pinNumberLocation = (pinNumber - 8) << 2; // bit location
regValue = (mode << 2) << pinNumberLocation;
GPIOA->CRH &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOA->CRH = regValue;
}
}
/**
* @brief Setup port A pin as an output
* @brief pinNumber the pin number
* @brief mode the output mode
* @brief speed the pin speed (lower results in less noise)
*/
void GPIOA_setupOutput(uint8_t pinNumber, OutputPinMode mode, PinSpeed speed){
uint32_t pinNumberLocation, regValue;
if(pinNumber < 8){
pinNumberLocation = pinNumber << 2; // bit location
regValue = ((mode << 2) << pinNumberLocation) + speed;
GPIOA->CRL &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOA->CRL |= regValue;
}else{
pinNumberLocation = (pinNumber - 8) << 2; // bit location
regValue = ((mode << 2) << pinNumberLocation) + speed;
GPIOA->CRH &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOA->CRH |= regValue;
}
}
/**
* @brief Setup port C pin as an output
* @brief pinNumber the pin number
* @brief mode the output mode
* @brief speed the pin speed (lower results in less noise)
*/
void GPIOC_setupOutput(uint8_t pinNumber, OutputPinMode mode, PinSpeed speed){
uint32_t pinNumberLocation, regValue;
if(pinNumber < 8){
pinNumberLocation = pinNumber << 2; // bit location
regValue = ((mode << 2) << pinNumberLocation) + speed;
GPIOC->CRL &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOC->CRL |= regValue;
}else{
pinNumberLocation = (pinNumber - 8) << 2; // bit location
regValue = ((mode << 2) << pinNumberLocation) + speed;
GPIOC->CRH &= ~(0b1111 << pinNumberLocation); // clear the register
GPIOC->CRH |= regValue;
}
}
bool GPIOA_readPin(uint8_t pinNumber){
uint16_t mask = 1 << pinNumber;
if(GPIOA->IDR & mask)
return true;
else
return false;
}
void GPIOA_setPin(uint8_t pinNumber){ GPIOA->BSRR = (1 << pinNumber);}
void GPIOC_setPin(uint8_t pinNumber){ GPIOC->BSRR = (1 << pinNumber);}
void GPIOA_clearPin(uint8_t pinNumber){ GPIOA->BSRR = ~(1 << (pinNumber + 16));}
void GPIOC_clearPin(uint8_t pinNumber){ GPIOC->BSRR = ~(1 << (pinNumber + 16));}
【问题讨论】:
-
GPIOA->CRL = GPIOB->CRL = GPIOC->CRL = GPIOD->CRL = GPIOE->CRL = crl; …- 这是一个非常糟糕的主意,甚至会损坏您的硬件。.c也不是头文件,它们不仅仅是声明,而是定义(也不应该在头文件中,inline函数除外。 -
@olaf 我意识到
*.c不是头文件。为了简洁起见,我只是没有将头文件放在这里。我将编辑添加。另外,为什么设置所有GPIOx->CRL和GPIOx->CRH是个坏主意?参考手册简单地说明它将所有引脚置于模拟输入模式。 -
您应该获得更好的手册并将 GPIO 设置为外部硬件期望的状态。
-
@Olaf 我目前没有关联的外部硬件。我正在学习该设备。感谢您花时间教育我,但我仍然没有看到这个问题。在启动时将所有 GPIO 初始化为已知输入状态对我来说似乎没有争议,而且坦率地说,这甚至不是一个紧迫的问题,因为寄存器写入根本不起作用。你看到上面有什么不允许我写寄存器吗?
-
我想知道你用那个设备做什么。没有 JTAG,没有 LED,没有按钮,没有晶体,什么都没有。如果你有一块死砖,你为什么还要写代码?