This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DRV2605: DRV2605 Problem

Part Number: DRV2605

Hi Team,

 

I experience a weird problem with the DRV2605.

I initialize the DRV2605 according to the datasheet, and I use ERM.

 

Once I set the GO bit in the GO register it will never reset, no effect on the ERM as well (no vibration).

 

During initialization the GO bit is set first in the calibration process, which should end after 1 second, the GO bit never resets.

 

I tried skipping the calibration, so the the GO bit is set in the diagnostics, the same result, the GO bit will not reset.

 

I tried to skip the diagnostics as well, and set the GO bit only for vibration, there was no vibration, and the GO bit will not reset.

 

I attach me code.

Best Regards,

Shlomi

drv2605.h

drv2605.c
/**
  ******************************************************************************
  * @file   : DRV2605.c
  * @author : Igal Ofri
  * @brief  : This file provides code for the configuration
  *           and APIs of DRV2605.
  ******************************************************************************
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are not permitted.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "drv2605.h"

#include "app_functions.h"
#include "gpio.h"
#include "i2c.h"

/* Defines ------------------------------------------------------------------*/
#define DRV2605_I2C_ADDRESS    0xB4

#define STATUS_REGISTER         0x00
//Status register bits
#define OVERCURRENT_DETECTED          0x01
#define OVERTEMPERATUE_DETECTED       0x02
#define FEEDBACK_CONTROLLER_TIMED_OUT 0x04  /* This indicates when the ERM
                                               back-EMF has been zero for more than ~10 ms in ERM mode, and
                                               indicates when the LRA frequency tracking has lost frequency lock in LRA
                                               mode. This bit is for debug purposes only, and can sometimes be set
                                               under normal operation when extensive braking periods are used. This bit
                                               will clear upon read.*/
#define AUTO_CALIBRATION_FAILED       0x08  /* This flag stores the result of the auto-calibration routine and the */
#define ACTUATOR_FAULT                0x08  /* diagnostic routine. The flag contains the result for whichever routine was
                                               executed last. The flag clears upon read. Test result is not valid until the GO
                                               bit selfclears at the end of the routine. */
#define DEVICE_ID_MASK                0xE0
#define DRV2604                       0x80  //contains RAM, does not contain licensed ROM library
#define DRV2605                       0x60  //contains licensed ROM library, does not contain RAM
#define DRV2604L                      0xC0  //low-voltage version of the DRV2604 device
#define DRV2605L                      0xE0  //low-voltage version of the DRV2605 device

#define MODE_REGISTER           0x01
//Mode register bits
#define INTERNAL_TRIGGER              0x00
#define EXTERNAL_TRIGGER_EDGE_MODE    0x01
#define EXTERNAL_TRIGGER_LEVEL_MODE   0x02
#define PWM_ANALO_INPUT               0x03
#define AUDIO_TO_VIBE_MODE            0x04
#define RTP_MODE                      0x05  //Real-time playback
#define DIAGNOSTICS_MODE              0x06
#define AUTO_CALIBRATION              0x07

#define STANDBY_MODE                  0x40
#define DEVICE_RESET                  0x80  /* Setting this bit performs the equivalent operation of power
                                               cycling the device. Any playback operations are immediately interrupted,
                                               and all registers are reset to the default values. The DEV_RESET bit selfclears
                                               after the reset operation is complete. */

/* This register is the entry point for real-time playback (RTP) data. The DRV2605
    playback engine drives the RT_PLAYBACK_INPUT[7:0] value to the load when
    MODE[2:0] = 5 (RTP mode). The RT_PLAYBACK_INPUT[7:0] value can be updated in
    real-time by the host controller to create haptic waveforms. The
    RT_PLAYBACK_INPUT[7:0] value is interpreted as signed by default, but can be set to
    unsigned by the DATA_FORMAT_RTP bit in register 0x1D. When the
    haptic waveform is complete, the user can idle the device by setting
    MODE[2:0] = 0, or alternatively by setting STANDBY = 1. */
#define RT_PLAYBACK_INPUT_REG   0x02

#define CONFIG_REGISTER         0x03
//Configuration register bits
#define NO_LIBRARY                    0x00
#define TS2200_LIBRARY_A              0x01
#define TS2200_LIBRARY_B              0x02
#define TS2200_LIBRARY_C              0x03
#define TS2200_LIBRARY_D              0x04
#define TS2200_LIBRARY_E              0x05
#define LRA_LIBRARY                   0x06

#define OUTPUT_DRIVE_IN_HI_Z          0x10  /* This bit sets the output driver into a true high-impedance state. The device
                                                must be enabled to go into the high-impedance state. When in hardware
                                                shutdown or standby mode, the output drivers have 15 k� to ground. When
                                                the HI_Z bit is asserted, the hi-Z functionality takes effect immediately, even
                                                if a transaction is taking place. */

#define WAVEFORM_SEQ_1          0x04
#define WAVEFORM_SEQ_2          0x05
#define WAVEFORM_SEQ_3          0x06
#define WAVEFORM_SEQ_4          0x07
#define WAVEFORM_SEQ_5          0x08
#define WAVEFORM_SEQ_6          0x09
#define WAVEFORM_SEQ_7          0x0A
#define WAVEFORM_SEQ_8          0x0B
//Waveform sequencer bits
#define WAVEFORM_SEQ_VAL_MASK         0x7F
#define WAVEFORM_WAIT                 0x80  /* When this bit is set, the WAV_FRM_SEQ[6:0] bit is interpreted as a wait
                                                time in which the playback engine idles. This bit is used to insert timed
                                                delays between sequentially played waveforms.
                                                Delay time = 10 ms � WAV_FRM_SEQ[6:0]
                                                If WAIT = 0, then WAV_FRM_SEQ[6:0] is interpreted as a waveform
                                                identifier for sequence playback. */

#define GO_REGISTER             0x0C
#define GO_BIT                        0x01  /* This bit is used to fire processes in the DRV2605 device. The process
                                                fired by the GO bit is selected by the MODE[2:0] bit (register 0x01). The
                                                primary function of this bit is to fire playback of the waveform identifiers in
                                                the waveform sequencer (registers 0x04 to 0x0B), in which case, this bit
                                                can be thought of a software trigger for haptic waveforms. The GO bit
                                                remains high until the playback of the haptic waveform sequence is
                                                complete. Clearing the GO bit during waveform playback cancels the
                                                waveform sequence. Using one of the external trigger modes can cause
                                                the GO bit to be set or cleared by the external trigger pin. This bit can also
                                                be used to fire the auto-calibration process or the diagnostic process. */

/* This register adds a time offset to the overdrive portion of the library
    waveforms. Some motors require more overdrive time than others,
    therefore this register allows the user to add or remove overdrive time
    from the library waveforms. The maximum voltage value in the library
    waveform is automatically determined to be the overdrive portion. This
    register is only useful in open-loop mode. Overdrive is automatic for
    closed-loop mode. The offset is interpreted as 2s complement, therefore
    the time offset can be positive or negative.
    Overdrive Time Offset (ms) = ODT[7:0] � PLAYBACK_INTERVAL */
#define OVERDRIVE_TIME_OFFSET   0x0D

/* This register adds a time offset to the positive sustain portion of the library
    waveforms. Some motors have a faster or slower response time than
    others, therefore this register allows the user to add or remove positive
    sustain time from the library waveforms. Any positive voltage value other
    than the overdrive portion is considered as a sustain positive value. The
    offset is interpreted as 2s complement, therefore the time offset can positive
    or negative.
    Sustain-Time Positive Offset (ms) = SPT[7:0] � PLAYBACK_INTERVAL */
#define SUSTAIN_TIME_OFFSET_POS 0x0E

/* This register adds a time offset to the negative sustain portion of the library
    waveforms. Some motors have a faster or slower response time than
    others, therefore this register allows the user to add or remove negative
    sustain time from the library waveforms. Any negative voltage value other
    than the overdrive portion is considered as a sustaining negative value. The
    offset is interpreted as two�s complement, therefore the time offset can be
    positive or negative.
    Sustain-Time Negative Offset (ms) = SNT[7:0] � PLAYBACK_INTERVAL */
#define SUSTAIN_TIME_OFFSET_NEG 0x0F

/* This register adds a time offset to the braking portion of the library waveforms.
    Some motors require more braking time than others, therefore this register
    allows the user to add or take away brake time from the library waveforms.
    The most negative voltage value in the library waveform is automatically
    determined to be the braking portion. This register is only useful in open-loop
    mode. Braking is automatic for closed-loop mode. The offset is interpreted as
    2s complement, therefore the time offset can be positive or negative.
    Brake Time Offset (ms) = BRT[7:0] � PLAYBACK_INTERVAL */
#define BRAKE_TIME_OFFSET       0x10

#define AUDIO_TO_VIBE_CONTROL   0x11
//Audio to vibe control bits
#define LPF_100HZ                     0x00
#define LPF_125HZ                     0x01
#define LPF_150HZ                     0x02
#define LPF_200HZ                     0x03

#define PEAK_DETECTION_10MS           0x00
#define PEAK_DETECTION_20MS           0x04
#define PEAK_DETECTION_30MS           0x08
#define PEAK_DETECTION_40MS           0x0C

/* This register sets the minimum voltage level at the IN/TRIG pin that is detected by
    the audio-to-vibe engine. Levels below this are ignored.
    ATH_MIN_INPUT Voltage (VPP) = ATH_MIN_INPUT[7:0] � 1.8 V / 255 */
#define AUDIO_TO_VIBE_MIN_LEVEL 0x12

/* This register sets the full-scale voltage level at the IN/TRIG pin for audio-to-vibe mode.
    ATH_MAX_INPUT Voltage (VPP) = ATH_MAX_INPUT[7:0] � 1.8 V / 255 */
#define AUDIO_TO_VIBE_MAX_LEVEL 0x13

/* This register sets the minimum output level that is applied to the actuator drive engine.
  ATH_MIN_DRIVE (%) = ATH_MIN_DRIVE[7:0] / 255 � 100% */
#define AUDIO_TO_VIBE_MIN_OUT   0x14

/* This register sets the maximum output level that is applied to the actuator drive engine.
    ATH_MAX_DRIVE (%) = ATH_MAX_DRIVE[7:0] / 255 � 100% */
#define AUDIO_TO_VIBE_MAX_OUT   0x15

/* This register sets the reference voltage for full-scale output during closed-loop
    operation. The auto-calibration routine uses this register as an input, therefore
    this register must be written with the rated voltage value of the motor before
    calibration is performed. This register is ignored for open-loop operation
    because the overdrive voltage sets the reference for that case. Any
    modification of this register value should be followed by calibration to set
    A_CAL_BEMF appropriately. */
#define RATED_VOLTAGE           0x16

/* During closed-loop operation the actuator feedback allows the output voltage
    to go above the rated voltage during the automatic overdrive and automatic
    braking periods. This register sets a clamp so that the automatic overdrive is
    bounded. This bit also serves as the full-scale reference voltage for open-loop
    operation. */
#define OVERDRIVE_CLAMP_VOLTAGE 0x17

/* This register contains the voltage-compensation result after execution of auto
    calibration. The value stored in the A_CAL_COMP bit compensates for any
    resistive losses in the driver. The calibration routine checks the impedance of
    the actuator to automatically determine an appropriate value. The autocalibration
    compensation-result value is multiplied by the drive gain during playback.
    Auto-calibration compensation coefficient = 1 + A_CAL_COMP[7:0] / 255 */
#define AUTO_CALIB_COMPENSATION 0x18

/* This register contains the rated back-EMF result after execution of auto
   calibration. The A_CAL_BEMF[7:0] bit is the level of back-EMF voltage that the
   actuator gives when the actuator is driven at the rated voltage. The DRV2605
   playback engine uses this the value stored in this bit to automatically determine
   the appropriate feedback gain for closed-loop operation.
   Auto-calibration back-EMF (V) = (A_CAL_BEMF[7:0] / 255) � 1.22 V /
   BEMF_GAIN[1:0] */
#define AUTO_CALIB_BACK_EMF     0x19

/* This register sets the analog gain of the back-EMF amplifier. This value is interpreted
    differently between ERM mode and LRA mode. Auto calibration automatically
    populates the BEMF_GAIN bit with the most appropriate value for the actuator. */
#define FEEDBACK_CONTROL_REG    0x1A
//Feedback control bits
#define ERM_X_0_33                    0x00
#define ERM_X_1_0                     0x01
#define ERM_X_1_8                     0x02
#define ERM_X_4_0                     0x03
#define LRA_X_5                       0x00
#define LRA_X_10                      0x01
#define LRA_X_20                      0x02
#define LRA_X_30                      0x03

#define LOOP_GAIN_LOW                 0x00    /* Loop gain bits selects a loop gain for the feedback control. The LOOP_GAIN[1:0] bit */
#define LOOP_GAIN_MEDIUM              0x04    /* sets how fast the loop attempts to make the back-EMF (and thus motor velocity) */
#define LOOP_GAIN_HIGH                0x08    /* match the input signal level. Higher loop-gain (faster settling) options provide */
#define LOOP_GAIN_VERY_HIGH           0x0C    /* less-stable operation than lower loop gain (slower settling). This value should be set  */
                                              /* prior to running auto calibration.*/

#define FEEDBACK_BRAKE_FACTOR_X1      0x00    /* Feedback brake factor bits selects the feedback gain ratio between braking gain and */
#define FEEDBACK_BRAKE_FACTOR_X2      0x10    /* driving gain. In general, adding additional feedback gain while braking is desirable so */
#define FEEDBACK_BRAKE_FACTOR_X3      0x20    /* that the actuator brakes as quickly as possible. Large ratios provide less-stable */
#define FEEDBACK_BRAKE_FACTOR_X4      0x30    /* operation than lower ones. This value should be set prior to running auto calibration. */
#define FEEDBACK_BRAKE_FACTOR_X6      0x40
#define FEEDBACK_BRAKE_FACTOR_X8      0x50
#define FEEDBACK_BRAKE_FACTOR_X16     0x60
#define FEEDBACK_BRAKE_DISABLED       0x70

#define ERM_MODE                      0x00    /* Mode selection - this bit should be set prior to running auto calibration. */
#define LRA_MODE                      0x80

#define CONTRL1_REGISTER        0x1B
//Control 1 bits
#define DRIVE_TIME_MASK               0x1F  /* LRA Mode: Sets initial guess for LRA drive-time in LRA mode. Drive time is
                                                automatically adjusted for optimum drive in real time; however, this register
                                                should be optimized for the approximate LRA frequency. If the bit is set too low,
                                                it can affect the actuator startup time. If it is set too high, it can cause instability.
                                                Optimum drive time (ms) . 0.5 x LRA Period
                                                Drive time (ms) = DRIVE_TIME[4:0] x 0.1 ms + 0.5 ms
                                               ERM Mode: Sets the sample rate for the back-EMF detection. Lower drive times
                                                cause higher peak-to-average ratios in the output signal, requiring more supply
                                                headroom. Higher drive times cause the feedback to react at a slower rate.
                                                Drive Time (ms) = DRIVE_TIME[4:0] x 0.2 ms + 1 ms */

#define COMMON_MODE_DRIVE_EN          0x20  /* This register applies a 0.9-V common mode voltage to the IN/TRIG pin when an AC coupling
                                                capacitor is used. This bit is only useful for analog input mode. This bit
                                                should not be asserted for PWM mode or external trigger mode. */

#define STARTUP_BOOST                 0x80  /* This registe applies higher loop gain during overdrive to enhance actuator transient response. */

#define CONTROL2_REGISTER       0x1C
//Control 2 register bits
#define CURRENT_DISSIPATION_TIME_MASK 0x03  /* This bit is the time allowed for the current to dissipate */
#define CURRENT_DISSIPATION_TIME_0    0x00  /* from the actuator between PWM cycles for flyback mitigation.*/
#define CURRENT_DISSIPATION_TIME_1    0x01
#define CURRENT_DISSIPATION_TIME_2    0x02
#define CURRENT_DISSIPATION_TIME_3    0x03

#define BLANKING_TIME_MASK            0x0C  /* Blanking time before the back-EMF AD makes a conversion. */
#define BLANKING_TIME_0               0x00
#define BLANKING_TIME_1               0x04
#define BLANKING_TIME_2               0x06
#define BLANKING_TIME_3               0x0C

#define SAMPLE_TIME_150US             0x00  /* LRA auto-resonance sampling time */
#define SAMPLE_TIME_200US             0x10
#define SAMPLE_TIME_250US             0x20
#define SAMPLE_TIME_300US             0x30

#define BRAKE_STABILIZER              0x40  /* When this bit is set, loop gain is reduced when braking is almost complete to
                                                improve loop stability */
#define UNIDIRECTIONAL_INPUT_MODE     0x00
#define BIDIRECTIONAL_INPUT_MODE      0x80

#define CONTROL3_REGISTER       0x1D
//Control 3 register bits
#define AUTO_RESONANCE_MODE           0x00
#define LRA_OPEN_LOOP_MODE            0x01

#define PWM_INPUT                     0x00
#define ANALOG_INPUT                  0x02

#define LRA_DRIVE_MODE_ONCE_PER_CYCLE 0x00
#define LRA_DRIVE_MODE_TWICE_PERCYCLE 0x04

#define RTP_FORMAT_SIGNED             0x00
#define RTP_FORMAT_UNSIGNED           0x08

#define SUPPLY_COMPENSATION_ENABLED   0x00
#define SUPPLY_COMPENSATION_DISABLED  0x10

#define ERM_CLOSED_LOOP               0x00
#define ERM_OPEN_LOOP                 0x20

#define PWM_NOISE_GATE_THRESHOLD_DIS  0x00
#define PWM_NOISE_GATE_THRESHOLD_2PCT 0x40
#define PWM_NOISE_GATE_THRESHOLD_4PCT 0x80
#define PWM_NOISE_GATE_THRESHOLD_8PCT 0xC0

#define CONTROL4_REGISTER       0x1E
//Control 4 register bits
#define OTP_PROGRAM                   0x01  /* This bit launches the programming process for one-time programmable (OTP)
                                                memory which programs the contents of register 0x16 through 0x1A into
                                                nonvolatile memory. This process can only be executed one time per device. */
#define OTP_PROGRAMMED                0x04

#define AUTO_CAL_TIME_150MS           0x00  /* These bits sets the length of the auto calibration time. The AUTO_CAL_TIME[1:0] */
#define AUTO_CAL_TIME_250MS           0x20  /*  bit should be enough time for the motor acceleration to settle when driven */
#define AUTO_CAL_TIME_500MS           0x40  /*  at the RATED_VOLTAGE[7:0] value. */
#define AUTO_CAL_TIME_1000MS          0x60

/* This register provides a real-time reading of the supply voltage at the VDD pin. The
    device must be actively sending a waveform to take a reading.
    VDD (V) = VBAT[7:0] � 5.6V / 255 */
#define VBAT_VOLTAGE_REGISTER   0x21

/* This bit reports the measurement of the LRA resonance period. The device must
    be actively sending a waveform to take a reading.
    LRA period (us) = LRA_Period[7:0] �~ 98.46 us */
#define LRA_RESONANCE_PERIOD_REG 0x22

/* Type Defnition ------------------------------------------------------------------*/

/* Global Variables ------------------------------------------------------------------*/
volatile struct HapticFeedbackParametersStruct haptic_feedbak_parameters;

/* Private Variables ------------------------------------------------------------------*/
/* Prototypes ------------------------------------------------------------------*/
static enum SystemFaultsEnum Dvr2605AutoCalibration(void);
static enum SystemFaultsEnum Dvr2605Failed(void);
static enum SystemFaultsEnum Dvr2605Vibrate(enum WaveformEffectEnum waveform_index);
static enum SystemFaultsEnum Dvr2605Diagnostics(void);
static uint8_t Drv2605IsBusy(void);


/**
  * @brief Initialization of DRV2605
  * @param  None
  * @retval eSYSTEM_OK or eDRV2605_FAILED
  */
enum SystemFaultsEnum Dvr2605Init(void)
{
  uint8_t register_value;

  EnableHapticDriver();
  WaitHere(eDELAY250USEC, SystemCoreClock);

  I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, STATUS_REGISTER, I2C_MEMADD_SIZE_8BIT, 1);
  if ((register_value & DEVICE_ID_MASK) != DRV2605)
    return Dvr2605Failed();

  register_value = INTERNAL_TRIGGER;    //exit standby
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, MODE_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return Dvr2605Failed();

#ifdef ERM_MODE
  register_value = ERM_MODE + ERM_X_1_8 + LOOP_GAIN_MEDIUM + FEEDBACK_BRAKE_FACTOR_X4;
#else
  register_value = LRA_MODE + LRA_X_20 + LOOP_GAIN_MEDIUM + FEEDBACK_BRAKE_FACTOR_X4;
#endif /* ERM_MODE */
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, FEEDBACK_CONTROL_REG, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return Dvr2605Failed();

  I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTROL4_REGISTER, I2C_MEMADD_SIZE_8BIT, 1);
  if (!(register_value & OTP_PROGRAMMED))
    if (Dvr2605AutoCalibration() != eSYSTEM_OK)
      return Dvr2605Failed();

  register_value = INTERNAL_TRIGGER;    //exit calibration mode
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, MODE_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return Dvr2605Failed();

#ifdef ERM_MODE
  register_value = TS2200_LIBRARY_C;
#else
  register_value = LRA_LIBRARY;
#endif /* ERM_MODE */
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONFIG_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return Dvr2605Failed();

#ifdef ERM_MODE
  register_value = ERM_CLOSED_LOOP + SUPPLY_COMPENSATION_DISABLED;
#else
  register_value = LRA_DRIVE_MODE_ONCE_PER_CYCLE + SUPPLY_COMPENSATION_DISABLED;
#endif /* ERM_MODE */
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTROL3_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return Dvr2605Failed();

  if (Dvr2605Diagnostics() != eSYSTEM_OK)
    return Dvr2605Failed();

  DisableHapticDriver();    //debug

  return eSYSTEM_OK;
}

/**
  * @brief Disables DRV2605 and returns error value
  * @param  None
  * @retval eDRV2605_FAILED
  */
static enum SystemFaultsEnum Dvr2605Failed(void)
{
  DisableHapticDriver();
  return eDRV2605_FAILED;
}

/**
  * @brief Perform the DRV2605 calibration according to the haptic used (LRA / ERM)
  * @param  None
  * @retval eSYSTEM_OK or eDRV2605_FAILED
  */
static enum SystemFaultsEnum Dvr2605AutoCalibration(void)
{
  uint8_t register_value;
  uint32_t delay;

  register_value = AUTO_CALIBRATION;
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, MODE_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

#ifdef ERM_MODE
  register_value = ERM_MODE + FEEDBACK_BRAKE_FACTOR_X3 + LOOP_GAIN_MEDIUM + ERM_X_1_8;
#else
  register_value = LRA_MODE + FEEDBACK_BRAKE_FACTOR_X3 + LOOP_GAIN_MEDIUM + LRA_X_20;
#endif /* ERM_MODE */
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, FEEDBACK_CONTROL_REG, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

#ifdef ERM_MODE
  register_value = 140;   //Calculated using rated volatge = 3V, 21.33 x 10^-3 x 140 = 2.98V
#else
  register_value = 83;  //Calculated using 300usec sample time, LRA 2V RMS rating, 175Hz
//  register_value = 70;  //Calculated using 300usec sample time, LRA 1.8V RMS rating, 240Hz
#endif /* ERM_MODE */
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, RATED_VOLTAGE, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

#ifdef ERM_MODE
  register_value = 136;   //Calculated using rated volatge = 3V, 21.96 x 10^-3 x 136 = 2.98V
#else
  register_value = 132;   //Calculated using max RMS (2.05V) * Sqrt(2)
//    register_value = 122;  //Calculated using max RMS (1.9V) * Sqrt(2)
#endif /* ERM_MODE */
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, OVERDRIVE_CLAMP_VOLTAGE, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

  register_value = AUTO_CAL_TIME_1000MS;
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTROL4_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

#ifdef ERM_MODE
  register_value = STARTUP_BOOST + 23;
#else
  register_value = STARTUP_BOOST + 23;    //Drive time - Calculated for 175Hz (~23.57)
//    register_value = STARTUP_BOOST + 16;    //Drive time - Calculated for 240Hz (~15.8)
#endif /* ERM_MODE */
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTRL1_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

#ifdef ERM_MODE
  register_value = BRAKE_STABILIZER + BLANKING_TIME_1 + CURRENT_DISSIPATION_TIME_1 + BIDIRECTIONAL_INPUT_MODE;
#else
  register_value = BRAKE_STABILIZER + SAMPLE_TIME_300US + BLANKING_TIME_1 + CURRENT_DISSIPATION_TIME_1 + BIDIRECTIONAL_INPUT_MODE;
#endif /* ERM_MODE */
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTROL2_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

  register_value = GO_BIT;
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

  delay = tick_counter;
  while (Drv2605IsBusy())
  {
    if ((tick_counter - delay) > eTICK_850MSEC)
      return eDRV2605_FAILED;
  }

 	if (I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, STATUS_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
 	  return eDRV2605_FAILED;

  if (register_value & AUTO_CALIBRATION_FAILED)
    return eDRV2605_FAILED;

  return eSYSTEM_OK;
}

/**
  * @brief Perform the DRV2605 diagnostics to detect ERM or LRA fault
  * @param  None
  * @retval eSYSTEM_OK or eDRV2605_FAILED
  * @note Execute after calibration and type of actuator is set
  */
static enum SystemFaultsEnum Dvr2605Diagnostics(void)
{
  uint8_t register_value;
  uint32_t delay;
  uint32_t elapsed;

  register_value = DIAGNOSTICS_MODE;
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, MODE_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

  delay = tick_counter;
  register_value = GO_BIT;
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

  do
  {
  	if (I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
  	  return eDRV2605_FAILED;

    elapsed = tick_counter - delay;
  } while((register_value & GO_BIT) && (elapsed < eTICK_200MSEC));

  if (elapsed >= eTICK_200MSEC)
    return eDRV2605_FAILED;

  I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, STATUS_REGISTER, I2C_MEMADD_SIZE_8BIT, 1);
  if (register_value & ACTUATOR_FAULT)
    return eDRV2605_FAILED;

  return eSYSTEM_OK;
}

/**
  * @brief Causes vibration using specific waveform
  * @note
  * @param  waveform_index: waveform to use, value of type WaveformEffectEnum
  * @retval eSYSTEM_OK or eDRV2605_FAILED
  */
#pragma diag_suppress=Pe177 //Suppressing function was declared but never referenced warning
static enum SystemFaultsEnum Dvr2605Vibrate(enum WaveformEffectEnum waveform_index)
{
  uint8_t register_value;

//  register_value = INTERNAL_TRIGGER;    //exit standby
//  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, MODE_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
//    return Dvr2605Failed();

  register_value = (uint8_t)waveform_index;
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, WAVEFORM_SEQ_1, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

  register_value = GO_BIT;
  if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
    return eDRV2605_FAILED;

  return eSYSTEM_OK;
}
#pragma diag_default=Pe177

/**
  * @brief Checks if there's ongoing operation of the DRV2605
  * @param none
  * @retval 1 - DRV2605 is busy, 0 - DRV2605 is ready
  */
#pragma optimize=low
static uint8_t Drv2605IsBusy(void)
{
  uint8_t register_value = 0;

  I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1);

  if (register_value & GO_BIT)
    return 1;
  else
    return 0;
}

/**
  * @brief Handles all haptic indication handling
  * @param haptic: pointer to a struct of type HapticFeedbackParametersStruct
  * @retval None
  */
void HapticFeedbackTask(volatile struct HapticFeedbackParametersStruct *haptic)
{
  if (haptic->enable_vibration)
  {
    /* We enter here if there is a request for haptic feedback from the application or feedback is in effect */
    if (!haptic->busy)
    {
      /* feedback request (not in effect yet) */
      if (haptic->waveform != eNO_WAVEFORM)
      {
        EnableHapticDriver();
        haptic->busy = 1;
        Dvr2605Vibrate(haptic->waveform);
      }

      /* This must be atomic operation so if haptic is enabled in interrupt it will not be disabled here */
      __disable_interrupt();
      haptic->waveform = eNO_WAVEFORM;
      haptic->enable_vibration = 0;
      __enable_interrupt();
    }
  }

  /* Complete current vibration feedback*/
  if (haptic->busy)
  {
    /* feedback is in effect */
    if (!Drv2605IsBusy())
    {
//      DisableHapticDriver();
      haptic->busy = 0;
      haptic->timeout_for_tap_detection_in_10ms = 10;
    }

  }
  else if (haptic->timeout_for_tap_detection_in_10ms)
    /* haptic feedback triggers the double tap, here is a timeout allowing the reverberations to settle before
       allowing double tap detection */
    haptic->timeout_for_tap_detection_in_10ms--;
}








  • Hi Shlomi,

    It will take me some time to review the code. It sounds like the device may be in software standby mode if there is no waveform being played. Can you readback register 0x01 to check this?
  • Hi Kelly,


    I set the mode register according to desired state (calibration, or normal operation [go triggered by software]). It is very clear reading the code. 

    In any case I will read the register to verify the settings received correctly and will report back.

    Thanks,

    Shlomi

     

  • Hi Kelly,

    I attached the registers values.

    I see the OC_DETECT, but there is no short on the OUT pins.

    I attached as well the ERM datasheet.

    Best Regards,

    Shlomi

    Z4KH2B0470652.pdf

    DRV2605.docx

  • Shlomi,

    According to register 0x1D or 0d29 = 0xA0, the device is set in ERM open-loop mode. We have a setup guide and also an excel table on the DRV2605 product page that can help with the register settings.
    That ERM should be compatible with our device.
  • Hi Kelly,

    Yes, register 0x1D is set (to ERM closed loop) only after the calibration procedure, as per paragraph 8.3.1 in the datasheet (initialization procedure)

     

    And by the way, it says the default is closed loop, but it is open loop, I don't change the register before the calibration and it is read as open loop after power up.

     

    In any case it didn't work, same problem persists.

     

    I tried using the excel, also got to the same results.

     

    I tried using the same initialization as in the firmware code of Haptic Feedback with Bluetooth® Low Energy and iOS App Reference Design - same results.

     

    I tried the initialization according to DRV2605 Setup Guide [SLOA189] paragraph 1.6.1, without performing the calibration, I tried executing waveform #1, the GO register stayed 1, status register was 0x61 (same results as before).

    I tried adding to the above the calibration routine (twice, once using open loop and once using closed loop), as per paragraph 2.2.1 of  DRV2605 Setup Guide and I get the same results.

     

    Best Regards,
    Shlomi

  • I found the problem, I swapped between the VDD and OUT- pins by mistake.
  • Hi Kelly,

    I fixed the pinout issue.

    Now occasionally all is well, but almost every time the calibration (or diagnostics) fail. what can be the reason?

    My code and ERM datasheet attached.

    Best Regards,

    Shlomi

    4135.drv2605.h

    0741.drv2605.c
    /**
      ******************************************************************************
      * @file   : DRV2605.c
      * @author : Igal Ofri
      * @brief  : This file provides code for the configuration
      *           and APIs of DRV2605.
      ******************************************************************************
      *
      * Redistribution and use in source and binary forms, with or without
      * modification, are not permitted.
      *
      ******************************************************************************
      */
    
    /* Includes ------------------------------------------------------------------*/
    #include "drv2605.h"
    
    #include "app_functions.h"
    #include "gpio.h"
    #include "i2c.h"
    
    /* Defines ------------------------------------------------------------------*/
    #define DRV2605_I2C_ADDRESS    0xB4
    
    #define STATUS_REGISTER         0x00
    //Status register bits
    #define OVERCURRENT_DETECTED          0x01
    #define OVERTEMPERATUE_DETECTED       0x02
    #define FEEDBACK_CONTROLLER_TIMED_OUT 0x04  /* This indicates when the ERM
                                                   back-EMF has been zero for more than ~10 ms in ERM mode, and
                                                   indicates when the LRA frequency tracking has lost frequency lock in LRA
                                                   mode. This bit is for debug purposes only, and can sometimes be set
                                                   under normal operation when extensive braking periods are used. This bit
                                                   will clear upon read.*/
    #define AUTO_CALIBRATION_FAILED       0x08  /* This flag stores the result of the auto-calibration routine and the */
    #define ACTUATOR_FAULT                0x08  /* diagnostic routine. The flag contains the result for whichever routine was
                                                   executed last. The flag clears upon read. Test result is not valid until the GO
                                                   bit selfclears at the end of the routine. */
    #define DEVICE_ID_MASK                0xE0
    #define DRV2604                       0x80  //contains RAM, does not contain licensed ROM library
    #define DRV2605                       0x60  //contains licensed ROM library, does not contain RAM
    #define DRV2604L                      0xC0  //low-voltage version of the DRV2604 device
    #define DRV2605L                      0xE0  //low-voltage version of the DRV2605 device
    
    #define MODE_REGISTER           0x01
    //Mode register bits
    #define INTERNAL_TRIGGER              0x00
    #define EXTERNAL_TRIGGER_EDGE_MODE    0x01
    #define EXTERNAL_TRIGGER_LEVEL_MODE   0x02
    #define PWM_ANALO_INPUT               0x03
    #define AUDIO_TO_VIBE_MODE            0x04
    #define RTP_MODE                      0x05  //Real-time playback
    #define DIAGNOSTICS_MODE              0x06
    #define AUTO_CALIBRATION              0x07
    
    #define STANDBY_MODE                  0x40
    #define DEVICE_RESET                  0x80  /* Setting this bit performs the equivalent operation of power
                                                   cycling the device. Any playback operations are immediately interrupted,
                                                   and all registers are reset to the default values. The DEV_RESET bit selfclears
                                                   after the reset operation is complete. */
    
    /* This register is the entry point for real-time playback (RTP) data. The DRV2605
        playback engine drives the RT_PLAYBACK_INPUT[7:0] value to the load when
        MODE[2:0] = 5 (RTP mode). The RT_PLAYBACK_INPUT[7:0] value can be updated in
        real-time by the host controller to create haptic waveforms. The
        RT_PLAYBACK_INPUT[7:0] value is interpreted as signed by default, but can be set to
        unsigned by the DATA_FORMAT_RTP bit in register 0x1D. When the
        haptic waveform is complete, the user can idle the device by setting
        MODE[2:0] = 0, or alternatively by setting STANDBY = 1. */
    #define RT_PLAYBACK_INPUT_REG   0x02
    
    #define CONFIG_REGISTER         0x03
    //Configuration register bits
    #define NO_LIBRARY                    0x00
    #define TS2200_LIBRARY_A              0x01
    #define TS2200_LIBRARY_B              0x02
    #define TS2200_LIBRARY_C              0x03
    #define TS2200_LIBRARY_D              0x04
    #define TS2200_LIBRARY_E              0x05
    #define LRA_LIBRARY                   0x06
    
    #define OUTPUT_DRIVE_IN_HI_Z          0x10  /* This bit sets the output driver into a true high-impedance state. The device
                                                    must be enabled to go into the high-impedance state. When in hardware
                                                    shutdown or standby mode, the output drivers have 15 k� to ground. When
                                                    the HI_Z bit is asserted, the hi-Z functionality takes effect immediately, even
                                                    if a transaction is taking place. */
    
    #define WAVEFORM_SEQ_1          0x04
    #define WAVEFORM_SEQ_2          0x05
    #define WAVEFORM_SEQ_3          0x06
    #define WAVEFORM_SEQ_4          0x07
    #define WAVEFORM_SEQ_5          0x08
    #define WAVEFORM_SEQ_6          0x09
    #define WAVEFORM_SEQ_7          0x0A
    #define WAVEFORM_SEQ_8          0x0B
    //Waveform sequencer bits
    #define WAVEFORM_SEQ_VAL_MASK         0x7F
    #define WAVEFORM_WAIT                 0x80  /* When this bit is set, the WAV_FRM_SEQ[6:0] bit is interpreted as a wait
                                                    time in which the playback engine idles. This bit is used to insert timed
                                                    delays between sequentially played waveforms.
                                                    Delay time = 10 ms � WAV_FRM_SEQ[6:0]
                                                    If WAIT = 0, then WAV_FRM_SEQ[6:0] is interpreted as a waveform
                                                    identifier for sequence playback. */
    
    #define GO_REGISTER             0x0C
    #define GO_BIT                        0x01  /* This bit is used to fire processes in the DRV2605 device. The process
                                                    fired by the GO bit is selected by the MODE[2:0] bit (register 0x01). The
                                                    primary function of this bit is to fire playback of the waveform identifiers in
                                                    the waveform sequencer (registers 0x04 to 0x0B), in which case, this bit
                                                    can be thought of a software trigger for haptic waveforms. The GO bit
                                                    remains high until the playback of the haptic waveform sequence is
                                                    complete. Clearing the GO bit during waveform playback cancels the
                                                    waveform sequence. Using one of the external trigger modes can cause
                                                    the GO bit to be set or cleared by the external trigger pin. This bit can also
                                                    be used to fire the auto-calibration process or the diagnostic process. */
    
    /* This register adds a time offset to the overdrive portion of the library
        waveforms. Some motors require more overdrive time than others,
        therefore this register allows the user to add or remove overdrive time
        from the library waveforms. The maximum voltage value in the library
        waveform is automatically determined to be the overdrive portion. This
        register is only useful in open-loop mode. Overdrive is automatic for
        closed-loop mode. The offset is interpreted as 2s complement, therefore
        the time offset can be positive or negative.
        Overdrive Time Offset (ms) = ODT[7:0] � PLAYBACK_INTERVAL */
    #define OVERDRIVE_TIME_OFFSET   0x0D
    
    /* This register adds a time offset to the positive sustain portion of the library
        waveforms. Some motors have a faster or slower response time than
        others, therefore this register allows the user to add or remove positive
        sustain time from the library waveforms. Any positive voltage value other
        than the overdrive portion is considered as a sustain positive value. The
        offset is interpreted as 2s complement, therefore the time offset can positive
        or negative.
        Sustain-Time Positive Offset (ms) = SPT[7:0] � PLAYBACK_INTERVAL */
    #define SUSTAIN_TIME_OFFSET_POS 0x0E
    
    /* This register adds a time offset to the negative sustain portion of the library
        waveforms. Some motors have a faster or slower response time than
        others, therefore this register allows the user to add or remove negative
        sustain time from the library waveforms. Any negative voltage value other
        than the overdrive portion is considered as a sustaining negative value. The
        offset is interpreted as two�s complement, therefore the time offset can be
        positive or negative.
        Sustain-Time Negative Offset (ms) = SNT[7:0] � PLAYBACK_INTERVAL */
    #define SUSTAIN_TIME_OFFSET_NEG 0x0F
    
    /* This register adds a time offset to the braking portion of the library waveforms.
        Some motors require more braking time than others, therefore this register
        allows the user to add or take away brake time from the library waveforms.
        The most negative voltage value in the library waveform is automatically
        determined to be the braking portion. This register is only useful in open-loop
        mode. Braking is automatic for closed-loop mode. The offset is interpreted as
        2s complement, therefore the time offset can be positive or negative.
        Brake Time Offset (ms) = BRT[7:0] � PLAYBACK_INTERVAL */
    #define BRAKE_TIME_OFFSET       0x10
    
    #define AUDIO_TO_VIBE_CONTROL   0x11
    //Audio to vibe control bits
    #define LPF_100HZ                     0x00
    #define LPF_125HZ                     0x01
    #define LPF_150HZ                     0x02
    #define LPF_200HZ                     0x03
    
    #define PEAK_DETECTION_10MS           0x00
    #define PEAK_DETECTION_20MS           0x04
    #define PEAK_DETECTION_30MS           0x08
    #define PEAK_DETECTION_40MS           0x0C
    
    /* This register sets the minimum voltage level at the IN/TRIG pin that is detected by
        the audio-to-vibe engine. Levels below this are ignored.
        ATH_MIN_INPUT Voltage (VPP) = ATH_MIN_INPUT[7:0] � 1.8 V / 255 */
    #define AUDIO_TO_VIBE_MIN_LEVEL 0x12
    
    /* This register sets the full-scale voltage level at the IN/TRIG pin for audio-to-vibe mode.
        ATH_MAX_INPUT Voltage (VPP) = ATH_MAX_INPUT[7:0] � 1.8 V / 255 */
    #define AUDIO_TO_VIBE_MAX_LEVEL 0x13
    
    /* This register sets the minimum output level that is applied to the actuator drive engine.
      ATH_MIN_DRIVE (%) = ATH_MIN_DRIVE[7:0] / 255 � 100% */
    #define AUDIO_TO_VIBE_MIN_OUT   0x14
    
    /* This register sets the maximum output level that is applied to the actuator drive engine.
        ATH_MAX_DRIVE (%) = ATH_MAX_DRIVE[7:0] / 255 � 100% */
    #define AUDIO_TO_VIBE_MAX_OUT   0x15
    
    /* This register sets the reference voltage for full-scale output during closed-loop
        operation. The auto-calibration routine uses this register as an input, therefore
        this register must be written with the rated voltage value of the motor before
        calibration is performed. This register is ignored for open-loop operation
        because the overdrive voltage sets the reference for that case. Any
        modification of this register value should be followed by calibration to set
        A_CAL_BEMF appropriately. */
    #define RATED_VOLTAGE           0x16
    
    /* During closed-loop operation the actuator feedback allows the output voltage
        to go above the rated voltage during the automatic overdrive and automatic
        braking periods. This register sets a clamp so that the automatic overdrive is
        bounded. This bit also serves as the full-scale reference voltage for open-loop
        operation. */
    #define OVERDRIVE_CLAMP_VOLTAGE 0x17
    
    /* This register contains the voltage-compensation result after execution of auto
        calibration. The value stored in the A_CAL_COMP bit compensates for any
        resistive losses in the driver. The calibration routine checks the impedance of
        the actuator to automatically determine an appropriate value. The autocalibration
        compensation-result value is multiplied by the drive gain during playback.
        Auto-calibration compensation coefficient = 1 + A_CAL_COMP[7:0] / 255 */
    #define AUTO_CALIB_COMPENSATION 0x18
    
    /* This register contains the rated back-EMF result after execution of auto
       calibration. The A_CAL_BEMF[7:0] bit is the level of back-EMF voltage that the
       actuator gives when the actuator is driven at the rated voltage. The DRV2605
       playback engine uses this the value stored in this bit to automatically determine
       the appropriate feedback gain for closed-loop operation.
       Auto-calibration back-EMF (V) = (A_CAL_BEMF[7:0] / 255) � 1.22 V /
       BEMF_GAIN[1:0] */
    #define AUTO_CALIB_BACK_EMF     0x19
    
    /* This register sets the analog gain of the back-EMF amplifier. This value is interpreted
        differently between ERM mode and LRA mode. Auto calibration automatically
        populates the BEMF_GAIN bit with the most appropriate value for the actuator. */
    #define FEEDBACK_CONTROL_REG    0x1A
    //Feedback control bits
    #define ERM_X_0_33                    0x00
    #define ERM_X_1_0                     0x01
    #define ERM_X_1_8                     0x02
    #define ERM_X_4_0                     0x03
    #define LRA_X_5                       0x00
    #define LRA_X_10                      0x01
    #define LRA_X_20                      0x02
    #define LRA_X_30                      0x03
    
    #define LOOP_GAIN_LOW                 0x00    /* Loop gain bits selects a loop gain for the feedback control. The LOOP_GAIN[1:0] bit */
    #define LOOP_GAIN_MEDIUM              0x04    /* sets how fast the loop attempts to make the back-EMF (and thus motor velocity) */
    #define LOOP_GAIN_HIGH                0x08    /* match the input signal level. Higher loop-gain (faster settling) options provide */
    #define LOOP_GAIN_VERY_HIGH           0x0C    /* less-stable operation than lower loop gain (slower settling). This value should be set  */
                                                  /* prior to running auto calibration.*/
    
    #define FEEDBACK_BRAKE_FACTOR_X1      0x00    /* Feedback brake factor bits selects the feedback gain ratio between braking gain and */
    #define FEEDBACK_BRAKE_FACTOR_X2      0x10    /* driving gain. In general, adding additional feedback gain while braking is desirable so */
    #define FEEDBACK_BRAKE_FACTOR_X3      0x20    /* that the actuator brakes as quickly as possible. Large ratios provide less-stable */
    #define FEEDBACK_BRAKE_FACTOR_X4      0x30    /* operation than lower ones. This value should be set prior to running auto calibration. */
    #define FEEDBACK_BRAKE_FACTOR_X6      0x40
    #define FEEDBACK_BRAKE_FACTOR_X8      0x50
    #define FEEDBACK_BRAKE_FACTOR_X16     0x60
    #define FEEDBACK_BRAKE_DISABLED       0x70
    
    #define ERM_MODE                      0x00    /* Mode selection - this bit should be set prior to running auto calibration. */
    #define LRA_MODE                      0x80
    
    #define CONTRL1_REGISTER        0x1B
    //Control 1 bits
    #define DRIVE_TIME_MASK               0x1F  /* LRA Mode: Sets initial guess for LRA drive-time in LRA mode. Drive time is
                                                    automatically adjusted for optimum drive in real time; however, this register
                                                    should be optimized for the approximate LRA frequency. If the bit is set too low,
                                                    it can affect the actuator startup time. If it is set too high, it can cause instability.
                                                    Optimum drive time (ms) . 0.5 x LRA Period
                                                    Drive time (ms) = DRIVE_TIME[4:0] x 0.1 ms + 0.5 ms
                                                   ERM Mode: Sets the sample rate for the back-EMF detection. Lower drive times
                                                    cause higher peak-to-average ratios in the output signal, requiring more supply
                                                    headroom. Higher drive times cause the feedback to react at a slower rate.
                                                    Drive Time (ms) = DRIVE_TIME[4:0] x 0.2 ms + 1 ms */
    
    #define COMMON_MODE_DRIVE_EN          0x20  /* This register applies a 0.9-V common mode voltage to the IN/TRIG pin when an AC coupling
                                                    capacitor is used. This bit is only useful for analog input mode. This bit
                                                    should not be asserted for PWM mode or external trigger mode. */
    
    #define STARTUP_BOOST                 0x80  /* This registe applies higher loop gain during overdrive to enhance actuator transient response. */
    
    #define CONTROL2_REGISTER       0x1C
    //Control 2 register bits
    #define CURRENT_DISSIPATION_TIME_MASK 0x03  /* This bit is the time allowed for the current to dissipate */
    #define CURRENT_DISSIPATION_TIME_0    0x00  /* from the actuator between PWM cycles for flyback mitigation.*/
    #define CURRENT_DISSIPATION_TIME_1    0x01
    #define CURRENT_DISSIPATION_TIME_2    0x02
    #define CURRENT_DISSIPATION_TIME_3    0x03
    
    #define BLANKING_TIME_MASK            0x0C  /* Blanking time before the back-EMF AD makes a conversion. */
    #define BLANKING_TIME_0               0x00
    #define BLANKING_TIME_1               0x04
    #define BLANKING_TIME_2               0x06
    #define BLANKING_TIME_3               0x0C
    
    #define SAMPLE_TIME_150US             0x00  /* LRA auto-resonance sampling time */
    #define SAMPLE_TIME_200US             0x10
    #define SAMPLE_TIME_250US             0x20
    #define SAMPLE_TIME_300US             0x30
    
    #define BRAKE_STABILIZER              0x40  /* When this bit is set, loop gain is reduced when braking is almost complete to
                                                    improve loop stability */
    #define UNIDIRECTIONAL_INPUT_MODE     0x00
    #define BIDIRECTIONAL_INPUT_MODE      0x80
    
    #define CONTROL3_REGISTER       0x1D
    //Control 3 register bits
    #define AUTO_RESONANCE_MODE           0x00
    #define LRA_OPEN_LOOP_MODE            0x01
    
    #define PWM_INPUT                     0x00
    #define ANALOG_INPUT                  0x02
    
    #define LRA_DRIVE_MODE_ONCE_PER_CYCLE 0x00
    #define LRA_DRIVE_MODE_TWICE_PERCYCLE 0x04
    
    #define RTP_FORMAT_SIGNED             0x00
    #define RTP_FORMAT_UNSIGNED           0x08
    
    #define SUPPLY_COMPENSATION_ENABLED   0x00
    #define SUPPLY_COMPENSATION_DISABLED  0x10
    
    #define ERM_CLOSED_LOOP               0x00
    #define ERM_OPEN_LOOP                 0x20
    
    #define PWM_NOISE_GATE_THRESHOLD_DIS  0x00
    #define PWM_NOISE_GATE_THRESHOLD_2PCT 0x40
    #define PWM_NOISE_GATE_THRESHOLD_4PCT 0x80
    #define PWM_NOISE_GATE_THRESHOLD_8PCT 0xC0
    
    #define CONTROL4_REGISTER       0x1E
    //Control 4 register bits
    #define OTP_PROGRAM                   0x01  /* This bit launches the programming process for one-time programmable (OTP)
                                                    memory which programs the contents of register 0x16 through 0x1A into
                                                    nonvolatile memory. This process can only be executed one time per device. */
    #define OTP_PROGRAMMED                0x04
    
    #define AUTO_CAL_TIME_150MS           0x00  /* These bits sets the length of the auto calibration time. The AUTO_CAL_TIME[1:0] */
    #define AUTO_CAL_TIME_250MS           0x20  /*  bit should be enough time for the motor acceleration to settle when driven */
    #define AUTO_CAL_TIME_500MS           0x40  /*  at the RATED_VOLTAGE[7:0] value. */
    #define AUTO_CAL_TIME_1000MS          0x60
    
    /* This register provides a real-time reading of the supply voltage at the VDD pin. The
        device must be actively sending a waveform to take a reading.
        VDD (V) = VBAT[7:0] � 5.6V / 255 */
    #define VBAT_VOLTAGE_REGISTER   0x21
    
    /* This bit reports the measurement of the LRA resonance period. The device must
        be actively sending a waveform to take a reading.
        LRA period (us) = LRA_Period[7:0] �~ 98.46 us */
    #define LRA_RESONANCE_PERIOD_REG 0x22
    
    /* Type Defnition ------------------------------------------------------------------*/
    
    /* Global Variables ------------------------------------------------------------------*/
    volatile struct HapticFeedbackParametersStruct haptic_feedbak_parameters;
    
    /* Private Variables ------------------------------------------------------------------*/
    /* Prototypes ------------------------------------------------------------------*/
    static enum SystemFaultsEnum Dvr2605AutoCalibration(void);
    static enum SystemFaultsEnum Dvr2605Failed(void);
    static enum SystemFaultsEnum Dvr2605Vibrate(enum WaveformEffectEnum waveform_index);
    static enum SystemFaultsEnum Dvr2605Diagnostics(void);
    static uint8_t Drv2605IsBusy(void);
    
    
    /**
      * @brief Initialization of DRV2605
      * @param  None
      * @retval eSYSTEM_OK or eDRV2605_FAILED
      */
    enum SystemFaultsEnum Dvr2605Init(void)
    {
    #if (DISABLE_HAPTIC > 0)
      return eSYSTEM_OK;
    #else
      uint8_t register_value;
    
      EnableHapticDriver();
      WaitHere(eDELAY250USEC, SystemCoreClock);
    
      I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, STATUS_REGISTER, I2C_MEMADD_SIZE_8BIT, 1);
      if ((register_value & DEVICE_ID_MASK) != DRV2605)
        return Dvr2605Failed();
    
      register_value = INTERNAL_TRIGGER;    //exit standby
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, MODE_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return Dvr2605Failed();
    
    #ifdef ERM_MODE
      register_value = ERM_MODE + ERM_X_1_8 + LOOP_GAIN_MEDIUM + FEEDBACK_BRAKE_FACTOR_X4;
    #else
      register_value = LRA_MODE + LRA_X_20 + LOOP_GAIN_MEDIUM + FEEDBACK_BRAKE_FACTOR_X4;
    #endif /* ERM_MODE */
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, FEEDBACK_CONTROL_REG, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return Dvr2605Failed();
    
    #ifdef ERM_MODE
        register_value = TS2200_LIBRARY_C;
    #else
        register_value = LRA_LIBRARY;
    #endif /* ERM_MODE */
        if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONFIG_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
          return Dvr2605Failed();
    
    #ifdef ERM_MODE
        register_value = PWM_NOISE_GATE_THRESHOLD_4PCT + ERM_CLOSED_LOOP + SUPPLY_COMPENSATION_DISABLED;
    #else
        register_value = PWM_NOISE_GATE_THRESHOLD_4PCT + LRA_DRIVE_MODE_ONCE_PER_CYCLE + SUPPLY_COMPENSATION_DISABLED;
    #endif /* ERM_MODE */
        if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTROL3_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
          return Dvr2605Failed();
    
      I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTROL4_REGISTER, I2C_MEMADD_SIZE_8BIT, 1);
      if (!(register_value & OTP_PROGRAMMED))
        if (Dvr2605AutoCalibration() != eSYSTEM_OK)
          return Dvr2605Failed();
    
      register_value = INTERNAL_TRIGGER;    //exit calibration mode
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, MODE_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return Dvr2605Failed();
    
    #ifdef ERM_MODE
      register_value = TS2200_LIBRARY_C;
    #else
      register_value = LRA_LIBRARY;
    #endif /* ERM_MODE */
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONFIG_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return Dvr2605Failed();
    
    #ifdef ERM_MODE
      register_value = PWM_NOISE_GATE_THRESHOLD_4PCT + ERM_CLOSED_LOOP + SUPPLY_COMPENSATION_DISABLED;
    #else
      register_value = PWM_NOISE_GATE_THRESHOLD_4PCT + LRA_DRIVE_MODE_ONCE_PER_CYCLE + SUPPLY_COMPENSATION_DISABLED;
    #endif /* ERM_MODE */
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTROL3_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return Dvr2605Failed();
    
      if (Dvr2605Diagnostics() != eSYSTEM_OK)
        return Dvr2605Failed();
    
      DisableHapticDriver();
    
      return eSYSTEM_OK;
    
    #endif /* DISABLE_HAPTIC */
    }
    
    /**
      * @brief Disables DRV2605 and returns error value
      * @param  None
      * @retval eDRV2605_FAILED
      */
    static enum SystemFaultsEnum Dvr2605Failed(void)
    {
      DisableHapticDriver();
      return eDRV2605_FAILED;
    }
    
    /**
      * @brief Perform the DRV2605 calibration according to the haptic used (LRA / ERM)
      * @param  None
      * @retval eSYSTEM_OK or eDRV2605_FAILED
      */
    #pragma diag_suppress=Pe177 //Suppressing function was declared but never referenced warning
    static enum SystemFaultsEnum Dvr2605AutoCalibration(void)
    {
      uint8_t register_value;
      uint32_t delay;
    
      static volatile uint8_t deb_reg = 0;
    
      register_value = AUTO_CALIBRATION;
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, MODE_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
    #ifdef ERM_MODE
      register_value = ERM_MODE + FEEDBACK_BRAKE_FACTOR_X4 + LOOP_GAIN_MEDIUM + ERM_X_1_8;
    #else
      register_value = LRA_MODE + FEEDBACK_BRAKE_FACTOR_X4 + LOOP_GAIN_MEDIUM + LRA_X_20;
    #endif /* ERM_MODE */
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, FEEDBACK_CONTROL_REG, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
    #ifdef ERM_MODE
      register_value = 140;   //Calculated using rated volatge = 3V, 21.33 x 10^-3 x 140 = 2.98V
    #else
      register_value = 83;  //Calculated using 300usec sample time, LRA 2V RMS rating, 175Hz
    //  register_value = 70;  //Calculated using 300usec sample time, LRA 1.8V RMS rating, 240Hz
    #endif /* ERM_MODE */
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, RATED_VOLTAGE, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
    #ifdef ERM_MODE
      register_value = 136;   //Calculated using rated volatge = 3V, 21.96 x 10^-3 x 136 = 2.98V
    #else
      register_value = 132;   //Calculated using max RMS (2.05V) * Sqrt(2)
    //    register_value = 122;  //Calculated using max RMS (1.9V) * Sqrt(2)
    #endif /* ERM_MODE */
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, OVERDRIVE_CLAMP_VOLTAGE, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
      register_value = AUTO_CAL_TIME_500MS;
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTROL4_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
    #ifdef ERM_MODE
      register_value = STARTUP_BOOST + 23;
    #else
      register_value = STARTUP_BOOST + 23;    //Drive time - Calculated for 175Hz (~23.57)
    //    register_value = STARTUP_BOOST + 16;    //Drive time - Calculated for 240Hz (~15.8)
    #endif /* ERM_MODE */
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTRL1_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
    #ifdef ERM_MODE
      register_value = BRAKE_STABILIZER + SAMPLE_TIME_300US + BLANKING_TIME_1 + CURRENT_DISSIPATION_TIME_1 + BIDIRECTIONAL_INPUT_MODE;
    #else
      register_value = BRAKE_STABILIZER + SAMPLE_TIME_300US + BLANKING_TIME_1 + CURRENT_DISSIPATION_TIME_1 + BIDIRECTIONAL_INPUT_MODE;
    #endif /* ERM_MODE */
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, CONTROL2_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
      register_value = GO_BIT;
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
      delay = tick_counter;
      while (Drv2605IsBusy())
      {
        if ((tick_counter - delay) > eTICK_850MSEC)
        {
          I2cBufferRead(HAPTIC_I2C, (uint8_t *)&deb_reg, DRV2605_I2C_ADDRESS, STATUS_REGISTER, I2C_MEMADD_SIZE_8BIT, 1);   //debug
          return eDRV2605_FAILED;
        }
      }
      
     	if (I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, STATUS_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
     	  return eDRV2605_FAILED;
    
      if (register_value & AUTO_CALIBRATION_FAILED)
        return eDRV2605_FAILED;
    
      return eSYSTEM_OK;
    }
    #pragma diag_default=Pe177
    
    /**
      * @brief Perform the DRV2605 diagnostics to detect ERM or LRA fault
      * @param  None
      * @retval eSYSTEM_OK or eDRV2605_FAILED
      * @note Execute after calibration and type of actuator is set
      */
    #pragma diag_suppress=Pe177 //Suppressing function was declared but never referenced warning
    #pragma optimize=medium
    static enum SystemFaultsEnum Dvr2605Diagnostics(void)
    {
      uint8_t register_value;
      uint32_t delay;
      uint32_t elapsed;
    
      register_value = DIAGNOSTICS_MODE;
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, MODE_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
      register_value = GO_BIT;
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
      delay = tick_counter;
      do
      {
      	if (I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
      	  return eDRV2605_FAILED;
    
        elapsed = tick_counter - delay;
      } while((register_value & GO_BIT) && (elapsed < eTICK_1SECOND));
    
      if (elapsed >= eTICK_1SECOND)
        return eDRV2605_FAILED;
    
      I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, STATUS_REGISTER, I2C_MEMADD_SIZE_8BIT, 1);
      if (register_value & ACTUATOR_FAULT)
        return eDRV2605_FAILED;
    
      return eSYSTEM_OK;
    }
    #pragma diag_default=Pe177
    
    /**
      * @brief Causes vibration using specific waveform
      * @note
      * @param  waveform_index: waveform to use, value of type WaveformEffectEnum
      * @retval eSYSTEM_OK or eDRV2605_FAILED
      */
    #pragma diag_suppress=Pe177 //Suppressing function was declared but never referenced warning
    static enum SystemFaultsEnum Dvr2605Vibrate(enum WaveformEffectEnum waveform_index)
    {
      uint8_t register_value;
    
      register_value = INTERNAL_TRIGGER;    //exit standby
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, MODE_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return Dvr2605Failed();
    
      register_value = (uint8_t)waveform_index;
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, WAVEFORM_SEQ_1, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
      register_value = GO_BIT;
      if (I2cBufferWrite(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK)
        return eDRV2605_FAILED;
    
      return eSYSTEM_OK;
    }
    #pragma diag_default=Pe177
    
    /**
      * @brief Checks if there's ongoing operation of the DRV2605
      * @param none
      * @retval 1 - DRV2605 is busy, 0 - DRV2605 is ready
      */
    #pragma optimize=low
    static uint8_t Drv2605IsBusy(void)
    {
      uint8_t register_value = 0;
    
      I2cBufferRead(HAPTIC_I2C, &register_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1);
    
      if (register_value & GO_BIT)
        return 1;
      else
        return 0;
    }
    
    /**
      * @brief Handles all haptic indication handling
      * @param haptic: pointer to a struct of type HapticFeedbackParametersStruct
      * @retval None
      */
    void HapticFeedbackTask(volatile struct HapticFeedbackParametersStruct *haptic)
    {
    #if (DISABLE_HAPTIC > 0)
      haptic->enable_vibration = 0;
      haptic->busy = 0;
    #else
      if (haptic->enable_vibration)
      {
        /* We enter here if there is a request for haptic feedback from the application or feedback is in effect */
        if (!haptic->busy)
        {
          /* feedback request (not in effect yet) */
          if (haptic->waveform != eNO_WAVEFORM)
          {
            EnableHapticDriver();
            haptic->busy = 1;
            Dvr2605Vibrate(haptic->waveform);
          }
    
          /* This must be atomic operation so if haptic is enabled in interrupt it will not be disabled here */
          __disable_interrupt();
    //      haptic->waveform = eNO_WAVEFORM;
          haptic->enable_vibration = 0;
          __enable_interrupt();
        }
      }
    
      /* Complete current vibration feedback*/
      if (haptic->busy)
      {
        /* feedback is in effect */
        if (!Drv2605IsBusy())
        {
    //      DisableHapticDriver();  //debug
          haptic->busy = 0;
          haptic->timeout_for_tap_detection_in_10ms = 10;
        }
    
      }
      else if (haptic->timeout_for_tap_detection_in_10ms)
        /* haptic feedback triggers the double tap, here is a timeout allowing the reverberations to settle before
           allowing double tap detection */
        haptic->timeout_for_tap_detection_in_10ms--;
    #endif /* DISABLE_HAPTIC */
    }
    
    
    
    
    
    
    
    
    

    Z4TH5B1241992.pdf

  • Hi Shlomi,

    The calibration can be tricky. There are a number of recent posts on why the calibration can fail. Can you reveiw these and let me know if any suggestions fix your problem?
  • Hi Shlomi,

    We haven't heard back from you. I am assuming that you were able to resolve your issue. If no, just reply with additional information or create a new post if this was locked due to time-out.

    Best Regards
    José Luis Figueroa
    Audio Applications Engineer
  • Hi Jose Luis,

    Sorry, I didn't update you, it is solved.

    Thanks,

    Shlomi