2023-01-22 12:32 PM
In an attempt to find a problem with the DMA2D causing display issues (random pixels showing), I have turned on the interrupt handler DMA2D_IRQHandler() with the following code to allow me to halt debugging inside the routine when needed:
void DMA2D_IRQHandler()
{
if(DMA2D->ISR == 0) {
// Set breakpoint here to observe
// interrupts with ISR = 0
return;
}
// Is this just a regular transfer-complete
// interrupt?
if(!(DMA2D->ISR & ~DMA2D_ISR_TCIF)) {
// Apparently the transfer-complete
// trigger has to be turned off as
// otherwise another IRQ will be
// triggered with ISR = 0 once the
// corresponding trigger gets
// turned off in the IFCR.
DMA2D->CR &= ~DMA2D_CR_TCIE;
// Clear interrupt register for transfer-
// complete interrupt
DMA2D->IFCR |= DMA2D_IFCR_CTCIF;
return;
}
// Set breakpoint here to observe
// unexpected DMA2D interrupts
// other than "transfer complete".
return;
}
I am using a custom board with an STM32H745. Spurious triggers with ISR = 0 may or may not occur (I have not found a way to trigger this consistently and reproducibly). It appears to be related to when code is executed upon an external trigger via EXTI0, EXTI1, EXTI2, EXTI3, or EXTI9_5.
I took measures to prevent the DMA2D to be called while it is still active:
// Wait for a potentially ongoing transfer to finish
while(DMA2D->CR & DMA2D_CR_START) {}
// set DMA2D registers (not all details shown)
DMA2D->OOR = ...
DMA2D->BGOR = ...
DMA2D->FGOR = ...
DMA2D->NLR = ...
DMA2D->OMAR = ...
DMA2D->BGMAR = ...
DMA2D->FGMAR = ...
DMA2D->FGCOLR = ...
DMA2D->OPFCCR = DMA2D_OUTPUT_MODE;
DMA2D->FGPFCCR = 0xFF000000 |
(DMA2D_COMBINE_ALPHA <<
DMA2D_FGPFCCR_AM_Pos) |
DMA2D_INPUT_A8;
DMA2D->BGPFCCR = (DMA2D_NO_MODIF_ALPHA <<
DMA2D_BGPFCCR_AM_Pos) |
DMA2D_INPUT_MODE;
// Turn on all DMA2D interrupt types and initiate
// blended memory-to-meory transfer
DMA2D->CR = DMA2D_CR_CEIE | DMA2D_CR_CTCIE |
DMA2D_CR_CAEIE | DMA2D_CR_TWIE |
DMA2D_CR_TCIE | DMA2D_CR_TEIE |
DMA2D_M2M_BLEND | DMA2D_CR_START;
// Wait for transfer to finish
while(DMA2D->CR & DMA2D_CR_START) {}
None of the above safety measures help preventing spurious DMA2D interrupt triggers. I have the suspicion that the DMA2D gets called by something without the DMA2D registers properly set, leading to the garbled LCD display.
What could be causing spurious DMA2D IRQ triggers?
For completeness sake, here are my interrupt settings:
void CM7InterruptPriorities(void) {
// DMA interrupts:
NVIC_SetPriority(DMA1_Stream0_IRQn, 1);
NVIC_EnableIRQ(DMA1_Stream0_IRQn);
// DMA2D interrupts:
NVIC_SetPriority(DMA2D_IRQn, 2);
NVIC_EnableIRQ(DMA2D_IRQn);
// Switch Driver:
// Timer 2 and 3 are used for debouncing switches 1 and 2, respectively
NVIC_SetPriority(TIM2_IRQn, 3);
NVIC_EnableIRQ(TIM2_IRQn);
NVIC_SetPriority(TIM3_IRQn, 3);
NVIC_EnableIRQ(TIM3_IRQn);
// Priorities for external interrupts (actuation of switches or encoders)
NVIC_SetPriority(EXTI0_IRQn, 4);
NVIC_EnableIRQ(EXTI0_IRQn);
NVIC_SetPriority(EXTI1_IRQn, 4);
NVIC_EnableIRQ(EXTI1_IRQn);
NVIC_SetPriority(EXTI2_IRQn, 4);
NVIC_EnableIRQ(EXTI2_IRQn);
NVIC_SetPriority(EXTI3_IRQn, 4);
NVIC_EnableIRQ(EXTI3_IRQn);
NVIC_SetPriority(EXTI9_5_IRQn, 4);
NVIC_EnableIRQ(EXTI9_5_IRQn);
// Menu Driver (misc):
NVIC_SetPriority(TIM4_IRQn, 5);
NVIC_EnableIRQ(TIM4_IRQn);
NVIC_SetPriority(TIM5_IRQn, 6);
NVIC_EnableIRQ(TIM5_IRQn);
NVIC_SetPriority(HSEM1_IRQn, 7);
NVIC_EnableIRQ(HSEM1_IRQn);
NVIC_SetPriority(TIM15_IRQn, 8);
NVIC_EnableIRQ(TIM15_IRQn);
}
I've been trying to debug this for days but have no idea how to proceed. Some help steering me in the right direction would be greatly appreciated.