-
Notifications
You must be signed in to change notification settings - Fork 1
/
Weftlib.cpp
217 lines (185 loc) · 7.32 KB
/
Weftlib.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
WEFTlib Electrovibration library
2017, nfeehan / AKA aka.farm
Addition of some methods to make electrovibration actuation more convenient. Probably also useful for piezo effects?
Based gratefully off of:
Yurikleb_DRV2667.h - Library for controling the TI - DRV2667 Hapic Piezo Driver
Created by Yuri Klenaov, January, 2016. (yurikleb.com)
Released into the public domain.
For more information see the DRV2667 Datasheet http://www.ti.com/lit/ds/symlink/drv2667.pdf
...there are three modes for this IC that result in output.
waveform synthesis playback: ie, send the ic a description of a sequence of sine waves
waveform "Direct Playback": in this mode, the IC basically reads a soundfile you've stored in RAM (via the savePattern() call)
analog in: calling setToAnalogInput() or setToAnalogInputGain(byte gain)
*/
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire.h> //Wire Library to use I2C
#include "Weftlib.h"
Weft::Weft(){
}
void Weft::begin() {
/*
Initialization Procedure
1. Apply power to the DRV2667 device.
2. Wait for 1 ms for the DRV2667 device to power-up before attempting an I2C write.
3. Exit low-power standby mode by clearing the STANDBY bit in register 0x02, bit6.
4. Choose the interface modeas analog or digital in register 0x01, bit2.
5. Select the gain setting for your application in register 0x01, bits[1:0].
6. Choose the desired timeout period if using the digital interface mode (FIFO), in register 0x02, bits[3:2].
7. If using the digital interface mode, the device is now ready to receive data.
If using the analog input mode, set the EN_OVERRIDE bit in register 0x02, bit 1 to enable the boost
and high-voltage amplifier and begin sourcing the waveform to the analog input.
*/
Wire.begin();
delay(300);
}
//Send a Wave to the DRV2667
void Weft::playWave(byte WaveForm[][4], byte WavesNumber) {
//control
writeRegisterBytes(REG_CTRL, STANDBY_OFF); //Take device out of standby mode
writeRegisterBytes(REG_GAINS, 0x03); //Set Gain 0-3 (0x00-0x03 25v-100v)
writeRegisterBytes(0x03, 0x01); //Set sequencer to play WaveForm ID #1
writeRegisterBytes(0x04, 0x00); //End of sequence
//header
/*
The header block describes the location of the waveform data content.
The structure of the header consists of 5- byte blocks containing the following information (see Figure 26):
• Start address, upper byte
• Start address, lower byte
• Stop address, upper byte
• Stop address, lower byte
• Repeat count ( A 0 in this byte is interpreted as an infinite loop and the waveform is played indefinitely until the GO bit is cleared by the user.)
*/
writeRegisterBytes(0xFF, 0x01); //Set memory to page 1
writeRegisterBytes(0x00, 0x05); //Header size –1
writeRegisterBytes(0x01, 0x80); //Start address upper byte (page), also indicates Mode 3
writeRegisterBytes(REG_CTRL, 0x06); //Start address lower byte (in page address)
writeRegisterBytes(0x03, 0x00); //Stop address upper byte
writeRegisterBytes(0x04, 0x06+WavesNumber-1); //Stop address Lower byte
writeRegisterBytes(0x05, 0x01); //Repeat count, play WaveForm once
//WaveForm Data From the array
for(byte i = 0; i < WavesNumber; i++){
writeRegisterBytes(0x06+i*4+0, WaveForm[i][0]);
writeRegisterBytes(0x06+i*4+1, WaveForm[i][1]);
writeRegisterBytes(0x06+i*4+2, WaveForm[i][2]);
writeRegisterBytes(0x06+i*4+3, WaveForm[i][3]);
}
//Control
writeRegisterBytes(0xFF, 0x00); //Set page register to control space
writeRegisterBytes(REG_CTRL, 0x01); //Set GO bit (execute WaveForm sequence)
//delay( 1000 * (cycles / (7.8125 * frequency)) );
}
//Send a Wave to the DRV2667
void Weft::playWaveGain(byte WaveForm[][4], byte WavesNumber, byte theGain) {
if(theGain>0x03){
theGain=0x03;
}
//control
writeRegisterBytes(REG_CTRL, STANDBY_OFF); //Take device out of standby mode
writeRegisterBytes(REG_GAINS, theGain); //Set Gain 0-3 (0x00-0x03 25v-100v)
writeRegisterBytes(0x03, 0x01); //Set sequencer to play WaveForm ID #1
writeRegisterBytes(0x04, 0x00); //End of sequence
//header
writeRegisterBytes(0xFF, 0x01); //Set memory to page 1
writeRegisterBytes(0x00, 0x05); //Header size –1
writeRegisterBytes(0x01, 0x80); //Start address upper byte (page), also indicates Mode 3
writeRegisterBytes(REG_CTRL, 0x06); //Start address lower byte (in page address)
writeRegisterBytes(0x03, 0x00); //Stop address upper byte
writeRegisterBytes(0x04, 0x06+WavesNumber-1); //Stop address Lower byte
writeRegisterBytes(0x05, 0x01); //Repeat count, play WaveForm once
//WaveForm Data From the array
for(byte i = 0; i < WavesNumber; i++){
writeRegisterBytes(0x06+i*4+0, WaveForm[i][0]);
writeRegisterBytes(0x06+i*4+1, WaveForm[i][1]);
writeRegisterBytes(0x06+i*4+2, WaveForm[i][2]);
writeRegisterBytes(0x06+i*4+3, WaveForm[i][3]);
}
//Control
writeRegisterBytes(0xFF, 0x00); //Set page register to control space
writeRegisterBytes(REG_CTRL, 0x01); //Set GO bit (execute WaveForm sequence)ss
//delay( 1000 * (cycles / (7.8125 * frequency)) );
}
float Weft::getWaveDuration(byte wf[][4], byte wn){
// TODO: test this to make sure it's correct!
// return wave duration in ms
float theCount = 0;
//WaveForm Data From the array
// ... the divide-by-4 might be wrong here
for(int j = 0; j < wn/4; j++){
// freq is in the 2nd byte
// num cycles is in 3rd
// duration in ms = 1000 * num
Serial.println(wf[j][1]);
if(wf[j][1]==0){
return 0;
} else {
theCount += (1000.0 * float(wf[j][2])) / (7.8125 * float(wf[j][1]));
}
}
return theCount;
}
void Weft::setToAnalogInput(){
//control
writeRegisterBytes(REG_CTRL, STANDBY_OFF); //Take device out of standby mode
writeRegisterBytes(REG_GAINS, 0x07); //Set to analog input + Gain 0-3 (0x04-0x07 25v-100v)
writeRegisterBytes(REG_CTRL, BOOST_AMP_ENABLED); //Set EN_OVERRIDE bit = boost and amplifier active
}
void Weft::setToAnalogInputGain(byte theGain){
//control
if(theGain>0x07){
theGain=0x07;
}
if(theGain<0x04){
theGain=0x04;
}
writeRegisterBytes(REG_CTRL, STANDBY_OFF); //Take device out of standby mode
writeRegisterBytes(REG_GAINS, theGain); //Set to analog input + Gain 0-3 (0x04-0x07 25v-100v)
writeRegisterBytes(REG_CTRL, BOOST_AMP_ENABLED); //Set EN_OVERRIDE bit = boost and amplifier active
}
void Weft::setTimeoutPeriod(byte thePeriod){
// TODO: test this on scope!
if(thePeriod==0x00 || thePeriod==0x04 || thePeriod==0x08 || thePeriod==0x0C){
writeRegisterBytes(REG_CTRL, thePeriod);
}
// 0x00: 5ms
// 0x04: 10ms
// 0x08: 15ms
// 0x0C: 20ms
}
void Weft::resetDevice(){
// TODO: test this on scope!
writeRegisterBytes(REG_CTRL, RESET_DEVICE);
// note this ALSO places IC into Standby Mode
}
void Weft::setToStandby(){
// TODO: test this on scope!
writeRegisterBytes(REG_CTRL, STANDBY_ON);
}
void Weft::wakeFromStandby(){
// TODO: test this on scope!
writeRegisterBytes(REG_CTRL, STANDBY_OFF);
}
//Write Bytes via I2c (Using Wire Library)
void Weft::writeRegisterBytes(byte reg, byte val) {
Wire.beginTransmission(DRV2667_ADDR);
Wire.write((byte)reg);
Wire.write((byte)val);
Wire.endTransmission();
}
void Weft::i2c_Scan(){
byte count = 0;
Wire.begin();
for (byte i = 8; i < 120; i++)
{
Wire.beginTransmission (i);
if (Wire.endTransmission () == 0)
{
count++;
delay (1);
}
}
}