STM32 external interrupt responds only in debug mode - c

I have a problem with my STM32F103C8T6 microcontroller. I am using (as an exercise) external interrupts to toggle on/off a led, by pressing an external switch wich in turn is connected to PC13. I am using StdPeriph Library.
When the chip has programmed, nothing happens. On the contrary, when I am using the debugger (debug in Coocox), the chip is working fine. I can not figure out where is the problem.
Can you help me please?
Here is my code.
#include<stm32f10x.h>
#include<stm32f10x_rcc.h>
#include<stm32f10x_gpio.h>
#include<stm32f10x_exti.h>
#include<misc.h>
typedef enum{
on,
off
}state;
state led=on;
int main(void){
// enable clocks
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
// uncomment to disable/remap JTAG pins
GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
// configure PC13 as input
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
// configure PB8 as led output
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
// connect PC13 to EXTI controller
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);
// enable and configure EXTI controller
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line13;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
// enable IRQ
NVIC_EnableIRQ(EXTI15_10_IRQn);
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);
// Configure NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStructure);
// switch on led
GPIO_WriteBit(GPIOB,GPIO_Pin_8,Bit_SET);
while(1);
return 0;
}
void EXTI15_10_IRQHandler(void){
// clear pending bit
if(EXTI_GetITStatus(EXTI_Line13)!=RESET){
EXTI_ClearITPendingBit(EXTI_Line13);
}
if(led==off){
GPIO_WriteBit(GPIOB,GPIO_Pin_8,Bit_SET);
led=on;
}else{
GPIO_WriteBit(GPIOB,GPIO_Pin_8,Bit_RESET);
led=off;
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t * file,uint32_t line){
/* Infinite loop */
while (1);
}
#endif

I had this issue as well. I'm using a STM32F030.
The problem for me was not having the SYSCFG clock enabled, which is bit 0 of RCC APB2ENR register. I'm guessing this setting is enabled in debug, so that the software can debug? Otherwise the clock is disabled!
I finally found this by looking into the STM32F1 reference manual, which is slightly more comprehensive.

It is generally a very bad idea to use external interrupts for the buttons and keys. You should use the timer interrupt instead.
You can see simple implementation of the key in the timer interrupt (click, double click, long click events supported) here : https://www.diymat.co.uk/arm-three-function-click-double-and-long-click-button-library-timer-interrupt-driven/

I don't have knowledge about the mentioned controller, but I worked on STM32L4 series controllers. In STM32L4 push button is connected to the PC13 pin. I observed gpio debouncing when pressing the push button. In your EXTI15_10_IRQHandler() implement debouncing logic. Make sure the interrupt is reaching this function for only once per button press. May be the debugger is slowing down the processor(cpu running in lower frequency compared to free run) and you are getting the interrupts properly.

Do you use different build config for debug? If so, try making the led variable volatile and see if it helps.
If not: add some delay loop, i.e. voliatile unsigned i; for (i=0; i < 50000u; ++i); after clearing the EXTI bit in the ISR. This is generally a bad pratcice to use blocking delays in the interrupt service (if it's ever a good practice...) but might be helpful to see if it is related to debuncing not done properly. If it helps, then debouncing the switch is the most likely problem.
EDIT: consider using bit-banding (if possible) to access the output port, then you could do sth like bind_band_led_port ^= 1;, but that's just a side note.

Related

While loop inside STM32F3xx HardFault handler does not execute forever as expected

I would like to find the cause of mysterious microcontroller resets that I am seeing in my project. The microcontroller I am using is an STM32F3 device with STM32F3xx driver library.
My setup also includes a J-link Ultra+ debugger, however frustratingly I have not yet figured out how to reproduce the resets. They occur almost always after leaving the device running for 12+ hours, and do not seem to occur when connected on a programming jig designed to interface with the debugger.
I believe that when the resets occur, the HardFault handler will be called. I have a number of these devices, and given I cannot connect them all to the debugger and the resets occur at inopportune times, I would like to be able to send some information via a serial line from the HardFault handler. The serial line would then be observed by an external device.
Further complicating things is the lack of unused UART pins. I am attempting to create a poor man's UART by flicking a GPIO on and off in the hard fault handler, with delays in between. To begin with, I just want to figure out how to flick this LED on and off with 50% duty cycle. My code currently looks something like this:
/**
* #brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
GPIO_InitTypeDef GPIO_InitStruct = {LED_Pin, GPIO_MODE_OUTPUT_PP,
GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, 0};
HAL_GPIO_Init(LED_Port, &GPIO_InitStruct);
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
HAL_GPIO_WritePin(LED_Port, LED_Pin, GPIO_PIN_RESET);
HAL_Delay(10);
HAL_GPIO_WritePin(LED_Port, LED_Pin, GPIO_PIN_SET);
HAL_Delay(10);
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
I am testing this by triggering a divide-by-zero reset. I have disabled all watchdogs yet I am finding that when this while loop is entered, it does not while forever, in fact the device restarts when it first hits a HAL_Delay() command.
Questions:
What might be causing the resets upon reaching HAL_Delay()?
Can I execute instructions indefinitely in the HardFault handler, or is there a limited amount of time I have to do things before a reset occurs?
Can I use timers in the hard fault handler?
Thanks very much for your help.
HAL_Delay(10); uses systick interrupt. When in HF you will not get any interrupts and this function will wait forever and your diodes will not flash. You need to delay another way, for example:
for(unsigned x = 0; x < 100000; x++) asm("");
Can I execute instructions indefinitely in the HardFault handler, or
is there a limited amount of time I have to do things before a reset
occurs?
Yes you can stay there as long as you wish. But no interrupts!!!!
Can I use timers in the hard fault handler?
Yes, but no timer interrupts. Basically, you can use all the peripherals if you wish.
What might be causing the resets upon reaching HAL_Delay
Hard to say. Did you enable watchdog?
Basically do not use HAL in HF as most of the functions use HAL_Delay internally. Program bare registers instead

Interrupt not returning control to main

Hi I'm using STM32G070 nucleo board and I was trying to learn how to use UART with interrupts. I made a simple led blinking program in the main and in the interrupt handler there is a simple echo program. The echo works fine but the led blinking never starts.
Below is my code:
//while loop for led blinking
while(1)
{
GPIOA->BSRR |= (GPIO_BSRR_BS5);
//delaySys is a blocking delay function that takes milli seconds as input
delaySys(1000);
GPIOA->BSRR &=~(GPIO_BSRR_BS5);
GPIOA->BSRR |= (GPIO_BSRR_BR5);
delaySys(1000);
}
Next is my interrupt handler
void USART2_IRQHandler()
{
if((USART2->ISR) & (USART_ISR_RXNE_RXFNE))
{
USART2->TDR = USART2->RDR;
while(!((USART2->ISR) & (USART_ISR_TC)))
;
NVIC_ClearPendingIRQ(USART2_IRQn);
}
if(((USART2->ISR) & (USART_ISR_TXE_TXFNF)))
{
//TRANSMISSION COMPLETE
}
}
If you expect a subsequent stream of bytes from the UART, it might sometimes be justified to hang in the ISR and poll, until you got the expected amount. However, the rest of the program will hang up and wait while you do.
You shouldn't need to call NVIC_ClearPendingIRQ from inside the ISR, because the flag causing the interrupt should be cleared automatically, typically by reading it followed by a data register access or such. Check the UART part of the manual for register descriptions.
A better but more complex way to deal with UART rx interrupts without stalling is to use DMA. I think most STM32 should have support for this, but I'm not sure.
Looking at your blinking code however, it's problematic:
// light up 1000ms
GPIOA->BSRR |= (GPIO_BSRR_BS5);
delaySys(1000);
// lights off
GPIOA->BSRR &=~(GPIO_BSRR_BS5);
// light up some other LED? NOTE: BR5 not BS5
GPIOA->BSRR |= (GPIO_BSRR_BR5);
delaySys(1000);
This can do one of two things:
If GPIO_BSRR_BS5 and GPIO_BSRR_BR5 are the same bit masks, then it lits up the LED approximately 1000ms and turns it off for approximately 50-100ns. The LED stays lit around 99.99% of the time.
If GPIO_BSRR_BS5 and GPIO_BSRR_BR5 are different bit masks, then one LED will blink with 1000ms duty cycle and another stay lit 100% of the time.
Okay I did fix the problem somehow. I had enabled the interrupt for tx before but when I have disabled it, everything works fine. Seems like Tx was sending an interrupt request and was competing with main.

How do I reset the STM32 HAL UART driver (HAL) state?

I know one can enable a UART receive interrupt using
HAL_UART_Receive_IT(&huart2, (uint8_t *)rx_buffer, expectedNumberOfBytes)
But once started how does one stop it, "manually"?
We can disable the UART interrupt using HAL_NVIC_DisableIRQ() (ex: HAL_NVIC_DisableIRQ(USART1_IRQn)). This will prevent it from raising an interrupt, but the state set by the function HAL_UART_Receive_IT which is HAL_UART_STATE_BUSY_RX needs to be set back to HAL_UART_STATE_READY for the uart handle to go back to a state that can accept a new HAL_UART_Receive_IT() call.
Question
How do I reset the state of the UART interrupt if I wish to disable a Rx interrupt after some time?
Stack Overflow questions do not address how to reset the state; I have referred to these questions:
Disabling interrupt in interrupt handler STM32F407
https://electronics.stackexchange.com/questions/100073/stm32-usart-rx-interrupts
I could use USART_ClearITPendingBit() or USART_ITConfig() but these are defined as private functions by STM's HAL library. So should I use them?
How [do I] reset the state of the UART interrupt if [I] wish to disable a Rx interrupt after some time[?]
(See it's usage in "stm32f4xx_hal_uart.c", for example.)
The huart->RxState member of a uart handle struct is really only used internally by the HAL library when doing things such as HAL_UART_Receive(), HAL_UART_Receive_IT(), HAL_UART_Receive_DMA(), (and many other internal functions like this), etc. If you manually implement your own interrupt-based and ring-buffer-based UART Tx and Rx calls, however, which is the preferred way to do it, this member is completely meaningless and it doesn't matter what you do with it, as it is used only inside HAL library function calls and HAL ISR handlers (neither of which you have to use), and really has nothing to do with the register-level interrupts and things directly.
By digging around the source code in stm32f4xx_hal_uart.c (for example), however, here are a couple valid options you can use:
1. How to reset huart->RxState to HAL_UART_STATE_READY:
Call HAL_UART_Init(). By inspecting its source code, you'll see it calls huart->RxState= HAL_UART_STATE_READY; before returning.
Just manually set huart->RxState = HAL_UART_STATE_READY; So long as you know you have properly stopped the interrupt-based receive in the middle of its processing, this is perfectly valid.
Let's take this further, however.
Imagine you are using UART7 on an STM32F4. Therefore, in your stm32f4xx_it.c interrupt handler file, you'll see the following code auto-generated by STM32CubeMX:
/**
* #brief This function handles UART7 global interrupt.
*/
void UART7_IRQHandler(void)
{
/* USER CODE BEGIN UART7_IRQn 0 */
/* USER CODE END UART7_IRQn 0 */
HAL_UART_IRQHandler(&huart7);
/* USER CODE BEGIN UART7_IRQn 1 */
/* USER CODE END UART7_IRQn 1 */
}
Let's go over some layers of disabling/enabling interrupts.
2. From broadest to narrowest scope, here are several ways to disable/enable the USART Rx interrupt:
You can disable/enable ALL interrupts, including this UART7_IRQHandler(), using these ARM-core CMSIS calls:
__disable_irq();
__enable_irq();
Source: https://stm32f4-discovery.net/2015/06/how-to-properly-enabledisable-interrupts-in-arm-cortex-m/
So, you could do the following to disable the interrupt, reset the RxState, and then start up the interrupt-based receive again when ready:
__disable_irq();
huart7->RxState= HAL_UART_STATE_READY;
__enable_irq();
HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
You can disable/enable ONLY the UART7_IRQHandler() interrupts (all 10 types of uart7 interrupts connected to this interrupt vector, including Tx-related, Rx-related, error-related, etc), using these STM32 HAL calls:
HAL_NVIC_DisableIRQ(UART7_IRQn);
HAL_NVIC_EnableIRQ(UART7_IRQn);
Then, do the same as just above except use these calls to disable/enable the interrupts instead.
If you dig down into the implementation of HAL_UART_IRQHandler(), however, which is called by UART7_IRQHandler(), you'll see that it only calls the interrupt-based receive handler, UART_Receive_IT(), if both the USART_SR_RXNE bit ("Receive Not Empty", inside the USART Status Register) and the USART_CR1_RXNEIE bit ("Receive Not Empty Interrupt Enable", inside the USART Control Register 1), are both set. The RXNE bit is set whenever a byte comes in, and is cleared whenever you read the data register or write a zero to it. The interrupt-enable bit is something you have full control over to disable this UART receive interrupt, and if you clear this bit manually, you will disable the receive interrupt withOUT disabling any other type of interrupt associated with this USART. This is the best way to do it, as there are 10 interrupt sources associated with this UART. In other words, clearing this bit not only causes the check inside HAL_UART_IRQHandler() to fail, but it also prevents the receive interrupt from happening in the first place! Refer to the Reference Manual RM0090 Rev 16, for example:
p969:
p1009:
p1011:
p1015:
p1013:
So, to disable/enable the USART Receive Not Empty interrupt only, do the following. Refer to the Control Register (USART_CR1) on p1013, shown just above.
// Disable the USART Receive Not Empty interrupt
CLEAR_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
// Enable the USART Receive Not Empty interrupt
SET_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
Now, you could do the following to disable the USART Receive interrupt, reset the HAL RxState, and then start up the interrupt-based receive again when ready:
CLEAR_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
huart7->RxState= HAL_UART_STATE_READY;
SET_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE); // This call isn't actually necessary, as this bit is set inside `HAL_UART_Receive_IT()` as well
HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
3. How to (awkwardly) use HAL_UART_Receive_IT() for continual interrupt-based receiving.
TODO
4. Why HAL_UART_Receive_IT() really isn't a very useful function after-all.
TODO
5. How to manually configure your own interrupt-based UART Tx and Rx ISRs and functions.
TODO
You can use HAL_UART_Abort_IT.
Most UARTs clear any pending Receive interrupt when the program reads from the holding register. So my answer would be: simply read the data register after disabling interrupts, and ignore the result.
I haven't had a chance to try this on my STM32 yet, but...
There is a function static void UART_EndRxTransfer(UART_HandleTypeDef *huart)
in the HAL library that does the following:
Disable RXNE, PE and ERR interrupts
restore huart->RxState to Ready
I found that function in the stm32f7xx_hal_uart.c file. However, it is defined as static, so I just copied over the definition into the file where I used it. It might be a bit hacky but it worked for me.

Disabling the STM32 IWDG during debugging

I have a ChibiOS 3.x program on a STM32F4 microcontroller where I use the IWDG watchdog to reset the MCU on errors like this:
int main() {
iwdgInit();
iwdgStart(&IWDGD, &wd_cfg);
while(true) {
// ... do stuff
}
}
If I now attach my debugger and, at any point, stop the program (manually or via a breakpoint), the microcontroller will reset after the timeout defined by the watchdog configuration (and therefore cause issues in my debugging process)
How can I disable this behaviour, i.e. how can I disable the IWDG while the core is stopped due to the debugger?
I have tried disabling it entirely, however, I need to leave it running to catch unwanted IWDG resets.
The STM32 MCUs contain a feature called debug freeze. You can stop several peripherals, including I2C timeouts, the RTC and, of course, the watchdog.
In the STM32 reference manual, refer to section 38.16.4ff "MCU debug component (DBGMCU)".
The IWDG is running on the APB1 bus. Therefore you need to modify DBGMCU_APB1_FZ, most specifically assert the bit DBG_IWDG_STOP in that register.
The POR value (= default value) for this register is 0x0, i.e. if you not actively disable it, the IWDG will still be running.
int main() {
// Disable IWDG if core is halted
DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_IWDG_STOP;
// Now we can enable the IWDG
iwdgInit();
iwdgStart(&IWDGD, &wd_cfg);
// [...]
}
Note that when not enabling the watchdog in software, it might still be enabled in hardware if the WDG_SW bit is reset in the flash option bytes.
If you are using the ST HAL (not included in ChibiOS, see STM32CubeF4), you can also use this macro:
__HAL_DBGMCU_FREEZE_IWDG();
(which basically does exactly the same as we did above)
Besides, you need enable the DBGMCU clock on APB2 before calling __HAL_DBGMCU_FREEZE_IWDG().
__HAL_RCC_DBGMCU_CLK_ENABLE();
When using the ST HAL, the right macro to use is:
__HAL_DBGMCU_FREEZE_IWDG()
According to the reference manual, the DBGMCU_CR register "can be written by the debugger under system reset", so, if the debugger supports it, there is no need for changes in the software.
For instance, in STM32CubeIDE (as of now Version 1.6.0) just set Project > Properties > Run/Debug Settings > Launch configurations for [project name]: > [project name] Debug > Edit > Debugger > Device Settings > Suspend watchdog counters while halted:
to Enable.

ARM Cortex-M3 example for interrupt pending

With an ARM Cortex-M3, such as an NXP LPC1788, why would someone use the Interrupt Set-Pending Register(s) or Interrupt Clear-Pending Registers?
Can someone provide a simple, canonical example of using these registers?
The only use case I can think of is the triggering of a low-priority software excaption form a high priority IRQHandler - like the GPIO interrupt handler.
Normally you would use PendSV for that, but when you have more than one task or priority level you can use any unused peripherial exception vector. Could be useful in programs that use the Sleep-on-Exit feature - where the µC will only run in exception handlers.
// Example for LPC17xx
void ETHERNET_Handler (void)
{
// toggle LED on P0.4
LPC_GPIO0->FIODIR0 ^= (1<<4);
}
void main(void)
{
// set Ethernet IRQ to loewst Priority
NVIC_SetPriority(ENET_IRQn,31);
NVIC_EnableIRQ(ENET_IRQn);
NVIC_SetPendingIRQ(ENET_IRQn); // trigger Ethernet IRQ Handler
// ...
while (1);
}

Resources