7

i am working on a project to connect a camera to an STM32F7 Discovery board using the DCMI interface. The camera part works fine, but i have a strange problem with external interrupts from the onboard push button.

I enable external interrupts for the button using the function provided in the STM BSP package:

BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_EXTI);

The external interrupt for this button is now on GPIO_PIN_11. This interrupt is handled by the HAL_GPIO_EXTI_Callback function which i can implement in my main.c file.

I am using STM HAL/BSP libraries.

The interrupt on a button press works and the callback function is entered correctly, but here is where the problem begins.

Here is what i want to do on a button press:

{
        if(capture_status == 0)
        {
            start_capture_continuous((uint8_t*)CAMERA_FRAME_BUFFER);//start continuous grabbing, if not already running
            if(suspended == 1)
            {
                Camera_Resume();//resume DCMI and DMA if necessary and wakeup sensor from standby
            }
        }
        else
        {
            Camera_status = stop_capture();//stop if already running and update the status
            Camera_Suspend();//halt DCMI and DMA and put sensor in standby mode
        }
    HAL_Delay(50);
}

Explanation of this code:

This code is for toggling the camera live preview on the LCD.

start_capture_continuous((uint8_t*)CAMERA_FRAME_BUFFER);

This function starts continuous grabbing of frames from the camera and updates the frame buffer. It basically references the HAL_DCMI_Start_DMA function.

stop_capture();

This function stops the DMA transfer.

Camera_Suspend and Camera_Resume disable/enable the DCMI interface and send standby/wakeup commands to my camera sensor via I2C.

So here is where the problem starts:

If i put this code in the callback function, the MCU gets stuck somewhere in this function. Just a reset can get me back to normal state.

Somewhere on the internet I read that this issue could be I2C related, but even if I delete the I2C parts in the callback function the behaviour is not as intended: Sometimes it works for about three times or it gets stuck immediately again. I believe the problem is in the HAL_DCMI_Start_DMA function, but i am not sure.

Are there any common mistakes which lead to a problem like this?

I hope is has become clear what my problem is and someone can give me some hints to solve it.

btw: If i use the button in polling mode in the main infinite loop and do exact the same things on a button press everything works well.

To clarify my interrupt routines:

Main interrupt Handler:

void EXTI15_10_IRQHandler(void)
{
//if button pressed
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_11) != RESET)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
}
//if touchscreen interrupt
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_13) != RESET)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
}

calls:

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}

calls after resetting IT flag:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
sprintf((char*)text, "EXTI pin: %d", GPIO_Pin);
BSP_LCD_DisplayStringAt(5, LINE(8), (uint8_t*)text, LEFT_MODE);
//if button pressed -> toggle preview
if(GPIO_Pin == GPIO_PIN_11)
{
    BSP_LED_Toggle(LED1);
}
//ts interrupt
if(GPIO_Pin == GPIO_PIN_13)
{

}
}

This works flawlessly, but if I replace BSP_LED_Toggle(LED1); with the code above, the function gets stuck.

Update: I found the mistake. The SysTick interrupt priority was set to the lowest (15), so calling HAL_Delay() from an ISR with the same or higher priority caused an infinite loop in the HAL_Delay function.

So, take care: If you are using the default HAL settings provided by ST, the priority for SysTick IRQ is set to 15 when calling HAL_Init(). You have to change that in the stm32f7xx_hal_conf.h file or by using the HAL_InitTick(TickPriority) function.

Here is what the HAL documentation of HAL_InitTick says about that issue:

Care must be taken if HAL_Delay() is called from a peripheral ISR process, The the SysTick interrupt must have higher priority (numerically lower) than the peripheral interrupt. Otherwise the caller ISR process will be blocked. The function is declared as __weak to be overwritten in case of other implementation in user file.

deinoppa
  • 179
  • 1
  • 2
  • 10
  • 1
    Did you include code to clear the interrupt flag inside your handler/callback? – SoreDakeNoKoto Jan 19 '16 at 11:50
  • 2
    That's a ton of stuff to do in an interrupt, and bad practice. Set a flag in the interrupt, and act on the flag in main. – Scott Seidman Jan 19 '16 at 11:56
  • I know this is bad practice, but this seems to be the standard practice of the ST HAL library. The main handler is the EXTI15_10_IRQHandler(void) function in stm32f7xx_it.c file. This function checks on which GPIO pin the interrupt occurred and calls HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11). The interrupt flag is cleared in the HAL function which also calls the callback function afterwards. So the procedure is indeed more complicated as necessary but the problem is not about clearing interrupt flags. – deinoppa Jan 19 '16 at 12:48
  • Which program are you using for debugging? I had a similar problem once and had to correct what I think it's a bug a ST HAL library. But in order to find out specifically where my program was getting stuck I used Visual Studio with VisualGDB, would be hard to exactly pinpoint your problem without a step-by-step debugging of some sort. If i can find where I changed the code I'll answer with it, but I am not sure it will solve your problem. – FMarazzi Jan 19 '16 at 13:24
  • I haven't set up a proper debugging environment yet. The problem is that I am using OpenSTM32 IDE based on Eclipse and the debugging tools (OpenOCD) are pretty confusing with support of the STM32F7. I also have to admit that I am relatively new to STM32 programming. – deinoppa Jan 19 '16 at 15:16
  • I have now set up an debugging environment and there seems to be a problem with interrupt priorities. So my button ISR is always interrupted by another interrupt (which i need for the DCMI interface) and therefore seems to hang. – deinoppa Jan 20 '16 at 11:04
  • 1
    You should post your solution and make it the accepted answer so people don't waste time reading this. – Tut Jan 20 '16 at 15:37

2 Answers2

9

Update: I found the mistake. The SysTick interrupt priority was set to the lowest (15), so calling HAL_Delay() from an ISR with the same or higher priority caused an infinite loop in the HAL_Delay function.

So, take care: If you are using the default HAL settings provided by ST, the priority for SysTick IRQ is set to 15 when calling HAL_Init(). You have to change that in the stm32f7xx_hal_conf.h file or by using the HAL_InitTick(TickPriority) function.

Here is what the HAL documentation of HAL_InitTick says about that issue:

Care must be taken if HAL_Delay() is called from a peripheral ISR process, The the SysTick interrupt must have higher priority (numerically lower) than the peripheral interrupt. Otherwise the caller ISR process will be blocked. The function is declared as __weak to be overwritten in case of other implementation in user file.

deinoppa
  • 179
  • 1
  • 2
  • 10
1

Assuming that the code isn't getting stuck in the ISR (by your last statement, that seems unlikely), the code is not clearing the interrupt flag inside of the interrupt service routine. When ISR exits, the microcontroller will "see" that the interrupt flag is still set, and immediately jump back to interrupt service routine.

You need to clear the interrupt flag inside of the interrupt service routine. I'm not familiar enough with the STM32 and the development environment to tell you exactly how to clear interrupt flag, but the interrupt flag needs to be cleared inside of the ISR.

CHendrix
  • 1,387
  • 9
  • 19