I'm currenty working on an interface between arduino and raspberry pi. The arduino is connected via usb cable to the Rasbperry Pi. The Arduino has an LED connected to a digital Pin that may be turned on and off by sending specified bytes over the USB serial connection. The Raspberry Pi then runs the following python script:
import serial
import time
arduino = serial.Serial('/dev/ttyACM0', baudrate=115200, timeout=.1)
time.sleep(2)
start = time.time()
for _ in range(10):
arduino.write(bytes([0x58])) //Turns LED on (on Arduino)
print(time.time()-start,'on')
time.sleep(.5)
arduino.write(bytes([0x18])) //Turns LED off (on Arduino)
print(time.time()-start,'off')
time.sleep(.5)
arduino.write(spam_the_COM_port) # will let the arduino start sending
# infinite amout of bytes
print('started spamming')
for _ in range(10):
arduino.write(turn_led_on) #Actual byte is 0x58
print(time.time()-start,'on')
time.sleep(.5)
arduino.write(turn_led_off) #Actual byte is 0x18
print(time.time()-start,'off')
time.sleep(.5)
So I'm switching on and off an LED that is connected to an arduino by sending it the specified bytes: 0x58 and 0x18 The Arduino runs code that looks like this:
bool spamming = false;
void setup()
{
Serial.begin(115200);
pinMode(24, OUTPUT);
}
void loop()
{
while(Serial.available() > 0)
{
unsigned char x = Serial.read();
if (x == 0x58)
{
digitalWrite(24, HIGH); //Turn on LED
}
else if (x == 0x18)
{
digitalWrite(24, LOW); //Turn off LED
}
else if (x == 0x00)
{
spamming = true;
}
}
if (spamming)
{
if (Serial.avialiableForWrite() > 0) Serial.write(0x01);
}
}
I get the expected result (which is just the console printing on and off 10 times (on the raspberry side) and the Arduino actually turning the LED on and off 10 times in a row.
I then send a command that will make the Arduino start sending an infinite amount of bytes to the Raspberry Pi whilst still checking the Serial incoming buffer for new commands. After that I repeat the same process as before and try to send the LED switching command.
Now the python console output stays the same (runs without any error raising), yet the program blocks at each arduino.write() command for a long time (around 10s or longer) even though there is a timeout specified (0.1s). After blocking, the console prints as usual and the LED on the arduino switches as usual. I just added timesamps to the python console output and the results look like this:
2.002582311630249 on
2.502887725830078 off
3.003848075866699 on
3.5050783157348633 off
4.005117177963257 on
4.5058839321136475 off
5.006282806396484 on
5.50661826133728 off
6.008156776428223 on
6.509922504425049 off
7.010948181152344 on
7.512096166610718 off
8.012341737747192 on
8.513236999511719 off
9.013462543487549 on
9.514604091644287 off
10.015231370925903 on
10.515642404556274 off
11.01583743095398 on
11.516374349594116 off
started spamming
12.018024444580078 on
12.518478155136108 off
13.01881217956543 on
13.519550085067749 off
28.621582508087158 on
44.68230104446411 off
57.40802550315857 on
63.064852714538574 off
65.58953928947449 on
68.61984610557556 off
77.50833535194397 on
96.19384908676147 off
102.6581130027771 on
109.2223105430603 off
132.55511474609375 on
155.684588432312 off
171.44103860855103 on
185.78372859954834 off
199.51972341537476 on
216.58949422836304 off
So the problem must be on the raspberry pi. I tried the same code on my windows machine (plugging the arduino in there of course) and the same thing happened, which led to the conclusion that it must have something to do with the virtual COM/Serial port.
So now to the actual question: Why does it take so long for the serial.write() function to write something to the output buffer (on the pi) when the input buffer (on the pi) is beeing spammed by the arduino? As far as I know, a UART Chip has two physically seperate buffers that are completely independent. Does a virtual COM port not have this independence of the two buffers? (Maybe just some allocated memory for both of them in a stack-heap kind of way?) Or is the problem that USB 1.0 and 2.0 are only half-duplex? (And then lastly is there a way to fix the fucntion block?)
[update] I managed to stop the function from blocking by adding
if arduino.inWaiting() > 1000: arduino.flushInput()
before every arduino.write()
statement. I'm still interested in how the Serial/COM port is managed by the operating system, be it linux/raspbian or windows.