Go Down

Topic: Solved: Sanguino, servo, LCD, and serial... (Read 1 time) previous topic - next topic

stratosfear

Oct 17, 2011, 12:46 pm Last Edit: Oct 25, 2011, 04:22 pm by stratosfear Reason: 1
Long time lurker, first post...

I’m trying to run servos, a 16x4 LCD, and hardware serial on a Sanguino board.  When there’s no incoming serial, I get an occasional and barely perceptible twitch on the one servo connected.  When the Sanguino is receiving serial data, the servo jitters continuously.  The same code runs on a Mega2560 without the jitter. 

The jitter can be measured with an o-scope when the servo and LCD are removed, so it’s not the hardware, power supply, or grounds.  A 1500uS pulse will jump by 50 to 90 uS.  Just to make sure it’s not the transmitter end, I even substituted a Duemilanove running a short piece of code. 

Since I’ve eliminated all the external hardware, I have to suspect incompatibility between the Sanguino core files and Arduino libraries.   Is anyone willing to confirm this, suggest a fix, or find an error in my program?



Sanguino receiver:

Code: [Select]


/*  receiver serial in
   
    Serial data is 21 byte frame.
    Frame prefix is 0xaa, 0xaa.
    Frame suffix is 0xed, 0xed.
    Eight 'little-endian' words, followed by one byte.
    High nibble of high byte indicates channel number.
    Value of Low three nibbles is 2 * pulsewidth in microseconds.


   LCD pin     Arduino pin
   1 = GND     GND
   2 = VCC     VCC
   3 = n/c     (LCD contrast)
   4 = RS      D7
   5 = R/W     D6
   6 = ENB     D5
   7 = D1      n/c
   8 = D2      n/c
   9 = D3      n/c
  10 = D7      n/c
  11 = D4      D4
  12 = D5      D3
  13 = D6      D2
  14 = D7      D1
*/

#include <LiquidCrystal.h>  //The liquid crystal display library
//LiquidCrystal(rs, rw, enable, d4, d5, d6, d7);
LiquidCrystal lcd(7, 6, 5, 4, 3, 2, 1);  //Assign pin functions

//Servo library and servo initialization
#include <Servo.h>
Servo ch1Out;
Servo ch2Out;
Servo ch3Out;
Servo ch4Out;
Servo ch5Out;
Servo ch6Out;
Servo ch7Out;
Servo ch8Out;


//Initialize 21 byte frame buffer
byte rcv[] = {0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00,
              0x00};

byte printFormat = 1;  //0 prints raw data.  1 prints decoded data
byte lcdDiag = 1;      //0 bypasses LCD printing, 1 prints to LCD
byte clearLCD = 0;     //Flag for "Ready" message erased
unsigned long elapsedStart;  // microseconds since last LCD update
           
void setup()  {
  Serial1.begin(125000);  //Yes, 125000 baud!
 
  lcd.begin (16,4);  //16 x 4 LCD
  //Tell user we're ready
  lcd.setCursor (0,0);
  lcd.print ("Ready");
 
  //attach the servos
  ch1Out.attach(15);
  ch2Out.attach(16);
  ch3Out.attach(17);
  ch4Out.attach(18);
  ch5Out.attach(19);
  ch6Out.attach(20);
  ch7Out.attach(21);
  ch8Out.attach(22);
 
  elapsedStart = micros();
}


void loop()  {
  if (Serial1.available() >0)  {  //Read byte from uart if available
    rcv[20] = Serial1.read();

    if ((rcv[0] == 0xaa) && (rcv[1] == 0xaa) && (rcv[19] == 0xed) && (rcv[20] == 0xed))  {
      //We have a valid frame, process it.

      ch1Out.writeMicroseconds(xlate(3));
      ch2Out.writeMicroseconds(xlate(5));
      ch3Out.writeMicroseconds(xlate(7));
      ch4Out.writeMicroseconds(xlate(9));
      ch5Out.writeMicroseconds(xlate(11));
      ch6Out.writeMicroseconds(xlate(13));
      ch7Out.writeMicroseconds(xlate(15));
      ch8Out.writeMicroseconds(xlate(17));

      if (lcdDiag == 1)  {
        lcdPrint();
      }
    }

    else  {
      /* We don't have a valid frame, so roll buffer contents
         one location to prepare for next byte from uart.  */
       for (byte count = 0; count <=19; count++)  {
        rcv[count] = rcv[count + 1];
      }
    }
  }
}

unsigned int xlate(byte index)  {
  /* Strip upper nibble from high byte.  combine with low byte to get value.
  divide by 2 to get pulsewidth in microseconds.  */
  unsigned int ch = (((rcv[index] & 0x0f) * 0x100) + rcv[index - 1]) / 2;
  return ch;
}

void lcdPrint()  {
    if (clearLCD == 0)  {  //only clear screen once, reduce flickering
      lcd.clear();
      clearLCD = 1;
    }

  if (printFormat == 0)  {
    // prints raw hex data as received

    printChVal(rcv[0], 0, 0);
    printChVal(rcv[1], 3, 0);
    printChVal(rcv[2], 6, 0);
    printChVal(rcv[3], 9, 0);
    printChVal(rcv[4], 12, 0);

    printChVal(rcv[5], 0, 1);
    printChVal(rcv[6], 3, 1);
    printChVal(rcv[7], 6, 1);
    printChVal(rcv[8], 9, 1);
    printChVal(rcv[9], 12, 1);

    printChVal(rcv[10], 0, 2);
    printChVal(rcv[11], 3, 2);
    printChVal(rcv[12], 6, 2);
    printChVal(rcv[13], 9, 2);
    printChVal(rcv[14], 12, 2);

    printChVal(rcv[15], 0, 3);
    printChVal(rcv[16], 3, 3);
    printChVal(rcv[17], 6, 3);
    printChVal(rcv[18], 9, 3);
    printChVal(rcv[19], 12, 3);
    printChVal(rcv[20], 14, 3);
  }

  else  {
    //prints data converted to microseconds

    //calculate elapsed time since last valid frame and print on top row at right
    lcd.setCursor (10,0);
    lcd.print(micros() - elapsedStart, DEC);
    lcd.print(" ");
    elapsedStart = micros();
 
    printChVal(xlate(3), 0, 0);
    printChVal(xlate(5), 5, 0);

    printChVal(xlate(7), 0, 1);
    printChVal(xlate(9), 5, 1);
   
    printChVal(xlate(11), 0, 2);
    printChVal(xlate(13), 5, 2);
   
    printChVal(xlate(15), 0, 3);
    printChVal(xlate(17), 5, 3);
   
    lcd.setCursor(10,3);
    lcd.print(rcv[18],DEC);
  }
}

void printChVal (unsigned int chanVal, byte col, byte row){
  lcd.setCursor(col, row);
  if (printFormat == 0)  {
    lcd.setCursor (col,row);
    lcd.print(chanVal, HEX);
  }
 
  else  {
    if (chanVal < 1000)  {  //print a leading space if less than 4 characters
      lcd.print(" ");
    }
    lcd.print(chanVal, DEC);
  }
}



Duemilanove transmitter:

Code: [Select]

//tx emulator

/* two prefix bytes, eight servo words, one unknown byte, two suffix bytes.
   all times are 1500uS */
byte tx[] = {0xaa, 0xaa,
             0xb8, 0x1b, 0xb8, 0x2b,
             0xb8, 0x3b, 0xb8, 0x4b,
             0xb8, 0x5b, 0xb8, 0x6b,
             0xb8, 0x7b, 0xb8, 0x8b,
             0x00, 0xed, 0xed};

void setup()  {
  Serial.begin(125000);  //to conform with device
}

void loop()  {
  long unsigned mSec;  //timing reference
  if (millis() - mSec >= 20)  {  //transmit a frame approx. every 20mS
    for (byte txCount = 0; txCount <=20; txCount++){
      Serial.write(tx[txCount]);
    }
  }
  mSec = millis();  //renew the timing reference
 
}





Thanks,
Jon

Paul Stoffregen

This sounds like issue 146

http://code.google.com/p/arduino/issues/detail?id=146

Maybe Sanguino never implemented this fix?

Just look at digitalWrite() inside wiring_digital.c to see if it's properly disabling interrupts when writing to the port register through the pointer.  Copy the fix from issue 146 and your jitters will probably be a thing of the past.

stratosfear


Thanks for the suggestion, Paul.  You're correct about the missing lines, and you've also confirmed my suspicion about corrupted interrupts.  My servo still jitters, however, so I'm going to install Arduino-0018 and use the modified file. 

Jon


stratosfear


Okay, Arduino-0018 did no good at all, so I returned to 0022 and started looking through the core files to see if anything looked wrong - not that I'm any good reading someone else's code.  On a guess, I deleted all the Sanguino core files, except pins_arduino.c and pins_arduino.h.  Then I copied all the other Arduino core files to the Sanguino core directory.  Now, I've got a nice, quiet servo! 

Although this procedure solved one problem, it may introduce others as my program expands.  Still, I'm confident enough to proceed with a circuit board. 

Jon

CrossRoads

You could also try the cores here
avr-developers.com

They seem to work well with -0022 and '1284 boards ('644 with 2x the memory)
Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Go Up