A library with drivers for different peripherals on the LPC4088 QuickStart Board or related add-on boards.

Dependencies:   FATFileSystem

Dependents:   LPC4088test LPC4088test_ledonly LPC4088test_deleteall LPC4088_RAMtest ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AR1021.cpp Source File

AR1021.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 "AR1021.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 AR1021::AR1021(PinName mosi, PinName miso, PinName sck, PinName cs, PinName siq) :
00077 _spi(mosi, miso, sck), _cs(cs), _siq(siq), _siqIrq(siq)
00078 {
00079     _cs = 1; // active low
00080 
00081     _spi.format(8, 1);
00082     _spi.frequency(500000);
00083 
00084     // default calibration inset is 25 -> (25/2 = 12.5%)
00085     _inset = 25;
00086 
00087     // make sure _calibPoint has an invalid value to begin with
00088     // correct value is set in calibrateStart()
00089     _calibPoint = AR1021_NUM_CALIB_POINTS+1;
00090 
00091     _x = 0;
00092     _y = 0;
00093     _pen = 0;
00094 
00095     _initialized = false;
00096 }
00097 
00098 
00099 bool AR1021::read(touchCoordinate_t &coord) {
00100 
00101     if (!_initialized) return false;
00102 
00103     coord.x = _x * _width/4095;
00104     coord.y = _y * _height/4095;
00105     coord.z = _pen;
00106 
00107     return true;
00108 }
00109 
00110 
00111 bool AR1021::init(uint16_t width, uint16_t height) {
00112     int result = 0;
00113     bool ok = false;
00114     int attempts = 0;
00115 
00116     _width = width;
00117     _height = height;
00118 
00119     while (1) {
00120 
00121         do {
00122             // disable touch
00123             result = cmd(AR1021_CMD_DISABLE_TOUCH, NULL, 0, NULL, 0);
00124             if (result == -AR1021_RESP_STAT_CANCEL_CALIB) {
00125                 debug("calibration was cancelled, short delay and try again");
00126                 wait_us(50);
00127                 result = cmd(AR1021_CMD_DISABLE_TOUCH, NULL, 0, NULL, 0);
00128             }
00129             if (result != 0) {
00130                 debug("disable touch failed (%d)\n", result);
00131                 break;
00132             }
00133             wait_us(50);
00134 
00135             char regOffset = 0;
00136             int regOffLen = 1;
00137             result = cmd(AR1021_CMD_REGISTER_START_ADDR_REQUEST, NULL, 0,
00138                     &regOffset, &regOffLen);
00139             if (result != 0) {
00140                 debug("register offset request failed (%d)\n", result);
00141                 break;
00142             }
00143 
00144             // enable calibrated coordinates
00145             //                  high, low address,                        len,  value
00146             char toptions[4] = {0x00, AR1021_REG_TOUCH_OPTIONS+regOffset, 0x01, 0x01};
00147             result = cmd(AR1021_CMD_REGISTER_WRITE, toptions, 4, NULL, 0);
00148             if (result != 0) {
00149                 debug("register write request failed (%d)\n", result);
00150                 break;
00151             }
00152 
00153             // save registers to eeprom
00154             result = cmd(AR1021_CMD_REGISTER_WRITE_TO_EEPROM, NULL, 0, NULL, 0);
00155             if (result != 0) {
00156                 debug("register write to eeprom failed (%d)\n", result);
00157                 break;
00158             }
00159 
00160             // enable touch
00161             result = cmd(AR1021_CMD_ENABLE_TOUCH, NULL, 0, NULL, 0);
00162             if (result != 0) {
00163                 debug("enable touch failed (%d)\n", result);
00164                 break;
00165             }
00166 
00167             _siqIrq.rise(this, &AR1021::readTouchIrq);
00168 
00169             _initialized = true;
00170             ok = true;
00171 
00172         } while(0);
00173 
00174         if (ok) break;
00175 
00176         // try to run the initialize sequence at most 2 times
00177         if(++attempts >= 2) break;
00178     }
00179 
00180 
00181     return ok;
00182 }
00183 
00184 bool AR1021::calibrateStart() {
00185     bool ok = false;
00186     int result = 0;
00187     int attempts = 0;
00188 
00189     if (!_initialized) return false;
00190 
00191     _siqIrq.rise(NULL);
00192 
00193     while(1) {
00194 
00195         do {
00196             // disable touch
00197             result = cmd(AR1021_CMD_DISABLE_TOUCH, NULL, 0, NULL, 0);
00198             if (result != 0) {
00199                 debug("disable touch failed (%d)\n", result);
00200                 break;
00201             }
00202 
00203             char regOffset = 0;
00204             int regOffLen = 1;
00205             result = cmd(AR1021_CMD_REGISTER_START_ADDR_REQUEST, NULL, 0,
00206                     &regOffset, &regOffLen);
00207             if (result != 0) {
00208                 debug("register offset request failed (%d)\n", result);
00209                 break;
00210             }
00211 
00212             // set insets
00213             // enable calibrated coordinates
00214             //                high, low address,                       len,  value
00215             char insets[4] = {0x00, AR1021_REG_CALIB_INSETS+regOffset, 0x01, _inset};
00216             result = cmd(AR1021_CMD_REGISTER_WRITE, insets, 4, NULL, 0);
00217             if (result != 0) {
00218                 debug("register write request failed (%d)\n", result);
00219                 break;
00220             }
00221 
00222             // calibration mode
00223             char calibType = 4;
00224             result = cmd(AR1021_CMD_CALIBRATE_MODE, &calibType, 1, NULL, 0, false);
00225             if (result != 0) {
00226                 debug("calibration mode failed (%d)\n", result);
00227                 break;
00228             }
00229 
00230             _calibPoint = 0;
00231             ok = true;
00232 
00233         } while(0);
00234 
00235         if (ok) break;
00236 
00237         // try to run the calibrate mode sequence at most 2 times
00238         if (++attempts >= 2) break;
00239     }
00240 
00241     return ok;
00242 }
00243 
00244 bool AR1021::getNextCalibratePoint(uint16_t* x, uint16_t* y) {
00245 
00246     if (!_initialized) return false;
00247     if (x == NULL || y == NULL) return false;
00248 
00249     int xInset = (_width * _inset / 100) / 2;
00250     int yInset = (_height * _inset / 100) / 2;
00251 
00252     switch(_calibPoint) {
00253     case 0:
00254         *x = xInset;
00255         *y = yInset;
00256         break;
00257     case 1:
00258         *x = _width - xInset;
00259         *y = yInset;
00260         break;
00261     case 2:
00262         *x = _width - xInset;
00263         *y = _height - yInset;
00264         break;
00265     case 3:
00266         *x = xInset;
00267         *y = _height - yInset;
00268         break;
00269     default:
00270         return false;
00271     }
00272 
00273     return true;
00274 }
00275 
00276 bool AR1021::waitForCalibratePoint(bool* morePoints, uint32_t timeout) {
00277     int result = 0;
00278     bool ret = false;
00279 
00280     if (!_initialized) return false;
00281 
00282     do {
00283         if (morePoints == NULL || _calibPoint >= AR1021_NUM_CALIB_POINTS) {
00284             break;
00285         }
00286 
00287         // wait for response
00288         result = waitForCalibResponse(timeout);
00289         if (result != 0) {
00290             debug("wait for calibration response failed (%d)\n", result);
00291             break;
00292         }
00293 
00294         _calibPoint++;
00295         *morePoints = (_calibPoint < AR1021_NUM_CALIB_POINTS);
00296 
00297 
00298         // no more points -> enable touch
00299         if (!(*morePoints)) {
00300 
00301             // wait for calibration data to be written to eeprom
00302             // before enabling touch
00303             result = waitForCalibResponse(timeout);
00304             if (result != 0) {
00305                 debug("wait for calibration response failed (%d)\n", result);
00306                 break;
00307             }
00308 
00309 
00310             // clear chip-select since calibration is done;
00311             _cs = 1;
00312 
00313             result = cmd(AR1021_CMD_ENABLE_TOUCH, NULL, 0, NULL, 0);
00314             if (result != 0) {
00315                 debug("enable touch failed (%d)\n", result);
00316                 break;
00317             }
00318 
00319             _siqIrq.rise(this, &AR1021::readTouchIrq);
00320         }
00321 
00322         ret = true;
00323 
00324     } while (0);
00325 
00326 
00327 
00328     if (!ret) {
00329         // make sure to set chip-select off in case of an error
00330         _cs = 1;
00331         // calibration must restart if an error occurred
00332         _calibPoint = AR1021_NUM_CALIB_POINTS+1;
00333     }
00334 
00335 
00336 
00337     return ret;
00338 }
00339 
00340 int AR1021::cmd(char cmd, char* data, int len, char* respBuf, int* respLen,
00341         bool setCsOff) {
00342 
00343     int ret = 0;
00344 
00345     // command request
00346     // ---------------
00347     // 0x55 len cmd data
00348     // 0x55 = header
00349     // len = data length + cmd (1)
00350     // data = data to send
00351 
00352     _cs = 0;
00353 
00354     _spi.write(0x55);
00355     wait_us(50); // according to data sheet there must be an inter-byte delay of ~50us
00356     _spi.write(len+1);
00357     wait_us(50);
00358     _spi.write(cmd);
00359     wait_us(50);
00360 
00361     for(int i = 0; i < len; i++) {
00362         _spi.write(data[i]);
00363         wait_us(50);
00364     }
00365 
00366 
00367     // wait for response (siq goes high when response is available)
00368     Timer t;
00369     t.start();
00370     while(_siq.read() != 1 && t.read_ms() < 1000);
00371 
00372 
00373     // command response
00374     // ---------------
00375     // 0x55 len status cmd data
00376     // 0x55 = header
00377     // len = number of bytes following the len byte
00378     // status = status
00379     // cmd = command ID
00380     // data = data to receive
00381 
00382 
00383     do {
00384 
00385         if (t.read_ms() >= 1000) {
00386             ret = AR1021_ERR_TIMEOUT;
00387             break;
00388         }
00389 
00390         int head = _spi.write(0);
00391         if (head != 0x55) {
00392             ret = AR1021_ERR_NO_HDR;
00393             break;
00394         }
00395 
00396         wait_us(50);
00397         int len = _spi.write(0);
00398         if (len < 2) {
00399             ret = AR1021_ERR_INV_LEN;
00400             break;
00401         }
00402 
00403         wait_us(50);
00404         int status = _spi.write(0);
00405         if (status != AR1021_RESP_STAT_OK) {
00406             ret = -status;
00407             break;
00408         }
00409 
00410         wait_us(50);
00411         int cmdId = _spi.write(0);
00412         if (cmdId != cmd) {
00413             ret = AR1021_ERR_INV_RESP;
00414             break;
00415         }
00416 
00417         if ( ((len-2) > 0 && respLen  == NULL)
00418                 || ((len-2) > 0 && respLen != NULL && *respLen < (len-2))) {
00419             ret = AR1021_ERR_INV_RESPLEN;
00420             break;
00421         }
00422 
00423         for (int i = 0; i < len-2;i++) {
00424             wait_us(50);
00425             respBuf[i] = _spi.write(0);
00426         }
00427         if (respLen != NULL) {
00428             *respLen = len-2;
00429         }
00430 
00431         // make sure we wait 50us before issuing a new cmd
00432         wait_us(50);
00433 
00434     } while (0);
00435 
00436 
00437 
00438     // disable chip-select if setCsOff is true or if an error occurred
00439     if (setCsOff || ret != 0) {
00440         _cs = 1;
00441     }
00442 
00443 
00444 
00445     return ret;
00446 }
00447 
00448 int AR1021::waitForCalibResponse(uint32_t timeout) {
00449     Timer t;
00450     int ret = 0;
00451 
00452     t.start();
00453 
00454     // wait for siq
00455     while (_siq.read() != 1 &&
00456             (timeout == 0 || (uint32_t)t.read_ms() < (int)timeout));
00457 
00458 
00459     do {
00460 
00461         if (timeout >  0 && (uint32_t)t.read_ms() >= timeout) {
00462             ret = AR1021_ERR_TIMEOUT;
00463             break;
00464         }
00465 
00466         int head = _spi.write(0);
00467         if (head != 0x55) {
00468             ret = AR1021_ERR_NO_HDR;
00469             break;
00470         }
00471 
00472         wait_us(50);
00473         int len = _spi.write(0);
00474         if (len != 2) {
00475             ret = AR1021_ERR_INV_LEN;
00476             break;
00477         }
00478 
00479         wait_us(50);
00480         int status = _spi.write(0);
00481         if (status != AR1021_RESP_STAT_OK) {
00482             ret = -status;
00483             break;
00484         }
00485 
00486         wait_us(50);
00487         int cmdId = _spi.write(0);
00488         if (cmdId != 0x14) {
00489             ret = AR1021_ERR_INV_RESP;
00490             break;
00491         }
00492 
00493 
00494         // make sure we wait 50us before issuing a new cmd
00495         wait_us(50);
00496 
00497     } while (0);
00498 
00499 
00500     return ret;
00501 }
00502 
00503 
00504 void AR1021::readTouchIrq() {
00505     while(_siq.read() == 1) {
00506 
00507         _cs = 0;
00508 
00509         // touch coordinates are sent in a 5-byte data packet
00510 
00511         int pen = _spi.write(0);
00512         wait_us(50);
00513 
00514         int xlo = _spi.write(0);
00515         wait_us(50);
00516 
00517         int xhi = _spi.write(0);
00518         wait_us(50);
00519 
00520         int ylo = _spi.write(0);
00521         wait_us(50);
00522 
00523         int yhi = _spi.write(0);
00524         wait_us(50);
00525 
00526         _cs = 1;
00527 
00528 
00529         // pen down
00530         if ((pen&AR1021_PEN_MASK) == (1<<7|1<<0)) {
00531             _pen = 1;
00532         }
00533         // pen up
00534         else if ((pen&AR1021_PEN_MASK) == (1<<7)){
00535             _pen = 0;
00536         }
00537         // invalid value
00538         else {
00539             continue;
00540         }
00541 
00542         _x = ((xhi<<7)|xlo);
00543         _y = ((yhi<<7)|ylo);
00544 
00545     }
00546 }
00547