Serial1 UART TX/RX pins stay high after transmitting data

Hello,
I am using a Particle Photon to update another MCU’s firmware over UART. The photon sets the MCU into bootload state and then transfers the firmware image over UART which is Serial1.

This process only works if the Tx pin of the Photon is connected to the ground using a resistor(pull-down). Without the pull-down resistor, the Tx and Rx pins go high after transmitting some data and stay high. With the pulldown resistor connected to Tx, and no resistor on the Rx pin, the transmission completes and Tx/Rx pins come low.

I am not sure what is causing the Tx pin to go high in the middle of UART transmission. I am using Serial1.write() to send data and Serial1.read() to read data.

Also, with the pulldown resistor in place, the communication works flawlessly for sometime. After that, during data transmission the Tx pin goes high again and requires a reboot to pull the Tx pin low again.

Not sure what’s causing this weird behaviour. Any ideas for the fix?

Thanks
Dheeraj

Also,
Serial1.flush() - waits for the data to be transmitted
while(Serial1.available() > 0) - waits till the data is in the Rx buffer

So, when Serial1.flush() finishes executing, does the TX buffer gets cleared always? and when while(Serial1.available() > 0) breaks, does the Rx buffer gets cleared?

@dheerajdake, serial UARTs use the Non-Return-Zero (NRZ) protocol meaning the output of the TX pin will remain HIGH by default. When you call Serial1.begin() and transmit data, the TX pin will go HIGH and remain HIGH after transmission. To release the pin, you need to disable Serial1, set the TX pin as a digital output and set it LOW:

Serial1.end();
pinMode(TX, OUTPUT);
digitalWrite(TX, LOW);

To restart Serial1, use Serial1.begin() again.

2 Likes

@peekay123
I am aware of the NRZ protocol. My situation is different though. I’ll be more clear this time,

I have 2 MCU’s one of which is photon, connected via UART. MCU1 sends a message to MCU2 which then replies via ack. Based on this MCU1 keeps on sending more data as long as the MCU1 ACK’s are right and data from the MCU1 is fully transmitted.

WIth the following connections between MCU1 and MCU2,
MCU1 <----> MCU2
VDD 3V3
GND GND
TX RX
RX TX

When I send data from MCU1, I get ACK from MCU2 and then Tx and Rx lines on MCU1 stays high(stop bit) and MCU1 won’t transmit data any further. The communication freezes.

With a pull-down resistor on Tx line, the communication works and the data is getting transmitted. But with pull-down resistor, I get an occasional UART communication freeze.

Summary:
Without the pull-down resistor on the Tx line I was unable to transmit data on the UART. With a pull-down resistor the communication works except that it freezes occasionally like once in 30 times maybe.

I am not sure what’s the cause behind this.

Here’s my code for Tx and Rx on the Photon side.

int WriteData(uint8_t* wrData, int byteCnt)
{
Serial1.write((uint8_t*)wrData, byteCnt);
Serial1.flush(); //waits for the transmission to complete
return(1);
}

int ReadData(uint8_t* rdData, int byteCnt)
{
uint8_t dataIndexCntr = 0;
while(!Serial1.available());

while (byteCnt > 0)
{
	if(Serial1.available() > 0){
		rdData[dataIndexCntr]=(uint8_t)(Serial1.read());
		dataIndexCntr++;
		byteCnt--;
	}
}
return(1);

}

Thanks
Dheeraj

@dheerajdake, if on MCU is a Photon, what is the other MCU? The serial protocol is REALLY well defined and having TX stay high is part of that protocol so I’m not sure why the second MCU might fail though there may be several reasons.

1 Like

The second MCU is Cypress BLE. From my earlier comment, [quote=“dheerajdake, post:2, topic:32624, full:true”]
Also,
Serial1.flush() - waits for the data to be transmitted
while(Serial1.available() > 0) - waits till the data is in the Rx buffer

So, when Serial1.flush() finishes executing, does the TX buffer gets cleared always? and when while(Serial1.available() > 0) breaks, does the Rx buffer gets cleared?
[/quote]

Is this true?

@dheerajdake, from what I can see in the source code, Serial1.flush() will return only once the circular buffer has been emptied and the last transmit frame has been sent.

Using while(!Serial1.available()) will break when no more characters are available in the circular receive buffer. That doesn’t mean a character is not in the process of being received.

Are you powering the Cypress BLE via the Photon’s 3V3 line? For testing purposes, I would create a simple program to send typed keystrokes from the Photon to the Cypress and have the Cypress simply echo what it receives back to the Photon.

1 Like

Is the Cypress part a 5V device or a 3.3V device? Do you need a level-shifter?

Does the Cypress part have hardware serial like the Photon or software emulated serial? There are lots of buggy implementations of soft serial, especially those that do not use interrupts.

How fast have you set your baud rate? Can you trying going slower and see if that helps.

1 Like

Got it. In that case,

  1. Are there API’s to check the status of THR(Transmit Holding Register) and RHR(Receiving Holding Register) registers of the UART (Serial1) ?
  2. Are there API’s to clean UART Tx/Rx FIFO’s?

Yes I am powering the Cypress BLE using Photons 3V3 line.

  1. Cypress BLE is capable of operating till 6V.
  2. How do I know if a level shifter is required?
  3. It has 2 Serial communication blocks - 1 I2C and another is SPI/UART. Not sure if it’s emulation.
  4. I had baudrate set to 115200. The actual baud rate for this speed is 114286. (Too much difference)
    I changed the baud to 38400 - The actual baud rate for this speed is 38462. I am testing with this rate.

I think this is your problem. You will not get reliable communication, particularly for long sequences of characters, if these rates are different. Even the 0.16% difference can make a difference.

I'm not sure why the baud rates are different, I would presume that you are using a funny crystal on the BLE part. Can you make the rates the same?

I have to choose the baud rates from a drop down menu while configuring the UART component. So if I can’t modify them on the Cypress side. If I choose to go with 38400 baud rate, can I set a baud rate of 38462 on the Photon like
Serial1.being(38462); ?

Edit:
Only the baud rates <=2400 doesn’t have any precision errors :expressionless:

Actually, you should be just fine with 114286.

UARTs resync on the falling edge of the start bit (generally, oversampling 8x or 16x), then sample the databits at 50% of the way through the bit; this means typically you can be about 3.75% out on baudrate and everything is fine. The UART starts looking for the next start bit immediately after seeing the mid-bit sample of the stop bit.

This is assuming 8x oversampling, and being able to slip 3/8ths of a bit by the 10th bit (stop bit).

Maybe post your code; could it be that there’s a deadlock (both ends waiting for data as something got out of sync, maybe?)

2 Likes

Sure the bit-level timing is robust (and generally 16x oversampled as you said), but fundamentally if the transmitter is sending continuously faster than the receiver can take data, there will be overruns.

If the transmitter is 0.7% faster as described above, approximately every 126 characters there will be an overrun, again assuming the transmitter can continuously transmit.

No, that’s not true - see my reply.

There will not be overruns - the UART receiver starts looking for a start bit halfway through the stop bit, which corrects the drift on a byte by byte basis, up to ~0.5 bit times, or a theoretical 5% inaccuracy (though with quantization it’s more like 3.75% as I said).

If this wasn’t the case, serial would be very unreliable, as most devices cannot have exactly locked clocks.

I have seen one UART implementation that didn’t look for the start bit until 15/16ths of the way through the stop bit, but that was a silicon bug and the vendor fixed it in the next chip revision.

1 Like