diff options
Diffstat (limited to 'arduino')
-rw-r--r-- | arduino/Laserharfe/Laserharfe.ino | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/arduino/Laserharfe/Laserharfe.ino b/arduino/Laserharfe/Laserharfe.ino new file mode 100644 index 0000000..8ad5f56 --- /dev/null +++ b/arduino/Laserharfe/Laserharfe.ino | |||
@@ -0,0 +1,282 @@ | |||
1 | /* | ||
2 | * MIDIUSB_test.ino | ||
3 | * | ||
4 | * Created: 4/6/2015 10:47:08 AM | ||
5 | * Author: gurbrinder grewal | ||
6 | * Modified by Arduino LLC (2015) | ||
7 | */ | ||
8 | |||
9 | #include "MIDIUSB.h" | ||
10 | #include <Wire.h> | ||
11 | |||
12 | #include "engine.h" | ||
13 | #include "config.h" | ||
14 | |||
15 | int led = 13; | ||
16 | |||
17 | enum { | ||
18 | MODE_STANDALONE = 0, | ||
19 | MODE_REPORTPOINTS = 1, | ||
20 | MODE_REPORTPOINTS_PLAY = 2, | ||
21 | } g_mode = MODE_REPORTPOINTS_PLAY; | ||
22 | |||
23 | /* | ||
24 | // First parameter is the event type (0x09 = note on, 0x08 = note off). | ||
25 | // Second parameter is note-on/note-off, combined with the channel. | ||
26 | // Channel can be anything between 0-15. Typically reported to the user as 1-16. | ||
27 | // Third parameter is the note number (48 = middle C). | ||
28 | // Fourth parameter is the velocity (64 = normal, 127 = fastest). | ||
29 | void noteOn(byte channel, byte pitch, byte velocity) { | ||
30 | midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity}; | ||
31 | MidiUSB.sendMIDI(noteOn); | ||
32 | } | ||
33 | |||
34 | void noteOff(byte channel, byte pitch, byte velocity) { | ||
35 | midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity}; | ||
36 | MidiUSB.sendMIDI(noteOff); | ||
37 | } | ||
38 | */ | ||
39 | |||
40 | void setup_pwm() { | ||
41 | // Set up the generic clock (GCLK4) used to clock timers | ||
42 | REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide the 48MHz clock source by divisor 2: 48MHz/2=24MHz | ||
43 | GCLK_GENDIV_ID(4); // Select Generic Clock (GCLK) 4 | ||
44 | while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization | ||
45 | |||
46 | REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW | ||
47 | GCLK_GENCTRL_GENEN | // Enable GCLK4 | ||
48 | GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source | ||
49 | GCLK_GENCTRL_ID(4); // Select GCLK4 | ||
50 | while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization | ||
51 | |||
52 | // Feed GCLK4 to TC4 and TC5 | ||
53 | REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK4 to TC4 and TC5 | ||
54 | GCLK_CLKCTRL_GEN_GCLK4 | // Select GCLK4 | ||
55 | GCLK_CLKCTRL_ID_TC4_TC5; // Feed the GCLK4 to TC4 and TC5 | ||
56 | while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization | ||
57 | |||
58 | REG_TC4_CTRLA |= TC_CTRLA_MODE_COUNT8; // Set the counter to 8-bit mode | ||
59 | while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization | ||
60 | |||
61 | REG_TC4_COUNT8_CC0 = 0; // Set the TC4 CC0 register to some arbitary value | ||
62 | while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization | ||
63 | REG_TC4_COUNT8_CC1 = 0; // Set the TC4 CC1 register to some arbitary value | ||
64 | while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization | ||
65 | REG_TC4_COUNT8_PER = 1; // Set the PER (period) register to flip each time | ||
66 | while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization | ||
67 | |||
68 | NVIC_DisableIRQ(TC4_IRQn); | ||
69 | NVIC_ClearPendingIRQ(TC4_IRQn); | ||
70 | // NVIC_SetPriority(TC4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest) | ||
71 | // NVIC_EnableIRQ(TC4_IRQn); // Connect TC4 to Nested Vector Interrupt Controller (NVIC) | ||
72 | |||
73 | REG_TC4_INTFLAG |= TC_INTFLAG_MC1 | TC_INTFLAG_MC0 | TC_INTFLAG_OVF; // Clear the interrupt flags | ||
74 | //REG_TC4_INTENSET = TC_INTENSET_MC1 | TC_INTENSET_MC0 | TC_INTENSET_OVF; // Enable TC4 interrupts | ||
75 | REG_TC4_INTENCLR = TC_INTENCLR_MC1 | TC_INTENCLR_MC0 | TC_INTENCLR_OVF; // Disable TC4 interrupts | ||
76 | |||
77 | int outpin = 15; | ||
78 | |||
79 | // Enable the port multiplexer for the digital pin D0 | ||
80 | PORT->Group[g_APinDescription[outpin].ulPort].PINCFG[g_APinDescription[outpin].ulPin].bit.PMUXEN = 1; | ||
81 | |||
82 | // Connect the TC4 timer to the port output D0 - port pins are paired odd PMUXO and even PMUXE | ||
83 | // Peripheral E specifies the TC timers, on this pin: TC4 | ||
84 | PORT->Group[g_APinDescription[outpin].ulPort].PMUX[g_APinDescription[outpin].ulPin >> 1].reg |= /*PORT_PMUX_PMUXO_E |*/ PORT_PMUX_PMUXE_E; | ||
85 | |||
86 | REG_TC4_CTRLA |= TC_CTRLA_PRESCALER_DIV1 | // Set prescaler to 1, 24MHz/1 = 24MHz | ||
87 | TC_CTRLA_ENABLE; // Enable TC4 | ||
88 | while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization | ||
89 | } | ||
90 | |||
91 | static void set_cam_register(uint8_t r, uint8_t v) { | ||
92 | Wire.beginTransmission(0x58); | ||
93 | Wire.write(r); | ||
94 | Wire.write(v); | ||
95 | Wire.endTransmission(); | ||
96 | } | ||
97 | |||
98 | static void setup_cam() { | ||
99 | set_cam_register(0x30, 0x01); | ||
100 | set_cam_register(0x06, 0x90); | ||
101 | set_cam_register(0x08, 0xc0); | ||
102 | set_cam_register(0x1a, 0x40); | ||
103 | set_cam_register(0x33, 0x01); | ||
104 | set_cam_register(0x30, 0x08); | ||
105 | } | ||
106 | |||
107 | void setup() { | ||
108 | pinMode(led, OUTPUT); | ||
109 | |||
110 | Wire.begin(); | ||
111 | digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) | ||
112 | setup_pwm(); | ||
113 | |||
114 | // Let PWM settle for a bit | ||
115 | delay(100); | ||
116 | setup_cam(); | ||
117 | |||
118 | Serial.begin(115200); | ||
119 | digitalWrite(led, LOW); // turn the LED on (HIGH is the voltage level) | ||
120 | } | ||
121 | |||
122 | void handle_wire() { | ||
123 | uint8_t ic2_result[32]; | ||
124 | char text[64]; | ||
125 | |||
126 | Wire.beginTransmission(0x58); | ||
127 | Wire.write(0x36); | ||
128 | Wire.endTransmission(); | ||
129 | Wire.requestFrom(0x58, 11); | ||
130 | |||
131 | for (int i=0; Wire.available() && i<=11; ++i) | ||
132 | ic2_result[i] = Wire.read(); | ||
133 | |||
134 | LPoint p1, p2, p3, p4; | ||
135 | |||
136 | int Ix1,Iy1,Ix2,Iy2; | ||
137 | int Ix3,Iy3,Ix4,Iy4; | ||
138 | int s; | ||
139 | |||
140 | s = ic2_result[3]; | ||
141 | p1.x = ((int)ic2_result[1]) | ( ( s << 4) & 0x300); | ||
142 | p1.y = ((int)ic2_result[2]) | ( ( s << 2) & 0x300); | ||
143 | p2.x = ((int)ic2_result[4]) | ( ( s << 8) & 0x300); | ||
144 | p2.y = ((int)ic2_result[5]) | ( ( s << 6) & 0x300); | ||
145 | |||
146 | s = ic2_result[8]; | ||
147 | p3.x = ((int)ic2_result[6]) | ( ( s << 4) & 0x300); | ||
148 | p3.y = ((int)ic2_result[7]) | ( ( s << 2) & 0x300); | ||
149 | p4.x = ((int)ic2_result[9]) | ( ( s << 8) & 0x300); | ||
150 | p4.y = ((int)ic2_result[10])| ( ( s << 6) & 0x300); | ||
151 | |||
152 | if (p1.x==1023 && p2.x==1023 && p3.x==1023 && p4.x==1023) | ||
153 | return; | ||
154 | |||
155 | long now = millis(); | ||
156 | if (g_mode==MODE_STANDALONE || g_mode==MODE_REPORTPOINTS_PLAY) { | ||
157 | if (p1.x!=1023) | ||
158 | engine_handle_point(&p1, now); | ||
159 | if (p2.x!=1023) | ||
160 | engine_handle_point(&p2, now); | ||
161 | if (p3.x!=1023) | ||
162 | engine_handle_point(&p3, now); | ||
163 | if (p4.x!=1023) | ||
164 | engine_handle_point(&p4, now); | ||
165 | } | ||
166 | |||
167 | if (g_mode==MODE_STANDALONE) | ||
168 | return; | ||
169 | if (p1.x!=1023) | ||
170 | Serial.write(text, sprintf(text, "%04d:%04d ", p1.x, p1.y)); | ||
171 | if (p2.x!=1023) | ||
172 | Serial.write(text, sprintf(text, "%04d:%04d ", p2.x, p2.y)); | ||
173 | if (p3.x!=1023) | ||
174 | Serial.write(text, sprintf(text, "%04d:%04d ", p3.x, p3.y)); | ||
175 | if (p4.x!=1023) | ||
176 | Serial.write(text, sprintf(text, "%04d:%04d ", p4.x, p4.y)); | ||
177 | Serial.println(""); | ||
178 | } | ||
179 | |||
180 | /* Do a fast nibble to hex representation conversion */ | ||
181 | static unsigned char fromhex(unsigned char x) { | ||
182 | x-='0'; if( x<=9) return x; | ||
183 | x&=~0x20; x-='A'-'0'; | ||
184 | if( x<6 ) return x+10; | ||
185 | return 0xff; | ||
186 | } | ||
187 | |||
188 | void handle_midi(char *command) { | ||
189 | // midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity}; | ||
190 | uint8_t m[6]; | ||
191 | /* expect 6 hex encoded MIDI bytes and a newline */ | ||
192 | for (int i=0; i<6; ++i) | ||
193 | if ((m[i] = fromhex(command[i])) == 0xff) | ||
194 | return; | ||
195 | if (command[6] != '\n') | ||
196 | return; | ||
197 | |||
198 | midiEventPacket_t p = { m[0], (m[0]<<4) | m[1], (m[2]<<4) | m[3], (m[4]<<4) | m[5] }; | ||
199 | MidiUSB.sendMIDI(p); | ||
200 | // MidiUSB.flush(); | ||
201 | } | ||
202 | |||
203 | void handle_configure(char *command) { | ||
204 | |||
205 | } | ||
206 | |||
207 | void handle_command(char *command) { | ||
208 | switch (*command) { | ||
209 | case 'M': /* Getting MIDI instruction */ | ||
210 | handle_midi(command+1); | ||
211 | break; | ||
212 | case 'S': /* Getting set mode instruction */ | ||
213 | switch (command[1]) { | ||
214 | case '1': | ||
215 | g_mode = MODE_STANDALONE; | ||
216 | break; | ||
217 | case '2': | ||
218 | g_mode = MODE_REPORTPOINTS_PLAY; | ||
219 | break; | ||
220 | case '3': | ||
221 | g_mode = MODE_REPORTPOINTS; | ||
222 | break; | ||
223 | default: | ||
224 | break; | ||
225 | } | ||
226 | break; | ||
227 | case 'C': /* Getting configure command */ | ||
228 | handle_configure(command+1); | ||
229 | break; | ||
230 | default: | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | void handle_serial() { | ||
236 | static char command[128]; | ||
237 | static int command_len; | ||
238 | static int skip_command; | ||
239 | |||
240 | while (Serial.available()) { | ||
241 | char c = command[command_len++] = Serial.read(); | ||
242 | if (c=='\n') { | ||
243 | if (!skip_command) { | ||
244 | command[command_len] = 0; | ||
245 | handle_command(command); | ||
246 | } | ||
247 | skip_command = 0; | ||
248 | command_len = 0; | ||
249 | // Read at max one command to allow polling the cam | ||
250 | return; | ||
251 | } | ||
252 | if (command_len==sizeof(command)) { | ||
253 | // If we end up at end of buffer, ignore everying to next \n | ||
254 | skip_command = 1; | ||
255 | command_len = 0; | ||
256 | } | ||
257 | } | ||
258 | } | ||
259 | |||
260 | void loop() { | ||
261 | static int led_state; | ||
262 | |||
263 | handle_wire(); | ||
264 | handle_serial(); | ||
265 | |||
266 | /* | ||
267 | Serial.write((const uint8_t*)"Sending note on\r\n", 17); | ||
268 | noteOn(0, note, 64); // Channel 0, middle C, normal velocity | ||
269 | MidiUSB.flush(); | ||
270 | delay(500); | ||
271 | digitalWrite(led, LOW); // turn the LED on (HIGH is the voltage level) | ||
272 | |||
273 | Serial.write((const uint8_t*)"Sending note off\r\n", 18); | ||
274 | noteOff(0, note, 64); // Channel 0, middle C, normal velocity | ||
275 | MidiUSB.flush(); | ||
276 | delay(1500); | ||
277 | */ | ||
278 | |||
279 | engine_checksilence(millis()); | ||
280 | digitalWrite(led, ++led_state & 1 ? HIGH : LOW); // turn the LED on (HIGH is the voltage level) | ||
281 | } | ||
282 | |||