Basic I2C Driver for the TI DRV2605 Haptic Driver. Currently only supports Open-Loop ERM operation using internal Immersion TouchSense 2200 software/library, although user can use the Read/Write Byte methods to manually set registers and control the device.
Dependents: DRV2605L_Haptic_Driver_Demo IoT_Haptic_Noise_Irritator DuelingTanks
Revision 0:3b2b4f34aaca, committed 2015-10-21
- Comitter:
- electromotivated
- Date:
- Wed Oct 21 01:02:59 2015 +0000
- Commit message:
- v1 Upload;
Changed in this revision
DRV2605.cpp | Show annotated file Show diff for this revision Revisions of this file |
DRV2605.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 3b2b4f34aaca DRV2605.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DRV2605.cpp Wed Oct 21 01:02:59 2015 +0000 @@ -0,0 +1,115 @@ +#include "DRV2605.h" + +DRV2605::DRV2605(PinName sda, PinName scl): i2c(sda, scl){ + wait_us(250); // Device datasheet specified wait time before I2C + // comms should be used +} + +void DRV2605::i2cWriteByte(char reg, char value){ + char buff[2] = {reg, value}; + i2c.write(SLAVE_ADDR_7_BIT<<1, buff, 2); +} + +uint8_t DRV2605::i2cReadByte(char reg){ + char result; // Temp result storage + i2c.write(SLAVE_ADDR_7_BIT<<1, ®, 1, true); + i2c.read(SLAVE_ADDR_7_BIT<<1, &result, 1); + + return result; +} + +void DRV2605::mode(Mode mode){ + i2cWriteByte(MODE, mode); +} + +int DRV2605::init(float actuator_peak_voltage, Library lib){ + int result = + auto_cal_open_loop(actuator_peak_voltage); // Perform Open-Loop ERM Cal + i2cWriteByte(LIBRARY_SELECTION, lib); // Select ROM Library + mode(STANDBY); // Put device into low- power mode + return result; // Cal/Init Result 0: Pass 1: Fail +} + +uint8_t DRV2605::diagnostics(){ + mode(DIAG); + i2cWriteByte(GO, 1); + while(i2cReadByte(GO)); // Wait for GO bit to clear + + return i2cReadByte(STATUS); // Return Status Reg Value +} + +void DRV2605::play_waveform(int waveform_effect){ + mode(INTERNAL_TRIG); // Bring device out of standby and set to internal trigger + i2cWriteByte(WAVEFORM_SEQUENCER_1, waveform_effect); // Load waveform index to play + i2cWriteByte(WAVEFORM_SEQUENCER_2, 0); // Insert stop condition so we don't play other registers if filled + i2cWriteByte(GO, 0x01); // Set GO bit to start playback +} + +void DRV2605::load_waveform_sequence(int effect1, int effect2, + int effect3, int effect4, + int effect5, int effect6, + int effect7, int effect8){ + i2cWriteByte(WAVEFORM_SEQUENCER_1, effect1); + i2cWriteByte(WAVEFORM_SEQUENCER_2, effect2); + i2cWriteByte(WAVEFORM_SEQUENCER_3, effect3); + i2cWriteByte(WAVEFORM_SEQUENCER_4, effect4); + i2cWriteByte(WAVEFORM_SEQUENCER_5, effect5); + i2cWriteByte(WAVEFORM_SEQUENCER_6, effect6); + i2cWriteByte(WAVEFORM_SEQUENCER_7, effect7); + i2cWriteByte(WAVEFORM_SEQUENCER_8, effect8); +} + +void DRV2605::play(){ + i2cWriteByte(MODE, INTERNAL_TRIG); // Internal Trigger Mode + i2cWriteByte(GO, 1); +} + +uint8_t DRV2605::auto_cal_open_loop(float actuator_peak_voltage){ + // Exit Standby Mode; Enter Auto- Cal Mode + mode(AUTO_CAL); + + /* Set the following registers to the appropriate values: + • Rated Voltage (0x16) + • Overdrive Voltage (0x17) + • Feedback Control (0x1A) – Bits [1:0] can be left blank and will be + populated by the auto-calibration engine + • Control 1 (0x1B), Control 2 (0x1C), and Control 3 (0x1D) + • Mode (0x01) – Set mode to Auto-Calibration + • Auto-calibration Memory Interface (0x1E) – the auto-calibration time + can be increased to improve calibration, but can be left as default + for the initial calibration + */ + // Rated Voltage (0x16) not referenced for open-loop operation, skip calc + + // Calc and Set Overdrive Voltage Register (0x17) + int od_clamp = (int)(((actuator_peak_voltage*255)/5.6)+0.5); + i2cWriteByte(OVERDRIVE_CLAMP_VOLTAGE, + i2cReadByte(OVERDRIVE_CLAMP_VOLTAGE) | od_clamp); + + // Set Feedback Control Register (0x1A), use default values + + + // Set Control 1 Register (0x1B), use default values + + + // Set Control 2 Register (0x1C), use default values + + // Set Control3 Register (0x1D), Set to ERM Open-Loop Operation + i2cWriteByte(CONTROL3, 0xA0); + + // Set Control 4 Register (0x1E) + i2cWriteByte(CONTROL4, + i2cReadByte(CONTROL4 | 0x30)); // Max Calibration Time + + // Device already set to Auto- Cal Mode at top of this code block + + // Start auto- calibration + i2cWriteByte(GO, 0x01); + + // Wait for calibration to complete + while(i2cReadByte(GO)); + + // Read and return DIAG_RESULT in Status Register (0x00) + return (i2cReadByte(STATUS)); // Return the Diag_Result Bit Result +} +
diff -r 000000000000 -r 3b2b4f34aaca DRV2605.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DRV2605.h Wed Oct 21 01:02:59 2015 +0000 @@ -0,0 +1,199 @@ +/* + Bryce Williams 10/16/2015 + + Library for the TI DRV2605L 2 to 5.2 V Haptic Driver for LRA and ERM + With Effect Library and Smart-Loop Architecture + + References: + http://www.ti.com/product/DRV2605L/description&lpos=Middle_Container&lid=Alternative_Devices + http://www.ti.com/lit/ds/symlink/drv2605l.pdf (Datasheet) + http://www.ti.com/lit/an/sloa189/sloa189.pdf (Setup Guide; SLOA189) +*/ + +#ifndef DRV2605_H +#define DRV2605_H + +#include "mbed.h" + +/****************************************************************************** +***** DRV2605 Addresses +******************************************************************************/ +#define SLAVE_ADDR_7_BIT 0x5A // 7-bit slave address + +/****************************************************************************** +****** DRV2605 REGISTERS ****************************************************** +******************************************************************************/ +#define STATUS 0x00 +#define MODE 0x01 +#define REAL_TIME_PLAYBACK 0x02 +#define LIBRARY_SELECTION 0x03 +#define WAVEFORM_SEQUENCER_1 0x04 +#define WAVEFORM_SEQUENCER_2 0x05 +#define WAVEFORM_SEQUENCER_3 0x06 +#define WAVEFORM_SEQUENCER_4 0x07 +#define WAVEFORM_SEQUENCER_5 0x08 +#define WAVEFORM_SEQUENCER_6 0x09 +#define WAVEFORM_SEQUENCER_7 0x0A +#define WAVEFORM_SEQUENCER_8 0x0B +#define GO 0x0C +#define OVERDRIVE_TIME_OFFSET 0x0D +#define POSITIVE_SUSTAIN_TIME_OFFSET 0x0E +#define NEGATIVE_SUSTAIN_TIME_OFFSET 0x0F +#define BRAKE_TIME_OFFSET 0x10 +#define AUDIO_TO_VIBE_CONTROL 0x11 +#define AUDIO_TO_VIBE_MINIMUM_INPUT_LEVEL 0x12 +#define AUDIO_TO_VIBE_MAXIMUM_INPUT_LEVEL 0x13 +#define AUDIO_TO_VIBE_MINIMUM_OUPUT_DRIVE 0x14 +#define AUDIO_TO_VIBE_MAXIMUM_OUTPUT_DRIVE 0x15 +#define RATED_VOLTAGE 0x16 +#define OVERDRIVE_CLAMP_VOLTAGE 0x17 +#define AUTO_CALIBRATION_COMPENSATION_RESULT 0x18 +#define AUTO_CALIBRATION_BACK_EMF_RESULT 0x19 +#define FEEDBACK_CONTROL 0x1A +#define CONTROL 0x1B +#define CONTROL2 0x1C +#define CONTROL3 0x1D +#define CONTROL4 0x1E +#define CONTROL5 0x1F +#define LRA_OPEN_LOOP_PERIOD 0x20 +#define VBAT_VOLTAGE_MONITOR 0x21 +#define LRA_RESONANCE_PERIOD 0x22 + +class DRV2605{ + + public: + //// modes defines the possible modes of the DRV2605L + enum Mode{ + INTERNAL_TRIG, // 0x00: Waveforms fired by Setting GO bit in Register 0x0C + EXTERNAL_EDGE, // 0x01: Rising Edge on IN/TRIG pin set GO Bit. + EXTERNAL_LEVEL, // 0x02: GO bit follows state of edge on IN/TRIG pin. + PWM_ANALOG, // 0x03: PWM or Analog Signal accepted at IN/TRIG pin. + AUDIO_TO_VIBE, // 0x04: An AC-coupled audio signal is accepted at the IN/TRIG pin. + RTP, // 0x05: Real- Time Playback + DIAG, // 0x06: Set to perform actuator diagnostics + AUTO_CAL, // 0x07: Set to perform auto calibration of device for actuator + STANDBY = 0x40, // 0x40: Set Device to Software Standby (Low- Power Mode) + RESET = 0x80, // 0x80: Reset Device (equivalent of power cycling the device) + }; + + //// FeedBack_Controls Fields Bitmasks (Register Addr: 0x1A) + enum Actuator_Type{ERM = 0, LRA = 0x80}; // bit-7 + enum Brake_Factor{x1 = 0x00, x2 = 0x10, x3 = 0x20, + x4 = 0x40, x6 = 0x80, x8 = 0x50, + x16 = 0x60, DISABLE = 0x70}; // bit-6..4 + enum Loop_Gain{LOW = 0x00, + MED = 0x04, + HIGH = 0x08, + VERY_HIGH = 0x0C}; // bit-3..2 + + enum Library{EMPTY, A, B, C, D, E, + LRA_LIB, F}; // ROM Waveform Library Selections + + /** + Constructor for DRV2605 Objects + */ + DRV2605(PinName sda, PinName scl); + + /** + Write value to specified register of device + @param reg The device register to write + @param value The value to write to the register + */ + void i2cWriteByte(char reg, char value); + + /** + Read value from register of device + @param reg The device register to read + @return The result + */ + uint8_t i2cReadByte(char reg); + + /** + Place device into specified mode + @param mode The mode to place device into + */ + void mode(Mode mode); + + /** + TODO: Expand to allow initialization for LRAs and Closed Loop operation + Initialize the device for Open- Loop ERM mode using specified ROM + Waveform Library as specified in Section 9.3 of Device Datasheet. + See also Device Setup Guide 1.6.1 ERM Initialization Example + @param actuator_peak_voltage The Peak Voltage Rating of Actuator + @param lib The ROM Waveform Library to use + */ + int init(float actuator_peak_voltage, Library lib = B); + + /** + Runs diagnostics on the Actuator and Device and returns the results. + The results indicate if an actuator is detected, over- current events, + etc. Refer to STATUS Register (0x00) in device datasheet for more + description register values. + + Note: This should be run if the user is having trouble getting the actuator + to work. + + @return The results of the diagnostics (i.e. Status Reg (0x00)) + */ + uint8_t diagnostics(); + + /** + Play single waveform from ROM Library as outlined in Section 9.3.2.1 + of Device Datasheet. + The library used is the one that is currently written + to the Library_Selection Register (0x03). This library + is set in the init(Library lib) method, but can be + changed manually. + @param waveform_effect The Waveform Effect Library Index value to play + (valid values are 1 to 123) + */ + void play_waveform(int waveform_effect); + + /** + Load Wave Sequence into DRV2605 Sequence Registers + @param effect1... effect8 The effect to play. Valid inputs are + 0 to 123; 0: Stop Condition, + 1- 123: Waveform Index + */ + void load_waveform_sequence(int effect1 = 0, int effect2 = 0, + int effect3 = 0, int effect4 = 0, + int effect5 = 0, int effect6 = 0, + int effect7 = 0, int effect8 = 0); + + /** + Plays the currently loaded waveform or waveform sequence. + Call this after calling play_waveform() or after calling + load_waveform_sequence() + Preconditions: User must have already loaded waveform(s) + using play_waveform() or load_waveform_sequence() + */ + void play(); + + /** + TODO: Add Closed Loop Calibration + + Run basic DRV2605L Auto- Calibration as detailed in Section 2 of + the Device Setup Guide for OPEN- LOOP ONLY. + This must be done before using the device in closed- loop mode + (unless cal has been done before with values stored in non-volatile + mem; see datasheet for more info). + + NOTE: It is NOT recommended to store cal values into device + non-volatile memory as this can be done only once. Thus do not + use this feature unless the device is being used in a final + project AND values have been confirmed to result in satisfactory + performance). + + This uses many of the default device register values such as + the default DRIVE_TIME . + + @param actuator_peak_voltage The maximum/peak voltage rating of the actuator + */ + uint8_t auto_cal_open_loop(float actuator_peak_voltage); + + private: + I2C i2c; + +}; + +#endif \ No newline at end of file