//-------------------------------------------------------------------------- // // This module implements a serial interface to the Agilent optical chip // using GPIO lines on the PSoC. It also provides an interface for reading // mouse movement. // //-------------------------------------------------------------------------- // $Archive: /WirelessUSB/WUSB Kits/CY4632 LS KBM RDK/DocSrc/CD_Root/Firmware/Source Code/RDK Mouse/optical.c $ // $Modtime: 6/16/04 4:38p10/11/04 10:58a $ // $Revision: 1012 $ //-------------------------------------------------------------------------- // // Copyright 2003-2004, Cypress Semiconductor Corporation. // // This software is owned by Cypress Semiconductor Corporation (Cypress) // and is protected by and subject to worldwide patent protection (United // States and foreign), United States copyright laws and international // treaty provisions. Cypress hereby grants to licensee a personal, // non-exclusive, non-transferable license to copy, use, modify, create // derivative works of, and compile the Cypress Source Code and derivative // works for the sole purpose of creating custom software in support of // licensee product to be used only in conjunction with a Cypress integrated // circuit as specified in the applicable agreement. Any reproduction, // modification, translation, compilation, or representation of this // software except as specified above is prohibited without the express // written permission of Cypress. // // Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, // WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // Cypress reserves the right to make changes without further notice to the // materials described herein. Cypress does not assume any liability arising // out of the application or use of any product or circuit described herein. // Cypress does not authorize its products for use as critical components in // life-support systems where a malfunction or failure may reasonably be // expected to result in significant injury to the user. The inclusion of // Cypress’ product in a life-support systems application implies that the // manufacturer assumes all risk of such use and in doing so indemnifies // Cypress against all charges. // // Use may be limited by and subject to the applicable Cypress software // license agreement. // //-------------------------------------------------------------------------- //-------------------------------------- // Included files //-------------------------------------- #include "appconfig.h" #include "optical.h" #include "timer.h" #include PLATFORM_H //-------------------------------------- // Local Definitions and Types //-------------------------------------- typedef enum _ADNS_SPI_DIRECTION { READ = 0, WRITE = 1, } ADNS_SPI_DIRECTION; // Agilent Optical sensor #define REG_PRODUCT_ID 0x00 #define REG_REVISION_ID 0x01 #define REG_MOTION 0x02 #define REG_DELTA_X 0x03 #define REG_DELTA_Y 0x04 #define REG_SQUAL 0x05 #define REG_AVERAGE_PIXEL 0x06 #define REG_MAXIMUM_PIXEL 0x07 #define REG_CONFIGURATION_BITS 0x0a #define REG_DATA_OUT_LOWER 0x0c #define REG_DATA_OUT_UPPER 0x0d #define REG_SHUTTER_LOWER 0x0e #define REG_SHUTTER_UPPER 0x0f #define REG_FRAME_PERIOD_LOWER 0x10 #define REG_FRAME_PERIOD_UPPER 0x11 #define PRODUCT_ID_ID 0x03 #define REVISION_REV 0x10 #define MOTION_MOT 0x80 #define MOTION_FAULT 0x20 #define MOTION_OVFY 0x10 #define MOTION_OVFX 0x08 #define MOTION_RES 0x01 #define AVERAGE_PIXEL 0x3f #define MAXIMUM_PIXEL 0x3f #define CONFIGURATION_BITS_RESET 0x80 #define CONFIGURATION_BITS_LED_MODE 0x40 #define CONFIGURATION_BITS_SELF_TEST 0x20 #define CONFIGURATION_BITS_RES 0x10 #define CONFIGURATION_BITS_PIX_DUMP 0x08 #define CONFIGURATION_BITS_SLEEP 0x01 #ifdef MOUSE_800_NOT_400_CPI #define CONFIG_VALUE ( \ CONFIGURATION_BITS_LED_MODE | \ CONFIGURATION_BITS_RES \ ) #else #define CONFIG_VALUE CONFIGURATION_BITS_LED_MODE #endif //-------------------------------------- // Local Function Declarations //-------------------------------------- static UINT8 adns_read(UINT8); static void adns_write(UINT8, UINT8); static UINT8 adns_spi(UINT8 mosiByte, ADNS_SPI_DIRECTION dir); static void set_sdio_dir_out(BOOL is_out); //-------------------------------------- // Local Definitions //-------------------------------------- //-------------------------------------------------------------------------- // optical_init //-------------------------------------------------------------------------- void optical_init(void) { UINT8 prod_id; MOUSE_OPTICAL_PORT &= ~MOUSE_OPTICAL_PD; MOUSE_OPTICAL_PORT &= ~MOUSE_OPTICAL_SDIO; MOUSE_OPTICAL_PORT |= MOUSE_OPTICAL_SCLK; timer_delay_msec(4); MOUSE_OPTICAL_PORT |= MOUSE_OPTICAL_SCLK; MOUSE_OPTICAL_PORT |= MOUSE_OPTICAL_SDIO; MOUSE_OPTICAL_PORT |= MOUSE_OPTICAL_PD; timer_delay_msec(1); MOUSE_OPTICAL_PORT &= ~MOUSE_OPTICAL_PD; timer_delay_msec(1); adns_write(REG_CONFIGURATION_BITS, CONFIGURATION_BITS_RESET); timer_delay_100_usec(); timer_delay_100_usec(); prod_id = adns_read(REG_PRODUCT_ID); if( prod_id == PRODUCT_ID_ID ) { adns_write( REG_CONFIGURATION_BITS, CONFIG_VALUE ); } else { // communication error with optics M8C_Stop; } } //-------------------------------------------------------------------------- // optical_get_report //-------------------------------------------------------------------------- BOOL optical_get_report(OPTICAL_REPORT *report) { BOOL result = FALSE; UINT8 motion; static UINT8 osc_motion = 0; // detect +/-1 oscillations in motion motion = adns_read(REG_MOTION); report->x = 0; report->y = 0; if (motion & MOTION_FAULT) { optical_init(); } else if( motion & (MOTION_OVFX | MOTION_OVFY) ) { do { motion = adns_read(REG_MOTION); adns_read(REG_DELTA_X); adns_read(REG_DELTA_Y); } while( motion & MOTION_MOT ); } else if (motion & MOTION_MOT) { UINT8 x; UINT8 y; x = report->x = (INT8)adns_read(REG_DELTA_X); y = report->y = -(INT8)adns_read(REG_DELTA_Y); // Account for 8-bit sign inversion for case y = -128 if( y == 0x80 ) { y = report->y = 0x7f; } // Prevent pointer oscillations when mouse is idle if( (x<2 || x==0xFF) && (y<2 || y==0xFF) ) { ++osc_motion; if( osc_motion == 0 ) { osc_motion = 0xFF; } } else { osc_motion = 0; } // Report valid packet if under oscillation count if( osc_motion < 250 ) { result = TRUE; } } return result; } //-------------------------------------------------------------------------- // optical_power_up //-------------------------------------------------------------------------- void optical_power_up(void) { MOUSE_OPTICAL_PORT &= ~MOUSE_OPTICAL_PD; timer_delay_msec(1); adns_write( REG_CONFIGURATION_BITS, CONFIG_VALUE ); } //-------------------------------------------------------------------------- // optical_power_down //-------------------------------------------------------------------------- void optical_power_down(void) { adns_write( REG_CONFIGURATION_BITS, 0 ); MOUSE_OPTICAL_PORT |= (MOUSE_OPTICAL_SCLK | MOUSE_OPTICAL_PD); } //-------------------------------------------------------------------------- // adns_read //-------------------------------------------------------------------------- static UINT8 adns_read(UINT8 address) { UINT8 data; adns_spi((UINT8)(address & 0x7f), WRITE); timer_delay_100_usec(); data = adns_spi(0, READ); timer_delay_100_usec(); timer_delay_10_usec(); timer_delay_10_usec(); return data; } //-------------------------------------------------------------------------- // adns_write //-------------------------------------------------------------------------- static void adns_write(UINT8 address, UINT8 data) { adns_spi((UINT8)(address | 0x80), WRITE); adns_spi(data, WRITE); timer_delay_100_usec(); } //-------------------------------------------------------------------------- // adns_spi //-------------------------------------------------------------------------- static UINT8 adns_spi(UINT8 mosiByte, ADNS_SPI_DIRECTION dir) { UINT8 misoByte = 0; UINT8 i; if(dir == READ) { set_sdio_dir_out(FALSE); } else { set_sdio_dir_out(TRUE); } for(i=0; i<8; i++) { MOUSE_OPTICAL_PORT &= ~MOUSE_OPTICAL_SCLK; if( dir == READ ) { misoByte <<= 1; misoByte |= (MOUSE_OPTICAL_PORT & MOUSE_OPTICAL_SDIO) ? 1 : 0; } else { if( mosiByte & 0x80 ) { MOUSE_OPTICAL_PORT |= MOUSE_OPTICAL_SDIO; } else { MOUSE_OPTICAL_PORT &= ~MOUSE_OPTICAL_SDIO; } mosiByte <<= 1; } MOUSE_OPTICAL_PORT |= MOUSE_OPTICAL_SCLK; } return misoByte; } //-------------------------------------------------------------------------- // set_sdio_dir_out //-------------------------------------------------------------------------- static void set_sdio_dir_out(BOOL is_out) { static BYTE shadow0 = MOUSE_OPTICAL_DM0_INIT; static BYTE shadow1 = MOUSE_OPTICAL_DM1_INIT; if( is_out ) { // strong drive shadow0 |= MOUSE_OPTICAL_SDIO; shadow1 &= ~MOUSE_OPTICAL_SDIO; } else { // high-z shadow0 &= ~MOUSE_OPTICAL_SDIO; shadow1 |= MOUSE_OPTICAL_SDIO; } MOUSE_OPTICAL_DM0 = shadow0; MOUSE_OPTICAL_DM1 = shadow1; }