kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Added driver for drv2605l
rodzic
032c17dd00
commit
986fbf79ee
|
@ -1,2 +1,3 @@
|
|||
add_subdirectory(st7789)
|
||||
add_subdirectory(msa301)
|
||||
add_subdirectory(msa301)
|
||||
add_subdirectory(drv2605l)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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, ®, 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, ®, 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
Ładowanie…
Reference in New Issue