启用外部中断 ARM Cortex-M0+ (STM32G070)

Posted

技术标签:

【中文标题】启用外部中断 ARM Cortex-M0+ (STM32G070)【英文标题】:Enable external interrupts ARM Cortex-M0+ (STM32G070) 【发布时间】:2020-12-24 00:37:07 【问题描述】:

我正在尝试对 STM32 微控制器的编程有一个基本的了解。我正在尝试使用按钮的外部中断来切换 LED 的状态,方法是设置所有适当的寄存器(没有外部库/定义)。我似乎无法让中断例程工作,控制永远不会传递给处理程序。

这是我用来将 PC-13(根据 Nucleo-G070RB 板连接了一个按钮)设置为外部中断的方法:

RCC_APBENR2  |= 0b1 <<  0; // Enable SYSCFGEN
RCC_IOPENR   |= 0b1 <<  2; // Enable PORTC
EXTI_RTSR1   |= 0b1 << 13; // Enable interrupt on rising edge at EXTI line 13
EXTI_EXTICR4 |= 0x2 <<  8; // Set PC-13 as GPIO pin for interrupt
EXTI_IMR1    |= 0x1 << 13; // Unmask EXTI line 13

NVIC_ISER    |= 0b1 <<  7; // Enable interrupts for EXTI4_15

我不确定我错过了什么。

这是完整的代码:

#include <stdint.h>
#include <stdio.h>

#define RCC_IOPENR   *((uint32_t volatile *) 0x40021034)
#define RCC_APBENR2  *((uint32_t volatile *) 0x40021040)

#define GPIOA_MODER  *((uint32_t volatile *) 0x50000000)
#define GPIOA_IDR    *((uint32_t volatile *) 0x50000010)
#define GPIOA_ODR    *((uint32_t volatile *) 0x50000014)

#define GPIOC_MODER  *((uint32_t volatile *) 0x50000800)
#define GPIOC_IDR    *((uint32_t volatile *) 0x50000810)
#define GPIOC_ODR    *((uint32_t volatile *) 0x50000814)

#define NVIC_ISER    *((uint32_t volatile *) 0xE000E100)

#define EXTI_RTSR1   *((uint32_t volatile *) 0x40021800)
#define EXTI_EXTICR1 *((uint32_t volatile *) (0x40021800 + 0x060 + 0x4 * 0))
#define EXTI_EXTICR2 *((uint32_t volatile *) (0x40021800 + 0x060 + 0x4 * 1))
#define EXTI_EXTICR3 *((uint32_t volatile *) (0x40021800 + 0x060 + 0x4 * 2))
#define EXTI_EXTICR4 *((uint32_t volatile *) (0x40021800 + 0x060 + 0x4 * 3))
#define EXTI_IMR1    *((uint32_t volatile *) (0x40021800 + 0x080))
#define EXTI_RPR1    *((uint32_t volatile *) (0x40021800 + 0x00C))

void button_init();
extern void initialise_monitor_handles();

uint8_t volatile g_button_pressed = 0;

int main(void) 
    //asm volatile ("cpsie i");
    initialise_monitor_handles();

    //printf("Hello World!\n");

    RCC_IOPENR  |= 0b1 << 0;         // Enable PORTA
    GPIOA_MODER &= ~(0b11 << (2*5)); // Clear MODE bits for 5th pin (PA-5)
    GPIOA_MODER |= 0b1 << (2*5);     // Set MODE bits for 5th pin (PA-5) to 01 (set output)
    GPIOC_MODER &= ~(0b11 << (2*13)); // Clear MODE bits for 13th pin (PC-13) (set input)

    button_init();

    while(1) 
        if (g_button_pressed) 
            GPIOA_ODR ^= 0b1 << 5;
            printf("Button pressed\n");
            g_button_pressed = 0;
        
    


void button_init() 
    RCC_APBENR2  |= 0b1 <<  0; // Enable SYSCFGEN
    RCC_IOPENR   |= 0b1 <<  2; // Enable PORTC
    EXTI_RTSR1   |= 0b1 << 13; // Enable interrupt on rising edge at EXTI line 13
    EXTI_EXTICR4 |= 0x2 <<  8; // Set PC-13 as GPIO pin for interrupt
    EXTI_IMR1    |= 0x1 << 13; // Unmask EXTI line 13

    NVIC_ISER    |= 0b1 <<  7; // Enable interrupts for EXTI4_15


void EXTI4_15_IRQHandler(void) 
    g_button_pressed = 1;
    printf("Button pressed\n");
    EXTI_RPR1 |= 0xFFFF << 0;

我正在使用带有默认编译器的 STM32CubeIDE,并使用 OpenOCD 通过半主机进行打印。

所以,我的问题是,我是错过了一步还是做错了什么?

【问题讨论】:

external 应该是最难的之一,您是否首先尝试了 systick 计时器,这是不通过 nvic 的东西? swi/svc 处理程序。然后说一个在内核外部但不在芯片之外的定时器中断?了解基础知识,然后将其提升到外部引脚? 与任何中断处理程序开发一样,您是否进行了轮询?从外围开始,朝着核心方向努力?一路了解中断状态和清除中断?一次一层? 加载到中断向量表中的中断处理程序的地址在哪里? 不要重新发明***并使用 CMSIS stm32 标头。那里已经定义了所有寄存器。 @P__J__ ,我在哪里可以找到 CMSIS STM32 标头?我刚刚从 STM32CubeMX 生成的项目中复制了它们 - 有没有更好的地方来获取它们? 【参考方案1】:

所以,我弄清楚了我的愚蠢错误是什么。我非常专注于试图了解我在设置外部中断时出错的地方,我并没有真正检查我是否正确设置了按钮。

我尝试将 PC13 设置为输入:

GPIOC_MODER &= ~(0b11 << (2*13)); // Clear MODE bits for 13th pin (PC-13) (set input)

在我调用 button_init() 函数之前,该函数通过以下方式启用 GPIOC 的时钟:

RCC_IOPENR   |= 0b1 <<  2; // Enable PORTC

由于没有启用 GPIOC,PC13 也没有设置为输入,所以没有检测到。

这是固定代码:(我还更新了它以使用 CMSIS stm32 标头,正如 P__J__ 所建议的那样)

#define STM32G070xx
#include "stm32g0xx.h"

uint8_t volatile g_button_pressed = 0;

void button_init();
//extern void initialise_monitor_handles();

int main(void) 
//  initialise_monitor_handles();

    //printf("Hello World!\n");
    RCC->IOPENR  |= 0b1 << 0;         // Enable PORTA
    GPIOA->MODER &= ~(0b11 << (2*5)); // Clear MODE bits for 5th pin (PA-5)
    GPIOA->MODER |= 0b1 << (2*5);     // Set MODE bits for 5th pin (PA-5) to 01 (set output)

    button_init();

    while(1) 
        if (g_button_pressed) 
            GPIOA->ODR ^= 0b1 << 5;
//          printf("Button pressed! Yay!\n");
            g_button_pressed = 0;
        
    


void button_init() 
    // RCC->APBENR2    |= (uint32_t) (0b1 <<  0); // Enable SYSCFGEN
    RCC->IOPENR     |= (uint32_t) (0b1 <<  2); // Enable PORTC
    GPIOC->MODER    &= ~(0b11 << (2*13));      // Clear MODE bits for 13th pin (PC-13) (set input)

    EXTI->RTSR1     |= (uint32_t) (0b1 << 13); // Enable interrupt on rising edge at EXTI line 13
    EXTI->EXTICR[3] |= (uint32_t) (0x2 <<  8); // Set PC-13 as GPIO pin for interrupt
    EXTI->IMR1      |= (uint32_t) (0x1 << 13); // Unmask EXTI line 13

    NVIC->ISER[0]   |= (uint32_t) (0b1 <<  7); // Enable interrupts for EXTI4_15


void EXTI4_15_IRQHandler(void) 
    g_button_pressed = 1;
//  printf("Button pressed\n");
    EXTI->RPR1 = 0b1 << 13;

【讨论】:

以上是关于启用外部中断 ARM Cortex-M0+ (STM32G070)的主要内容,如果未能解决你的问题,请参考以下文章

STM32中EXTI和NVIC的关系

ARM Cortex-M3 MCU的I2C&DMA操作被频繁的中断打挂了

单片机或ARM外部晶振最大值由啥因素决定的?比如说Freescale Kinetis Cortex-M0+外部晶振貌似只有8M

arm 学习选Cortex-M3还是arm9?

有关于ARM cortex-M0的,跪求知道用啥编程软件编程的。希望可以给个程序例子。谢谢

Arm Cortex-M4 LDRD 指令导致硬故障