Go Down

Topic: [SOLVED] Erraneous transmission at high baud rate for serial communications (Read 2412 times) previous topic - next topic

yw5aj

Hi Coding Badly,

I feel that this post deviated far enough from the OP, as I have made progresses to narrow down the source of the problem. People will get lost if I keep posting here. Could you please help review whether the following post is OK to create a new one? It would be OK to say no too and I really appreciate your work in help organizing this forum.


Subject: Sending constant int from Arduino to PC causes error

I am using Arduino Uno Rev 3, and according to this link we can achieve 2000000 baud rate.

This problem can be easily repeated by the following code:

Code: [Select]

void setup() {
  Serial.begin(2000000);
}

void loop() {
  int val = 234;
  Serial.println(val);
}


I am using the serial-USB cable. To read the data, I used Python pyserial (< 20 lines of code including empty lines and import lines):

Code: [Select]

import serial
import matplotlib.pyplot as plt

LEN = 10000
data = []
ser = serial.Serial('COM3', baudrate=2000000)
for i in range(LEN):
    try:
        data.append(int(ser.readline()))
    except:
        pass
ser.close()

# %% Plot data
plt.figure(figsize=(6, 4))
plt.plot(data)
plt.savefig('data.png')


Here is what I got:

Coding Badly

Could you please help review whether the following post is OK to create a new one?
Really?  Rather than helping you with your problem you want me to waste my time justifying my moderation decisions?  I will pass.


yw5aj

Really?  Rather than helping you with your problem you want me to waste my time justifying my moderation decisions?  I will pass.


Don't take me wrong please! Again, as I said in the post above, I really appreciate your time and help in organizing the forum threads. Instead of trying to fight, I was thinking whether that would be a better way to discuss this issue. I will not post a new thread then.

Please don't misunderstand me, who truly appreciate all your effort!

Shawn

Coding Badly


I cannot get it to fail (excess 234s trimmed)...

Code: [Select]

C:\ >C:\Python34\python
Python 3.4.1 (v3.4.1:c0e311e010fc, May 18 2014, 10:45:13) [MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import serial
>>>
>>> LEN = 10000
>>> data = []
>>> ser = serial.Serial('COM3', baudrate=2000000)
>>> for i in range(LEN):
...     try:
...         data.append(int(ser.readline()))
...     except:
...         pass
...
>>> ser.close()
>>>
>>> data
[234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
....
 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234]
>>>

Coding Badly


...which brings us full circle to Reply #1.  Your Python script is not removing data from the serial buffer fast enough.  You need some combination of: faster PC, better kernel driver, faster Python run-time, different computer-side programming language, framing, error detection.


yw5aj

...which brings us full circle to Reply #1.  Your Python script is not removing data from the serial buffer fast enough.  You need some combination of: faster PC, better kernel driver, faster Python run-time, different computer-side programming language, framing, error detection.


Thanks a lot for testing it Coding! I have two thoughts though,

1) One reason that makes me think it is not a issue from slow computer/connection is my Reply #8, where I added a very small sinusoidal curve to the int, and it worked perfectly. It is still a high baud rate, so if the speed is an issue, it would fail there too. If you don't mind, could you please take a look at that thread's code? I find that phenomenon really weird to understand (looks like the data type was automatically promoted by adding a value to it, but then again it is still int).

2) There is another slight chance (I might be totally wrong): because the error rate is relatively low, I only find out the "spikes" by plotting them (eye-balling them through the IDLE console does not work). If you do
Code: [Select]

for datum in data:
    if datum > 234:
        print(datum)

Would any value be printed out? (I might be wrong though)

Thanks again - I do appreciate your time into this very much!

Shawn

Coding Badly

1) One reason that makes me think it is not a issue from slow computer/connection is my Reply #8, where I added a very small sinusoidal curve to the int, and it worked perfectly. It is still a high baud rate, so if the speed is an issue, it would fail there too.
You increased the amount of work the Arduino must do between println calls.  That slows the data rate.  It slows the data rate enough that your computer can keep up.

The code is functionally equivalent to this where PauseForSlowComputer is high enough that the computer can keep up...

Code: [Select]
#define FASTADC 1  // Flag for prescale 16
// Code pasted for modifying ADCSRA
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

void setup() {
  Serial.begin(1000000);
  #if FASTADC
    // set prescale to 16
    sbi(ADCSRA,ADPS2) ;
    cbi(ADCSRA,ADPS1) ;
    cbi(ADCSRA,ADPS0) ;
  #endif
}

const unsigned PauseForSlowComputer = 50;

void loop() {
  int val;
  val = analogRead(A0);
  delayMicroseconds( PauseForSlowComputer );
  Serial.println(val);
}

Coding Badly

2) There is another slight chance (I might be totally wrong): because the error rate is relatively low, I only find out the "spikes" by plotting them (eye-balling them through the IDLE console does not work). If you do ... Would any value be printed out? (I might be wrong though)
This has been running for about 10 minutes (precise capture of the screen)...

Code: [Select]
C:\windows\system32 >C:\Python34\python
Python 3.4.1 (v3.4.1:c0e311e010fc, May 18 2014, 10:45:13) [MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import serial
>>>
>>> count = 0
>>> ser = serial.Serial('COM3', baudrate=2000000)
>>> ser.flush()
>>> while True:
...   count = count + 1
...   line = ser.readline()
...   if line != b'234\r\n':
...     print( '#', count, ':', line )
...

yw5aj

You increased the amount of work the Arduino must do between println calls.  That slows the data rate.  It slows the data rate enough that your computer can keep up.

The code is functionally equivalent to this where PauseForSlowComputer is high enough that the computer can keep up...

Code: [Select]
#define FASTADC 1  // Flag for prescale 16
// Code pasted for modifying ADCSRA
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

void setup() {
  Serial.begin(1000000);
  #if FASTADC
    // set prescale to 16
    sbi(ADCSRA,ADPS2) ;
    cbi(ADCSRA,ADPS1) ;
    cbi(ADCSRA,ADPS0) ;
  #endif
}

const unsigned PauseForSlowComputer = 50;

void loop() {
  int val;
  val = analogRead(A0);
  delayMicroseconds( PauseForSlowComputer );
  Serial.println(val);
}


You are totally right! My goodness I should have thought about that. Thank you so much for your helpful experience! Finally got it: it worked when the sinusoid curve is there because it added a wait time between writing the serial port!

And - thank you for running the test too! Really appreciate it.

I will now update the title to show it has been answered.



Robin2

Thank you Robin for your response! I did read your code before you post, but I thought that was a different kind of data being read. Mine was continuous data streaming from the sensor, with delimiters ("\r\n").
So use \r\n as a delimiter in place of the <> that my code uses. In fact you can probably just use \n on its own.

The second example in serial input basics just uses an end-marker rather than start- and end-markers.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Go Up