Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC UART stops responding to messages if I send them too fast, doesn't recover

Status
Not open for further replies.

Triode

Well-Known Member
I know this isn't enough to cover the entire range of things that could be going wrong, but for now I'm just trying to figure out one detail that perplexes me. Given that this receive interrupt can get messages too quickly and jam up, why won't it unjam itself when they slow down? I'm sure it's something simple I've missed.

I was using the 9th address bit but to try to solve this problem where it drops out and quits responding I decided to just use numbers 0<n<24 as addresses, since I only need a few commands. I suspected lag in LabVIEW's serial visa changing the number of bits, but that seems not to have been the case.

Code:
[CODE]//Inside interrupt routine

if(PIR1bits.RCIF == 1)
    {

            if(DataRdyUSART())
            {
               
                MessageChar = ReadUSART();
                //designate that values under 24 are addresses, 0 is blank
                if(MessageChar < 24 && MessageChar > 0) //is address
                {
                    if(MessageChar == MyAddress)//is my address
                    {
                        Addressed = 1;
                        LATB4 = 0;
                    }
                    else //is not my address
                    {
                        Addressed = 0;
                        LATB4 = 1;
                    }
                }
                else //is data
                {
                    if(Addressed == 1 && MessageChar >= 24)//is my data range 24 to 254
                    {
                            MessageBuffer[i] = MessageChar; //read the byte from rx register
                            i++;
                            if(i >= 200) i = 0;//make it a cyclic buffer
                    }
                }   

                PIR1bits.RCIF = 0; // clear rx flag
            }
    }

Oddly, it runs fine if I send messages at less than 2 per second, this is at 19200 baud, and they're coming from a labview serial VISA over RS 485. If I start sending them faster it quits responding. But the reason it jams up isn't what I'm confused about so much as WHY it won't UNJAM itself. That is, once it stops responding it does not start again even if I slow the messages way down.

To use the commands we have this in Main
Code:
    while(1) //infinite loop
    {
        for(j = 0; j < 200; j++)//scan entire buffer
        {
            if(MessageBuffer[j] != 0)
            {
                //process the commands
                  {...}
             MessageBuffer[j] = 0;// clear the message that was just read
            }
        }

I know this is a rather simplistic scheme, but I couldn't get it to stop ceasing to respond to commands, so I kept making it simpler. I have an LED for a heartbeat that confirms that the processor is still running. This is concerning because while I can have it send a confirmation and re-send a missed message, there's not much I can do if it's going to drop off and just quit listening forever.

I can add more detail as needed, I just didn't want to flood this with the entire project.

Thanks for any help!
 
It might have a overrun error.
Add this to the ISR for the uart.
Code:
if(PIR1bits.RCIF == 1)
    {
        if (RCSTA1bits.OERR) {
            RCSTA1bits.CREN = LOW; // clear overrun
            RCSTA1bits.CREN = HIGH; // re-enable
        }
.....

There no need for if(DataRdyUSART()) (the interrupt means it has data) or to clear the flag with PIR1bits.RCIF = 0; // clear rx flag. Reading the UART data auto clears the flag with MessageChar = ReadUSART();.
 
Thanks. I actually just figured out that I had to do that to clear the overflow bit. Then I was looking for the cause of the overflow. Oddly without removing all the other interrupts it was not able to keep up. One was just a timer interrupt that blinks a light at 1 Hz and the other was to turn off the transmit buffer when empty, and since I wasn't sending any messages it should have been off most of the time. I'll have to check if those are triggering more often than I expected for some reason. For now it's able to take 1000 8-bit commands per second without jamming, so it's a big improvement. Eventually I'll need to put the transmit disable interrupt back in without slowing it down too much. But I suspect it was just running all the time or something.

This was the other stuff in the ISR, I'll probably just move it to a separate, low priority ISR

Code:
    //check if interrupt is from timer 0
    if(INTCONbits.TMR0IF == 1)
    {
        //LATB4 = ~LATB4;//Blink the active LED TEMP disable heartbeat LED
       
        INTCONbits.TMR0IF = 0;//clear flag
        WriteTimer0(0xE17B); //use HEX
      
    }
   
    //interrupt from transmitter
    if(PIR1bits.TXIF == 1)//transmit buffer is empty
    {
        LATD4 = 0;//disable transmit
    }
 
I suspect it might have been the TXIF flag.

I usually implement a small FIFO ring buffer for transmit (receive too) for data flow abstraction (load and go) and control it with the enable bit. (9 bit example)
Code:
/* isr snip */
    if (PIE1bits.TX1IE && PIR1bits.TX1IF) { // send data to USART
        if (ringBufS_empty(L.tx1b)) { // buffer has been sent
            if (TXSTA1bits.TRMT) { // last bit has been shifted out
                PIE1bits.TX1IE = LOW; // stop data xmit
            }
        } else {
            ct1 = ringBufS_get(L.tx1b); // get the 9 bit data from 16 bit data buffer
            TXSTA1bits.TX9D = (ct1 & 0b100000000) ? HIGH : LOW;
            TXREG1 = ct1; // send data and clear FLAG
            V.c1t_int++;
        }
    }
....
/*
* start the tx usart running from user context
* return TRUE if it's already enabled
*/
int8_t start_tx1(void)
{
    int8_t tx_running = LOW;

    if (PIE1bits.TX1IE) tx_running = HIGH;
    PIE1bits.TX1IE = HIGH;
    PIR1bits.TX1IF = HIGH;
    return tx_running;
}
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top