1
\$\begingroup\$

I've been learning to program in bare-metal and I'm trying to learn how EXTIs work. I wrote a simple program that would turn on an onboard LED on PB7 when triggered by a button on PC13. Code as follows:

Initialization:

 RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
 RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
 GPIOB->MODER |= GPIO_MODER_MODER0_0 | GPIO_MODER_MODER7_0 | GPIO_MODER_MODER14_0;
 GPIOC->PUPDR |= GPIO_PUPDR_PUPD13_1;
 SYSCFG->EXTICR[4] |= SYSCFG_EXTICR4_EXTI13_PC;
 EXTI->IMR |= EXTI_IMR_IM13;
 EXTI->RTSR |= EXTI_RTSR_TR13;
 EXTI->FTSR &= ~EXTI_FTSR_TR13;
 NVIC_EnableIRQ(EXTI15_10_IRQn);

Interrupt Handler:

void EXTI15_10_IRQHandler(void)
{
 if (EXTI->PR & EXTI_PR_PR13)
 {
 GPIOB->BSRR |= GPIO_BSRR_BS7;
 HAL_Delay(1000);
 GPIOB->BSRR |= GPIO_BSRR_BR7;
 }
 EXTI->PR |= EXTI_PR_PR13;
}

When running this program, the LED turns on and stays on. When checking the SYSCFG_EXTICR4 register, bit 5 which corresponds to Port C seems to be set to zero even though I enabled it in the code (Although I think it could have something to do with them displaying the bits).

enter image description here

But so far, I've followed the exact instructions in the datasheet and can't figure out where I'm going wrong. Also, I'm using a Nucleo F413ZH 144 pin board and STM32CubeIDE. Thanks!

Update: SYSCFG_EXTICR4_EXTI13_PC is mapped to SYSCFG->EXTICR[3]. Also, EXTI->PR = EXTI_PR_PR13;

asked May 1, 2021 at 5:53
\$\endgroup\$
8
  • \$\begingroup\$ Have yoy debugged this and how? Where is the code that configures the PC13 as digital input? \$\endgroup\$ Commented May 1, 2021 at 6:30
  • \$\begingroup\$ @Justme I’ve looked at the special function registers. I’m pretty new so I don’t know much about debugging apart from looking at the registers and using live expressions. Also, the pins are input by default. Usually, if I need an input pin, I just configure other parameters and leave the MODER bits for the pin to default and that’s worked fine for me. \$\endgroup\$ Commented May 1, 2021 at 6:34
  • \$\begingroup\$ You are right, on this STM32 the GPIO pins seem to be digital inputs when uninitialized - on some other STM32 devices they are off as analog inputs. May I ask what is the motivation to try learning using the registers directly, as you seem to be using the HAL anyway and the CubeMX code generator can prebuild you a proven working program example code where you fill in the LED blinking in 5 minutes. You can then examine the code and compare what your code does differently. \$\endgroup\$ Commented May 1, 2021 at 7:15
  • 1
    \$\begingroup\$ Yes, it is good to be able to work around HAL limitations and bugs. But my suggestion still applies; do it with HAL, examine generated HAL code what it does and why to make it work, and then look for differences what HAL code does that yours doesn't, and replicate minimal custom version. \$\endgroup\$ Commented May 1, 2021 at 8:25
  • 1
    \$\begingroup\$ You can't use HAL_Delay() inside an ISR. HAL_Delay() relies on the SysTick interrupt firing and its ISR incrementing a counter, but that will never happen because your code is already inside your EXTI ISR. Nesting ISRs to make this work is possible, although not what I'd recommend to solve this problem and not at a beginner level anyway. In addition, Kartman's answer is correct about EXTI->PR. The way you're doing it could be unintentionally clearing other bits in addition to EXTI_PR_PR13. \$\endgroup\$ Commented May 1, 2021 at 13:56

1 Answer 1

3
\$\begingroup\$

This line looks suspect: EXTI->PR |= EXTI_PR_PR13;

The user manual tells you to write a '1' bit to clear the interrupt. That line does not quite do what you expect. Why you might ask? The register you read is not the same register you write. This is why doing a read/modify/write is not correct in this situation.

the required code is: EXTI->PR = EXTI_PR_PR13;

or if you want to clear all flags in this register: EXTI->PR |= EXTI_PR;

You might also want to check that EXTI_PR_PR13 is actually a bit mask and not a bit number. eg: a bit mask might be (1 << 13) and the bit number is 13.

There might be other issues with your code, but the above is what jumped out at me as it is a common mistake.

Other observations:

it is generally bad juju to put a delay in an isr. In this instance it is test code, but tying up a processor with a delay is not good practice. Use a timer to generate a tick (or use systick).

using pushbutton/switches external signals with external interrupts. Ok if you want to wake the cpu from sleep, but beyond that disable the external interrupt and use a timer tick to poll the input and filter/debounce it. Switches work in the realm of 10's of milliseconds. Interrupts on a STM F4 series are sub-microsecond. Use interrupts where you need the fast response.

answered May 1, 2021 at 11:31
\$\endgroup\$
3
  • \$\begingroup\$ This doesn’t work. Also, I can confirm that EXTI_PR_PR13 is a bit mask and not bit number. As for the delay, I haven’t learnt how to create delays with timers yet, and thats definitely next in my list of things to learn. \$\endgroup\$ Commented May 1, 2021 at 12:33
  • \$\begingroup\$ How do you know it doesn’t work? It has probably resolved one problem, but theres more. \$\endgroup\$ Commented May 1, 2021 at 13:14
  • \$\begingroup\$ I figured it out. HAL_Delay doesn't work within an ISR, so I replaced the delay and GPIO_BSRR with GPIOB->ODR|= GPIO_ODR_OD7. Also, SYSCFG_EXTICR4_EXTI13_PC is mapped to SYSCFG->EXTICR[3] which is confusing but the program works now. \$\endgroup\$ Commented May 1, 2021 at 14:45

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.