PDA

View Full Version : Serial1.flush() Problems



rekcut
03-31-2014, 09:55 PM
Hey guys,

The Serial1.flush() function isn't doing what its supposed to be doing by waiting for the TX buffer to be empty... Any fixes for this?

Best,
rekcut

stevech
03-31-2014, 11:05 PM
Forum rule: post detail/specifics, code that causes problem, and steps to reproduce it.

As I see the code, the flush() does not truncate the current buffer. It waits for that to empty into the UART's FIFO. And some interrupts from the UART may occur.

christoph
03-31-2014, 11:11 PM
Steve is right, without more information it's impossible to help you more than by simply saying "it should work".

Serial1.end() seems to do the same thing as flush(), it waits for (transmitting == 0).

rekcut
03-31-2014, 11:19 PM
so basically I'm using an RS485 bi-directional transceiver chip which you have to enable with an external pin. Here is the basic code I am using to see whether or not the flush is working. However, flush is returning early and the RS485 chip is being set to RX mode before it should.

int temp;
int k = 0;
char array[5] = {0x3A,0xD8,0x00,0x01,0xE9};
//char array[8] = {0xD,0x8,0x0,0x0,0x0,0x1,0xE,0x9};
char inchar[5]={0};
void setup()
{
Serial1.begin(19200);
Serial.begin(19200);
pinMode(13,OUTPUT);
}
void loop()
{

if(k==0)
{
delay(3000);
digitalWrite(13,HIGH);
for(int i=0;i<5;i++)
{
Serial1.print(array[i]);
}
digitalWrite(13,LOW);
k++;
}
Serial1.flush();
temp = Serial1.available();
if(temp > 0)
{
digitalWrite(13,HIGH);
Serial1.println("hi");
Serial1.flush();
digitalWrite(13,LOW);
}
}

stevech
03-31-2014, 11:23 PM
Yes, the flush or end code does not wait for the UART's shift register to finish. The shift register is fed by the UART's FIFO (if FIFO mode is enabled).

What you want can be done, with added code that looks at certain UART status bits to see that the FIFO is empty and the dual-rang shift register is empty and the final stop bit has been sent. Or you can kludge in a time delay after the flush, where the delay is baud-rate dependent

rekcut
03-31-2014, 11:31 PM
Where would I find a datasheet to look at the status control registers to do that? I'm familiar with how to do what i want with the ATmega328p but not with the Teensy's micro-controller.

stevech
03-31-2014, 11:53 PM
I'd use a scope to see what the bit stream looks like vs. your program's logic.
Look at the library source code for serial.cpp.
Note that serial1.end() may affect your goals.

The Freescale data sheets for the ARM CPU explain the UARTS. They differ slightly between the CPU in the Teensy 3.0 and 3.1, and as I recall, in 3.1, serial 3 has no FIFO capability.
http://www.freescale.com/webapp/sps/site/taxonomy.jsp?code=K20_USB_MCU&tid=mKOvp

PaulStoffregen
04-01-2014, 01:19 AM
I'd give this a try right now, except I can't see any mention of which Teensy board you're using. I have them all right here, but which one should I hook up to test with your code?



so basically I'm using an RS485 bi-directional transceiver chip which you have to enable with an external pin.


Teensy has an undocumented Serail1.transmitterEnable(pin) which is meant for automatically controlling the pin.

Still, this approach with flush() should work. I'll test it here, but only if you tell me which board you're using!

PaulStoffregen
04-01-2014, 01:42 AM
I tried this on a Teensy 3.1.

The problem is with your code. You're calling digitalWrite(13,LOW) before Serial1.flush(), which turns off the transmitter before even the first bit is completed.

Serial1.flush() does work properly. You simply need to mode digitalWrite(13,LOW) after Serial1.flush(), so the transmitter remains on.

Here's a modified program:



char array[5] = {
0x3A,0xD8,0x00,0x01,0xE9};
void setup()
{
Serial1.begin(19200);
Serial.begin(19200);
pinMode(13,OUTPUT);
}
void loop()
{
delay(100);
digitalWrite(13,HIGH);
for(int i=0;i<5;i++) {
Serial1.print(array[i]);
}
Serial1.flush();
digitalWrite(13,LOW);
}


Here are the waveforms on pins 1 and 13:

1765

You can also get a similar result with this code:



char array[5] = {
0x3A,0xD8,0x00,0x01,0xE9};
void setup()
{
Serial1.begin(19200);
Serial1.transmitterEnable(13);
Serial.begin(19200);
}
void loop()
{
delay(100);
for(int i=0;i<5;i++) {
Serial1.print(array[i]);
}
}

rekcut
04-01-2014, 02:05 AM
I'm using the teensy 3.1, and yes that was a problem in the code. But the greater issue is when checking Serial1.available() right after you use serial flush... Here is the code in part of my big project I'm working on... I get an overflow issue when printing one of the errors because Serial1.flush() doesnt wait for all of the data to send.

int temp;
int k = 0;
char array[5] = {0x3A,0xD8,0x00,0x01,0xE9};
//char array[8] = {0xD,0x8,0x0,0x0,0x0,0x1,0xE,0x9};
char inchar[5]={0};
void setup()
{
Serial1.begin(19200);
pinMode(13,OUTPUT);
}
void loop()
{
char inChar = -1;
byte numBytesAvailable = 0;
int ValidCmd = 0;
numBytesAvailable = Serial1.available();
char cmdword[4]={
0x3,0xA,0xD,0x8 };

if (numBytesAvailable > 0)// if there is something to read
{
int i;
int j = 0;
if(numBytesAvailable == 5)
{

for (i = 0; i < numBytesAvailable; i++)// store everything into "inChar"
{
inChar = Serial1.read();
}
}

else if(numBytesAvailable > 5)
{
// Error Code - Received Command Word is too Long
char temp[5] = {
0x3A,0x79,0x00,0x02,0xEE };
digitalWrite(13,HIGH);
for(int i=0;i<5;i++)
{
Serial1.print(temp[i],HEX);
Serial1.flush();
}
digitalWrite(13,LOW);
}
else if(numBytesAvailable < 5 && numBytesAvailable > 0)
{
// Error Code - Received Command Word is too Short
char temp[5] = {
0x3A,0x79,0x00,0x01,0xEF };
digitalWrite(13,HIGH);
for(int i=0;i<5;i++)
{
Serial1.print(temp[i],HEX);
Serial1.flush();
}
digitalWrite(13,LOW);
}
}
}

PaulStoffregen
04-01-2014, 03:17 AM
I get an overflow issue when printing one of the errors because Serial1.flush() doesnt wait for all of the data to send.


I believe the oscilloscope waveform proves Serial1.flush() does indeed wait for all of the data to send.

Perhaps the error is due to some other cause?

PaulStoffregen
04-01-2014, 03:34 AM
Your program's logic, in reply #10, appears to be flawed.

Each time loop() runs, you're calling Serial1.available(). If any data is available, you're running one of three chunks of code.

In order:

#1: If there's more than 5 bytes, you're considering that an error.

#2: If there's exactly 5 bytes, you consider the input correct.

#3: If there's fewer than 5 bytes, you consider the input to be an error!

This seems like deeply flawed logic. How can condition #1 or #2 occur? Since the data arrives at a fairly slow baud rate, and the odds are almost certain that fewer than 5 bytes will be available for quite some time before all 5 appear. But your code in #3 turns on the transmitter, which will prevent any more data from being received.

I'm certain Serial1.flush() is working correctly.

The error is in your code.

rekcut
04-01-2014, 07:01 AM
Hmm... the logic of the code is fine because I'm using if() else if() statements... when one matches it should automatically jump out of them. It seems that the Bi-directional chip I was using was creating some sort of feedback to the receive pin on the Teensy... just took care of the problem by doing a little Serial.clear() after sending my error code. Thank you for the help guys, especially Paul for sending me the scope pics. :-) Here is my fixed code to get rid of the issue.

int temp;
int k = 0;
char array[5] = {0x3A,0xD8,0x00,0x01,0xE9};
//char array[8] = {0xD,0x8,0x0,0x0,0x0,0x1,0xE,0x9};
char inchar[5]={0};
void setup()
{
Serial1.begin(19200);
pinMode(13,OUTPUT);
}
void loop()
{
char inChar = -1;
byte numBytesAvailable = 0;
int ValidCmd = 0;
numBytesAvailable = Serial1.available();
char cmdword[4]={
0x3,0xA,0xD,0x8 };

if (numBytesAvailable > 0)// if there is something to read
{
delay(30);
numBytesAvailable = Serial1.available();
int i;
int j = 0;
if(numBytesAvailable == 5)
{

for (i = 0; i < numBytesAvailable; i++)// store everything into "inChar"
{
inChar = Serial1.read();
}
}

else if(numBytesAvailable > 5)
{
// Error Code - Received Command Word is too Long
char temp[5] = {
0x3A,0x79,0x00,0x02,0xEE };
digitalWrite(13,HIGH);
for(int i=0;i<5;i++)
{
Serial1.print(temp[i],HEX);
Serial1.flush();
}
Serial1.clear();
digitalWrite(13,LOW);
}
else if(numBytesAvailable < 5 && numBytesAvailable > 0)
{
// Error Code - Received Command Word is too Short
char temp[5] = {
0x3A,0x79,0x00,0x01,0xEF };
digitalWrite(13,HIGH);
for(int i=0;i<5;i++)
{
Serial1.print(temp[i],HEX);
Serial1.flush();
}
Serial1.clear();
digitalWrite(13,LOW);
}
}
}