Electronic – PIC18 USART Interrupt for reception, doesn’t trigger

cinterruptspicuart

I have set up the Enhanced USART module for a PIC18F4331 and have been trying to do a loop test. I am using MPLABX, programming in XC8, using Pickit3 for debugging and monitoring serial pins with an oscilloscope.

Without going into much detail, this is basically what I am doing:

1) In the main function, USART is transmitting values (solely for debugging)
2) Receiver Interrupt is set, when triggered it stops transmitting and jumps to ISR

This is what happens when I connect TX to RX:

1) USART transmits fine.
2) The Rx register receives a byte and sets flag RCIF after the first STOP bit, but the ISR does not trigger. Therefore the RX register overruns because it hasn't been read. The program does not go in the ISR at all.

I am thinking that the problem might be that it may not be possible to trigger an interrupt by receiving a byte while USART is transmitting? They are independent though so I don't understand why I couldn't do it.

My code:

int main(int argc, char *argv[]) {

//***********************Initializing Values****************************//
unsigned int ResultADC, FLAG; 
unsigned char temp, idle; //High Byte result store, 8bits long

//***********************ADC and SPI Settings****************************//

Initialize_control();    //Initialize Control Configuration Pins
InitializeADC();         //Initialize ADC in Continuous Mode
USART_initialize();      //Initialize USART module
InitializeMasterSPI();   //Initialize SPI module

//***********************ADC Capture and Output to SPI******************//

  while(1){             //While ADC buffer has something

    //Enable transmission
     TXREG = 0xff; //Debugger

     while(!TXSTAbits.TRMT);//wait while TSR is full

     TXREG = 0x0; //Debugger

     while(!TXSTAbits.TRMT);//wait while TSR is full

  }
  return 0;
}

//////////////////INTERRUPT SERVICE ROUTINE/////////////////

static void interrupt isr(void){

//Disable Interrupt
PIE1bits.RCIE  = 0;

int count;

//Read USART data
//PIR1bits.RCIF;//Data has been passed to RCREG
RX_Data[count] = RCREG; //Read RX register
count++;
//Reading RX_data clears RCIF, how to read more than 1 byte?

if (count==3){
    //Use data for control
    Control_Arduino(RX_Data);
    count = 0;
}

PIE1bits.RCIE  = 1;
}

//**********************Functions****************************//

void USART_initialize(void){

//Configuration TX and RX pins
TRISCbits.RC6 = 0; //TX output
TRISCbits.RC7 = 1; //RX input

//TXSTA: Transmit Status and Control Register
TXSTAbits.SYNC = 0; //Asynchronous mode
TXSTAbits.TX9 = 0; //8bit transmission
TXSTAbits.BRGH = 1; //Set HIGH Baud rate
TXSTAbits.TXEN = 1; //Enable transmitter
TXSTAbits.SENDB = 0; //Disable break

//RCSTA: Receive Status and Control Register
RCSTAbits.SPEN = 1; //Serial Port enabled
RCSTAbits.RX9 = 0; //8bit reception
RCSTAbits.CREN = 1; //Enables Receiver

//Test bits
//    RCSTAbits.FERR = 0; //No framing error, cleared by reading
//    RCSTAbits.OERR = 0; //No Overrun error, cleared by clearing CREN
                      //Disable receiver CREN 0

//BAUDCON Control register
BAUDCONbits.BRG16 = 1;  //16bit baud rate generator
SPBRG = 0xCF;           // Set to 19200 baud rate, 12Mhz, High Speed, BRG16
//Test bits
//    BAUDCONbits.RCIDL = 0; //Receive in progress

// USART interrupts configuration
RCONbits.IPEN   = 1; // ENABLE interrupt priority
INTCONbits.GIE  = 1; // ENABLE interrupts
INTCONbits.PEIE = 1; // ENable peripheral interrupts.
PIE1bits.RCIE   = 1; // ENABLE USART receive interrupt
PIE1bits.TXIE   = 0; // disable USART TX interrupt

}

Best Answer

Every processor has its own special interrupt-handling quirks.

Microchip's PIC18F4331 page has links to an errata document and the PIC18F4331 datasheet. In particular, the datasheet has some good tips in section 20 "Enhanced universal synchronous asynchronous receiver transmitter (EUSART)" and even more particularly, the 3 steps listed in section 20.0 and the 10 steps of "To set up an Asynchronous Reception" in section 20.3.2.

I've changed a few things that look like they might help:

// WARNING: untested code
int main(void){

//***********************Initializing Values****************************//
unsigned int ResultADC, FLAG; 
unsigned char temp, idle; //High Byte result store, 8bits long

//***********************ADC and SPI Settings****************************//

Initialize_control();    //Initialize Control Configuration Pins
InitializeADC();         //Initialize ADC in Continuous Mode
USART_initialize();      //Initialize USART module
InitializeMasterSPI();   //Initialize SPI module

//***********************ADC Capture and Output to SPI******************//

  while(1){             //While ADC buffer has something

    //Enable transmission
     TXREG = 0xff; //Debugger

     while(!TXSTAbits.TRMT);//wait while TSR is full

     TXREG = 0x0; //Debugger

     while(!TXSTAbits.TRMT);//wait while TSR is full

  }
  return 0;
}

//////////////////INTERRUPT SERVICE ROUTINE/////////////////

static void interrupt isr(void){
    // The PIC hardware has already disabled global interrupts
    // by the time it starts executing the ISR,
    // so there's no need to do "PIE1bits.RCIE  = 0;".

int count;

//Read USART data
//PIR1bits.RCIF;//Data has been passed to RCREG
RX_Data[count] = RCREG; //Read RX register
count++;
//Reading RCREG automatically clears the RX flag.
// so there's no need to do "PIR1bits.RCIF = 0;".
// Q: How to read more than 1 byte?
// A: FIGURE 20-5 of the datasheet
// Implies that there's only a 1 byte buffer.
// Therefore, to read more than 1 byte, we must:
// pull the current byte out of the hardware buffer,
// store it in a software buffer RX_Data[] in RAM,
// then return to normal background main loop
// until the next byte in the message
// triggers another interrupt.

// Would it be better to do the following in the main loop?
  if (count==3){
    //Use data for control
    Control_Arduino(RX_Data);
    count = 0;
  }

/*
The datasheet p. 229 is a little confusing about
whether "CREN" should be set (step 5) or cleared (step 9).
p. 219 which clearly seems to say CREN should be set.
But maybe it needs to be cleared to flush out any errors,
and then be set?
Are the following 2 lines really necessary?
*/
RCSTAbits.CREN = 0; //clear error (if any)
RCSTAbits.CREN = 1; //Enables Receiver

// the PIC hardware enables global interrupts
// automatically during the return-from-interrupt,
// so there's no need to do a "PIE1bits.RCIE  = 1;"
// See the datasheet section 10.0: "Interrupts" for details.

}

//**********************Functions****************************//

void USART_initialize(void){

//Configuration TX and RX pins
// *normally* we use a "0" to indicate "output",
// but the TX output pin is different, see p. 217 of datasheet
TRISCbits.RC6 = 1; //TX output
TRISCbits.RC7 = 1; //RX input

//TXSTA: Transmit Status and Control Register
TXSTAbits.SYNC = 0; //Asynchronous mode
TXSTAbits.TX9 = 0; //8bit transmission
TXSTAbits.BRGH = 1; //Set HIGH Baud rate
TXSTAbits.TXEN = 1; //Enable transmitter
TXSTAbits.SENDB = 0; //Disable break

//RCSTA: Receive Status and Control Register
RCSTAbits.SPEN = 1; //Serial Port enabled
RCSTAbits.RX9 = 0; //8bit reception
RCSTAbits.CREN = 1; //Enables Receiver

//Test bits
//    RCSTAbits.FERR = 0; //No framing error, cleared by reading
//    RCSTAbits.OERR = 0; //No Overrun error, cleared by clearing CREN
                      //Disable receiver CREN 0

//BAUDCON Control register
BAUDCONbits.BRG16 = 1;  //16bit baud rate generator
SPBRG = 0xCF;           // Set to 19200 baud rate, 12Mhz, High Speed, BRG16
//Test bits
//    BAUDCONbits.RCIDL = 0; //Receive in progress

// USART interrupts configuration
RCONbits.IPEN   = 1; // ENABLE interrupt priority
// (p. 4 of http://www.gooligum.com.au/tutorials/midrange/PIC_Mid_C_3.pdf )
ei(); // same as INTCONbits.GIE  = 1; // ENABLE interrupts
INTCONbits.PEIE = 1; // ENable peripheral interrupts.
PIE1bits.RCIE   = 1; // ENABLE USART receive interrupt
PIE1bits.TXIE   = 0; // disable USART TX interrupt

// make sure the RX flag is clear
    PIR1bits.RCIF = 0;
}

Other code online:

"AN944: Using the EUSART on the PIC16F688" http://www.gooligum.com.au/tutorials/midrange/PIC_Mid_C_3.pdf https://forum.sparkfun.com/viewtopic.php?t=7542 http://panteltje.com/panteltje/pic/scope_pic/ http://www.microchip.com/forums/m411875.aspx http://www.enmcu.com/guides/autobaudratebasedoneusartmodule

Tell us if you ever figure out the real problem, OK?