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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
|
/*
* MIDIUSB_test.ino
*
* Created: 4/6/2015 10:47:08 AM
* Author: gurbrinder grewal
* Modified by Arduino LLC (2015)
*/
#include "MIDIUSB.h"
#include <Wire.h>
#include "main.h"
#include "config.h"
#include "engine.h"
int led = 13;
enum {
MODE_STANDALONE = 0,
MODE_REPORTPOINTS = 1,
MODE_REPORTPOINTS_PLAY = 2,
} g_mode = MODE_REPORTPOINTS_PLAY;
uint32_t now() {
return millis();
}
void setup_pwm() {
// Set up the generic clock (GCLK4) used to clock timers
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide the 48MHz clock source by divisor 2: 48MHz/2=24MHz
GCLK_GENDIV_ID(4); // Select Generic Clock (GCLK) 4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK4
GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source
GCLK_GENCTRL_ID(4); // Select GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Feed GCLK4 to TC4 and TC5
REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK4 to TC4 and TC5
GCLK_CLKCTRL_GEN_GCLK4 | // Select GCLK4
GCLK_CLKCTRL_ID_TC4_TC5; // Feed the GCLK4 to TC4 and TC5
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_TC4_CTRLA |= TC_CTRLA_MODE_COUNT8; // Set the counter to 8-bit mode
while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_TC4_COUNT8_CC0 = 0; // Set the TC4 CC0 register to some arbitary value
while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_TC4_COUNT8_CC1 = 0; // Set the TC4 CC1 register to some arbitary value
while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_TC4_COUNT8_PER = 1; // Set the PER (period) register to flip each time
while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization
NVIC_DisableIRQ(TC4_IRQn);
NVIC_ClearPendingIRQ(TC4_IRQn);
// NVIC_SetPriority(TC4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
// NVIC_EnableIRQ(TC4_IRQn); // Connect TC4 to Nested Vector Interrupt Controller (NVIC)
REG_TC4_INTFLAG |= TC_INTFLAG_MC1 | TC_INTFLAG_MC0 | TC_INTFLAG_OVF; // Clear the interrupt flags
//REG_TC4_INTENSET = TC_INTENSET_MC1 | TC_INTENSET_MC0 | TC_INTENSET_OVF; // Enable TC4 interrupts
REG_TC4_INTENCLR = TC_INTENCLR_MC1 | TC_INTENCLR_MC0 | TC_INTENCLR_OVF; // Disable TC4 interrupts
int outpin = 15;
// Enable the port multiplexer for the digital pin D0
PORT->Group[g_APinDescription[outpin].ulPort].PINCFG[g_APinDescription[outpin].ulPin].bit.PMUXEN = 1;
// Connect the TC4 timer to the port output D0 - port pins are paired odd PMUXO and even PMUXE
// Peripheral E specifies the TC timers, on this pin: TC4
PORT->Group[g_APinDescription[outpin].ulPort].PMUX[g_APinDescription[outpin].ulPin >> 1].reg |= /*PORT_PMUX_PMUXO_E |*/ PORT_PMUX_PMUXE_E;
REG_TC4_CTRLA |= TC_CTRLA_PRESCALER_DIV1 | // Set prescaler to 1, 24MHz/1 = 24MHz
TC_CTRLA_ENABLE; // Enable TC4
while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization
}
static void set_cam_register(uint8_t r, uint8_t v) {
Wire.beginTransmission(0x58);
Wire.write(r);
Wire.write(v);
Wire.endTransmission();
}
static void setup_cam() {
set_cam_register(0x30, 0x01);
set_cam_register(0x06, 0x90);
set_cam_register(0x08, 0xc0);
set_cam_register(0x1a, 0x40);
set_cam_register(0x33, 0x01);
set_cam_register(0x30, 0x08);
}
void setup() {
pinMode(led, OUTPUT);
Wire.begin();
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
setup_pwm();
// Let PWM settle for a bit
delay(100);
setup_cam();
Serial.begin(115200);
digitalWrite(led, LOW); // turn the LED on (HIGH is the voltage level)
}
void handle_wire() {
uint8_t ic2_result[32];
char text[64];
Wire.beginTransmission(0x58);
Wire.write(0x36);
Wire.endTransmission();
Wire.requestFrom(0x58, 11);
for (int i=0; Wire.available() && i<=11; ++i)
ic2_result[i] = Wire.read();
LPoint p1, p2, p3, p4;
int Ix1,Iy1,Ix2,Iy2;
int Ix3,Iy3,Ix4,Iy4;
int s;
s = ic2_result[3];
p1.x = ((int)ic2_result[1]) | ( ( s << 4) & 0x300);
p1.y = ((int)ic2_result[2]) | ( ( s << 2) & 0x300);
p2.x = ((int)ic2_result[4]) | ( ( s << 8) & 0x300);
p2.y = ((int)ic2_result[5]) | ( ( s << 6) & 0x300);
s = ic2_result[8];
p3.x = ((int)ic2_result[6]) | ( ( s << 4) & 0x300);
p3.y = ((int)ic2_result[7]) | ( ( s << 2) & 0x300);
p4.x = ((int)ic2_result[9]) | ( ( s << 8) & 0x300);
p4.y = ((int)ic2_result[10])| ( ( s << 6) & 0x300);
if (p1.x==1023 && p2.x==1023 && p3.x==1023 && p4.x==1023)
return;
uint32_t now = millis();
if (g_mode==MODE_STANDALONE || g_mode==MODE_REPORTPOINTS_PLAY) {
/*
if (p1.x!=1023)
engine_handle_point(&p1, now);
if (p2.x!=1023)
engine_handle_point(&p2, now);
if (p3.x!=1023)
engine_handle_point(&p3, now);
if (p4.x!=1023)
engine_handle_point(&p4, now);
*/
}
if (g_mode==MODE_STANDALONE)
return;
if (p1.x!=1023)
Serial.write(text, sprintf(text, "%04d:%04d ", p1.x, p1.y));
if (p2.x!=1023)
Serial.write(text, sprintf(text, "%04d:%04d ", p2.x, p2.y));
if (p3.x!=1023)
Serial.write(text, sprintf(text, "%04d:%04d ", p3.x, p3.y));
if (p4.x!=1023)
Serial.write(text, sprintf(text, "%04d:%04d ", p4.x, p4.y));
Serial.println("");
}
/* Do a fast nibble to hex representation conversion */
static unsigned char fromhex(unsigned char x) {
x-='0'; if( x<=9) return x;
x&=~0x20; x-='A'-'0';
if( x<6 ) return x+10;
return 0xff;
}
void handle_midi(char *command) {
// midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
uint8_t m[6];
/* expect 6 hex encoded MIDI bytes and a newline */
for (int i=0; i<6; ++i)
if ((m[i] = fromhex(command[i])) == 0xff)
return;
if (command[6] != '\n')
return;
midiEventPacket_t p = { m[0], (m[0]<<4) | m[1], (m[2]<<4) | m[3], (m[4]<<4) | m[5] };
MidiUSB.sendMIDI(p);
// MidiUSB.flush();
}
void midi_playnote(int channel, int note, int octave_offset ) {
midi_pitchbend(channel, 0);
midiEventPacket_t p = { 0x9, 0x90 | channel, note + 12 * octave_offset, 0x7f };
MidiUSB.sendMIDI(p);
}
void midi_silencenote( int channel, int note, int octave_offset ) {
midiEventPacket_t p = { 0x8, 0x80 | channel, note + 12 * octave_offset, 0x7f };
MidiUSB.sendMIDI(p);
}
void midi_pitchbend( int channel, int pitch ) {
pitch += 8192;
if (pitch < 0) pitch = 0;
if (pitch > 16383) pitch = 16383;
midiEventPacket_t p = { 0xe, 0xe0 | channel, 0x7f & pitch, 0x7f & (pitch>>7) };
MidiUSB.sendMIDI(p);
}
void handle_configure(char *command) {
}
void handle_command(char *command) {
switch (*command) {
case 'M': /* Getting MIDI instruction */
handle_midi(command+1);
break;
case 'S': /* Getting set mode instruction */
switch (command[1]) {
case '1':
g_mode = MODE_STANDALONE;
break;
case '2':
g_mode = MODE_REPORTPOINTS_PLAY;
break;
case '3':
g_mode = MODE_REPORTPOINTS;
break;
default:
break;
}
break;
case 'C': /* Getting configure command */
handle_configure(command+1);
break;
default:
break;
}
}
void handle_serial() {
static char command[128];
static int command_len;
static int skip_command;
while (Serial.available()) {
char c = command[command_len++] = Serial.read();
if (c=='\n') {
if (!skip_command) {
command[command_len] = 0;
handle_command(command);
}
skip_command = 0;
command_len = 0;
// Read at max one command to allow polling the cam
return;
}
if (command_len==sizeof(command)) {
// If we end up at end of buffer, ignore everying to next \n
skip_command = 1;
command_len = 0;
}
}
}
void loop() {
static int led_state;
handle_wire();
handle_serial();
/*
Serial.write((const uint8_t*)"Sending note on\r\n", 17);
noteOn(0, note, 64); // Channel 0, middle C, normal velocity
MidiUSB.flush();
delay(500);
digitalWrite(led, LOW); // turn the LED on (HIGH is the voltage level)
Serial.write((const uint8_t*)"Sending note off\r\n", 18);
noteOff(0, note, 64); // Channel 0, middle C, normal velocity
MidiUSB.flush();
delay(1500);
*/
//engine_checksilence(millis());
digitalWrite(led, ++led_state & 1 ? HIGH : LOW); // turn the LED on (HIGH is the voltage level)
}
|