【问题标题】:STM32 || Unable to initialise interrupts || Nucleo - F746ZGSTM32 ||无法初始化中断 ||核 - F746ZG
【发布时间】:2022-06-20 13:47:44
【问题描述】:

我是 STM32 MCU 世界的新手,所以请多多包涵。

我正在关注 Udemy 上的教程并尝试从头开始编写 GPIO 中断代码。我已经完成了所有的寄存器配置,并且配置工作正常,正如在调试模式下通过 SFR 视图看到的那样,但是当我运行代码时,似乎没有启用中断。 代码永远不会出现在处理函数中。

            /*
             * 003button_interrupt.c
             */
            
            #include <string.h>
            #include "stm32f746xx.h"
            
            void delay(void){
                for(uint32_t i=0; i<100000; i++);
            }
            
            int main(){
            
                GPIO_PeriClockControl(GPIOC,ENABLE);
                GPIO_PeriClockControl(GPIOB,ENABLE);
            
                GPIO_Handle_t LED, BTN;
                memset(&LED, 0, sizeof(LED));
                memset(&BTN, 0, sizeof(BTN));
            
                LED.pGPIOx = GPIOB;
                LED.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_NO_14;
                LED.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_OUT;
                LED.GPIO_PinConfig.GPIO_PinOPType = GPIO_OP_TYPE_PP;
                LED.GPIO_PinConfig.GPIO_PinSpeed = GPIO_SPEED_VERY_HIGH;
                LED.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_NO_PUPD;
            
                GPIO_Init(&LED);
            
                LED.pGPIOx = GPIOB;
                LED.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_NO_7;
                LED.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_OUT;
                LED.GPIO_PinConfig.GPIO_PinOPType = GPIO_OP_TYPE_PP;
                LED.GPIO_PinConfig.GPIO_PinSpeed = GPIO_SPEED_VERY_HIGH;
                LED.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_NO_PUPD;
            
                GPIO_Init(&LED);
            
                BTN.pGPIOx = GPIOC;
                BTN.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_NO_13;
                BTN.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_IT_FT;
                BTN.GPIO_PinConfig.GPIO_PinSpeed = GPIO_SPEED_VERY_HIGH;
                BTN.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_PIN_PU;
            
                GPIO_Init(&BTN);
            
                //IRQ interrupt and priority configuration
                GPIO_IRQPriorityConfig(IRQ_NO_EXTI10_15,NVIC_IRQ_PRIO_15);
                GPIO_IRQIntConfig(IRQ_NO_EXTI10_15,ENABLE);
            
                while(1);
            }
            
            void EXTI15_10_IRQHandler(void){
                delay();
                GPIO_IRQHandling(GPIO_PIN_NO_13);
                GPIO_ToggleOutputPin(GPIOB,GPIO_PIN_NO_14);
                GPIO_ToggleOutputPin(GPIOB,GPIO_PIN_NO_7);
            }

            /*
             * stm32f746xx_gpio_driver.c
             */
            
            #include "stm32f746xx_gpio_driver.h"
            
            /*
             * peripheral clock setup
             */
            void GPIO_PeriClockControl(GPIO_RegDef_t *pGPIOx, uint8_t EnOrDis){
                if(EnOrDis == ENABLE){
                    if(pGPIOx == GPIOA){
                        GPIOA_PCLK_EN();
                    }else if(pGPIOx == GPIOB){
                        GPIOB_PCLK_EN();
                    }else if(pGPIOx == GPIOC){
                        GPIOC_PCLK_EN();
                    }else if(pGPIOx == GPIOD){
                        GPIOD_PCLK_EN();
                    }else if(pGPIOx == GPIOE){
                        GPIOE_PCLK_EN();
                    }else if(pGPIOx == GPIOF){
                        GPIOF_PCLK_EN();
                    }else if(pGPIOx == GPIOG){
                        GPIOG_PCLK_EN();
                    }else if(pGPIOx == GPIOH){
                        GPIOH_PCLK_EN();
                    }else if(pGPIOx == GPIOI){
                        GPIOI_PCLK_EN();
                    }else if(pGPIOx == GPIOJ){
                        GPIOJ_PCLK_EN();
                    }else if(pGPIOx == GPIOK){
                        GPIOK_PCLK_EN();
                    }
                } else {
                    if(pGPIOx == GPIOA){
                        GPIOA_PCLK_DIS();
                    }else if(pGPIOx == GPIOB){
                        GPIOB_PCLK_DIS();
                    }else if(pGPIOx == GPIOC){
                        GPIOC_PCLK_DIS();
                    }else if(pGPIOx == GPIOD){
                        GPIOD_PCLK_DIS();
                    }else if(pGPIOx == GPIOE){
                        GPIOE_PCLK_DIS();
                    }else if(pGPIOx == GPIOF){
                        GPIOF_PCLK_DIS();
                    }else if(pGPIOx == GPIOG){
                        GPIOG_PCLK_DIS();
                    }else if(pGPIOx == GPIOH){
                        GPIOH_PCLK_DIS();
                    }else if(pGPIOx == GPIOI){
                        GPIOI_PCLK_DIS();
                    }else if(pGPIOx == GPIOJ){
                        GPIOJ_PCLK_DIS();
                    }else if(pGPIOx == GPIOK){
                        GPIOK_PCLK_DIS();
                    }
                }
            }
            
            /*
             * init and deInit
             */
            void GPIO_Init(GPIO_Handle_t *pGPIOHandle){
                uint32_t temp = 0;
                if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode <= GPIO_MODE_ANALOG){
                    temp = (pGPIOHandle->GPIO_PinConfig.GPIO_PinMode << (2* pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
                    pGPIOHandle->pGPIOx->MODER &= ~(0x03 << pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber); // clearing ; always clear before setting
                    pGPIOHandle->pGPIOx->MODER |= temp; // setting
                } else {
            
                    // 1. configure RTSR / FTSR
                    if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode == GPIO_MODE_IT_FT){
                        (*EXTI).FTSR |= (1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
                        (*EXTI).RTSR &= ~(1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber); // coz we only want FT, clear the corresponding RTSR bit; just to be safe if it is not already cleared for some reason
                    } else if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode == GPIO_MODE_IT_RT){
                        (*EXTI).RTSR |= (1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
                        (*EXTI).FTSR &= ~(1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
                    } else if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode == GPIO_MODE_IT_RFT){
                        (*EXTI).RTSR |= (1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
                        (*EXTI).FTSR |= (1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
                    }
            
                    // 2. config the gpio port selection in SYSCFG_EXTICR
                    uint8_t temp1 = pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber / 4;
                    uint8_t temp2 = pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber % 4;
                    uint8_t portcode = GPIO_BASEADDR_TO_CODE(pGPIOHandle->pGPIOx);
                    SYSCFG_PCLK_EN();
                    (*SYSCFG).EXTICR[temp1] = portcode << (temp2 * 4);
            
                    // 3. enable the exti interrupt delivery using IMR
                    (*EXTI).IMR |= (1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
                }
                temp = 0;
            
                temp = (pGPIOHandle->GPIO_PinConfig.GPIO_PinSpeed << (2* pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
                pGPIOHandle->pGPIOx->OSPEEDR &= ~(0x03 << pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber); // clearing
                pGPIOHandle->pGPIOx->OSPEEDR |= temp; // setting
                temp = 0;
            
                temp = (pGPIOHandle->GPIO_PinConfig.GPIO_PinPuPdControl << (2* pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
                pGPIOHandle->pGPIOx->PUPDR &= ~(0x03 << pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber); // clearing
                pGPIOHandle->pGPIOx->PUPDR |= temp; // setting
                temp = 0;
            
                temp = (pGPIOHandle->GPIO_PinConfig.GPIO_PinOPType << (pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
                pGPIOHandle->pGPIOx->OTYPER &= ~(0x01 << pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber); // clearing
                pGPIOHandle->pGPIOx->OTYPER |= temp; // setting
                temp = 0;
            
                if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode == GPIO_MODE_ALTFN){
                    uint8_t temp1 = pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber / 8;
                    uint8_t temp2 = pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber % 8;
                    pGPIOHandle->pGPIOx->AFR[temp1] &= ~(0x0f << (4* temp2)); // clearing
                    pGPIOHandle->pGPIOx->AFR[temp1] |= pGPIOHandle->GPIO_PinConfig.GPIO_PinAltFunMode << (4* temp2); // setting
                }
            }
            
            void GPIO_DeInit (GPIO_RegDef_t *pGPIOx){
                if(pGPIOx == GPIOA){
                    GPIOA_REG_RESET();
                }else if(pGPIOx == GPIOB){
                    GPIOB_REG_RESET();
                }else if(pGPIOx == GPIOC){
                    GPIOC_REG_RESET();
                }else if(pGPIOx == GPIOD){
                    GPIOD_REG_RESET();
                }else if(pGPIOx == GPIOE){
                    GPIOE_REG_RESET();
                }else if(pGPIOx == GPIOF){
                    GPIOF_REG_RESET();
                }else if(pGPIOx == GPIOG){
                    GPIOG_REG_RESET();
                }else if(pGPIOx == GPIOH){
                    GPIOH_REG_RESET();
                }else if(pGPIOx == GPIOI){
                    GPIOI_REG_RESET();
                }else if(pGPIOx == GPIOJ){
                    GPIOJ_REG_RESET();
                }else if(pGPIOx == GPIOK){
                    GPIOK_REG_RESET();
                }
            }
            
            
            /*
             * data read and write
             */
            uint8_t GPIO_ReadFromInputPin(GPIO_RegDef_t *pGPIOx, uint8_t PinNumber){
                uint8_t value;
                value = (uint8_t)((pGPIOx->IDR >> PinNumber) & 0x00000001);
                return value;
            }
            
            uint16_t GPIO_ReadFromInputPort(GPIO_RegDef_t *pGPIOx){
                uint16_t value;
                value = pGPIOx->IDR;
                return value;
            }
            
            void GPIO_WriteToOutputPin(GPIO_RegDef_t *pGPIOx, uint8_t PinNumber, uint8_t value){
                if(value == GPIO_PIN_SET){
                    pGPIOx->ODR |= (1 << PinNumber);
                } else if(value == GPIO_PIN_CLEAR || value == GPIO_PIN_RESET){
                    pGPIOx->ODR &= ~(1 << PinNumber);
                }
            }
            
            void GPIO_WriteToOutputPort(GPIO_RegDef_t *pGPIOx, uint16_t value){
                pGPIOx->ODR = value;
            }
            
            void GPIO_ToggleOutputPin(GPIO_RegDef_t *pGPIOx, uint8_t PinNumber){
                pGPIOx->ODR ^= (1 << PinNumber);
            }
            
            /*
             * IRQ configuration and ISR handling
             */
            
            // IRQConfig is for config in processor side
            void GPIO_IRQIntConfig(uint16_t IRQNumber, uint8_t EnOrDis){
                if(EnOrDis == ENABLE){
            //      *(NVIC_ISER0 + (((uint32_t)(int32_t)IRQNumber) >> 5UL)) = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQNumber) & 0x1FUL));
                    if(IRQNumber <= 31){
                        (*NVIC_ISER0) |= (1<<IRQNumber);
                    } else if((IRQNumber > 31) && (IRQNumber <= 63)){
                         (*NVIC_ISER1) |= (1<<(IRQNumber%32));
                    } else if((IRQNumber > 63) && (IRQNumber <= 95)){
                        (*NVIC_ISER2) |= (1<<(IRQNumber%64));
                    } else if(IRQNumber > 95){
                        (*NVIC_ISER3) |= (1<<(IRQNumber%96));
                    }
                } else if (EnOrDis == DISABLE){
                    if(IRQNumber <= 31){
                        (*NVIC_ICER0) |= (1<<IRQNumber);
                    } else if((IRQNumber > 31) && (IRQNumber <= 63)){
                        (*NVIC_ICER1) |= (1<<(IRQNumber%32));
                    } else if((IRQNumber > 63) && (IRQNumber <= 95)){
                        (*NVIC_ICER2) |= (1<<(IRQNumber%64));
                    } else if(IRQNumber > 95){
                        (*NVIC_ICER3) |= (1<<(IRQNumber%96));
                    }
                }
            }
            
            void GPIO_IRQPriorityConfig(uint16_t IRQNumber, uint16_t IRQPriority){
                // 1. find the ipr register and section
                uint32_t iprx = IRQNumber / 4;
                uint32_t iprx_section = IRQNumber % 4;
            
                // 2. store the value
                uint8_t shift_value = (8*iprx_section) + (8-NO_IPR_BITS_IMPLEMENTED); // need to move more by (8-NO_IPR_BITS_IMPLEMENTED) bits, since not all of 8 bits are used..
                uint16_t temp = (IRQPriority << shift_value);
                *(NVIC_IPR_BASEADDR + iprx) |= temp; // iprx is multiplied by 4 because each address jump is of 4 bytes..
            }
            
            void GPIO_IRQHandling(uint8_t PinNumber){
                // clear the exti pr register bit corresponding to the pin number
                if((*EXTI).PR & (1<<PinNumber)){
                    (*EXTI).PR |= ( 1 << PinNumber );
                }
            }

请帮我找出问题所在。 谢谢!

【问题讨论】:

  • 您能指出您使用的是什么IDE吗? CubeIDE?

标签: driver stm32 interrupt gpio stm32f7


【解决方案1】:

代码几乎不可读。它为初学者使用了一些非常狂野的东西。老实说,我不认为这是一个很好的起点课程,作为入门课程感觉不必要地复杂。我不想承认这一点,但在我弄清楚如何使用文档解决问题之前,我还使用了一门课程来获得基本的总体感觉——这是最重要的技能(该课程对此有所帮助;它也是一门 Udemy 课程- 但是,嘿,信息就是信息,无论它来自哪里)。


回到主题。很难确定代码的开头或结尾,尤其是在某些细节出现错误的情况下。请清楚地说明您刚刚从某个来源复制粘贴的代码以及您自己创建的代码。如果存在复制代码,则问题更有可能出在您自己的代码中,因为您可能不是第一个使用该代码的人。乍一看,代码中提到了所有需要提及的部分:

  1. 您设置了 GPIO 属性。
  2. 您设置了 EXTI 外设,您可以在其中选择要触发中断的引脚。
  3. 您设置了 SYSCFG,您可以在其中告诉 EXTI 引脚指的是哪个端口(引脚 14 表示 GPIOB 14 而不是 GPIOC 14)。
  4. 您启用 NVIC

如果你的中断没有触发,那么查看 SFR 绝对必须显示一些东西。既然你已经知道如何操作调试模式,那肯定是你忽略了。

我注意到您没有为 SYSCFG 激活时钟,它将 GPIO 端口绑定到 EXTI 中断引脚。您可以使用两件事检查 SYSCFG 是否正在运行:

  1. 在调试模式下打开 SFR。如果 SYSCFG 的所有寄存器都是 0x00,那就是 sus。可能它的时钟没有走。
  2. 在调试模式下打开 SFR。打开 RCC -> APB2ENR,必须设置位 SYSCFGEN。

要设置该位,请在 GPIO 时钟激活旁边执行 RCC-&gt;APB2ENR |= RCC_APB2ENR_SYSCFGEN;(或使用您拥有的库查找如何设置该位)

【讨论】:

    【解决方案2】:

    您好 Ilya,感谢您的回复。 我没有复制任何代码。我按照课程中给出的说明,自己编写了所有内容。 我按照您的要求检查了寄存器值。我认为所有的值都是正确的。

    SYSCFG register values

    SYSCFGGEN bit value

    【讨论】:

      猜你喜欢
      • 2017-08-29
      • 1970-01-01
      • 2022-06-18
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 2020-01-22
      • 2017-03-26
      • 2019-01-05
      相关资源
      最近更新 更多