Graphical demo for the LPC4088 Experiment Base Board with one of the Display Expansion Kits. This demo shows a number of dots projected on a rotating sphere.

Dependencies:   EALib mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AR1021I2C.cpp Source File

AR1021I2C.cpp

00001 /*
00002  *  Copyright 2013 Embedded Artists AB
00003  *
00004  *  Licensed under the Apache License, Version 2.0 (the "License");
00005  *  you may not use this file except in compliance with the License.
00006  *  You may obtain a copy of the License at
00007  *
00008  *    http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  *  Unless required by applicable law or agreed to in writing, software
00011  *  distributed under the License is distributed on an "AS IS" BASIS,
00012  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *  See the License for the specific language governing permissions and
00014  *  limitations under the License.
00015  */
00016 
00017 /******************************************************************************
00018  * Includes
00019  *****************************************************************************/
00020 
00021 #include "mbed.h"
00022 #include "mbed_debug.h"
00023 
00024 #include "AR1021I2C.h"
00025 
00026 /******************************************************************************
00027  * Defines and typedefs
00028  *****************************************************************************/
00029 
00030 #define AR1021_REG_TOUCH_THRESHOLD        (0x02)
00031 #define AR1021_REG_SENS_FILTER            (0x03)
00032 #define AR1021_REG_SAMPLING_FAST          (0x04)
00033 #define AR1021_REG_SAMPLING_SLOW          (0x05)
00034 #define AR1021_REG_ACC_FILTER_FAST        (0x06)
00035 #define AR1021_REG_ACC_FILTER_SLOW        (0x07)
00036 #define AR1021_REG_SPEED_THRESHOLD        (0x08)
00037 #define AR1021_REG_SLEEP_DELAY            (0x0A)
00038 #define AR1021_REG_PEN_UP_DELAY           (0x0B)
00039 #define AR1021_REG_TOUCH_MODE             (0x0C)
00040 #define AR1021_REG_TOUCH_OPTIONS          (0x0D)
00041 #define AR1021_REG_CALIB_INSETS           (0x0E)
00042 #define AR1021_REG_PEN_STATE_REPORT_DELAY (0x0F)
00043 #define AR1021_REG_TOUCH_REPORT_DELAY     (0x11)
00044 
00045 
00046 #define AR1021_CMD_GET_VERSION                 (0x10)
00047 #define AR1021_CMD_ENABLE_TOUCH                (0x12)
00048 #define AR1021_CMD_DISABLE_TOUCH               (0x13)
00049 #define AR1021_CMD_CALIBRATE_MODE              (0x14)
00050 #define AR1021_CMD_REGISTER_READ               (0x20)
00051 #define AR1021_CMD_REGISTER_WRITE              (0x21)
00052 #define AR1021_CMD_REGISTER_START_ADDR_REQUEST (0x22)
00053 #define AR1021_CMD_REGISTER_WRITE_TO_EEPROM    (0x23)
00054 #define AR1021_CMD_EEPROM_READ                 (0x28)
00055 #define AR1021_CMD_EEPROM_WRITE                (0x29)
00056 #define AR1021_CMD_EEPROM_WRITE_TO_REGISTERS   (0x2B)
00057 
00058 #define AR1021_RESP_STAT_OK           (0x00)
00059 #define AR1021_RESP_STAT_CMD_UNREC    (0x01)
00060 #define AR1021_RESP_STAT_HDR_UNREC    (0x03)
00061 #define AR1021_RESP_STAT_TIMEOUT      (0x04)
00062 #define AR1021_RESP_STAT_CANCEL_CALIB (0xFC)
00063 
00064 
00065 #define AR1021_ERR_NO_HDR      (-1000)
00066 #define AR1021_ERR_INV_LEN     (-1001)
00067 #define AR1021_ERR_INV_RESP    (-1002)
00068 #define AR1021_ERR_INV_RESPLEN (-1003)
00069 #define AR1021_ERR_TIMEOUT     (-1004)
00070 
00071 // bit 7 is always 1 and bit 0 defines pen up or down
00072 #define AR1021_PEN_MASK (0x81)
00073 
00074 #define AR1021_NUM_CALIB_POINTS (4)
00075 
00076 #define AR1021_ADDR  (0x4D << 1)
00077 
00078 #define AR1021_TIMEOUT     1000        //how many ms to wait for responce 
00079 #define AR1021_RETRY          5        //how many times to retry sending command 
00080 
00081 #define AR1021_MIN(__a, __b) (((__a)<(__b))?(__a):(__b))
00082 
00083 
00084 AR1021I2C::AR1021I2C(PinName sda, PinName scl, PinName siq) :
00085 _i2c(sda, scl), _siq(siq), _siqIrq(siq)
00086 {
00087     _i2c.frequency(200000);
00088 
00089     // default calibration inset is 25 -> (25/2 = 12.5%)
00090     _inset = 25;
00091 
00092     // make sure _calibPoint has an invalid value to begin with
00093     // correct value is set in calibrateStart()
00094     _calibPoint = AR1021_NUM_CALIB_POINTS+1;
00095 
00096     _x = 0;
00097     _y = 0;
00098     _pen = 0;
00099 
00100     _initialized = false;
00101 }
00102 
00103 
00104 bool AR1021I2C::read(touchCoordinate_t &coord) {
00105 
00106     if (!_initialized) return false;
00107 
00108     coord.x = _x * _width/4095;
00109     coord.y = _y * _height/4095;
00110     coord.z = _pen;
00111 
00112     return true;
00113 }
00114 
00115 
00116 bool AR1021I2C::init(uint16_t width, uint16_t height) {
00117     int result = 0;
00118     bool ok = false;
00119     int attempts = 0;
00120 
00121     _width = width;
00122     _height = height;
00123 
00124     while (1) {
00125 
00126         do {
00127             // disable touch
00128             result = cmd(AR1021_CMD_DISABLE_TOUCH, NULL, 0, NULL, 0);
00129             if (result != 0) {
00130                 debug("disable touch failed (%d)\n", result);
00131                 break;
00132             }
00133 
00134             char regOffset = 0;
00135             int regOffLen = 1;
00136             result = cmd(AR1021_CMD_REGISTER_START_ADDR_REQUEST, NULL, 0,
00137                     &regOffset, &regOffLen);
00138             if (result != 0) {
00139                 debug("register offset request failed (%d)\n", result);
00140                 break;
00141             }
00142 
00143             // enable calibrated coordinates
00144             //                  high, low address,                        len,  value
00145             char toptions[4] = {0x00, AR1021_REG_TOUCH_OPTIONS+regOffset, 0x01, 0x01};
00146             result = cmd(AR1021_CMD_REGISTER_WRITE, toptions, 4, NULL, 0);
00147             if (result != 0) {
00148                 debug("register write request failed (%d)\n", result);
00149                 break;
00150             }
00151 
00152             // save registers to eeprom
00153             result = cmd(AR1021_CMD_REGISTER_WRITE_TO_EEPROM, NULL, 0, NULL, 0);
00154             if (result != 0) {
00155                 debug("register write to eeprom failed (%d)\n", result);
00156                 break;
00157             }
00158 
00159             // enable touch
00160             result = cmd(AR1021_CMD_ENABLE_TOUCH, NULL, 0, NULL, 0);
00161             if (result != 0) {
00162                 debug("enable touch failed (%d)\n", result);
00163                 break;
00164             }
00165 
00166             _siqIrq.rise(this, &AR1021I2C::readTouchIrq);
00167 
00168             _initialized = true;
00169             ok = true;
00170 
00171         } while(0);
00172 
00173         if (ok) break;
00174 
00175         // try to run the initialize sequence at most 2 times
00176         if(++attempts >= 2) break;
00177     }
00178 
00179 
00180     return ok;
00181 }
00182 
00183 bool AR1021I2C::calibrateStart() {
00184     bool ok = false;
00185     int result = 0;
00186     int attempts = 0;
00187 
00188     if (!_initialized) return false;
00189 
00190     _siqIrq.rise(NULL);
00191 
00192     while(1) {
00193 
00194         do {
00195             // disable touch
00196             result = cmd(AR1021_CMD_DISABLE_TOUCH, NULL, 0, NULL, 0);
00197             if (result != 0) {
00198                 debug("disable touch failed (%d)\n", result);
00199                 break;
00200             }
00201 
00202             char regOffset = 0;
00203             int regOffLen = 1;
00204             result = cmd(AR1021_CMD_REGISTER_START_ADDR_REQUEST, NULL, 0,
00205                     &regOffset, &regOffLen);
00206             if (result != 0) {
00207                 debug("register offset request failed (%d)\n", result);
00208                 break;
00209             }
00210 
00211             // set insets
00212             // enable calibrated coordinates
00213             //                high, low address,                       len,  value
00214             char insets[4] = {0x00, AR1021_REG_CALIB_INSETS+regOffset, 0x01, _inset};
00215             result = cmd(AR1021_CMD_REGISTER_WRITE, insets, 4, NULL, 0);
00216             if (result != 0) {
00217                 debug("register write request failed (%d)\n", result);
00218                 break;
00219             }
00220 
00221             // calibration mode
00222             char calibType = 4;
00223             result = cmd(AR1021_CMD_CALIBRATE_MODE, &calibType, 1, NULL, 0, false);
00224             if (result != 0) {
00225                 debug("calibration mode failed (%d)\n", result);
00226                 break;
00227             }
00228 
00229             _calibPoint = 0;
00230             ok = true;
00231 
00232         } while(0);
00233 
00234         if (ok) break;
00235 
00236         // try to run the calibrate mode sequence at most 2 times
00237         if (++attempts >= 2) break;
00238     }
00239 
00240     return ok;
00241 }
00242 
00243 bool AR1021I2C::getNextCalibratePoint(uint16_t* x, uint16_t* y) {
00244 
00245     if (!_initialized) return false;
00246     if (x == NULL || y == NULL) return false;
00247 
00248     int xInset = (_width * _inset / 100) / 2;
00249     int yInset = (_height * _inset / 100) / 2;
00250 
00251     switch(_calibPoint) {
00252     case 0:
00253         *x = xInset;
00254         *y = yInset;
00255         break;
00256     case 1:
00257         *x = _width - xInset;
00258         *y = yInset;
00259         break;
00260     case 2:
00261         *x = _width - xInset;
00262         *y = _height - yInset;
00263         break;
00264     case 3:
00265         *x = xInset;
00266         *y = _height - yInset;
00267         break;
00268     default:
00269         return false;
00270     }
00271 
00272     return true;
00273 }
00274 
00275 bool AR1021I2C::waitForCalibratePoint(bool* morePoints, uint32_t timeout) {
00276     int result = 0;
00277     bool ret = false;
00278 
00279     if (!_initialized) return false;
00280 
00281     do {
00282         if (morePoints == NULL || _calibPoint >= AR1021_NUM_CALIB_POINTS) {
00283             break;
00284         }
00285 
00286         // wait for response
00287         result = waitForCalibResponse(timeout);
00288         if (result != 0) {
00289             debug("wait for calibration response failed (%d)\n", result);
00290             break;
00291         }
00292 
00293         _calibPoint++;
00294         *morePoints = (_calibPoint < AR1021_NUM_CALIB_POINTS);
00295 
00296 
00297         // no more points -> enable touch
00298         if (!(*morePoints)) {
00299 
00300             // wait for calibration data to be written to eeprom
00301             // before enabling touch
00302             result = waitForCalibResponse(timeout);
00303             if (result != 0) {
00304                 debug("wait for calibration response failed (%d)\n", result);
00305                 break;
00306             }
00307 
00308 
00309             // clear chip-select since calibration is done;
00310 //            _cs = 1;
00311 
00312             result = cmd(AR1021_CMD_ENABLE_TOUCH, NULL, 0, NULL, 0);
00313             if (result != 0) {
00314                 debug("enable touch failed (%d)\n", result);
00315                 break;
00316             }
00317 
00318             _siqIrq.rise(this, &AR1021I2C::readTouchIrq);
00319         }
00320 
00321         ret = true;
00322 
00323     } while (0);
00324 
00325 
00326 
00327     if (!ret) {
00328         // make sure to set chip-select off in case of an error
00329 //        _cs = 1;
00330         // calibration must restart if an error occurred
00331         _calibPoint = AR1021_NUM_CALIB_POINTS+1;
00332     }
00333 
00334 
00335 
00336     return ret;
00337 }
00338 
00339 int AR1021I2C::cmd(char cmd, char* data, int len, char* respBuf, int* respLen,
00340         bool setCsOff) {
00341 
00342     int ret = 0;
00343     int readLen = (respLen == NULL) ? 0 : *respLen;
00344     for (int attempt = 1; attempt <= AR1021_RETRY; attempt++) {
00345         if (attempt > 1) {
00346             wait_ms(50);
00347         }
00348 
00349         // command request
00350         // ---------------
00351         // 0x00 0x55 len cmd data
00352         // 0x00 = protocol command byte
00353         // 0x55 = header
00354         // len = data length + cmd (1)
00355         // data = data to send
00356 
00357         _i2c.start(); 
00358         _i2c.write(AR1021_ADDR);                   //send write address 
00359         _i2c.write(0x00); 
00360         _i2c.write(0x55);                          //header 
00361         _i2c.write(len+1);                         //message length 
00362         _i2c.write(cmd);
00363         for (int i = 0; i < len; i++) {
00364             _i2c.write(data[i]);
00365         }
00366         wait_us(60);
00367         _i2c.stop();
00368      
00369         // wait for response (siq goes high when response is available)
00370         Timer t;
00371         t.start();
00372         while(_siq.read() != 1 && t.read_ms() < AR1021_TIMEOUT);
00373         
00374         if (t.read_ms() < AR1021_TIMEOUT) {
00375         
00376             // command response
00377             // ---------------
00378             // 0x55 len status cmd data
00379             // 0x55 = header
00380             // len = number of bytes following the len byte (i.e. including the status&cmd)
00381             // status = status
00382             // cmd = command ID
00383             // data = data to receive
00384             _i2c.start();
00385             _i2c.write(AR1021_ADDR + 1);        //send read address 
00386             char header = _i2c.read(1);         //header should always be 0x55
00387             if (header != 0x55) {
00388                 ret = AR1021_ERR_NO_HDR;
00389                 continue;
00390             }
00391             char length = _i2c.read(1);         //data length
00392             if (length < 2) {
00393                 ret = AR1021_ERR_INV_LEN;       //must have at least status and command bytes
00394                 continue;
00395             }
00396             length -= 2;
00397             if (length > readLen) {
00398                 ret = AR1021_ERR_INV_LEN;       //supplied buffer is not enough
00399                 continue;
00400             }
00401 
00402             char status = _i2c.read(1);         //command status
00403             char usedCmd;
00404             if (readLen <= 0) {
00405                 usedCmd = _i2c.read(0);         //no data => read command byte + NACK
00406             } else {
00407                 usedCmd = _i2c.read(1);         //which command
00408 
00409                 //we need to send a NACK on the last read. 
00410                 int i;
00411                 for (i = 0; i < (length-1); i++) {
00412                     respBuf[i] = _i2c.read(1);
00413                 }
00414                 respBuf[i] = _i2c.read(0);      //last returned data byte + NACK
00415             }
00416             _i2c.stop();
00417             
00418             
00419             if (status != AR1021_RESP_STAT_OK) {
00420                 ret = -status;
00421                 continue;
00422             }
00423             if (usedCmd != cmd) {
00424                 ret = AR1021_ERR_INV_RESP;
00425                 continue;
00426             }
00427             
00428             // success
00429             ret = 0;
00430             break;
00431             
00432         } else {
00433             ret = AR1021_ERR_TIMEOUT;
00434             continue;
00435         }
00436     }
00437 
00438     return ret;
00439 }
00440 
00441 int AR1021I2C::waitForCalibResponse(uint32_t timeout) {
00442     Timer t;
00443     int ret = 0;
00444 
00445     t.start();
00446 
00447     // wait for siq
00448     while (_siq.read() != 1 &&
00449             (timeout == 0 || (uint32_t)t.read_ms() < (int)timeout));
00450 
00451 
00452     do {
00453 
00454         if (timeout >  0 && (uint32_t)t.read_ms() >= timeout) {
00455             ret = AR1021_ERR_TIMEOUT;
00456             break;
00457         }
00458 
00459         // command response
00460         // ---------------
00461         // 0x55 len status cmd data
00462         // 0x55 = header
00463         // len = number of bytes following the len byte (should be 2)
00464         // status = status
00465         // cmd = command ID
00466         _i2c.start();
00467         _i2c.write(AR1021_ADDR + 1);        //send read address 
00468         char header = _i2c.read(1);         //header should always be 0x55  
00469         char length = _i2c.read(1);         //data length
00470 
00471         if (header != 0x55) {
00472             ret = AR1021_ERR_NO_HDR;
00473             break;
00474         }
00475         if (length < 2) {
00476             ret = AR1021_ERR_INV_LEN;
00477             break;
00478         }
00479         char status = _i2c.read(1);         //status
00480         char cmd    = _i2c.read(0);         //command, should be NACK'ed
00481         _i2c.stop();
00482         if (status != AR1021_RESP_STAT_OK) {
00483             ret = -status;
00484             break;
00485         }
00486         if (cmd != AR1021_CMD_CALIBRATE_MODE) {
00487             ret = AR1021_ERR_INV_RESP;
00488             break;
00489         }
00490         
00491         // success
00492         ret = 0;
00493 
00494     } while (0);
00495 
00496     return ret;
00497 }
00498 
00499 
00500 void AR1021I2C::readTouchIrq() {
00501     while(_siq.read() == 1) {
00502 
00503         // touch coordinates are sent in a 5-byte data packet
00504         _i2c.start();
00505         _i2c.write(AR1021_ADDR + 1);        //send read address 
00506         int pen = _i2c.read(1);
00507         int xlo = _i2c.read(1);
00508         int xhi = _i2c.read(1);
00509         int ylo = _i2c.read(1);
00510         int yhi = _i2c.read(0);
00511         _i2c.stop();
00512         
00513         // pen down
00514         if ((pen&AR1021_PEN_MASK) == (1<<7|1<<0)) {
00515             _pen = 1;
00516         }
00517         // pen up
00518         else if ((pen&AR1021_PEN_MASK) == (1<<7)){
00519             _pen = 0;
00520         }
00521         // invalid value
00522         else {
00523             continue;
00524         }
00525 
00526         _x = ((xhi<<7)|xlo);
00527         _y = ((yhi<<7)|ylo);
00528     }
00529 }
00530 
00531 bool AR1021I2C::info(int* verHigh, int* verLow, int* resBits, int* type)
00532 {
00533     char buff[3] = {0,0,0};
00534     int read = 3;
00535     int res = cmd(AR1021_CMD_GET_VERSION, NULL, 0, buff, &read);
00536     if (res == 0) {
00537         *verHigh = buff[0];
00538         *verLow = buff[1];
00539         switch(buff[2] & 3) {
00540             case 0:   
00541                 *resBits = 8;
00542                 break;
00543             case 1:   
00544                 *resBits = 10;
00545                 break;
00546             case 2:   
00547                 *resBits = 12;
00548                 break;
00549             case 3:   
00550                 *resBits = 12;
00551                 break;
00552             default:
00553                 res = 25;
00554                 printf("Invalid resolution %d\n", buff[2]&3);
00555                 break;
00556         }
00557         *type = buff[2]>>2;
00558     }
00559     return (res == 0);
00560 }