News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

ADNS 8030 Optical Flow Sensor

Started by SeanG_65, Oct 24, 2023, 03:12 AM

Previous topic - Next topic

SeanG_65

Has anyone played with one of these, and if so do you have any sample code?

top204

#1
I don't have an ADNS-3080, or can afford one, for testing only, but it intrigued me when I read its datasheet, so I had a look at the manufacturer's code and adapted it to Positron8 as best I can.

The code has not been tested and if it is not working, it is probably the ADNS_SPI_Write or ADNS_SPI_Read procedures that need changing:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Experimental, and untested, program to read an ADNS-3080 optical mouse sensor
' The author does not have an ADNS-3080 sensor, so the code is written based upon the official C++ code from the manufacturer
' Hopefully, it will give the reader of this code an idea of how the device works.
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
    Device = 18F25K20                                       ' Tell the compiler what device to compile for
    Declare Xtal = 16                                       ' Tell the compiler what frequency the device is operating at (in MHz)
'
' Setup USART1
'
    Declare HSerial_Baud = 9600
    Declare HRsout1_Pin = PORTC.6
'
' Pins used for the SPI interface to the ADNS-3080 device
'
$define ADNS_SCK_Pin   PORTC.3
$define ADNS_MOSI_Pin  PORTC.4
$define ADNS_MISO_Pin  PORTC.5
$define ADNS_Reset_Pin PORTC.0
$define ADNS_CS_Pin    PORTC.1
'
' Register Map for the ADNS-3080 Optical Flow Sensor
'
$define cADNS3080_PRODUCT_ID            $00
$define cADNS3080_MOTION                $02
$define cADNS3080_DELTA_X               $03
$define cADNS3080_DELTA_Y               $04
$define cADNS3080_SQUAL                 $05
$define cADNS3080_CONFIGURATION_BITS    $0A
$define cADNS3080_MOTION_CLEAR          $12
$define cADNS3080_FRAME_CAPTURE         $13
$define cADNS3080_MOTION_BURST          $50
'
' ADNS-3080 hardware config
'
$define cADNS3080_PIXELS_X              30
$define cADNS3080_PIXELS_Y              30

$define cADNS3080_PRODUCT_ID_VALUE      $17                             ' ID returned by cADNS3080_PRODUCT_ID register

$ifndef True
    $define True 1
$endif
$ifndef False
    $define False 0
$endif
'
' Create some variables
'
    Dim Global_dXpos As SDword                                          ' Holds the X position of the sensor
    Dim Global_dYpos As SDword                                          ' Holds the Y position of the sensor

'---------------------------------------------------------------------------------------------
' The main program starts here
'
Main:
    ADNS_Setup()
'
' Uncomment and use this loop to read and transmit the motion values from the ADNS-3080 device
'
    Do
        ADNS_Read()
        DelayMs 255
    Loop
'
' Uncomment and use this loop to read and transmit the pixel values from the ADNS-3080 device
'
(*
    Do
        ADNS_GetPixelData()
        DelayMs 255
    Loop
*)

'---------------------------------------------------------------------------------------------
' Transmit the pixels read from the ADNS-3080 device
' Input     : None
' Output    : None
' Notes     : None
'
Proc ADNS_GetPixelData()
    Dim tFirstPixel As Bit = True
    Dim bPixVal As Byte
    Dim bPixelX As Byte
    Dim bPixelY As Byte
'
' Write to frame capture register to force capture of frame
'
    ADNS_RegWrite(cADNS3080_FRAME_CAPTURE, $83)
'
' Wait 3 frame periods + 10 nanoseconds for frame to be captured
'
    DelayUs 1510                                                        ' Minimum frame speed is 2000 frames/second so 1 frame = 500 nano seconds. So 500 x 3 + 10 = 1510
'
' Read and Transmit the pixel data
'
    For bPixelX = 0 To cADNS3080_PIXELS_Y - 1                           ' Create a loop for the Y pixels
        For bPixelY = 0 To cADNS3080_PIXELS_X - 1                       ' Create a loop for the X pixels
            bPixVal = ADNS_RegRead(cADNS3080_FRAME_CAPTURE)
            If tFirstPixel = 1 And bPixVal.6 = 0 Then
                HRsoutLn "Failed to find first pixel"
                ADNS_Reset()                                            ' Hardware reset to restore sensor to normal operation
                ExitProc
            EndIf
            tFirstPixel = False
            bPixVal = bPixVal << 2                                      ' Only lower 6 bits have data
            HRsout1 bPixVal
        Next
    Next
EndProc

'---------------------------------------------------------------------------------------------
' Read the ADNS-3080 device
' Input     : None
' Output    : ADNS_bMotion holds the motion value
'           : ADNS_bDX holds the Delta X value
'           : ADNS_bDY holds the Delta Y value
'           : ADNS_bSurfaceQual holds the Surface Quality value
' Notes     : None
'
Proc ADNS_Read()
Global Dim ADNS_bMotion      As Byte
Global Dim ADNS_bDX          As Byte
Global Dim ADNS_bDY          As Byte
Global Dim ADNS_bSurfaceQual As Byte
'
' Read the sensor
'
    PinClear ADNS_CS_Pin
    ADNS_SPI_Write(cADNS3080_MOTION_BURST)
    ADNS_bMotion      = ADNS_SPI_Read()
    ADNS_bDX          = ADNS_SPI_Read()
    ADNS_bDY          = ADNS_SPI_Read()
    ADNS_bSurfaceQual = ADNS_SPI_Read()
    PinSet ADNS_CS_Pin

    HRsoutLn Dec ADNS_bMotion.0                                         ' Transmit the Motion value
    If ADNS_bMotion.4 = 1 Then                                          ' Check if there has been an overflow
        HRsoutLn "ADNS-3080 overflow\n"

    ElseIf ADNS_bMotion.7 = 1 Then
        Global_dXpos = Global_dXpos + ADNS_bDX
        Global_dYpos = Global_dYpos + ADNS_bDY
        '
        ' Transmit the values
        '
        HRsout1Ln SDec Global_dXpos, ",", Dec ADNS_bDX
        HRsout1Ln SDec Global_dYpos, ",", Dec ADNS_bDY
        HRsout1Ln Dec ADNS_bSurfaceQual
    EndIf
    DelayMs 10
EndProc

'---------------------------------------------------------------------------------------------
' Setup the ADNS-3080 device
' Input     : None
' Output    : Returns false if the device fails to setup
' Notes     : None
'
Proc ADNS_Setup(), Bit
    Dim bID As Byte
    Dim bConfig As Byte

    Result = True
    PinHigh ADNS_CS_Pin
    PinHigh ADNS_SCK_Pin
    PinHigh ADNS_MOSI_Pin
    PinInput ADNS_MISO_Pin
    PinHigh ADNS_Reset_Pin

    Global_dXpos = 0
    Global_dYpos = 0
    ADNS_Reset()

    bID = ADNS_RegRead(cADNS3080_PRODUCT_ID)
    If bID = cADNS3080_PRODUCT_ID_VALUE Then
        HRsoutLn "ADNS-3080 found"
    Else
        HRsoutLn "Could not find ADNS-3080: ", Hex bID
        Result = False
        ExitProc
    EndIf

    bConfig = ADNS_RegRead(cADNS3080_CONFIGURATION_BITS)
    ADNS_RegWrite(cADNS3080_CONFIGURATION_BITS, bConfig | %00010000)    ' Set the resolution to 1600 counts per inch
EndProc

'---------------------------------------------------------------------------------------------
' Reset the ADNS-3080 device
' Input     :
' Output    :
' Notes     :
'
Proc ADNS_Reset()
    PinSet ADNS_Reset_Pin                                   ' Set the ADNS_Reset_Pin high
    DelayUs 10                                              ' A delay between the reset pulse
    PinClear ADNS_Reset_Pin                                 ' Pull the ADNS_Reset_Pin low
    DelayUs 500                                             ' Wait for sensor to be ready
endProc

'---------------------------------------------------------------------------------------------
' Clear the Delta_X, Delta_Y, and internal Motion registers
' Input     : None
' Output    : None
' Notes     : None
'
Proc ADNS_ClearMotion()
    ADNS_RegWrite(cADNS3080_MOTION_CLEAR, $FF)              ' Writing anything to this register will clear the sensor's ADNS_bMotion registers
    Global_dXpos = 0
    Global_dYpos = 0
EndProc

'---------------------------------------------------------------------------------------------
' Write to a register in the ADNS-3080 device
' Input     : pReg holds the register to write too
'           : pData hold the value to write to the register
' Output    : None
' Notes     : None
'
Proc ADNS_RegWrite(pReg As Byte, pData As Byte)
    PinClear ADNS_CS_Pin
    pReg.7 = 1                                              ' Set for a write operation
    ADNS_SPI_Write(pReg)
    DelayUs 75                                              ' Wait minimum 75 us in case writing to Motion or Motion_Burst registers
    ADNS_SPI_Write(pData)
    PinSet ADNS_CS_Pin
EndProc

'---------------------------------------------------------------------------------------------
' Read a register from the ADNS-3080 device
' Input     : pReg holds the register to read from
' Output    : Returns the byte read from the register
' Notes     : None
'
Proc ADNS_RegRead(pReg As Byte), Byte
    PinClear ADNS_CS_Pin
    ADNS_SPI_Write(pReg)
    Result = ADNS_SPI_Read()
    PinSet ADNS_CS_Pin
EndProc

'---------------------------------------------------------------------------------------------
' Transmit a byte to the SPI bus
' Input     : pBytein holds the 8-bit value to send
' Output    : None
' Notes     : Implements the SPI protocol 3. SCK is idle-high, and bits are latched on SCK rising
'
Proc ADNS_SPI_Write(pBytein As Byte)
Global Dim ADNS_bLoop As Byte Access Shared                 ' Used for the bit counter

    For ADNS_bLoop = 7 DownTo 0                             ' 8-bit SPI loop
        PinClear ADNS_SCK_Pin                               ' Pull the SCK pin low
        ADNS_MOSI_Pin = pBytein.7                           ' Put the current outgoing bit on ADNS_MOSI_Pin
        Rol pBytein                                         ' Shift the next bit into MSB
        DelayUs 1                                           ' A delay to slow down the SPI transfer
        PinSet ADNS_SCK_Pin                                 ' Set the SCK pin high
    Next
EndProc

'---------------------------------------------------------------------------------------------
' Receive a byte from the SPI bus
' Input     : None
' Output    : Returns the 8-bit value received
' Notes     : Implements the SPI protocol 3. SCK is idle-high, and bits are latched on SCK rising
'
Proc ADNS_SPI_Read(), Byte
Global Dim ADNS_bLoop As Byte Access Shared                 ' Used for the bit counter

    PinSet ADNS_MOSI_Pin                                    ' Set the ADNS_MOSI_Pin high
    For ADNS_bLoop = 7 DownTo 0                             ' 8-bit SPI loop
        PinClear ADNS_SCK_Pin                               ' Pull the SCK pin low
        Result = Result << 1                                ' Shift next bit into MSB
        DelayUs 1                                           ' A delay to slow down the SPI transfer
        PinSet ADNS_SCK_Pin                                 ' Set the SCK pin high
        Result = Result | ADNS_MISO_Pin                     ' Capture the current bit from the ADNS_MISO_Pin
    Next
EndProc

SeanG_65

BRILLIANT, thank you!

I have a couple spare, I can send you one to play with if you want, in the mean time, I will have a go with the code you generously posted and let you know what the results are.

top204

That would be excellent SeanG. I can then test the code and place it in the WIKI when it is working, and create code to display the pixels on a graphic LCD attached to the device.

Please send me a message and I will give you my address.

Many thanks
Les