Serial1.flush() not working as intended

I am using a half-duplex buffer chip which is used to control servos.

Before data is sent high the direction pin is set high and once data is sent, the pin is set low again.

Serial1.flush();
digitalWrite(Direction_Pin,LOW);	

What occurs here is that the command isn’t fully sent, so nothing happens.
Changing this to:

delay(1);
digitalWrite(Direction_Pin,LOW);	

Is however, successful in sending data.
From this, it seems that Serial1.flush() is still not functioning correctly.

Hmm, not sure about this one, maybe someone who is more familiar with this can chime in. In the meantime I’m going to log a bug for our firmware guys to check it out.

Thanks,
David

It looks like the flush() command only waits for the current character to transmit, not for the entire tx ring buffer to flush.


void USARTSerial::flush()
{
	// Loop until USART DR register is empty
	while (transmitting && (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET));
	transmitting = false;
}

This should probably wait for the tx ring buffer to be empty.

As a work-around @Mike43110 you could Serial1.write() and Serial1.flush each character that need to be sure are transmitted since it would work for one byte.

1 Like

Nice! Thanks for the proper explanation – amending that bug report. :smile:

bko, as you said, flush() only looks a the status of the last char transmit status using the USART_FLAG_TXE flag. If I understand the specs correctly, using the USART_FLAG_TC flag indicates when there are not more bytes pending to be sent AND transmission is complete. Would changing the while to testing the USART_FLAG_TC flag work in your opinion?

1 Like

Hi @peekay123

I think it needs to wait for the tx buffer to empty and then wait for the last char to be sent, something like:

void USARTSerial::flush()
{
	while ( _tx_buffer->head != _tx_buffer->tail );
        // Loop until USART DR register is empty
	while (transmitting && (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET));
	transmitting = false;
}

since that would mean that the full tx ring buffer has been flushed and all bytes have been sent. I am not sure I know enough about the interrupt driven part to say for sure this is the exact right way, but something like this is needed.

2 Likes
void USARTSerial::flush()

{
	while ( _tx_buffer->head != _tx_buffer->tail );
        // Loop until USART DR register is empty
	while (transmitting && (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET));
	transmitting = false;
}

The above works. TC must be used instead of TXE however otherwise it does not function correctly for timing critical applications.

I have tested it and it works 100% so far. It is actually more reliable than the Arduino communications at the moment for the same application.

2 Likes

Nice work Mike43110! You should put in a pull request for this one. :smile:

1 Like

Well, I did exactly that now :smile:

I hope that my first commit to an open source project is not relative to the rest of my career!
(flush the career too :stuck_out_tongue:)

Well, now at last my servos are working 100%! Now to make the snake slither!

1 Like

That's what she said! :musical_note:Rimshot:musical_note:

1 Like