2
\$\begingroup\$

I have PIC16F628A that I am trying to have read from UART. Without interrupts, it reads the first 3 bytes fine but hits an OERR. To combat this, I thought an interrupt would be good and load any received bytes into a buffer variable that could be read in later (ring buffer of array type char). But the interrupt is not triggering and I've run out of ideas.

CMCON = 0x07;           //16F627/8 spcial function reg (RAx is port)
CCP1CON = 0b00000000;   //Capt/Comp/PWM off

OPTION_REG = 0b00000000;

T1CON = 0;
INTCON = 0;
PIR1 = 0;
GIE = 0;

PIE1 = 0;

BRGH = 1;   /* high baud rate */
SPBRG = 19200;  /* set the baud rate */

SYNC = 0; //Async
TXEN = 0; //Disable transmit
TXIE = 0; //Disable transmit interrupt
RCIE = 1; //Enable Receive interrupt
SPEN = 1; //Enable serial pins
CREN = 1; //Enable continuous receive
SREN = 0;
TX9  = ninebits?1:0;    /* 8- or 9-bit transmission */
RX9  = ninebits?1:0;    /* 8- or 9-bit reception */

PEIE = 1; //Enable external interrupt
GIE = 1; //Enable global interrupt

I have simplified my interrupt to turning on a light:

extern interrupt isr(void)
{
    RB5 = 1;
}

But it's not triggering. The project is reading a barcode scanner over serial and processing the barcode. Can anyone offer some assistance?

EDIT

Ok since you don't seem to understand. I'm going to post the actual routines:

void initialize()
{
    CMCON = 0x07;           //16F627/8 spcial function reg (RAx is port)
    CCP1CON = 0b00000000;   //Capt/Comp/PWM off

    OPTION_REG = 0b00000000;

    T1CON = 0;
    INTCON = 0;
    PIR1 = 0;
    GIE = 0;
    PEIE = 0;
    PIE1 = 0;

    sci_Init(BAUDRATE ,SCI_EIGHT);// Baud set and Bit set

    TMR0 = 1000;
    T0IE = 0;
    PEIE = 1; //Enable external interrupt
    GIE = 1; //Enable global interrupt

    //Set inputs to input
    SetButtons();

    //Set relays to output
    SetRelays();

    TRISB5 = 0;

    LEDStatus = 0;
}

unsigned char sci_Init(unsigned long int baud, unsigned char ninebits)
{
    int X;
    unsigned long tmp;

    /* calculate and set baud rate register */
    /* for asynchronous mode */
    tmp = 16UL * baud;
    X = (int)(FOSC/tmp) - 1;
    if((X>255) || (X<0))
    {
        tmp = 64UL * baud;
        X = (int)(FOSC/tmp) - 1;
        if((X>255) || (X<0))
        {
            return 1;   /* panic - baud rate unobtainable */
        }
        else
            BRGH = 0;   /* low baud rate */
    }
    else
        BRGH = 1;   /* high baud rate */
    SPBRG = X;  /* set the baud rate */

    SYNC = 0; //Async
    TXEN = 0; //Disable transmit
    TXIE = 0; //Disable transmit interrupt
    RCIE = 1; //Enable Receive interrupt
    SPEN = 1; //Enable serial pins
    CREN = 1; //Enable continuous receive
    SREN = 0;
    TX9  = ninebits?1:0;    /* 8- or 9-bit transmission */
    RX9  = ninebits?1:0;    /* 8- or 9-bit reception */

    rxBuffIndex = 0;
    rxBuffRead = 0;

    return 1;
}

void sci_LoadBuffer(void)
{
    rxBuffer[rxBuffIndex] = RCREG;

    rxBuffIndex = ++rxBuffIndex % MAXBUFFER;
}

unsigned char sci_ReadBuffer()
{
    unsigned char byte;

    do
    {
        byte = rxBuffer[rxBuffRead];
    }while( byte == 0 ); //Block until valid data

    rxBuffer[rxBuffRead] = 0;
    rxBuffRead = (++rxBuffRead) % MAXBUFFER;

    return byte;
}

void interrupt isr(void)
{
    if(RCIF) sci_LoadBuffer();
    LEDStatus = 1;
}

I know that's not EVERYTHING but that should be enough to diagnose why the interrupts aren't triggering. THAT'S ALL I NEED! Triggering the interrupts.

I'm using MPLab with Hi-Tech C Compiler. Which from the manual automatically saves state and restores it when entering/exiting the interrupt.

\$\endgroup\$
  • \$\begingroup\$ My real interrupt function: void interrupt isr(void) { if(RCIF) sci_LoadBuffer(); LEDStatus = 1; } void sci_LoadBuffer(void) { rxBuffer[rxBuffIndex] = RCREG; rxBuffIndex = ++rxBuffIndex % MAXBUFFER; } \$\endgroup\$ – Teagan Jul 29 '11 at 21:37
  • \$\begingroup\$ Sorry about the formatting... \$\endgroup\$ – Teagan Jul 29 '11 at 21:49
  • \$\begingroup\$ formatting fixed. \$\endgroup\$ – tcrosley Jul 29 '11 at 22:35
  • \$\begingroup\$ I'm not familiar with PICs, but many of these kinds of devices also have a global interrupt mask somewhere, and sometimes within the CPU core itself there are global enable/disable controls for interrupts. Of course if you are able to get interrupts from other sources then that shoots that theory. Something to think about. \$\endgroup\$ – JustJeff Jul 31 '11 at 2:56
  • \$\begingroup\$ There are many possible sources of problems. A stack overflow, timing problems, TRISxx set wrongly, wrong Baudrate (SPBRG = 19200 looks odd), etc... Can you break and post a dump of the SFRs? \$\endgroup\$ – AndreKR Oct 8 '11 at 1:45
2
\$\begingroup\$

TRISB1 needs to be set to 1 to configure RB1 (RX) as an input. I'm not sure what the default is, so it may be ok.

You need to clear the receive interrupt flag (RCIF) by reading the receive register (RCREG). In addition, since the receive register is doubled-buffered, you may need to read it more than once.

So your interrupt routine needs to look more like this:

extern interrupt isr(void)
{
    while (RCIF)
    {
        char ch;

        RB5 = 1;
        ch = RCREG;    // normally would go into an array and increment a counter
    }
}

I don't know if that is your only problem, since you indicate you are not getting into the interrupt routine at all. But the above is the correct way to read the characters out of the receive buffer.

======================================

EDIT:

Don't know if this will help or not, but in this post, before enabling interrupts, the code clears out the FIFO first. (Their code also clears out the RCIF flag, but since it is readonly on your chip, that isn't needed.)

ch = RCREG;    // clear FIFO  
ch = RCREG;
ch = RCREG;

// then enable interruupts ...
\$\endgroup\$
  • \$\begingroup\$ I mentioned that I was able to get characters out of the receive buffer without interrupts using same sort of code: unsigned char sci_GetByte() { while(!RCIF) continue; //Block until data in return RCREG; } My problem is trying to get interrupts to trigger \$\endgroup\$ – Teagan Jul 29 '11 at 21:41
1
\$\begingroup\$

Ok, two things.

First, within your interrupt routine, you usually have to clear the IF flag RCIF to enable the interrupt to fire again.

That's not the reason the interrupt's not firing at all though.

The problem with your code is that you are defining a function as an interrupt - which is fine - that causes the compiler to push things to the stack for you automatically, and pop them off after the routine is over. It also terminates the function with a "return from interrupt" command instead of a simple "return" command.

What it doesn't do is link the function into the interrupt vector. There is usually only a small amount of space around the interrupt vector area, so it is normal to place a goto at the address of the interrupt vector which calls the name of your interrupt routine.

Depending on your compiler there are a number of ways of doing this. I suggest you read the manual for your compiler about interrupt vectors and the sample code for it.

\$\endgroup\$
1
\$\begingroup\$

I didn't read all of your long post, but happend to notice this on skimming:

extern interrupt isr(void)
{
    RB5 = 1;
}

This is definitely wrong. I don't know what the interrupt condition is, but you're not clearing it. The processor will get hung on the first interrupt because it will re-enter the interrupt routine immediately after it completes because the interrupt condition is still active.

\$\endgroup\$
  • \$\begingroup\$ Don't most modern PICs automatically clear the interrupt condition? I haven't worked with PIC16s, but this seems like an unnecessary burden to place on the programmer. At the very least, this code could be automatically generated by the compiler... \$\endgroup\$ – Kevin Vermeer Jan 5 '12 at 17:03
  • 1
    \$\begingroup\$ @Kevin: No, the processor entering the interrupt routine does not clear the interrupt condition on a PIC or any other processor I've ever looked at. It does temporarily disable interrupts, but those get re-enabled at the end of a normal interrupt routine. On a PIC 16, this is done with the RETFIE instruction. No, you don't want a compiler doing this for you. In some cases it's important to clear the interrupt condition in the right sequence with other interactions with the device. \$\endgroup\$ – Olin Lathrop Jan 5 '12 at 17:16
  • \$\begingroup\$ Interesting; the TI DSP that I've recently been working with and the Cortex-M3 that I worked with before that automatically cleared the interrupt flag. I seem to recall that there were options to disable this functionality, though... \$\endgroup\$ – Kevin Vermeer Jan 5 '12 at 17:33
  • \$\begingroup\$ @Kevin: Are you sure the interrupt flag for the specific peripheral was cleared, or just some general flag set on the leading edge of any interrupt? \$\endgroup\$ – Olin Lathrop Jan 5 '12 at 18:13
  • \$\begingroup\$ The MSP430 also automatically clears interrupt flags that have a single source and in addition it clears for example the UART transmit interrupt when the transmit buffer is written. \$\endgroup\$ – AndreKR Jan 5 '12 at 19:22
0
\$\begingroup\$

Have you tried looking at the RS-232 signal on a scope to see if the baud rate is correct? Try transmitting a few characters from the PIC to make sure the UART has the right baud rate setting.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.