diff options
| author | erdgeist <erdgeist@bauklotz.fritz.box> | 2016-08-12 14:47:28 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@bauklotz.fritz.box> | 2016-08-12 14:47:28 +0200 |
| commit | 830ec9041b5b70782f5a3781d27af9b149c028b1 (patch) | |
| tree | ebdd5e8719d03c8b94d6bff1072a27298dea5c84 | |
| parent | a8be0d3d20f07d4561826b01f566ca307eb23526 (diff) | |
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 | |||
