Interrupt race condition

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Interrupt race condition

3,329 Views
JohnBarber
Contributor II
Hi,
I'm using the MC9S08DZ60.
 
If I connect the SCI2 TX and RX pins to the same line, enable receiver and transmitter, enable Transmission complete interrupt and enable Receiver Interrupt, which interrupt will be served first when sending data? The transmission complete interrupt or the receiver interrupt?
 
/John
Labels (1)
0 Kudos
13 Replies

863 Views
JohnBarber
Contributor II
Hi Ake,
I think you are wrong. Suppose TX and RX lines are connected. When the data is sent the Transmission Complete Interrupt is raised. At this point the data is in the receiver shift register. The Receiver interrupt is raised first when the data is shifted to the receiver data register and the RDRF flag is set.
 
So the Transmission Complete interrupt will be served first.
 
/John
0 Kudos

863 Views
bigmac
Specialist III
Helllo John,
 
I think what you are implying is that the transmission complete flag is set before the receive flag is set , under your specific conditions, probably due to a slight difference in timing within the SCI module.  However, should interrupts be globally disabled at the time when both flags become set, I would assume the interrupt priority situation would exist when interrupts were re-enabled, and the receive interrupt would be serviced first.
 
If this is the situation, an ambiguity can exist for your case.  Whether the delay difference is "a few microseconds", or a substantial portion of a bit period, would be an interesting question.
 
If you require a consistent priority, for example TC, you might first test whether the TC flag is set from within the receive ISR, and process the TC event if so, prior to receive processing.  It should be possible to also use this technique to identify the actual amount of delay, by waiting for the receive flag to become set from within the TC ISR, and use the timer count to estimate the delay.
 
Regards,
Mac
 
0 Kudos

863 Views
JohnBarber
Contributor II
Hi,
thanks for interesting comments.
I've done the following experiment:
From a routine I start the sending of a series of data by writing the first byte to SCI2D.
The first interrupt that occur is the transmission complete interrupt.
In the ISR I send data byte 2.
The next interrupt to occur is transmission complete. In the ISR I send byte 3.
After that, the first receive interrupt occurs. It obviously lags 2 bytes compared to the TC.
 
So my conclusion is that TC interrupt will occur first.
 
/John
0 Kudos

863 Views
bigmac
Specialist III
Hello John,
 
I am not sure whether you are exiting the ISR each time, or remaining within the ISR.  Since all interrupts will normally remain disabled whilst you are within the TC ISR, the receive interrupt cannot occur until you leave the ISR, (but you can still test the RDRF flag).  Perhaps another possibility may be that you actually enabled interrupts for both TC and TDRE flags (which use the same vector).  If both sources are enabled, a test will be required to determine the source of a particular interrupt.  I find it hard to believe there is a two byte lag.
 
Incidently, when sending a string of characters, and assuming full duplex RS232 interface, it is unusual to utilize the TC interrupt.  Since there is double buffering, it is more usual to send the next character when the TDRE flag becomes set.  This should result in faster throughput.  The TC flag is more useful for half-duplex operation, such as RS485, for determining when to revert from send to receive mode.
 
Regards,
Mac
 
.
0 Kudos

863 Views
JohnBarber
Contributor II
Hello bigmac,
I exit the ISR each time.
I have only enabled the Transmission Complete Interrupt and the Receiver Interrupt.
I'm using half duplex RS232. TX and RX pins are connected to each other with a single wire. Transmitted data is read back in the RX ISR.
 
I can see that the RX interrupt lags 2 bytes.
 
/John
 
 
 
0 Kudos

863 Views
bigmac
Specialist III
Hello John,
 


John Barber wrote:
,
I have only enabled the Transmission Complete Interrupt and the Receiver Interrupt.
I'm using half duplex RS232. TX and RX pins are connected to each other with a single wire. Transmitted data is read back in the RX ISR.


There seems to be some confusion whether you are attempting to implement  half-duplex transmission, or are simply doing a loop-back test.
 
For the half duplex case, you do not need to activate receive interrupts whilst a transmission is in progress, because the received data is of no interest (you already know the data contents).  I might tackle the process in the following manner -
 
  1. In the normal state, the reception of data is enabled, using the receive interrupt.  The send interrupts, both TDRE and TC would remain disabled.
  2. When you need to send a data packet, disable the receive interrupt, enable the TDRE interrupt only, and send the first data byte.
  3. Within the send ISR, check that the TDRE flag is set, and send the next data byte.  The ISR is called once for each send byte.  Prior to sending the final data byte, disable the TDRE interrupt source, and enable the TC interrupt, clear the TC flag, and then send the character.
  4. When the send ISR is next entered, check that the TC flag is the source, clear the flag, disable TC interrupts, and re-enable the receive interrupt, also clearing the flag (in case it is already set).
At the completion of this transmission process, you might check whether the previous problem really exists.  If so, would be evidenced by a receive interrupt occurring immediately after the transmission completes, without the presence of an incoming character.  Should there still be a problem, its solution would probably require an additional short delay before re-enabling the receive interrupt.
 
Regards,
Mac
 


Message Edited by bigmac on 2008-02-10 11:13 PM
0 Kudos

863 Views
PeterHouse
Contributor I
For half duplex operation 2 bytes should be correct.

When you place the byte in the transmit register it takes one byte time to shift it out and simultaneously be shifted in to the receiver.  The receiver then turns it around, assume near zero turn around time, and the receiver then shifts its transmit byte out whil the original sender simultaneously receives it and at the end of reception generates an interrupt.   These are your two byte times.


Good Luck,

Peter House
0 Kudos

864 Views
allawtterb
Contributor IV


PeterHouse wrote:
receiver then turns it around, assume near zero turn around time, and the receiver then shifts its transmit byte out whil the original sender simultaneously receives it and at the end of reception generates an interrupt.   These are your two byte times.


I don't see why you are talking about the receiver transmitting anything, I thought we were talking about one chip with a loopback setup.  I don't see why there would be a 2 byte delay, I might do a little test with a DZ60 here using a really slow baud rate to test this.
0 Kudos

864 Views
allawtterb
Contributor IV
I just did a simple test and I got different results, the receive data register full interrupt occured first, then the transmit register empty flag. Here is how I setup everything.
 
This was my main:
Code:
void main(void) {   uint8_t i;      MCU_init(); /* call Device Initialization */   for (i=1;i<21;i++)    // Fill transmit data with 1-20   {      TXData[i-1] = i;   }   SCI1D = TXData[TXCounter];  // Send the first byte   TXCounter++;                   SCI1C2_TCIE = True;         // Enable the transmit complete interrupt   SCI1C2_RIE = True;          // Enable the receive data register full interrupt     while(RXCounter < 20);      // Wait until all data has been received   _asm NOP;

 Then my 2 ISR's:
Code:
__interrupt void SCI1_Rx_ISR(void){  /* Write your interrupt code here ... */   if (SCI1S1_RDRF)   {      RXData[RXCounter] = SCI1D;            RXCounter++;       TestData[TestCounter] = 0x65;          TestCounter++;   }}__interrupt void SCI1_Tx_ISR(void){  /* Write your interrupt code here ... */   if (SCI1S1_TC)   {      SCI1D = TXData[TXCounter];      TXCounter++;       TestData[TestCounter] = 0x1C;      TestCounter++;         }}

 
The baud rate used was about 122 baud with the bus running at 16MHz.  The first entry in TestData is 0x65 then 0x1C.  It alternates back and forth as expected from that point on but 0x65 is the first entry.  Another way to get more information on this would be to set a fast free running counter and store the count when the interrupts occur.  This would tell you how long after the receive interrupt the transmit complete interrupt fired.

 
0 Kudos

864 Views
peg
Senior Contributor IV
Hi,

First of all I think that Peter has gone off on the wrong track with his musings. We are just talking about one device simply looped-back here, aren't we?

Also, although I don't have this exact device, I would tend agree with the others and suggest that John is somehow missing something.

The outcome for this is certainly unspecified.
It should however be a close race and I don't think I would be placing bets either way, but allowing for either outcome.

As for the point that the reciever needs to somehow receive two bytes before it indicates RDRF, this is wrong and the SCI would be severly broken if it were the case.

To the OP, why are you looking at this anyway?

0 Kudos

864 Views
JimDon
Senior Contributor III
"which interrupt will be served first when sending data?"

That was the question which Ake correctly answered in the first reply. John rebuked the response, as I guess he missed the fully meaning of his question.

As to which interrupt pending flag would be set first, while for a narrow set of carefully defined parameters, may be determinate given inside knowledge of how the hardware was designed, is actually of little relevance and should not be used to design the software. As John tried to point out, in real life there is no way to determine actual arrival of data with respect to it's transmission. One can hardly blame John for assuming a real life application as the bases for his response.

Perhaps "peg" has the right idea in requesting a clarification of the purpose of the inquiry.
0 Kudos

864 Views
PeterHouse
Contributor I
This discussion is only valid for a loopback condition.  Remember - this is asyncronous communications.  There is no way to know when the receive interrupt will occur since you do not know when the remote device will send a byte.

If your interrupt handler is short and only deals with the incomming/outgoing byte long enough to write it to a buffer/read it from a buffer then the interrupt priority between receive and transmit should not make any difference even at the highest data rates.  If you must do a lot of processing in your interrupt then you could certainly check the flags for the other interrupt and deal with them - although this sort of defeats the purpose of using interrupts since you are now polling.

Good Luck,

Peter House
0 Kudos

864 Views
Ake
Contributor II
Hello,
If you look in the MC9S08DZ60 book, Table 4-1, there is a list of all the interrupts in the 9S08DZ.
The SCI receiver interrupt has priority 17 and the transmitter has priority 18.
The lowest number gets the interrupt handled first.
 
(the numbers are not shown, you will have to calculate them yourselve. The bottom one, no 0 is the RESET and the highest one, 25 is the RTC.
 
Regards,
Ake
0 Kudos