2017-03-09 04:34 AM
Hi to all,
I am developing a graphic driver that handle 2 LCD over the SPI1 port and different CS lines. I setup a frame renderer tat renders 128 scanlines made of 160 pixels. A frame rendering can be launched by the TIM3 IRQ set to a frequency of 25Hz.
Every scanline is rendered and then passed to the DMA that drives the SPI. In this way the engine sends the scanline to the LCD while rendering the next line. Of course I have set a double buffering system to prevent a conflict while accessing to buffers.
Now, when there is graphics on one LCD only no problems. but when both LCD need to show graphics the DMA should transfer one scanline to one LCD and after that select the second and transfer the other scanline.
In order to do that I thought to take advantage of the Transfer complete interrupt, and switch the CS lines of the LCD. Now problems come. The TC interrupt occurs only after the frame renderer interrupt.
Let's say that one frame is called every 40ms, the TC of the DMA is fired every 40ms, while it's evident that the transfer takes much less. I tried to change the NVIC settings to change the priorities but no luck. TIM3 always wins versus the DMA. so only one display is refreshed.
If I set the Systick IRQ to count milliceconds and trig the frame rendering everything works perfectly, the TC of the DMA is called perfectly and the two scanlines are sent to the LCDs while the engine renders scanlines to the buffers.
Is there something I am missing?
Both display driven by the Systick, DMA, SPI:https://www.youtube.com/watch?v=K99M4i-i_yo
Thanks
#timers #lcd #dma #spi #stm32f4072017-03-09 06:09 AM
I don't quite get it. Are you trying to fire the DMA TC interrupt while still within the TIM3 interrupt service routine?
JW
2017-03-09 06:36 AM
Uhm yes, the TIM3 IRQ handler calls the functioon 'Render_Layer', where a cycle renders all the scanlines. After a scanline is rendered and ready in the buffer the DMA is setup and the SPI DMA command is triggered...
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
{
// Reset the counter compare flag.
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
if (gRender)
LCD_Render_Layers(gLayersToRender);
gVerticalRefresh = FALSE;
} // End if.
} // End TIM3_IRQHandler.
The renderer, after filling the buffer, trigs the DMA like:
...
// Send the scanline to the LCD.
DMA_DeInit(LCD_DMA_STREAM);
gDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)gLCD[gLCDTransmit].line_buffer[gLCD[gLCDTransmit].transmit_buffer];
gDMA_InitStructure.DMA_BufferSize = gLCD[gLCDTransmit].line_buffer_length;
DMA_Init(LCD_DMA_STREAM, &gDMA_InitStructure);
DMA_ITConfig(LCD_DMA_STREAM, DMA_IT_TC, ENABLE);
LCD_Area_Set(gLCDTransmit, 0, lScanline, gLCD[gLCDTransmit].width, 1);
LCD_A0_HIGH();
SPI_I2S_DMACmd(gLCD[gLCDTransmit].port.port, SPI_I2S_DMAReq_Tx, ENABLE);
DMA_Cmd(LCD_DMA_STREAM, ENABLE);
Is there a problem if the DMA is triggered from within the IRQ handler? How can I solve this?
Thanks.
2017-03-09 06:54 AM
Posted on March 09, 2017 at 15:54
<LINK NO LONGER ACTIVE>
Might give you a richer mecanism when trying to drive 2 SPI Slaves with same or multiple SPIs.
The mecanism is full under interrupt, the user function only needs to kickstart and poll or get calledback.
2017-03-09 08:24 AM
Uhm, unfortunately my slaves are LCDs that don't send any data back. But yes, maybe a FSM could drive the CS lines of the LCDs. The problem is that I need to send line buffers to their corresponding LCDs that share the same SPI, so they must be selected in sequence as soon as the DMA finishes to send data. I need to take advantage of the rendering time.
I can't understand why if I trig the DMA and SPI from the Systick Interrupt handler everything works. Of course if I manually set the priority of the Systick IRQ to the same value of the DMA IRQ the effect is the same as the Timer does. I believe there might something with NVIC and priorities but I can't get it.
2017-03-09 02:12 PM
Of course if I manually set the priority of the Systick IRQ to the same value of the DMA IRQ the effect is the same as the Timer does.
Then do the 'inverse': set manually the priority of the timer IRQ to the same value as the priority of Systick IRQ is.
You are aware of the grouping of interrupt priorities, aren't you? PM0214 rev.3, 2.3.6 Interrupt priority grouping
I am not going to comment on the general design of your software.
JW
2017-03-10 08:32 AM
Oh, you are right, I forgot to think about the groups... I just configured it and changed the priorities as needed... now it works! Thank you for the suggestion!