ADNS5050

Has anyone successfully interfaced one of these (ref http://www.avagotech.com/pages/en/navigation_interface_devices/navigation_sensors/led-based_sensors/adns-5050/) with an Arduino? I’ve been working off of this old forum post http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1154816099 (nb in French) and the sparkfun code for the 2620 (http://www.sparkfun.com/products/10105) but I’m not having any luck even just getting the ADNS5050 to respond with its PRODUCT_ID.

I’ve wired it up as shown in the diagram. Not sure why all the capacitors are necessary, but I’m simply following the diagram from the datasheet. Excuse the image too, fritzing isn’t being my friend lately. Anything obvious that I’m missing or does anyone have any advice? I’d be happy to post code if it’s helpful.

Your first link gives - page not found - error

Odd, guess the Avago site can't redirect w/o the trailing '/', the link is corrected: http://www.avagotech.com/pages/en/navigation_interface_devices/navigation_sensors/led-based_sensors/adns-5050/

From the link

Description The ADNS-5050 is a mainstream, small form factor optical mouse sensor. It is a user-friendly product with many built-in features and optimized for LED-based corded products. The ADNS-5050 is capable of high-speed motion detection – up to 30ips and 8g. In addition, it has an on-chip oscil-lator and built-in LED driver to minimize external compo-nents. Frame rate is also adjusted internally.

The sensor is programmed via registers through a three-wire SPI interface.

The PDF - http://www.avagotech.com/docs/AV02-1045EN - shows a schematic how to build a mouse (figure 8) and has a description of how a read operation should work.

Can you post your code ?

Here’s the code. The 3 wire SPI seems to be (unless I misunderstood) the CS pulled low, and then a clock and IO pin. I’ve set these on 2 and 3. The CS pin, I just set on 4.

#define SCLK                3
#define SDIO                2

#define PRODUCT_ID          0x00
#define DELTA_Y_REG         0x03
#define DELTA_X_REG         0x04
#define SQUAL_REG           0x05
#define MAXIMUM_PIXEL_REG   0x08
#define MINIMUM_PIXEL_REG   0x0a
#define PIXEL_SUM_REG       0x09
#define PIXEL_DATA_REG      0x0b
#define SHUTTER_UPPER_REG   0x06
#define SHUTTER_LOWER_REG   0x07
#define RESET				0x3a
#define CPI500v				0x00
#define CPI1000v			0x01

const int NCS = 4;

void setup()
{
  Serial.begin(57600);

  pinMode(NCS, OUTPUT);
  digitalWrite(NCS, LOW);

  pinMode(SDIO, OUTPUT);
  pinMode(SCLK, OUTPUT);

  delay(50); //from PD inactive (when NRESET pin is asserted high or write 0x5a to register 0x3a) to valid motion
  sync(); // 
  //call reset
  writeReg(RESET, 0x5a);
  delay(50); // From NRESET pull high to valid mo tion, assuming VDD and motion is present.

}

void loop()
{
  delay(100);
  Serial.print(readReg(PRODUCT_ID), DEC); // this should return 0x12 :/
}

//Essentially resets communication to the ADNS5050
void sync()
{
  digitalWrite(SCLK, HIGH);
  delay(1);
  digitalWrite(SCLK, LOW);
  delay(1);  
  digitalWrite(SCLK, HIGH);
  delay(100);
}

//Reads a register from the ADNS5050 sensor. Returns the result to the calling function.
char readReg(char address)
{
  char value=0;
  pinMode(SDIO, OUTPUT); //Make sure the SDIO pin is set as an output.
  digitalWrite(SCLK, HIGH); //Make sure the clock is high.
  address &= 0x7F;    //Make sure the highest bit of the address byte is '0' to indicate a read.

  //Send the Address to the ADNS5050
  for(int address_bit=7; address_bit >=0; address_bit--){
    digitalWrite(SCLK, LOW);  //Lower the clock
    pinMode(SDIO, OUTPUT); //Make sure the SDIO pin is set as an output.
    //If the current bit is a 1, set the SDIO pin. If not, clear the SDIO pin
    if(address & (1<<address_bit)){
      digitalWrite(SDIO, HIGH);
    }
    else{
      digitalWrite(SDIO, LOW);

    }
    delayMicroseconds(10);
    digitalWrite(SCLK, HIGH);
    delayMicroseconds(10);
  }
  delayMicroseconds(120);   //Allow extra time for ADNS5050 to transition the SDIO pin (per datasheet)
  //Make SDIO an input on the microcontroller
  pinMode(SDIO, INPUT);	//Make sure the SDIO pin is set as an input.
  digitalWrite(SDIO, HIGH); //Enable the internal pull-up

  //Send value byte
  for(int value_bit=7; value_bit >= 0; value_bit--){
    digitalWrite(SCLK, LOW);  //Lower the clock
    delayMicroseconds(10); //Allow the ADNS5050 to configure the SDIO pin
    digitalWrite(SCLK, HIGH);  //Raise the clock
    delayMicroseconds(10);
    //If the SDIO pin is high, set the current bit in the 'value' variable. If low, leave the value bit default (0).    
    //if((ADNS_PIN & (1<<ADNSSDIO)) == (1<<ADNSSDIO))value|=(1<<value_bit);
    if(digitalRead(SDIO))value |= (1<<value_bit);
  }
  return value;
}

//Writes a value to a register on the ADNS5050.
void writeReg(char address, char value)
{
  pinMode(SDIO, OUTPUT);	//Make sure the SDIO pin is set as an output.
  digitalWrite(SCLK, HIGH);          //Make sure the clock is high.
  address |= 0x80;    //the highest bit is '1' to indicate a write.

  //Send Address
    for(int address_bit=7; address_bit >=0; address_bit--){
    digitalWrite(SCLK, LOW); //Lower the clock
    delayMicroseconds(10); //small delay 
    //If the current bit is a 1, set the SDIO pin. If not, clear the SDIO pin
    if(address & (1<<address_bit))digitalWrite(SDIO, HIGH);
    else digitalWrite(SDIO, LOW);
    delayMicroseconds(10);
    digitalWrite(SCLK, HIGH);
    delayMicroseconds(10);

  }

  //Send the Value byte to the ADNS5050

    for(int value_bit=7; value_bit >= 0; value_bit--){
    digitalWrite(SCLK, LOW);  //Lower the clock
    //If the current bit is a 1, set the SDIO pin. If not, clear the SDIO pin
    if(value & (1<<value_bit))digitalWrite(SDIO, HIGH);
    else digitalWrite(SDIO, LOW);
    delayMicroseconds(10);
    digitalWrite(SCLK, HIGH);
    delayMicroseconds(10);
  }

}

Found another reference for this that I’m going to try to get into Arduino-ready shape. It’s Atmega328 code, if anyone is interested: http://servomagazine.com/index.php/magazine/article/july2011_mrroboto

I have worked on A5020 (with SCLK, NCS, SDIO). If your A5050 is similar than maybe I can help you out.

thanks nitin29. I’d love to hear any advice you have. I’m not sure if you meant that I should post all my code, but I’m going to go for it anyways. If anything in here looks wrong, I’d love to know about it. Thanks!

#define SCLK                18
#define SDIO                19

#define PRODUCT_ID          0x00 // should be 0x12
#define PRODUCTID2          0x3e
#define REVISION_ID         0x01
#define DELTA_Y_REG         0x03
#define DELTA_X_REG         0x04
#define SQUAL_REG           0x05
#define MAXIMUM_PIXEL_REG   0x08
#define MINIMUM_PIXEL_REG   0x0a
#define PIXEL_SUM_REG       0x09
#define PIXEL_DATA_REG      0x0b
#define SHUTTER_UPPER_REG   0x06
#define SHUTTER_LOWER_REG   0x07
#define RESET		    0x3a
#define CPI500v		    0x00
#define CPI1000v	    0x01

const int NCS = 4;

void setup()
{
  Serial.begin(57600);

  pinMode(SDIO, OUTPUT);
  pinMode(SCLK, OUTPUT);

  pinMode(NCS, OUTPUT);
  digitalWrite(NCS, LOW);
  delayMicroseconds(2);
  digitalWrite(NCS, HIGH);

  //call reset
  
  ADNS_write(RESET, 0x5a);
  delay(50); // From NRESET pull high to valid mo tion, assuming VDD and motion is present.

}

void loop()
{
  delay(200);
  Serial.println(ADNS_read(PRODUCT_ID), BIN);
}

void ADNS_write(unsigned char addr, unsigned char data) {
  char temp;
  int n;

  digitalWrite(NCS, LOW);//nADNSCS = 0; // select the chip

  temp = addr;
  digitalWrite(SCLK, LOW);					// start clock low
  pinMode(SDIO, OUTPUT); // set data line for output
  for (n=0; n<8; n++) {
    digitalWrite(SCLK, LOW);
    pinMode(SDIO, OUTPUT);
    delayMicroseconds(1);
    if (temp & 0x80)
      digitalWrite(SDIO, HIGH);
    else
      digitalWrite(SDIO, LOW);
    temp = (temp << 1);
    digitalWrite(SCLK, HIGH);
    delayMicroseconds(1);//delayMicroseconds(1);			// short clock pulse
  }
  temp = data;
  for (n=0; n<8; n++) {
    digitalWrite(SCLK, LOW);
    delayMicroseconds(1);
    if (temp & 0x80)
      digitalWrite(SDIO, HIGH);
    else
      digitalWrite(SDIO, LOW);
    temp = (temp << 1);
    digitalWrite(SCLK, HIGH);
    delayMicroseconds(1);			// short clock pulse
  }
  delayMicroseconds(20);
  digitalWrite(NCS, HIGH); // de-select the chip
}

byte ADNS_read(unsigned char addr) {
  byte temp;
  int n;

  digitalWrite(NCS, LOW);				// select the chip
  temp = addr;
  digitalWrite(SCLK, OUTPUT);					// start clock low
  pinMode(SDIO, OUTPUT);					// set data line for output
  for (n=0; n<8; n++) {

    digitalWrite(SCLK, LOW);
    pinMode(SDIO, OUTPUT);
    if (temp & 0x80) {
      digitalWrite(SDIO, HIGH);
    } 
    else {
      digitalWrite(SDIO, LOW);
    }
    temp = (temp << 1);
    delayMicroseconds(1);
    digitalWrite(SCLK, HIGH); 
    delayMicroseconds(1);			// short clock pulse
  }
  
  temp = 0;					// This is a read, switch to input
  pinMode(SDIO, INPUT); 
  delayMicroseconds(4);
  for (n=0; n<8; n++) {		// read back the data
    digitalWrite(SCLK, LOW);
    delayMicroseconds(1);
    if(digitalRead(SDIO)) {				// got a '1'
      temp |= 0x1;
    }
    temp = (temp << 1);		// shift left
    digitalWrite(SCLK, HIGH);
    delayMicroseconds(1);
  }
  
  digitalWrite(NCS, HIGH);				// de-select the chip
  return temp;
}

I’m not able to get the chip to respond with anything at the moment, very frustrating as I’ve followed the data sheet very precisely.

Came back to this and realized that I forgot to pull down the reset pin. Embarrassing, thanks for not embarrassing me futher by commenting on it :slight_smile: There were also some timing and read issues that I sorted out. Here’s the code, and I’ll put it wrapped nicely up on github. Big thanks to robtillaart for the copy/paste and internet tips.

#define SCLK                18
#define SDIO                19
#define RESET               3
#define NCS                  4

#define PRODUCT_ID          0x00 // should be 0x12
#define PRODUCTID2          0x3e
#define REVISION_ID         0x01
#define DELTA_Y_REG         0x03
#define DELTA_X_REG         0x04
#define SQUAL_REG           0x05
#define MAXIMUM_PIXEL_REG   0x08
#define MINIMUM_PIXEL_REG   0x0a
#define PIXEL_SUM_REG       0x09
#define PIXEL_DATA_REG      0x0b
#define SHUTTER_UPPER_REG   0x06
#define SHUTTER_LOWER_REG   0x07
#define RESET		    0x3a
#define CPI500v		    0x00
#define CPI1000v	    0x01

#define NUM_PIXELS          361

byte pix[360];

void setup()
{
  Serial.begin(57600);

  pinMode(SDIO, OUTPUT);
  pinMode(SCLK, OUTPUT);

  pinMode(RESET, OUTPUT);
  digitalWrite(RESET, LOW);
  
  sync();
  
  ADNS_write(RESET, 0x5a);
  delay(50); // From NRESET pull high to valid mo tion, assuming VDD and motion is present.

}

void loop()
{
  digitalWrite(RESET, LOW);
  delay(50);
  Serial.println(ADNS_read(MINIMUM_PIXEL_REG), BIN);
  //pixelGrab();
}

void sync() {
  pinMode(NCS, OUTPUT);
  digitalWrite(NCS, LOW);
  delayMicroseconds(2);
  digitalWrite(NCS, HIGH);
}

void ADNS_write(unsigned char addr, unsigned char data) {
  char temp;
  int n;

  digitalWrite(NCS, LOW);//nADNSCS = 0; // select the chip

  temp = addr;
  digitalWrite(SCLK, LOW);//SCK = 0;					// start clock low
  pinMode(SDIO, OUTPUT);//DATA_OUT; // set data line for output
  for (n=0; n<8; n++) {
    digitalWrite(SCLK, LOW);//SCK = 0;
    pinMode(SDIO, OUTPUT);
    delayMicroseconds(1);
    if (temp & 0x80)
      digitalWrite(SDIO, HIGH);//SDOUT = 1;
    else
      digitalWrite(SDIO, LOW);//SDOUT = 0;
    temp = (temp << 1);
    digitalWrite(SCLK, HIGH);//SCK = 1;
    delayMicroseconds(1);//delayMicroseconds(1);			// short clock pulse
  }
  temp = data;
  for (n=0; n<8; n++) {
    digitalWrite(SCLK, LOW);//SCK = 0;
    delayMicroseconds(1);
    if (temp & 0x80)
      digitalWrite(SDIO, HIGH);//SDOUT = 1;
    else
      digitalWrite(SDIO, LOW);//SDOUT = 0;
    temp = (temp << 1);
    digitalWrite(SCLK, HIGH);//SCK = 1;
    delayMicroseconds(1);			// short clock pulse
  }
  delayMicroseconds(20);
  digitalWrite(NCS, HIGH);//nADNSCS = 1; // de-select the chip
}

byte ADNS_read(unsigned char addr) {
  byte temp;
  int n;

  digitalWrite(NCS, LOW);//nADNSCS = 0;				// select the chip
  temp = addr;
  digitalWrite(SCLK, OUTPUT); //SCK = 0;					// start clock low
  pinMode(SDIO, OUTPUT); //DATA_OUT;					// set data line for output
  for (n=0; n<8; n++) {

    digitalWrite(SCLK, LOW);//SCK = 0;
    pinMode(SDIO, OUTPUT); //DATA_OUT;
    if (temp & 0x80) {
      digitalWrite(SDIO, HIGH);//SDOUT = 1;
    } 
    else {
      digitalWrite(SDIO, LOW);//SDOUT = 0;
    }
    temp = (temp << 1);
    delayMicroseconds(1);
    digitalWrite(SCLK, HIGH); //SCK = 1;
    delayMicroseconds(1);			// short clock pulse
  }
  
  temp = 0; // This is a read, switch to input
  pinMode(SDIO, INPUT); //DATA_IN;
  for (n=0; n<8; n++) {		// read back the data
    digitalWrite(SCLK, LOW);
    if(digitalRead(SDIO)) {// got a '1'
      temp |= 0x1;
    }
    if( n != 7) temp = (temp << 1); // shift left
    digitalWrite(SCLK, HIGH);
  }
  
  digitalWrite(NCS, HIGH);// de-select the chip
  return temp;
}

void pixelGrab()
{
  
  int grabCount = 0; 
  while( grabCount < NUM_PIXELS )
  {
    pix[grabCount] = ADNS_read(PIXEL_DATA_REG);
    grabCount++;
  }
  
}

I have some problems with ADNS5050 on Arduino atmega328 board?I appreciate anyone who can help me out.I get some code on the internet but it doesnot work well.Can you post your code ? I will learn it very hard .Thanks !

Anyone can help me ?