andrewm@268: /* andrewm@268: * I2C_MPR121.cpp andrewm@268: * andrewm@268: * Created on: Oct 14, 2013 andrewm@268: * Author: Victor Zappi andrewm@268: */ andrewm@268: andrewm@268: andrewm@268: #include "I2C_MPR121.h" andrewm@268: andrewm@268: I2C_MPR121::I2C_MPR121() { andrewm@268: andrewm@268: } andrewm@268: andrewm@268: boolean I2C_MPR121::begin(uint8_t bus, uint8_t i2caddr) { andrewm@268: _i2c_address = i2caddr; andrewm@268: andrewm@268: if(initI2C_RW(bus, i2caddr, 0) > 0) andrewm@268: return false; andrewm@268: andrewm@268: // soft reset andrewm@268: writeRegister(MPR121_SOFTRESET, 0x63); andrewm@268: usleep(1000); andrewm@268: //delay(1); andrewm@268: for (uint8_t i=0; i<0x7F; i++) { andrewm@268: // Serial.print("$"); Serial.print(i, HEX); andrewm@268: // Serial.print(": 0x"); Serial.println(readRegister8(i)); andrewm@268: } andrewm@268: andrewm@268: andrewm@268: writeRegister(MPR121_ECR, 0x0); andrewm@268: andrewm@268: uint8_t c = readRegister8(MPR121_CONFIG2); andrewm@268: andrewm@268: if (c != 0x24) { andrewm@268: rt_printf("MPR121 read 0x%x instead of 0x24\n", c); andrewm@268: return false; andrewm@268: } andrewm@268: andrewm@268: setThresholds(12, 6); andrewm@268: writeRegister(MPR121_MHDR, 0x01); andrewm@268: writeRegister(MPR121_NHDR, 0x01); andrewm@268: writeRegister(MPR121_NCLR, 0x0E); andrewm@268: writeRegister(MPR121_FDLR, 0x00); andrewm@268: andrewm@268: writeRegister(MPR121_MHDF, 0x01); andrewm@268: writeRegister(MPR121_NHDF, 0x05); andrewm@268: writeRegister(MPR121_NCLF, 0x01); andrewm@268: writeRegister(MPR121_FDLF, 0x00); andrewm@268: andrewm@268: writeRegister(MPR121_NHDT, 0x00); andrewm@268: writeRegister(MPR121_NCLT, 0x00); andrewm@268: writeRegister(MPR121_FDLT, 0x00); andrewm@268: andrewm@268: writeRegister(MPR121_DEBOUNCE, 0); andrewm@268: writeRegister(MPR121_CONFIG1, 0x10); // default, 16uA charge current andrewm@268: writeRegister(MPR121_CONFIG2, 0x20); // 0.5uS encoding, 1ms period andrewm@268: andrewm@268: // writeRegister(MPR121_AUTOCONFIG0, 0x8F); andrewm@268: andrewm@268: // writeRegister(MPR121_UPLIMIT, 150); andrewm@268: // writeRegister(MPR121_TARGETLIMIT, 100); // should be ~400 (100 shifted) andrewm@268: // writeRegister(MPR121_LOWLIMIT, 50); andrewm@268: // enable all electrodes andrewm@268: writeRegister(MPR121_ECR, 0x8F); // start with first 5 bits of baseline tracking andrewm@268: andrewm@268: return true; andrewm@268: } andrewm@268: andrewm@268: void I2C_MPR121::setThresholds(uint8_t touch, uint8_t release) { andrewm@268: for (uint8_t i=0; i<12; i++) { andrewm@268: writeRegister(MPR121_TOUCHTH_0 + 2*i, touch); andrewm@268: writeRegister(MPR121_RELEASETH_0 + 2*i, release); andrewm@268: } andrewm@268: } andrewm@268: andrewm@268: uint16_t I2C_MPR121::filteredData(uint8_t t) { andrewm@268: if (t > 12) return 0; andrewm@268: return readRegister16(MPR121_FILTDATA_0L + t*2); andrewm@268: } andrewm@268: andrewm@268: uint16_t I2C_MPR121::baselineData(uint8_t t) { andrewm@268: if (t > 12) return 0; andrewm@268: uint16_t bl = readRegister8(MPR121_BASELINE_0 + t); andrewm@268: return (bl << 2); andrewm@268: } andrewm@268: andrewm@268: uint16_t I2C_MPR121::touched(void) { andrewm@268: uint16_t t = readRegister16(MPR121_TOUCHSTATUS_L); andrewm@268: return t & 0x0FFF; andrewm@268: } andrewm@268: andrewm@268: /*********************************************************************/ andrewm@268: andrewm@268: andrewm@268: uint8_t I2C_MPR121::readRegister8(uint8_t reg) { andrewm@268: unsigned char inbuf, outbuf; andrewm@268: struct i2c_rdwr_ioctl_data packets; andrewm@268: struct i2c_msg messages[2]; andrewm@268: andrewm@268: /* andrewm@268: * In order to read a register, we first do a "dummy write" by writing andrewm@268: * 0 bytes to the register we want to read from. This is similar to andrewm@268: * the packet in set_i2c_register, except it's 1 byte rather than 2. andrewm@268: */ andrewm@268: outbuf = reg; andrewm@268: messages[0].addr = 0x5A; andrewm@268: messages[0].flags = 0; andrewm@268: messages[0].len = sizeof(outbuf); andrewm@268: messages[0].buf = &outbuf; andrewm@268: andrewm@268: /* The data will get returned in this structure */ andrewm@268: messages[1].addr = 0x5A; andrewm@268: messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/; andrewm@268: messages[1].len = sizeof(inbuf); andrewm@268: messages[1].buf = &inbuf; andrewm@268: andrewm@268: /* Send the request to the kernel and get the result back */ andrewm@268: packets.msgs = messages; andrewm@268: packets.nmsgs = 2; andrewm@268: if(ioctl(i2C_file, I2C_RDWR, &packets) < 0) { andrewm@268: rt_printf("Unable to send data"); andrewm@268: return 0; andrewm@268: } andrewm@268: andrewm@268: return inbuf; andrewm@268: } andrewm@268: andrewm@268: uint16_t I2C_MPR121::readRegister16(uint8_t reg) { andrewm@268: unsigned char inbuf[2], outbuf; andrewm@268: struct i2c_rdwr_ioctl_data packets; andrewm@268: struct i2c_msg messages[2]; andrewm@268: andrewm@268: /* andrewm@268: * In order to read a register, we first do a "dummy write" by writing andrewm@268: * 0 bytes to the register we want to read from. This is similar to andrewm@268: * the packet in set_i2c_register, except it's 1 byte rather than 2. andrewm@268: */ andrewm@268: outbuf = reg; andrewm@268: messages[0].addr = _i2c_address; andrewm@268: messages[0].flags = 0; andrewm@268: messages[0].len = sizeof(outbuf); andrewm@268: messages[0].buf = &outbuf; andrewm@268: andrewm@268: /* The data will get returned in this structure */ andrewm@268: messages[1].addr = _i2c_address; andrewm@268: messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/; andrewm@268: messages[1].len = sizeof(inbuf); andrewm@268: messages[1].buf = inbuf; andrewm@268: andrewm@268: /* Send the request to the kernel and get the result back */ andrewm@268: packets.msgs = messages; andrewm@268: packets.nmsgs = 2; andrewm@268: if(ioctl(i2C_file, I2C_RDWR, &packets) < 0) { andrewm@268: rt_printf("Unable to send data"); andrewm@268: return 0; andrewm@268: } andrewm@268: andrewm@268: return (uint16_t)inbuf[0] | (((uint16_t)inbuf[1]) << 8); andrewm@268: } andrewm@268: andrewm@268: /**************************************************************************/ andrewm@268: /*! andrewm@268: @brief Writes 8-bits to the specified destination register andrewm@268: */ andrewm@268: /**************************************************************************/ andrewm@268: void I2C_MPR121::writeRegister(uint8_t reg, uint8_t value) { andrewm@268: uint8_t buf[2] = { reg, value }; andrewm@268: andrewm@268: if(write(i2C_file, buf, 2) != 2) andrewm@268: { andrewm@268: cout << "Failed to write register " << (int)reg << " on MPR121\n"; andrewm@268: return; andrewm@268: } andrewm@268: } andrewm@268: