31#include "../SensorBuildOpt.h"
32#if !SENSORLIB_EXCLUDE_HAPTIC_AW86224
46 _f0(0), _vbat(0), _lra(0),
51 _ramBaseAddr(0), _ramNum(0),
53 _cont_brk_time(0x06), _cont_brk_gain(0x08),
54 _cont_drv1_lvl(0x7F), _cont_drv1_time(0x04), _cont_drv2_time(0x14),
55 _cont_track_margin(0x0F),
57 _pwmcfg4_prtime(0x32), _pwmcfg3_prlvl(0x3F),
58 _auto_brk_enabled(false),
60 _duration(0), _vibrationStartTime(0),
127 uint8_t state = getGlobalState() & 0x0F;
128 return state != 0x00 && state != 0x07;
138 if (!_ramInit)
return false;
145 if (!_ramInit)
return false;
154 setTrimLRA(
static_cast<uint8_t
>(_f0_cali_data));
166 if (!_ramInit)
return;
174 if (_duration > 0 &&
hal->millis() - _vibrationStartTime >= _duration) {
179 if ((getGlobalState() & 0x0F) != 0x07)
run();
184 if (slot >= 8)
return false;
185 setWaveSeq(slot,
static_cast<uint8_t
>(effect));
191 for (uint8_t
i = 0;
i < 8;
i++) {
199 if (!_ramInit)
return false;
208 _isCalibrated =
true;
214 return !_isCalibrated || _f0 == 0;
219void HapticDriver_AW86224::cancelVibration()
224void HapticDriver_AW86224::ram_vbat_comp(
bool flag)
228 uint32_t vbat = _vbat < 3000 ? 3000 : _vbat;
229 int temp_gain =
static_cast<int>(_gain) * AW_VBAT_REFER / vbat;
230 if (temp_gain > 255) temp_gain = 255;
233 Serial.printf(
"[VBAT_COMP] vbat=%d, orig=0x%02X, comp=0x%02X\n", vbat, _gain, temp_gain);
236 setGain(
static_cast<uint8_t
>(temp_gain));
239void HapticDriver_AW86224::ramInit(
bool enable)
242 updateBits(REG_SYSCTRL1, MASK_EN_RAMINIT, MASK_EN_RAMINIT);
243 hal->delayMicroseconds(500);
249void HapticDriver_AW86224::playStop()
253 updateBits(REG_PLAYCFG3, MASK_PLAY_MODE, MASK_PLAY_MODE);
254 writeReg(REG_PLAYCFG4, PLAYCFG4_GO_ON);
261 if ((val & MASK_GLB_STATE) == STATE_STANDBY)
break;
265 if ((val & MASK_GLB_STATE) != STATE_STANDBY) {
266 updateBits(REG_SYSCTRL2, MASK_STANDBY, MASK_STANDBY);
272bool HapticDriver_AW86224::checkQualify()
274 return (
readReg(REG_CHIPID) & 0x80) == 0x80;
277bool HapticDriver_AW86224::offsetCalibration()
279 if (_d2s_gain == 0)
return false;
281 updateBits(REG_SYSCTRL7, MASK_D2S_GAIN, _d2s_gain & MASK_D2S_GAIN);
282 int d2s_gain = selectD2sGain(_d2s_gain & MASK_D2S_GAIN);
283 if (d2s_gain < 0)
return false;
287 updateBits(REG_DETCFG2, MASK_DIAG_GO, MASK_DIAG_GO);
291 reg_val[0] =
readReg(REG_DET_OS);
292 reg_val[1] =
readReg(REG_DET_LO);
295 int os_code = (reg_val[1] & 0xFC) >> 2;
296 os_code = (reg_val[0] << 2) | os_code;
297 os_code = os_formula(os_code, d2s_gain);
299 return (os_code <= 15 && os_code >= -15);
302int HapticDriver_AW86224::selectD2sGain(uint8_t reg)
317void HapticDriver_AW86224::setSramSize(SramSize size)
334void HapticDriver_AW86224::autoBrkConfig(
bool enable)
336 updateBits(REG_PLAYCFG3, MASK_BRK_EN, enable ? MASK_BRK_EN : 0);
339void HapticDriver_AW86224::setPwm(PwmMode mode)
348void HapticDriver_AW86224::playMode(PlayMode mode)
357 autoBrkConfig(
false);
377void HapticDriver_AW86224::config()
380 updateBits(REG_TRGCFG8, MASK_TRG1_MODE, 0x10);
381 updateBits(REG_ANACFG8, MASK_TRTF_CTRL_HDRV, MASK_TRTF_CTRL_HDRV);
383 if (_cont_brk_time)
writeReg(REG_CONTCFG10, _cont_brk_time);
384 else _cont_brk_time = 1;
386 if (_cont_brk_gain)
updateBits(REG_CONTCFG5, MASK_BRK_GAIN, _cont_brk_gain);
387 else _cont_brk_gain = 1;
390void HapticDriver_AW86224::protectConfig(uint8_t prtime, uint8_t prlvl)
394 writeReg(REG_PWMCFG3, MASK_PR_EN | (prlvl & ~MASK_PRLVL));
401void HapticDriver_AW86224::miscParaInit()
403 updateBits(REG_SYSCTRL7, MASK_GAIN_BYPASS, GAIN_BYPASS_CHANGEABLE);
404 _cont_drv2_lvl = drv2_lvl_formula(_f0_pre, _lra_vrms);
405 if (_cont_drv2_lvl > 127) _cont_drv2_lvl = 127;
408 protectConfig(_pwmcfg4_prtime, _pwmcfg3_prlvl);
411void HapticDriver_AW86224::trigInit()
413 updateBits(REG_TRGCFG8, MASK_TRG1_MODE, 0x10);
422bool HapticDriver_AW86224::measureF0()
424 uint8_t val[2] = {0};
425 uint8_t brk_en_temp = 0;
428 bool success =
false;
431 updateBits(REG_SYSCTRL7, MASK_D2S_GAIN, _d2s_gain & MASK_D2S_GAIN);
436 updateBits(REG_CONTCFG1, MASK_EN_F0_DET, MASK_EN_F0_DET);
437 updateBits(REG_CONTCFG6, MASK_TRACK_EN, MASK_TRACK_EN);
439 brk_en_temp =
readReg(REG_PLAYCFG3) & MASK_BRK_EN;
440 updateBits(REG_CONTCFG6, MASK_DRV1_LVL, _cont_drv1_lvl);
441 writeReg(REG_CONTCFG7, _cont_drv2_lvl);
442 writeReg(REG_CONTCFG8, _cont_drv1_time);
443 writeReg(REG_CONTCFG9, _cont_drv2_time);
444 writeReg(REG_CONTCFG11, _cont_track_margin);
446 if (_f0_pre == 0)
return false;
447 int drv_width = (((_f0_pre / 10) * 15) / (_cont_track_margin + 3)) / 100;
448 if (drv_width < 8) drv_width = 8;
449 if (drv_width > 255) drv_width = 255;
450 writeReg(REG_CONTCFG3,
static_cast<uint8_t
>(drv_width));
456 if ((getGlobalState() & MASK_GLB_STATE) == STATE_STANDBY) {
465 f0_reg = (val[0] << 8) | val[1];
466 if (f0_reg) _f0 = f0_formula(f0_reg);
470 updateBits(REG_PLAYCFG3, MASK_BRK_EN, brk_en_temp);
475bool HapticDriver_AW86224::measureVbat()
479 updateBits(REG_DETCFG2, MASK_VBAT_GO, MASK_VBAT_GO);
482 uint32_t vbat_code =
readReg(REG_DET_VBAT) << 2;
483 vbat_code |= (
readReg(REG_DET_LO) & MASK_VBAT_LO) >> SHIFT_VBAT_LO;
485 _vbat = vbat_formula(vbat_code);
486 if (_vbat > 4500) _vbat = 4500;
487 if (_vbat < 3000) _vbat = 3000;
493void HapticDriver_AW86224::getLraResistance()
495 uint8_t d2s_gain_temp =
readReg(REG_SYSCTRL7) & MASK_D2S_GAIN;
496 int d2s_gain = selectD2sGain(5);
497 if (d2s_gain < 0)
return;
503 updateBits(REG_DETCFG1, MASK_RL_OS, MASK_RL_OS);
504 updateBits(REG_DETCFG2, MASK_DIAG_GO, MASK_DIAG_GO);
507 uint32_t lra_code =
readReg(REG_DET_RL) << 2;
508 lra_code |=
readReg(REG_DET_LO) & MASK_RL_LO;
509 _lra = rl_formula(lra_code, d2s_gain) * 10;
512 updateBits(REG_SYSCTRL7, MASK_D2S_GAIN, d2s_gain_temp);
530 hal->delayMicroseconds(50);
531 int ret =
writeReg(REG_PLAYCFG4, PLAYCFG4_GO_ON);
532 hal->delayMicroseconds(50);
546 if (!_ramInit || index == 0)
return;
557 setTrimLRA(
static_cast<uint8_t
>(_f0_cali_data));
565 uint32_t playTime =
loop * 50;
566 if (playTime < 100) playTime = 100;
567 hal->delay(playTime);
572 if (!_ramInit || index == 0 || duration_ms == 0)
return;
584 _duration = duration_ms;
585 _vibrationStartTime =
hal->millis();
586 setTrimLRA(
static_cast<uint8_t
>(_f0_cali_data));
595 uint32_t start =
hal->millis();
596 while (
hal->millis() - start < duration_ms) {
597 if ((getGlobalState() & 0x0F) != 0x07)
run();
616 uint8_t reg = REG_WAVCFG9 + (wav / 2);
624void HapticDriver_AW86224::setFifoAddr()
626 uint8_t ae_addr_h = (_ramBaseAddr >> 1) >> 4 & 0xF0;
627 uint8_t af_addr_h = ((_ramBaseAddr - (_ramBaseAddr >> 2)) >> 8) & 0x0F;
629 static_cast<uint8_t
>(ae_addr_h | af_addr_h),
630 static_cast<uint8_t
>((_ramBaseAddr >> 1) & 0xFF),
631 static_cast<uint8_t
>((_ramBaseAddr - (_ramBaseAddr >> 2)) & 0xFF)
636void HapticDriver_AW86224::setBaseAddr()
638 updateBits(REG_RTPCFG1, MASK_BASE_ADDR_H, (_ramBaseAddr >> 8) & MASK_BASE_ADDR_H);
639 writeReg(REG_RTPCFG2, _ramBaseAddr & 0xFF);
642void HapticDriver_AW86224::setRamAddr()
644 writeReg(REG_RAMADDRH, (_ramBaseAddr >> 8) & 0x3F);
645 writeReg(REG_RAMADDRL, _ramBaseAddr & 0xFF);
655 if (!data || len == 0)
return false;
667 updateBits(REG_RTPCFG1, MASK_BASE_ADDR_H, (_ramBaseAddr >> 8) & MASK_BASE_ADDR_H);
668 writeReg(REG_RTPCFG2, _ramBaseAddr & 0xFF);
671 if (!
run())
return false;
674 if (!waitRtpGo(200)) {
679 writeRegBuff(REG_RTPDATA,
const_cast<uint8_t*
>(data), len);
684 uint32_t buf_len = (len - cnt) > 64 ? 64 : (len - cnt);
685 writeRegBuff(REG_RTPDATA,
const_cast<uint8_t*
>(data + cnt), buf_len);
692bool HapticDriver_AW86224::waitRtpGo(uint32_t timeout_ms)
694 uint32_t start =
hal->millis();
695 while (
hal->millis() - start < timeout_ms) {
696 if ((
readReg(REG_GLBRD5) & 0x0F) == STATE_RTP_GO)
return true;
697 hal->delayMicroseconds(1000);
702void HapticDriver_AW86224::setRepeatSeq(uint8_t seq)
709void HapticDriver_AW86224::contConfig()
712 updateBits(REG_CONTCFG6, MASK_TRACK_EN | MASK_DRV1_LVL, MASK_TRACK_EN | (_cont_drv1_lvl & MASK_DRV1_LVL));
713 writeReg(REG_CONTCFG7, _cont_drv2_lvl);
718void HapticDriver_AW86224::interruptSetup()
720 updateBits(REG_SYSCTRL7, INT_MODE_EDGE, INT_MODE_EDGE);
722 updateBits(REG_SYSINTM, MASK_UVLM | MASK_FF_AEM | MASK_FF_AFM | MASK_OCDM | MASK_OTM | MASK_DONEM, MASK_UVLM);
725uint8_t HapticDriver_AW86224::getGlobalState()
const
730bool HapticDriver_AW86224::waitStandby(uint32_t timeout_ms)
732 uint32_t start =
hal->millis();
733 while (
hal->millis() - start < timeout_ms) {
734 if ((getGlobalState() & MASK_GLB_STATE) == STATE_STANDBY)
return true;
740int HapticDriver_AW86224::getIrqState()
742 uint8_t reg_val =
readReg(REG_SYSINT);
743 if (reg_val & MASK_UVLI)
return IRQ_UVL;
744 if (reg_val & MASK_OCDI)
return IRQ_OCD;
745 if (reg_val & MASK_OTI)
return IRQ_OT;
746 if (reg_val & MASK_DONEI)
return IRQ_DONE;
747 if (reg_val & MASK_FF_AFI)
return IRQ_ALMOST_FULL;
748 if (reg_val & MASK_FF_AEI)
return IRQ_ALMOST_EMPTY;
752void HapticDriver_AW86224::irqClear()
757uint8_t HapticDriver_AW86224::rtpGetFifoAfs()
759 return (
readReg(REG_SYSST) & MASK_FF_AFS) >> 3;
762void HapticDriver_AW86224::setRtpAei(
bool enable)
764 updateBits(REG_SYSINTM, MASK_FF_AEM, enable ? 0 : MASK_FF_AEM);
769 if (!data || len == 0)
return false;
770 if (!getBaseAddr(data, len))
return false;
780 uint32_t chunk = (len -
i) > 32 ? 32 : (len -
i);
781 writeRegBuff(REG_RAMDATA,
const_cast<uint8_t*
>(data +
i), chunk);
783 hal->delayMicroseconds(100);
792bool HapticDriver_AW86224::getBaseAddr(
const uint8_t *data, uint32_t len)
794 uint16_t last_end = 0, next_start = 0;
797 for (
int i = 3; i < static_cast<int>(len);
i += 4) {
798 last_end = (data[
i] << 8) | data[
i + 1];
799 next_start = (data[
i + 2] << 8) | data[
i + 3];
800 if ((next_start - last_end) == 1) ram_num++;
804 for (
int i = ram_num * 4;
i >= 4;
i -= 4) {
805 last_end = (data[
i - 1] << 8) | data[
i];
806 _ramBaseAddr =
static_cast<int>((data[1] << 8) | data[2]) - ram_num * 4 - 1;
807 if ((last_end - _ramBaseAddr + 1) ==
static_cast<int>(len)) {
814 _ramBaseAddr = (data[1] << 8) | data[2];
815 _ramNum = ((_ramBaseAddr - _ramBaseAddr) - 1) / 4;
819void HapticDriver_AW86224::vbatModeConfig(uint8_t flag)
821 if (flag == CONT_VBAT_HW_COMP_MODE) {
823 updateBits(REG_SYSCTRL1, MASK_VBAT_MODE, MASK_VBAT_MODE);
829void HapticDriver_AW86224::calculateCaliData()
831 int f0_cali_step = 100000 * (
static_cast<int>(_f0) -
static_cast<int>(_f0_pre)) / (
static_cast<int>(_f0_pre) * F0_CALI_ACCURACY);
833 if (f0_cali_step >= 0) {
834 f0_cali_step = (f0_cali_step % 10 >= 5) ? (32 + f0_cali_step / 10 + 1) : (32 + f0_cali_step / 10);
836 f0_cali_step = (f0_cali_step % 10 <= -5) ? (32 + f0_cali_step / 10 - 1) : (32 + f0_cali_step / 10);
839 int8_t f0_cali_lra = (f0_cali_step > 31) ?
static_cast<int8_t
>(f0_cali_step - 32) :
static_cast<int8_t
>(f0_cali_step + 32);
840 _f0_cali_data = f0_cali_lra;
843void HapticDriver_AW86224::reset()
846 hal->pinMode(_rstPin, OUTPUT);
847 hal->digitalWrite(_rstPin, LOW);
849 hal->digitalWrite(_rstPin, HIGH);
929bool HapticDriver_AW86224::initImpl(uint8_t param)
934 hal->pinMode(_rstPin, OUTPUT);
935 hal->digitalWrite(_rstPin, LOW);
937 hal->digitalWrite(_rstPin, HIGH);
941 if (!parseChipID())
return false;
945 if (!offsetCalibration()) {
954 if (!
loadRamData(aw862xx_ram_data, aw862xx_ram_len))
return false;
959bool HapticDriver_AW86224::parseChipID()
962 for (
int i = 0;
i < 5;
i++) {
969 uint8_t ef_id =
readReg(REG_CHIPID);
970 if ((ef_id & 0x41) == 0x01) {
972 }
else if ((ef_id & 0x41) == 0x00) {
977 }
else if (reg == 0x01) {
978 uint8_t ef_id =
readReg(REG_CHIPID);
979 if ((ef_id & 0x41) == 0x41) {
990void HapticDriver_AW86224::hapticInit()
992 _f0_pre = F0_PRE_VAL;
996 vbatModeConfig(CONT_VBAT_HW_COMP_MODE);
1001void HapticDriver_AW86224::f0Calibration()
1009 if (!judgeF0WithinRange())
return;
1011 calculateCaliData();
1012 setTrimLRA(
static_cast<uint8_t
>(_f0_cali_data));
1013 _isCalibrated =
true;
1016bool HapticDriver_AW86224::judgeF0WithinRange()
1018 uint32_t f0_cali_min = _f0_pre * (100 - _f0_cali_percent) / 100;
1019 uint32_t f0_cali_max = _f0_pre * (100 + _f0_cali_percent) / 100;
1020 return (_f0 >= f0_cali_min && _f0 <= f0_cali_max);
1023void HapticDriver_AW86224::printRegs()
1026 Serial.println(
"\n=== Register Dump ===");
1027 Serial.printf(
"PLAYCFG2: 0x%02X\n",
readReg(0x07));
1028 Serial.printf(
"PLAYCFG3: 0x%02X\n",
readReg(0x08));
1029 Serial.printf(
"PLAYCFG4: 0x%02X\n",
readReg(0x09));
1030 Serial.printf(
"WAVCFG1: 0x%02X\n",
readReg(0x0A));
1031 Serial.printf(
"WAVCFG2: 0x%02X\n",
readReg(0x0B));
1032 Serial.printf(
"WAVCFG9: 0x%02X\n",
readReg(0x12));
1033 Serial.printf(
"GLBRD5: 0x%02X\n",
readReg(0x3F));
1034 Serial.printf(
"SYSCTRL7: 0x%02X\n",
readReg(0x49));
1035 Serial.printf(
"TRIMCFG3: 0x%02X\n",
readReg(0x5A));
1036 Serial.println(
"======================");
HapticStatus
Vibration playback status.
@ PLAYING
Currently playing.
HapticActuatorType
Actuator type.
@ LRA
Linear Resonant Actuator.
HapticMode
Generic haptic operating mode.
@ INTERNAL_TRIGGER
Play by selecting waveforms/effects and calling run()
@ AUTO_CALIBRATE
Auto-calibration mode.
@ REAL_TIME_PLAYBACK
RTP mode (direct drive value)
uint16_t HapticEffectId
Haptic effect ID type.
std::unique_ptr< SensorHal > hal
Abstract base class for haptic drivers.
void setReady(bool ready)
Set ready state.
void end() override
Deinitialize the haptic driver and release resources.
void setPlayMode(PlayMode mode)
Set playback mode.
bool setSequence(uint8_t slot, HapticEffectId effect) override
Set a waveform in the sequence.
bool playEffectAsync(HapticEffectId effect) override
Play a haptic effect (non-blocking).
void setWaveLoop(uint8_t wav, uint8_t loop)
Set waveform loop count.
@ PWM_12K
12kHz PWM rate (default)
void stopVibration()
Stop any ongoing vibration.
void setWaveSeq(uint8_t wav, uint8_t seq)
Update vibration state (for non-blocking mode)
bool calibrate() override
Perform auto-calibration.
bool isPlaying() const override
Check if haptic is currently playing.
void setTrimLRA(uint8_t val)
Set LRA frequency trim value.
bool setGain(uint8_t gain) override
Set the gain/amplitude (0x00 to 0xFF).
uint32_t getVbat() override
Get the battery voltage.
bool loadRamData(const uint8_t *data, uint32_t len)
Load RAM waveform data.
void setPins(uint8_t resetPin, uint8_t intPin)
setPins
bool stop() override
Stop haptic playback immediately.
bool setMode(HapticMode mode) override
Set the operating mode.
uint32_t getF0() const override
Get the measured resonant frequency (F0).
HapticMode getMode() const override
Get the current operating mode.
void setRtpData(uint8_t *data, uint32_t len)
Set RTP waveform data.
bool playRtp(const uint8_t *data, uint32_t len, uint8_t gain=0x80)
Play RTP (Real-Time Playback) waveform.
bool setActuatorType(HapticActuatorType type) override
Set the actuator type.
uint8_t getGain() const override
Get the current gain value.
bool setRealtimeValue(uint8_t value) override
Set RTP (real-time playback) value.
bool isReady() const override
Check if the driver is initialized and ready.
void softReset()
Perform soft reset.
void vibrationUpdate() override
Update vibration state (for non-blocking mode).
void continuousVibration(uint32_t duration_ms, bool blocking=true) override
Play a continuous vibration for specified duration.
HapticActuatorType getActuatorType() const override
Get the actuator type.
bool playEffect(HapticEffectId effect) override
Play a haptic effect.
HapticStatus getStatus() const override
Get current playback status.
bool run() override
Start haptic playback.
bool clearSequence() override
Clear the waveform sequence.
HapticDriver_AW86224()
Default constructor.
void shortVibration(uint8_t index, uint8_t gain=0x80, uint8_t loop=1)
Play a short vibration effect.
HapticCapabilities getCapabilities() const override
Get device capabilities.
const char * getChipName() const override
Get the chip name.
void longVibration(uint8_t index, uint8_t gain=0x80, uint32_t duration_ms=1000, bool blocking=true)
Play a long continuous vibration effect.
PlayMode
Playback mode enumeration.
@ CONT
Continuous mode with F0 tracking.
@ RAM_LOOP
RAM loop mode, continuous playback.
@ RAM
RAM playback mode, single play.
@ STANDBY
Standby mode, minimal power consumption.
@ RTP
Real-time playback mode.
bool needsCalibration() const override
Check if calibration is needed.
uint8_t getChipID() const override
Get the chip ID.
bool playSequence() override
Play the waveform sequence.
int readReg(uint8_t reg) const
int writeRegBuff(uint8_t reg, uint8_t *buf, size_t len)
int writeReg(uint8_t reg, uint8_t val)
int readRegBuff(uint8_t reg, uint8_t *buf, size_t len) const
int updateBits(uint8_t reg, uint8_t mask, uint8_t value_shifted)
constexpr uint32_t _bv(uint8_t b)
uint8_t maxSequenceLength
Maximum waveform sequence length.
uint8_t hasF0Calibration
Supports F0 (resonant frequency) calibration.
uint16_t maxDurationMs
Maximum vibration duration in ms (0 = unlimited)
uint8_t hasAutoCalibration
Supports auto-calibration.
uint8_t hasVbatCompensation
Supports automatic voltage compensation.
uint8_t hasRTP
Supports Real-Time Playback mode.
uint8_t hasBreakEffect
Supports brake/break effects.
uint8_t hasOverdrive
Supports overdrive effects.
uint8_t maxEffectCount
Maximum number of effect IDs supported.
uint8_t hasContinuousMode
Supports continuous vibration mode.
uint8_t hasSequence
Supports waveform sequencing.