Interface to access to Avago ADNS-9500 laser mouse sensors.
Fork of ADNS9500 by
Diff: adns9500.cpp
- Revision:
- 2:ee0c13ef1320
- Parent:
- 1:fa3052be61b5
- Child:
- 3:898ed1944119
--- a/adns9500.cpp Mon Feb 13 11:39:24 2012 +0000 +++ b/adns9500.cpp Thu Mar 22 15:04:33 2012 +0000 @@ -16,6 +16,7 @@ * limitations under the License. */ +#include <cstdlib> #include <fstream> #include <math.h> #include <mbed.h> @@ -24,18 +25,30 @@ #include <adns9500.hpp> #define WAIT_TSRAD() wait_us(100) -#define WAIT_TSRWR() wait_us(20) +#define WAIT_TSRR() wait_us(20) +#define WAIT_TSRW() wait_us(20) +#define WAIT_TSWR() wait_us(120) +#define WAIT_TSWW() wait_us(120) #define WAIT_TBEXIT() wait_us(1) // 500ns #define WAIT_TNCSSCLK() wait_us(1) // 120ns #define WAIT_TSCLKNCS() wait_us(20) #define WAIT_TLOAD() wait_us(15) +#define LONG_WAIT_MS(x) \ + WAIT_TSCLKNCS(); ncs_.write(1); wait_ms(x); ncs_.write(0); WAIT_TNCSSCLK() +#define LONG_WAIT_US(x) \ + WAIT_TSCLKNCS(); ncs_.write(1); wait_us(x); ncs_.write(0); WAIT_TNCSSCLK() + #define DEFAULT_MAX_FPS 1958 -#define DEFAULT_MAX_FRAME_PERIOD ceil(1.0e6 / DEFAULT_MAX_FPS) // in us +#define DEFAULT_MAX_FRAME_PERIOD ((int)ceil(1e6 / DEFAULT_MAX_FPS)) // in us #define DEFAULT_X_CPI 1620 #define DEFAULT_Y_CPI 1620 #define CPI_CHANGE_UNIT 90 +#define SPI_BITS_PER_FRAME 8 +#define SPI_MODE 3 +#define SPI_WRITE_MODE 0x80 + #define SET_BIT(word, mask) (word | mask) #define CLEAR_BIT(word, mask) (word & (~mask)) @@ -47,9 +60,11 @@ motion_(motion), ncs_(ncs), enabled_(false), - dx_(0), dy_(0), xCpi_(DEFAULT_X_CPI), yCpi_(DEFAULT_Y_CPI) { + spi_.format(SPI_BITS_PER_FRAME, SPI_MODE); + + motion_.mode(PullUp); motion_.fall(this, &ADNS9500::motionTrigger); } @@ -67,46 +82,41 @@ WAIT_TNCSSCLK(); // send 0x3a to POWER_UP_RESET and wait for at least 50ms - spi_.write(POWER_UP_RESET); - WAIT_TSRAD(); - spi_.write(0x5a); - wait_ms(50); + spiSend(POWER_UP_RESET, 0x5a); + LONG_WAIT_MS(50); // clear observation register. Only required to deassert shutdown mode. - spi_.write(OBSERVATION); - WAIT_TSRAD(); - spi_.write(0x00); - wait_us(DEFAULT_MAX_FRAME_PERIOD); + spiSend(OBSERVATION, 0x00); + LONG_WAIT_US(DEFAULT_MAX_FRAME_PERIOD); // check observation register bits [5:0] - spi_.write(OBSERVATION); - WAIT_TSRAD(); - int observation = spi_.write(0x00); - WAIT_TSRAD(); - + int observation = spiReceive(OBSERVATION); if (! ADNS9500_IF_OBSERVATION_TEST(observation)) error("ADNS9500::reset : observation register test failed: 0x%x\n", observation); // read motion data - spi_.write(MOTION); - WAIT_TSRAD(); - spi_.write(DELTA_X_L); - WAIT_TSRAD(); - spi_.write(DELTA_X_H); - WAIT_TSRAD(); - spi_.write(DELTA_Y_L); - WAIT_TSRAD(); - spi_.write(DELTA_Y_H); - WAIT_TSRAD(); + WAIT_TSRR(); + spiReceive(MOTION); + WAIT_TSRR(); + spiReceive(DELTA_X_L); + WAIT_TSRR(); + spiReceive(DELTA_X_H); + WAIT_TSRR(); + spiReceive(DELTA_Y_L); + WAIT_TSRR(); + spiReceive(DELTA_Y_H); - // read product and revision id to test the connection + // read product and revision id to test the connection + WAIT_TSRR(); spi_.write(PRODUCT_ID); WAIT_TSRAD(); - int product_id = spi_.write(REVISION_ID); + int product_id = spi_.write(0x00); + WAIT_TSRR(); + spi_.write(REVISION_ID); WAIT_TSRAD(); int revision_id = spi_.write(0x00); + WAIT_TSCLKNCS(); - ncs_.write(1); if (product_id != 0x33) { @@ -134,11 +144,9 @@ WAIT_TNCSSCLK(); // send 0x3a to POWER_UP_RESET - spi_.write(POWER_UP_RESET); - WAIT_TSRAD(); - spi_.write(0x5a); + spiSend(POWER_UP_RESET, 0x5a); + WAIT_TSCLKNCS(); - ncs_.write(1); enabled_ = false; @@ -153,12 +161,11 @@ WAIT_TNCSSCLK(); // send the command to read the register - spi_.write(lregister); - WAIT_TSRAD(); - int value = spi_.write(0x00); + int value = spiReceive(lregister); + WAIT_TSCLKNCS(); - ncs_.write(1); + return value; } @@ -171,13 +178,11 @@ WAIT_TNCSSCLK(); // send the command to read the registers - spi_.write(lregister); - WAIT_TSRAD(); - int lvalue = spi_.write(uregister); - WAIT_TSRAD(); - int uvalue = spi_.write(0x00); + int lvalue = spiReceive(lregister); + WAIT_TSRR(); + int uvalue = spiReceive(uregister); + WAIT_TSCLKNCS(); - ncs_.write(1); return ADNS9500_UINT16(uvalue, lvalue); @@ -192,25 +197,22 @@ WAIT_TNCSSCLK(); // SROM download - spi_.write(CONFIGURATION_IV); - WAIT_TSRAD(); - spi_.write(ADNS9500_CONFIGURATION_IV_SROM_SIZE); - WAIT_TSRAD(); - spi_.write(SROM_ENABLE); - WAIT_TSRAD(); - spi_.write(0x1d); - wait_us(DEFAULT_MAX_FRAME_PERIOD); - spi_.write(SROM_ENABLE); - WAIT_TSRAD(); - spi_.write(0x18); - WAIT_TSRAD(); - spi_.write(SROM_LOAD_BURST); - - // TODO: Comprobar que pasa si el archivo no existe + spiSend(CONFIGURATION_IV, ADNS9500_CONFIGURATION_IV_SROM_SIZE); + WAIT_TSWW(); + spiSend(SROM_ENABLE, 0x1d); + LONG_WAIT_US(DEFAULT_MAX_FRAME_PERIOD); + + spiSend(SROM_ENABLE, 0x18); + WAIT_TSWW(); + spi_.write(SET_BIT(SROM_LOAD_BURST, SPI_WRITE_MODE)); + + // we expect a line per byte in hex without 0x prefix + char buffer[4]; ifstream ifs(filename, ifstream::in); - while(ifs.good()) { + while(ifs.getline(buffer, sizeof(buffer)).good()) { WAIT_TLOAD(); - spi_.write(ifs.get()); + int byte = strtol(buffer, NULL, 16); + spi_.write(byte); } WAIT_TSCLKNCS(); ncs_.write(1); @@ -223,9 +225,9 @@ wait_us(160); ncs_.write(0); WAIT_TNCSSCLK(); - spi_.write(SROM_ID); - WAIT_TSRAD(); - int srom_id = spi_.write(0x00); + + int srom_id = spiReceive(SROM_ID); + WAIT_TSCLKNCS(); ncs_.write(1); @@ -235,9 +237,9 @@ // test laser fault condition ncs_.write(0); WAIT_TNCSSCLK(); - spi_.write(MOTION); - WAIT_TSRAD(); - int motion = spi_.write(0x00); + + int motion = spiReceive(MOTION); + WAIT_TSCLKNCS(); ncs_.write(1); @@ -248,15 +250,12 @@ ncs_.write(0); WAIT_TNCSSCLK(); - spi_.write(SROM_ENABLE); - WAIT_TSRAD(); - spi_.write(0x15); - wait_us(10); - spi_.write(DATA_OUT_LOWER); - WAIT_TSRAD(); - int lcrc = spi_.write(DATA_OUT_UPPER); - WAIT_TSRAD(); - int ucrc = spi_.write(0x00); + spiSend(SROM_ENABLE, 0x15); + LONG_WAIT_MS(10); + + int lcrc = spiReceive(DATA_OUT_LOWER); + WAIT_TSRR(); + int ucrc = spiReceive(DATA_OUT_UPPER); WAIT_TSCLKNCS(); ncs_.write(1); @@ -268,19 +267,17 @@ { if (! enabled_) error("ADNS9500::enableLaser : the sensor is not enabled\n"); - + ncs_.write(0); WAIT_TNCSSCLK(); - spi_.write(LASER_CTRL0); - WAIT_TSRAD(); if (enable) { int laser_ctrl0 = CLEAR_BIT(0x00, ADNS9500_LASER_CTRL0_FORCE_DISABLED); - spi_.write(laser_ctrl0); + spiSend(LASER_CTRL0, laser_ctrl0); } else { int laser_ctrl0 = SET_BIT(0x00, ADNS9500_LASER_CTRL0_FORCE_DISABLED); - spi_.write(laser_ctrl0); + spiSend(LASER_CTRL0, laser_ctrl0); } WAIT_TSCLKNCS(); @@ -294,34 +291,26 @@ ncs_.write(0); WAIT_TNCSSCLK(); - - spi_.write(MOTION); - WAIT_TSRAD(); - int motion = spi_.write(DELTA_X_L); - WAIT_TSRAD(); - + + dx = 0; + dy = 0; + + int motion = spiReceive(MOTION); if (ADNS9500_IF_MOTION(motion)) { - int tmp = spi_.write(DELTA_X_L); - WAIT_TSRAD(); - dx = ADNS9500_UINT16(spi_.write(DELTA_X_H), tmp); - WAIT_TSRAD(); - tmp = spi_.write(DELTA_Y_L); - WAIT_TSRAD(); - dy = ADNS9500_UINT16(spi_.write(DELTA_Y_H), tmp); + WAIT_TSRR(); + int dxl = spiReceive(DELTA_X_L); + WAIT_TSRR(); + dx += ADNS9500_INT16(spiReceive(DELTA_X_H), dxl); - dx_ = dx; - dy_ = dy; + WAIT_TSRR(); + int dyl = spiReceive(DELTA_Y_L); + WAIT_TSRR(); + dy += ADNS9500_INT16(spiReceive(DELTA_Y_H), dyl); } - else { - spi_.write(0x00); - dx = dx_; - dy = dy_; - } - WAIT_TSCLKNCS(); ncs_.write(1); - + return ADNS9500_IF_MOTION(motion); } @@ -345,25 +334,21 @@ WAIT_TNCSSCLK(); // activate motion burst mode - spi_.write(MOTION_BURST); - WAIT_TSRAD(); spi_.write(0x50); - - // if in run mode, wait for 1 frame - wait_us(DEFAULT_MAX_FRAME_PERIOD); + WAIT_TSRAD(); // see the chronogram // read motion burst data data.motion = spi_.write(0x00); data.observation = spi_.write(0x00); int ldx = spi_.write(0x00); - data.dx = ADNS9500_UINT16(spi_.write(0x00), ldx); + data.dx = ADNS9500_INT16(spi_.write(0x00), ldx); int ldy = spi_.write(0x00); - data.dy = ADNS9500_UINT16(spi_.write(0x00), ldy); + data.dy = ADNS9500_INT16(spi_.write(0x00), ldy); - data.squal = spi_.write(0x00); - data.pixelSum = spi_.write(0x00); + data.surfaceQuality = spi_.write(0x00) * 4; + data.averagePixel = spi_.write(0x00) / 1.76; data.maximumPixel = spi_.write(0x00); data.minimumPixel = spi_.write(0x00); @@ -376,7 +361,19 @@ WAIT_TSCLKNCS(); ncs_.write(1); WAIT_TBEXIT(); + + data.dxMM = (float)data.dx / xCpi_ * 25.4; + data.dyMM = (float)data.dy / yCpi_ * 25.4; + + // write a value to Motion register to clear motion bit + ncs_.write(0); + WAIT_TNCSSCLK(); + spiSend(MOTION, 0x00); + + WAIT_TSCLKNCS(); + ncs_.write(1); + return ADNS9500_IF_MOTION(data.motion); } @@ -389,17 +386,14 @@ WAIT_TNCSSCLK(); // enable XY axes CPI in sync mode - spi_.write(CONFIGURATION_II); - WAIT_TSRAD(); - int rpt_mod = spi_.write(0x00); - WAIT_TSRAD(); - spi_.write(CLEAR_BIT(rpt_mod, ADNS9500_CONFIGURATION_II_RPT_MOD)); - WAIT_TSRAD(); + int rpt_mod = spiReceive(CONFIGURATION_II); + rpt_mod = CLEAR_BIT(rpt_mod, ADNS9500_CONFIGURATION_II_RPT_MOD); + WAIT_TSRW(); + spiSend(CONFIGURATION_II, rpt_mod); // set resolution for X-axis and Y-axis - spi_.write(CONFIGURATION_I); - WAIT_TSRAD(); - spi_.write(xy_resolution); + WAIT_TSWW(); + spiSend(CONFIGURATION_I, xy_resolution); WAIT_TSCLKNCS(); ncs_.write(1); @@ -417,23 +411,18 @@ WAIT_TNCSSCLK(); // disable XY axes CPI in sync mode - spi_.write(CONFIGURATION_II); - WAIT_TSRAD(); - int rpt_mod = spi_.write(0x00); - WAIT_TSRAD(); - spi_.write(SET_BIT(rpt_mod, ADNS9500_CONFIGURATION_II_RPT_MOD)); - WAIT_TSRAD(); + int rpt_mod = spiReceive(CONFIGURATION_II); + rpt_mod = SET_BIT(rpt_mod, ADNS9500_CONFIGURATION_II_RPT_MOD); + WAIT_TSRW(); + spiSend(CONFIGURATION_II, rpt_mod); // set resolution for X-axis - spi_.write(CONFIGURATION_I); - WAIT_TSRAD(); - spi_.write(x_resolution); - WAIT_TSRAD(); + WAIT_TSWW(); + spiSend(CONFIGURATION_I, x_resolution); // set resolution for Y-axis - spi_.write(CONFIGURATION_V); - WAIT_TSRAD(); - spi_.write(y_resolution); + WAIT_TSWW(); + spiSend(CONFIGURATION_V, y_resolution); WAIT_TSCLKNCS(); ncs_.write(1); @@ -450,25 +439,20 @@ ncs_.write(0); WAIT_TNCSSCLK(); - spi_.write(FRAME_CAPTURE); - WAIT_TSRAD(); - spi_.write(0x93); - WAIT_TSRAD(); - spi_.write(FRAME_CAPTURE); - WAIT_TSRAD(); - spi_.write(0xc5); - wait_us(DEFAULT_MAX_FRAME_PERIOD); - wait_us(DEFAULT_MAX_FRAME_PERIOD); - + spiSend(FRAME_CAPTURE, 0x93); + WAIT_TSWW(); + spiSend(FRAME_CAPTURE, 0xc5); + LONG_WAIT_US(2*DEFAULT_MAX_FRAME_PERIOD); + // check for first pixel reading motion bit - spi_.write(MOTION); while(true) { - WAIT_TSRAD(); - int motion = spi_.write(MOTION); + int motion = spiReceive(MOTION); if (ADNS9500_IF_MOTION(motion)) break; + WAIT_TSRR(); } - + WAIT_TSRR(); + // read pixel values spi_.write(PIXEL_BURST); WAIT_TSRAD(); @@ -482,4 +466,17 @@ ncs_.write(1); WAIT_TBEXIT(); } + + void ADNS9500::spiSend(Register address, int value) + { + spi_.write(SET_BIT(address, SPI_WRITE_MODE)); + spi_.write(value); + } + + int ADNS9500::spiReceive(Register address) + { + spi_.write(CLEAR_BIT(address, SPI_WRITE_MODE)); + WAIT_TSRAD(); + return spi_.write(0x00); + } } \ No newline at end of file