Added driver for drv2605l

driver-drv2605l
ZodiusInfuser 2021-01-25 17:26:49 +00:00
rodzic 032c17dd00
commit 986fbf79ee
5 zmienionych plików z 260 dodań i 1 usunięć

Wyświetl plik

@ -1,2 +1,3 @@
add_subdirectory(st7789)
add_subdirectory(msa301)
add_subdirectory(msa301)
add_subdirectory(drv2605l)

Wyświetl plik

@ -0,0 +1,10 @@
add_library(drv2605l INTERFACE)
target_sources(drv2605l INTERFACE
${CMAKE_CURRENT_LIST_DIR}/drv2605l.cpp
)
target_include_directories(drv2605l INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(drv2605l INTERFACE pico_stdlib hardware_i2c)

Wyświetl plik

@ -0,0 +1,10 @@
add_library(drv2605l INTERFACE)
target_sources(drv2605l INTERFACE
${CMAKE_CURRENT_LIST_DIR}/drv2605l.cpp
)
target_include_directories(drv2605l INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(drv2605l INTERFACE pico_stdlib hardware_i2c)

Wyświetl plik

@ -0,0 +1,139 @@
#include <cstdlib>
#include <math.h>
#include <map>
#include <vector>
#include "drv2605l.hpp"
namespace pimoroni {
enum reg {
STATUS = 0x00,
MODE = 0x01,
REALTIME_PLAYBACK = 0x02,
LIBRARY_SELECTION = 0x03,
WAVEFORM_SEQUENCER = 0x04,
GO = 0x0c,
TIME_OFFSET = 0x0d,
AUDIO_CONTROL = 0x11,
AUDIO_INPUT_LEVEL = 0x12,
AUDIO_OUTPUT_DRIVE = 0x14,
VOLTAGE = 0x16,
AUTO_CALIBRATION_RESULT = 0x18,
FEEDBACK_CONTROL = 0x1a,
CONTROL1 = 0x1b,
CONTROL2 = 0x1c,
CONTROL3 = 0x1d,
CONTROL4 = 0x1e,
CONTROL5 = 0x1f,
LRA_OPEN_LOOP_PERIOD = 0x20,
VOLTAGE2 = 0x21,
LRA_RESONANCE = 0x22,
};
void DRV2605L::init() {
i2c_init(i2c, 400000);
gpio_set_function(sda, GPIO_FUNC_I2C); gpio_pull_up(sda);
gpio_set_function(scl, GPIO_FUNC_I2C); gpio_pull_up(scl);
reset();
}
void DRV2605L::i2c_reg_write_uint8(uint8_t reg, uint8_t value) {
uint8_t buffer[2] = {reg, value};
i2c_write_blocking(i2c, address, buffer, 2, false);
}
uint8_t DRV2605L::i2c_reg_read_uint8(uint8_t reg) {
uint8_t value;
i2c_write_blocking(i2c, address, &reg, 1, true);
i2c_read_blocking(i2c, address, (uint8_t *)&value, 1, false);
return value;
}
int16_t DRV2605L::i2c_reg_read_int16(uint8_t reg) {
int16_t value;
i2c_write_blocking(i2c, address, &reg, 1, true);
i2c_read_blocking(i2c, address, (uint8_t *)&value, 2, false);
return value;
}
void DRV2605L::reset() {
i2c_reg_write_uint8(reg::MODE, 0x80);
sleep_ms(0.1);
while(i2c_reg_read_uint8(reg::MODE) & 0x80) {
sleep_ms(0.01);
}
i2c_reg_write_uint8(reg::MODE, 0x00);//standby=False)
}
void DRV2605L::set_feedback_mode(uint8_t mode) {
switch(mode) {
case FB_MODE_LRA:
i2c_reg_write_uint8(reg::FEEDBACK_CONTROL, i2c_reg_read_uint8(reg::FEEDBACK_CONTROL) | 0x80);
break;
case FB_MODE_ERM:
default:
i2c_reg_write_uint8(reg::FEEDBACK_CONTROL, i2c_reg_read_uint8(reg::FEEDBACK_CONTROL) & 0x7f);
break;
}
}
void DRV2605L::set_library(uint8_t library) {
i2c_reg_write_uint8(reg::LIBRARY_SELECTION, library);
}
void DRV2605L::set_mode(uint8_t mode) {
i2c_reg_write_uint8(reg::MODE, 0x00); //mode=mode)
}
void DRV2605L::auto_calibrate(uint8_t loop_gain, uint8_t feedback_brake_factor, uint8_t auto_calibration_time,
uint8_t zero_crossing_detection_time, uint8_t idiss_time) {
uint8_t mode = i2c_reg_read_uint8(reg::MODE);
i2c_reg_write_uint8(reg::MODE, MODE_AUTO_CALIBTRATION);
i2c_reg_write_uint8(reg::FEEDBACK_CONTROL, loop_gain | feedback_brake_factor);
i2c_reg_write_uint8(reg::CONTROL4, auto_calibration_time | zero_crossing_detection_time);
i2c_reg_write_uint8(reg::CONTROL2, idiss_time);
i2c_reg_write_uint8(reg::GO, 0x01);
while(i2c_reg_read_uint8(reg::GO)) {
sleep_ms(0.01);
}
i2c_reg_write_uint8(reg::MODE, mode);
}
void DRV2605L::set_realtime_input(uint8_t value) {
i2c_reg_write_uint8(reg::REALTIME_PLAYBACK, value);
}
void DRV2605L::set_realtime_data_format(uint8_t value) {
switch(value) {
case RT_UNSIGNED:
i2c_reg_write_uint8(reg::CONTROL3, i2c_reg_read_uint8(reg::CONTROL3) | 0x08);
break;
case RT_SIGNED:
default:
i2c_reg_write_uint8(reg::CONTROL3, i2c_reg_read_uint8(reg::CONTROL3) & 0xf7);
break;
}
}
void DRV2605L::set_waveform(uint8_t slot, uint8_t w) {
if(slot < 8)
i2c_reg_write_uint8(reg::WAVEFORM_SEQUENCER + slot, w);
}
void DRV2605L::go() {
i2c_reg_write_uint8(reg::GO, 0x01);
}
void DRV2605L::stop() {
i2c_reg_write_uint8(reg::GO, 0x00);
}
bool DRV2605L::busy() {
return i2c_reg_read_uint8(reg::GO) != 0;
}
}

Wyświetl plik

@ -0,0 +1,99 @@
#pragma once
#include "hardware/i2c.h"
#include "hardware/gpio.h"
namespace pimoroni {
class DRV2605L {
public:
static const uint8_t FB_MODE_ERM = 0x00;
static const uint8_t FB_MODE_LRA = 0x80;
static const uint8_t LIB_EMPTY = 0;
static const uint8_t LIB_TS2200_A = 1;
static const uint8_t LIB_TS2200_B = 2;
static const uint8_t LIB_TS2200_C = 3;
static const uint8_t LIB_TS2200_D = 4;
static const uint8_t LIB_TS2200_E = 5;
static const uint8_t LIB_LRA = 6;
static const uint8_t LIB_TS2200_F = 7;
static const uint8_t MODE_INTERNAL_TRIGGER = 0; //Waveforms are fired by setting the GO bit in register 0x0C
static const uint8_t MODE_EDGE_TRIGGER = 1; //A rising edge on INT/TRIG sets the GO bit, a second rising edge cancels the waveform
static const uint8_t MODE_LEVEL_TRIGGER = 2; //A rising edge on INT/TRIG sets the GO bit, a falling edge cancels the waveform
static const uint8_t MODE_PWM_ANALOG_IN = 3; //A PWM or Analog signal is accepted on INT/TRIG and used as a direct driving source
static const uint8_t MODE_AUDIO_IN = 4; //An AC-coupled audio signal is accepted on INT/TRIG and turned into meaningful vibration
//(AC_COUPLE and N_PWM_ANALOG should also be set)
static const uint8_t MODE_REALTIME_PLAYBACK = 5; //The contents of the REALTIME_PLAYBACK register are used as a waveform
static const uint8_t MODE_DIAGNOSTICS = 6; //Perform a diagnostic test on the actuator- triggered by setting the GO bit
static const uint8_t MODE_AUTO_CALIBTRATION = 7; //Perform an auto-calibration- triggered by setting the GO bit
static const uint8_t RT_SIGNED = 0;
static const uint8_t RT_UNSIGNED = 1;
static const uint8_t LOOP_GAIN_LOW = 0 << 2;
static const uint8_t LOOP_GAIN_MED = 1 << 2;
static const uint8_t LOOP_GAIN_HIGH = 2 << 2;
static const uint8_t LOOP_GAIN_VHIGH = 3 << 2;
static const uint8_t FBF_1 = 0 << 4;
static const uint8_t FBF_2 = 1 << 4;
static const uint8_t FBF_3 = 2 << 4;
static const uint8_t FBF_4 = 3 << 4;
static const uint8_t FBF_6 = 4 << 4;
static const uint8_t FBF_8 = 5 << 4;
static const uint8_t FBF_16 = 6 << 4;
static const uint8_t FBF_0 = 7 << 4;
static const uint8_t AUTO_CALIB_TIME_150 = 0 << 4;
static const uint8_t AUTO_CALIB_TIME_250 = 1 << 4;
static const uint8_t AUTO_CALIB_TIME_500 = 2 << 4;
static const uint8_t AUTO_CALIB_TIME_1000 = 3 << 4;
static const uint8_t ZERO_CROSS_TIME_100 = 0 << 6;
static const uint8_t ZERO_CROSS_TIME_200 = 1 << 6;
static const uint8_t ZERO_CROSS_TIME_300 = 2 << 6;
static const uint8_t ZERO_CROSS_TIME_390 = 3 << 6;
private:
i2c_inst_t *i2c = i2c0;
// interface pins with our standard defaults where appropriate
int8_t address = 0x5a;
int8_t sda = 20;
int8_t scl = 21;
int8_t interrupt = 22;
public:
DRV2605L() {}
DRV2605L(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt) :
i2c(i2c), sda(sda), scl(scl), interrupt(interrupt) {}
void init();
void reset();
void set_feedback_mode(uint8_t mode = FB_MODE_LRA);
void set_library(uint8_t library = LIB_LRA);
void set_mode(uint8_t mode);
void auto_calibrate(uint8_t loop_gain = LOOP_GAIN_HIGH,
uint8_t feedback_brake_factor = FBF_2,
uint8_t auto_calibration_time = AUTO_CALIB_TIME_1000,
uint8_t zero_crossing_detection_time = ZERO_CROSS_TIME_100,
uint8_t idiss_time = 1);
void set_realtime_input(uint8_t value);
void set_realtime_data_format(uint8_t value);
void set_waveform(uint8_t slot, uint8_t w);
void go();
void stop();
bool busy();
void i2c_reg_write_uint8(uint8_t reg, uint8_t value);
uint8_t i2c_reg_read_uint8(uint8_t reg);
int16_t i2c_reg_read_int16(uint8_t reg);
};
}