Pages: 1 [2]   Go Down
Author Topic: Poor serial performance when sending data from RaspberryPi to Arduino  (Read 6080 times)
0 Members and 1 Guest are viewing this topic.
London, UK
Offline Offline
Newbie
*
Karma: 1
Posts: 41
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello Arduino hivemind. I'm still struggling with getting decent speed sending serial data between my Rasberry Pi and Arduino.

To recap:

I'm driving an Arduino Mega from a Raspberry Pi. The mega runs code from Adafruit to drive an LED Matrix. I want to pump 'screens' of pixel data from the Pi over the serial link to the mega to display. Each 'screen' is 32x32 RGB pixels.

Pixels are encoded as 4 bits per colour, so 12 bits make up one pixel. I can therefore send 2 pixels P1 and P2 in 3 bytes as: R1G1, B1R2, G2B2.

The matrix is 32x32 = 1024 pixels. Each pixels is 1.5 bytes, so a whole frame takes 1536 bytes. At 115200 baud using 8N1 I should get something like 92160bits to play with (80% of 115200) or 11520 bytes/s or 11.5 KB/s.

With a rate of 11.5KB/s I reckon I should be able to send 8 or 9 frames per second.


So... I tried using Python on the Pi as the sending code but it was too slow (using things like arrays) so I've switched to C.

The test script below sends a control byte to choose "draw screen mode" then 1536 bytes of data to show a screen of red pixels , then repeats with a screen of green pixels , then blue. However I'm only seeing 1 or so FPS (with the delays in the sender code). If I remove the delays my output gets garbled - a mess of RGB pixels.

I first tried connecting the two boards over the USB serial link, but Grumpy_Mike mentioned the converter chips encapsulate my data in frames of their own so the data rate isn't maintained. So now I'm using the secondary UART on the Pi (/dev/ttyAMA0), and that is going direct into the Arduino Mega (Serial1). (I've commented this out in /etc/initab).

I've tried increasing the buffer on the arduino by changing the value in HardwareSerial.cpp but it makes no difference.

When I was connected via serial over USB I had the Arduino ACKing (by printing an "A") after receiving each byte and then waiting for the ACK in the sendData function before continuing. This worked but was also slow. 1 frame a sec or so.

I'm not sure where what else to try, other than using something like SPI instead.

Any thoughts appreciated...


Here is the C send code that runs on the Pi:
Code:
#include "rs232.h"
#include <sched.h>

#define COMPORT         0           // this is '/dev/ttyAMA0' (for raspberry pi UART pins)
#define BAUDRATE        115200   // or whatever baudrate you want
#define RECEIVE_CHARS 4096      // or whatever size of buffer you want to receive
#define SEND_CHARS      1          // or whatever size of buffer you want to send



//Set high Priority - Need to be root to do this.
void setHighPri (void)
{
  struct sched_param sched ;

  memset (&sched, 0, sizeof(sched)) ;

  sched.sched_priority = 10 ;
  if (sched_setscheduler (0, SCHED_RR, &sched))
    printf ("Warning: Unable to set high priority\n") ;
}



void sendData(unsigned char send_byte){

   SendByte(COMPORT, send_byte);
    usleep(250);     

}



void drawScreen(int r1, int g1, int b1){ //pass in rgb colours for all pixels - this is a test so dont need to set individual pixels

sendData(3); //3 = enter drawScreen mode

int x=0;
int y=0;
int r2,g2,b2 //pixels
int byt1,byt2,byt3; //3 bytes = 2 pixels

//2 pixels per 3 bytes. 1024 pixels = 1536 bytes to send
while (y < 32){

               //r1=0 //Pixel 1 to send - these would normally be set individually via an array but passed in for this test
               //g1=0
               //b1=0

x++; //goto next pixel

r2 = r1; //Pixel 2 - again would normally set via array but - just set to same as 1st pixel for this test
g2 = g1;
b2 = b1;

x++; //goto next pixel

        if (x==32){
    x=0;
            y=y+1;
        }
       
    //send 3 bytes now we have our 2 pixels, pack nibbles into byte
        byt1 = 0xff & (((0xff & g1) << 4) | (0xff & r1)); //pack r in lhs g rhs
    sendData(byt1);
       
        byt2 = 0xff & (((0xff & r2) << 4) | (0xff & b1));
        sendData(byt2);
       
        byt3 = 0xff & (((0xff & b2) << 4) | (0xff & g2));
        sendData(byt3);
       
}
}


int main (int argc, char **argv) {

setHighPri () ; //run as high priority - doesnt seem to make any odds

OpenComport(COMPORT, BAUDRATE);
sleep(2);

while(1) {
drawScreen(5,0,0); //draw screen of red
usleep(1000);
drawScreen(0,5,0); //draw screen of green
usleep(1000);
drawScreen(0,0,5); //draw screen of bue
usleep(1000);
}
CloseComport(COMPORT);
}





Here is the arduino receive code:
Code:
#include "RGBmatrixPanel.h"

#define A   5 //A3
#define B   4 //A2
#define C   3 //A1
#define D   2 //A0
#define CLK 10  // was 8 MUST be on PORTB!
#define LAT 9
#define OE  7
RGBmatrixPanel matrix(A, B, C, D, CLK, LAT, OE, true);

void setup() {
  Serial1.begin(115200);
  matrix.begin();
  //Serial.println("matrix routine started");
}

void loop() {

  byte incomingByte = 0;

  if (Serial1.available() > 0) {  //if > 1 get 1st byte which is control byte
   
    // read the incoming byte:
    incomingByte = Serial1.read();

    switch (incomingByte) {
    case 0:
      //Serial.println("clear screen");
      clearDisp(); 
      break;
    case 1:
      //Serial.println("swap buffers");
      matrix.swapBuffers(false);
      break;
    case 3:
      //Serial.println("Drawing screen of 1024 pixels");
      drawScreen();
      break;
    case 49:
      Serial.println("light a test led");
      testLed();
      break;
      //default:
      //Serial.println("unknown cmd");
    } 
  }
}



void drawScreen() {

  //Receiving 32x32 pixels = 1024 pixels. Each pixel is 3x4 bit values, so each pixel = 1.5 bytes. Total bytes to receive is 1536

  byte x = 0; //screen x
  byte y = 0; //screen y
  byte r = 0; //red
  byte g = 0; //green
  byte b = 0; //blue
  byte data = 0; //incoming byte

  //unsigned long startTime= millis();

  while (y < 32 ) { 

    //wait for 1st byte of data
    while (Serial1.available() < 1) {
      //do nothing
    }
   
    //ack
    //Serial.print("A");
   
    //read 1st byte and split into 2 lots of 4 bits, (red and green)
    data = byte (Serial1.read());
    r = data & B00001111;
    g = data >> 4; 
   
    //wait for 2nd byte
    while (Serial1.available() < 1) {
      //do nothing
    }
   
    //ack
    //Serial.print("A");
   
    //read 2nd byte - b and r of next pixel
    data = byte (Serial1.read());
    b = data & B00001111;
   
    //draw pixel 1
    matrix.drawPixel(x, y, matrix.Color444(r,g,b));

    //inc x for next pixel along
    x++;
   
    //get red val from 2nd byte for 2nd pixel
    r = data >> 4; 

    //wait for 3rd byte
    while (Serial1.available() < 1) {
      //do nothing
    }
   
    //ack
    //Serial.print("A");
   
    //read 3rd byte, g and b
    data = byte (Serial1.read());
    g = data & B00001111;
    b = data >> 4;

    //draw pixel 2
    matrix.drawPixel(x, y, matrix.Color444(r,g,b));

    //inc for next pixel or reset if x at end of row
    if (x == 31){
      x=0;
      y++;
    }
    else {
      x++;
    }         
  }

  //print time it took
  //Serial.println(millis() - startTime);

  //when all data received, swap buffers to show screen
  matrix.swapBuffers(false);

}

void clearDisp() {
  matrix.fill(matrix.Color333(0, 0, 0));
}

void testLed() {
  matrix.drawPixel(0, 0, matrix.Color444(15,0,0));
  matrix.swapBuffers(false);
  delay(500);
  matrix.drawPixel(0, 0, matrix.Color444(0,0,0));
  matrix.swapBuffers(false);
}

Logged

0
Offline Offline
God Member
*****
Karma: 39
Posts: 986
Get Bitlash: http://bitlash.net
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Do you see the same problems at a really slow baud rate like 9600?

If you send fast enough to get ahead of the arduino's read/draw loop by more than the size of the serial buffer on the arduino there will be lost characters, right?

You may have to transmit that big packet in smaller chunks to avoid the pig-in-the-anaconda effect.

-br
Logged

London, UK
Offline Offline
Newbie
*
Karma: 1
Posts: 41
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok i think you might be right. I realised I adjusted the serial buffer on the wrong Arduino version so it didnt take effect. I've pushed it all the way up to 512 bytes and I can now get away with removing all the pauses apart from a usleep(1) after sending every bit (in the sendData function.)

Pushing the buffer to 1024 as mentioned in a few posts http://forums.reprap.org/read.php?218,86984,86984,quote=1 seems to hand the arduino somewhere, plus I'm sure it's not the most elegant solution.

It seems a little faster to the eye through the secondary UART rather than the USB. I'm getting maybe 2/3 FPS now. Still not fast enough for what i'd like though.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 548
Posts: 46042
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Pushing the buffer to 1024 as mentioned in a few posts http://forums.reprap.org/read.php?218,86984,86984,quote=1 seems to hand the arduino somewhere, plus I'm sure it's not the most elegant solution.
Since the buffer size affects both the incoming and outgoing buffers for all the instances of HardwareSerial, of which there are 4 on the Mega, setting the buffer size to 1/8 of the available SRAM will cause every bit of SRAM to be used just for the Serial functions. That doesn't seem like a good idea to me.

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hi, sorry for my bad english.
But i have the similar problem with a program in c#, I has open the COM port at 250.000 bps in pc and in the arduino leonardo.

But really the port always is opening at 9600 bps, trought virtual port COM the faster speed is 9.600 bps.

I think that trought a dll is posible

With a ft232 i has the same problem, virtual COM = 9.600 bps max, but using the d2xx.dll until 3.000.000 bps

I need know how to do the same with arduino leonardo (trought a dll)

If you know please tell me

thanks
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 548
Posts: 46042
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
If you know please tell me
I know that your issue has absolutely nothing to do with communication between a Raspberry Pi and an Arduino, so I know that tacking it onto the end of this thread was wrong.

Besides, no one can help you without seeing your code, and some proof that the port is only communicating at 9600 baud despite being told to operate at a different speed.

I also know that you will have no success at trying to load a dll on the Arduino.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

sorry I do not speak English very well and I got confused.
Thanks for the clarification
Logged

Pages: 1 [2]   Go Up
Jump to: