improve my USB transfert rate

Hi every body,

I have a problem with Serial.print(). I saw, in the documentation, that print writes ASCII text (8bits) and I need to send only one bit (for more speed) =>>> How can I do ?

more explications of my context:
I want to sample a binary signal at 44kHz, each loop must not exceed 22 microseconds :

boolean val;

void loop() {
val = digitalRead(inPin);
Serial.print(val);
}

with 115200 baudrate in theory I need 8,68 microsec to send 1bit (that’s enaugh!)
but when I test this delay, I found 85 microseconds (about 69,44 microsec for 8 bits + the digital read).

thx for your help !!

It is impossible to send a single bit using Serial because it is designed for sending bytes.

Serial.write() should be faster than Serial.print() as it just sends the binary value without converting it to text. However that can make things more complex on the receiving end - about which you have told us nothing.

I regularly use my Uno at 500,000 baud. At that rate a single byte (10 bits) should take about 20 µsecs. I suspect that is still too close to your target of 22 µsecs. The Uno should also work at 1,000,000 baud.

A better solution, if you just want to send a single bit for each sample (i.e. a 1 or 0), would be to consolidate 8 readings into a single byte. That would greatly reduce the required serial throughput.

...R

Direct port manipulation can read pins much faster than digitalRead.

Is it an option to collect 8 bits first and next send them as one byte?

What is the receiving side? I think the Uno can do 500000 baud, that would be fast enough to send a byte per sample.

Hmm, Robin did beat me :slight_smile:

I use an arduino nano v3…
I will try the 3 ideas :

  • replace print by write
  • test a bigger baudrate
  • read faster with direct port manipulation

Thx for the ideas :slight_smile:

alexrtou:
I will try the 3 ideas :

The 4th idea (which you did not mention) is probably the most important - sending 8 bits in a single byte to reduce the required Serial throughput by a factor of 8

...R

hey hey,
This 4th idea, is not possible...

22µs
|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|...

Read (8 times):

|----|----|----|----|----|----|----|----| ? ? ? |----|----|----|----|...
Send (68µs = about 3 read):

|----|----|----| ...

alexrtou:
This 4th idea, is not possible...

I don't understand why that is so as I don't understand your diagram.

And I suspect you are misunderstanding what we have in mind.

...R

Regarding reply#6

68us (not sure where that comes from) is indeed about 3 reads; but you can ignore that. When using serial, data is placed in a software buffer (if the buffer is empty, the first byte is straight away placed in the TX register of the UART and the remainder goes in the software buffer). After that the hardware and interrupts takes care of the transmission so it does not block the code during those 68us and you can happily do your 3 meausrements.

You do 8 measurements which takes 8x22us = 176us. Transfer of the byte at 500kBits per second takes 20us. Leaves you ages (~ 150us) to do other stuff as well. Even at a more normal baudrate of 115200 the transfer of the byte takes less than 100us.

My impression is that you want to send serial data synchronously. The UART in the AVR sends asynchronously, using framing bits (start and stop) as well as one parity bit. Those are probably the "extra 3 bits" that you have calculated. You should have taken the time to investigate standard serial protocols at the level of sophistication that you expect your program to operate.

There are ways of sending synchronous data, but then you have to have some method of "framing" the data... knowing where segments of it begin and end.

I'm back :slight_smile:

here is my result :

  • I set serial baudrate to 230400. This is nearly my baudrate max on my nano v3.
  • I simplify the code to the minimum :

void loop() {
Serial.print(digitalRead(pin));
}

I am able to sample to 22kHz. I did my best :slight_smile:

thanks every body