Device: PIC16F1829, half-duplex communication (RS-485)
The USART is having two registers - TSR and TXREG. Transmit is performed from TSR and process is indicated by TRMT bit. TXREG is second register in transmit FIFO.
When I write to TXREG first time, data is transferred to TSR and transmission starts. I immediately get interrupt that TXREG is empty, putting second char to transmit. This is clear.
The problem I get is related to finishing the transmitting, when I switch transmitter off and turn receiver on.
When I put last character into the TXREG, I wait for another interrupt, which informs that TXREG is empty and TSR must have started transmitting last character. I guess if I turn transmitter off at this point, last character is not transmitted - therefore I must wait for TRMT status bit to set (transmitter finished transmitting):
But:
- TRMT does not generate interrupt. How do I know it has set other than being stuck in the ISR for unacceptably long time (imagine 2400 baud)?
- TRMT sets at the middle of stop bit. If I turn off transmitter at this point, stop bit becomes truncated, and there's a chance remote equipment has problems with it - how to identify the time to wait until this last stop bit is fully transmitted?
I have an idea of the workaround here: on last interrupt put dummy character into the TXREG, and wait for next interrupt when this dummy character transfers to TSR, and here immediately disable the transmitter. However:
you can see the TXIF bit is again set at the center of the last stop bit, and problem (2) is still here - I turn transmitter off at the time remote node is expected to sample it. In addition, if ISR gets delayed then there's a chance, at high speeds, that TSR starts transmitting start bit, which will confuse the receiver, and the whole transmission risks to be invalidated.
I do not see a solution to it, may only guess on specific workarounds, which would cost some code and even probably some electronics (like disabling transceiver but still keeping interface chip output on at high level, kind of prolonging the stop bit).
I am unable to find anything material in the internet, which is strange, I am sure should not be the first one getting issue with it. Any ideas how to handle in this setup?
Edit: another workaround would be to set up any timer and time a character, or slightly more than character, but this is rather ugly for the functionality of the USART microcontroller like this.
-
1\$\begingroup\$ Which PIC16? Can you link to a specific data sheet? \$\endgroup\$Justme– Justme2024年02月05日 10:31:59 +00:00Commented Feb 5, 2024 at 10:31
1 Answer 1
OK, you are using RS-485 so you anyway have a half-duplex medium and generally you can't receive on RXD what you send on TXD, and, you must reserve some turnaround time, during which, the byte transmission has ended, the stop/idle state has been transmitted for long enough before transmitter is disabled and the other nodes must wait until sufficiently long time has passed from last byte so they can assume the node that just transmitted is ready to receive again.
If you can arrange the RS-485 transceiver to echo back what you transmit, you can send out the last byte and check when it is received. But it also is signaled with an interrupt in the middle of stop bit, so might not work.
If you can afford sending an extra byte, you can always disable the transmission after that byte is on wire, and even cut off mid-byte if you want.
The reason is that the logic 1 matches the idle bus and stop bit state, so maybe send an 0xFF which only has low start bit. Also if you cut the transmission during the start bit, the receivers either see that as a 0xFF or ignore it if the start bit was too short.
You could also cut off the transmission during stop bit of the last actual data byte for the same reason but send a dummy 0xFF with RS-485 transmitter disabled.
Or you could disconnect the GPIO pin from USART and send a logic high with GPIO while the UART itself transfers out the unused dummy byte not actually sent.
You could always use timers too, for example when last byte is written, disable further UART transmitter empty interrupts and start a timer to interrupt some time later when the last byte and some idle time is passed to switch to receiving mode. The transmission could also be handled completely in timer interrupts as well, which enables to control the PHY transmit enable to be active well before starting transmission, and well after transmission is complete, and even include some dead time before activating the reception.
But one thing is sure, your system should be set up so that disabling transmit during the stop bit is irrelevant, the receivers should see that as idling logic high when all transmitters are disabled. Unless there are ringing and reflections, which should not be a problem on a properly terminated bus.
If there are problems, often the bus has fail-safe biasing resistors to keep bus at logic 1 while nothing is driving the bus.