Electronic – Handling multiple interrupts dsPIC

bufferinterruptsmicrocontrollerpicuart

I have been thinking about my design for a while but couldn't figure out a better way to deal with buffer overrun in multiple interrupts.

A dsPIC33EP chip is connected to a TFT display, a UART sensor, a micro-SD card and a UART camera. The baudrate of the UART sensor is 921600 and the camera (50k per pic) is 57600. The SD card sector write (512 bytes) time is a little bit less than 2ms. The screen (EVE FT800) takes 20ms to update.

The goal is to respond to the UART sensor (at least every 30ms) and update screen accordingly (update labels) and at the same time write pictures into the SD card.

To break down the task, I have successfully saved multiple pictures to the SD card using interrupts when only camera and SD card are running.

The interrupt routine:

volatile unsigned char buff[512];
volatile unsigned int ptr=0;
volatile unsigned char EOF=0;
volatile unsigned char buffReady=0;
void ISR(){
    static unsigned char temp;
    temp=UART_Read();
    buff[ptr++]=temp;
    if(ptr==512){ptr=0;buffReady=1;}
    if(...){EOF=1;}
}

While the program is stuck in a loop to check EOF flag

while(1){
   if(buffReady){SD_Write_Sector(buff);buffReady=0;}//write 512 bytes of image to SD card
   if(EOF){break;}//jump out if the image has been finished
}

My concern is, how do I incorporate the routines to update the screen while receiving data from the UART sensor? It looks like the buffReady flag must be checked constantly. Any delay between each check may lose couple bytes since they are overwritten with new bytes.

Since the picture size is around 50K and the baudrate is 57600, there will be six bytes coming from the camera every millisecond. If the screen introduces a 20ms delay in between, the picture will sure be corrupted.

I thought about using a larger buffer to store pictures but larger buffer needs more time to be written to the SD card.

How should I arrange update screen and write image to SD card?

Best Answer

The dsPIC33EP provides a DMA interface to the UART (see chapter 8 of the datasheet). If you configure a buffer large enough for 20ms of data, you can configure the DMA to write into that buffer and then read the results between screen updates. Note that: $$ 57,600~bps \cdot 0.02~sec = 1152~bits = 144~bytes $$ If you are using SPI to write to the SD card, DMA can also be used there to limit the CPU load during the larger writes (the driver might already have built-in DMA support).

Alternatively, you could perform the actual buffer read in the interrupt (instead of polling for a flag). This is a bad idea in most cases, however, for multiple reasons:

  • As little code as possible should be placed in interrupts, to reduce system latency;
  • It depends on the method being used to drive the display, but it is likely that read interrupts received during a screen refresh will result in visual glitches;
  • Function calls from within interrupts are rarely a good idea--they typically increase the pre- and post-interrupt code written by the compiler (to save off registers, etc.), and introduce opportunities for deadlock that would be more obvious with inline code.

In short, DMA is made for the situation you describe. It is usually a painful process to set up and debug multiple DMA transfers, but it will allow clean display refreshes due to the longer reads and writes without CPU intervention.