STM32F756VGH6 register based interrupt syntax.
Hi,
I am a beginner in STM32 programming. I chose purely register based programming approach without using HAL as I find it a bit harder and slower but more contributing to the overall system performance in the long term code writing skills. This time I am asking help with the external interrupt code.
Idea is to hook the external interrupt on an pulled up button and generate the interrupt each time the button is pressed (when the MCU receives falling edge.) I wrote this code that compiles and runs, but nothing happens when the button is pressed (it should turn 2 leds off). I have already verified and tested the timer, gpio and core clock setup functions, everything is working. So the problem lies somewhere in the interrupt setup syntax or the ISR itself. Since it is my first time working with interrupts on STM32, I hope only minor syntax update will get my code doing its duty.
#include "main.h"
void Core_Clock_Setup (void){
RCC->CR |= RCC_CR_HSEON; //Set the clock source to external crystal/resonator (HSE)
while (!(RCC->CR & RCC_CR_HSEON)); //Wait until clock gets stable
RCC->APB1ENR |= RCC_APB1ENR_PWREN; //Enable power interface clock
PWR->CR1 &= ~(1U << 14);
PWR->CR1 &= ~(1U << 15); //Set internal voltage regulator to is reset value (scale 1)
FLASH->ACR &= ~FLASH_ACR_ARTEN; //Disable ART accelerator
FLASH->ACR &= ~FLASH_ACR_ARTRST; //Reset ART accelerator
FLASH->ACR |= FLASH_ACR_PRFTEN; //Enable prefetch
FLASH->ACR |= FLASH_ACR_LATENCY_6WS; //Set 7 CPU clock cycle flash memory access time (in order to get 200 MHz core clock)
//@ 25 MHz crystal, 200 MHz core clock configuration down below
RCC->CFGR &= ~(((1 << (7 - 4 + 1)) - 1) << 4);
RCC->CFGR &= ~(1 << 4); //Core clock division by 1 (core clock is not devided)
RCC->CFGR &= ~(1 << 5);
RCC->CFGR &= ~(1 << 6);
RCC->CFGR &= ~(1 << 7);
RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE;//HSE is set to be PLL entry
RCC->PLLCFGR &= ~(1 << 16); //PLLP Setting corresponding PLL prescalers (division by 2)
RCC->PLLCFGR &= ~(1 << 17);
//RCC->PLLCFGR &= ~((1 << 6) - 1);
//RCC->PLLCFGR |= (16 & ((1 << 6) - 1)); //PLLM Setting corresponding PLL prescalers (division by 16)
RCC->PLLCFGR |= (16 << 0);
RCC->PLLCFGR &= ~(((1 << (14 - 6 + 1)) - 1) << 6);
RCC->PLLCFGR |= (256 << 6); //PLLN Setting corresponding PLL prescalers ( multiplication by 256)
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 Low speed prescaler of 4 (50 MHz, max is 54 Mhz)
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; //APB2 High speed prescaler of 2 (100 MHz, max is 108 Mhz)
RCC->CR |= RCC_CR_PLLON; //Enable PLL
while (!(RCC->CR & RCC_CR_PLLRDY)); //Wait until PLL gets stable
RCC->CFGR |= RCC_CFGR_SW_PLL; //PLL is set to be core clock
//RCC->CFGR |= RCC_CFGR_SW_HSE; //HSE is set to be core clock
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait until PLL indeed becomes core clock source
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Timer1_Setup(void){ //16 bit advanced timer
RCC->DCKCFGR1 &= ~ (1 << 24); //TIMxCLK = 2xPCLKx
//When TIMPRE bit of the RCC_DCKCFGR1 register is reset, if APBx prescaler is 1, then TIMxCLK = PCLKx, otherwise
//TIMxCLK = 2x PCLKx.
// When TIMPRE bit in the RCC_DCKCFGR1 register is set, if APBx prescaler is 1,2 or 4, then TIMxCLK = HCLK, otherwise
//TIMxCLK = 4x PCLKx.
//TIM1 CLK is HCLK in this case
RCC->APB2ENR |= (1 << 0); //Enable Timer 1 clock
TIM1->PSC = 99; //APB1 is 50 Mhz and 100 MHZ for timer (The number is set: Clock in MHz - 1) 1 full period equals 1 MHZ
TIM1->ARR = 0xFFFF; //Auto reload at 100 ticks -> around 100 micro seconds at 100 MHz timer clock
TIM1->CR1 |= (1 << 0); //Enable Timer 6 counter
while(!(TIM1->SR & (1<<0))); //Wait until timer update bit is set
}
void delay_ms (uint16_t ms){
for(uint16_t i = 0; i<ms; i++)
{
TIM1->CNT = 0; //Reset counter
while (TIM1->CNT < 2000); //Wait until counter reaches desired value
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void GPIO_Setup(void){
//PC14 OUTPUT //LEDS
RCC->AHB1ENR |= (1 << 2);
GPIOC->MODER |= (0b01 << 28); //PC15 General purpose output mode
GPIOC->OTYPER &= ~ (1 << 14); //PC15 Output push-pull (reset state)
GPIOC->OSPEEDR |= (0b11 << 28); //PC15 very high GPIO speed
GPIOC->PUPDR |= (0b10 << 28); //PC15 pull down resistors
//PC15 OUTPUT
GPIOC->MODER |= (0b01 << 30); //PC15 General purpose output mode
GPIOC->OTYPER &= ~ (1 << 15); //PC15 Output push-pull (reset state)
GPIOC->OSPEEDR |= (0b11 << 30); //PC15 very high GPIO speed
GPIOC->PUPDR |= (0b10 << 30); //PC15 pull down resistors
//PE4 OUTPUT
RCC->AHB1ENR |= (1 << 4); //Enable clock for GPIO bank A
GPIOE->MODER |= (0b01 << 8); //PE4 General purpose output mode
GPIOE->OTYPER &= ~ (1 << 4); //PE4 Output push-pull (reset state)
GPIOE->OSPEEDR |= (0b11 << 8); //PE4 very high GPIO speed
GPIOE->PUPDR |= (0b10 << 8); //PE4 pull down resistors
//PE0 OUTPUT
GPIOE->MODER |= (0b01 << 0); //PE0 General purpose output mode
GPIOE->OTYPER &= ~ (1 << 0); //PE0 Output push-pull (reset state)
GPIOE->OSPEEDR |= (0b11 << 0); //PE0 very high GPIO speed
GPIOE->PUPDR |= (0b10 << 0); //PE0 pull down resistors
//-----------------------------------------------------------------------------------
//PE5 INPUT ALL BUTTONS EXTERNALLY PULLED UP
GPIOE->MODER |= (0b00 << 10); //PE5 General purpose input mode
//PE6 INPUT
GPIOE->MODER |= (0b00 << 12); //PE6 General purpose input mode
/*
//PH0 INPUT
RCC->AHB1ENR |= (1 << 7);
GPIOH->MODER |= (0b00 << 0); //PH0 General purpose input mode
//PH1 INPUT
GPIOH->MODER |= (0b00 << 2); //PH1 General purpose input mode
*/
}
void Interrupt_setup(void){
//PE5
RCC->APB2ENR |= (1 << 14); //System configuration controller clock enabled
SYSCFG->EXTICR[2] |= (0b0100 << 5); //0100: PE[x] pin
EXTI->IMR |= (1<< 5); //Interrupt request from line x is not masked
EXTI->FTSR |= (1<< 5); //Falling trigger enabled (for Event and Interrupt) for input line
//EXTI->RTSR &= ~ (1<< 5); //Rising trigger disabled (for Event and Interrupt) for input line
NVIC_SetPriority(EXTI9_5_IRQn, 0);
NVIC_EnableIRQ (EXTI9_5_IRQn);
}
void EXTI9_5_IRQHandler(void){
//if (EXTI->PR & (1 << 5)){
//EXTI->PR |= (1 << 5);
GPIOC->BSRR |= ((1 << 14) << 16);
GPIOE->BSRR |= ((1 << 4) << 16);
//}
}
int main (void){
Core_Clock_Setup();
Timer1_Setup();
GPIO_Setup();
Interrupt_setup();
while(1){
GPIOC->BSRR |= (1 << 14);
GPIOC->BSRR |= (1 << 15);
GPIOE->BSRR |= (1 << 4);
GPIOE->BSRR |= (1 << 0);
delay_ms(500);
//if(GPIOE->IDR & (1 << 5)){
//GPIOC->BSRR |= ((1 << 14) << 16);
//}
GPIOC->BSRR |= ((1 << 15) << 16);
/*
if(GPIOE->IDR & (1 << 6)){
GPIOE->BSRR |= ((1 << 4) << 16);
}
*/
GPIOE->BSRR |= ((1 << 0) << 16);
delay_ms(500);
}
}
Side note: the datasheet tells to pick your interrupt pin (PE5 in my case) in the SYSCFG_EXTICR2 register. But the compiler says, there is no such register. I tried SYSCFG->EXTICR[1] and SYSCFG->EXTICR[2] which do compile, but did not change anything. Hope thats all the relevant details. And yes, I have already checked my wiring :) the hardware is all good.
