Jump to content
 
  • 0

Interrup with Mcc - Uart


ingbaker
 Share

Question

5 answers to this question

Recommended Posts

  • 0
  • Member

I think specifically we need to know what processor you are trying to use as this differs from device to device.

The simplest and most generic answer would be to add the UART to your project and click on the checkbox to enable interrupts for the driver. After generating code you will have to set the callback which you want called when the interrupt occurs. After this you need to make sure you are enabling interrupts in your main code and it should work.

If you supply us with the details above I will post some screenshots for you on how to do this.

Just to show you the idea I picked the 16F18875 and added the EUSART as follows:
image.png

You can see I clicked next to "Enable EUSART Interrupts"

Then in my main I ensured the interrupts are enabled.

image.png

When I now run the code the ISR created by MCC is executed every time a byte is received. The ISR function is called EUSART_Receive_ISR and it is located in the eusart.c file. You can edit this function or replace it by setting a different function as ISR by calling EUSART_SetRxInterruptHandler if you want to change the behavior.

 

  • Like 2
Link to comment
Share on other sites

  • 0

and in the eusart.c file there is another function "EUSART2_RxDataHandler" can you explain how this works?

void EUSART2_RxDataHandler(void){
    // use this default receive interrupt handler code
    eusart2RxBuffer[eusart2RxHead++] = RCREG2;
    
    if(sizeof(eusart2RxBuffer) <= eusart2RxHead)
    {
        eusart2RxHead = 0;
    }
    eusart2RxCount++;
}

and "EUSART2_Read"  function seems very complicated

uint8_t EUSART2_Read(void)
{
    uint8_t readValue  = 0;
    
    while(0 == eusart2RxCount)
    {
    }

    eusart2RxLastError = eusart2RxStatusBuffer[eusart2RxTail];

    readValue = eusart2RxBuffer[eusart2RxTail++];
    if(sizeof(eusart2RxBuffer) <= eusart2RxTail)
    {
        eusart2RxTail = 0;
    }
    PIE3bits.RC2IE = 0;
    eusart2RxCount--;
    PIE3bits.RC2IE = 1;

    return readValue;
}

 

Link to comment
Share on other sites

  • 0
  • Member

The two functions you see are both halves of a ring buffer driver.  The first function unloads the UART receive buffer and puts the bytes into the array eusart2RXBuffer.  This array is indexed by eusart2RXHead.  The head is always incremented and it rolls over when it reaches the maximum value.

This receiving function creates a basic ring buffer insert  that sacrifices error handling for speed.  There are four possible errors that can occur.

  1. UART framing error.  If a bad UART signal arrives the UART will abort reception with a framing error.  It can be important to know if framing errors have occurred, and it is critical that the framing error bit be cleared if it gets set.
  2. The UART receiver is overrun.  This happens if a third byte begins before any bytes are removed from the UART.  With an ISR unloading the receiver this is generally not a real threat but if the baudrate is very high, and/or interrupts are disabled for too long, it can be a problem.
  3. The ring buffer head overwrites the tail.  The oldest bytes will be lost but worse, the tail is not "pushed" ahead so the next read will return the newest data and then the oldest data.  That can be a strange bug to sort out.  It is better to add a check for head == tail and then increment the tail in that instance.
  4. This error is perhaps an extension of #3.  The eusart2RxCount variable keeps track of the bytes in the buffer.  This makes the while loop at the beginning of the read function much more efficient (probably 2 instructions on a PIC16).  However if there is a head-tail collision, the the count variable will be too high which will later cause a undetected underrun in the read function.

The second function is to be called from your application to retrieve the data captured by the interrupt service routine.  This function will block until data is available.  If you do not want to block, there are other functions that indicate the number of bytes available.

The read function does have a number of lines of code, but it is a very efficient ring buffer implementation which extends the UART buffer size and helps keep UART receive performance high.

That said, not all UART applications require a ring buffer.  If you turn off the UART interrupts, you should get simple polling code that blocks for a character but does not add any buffers.  The application interface should be identical (read) there will simply be no interrupt or buffers supporting the read function.

  • Helpful 1
Link to comment
Share on other sites

  • 0
  • Member
On 11/26/2019 at 7:15 AM, mehmetozdemir said:

and "EUSART2_Read"  function seems very complicated

I think with these drivers it always depends on what you need and if this is a good match for your requirements. If you say that this seems very complicated it sounds like this driver probrably is doing a lot more than you need, so my first question would be "what do you expect instead"?

I know N9WXU has talked to much of this already and also said it depends on whether you require a ring buffer. What I can offer you is what the thinking was for this implementation.

For this driver the requirements were:

  1. We have to be able to receive data on interrupt, this ensures we never miss any bytes due to data overrun (next byte received before prior byte is read out).
  2. The application does NOT want to process the data inside of the ISR, so we need to store the data temporarily
  3. We need to be able to store multiple bytes, which means we may have 7 or 8 interrupts before we process the data. This means the application can safely take much longer to process the data before we lose data.

If you serial port is running 115200 it means one character arrives every 87us. If we have a buffer of 16 bytes it means we only need to service the serial port at least once every 1.4ms to be sure we never lose any data, this extra time can be very important to us, and we can make the buffer bigger to get even more time.

If this matches your situation you need to do the following.

In the ISR you need to:

1. Store the data in a temp buffer

 // use this default receive interrupt handler code
    eusart2RxBuffer[eusart2RxHead++] = RCREG2;

2. Handle wrapping of the buffer when you reach the end of the array

    if(sizeof(eusart2RxBuffer) <= eusart2RxHead)
    {
        eusart2RxHead = 0;
    }

3. And keep track of how many bytes we have ready for processing

    eusart2RxCount++;

 

When the app processes the data you need to:

1. If you try to read 1 byte before the data is available you need to wait until there is something to read 

    uint8_t readValue  = 0;
    
    while(0 == eusart2RxCount)
    {
    }

2. Remove one byte from the ring buffer and again handle the wrapping at the end of the array

    readValue = eusart2RxBuffer[eusart2RxTail++];
    if(sizeof(eusart2RxBuffer) <= eusart2RxTail)
    {
        eusart2RxTail = 0;
    }

3. Reduce the number of bytes in the buffer by one (we need to disable the ISR or a collision can happen here), and then return the retrieved byte

    PIE3bits.RC2IE = 0;
    eusart2RxCount--;
    PIE3bits.RC2IE = 1;

    return readValue;

 

I think this is kind of as simple as you can ever do this without reducing the functionality. 
 

Of course if you just wanted to without interrupts read the single byte all you need is to return RCREG,  which BTW is what you will get if you uncheck the interrupt checkbox. Also if you do not like all of the ring buffer stuff you can enable interrupts and replace the ISR with the same thing you get when you do not need a buffer, then it is simpler but more likely to lose data.

 

PS. I did not describe the eusart2RxLastError line as I cannot see all the code for that here and I cannot remember the details about that one line. What it is doing is updating a global (eusart2RxLastError) to indicate if there was any error. From the looks of this code snippet that part of the code may have some bugs in it as the last error is not updated after the byte is read out, but I may just be missing the start of the ISR ...
 

 

 

  • Helpful 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

 


×
×
  • Create New...