Go Down

Topic: Arduino Uno serial speed issue (Read 2554 times) previous topic - next topic

Exodus

Hello, we were previously using a Duemilanove.  We've gone to the Uno at first all appeared to go well.  We are sending 3 bytes of information at 60Hz.  The Duemilanove with the FTDI took this no problem.  However, the Uno just goes dead at that rate.  I had to back it off by about 15Hz down to 45Hz to get it to perform consistently.  At about 53Hz it becomes unstable and the output becomes erratic.  Is this a limitation of the new native USB controller on the Uno?  I saw an earlier thread about serial library incompatibility.  We are using Spi for our shield and the Serial.* family of calls for our USB comms.  Will using NewSerial* solve the speed issue?

I would like to use the Arduino platform in the future to replace a simulation controller platform that is now obsolete.  That clearly is a task for a more sophisticated version of the Arduino but if it uses the same USB controller and that is where the performance issues lie then that wouldn't be an option.

thanks, this is an awesome platform!

mellis

What baud rate are you using?  What program or hardware are you using to talk to the Uno?  Do you have any example code we can try?

The actual speed used for Serial.begin(57600) differs in the core library in 0021 from the one used by the 8U2 firmware.  This will be fixed in the next release: https://github.com/arduino/Arduino/commit/66755f9bced2009612052800ef7f1a0b9afde3c5.  

Exodus

Thanks for the prompt response!  The rate is 115200.  I am using the USB port of a Dell Optiplex 755 which is the same hardware I was using previously with the Duemilanove.  Here is the source code:


#include <Spi.h>

// Melexis definitions
#define MLX_START_BIT   0x80
#define MLX_RESET_PIN   8
#define MLX_ERRB_PIN    9

#define SER_READ_DELAY  10 // in microseconds

#define GAUGE_LOOKUP { 0x00, 0x10, 0x30, 0x40, 0x60, 0x50 }

#define OP_ZERO_GAUGE   0x0
#define OP_R_U_THERE    0x1
#define OP_SET_GAUGE    0x2
#define OP_DEBUG        0x7

#define ACK_CODE_BIT    0x80
#define RC_OK           0X00
#define RC_ERR_UOP      0x01  // Unknown op code received
#define RC_ERR_MDATA    0x02  // Missing expected data packets
#define RC_ERR_OP_WDATA 0x03  // Wrong number of data packets for op
#define RC_ERR_INV_METR 0x04  // Invalid meter or gauge specified

const byte gauge_lookup_tbl[6] = GAUGE_LOOKUP;

int data = 2;
int clock = 3;
int latch = 4;
int debug = 0;

void setup() {
 int  var = 0;
 byte spi_config = 0;
 
 Serial.begin(115200);
 pinMode(MLX_RESET_PIN, OUTPUT);
 pinMode(MLX_ERRB_PIN, INPUT);
 pinMode(data, OUTPUT);
 pinMode(clock, OUTPUT);
 pinMode(latch, OUTPUT);

 var = digitalRead(MLX_ERRB_PIN);
 digitalWrite(MLX_RESET_PIN, HIGH);
 delayMicroseconds(8000);
 SPSR &= B11111110; // 0th bit is SPIX2
 spi_config |= (1 << SPE) | (1 << MSTR) | (1 << SPR0);
 Spi.mode(spi_config);
}


void loop() {
 byte cmd = 0, dataPackets = 0, data[3];
 int rc = RC_OK, val = 0, gaugeNum = 0;
 
 data[0] = 0; data[1] = 0; data[2] = 0;
 
 if (Serial.available()) {
   cmd = Serial.read();
   updateLEDs(cmd);
   if (cmd == -1) return; // If nothing read no need to continue
   dataPackets = (cmd >> 3) & 0x3;
   switch(cmd >> 5) {
   case OP_SET_GAUGE:
     gaugeNum = cmd & 0x3;
     if (dataPackets != 2)
       rc = RC_ERR_OP_WDATA;
     else if (gaugeNum < 1 || gaugeNum > 5)
       rc = RC_ERR_INV_METR;
     else {
       rc = readDataBytes(data, dataPackets);
       if (rc == RC_OK) {
         val = data[0] << 8 | data[1];
         setGauge(gaugeNum, val);
       }
     }
     // TODO: Check pin ERRB on melexis to detect errors and return them
     //sendAck(RC_OK);
     break;
   case OP_ZERO_GAUGE:
     gaugeNum = cmd & 0x3;
     if (dataPackets != 0)
       rc = RC_ERR_OP_WDATA;
     else if (gaugeNum < 1 || gaugeNum > 5)
       rc = RC_ERR_INV_METR;
     else
       initMainLogometers();
     break;
   case OP_R_U_THERE:
     if (dataPackets != 0)
       rc = RC_ERR_OP_WDATA;
     break;
   case OP_DEBUG:
     debug = 1;
     if (dataPackets != 0)
       rc = RC_ERR_OP_WDATA;
     break;
   default:
     rc = RC_ERR_UOP;
     break;
   }
   sendAck(rc);
 }

}


int readDataBytes(byte *data, int count) {
 int i = 0, readCount = 0;
 byte cmd;
 
 for (i = 0; i < count; i++) {
   do {
     data = Serial.read();
     readCount++;
     if (data == -1)
       delayMicroseconds(SER_READ_DELAY);
     else
       break;
   } while (readCount < 10);
   if (data == -1)
     return RC_ERR_MDATA;
 }
 return RC_OK;
}


void sendAck(int errCode) {
 byte cmd = 0;
 
 cmd = ACK_CODE_BIT | (errCode & 0x7f);
 Serial.write(cmd);
}


void setGauge(int gauge, int val) {
 int quad = 0, offset = 0;
 
 quad = 0x3 & (3 + (val/512));
 offset = val % 512;
 sendByComp(gauge, quad, offset);
}


void initMainLogometers () {
 int i = 0, calDelay = 1000, quad = 0, offset = 0;
 for (i = 200; i < 1500; i += 4) {
   delayMicroseconds(calDelay);
   quad = 0x3 & (3 + (i/512));
   offset = i % 512;
   sendByComp(1, quad, offset);
   sendByComp(2, quad, offset);
 }
 for (i = 1500; i >= 200; i -= 4) {
   delayMicroseconds(calDelay);
   quad = 0x3 & (3 + (i/512));
   offset = i % 512;
   sendByComp(1, quad, offset);
   sendByComp(2, quad, offset);
 }
}


void sweepMainLogometers () {
 int i = 0, j = 0, calDelay = 2000;
 for (j = 3; j < 7; j++) {
   for (i = 0; i < 512; i++) {
     delayMicroseconds(calDelay);
     sendByComp(1, 0x3&j, i);
     sendByComp(2, 0x3&j, i);
   }
 }
 for (j = 6; j >= 3; j--) {
   for (i = 511; i >= 0; i--) {
     delayMicroseconds(calDelay);
     sendByComp(1, 0x3&j, i);
     sendByComp(2, 0x3&j, i);
   }
 }
}


void sendByComp(int gauge, int quad, int val) {
 byte b1;
 byte b2;
 
 if (val < 0 || val > 511) {
   pDataValidationError("Error valid quadrant table lookups are 0 to 511, received ", val);
   return;
 }
 
 if (quad < 0 || quad > 3) {
   pDataValidationError("Error valid quadrants are 0 to 3, received ", quad);
   return;
 }
 
 b1 = MLX_START_BIT | gauge_lookup_tbl[gauge] | (val >> 5);
 b2 = 0x00 | val << 3 | quad;
 
 digitalWrite(SS_PIN, HIGH);
 Spi.transfer(b1);
 Spi.transfer(b2);
 digitalWrite(SS_PIN, LOW);
}


void pDataValidationError(char *msg, int val) {
 Serial.print(msg);
 Serial.print(val);
 Serial.println();
}


void updateLEDs(int value){
 digitalWrite(latch, LOW);     //Pulls the chips latch low
 shiftOut(data, clock, MSBFIRST, value); //Shifts out the 8 bits to the shift register
 digitalWrite(latch, HIGH);   //Pulls the latch high displaying the data
}

mellis

Can you reduce this to a simple program with the same problem?  What software is running on the computer?

vext01

Is this related?:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1292954023

Exodus

Great question, perhaps it is!  I will have to try that and see.

Go Up