AnsweredAssumed Answered

9S12A256 SCI, RDRF Not Triggering Receive Interrupt During Transmission?

Question asked by Peter Lacerenza on Apr 22, 2014
Latest reply on Apr 23, 2014 by Peter Lacerenza

I'm writing code for a project using the 9S12A256 microcontroller, and it is expected to have some serious traffic IN (RX) to an SCI port, and some minimal traffic OUT (TX) from the same SCI port.  For various reasons, I want the serial receive, at minimum, to be interrupt-driven.


The problem I'm having is that while I am transmitting data, received data does not trigger an interrupt, despite the RDRF flag going high and the RIE==1 at all times after initialization.  If I am not transmitting anything, receive works perfectly.  If bytes come in while I'm mid-transmission, or I start transmission mid-receive, RDRF flag goes high but does not trigger an interrupt until after all transmission is complete from the serial port.

I found Errata from some time ago that specified an even number of interrupt requests did not trigger an interrupt at one time (I presume it's been taken care of in hardware already a long time ago, but better safe than sorry), so I am intentionally only setting up interrupts for receive for my testing.


The code I'm testing has a real time interrupt (1ms interval) counting down delay timer(s), a SCI receive interrupt, and main with initialization code for I/O and a for(;;) loop that checks/sets a delay timer decremented in the real-time interrupt.

The for(;;) loop in main consistently checks every loop iteration "do we have something to transmit, and if so, is SCI1SR1_TDRE and SCI1SR1_TC both set to 1?  If so, SCI1DRL = [byte to send]."  I have introduced small delays in this to no noticeable effect.

Also in main's for(;;), there is a 1ms delay timer set/checked to do received bytes parsing.


The microcontroller has 2 ports, port 0 and 1, we're using port 1.  A real time interrupt is also set up for approximately 1ms intervals, which currently just counts down timers.  Port 0 is disabled.


Among my initialization code:

RTI frequency divider set up to trigger every ~1ms.

Baud rate is set successfully at 115200 kHz, I've already confirmed via oscilloscope that sent bits are being both sent and received at 115.2kHz.

SCI1CR1 = 0x00;



RIE is never set to 0, SCTIE and TCIE are always 0.


Prior to showing snippets of code, the following global data is used

unsigned char OverrunHandledFlag=0; //0/FALSE if  no overrun has been seen, 1/TRUE if ISR saw and handled an Overrun condition since the last time the parsing function ran, initialized to 0.

#define BYTES_IN_REC_BUFFER 1024 //arbitrary buffer size that I intend to shrink down and test once I'm done with this issue.

signed char RecByteBuffer[BYTES_IN_REC_BUFFER]; //the array the bytes from the ISR get placed.

unsigned int RecByte_NextToParseIndex=0; //the next index that will get parsed if "NextToEnterIndex" isn't equal to it already.

unsigned int RecByte_NextToEnterInde=0; //the next index that a byte will get placed in in the ISR.


DisableInterrupts is simply {__asm SEI:}, and EnableInterrupts, {__asm CLI;}, for those not familiar with hidef.h by Freescale.


Aside from initialization code and the RTI, DisableInterrupts/EnableInterrupts is only called where specified in below code snippets.


My ISR is as follows:

void _Port_1_ISR(void)  //commands from REMOTE SYSTEM -OR- PROGRAM MODULE -OR- COMPUTER {      if(SCI1CR2_RIE)          //if receive interrupts are enabled      {           if (SCI1SR1_OR)  //check for over run           {                (void)SCI1DRL;          //flush the buffer                (void)SCI1DRL;          //found sometimes 1 read doesn't do it where 2 reads did?                OverrunHandledFlag = TRUE;          //start receive over in parse code           }            while(SCI1SR1_RDRF)                                                  //if char are available           {                if((RecByte_NextToEnterIndex + 1) != RecByte_NextToParseIndex)                {                     RecByteBuffer[RecByte_NextToEnterIndex++] = SCI1DRL;                                          if(RecByte_NextToEnterIndex >= BYTES_IN_REC_BUFFER)                          RecByte_NextToEnterIndex = 0;                }                else                {                     //Buffer size too small or not parsing enough, TBD                     (void)SCI1DRL;                }           }      } }


The following is snippets of my received bytes parsing function:

void serialPort1_ReceiveCharBufferParse(void) {      unsigned int _temp_nextToEnterIndex = 0;      char _temp_CurrentChar = 0x00;            DisableInterrupts;      {           //only grabbing once per function call, just to make sure we're never in a position that constantly received data           // prevents any other functionality from happening.           _temp_nextToEnterIndex = RecByte_NextToEnterIndex;      }      EnableInterrupts;            while(RecByte_NextToParseIndex != _temp_nextToEnterIndex)      {           DisableInterrupts;           {                //OverrunHandledFlag written to in ISR, lock away interrupts while reading/changing it.                if(OverrunHandledFlag)                {                     //if overrun occurred, we missed AT LEAST 1 byte of data... if mid-message, ignore the rest of it, don't know what we missed, could be anything.                     OverrunHandledFlag = FALSE;                     ReceiveState1 = 0;                }                                //get the current byte to parse, buffer is written to and NextToParse is read from, so lock away interrupts for this line.                _temp_CurrentChar = RecByteBuffer[RecByte_NextToParseIndex++];           }           EnableInterrupts;                      if(RecByte_NextToParseIndex >= BYTES_IN_REC_BUFFER)           {                DisableInterrupts;                {                     //NextToParseIndex is never written to in the ISR, but it is read from, so have writes to it locked off.                     RecByte_NextToParseIndex = 0;                }                EnableInterrupts;           }                      if(_temp_CurrentChar == START_CHAR)      //look for start char           {                ReceiveState1 = 1;          //got start char                //set up "complete message buffer," next characters received go into this buffer up to an END_CHAR.           }           else           {                switch(ReceiveState1)                {                case 0:                     break;                                        //wait here for start char                                     //-----                //multiple cases for determining of message is as expected, storing into buffer, or ending parse.  At end, ReceiveState1 = 0;                //Complete messages handled elsewhere                //-----                                     default:                     ReceiveState1 = 0;          //start over                     break;                }           }      } }


All of the above works beautifully if NOTHING is being transmitted.  But as soon as something gets transmitted, for some reason, it fouls up RDRF triggering interrupts, which leads to my not reading in bytes, which leads to Overrun conditions occurring.  As soon as a transmission is complete, receive interrupts work fine again until the next transmission!


I don't understand why these issues are occurring if transmit and receive should be doable at the same time.  Oscilloscope captures look clean and without noise, and I've set up I/O from the micro to be 1 or 0 based on various conditions from "Is SCI1SR1_RDRF high?" to "Is SCI1SR1_OR high?" to "1 at start of serial ISR, 0 when done," to "1 about to write to SCI1DRL, then change I/O to 0," among other considerations.  Everything points to "When transmitting, interrupts for RDRF are not happening, but RIE is still 1 and Transmit Interrupts are still disabled."  I've even tried setting DisableInterrupt / EnableInterrupt around the transmission (to zero effect).


Any thoughts?