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
/** ****************************************************************************** * @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, ®ister_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, ®ister_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, ®ister_value, DRV2605_I2C_ADDRESS, FEEDBACK_CONTROL_REG, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK) return Dvr2605Failed(); I2cBufferRead(HAPTIC_I2C, ®ister_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, ®ister_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, ®ister_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, ®ister_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, ®ister_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, ®ister_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, ®ister_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, ®ister_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, ®ister_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, ®ister_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, ®ister_value, DRV2605_I2C_ADDRESS, CONTROL2_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK) return eDRV2605_FAILED; register_value = GO_BIT; if (I2cBufferWrite(HAPTIC_I2C, ®ister_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, ®ister_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, ®ister_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, ®ister_value, DRV2605_I2C_ADDRESS, GO_REGISTER, I2C_MEMADD_SIZE_8BIT, 1) != HAL_OK) return eDRV2605_FAILED; do { if (I2cBufferRead(HAPTIC_I2C, ®ister_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, ®ister_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, ®ister_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, ®ister_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, ®ister_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, ®ister_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--; }