Image with optical mouse sensor ADNS 2080

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

 

In the device I am developing I need to measure movement x/y distance in a similar way a mouse does, though my focusing distance is about 1,2 m.

To get the things working, I need to be able to be able to calibrate my optical focus and lighting, and to do so I am trying to visualize an image, using the PIX GRAB command.

My 3-wire SPI communication is ready and working, I get very precise 1 MHz signals and all read/write commands seem to work fine.

 

When I use Pix Grab with standard read to read delays, I get tons of errors, - from the 484 pixels I get 1 in about 50 to be valid. Time between read and subsequent commands is specified to be 250 ns, but I've experimented with all kinds of timings.

When I put bigger delay between the readings of specific pixels, the ratio correct to wrong pixels gets better and when I finally put about 7ms after each pixel, I get only valid pixels and somewhat valid image (I still have problems with lighting and focus, but crude forms can be properly observed). This timing is huge, though, I need more than 3 seconds for 22x22 pixels to be read.

 

What can also be observed is that when the time is less, e.g. 1ms, the amount of errors is light dependent - in darker conditions I get more errors, in extreme lighting I get less errors, so what I am thinking is that this might be caused by exposure time (how long is the shutter openned) - it is automatically configured by the sensor.

 

The movement functions return almost no results, so I detect almost no movement, but this seems normal when I get so bad image quallity and low lighting.

 

Any ideas/code for using the Pix Grabber functionallity?

 

Here is some yet unreleased documentation:

Procedure to start pixel grab is listed as:
1. Write register 0x22 with value 0x60 // force run mode
2. Write any value to register 0x0B // reset the register & ready it for pixel grab
3. Read register 0x0B to ensure Bit-7 is a valid “1”.
4. Continuously read register 0x0B for 484 times.
5. Any write to register 0x0B will reset the register content.
6. Write register 0x22 with value 0x00 // restore the sensor to normal operation mode

Here is some code:

 

    unsigned char x,y,tmpC;
    unsigned int color;

    unsigned char memColor[OPT_X_SIZE][OPT_Y_SIZE]; //new mode
    unsigned char* pMemColor;

    CLI();

    VSPI_CMD_Write(0x22,0x60); //wake up and forbid sleep
    VSPI_DelayWtoW(); //30 us

    VSPI_CMD_Write(OPT_ADDR_PIX_GRAB,0x00); //address + W, then 0xfe
    VSPI_DelayWtoR(); //20 us

    pMemColor = &(memColor[0][0]);

    for (x=0; x<OPT_X_SIZE; x++) //this could be optimized to a while cycle, e.g. while (pMemColor < endAddress), where endAddress = &memColor[OPT_X_SIZE][0];
    {
        for (y=0; y<OPT_Y_SIZE; y++)
        {
            VSPI_CMD_Read(OPT_ADDR_PIX_GRAB, &tmpC); //address, then 1 byte read
            if (tmpC < 0x80)
            {
                *pMemColor++ = 0xff; //mark error
            }
            else
            {
                tmpC &= 0x7C;
                tmpC >>= 2; //convert from 7 to 5 byte grayscale per color
                *pMemColor++ = tmpC; //&0x1f;
            }
            DelayMiliseconds(7);
        }
    }

    //draw
    //Here I do some drawing, which is application and LCD specific, not very interesting
    // I visualize the matrix

    VSPI_CMD_Write(0x22,0x00); //restore normal mode
    VSPI_DelayWtoW();

    SEI();

 

I am attaching also the read/write functions, since a lot of people here seem to have problems with the 3-wire SPI. I am not using any SPI integrated functionallities, just two IO pins - clock and data, so it is actually 2 

The timings are calibrated via tests for 32 MHz. 

 

void VSPI_Write(unsigned char Data)
{
    unsigned char tmpCh;

    //CLI should be initiated
    VSPI_DATA_PORT_DIRSET = VSPI_DATA_PIN_MSK; //make data pin an output

    for (tmpCh=0; tmpCh<8; tmpCh++)
    {
        if (Data > 0x7F)
        {
            VSPI_CLK_PORT_OUTCLR = VSPI_CLK_PIN_MSK;
            VSPI_DATA_PORT_OUTSET = VSPI_DATA_PIN_MSK;
        }
        else
        {
            VSPI_CLK_PORT_OUTCLR = VSPI_CLK_PIN_MSK;
            VSPI_DATA_PORT_OUTCLR = VSPI_DATA_PIN_MSK;
        }
        Data <<= 1;

        asm("nop");asm("nop");asm("nop");
        asm("nop");asm("nop");asm("nop");
        asm("nop");asm("nop");asm("nop");

        VSPI_CLK_PORT_OUTSET = VSPI_CLK_PIN_MSK;

        asm("nop");asm("nop");asm("nop");
        asm("nop");asm("nop");
    }
}

/********************************************************/
void VSPI_Read(unsigned char* data)
{
    unsigned char tmpCh;
    unsigned char tempData = 0;

    //CLI should be initiated
    VSPI_DATA_PORT_DIRCLR = VSPI_DATA_PIN_MSK; //make data pin an input

    for (tmpCh=0; tmpCh<8; tmpCh++)
    {
        tempData <<= 1;
        VSPI_CLK_PORT_OUTCLR = VSPI_CLK_PIN_MSK;
        //some nops here so that 500 ns have passed

        asm("nop");asm("nop");asm("nop");
        asm("nop");asm("nop");asm("nop");
        asm("nop");asm("nop");asm("nop");
        asm("nop");asm("nop");asm("nop");
        asm("nop");asm("nop");

        VSPI_CLK_PORT_OUTSET = VSPI_CLK_PIN_MSK;
        if (VSPI_DATA_PORT_IN & VSPI_DATA_PIN_MSK) tempData++; //make the LSB 1
        else asm("nop"); //balace with nops if have to

        asm("nop");asm("nop");
    }
    VSPI_DATA_PORT_DIRSET |= VSPI_DATA_PIN_MSK;
    VSPI_DATA_PORT_OUTSET |= VSPI_DATA_PIN_MSK; //these two lines are not necessary

    *data = tempData;
}

/******************************************************/
void VSPI_CMD_Write(unsigned char address, unsigned char data)
{
    VSPI_Write(address | 0x80);
    VSPI_Write(data);
}

/******************************************************/
void VSPI_CMD_Read(unsigned char address, unsigned char* data)
{
    VSPI_Write(address);
    VSPI_DATA_PORT_OUTSET = VSPI_DATA_PIN_MSK; //this is not necessary
    DelayMicroseconds(2); //mind this not, it results in 4us, there is some delay in entering and exiting the function
    VSPI_Read(data);
}

Any ideas are appreciated, thanks :)

 

This topic has a solution.
Last Edited: Tue. Feb 9, 2016 - 09:23 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To get it working, validity of each pixel should be checked and reading should be retried (without moving to the next pixel).

Time, needed for the operation, seems to be dependent on the Shutter Low/high value, which is automatically adjusted, depending on the available light - in darker conditions shutter stays open longer and pixel are read slower.

 

Here is some working code:

Note that if there is no response or correct pixels read, the device will be reset by the WDR, which is ok for my application, but might not be ok in yours;

    unsigned char memColor[OPT_X_SIZE][OPT_Y_SIZE];
    unsigned char* pMemColor = &(memColor[0][0]);
    unsigned char* endAddress = &(memColor[OPT_X_SIZE][0]);

    VSPI_CMD_Write(0x22,0x60); //wake up and forbid sleep
    VSPI_DelayWtoW();
    VSPI_CMD_Write(OPT_ADDR_PIX_GRAB,0x00); //write anything into 0x0B register to reset pixel position to 0
    VSPI_DelayWtoR(); //20 us

    while (pMemColor < endAddress)
    {
        VSPI_CMD_Read(OPT_ADDR_PIX_GRAB, pMemColor); //address, then 1 byte read
        if (*pMemColor >= 0x80)
        {
            pMemColor++;
            WDR();
        }
    }

    VSPI_CMD_Write(0x22,0x00); //restore normal mode
    VSPI_DelayWtoW();

 

Last Edited: Tue. Feb 9, 2016 - 09:05 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very silly question but why try to reuse a mouse sensor? Why not use a real image sensor?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My goal is to use that sensor to detect position offset over scanned surfice, so I need x/y deviation.

Pix grabber (or getting the image) I need to calibrate the focus of lens and to check out some actual sizes - I need that to calculate the real offsets per signal bit, since I am using this sensor on about 1,5m distance from the survice.

Similar usage you can see here: http://diydrones.com/profiles/bl...

 

First I used a very complex method, including compass (magnetometer), accelerometer and some complex math conversions to compensate G on tilt, including two related coordinate systems and so on. Of course, the error was too big and the data - unusable; to calculate distance I had to integrate the compensated acceleration twise (acc to speed and speed to distance), so you can imagine how that error multiplies over time. Also the procedure was slow.

 

If you have any better ideas, I am ready to send beer to any destination around the globe :)