Problem with frame finished interrupt of Usic Module in Uart mode

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
User10215
Level 4
Level 4
First like received
Hi everybody,

I'm working with a XMC4500 microcontroller in conjunction with Keil as IDE and debugger. I use 5 of the USIC-channels as UART-channels in half duplex configuration. Since my communication runs via RS485 I have a transceiver with a dedicated control pin to tell it to be in receive or transmit mode. Therefore I need to know exactly when a transmitted frame is finished in order to switch the RS485-transceiver back into receive mode.
I used Dave 4.1.2 to configure the USIC-channels for UART communication and the Hardware-FIFO with 32 elements for each channel (16 for receive and 16 for transmit). Then I went ahead and modified the generated Dave-code of the Interrupt-service-routine for transmission (function name: void UART_lTransmitHandler(const UART_t * const handle)) in the file "uart.c".
What the old Dave Code did was:
- Interrupt gets called as soon as FIFO fill level goes to zero
- see if there is more data to be send...if yes fill the FIFO again and finish the Interrupt Routine
- if no data needs to be send anymore, wait in a while loop until the last byte has been copied into the shift register
- set some variables and, if available, run the user callback-function

What I didn't like was the while loop in the interrupt routine which waits for a whole byte to be transmitted in order to get to the user-callback-function. This function is then called while the last byte is still in transmission which is also not good for my application which, as mentioned above, needs to know exactly, when all the bytes have been send out.
My modification of the code was supposed to do the following:
- Interrupt gets called as soon as FIFO fill level goes to zero
- see if there is more data to be send...if yes fill the FIFO again and finish the Interrupt routine
- if no data needs to be send anymore disable the standard TxFifo event and activate the Frame Finished Event (during initialization I set the Interrupt Output line for the Frame finished Interrupt to the same line as the standard TxFifo event) then finish the Interrupt routine
- Interrupt gets called as soon as the Byte before the last Byte has been finished...Interrupt Routine finishes doing nothing
- Interrupt gets called again as soon as the last Byte has been finished...disable the Frame finished event and tell the RS485-transceiver to go into receive-mode and finish the Interrupt Routine.

The standard TxFifo event is activated again as soon as new data has to be transmitted.
Now, because this did not work I inserted a debug variable. I set this Variable to 1 at the beginning of the Interrupt function and I reset it to 0 at the end of the Interrupt function. Using a ULINKpro and the Logic Analyzer of the Keil Debugger I can see, that for each of the last two bytes where the Frame finished Interrupt is activated the Interrupt Routine gets called twice in short succession (~3 us). How can this behaviour be explained? I read the errata-sheet but there is nothing in there about this. Is this a hardware-bug?
Just ask if more Information is needed.

Best regards,
Niclas
0 Likes
8 Replies
chismo
Employee
Employee
First like received
Hello Niclas,

To understand better the problem, do you mean that switching off the transceiver after the second Transmitter Frame Finished interrupt is still too early?

Regarding the duration between successive TFF interrupts, a shorter than expected duration could be the result of the late entry to the first TFF interrupt, e.g. if there is a same or higher priority interrupt being serviced when the first TFF interrupt is triggered.

Regards,
Min Wei
0 Likes
User10215
Level 4
Level 4
First like received
Hi Min Wei,

thank you for answering. I'll try to describe the behavior I see in the Debugger as best as I can...so to better understand you have to know that I modified the Dave-Code in the uart.c so that the FIFO is now filled in the "UART_Transmit" and not in the interrupt service Routine. So the FIFO is being filled and the standard TxFifo Event is activated.
When the Interrupt Service Routine is called for the first time I know that the FIFO is empty. Two bytes are now still being send out, one in TBUF and one in the shift register. So in the interrupt function I deactivate the standard TxFifo event and activate the Frame finished Interrupt and after that I finish the interrupt function.
Next time the Interrupt is called I know that the data in the shift register has been send and the data which was in the TBUF is copied to the shift register and send out. So being in the Interrupt function I just set a variable to remember that the next time I'm in the Interrupt function the last byte has been finished. So this call of the Interrupt is pretty quick. What I now expect is that it takes somwhere around 87us until the last Byte has been send and the Interrupt is called again (10 bits with a baudrate of 115200).
BUT[/U ] the next call of the Interrupt function is after around 3us!
I went ahead and ignored this call. The next Interrupt then happens after the expected time of around 87us where I then deactivate the Frame finished Interrupt and tell the RS485-transceiver to go into receive mode by toggling a GPIO. Here, I noticed the following: when the deactivation of the Frame finished Interrupt happens too late the Interrupt Routine is called again after the mysterious 3us! When I deactivate the Frame finished Interrupt as soon as I get into the Interrupt function this second call doesn't happen.
Also what I noticed with an oscilloscope is that the stop bit of the last byte is too short when I switch the RS485-transcevier back into recive mode (~6.5us instead of 8.6us with the given baudrate). When I do the switch of the transceiver in the second of the last two calls of the Interrupt function the length of the stop bit is ok.
The measurement described above was done by using a global variable which I set to 1 at the beginning of the Interrupt function and to 0 at the end of the function. Using the logic analyzer in Keil's microvision with an ULINKpro as Debugger I can see the behaviour described above where I get two peaks of this debug-variable in short succession everytime the Frame finished Interrupt fires and as long as the Frame finished Interrupt isn't deactivated fast enough.
I would've posted a picture of what I saw in the logic analyzer but I've already rewritten the code to the point where it now works reliable. If the description above isn't comprehensible I will go ahead and rewrite the code until I get the described behaviour again in order to post a Picture of the logic analyzer.

Best regards,
Niclas
0 Likes
User10215
Level 4
Level 4
First like received
I reproduced the old code...this is what I see in the logic analyzer:



The variable "u8_DebugTransmissionStatus" is the variable I set to 1 at the beginning of the Interrupt. At the end of the function it will be set to 0 again.
0 Likes
chismo
Employee
Employee
First like received
Hello Niclas,

From your description, I am suspecting that the transmit shift interrupt (TSIF) is also enabled.
This interrupt is triggered with the shift of the last data bit so roughly one bit time earlier than TFF.

Can you check this by reading out the CCR register? Specifically, bit 12 controls the TSIF interrupt generation.
I doubt that the TFF event is triggering the additional interrupts.

Regards,
Min Wei
0 Likes
User10215
Level 4
Level 4
First like received
Hi Min Wei,

I went ahead and added some variables to the Interrupt function. Those Variables read out certain Registers at the beginning and the end of the Interrupt function. The Registers in the first measurements are CCR, TCSR and PSR and in the second measurement TCSR, PSR and PCR. The variables are also put into the logic analyzer. This is the result for CCR, TCSR and PSR:

1564.attach

In the Picture I added some numbered lines. These are the register-values at the corresponding line:
Line 1:
CCR = 0x00000002
TCSR = 0x15000580
PSR = 0x0000F583

Line 2:
CCR = 0x00000002
TCSR = 0x15000580
PSR = 0x0000F483

Line 3:
CCR = 0x00000002
TCSR = 0x15000580
PSR = 0x0000F483

Line 4:
CCR = 0x00000002
TCSR = 0x15000580
PSR = 0x0000F483

Line 5:
CCR = 0x00000002
TCSR = 0x15000580
PSR = 0x0000F583

Line 6:
CCR = 0x00000002
TCSR = 0x15000580
PSR = 0x0000F483

Line 7:
CCR = 0x00000002
TCSR = 0x05000500
PSR = 0x0000F483

Line 8:
CCR = 0x00000002
TCSR = 0x05000500
PSR = 0x0000F183

And here the second measurement with the Registers TCSR, PSR and PCR:

1565.attach

Line 1:
TCSR = 0x15000580
PSR = 0x0000F583
PCR = 0x00000901

Line 2:
TCSR = 0x15000580
PSR = 0x0000F483
PCR = 0x00000981

Line 3:
TCSR = 0x15000580
PSR = 0x0000F483
PCR = 0x00000981

Line 4:
TCSR = 0x15000580
PSR = 0x0000F483
PCR = 0x00000981

Line 5:
TCSR = 0x15000580
PSR = 0x0000F583
PCR = 0x00000981

Line 6:
TCSR = 0x15000580
PSR = 0x0000F483
PCR = 0x00000981

Line 7:
TCSR = 0x05000500
PSR = 0x0000F483
PCR = 0x00000981

Line 8:
TCSR = 0x05000500
PSR = 0x0000F183
PCR = 0x00000901

I cannot see that it is TSIF that fires that one particular additional interrupt.

Regards,
Niclas
0 Likes
User10215
Level 4
Level 4
First like received
Here some more Registers corresponding to the numbered lines in the Pictures above:

Line 1:
TRBSR = 0x00050901
RBCTR = 0x14240000
TBCTR = 0x44050100

Line 2:
TRBSR = 0x00050901
RBCTR = 0x14240000
TBCTR = 0x04050100

Line 3:
TRBSR = 0x00060901
RBCTR = 0x14240000
TBCTR = 0x04050100

Line 4:
TRBSR = 0x00060901
RBCTR = 0x14240000
TBCTR = 0x04050100

Line 5:
TRBSR = 0x00060901
RBCTR = 0x14240000
TBCTR = 0x04050100

Line 6:
TRBSR = 0x00060901
RBCTR = 0x14240000
TBCTR = 0x04050100

Line 7:
TRBSR = 0x00070901
RBCTR = 0x14240000
TBCTR = 0x04050100

Line 8:
TRBSR = 0x00000909
RBCTR = 0x74240000
TBCTR = 0x04050100

One can see that the RxFifo gets filled during Transmission due to the half duplex nature of the UART-configuration. However, receive-interrupts are deactivated during transmission and the Interrupt Output-line is not the same line as for transmit-interrupts, so that shouldn't be the reason for the Problem.

Regards,
Niclas
0 Likes
chismo
Employee
Employee
First like received
Hello Niclas,

Thanks for providing these details. It is clear to me now, the extra interrupt is due to the received frame finished event (RFF).
RFF shares the same interrupt enable as TFF, i.e. PCR.FFIEN and with half-duplex UART configuration, data reception is taking place at the same time as data transmission.

This can be seen from your observations on the PSR register.
- The interrupt triggered at line 3 is due to RFF of the 2nd last received word. Hence at line 3 and line 4, RFF remains set and TFF is 0.
- The interrupt triggered at line 5 is due to TFF as shown in PSR.TFF=1.
- At line 6, PSR.TFF is cleared to 0 by your service routine.
- The interrupt triggered at line 7 is then due to the RFF of the last received word. PSR.TFF remains 0 at this point in time.
- But here do you clear PSR.RFF because at line 8, I see that PSR.TFF=1 but PSR.RFF=0.

RFF is happening about half a bit time earlier than TFF. This because from receive perspective, the sampling points determines the completion whereas from transmit perspective, the completion is based on the end of the internal shift clock cycle.

For your application, would it make sense to treat RFF as dummy interrupts and service only the interrupts triggered by TFF? In your service routine, you can check if PSR.TFF bit is set.

Regards,
Min Wei
0 Likes
User10215
Level 4
Level 4
First like received
Hi Min Wei,

thank you very much! I didn't notice that receive and transmit share the same Frame finished Interrupt! Now that I know what the problem is I will find a solution that fits best. Maybe, as you said, by ignoring the Interrupt call or maybe by waiting until PSR.TFF is also set. Again, thank you!

Regards,
Niclas
0 Likes