/* * This goal of the application is to set the digital output on pins 8-13 * This can be accomplished in three ways. First, a serial command can directly set * the digital output pattern. Second, a series of patterns can be stored in the * Arduino and TTLs coming in on pin 2 will then trigger to the consecutive pattern (trigger mode). * Third, intervals between consecutive patterns can be specified and paterns will be * generated at these specified time points (timed trigger mode). * * Interface specifications: * digital pattern specification: single byte, bit 0 corresponds to pin 8, * bit 1 to pin 9, etc.. Bits 7 and 8 will not be used (and should stay 0). * * Set digital output command: 1p * Where p is the desired digital pattern. Controller will return 1 to * indicate succesfull execution. * * Get digital output command: 2 * Controller will return 2p. Where p is the current digital output pattern * * Set Analogue output command: 3xvv * Where x is the output channel (either 1 or 2), and vv is the output in a * 12-bit significant number. * Controller will return 3xvv: * * Get Analogue output: 4 * * * Set digital patten for triggered mode: 5xd * Where x is the number of the pattern (currently, 12 patterns can be stored). * and d is the digital pattern to be stored at that position. Note that x should * be the real number (i.e., not ASCI encoded) * Controller will return 5xd * * Set the Number of digital patterns to be used: 6x * Where x indicates how many digital patterns will be used (currently, up to 12 * patterns maximum). In triggered mode, after reaching this many triggers, * the controller will re-start the sequence with the first pattern. * Controller will return 6x * * Skip trigger: 7x * Where x indicates how many digital change events on the trigger input pin * will be ignored. * Controller will respond with 7x * * Start trigger mode: 8 * Controller will return 8 to indicate start of triggered mode * Stop triggered mode by sending any key (including new commands, that will be * processed). Trigger mode will stop blanking mode (if it was active) * * Get result of Trigger mode: 9 * Controller will return 9x where x is the number of triggers received during the last * trigger mode run * * Set time interval for timed trigger mode: 10xtt * Where x is the number of the interval (currently, 12 intervals can be stored) * and tt is the interval (in ms) in Arduino unsigned int format. * Controller will return 10x * * Sets how often the timed pattern will be repeated: 11x * This value will be used in timed-trigger mode and sets how often the output * pattern will be repeated. * Controller will return 11x * * Starts timed trigger mode: 12 * In timed trigger mode, digital patterns as set with function 5 will appear on the * output pins with intervals (in ms) as set with function 10. After the number of * patterns set with function 6, the pattern will be repeated for the number of times * set with function 11. Any input character (which will be processed) will stop * the pattern generation. * Controller will retun 12. * * Start blanking Mode: 20 * In blanking mode, zeroes will be written on the output pins when the trigger pin * is low, when the trigger pin is high, the pattern set with command #1 will be * applied to the output pins. * Controller will return 20 * * Stop blanking Mode: 21 * Stops blanking mode. Controller returns 21 * * Blanking mode trigger direction: 22x * Sets whether to blank on trigger high or trigger low. x=0: blank on trigger high, * x=1: blank on trigger low. x=0 is the default * Controller returns 22 * * * Get Identification: 30 * Returns (asci!) MM-Ard\r\n * * Get Version: 31 * Returns: version number (as ASCI string) \r\n * * Read digital state of analogue input pins 0-5: 40 * Returns raw value of PINC (two high bits are not used) * * Read analogue state of pint pins 0-5: 41x * x=0-5. Returns analogue value as a 10-bit number (0-1023) * * * * Possible extensions: * Set and Get Mode (low, change, rising, falling) for trigger mode * Get digital patterm * Get Number of digital patterns */ unsigned int version_ = 2; // pin on which to receive the trigger (either 2 or 3, changed attachInterrupt accordingly) int inPin_ = 2; // pin connected to DIN of TLV5618 int dataPin = 3; // pin connected to SCLK of TLV5618 int clockPin = 4; // pin connected to CS of TLV5618 int latchPin = 5; const int SEQUENCELENGTH = 12; // this should be good enough for everybody;) byte triggerPattern_[SEQUENCELENGTH] = {0,0,0,0,0,0,0,0,0,0,0,0}; unsigned int triggerDelay_[SEQUENCELENGTH] = {0,0,0,0,0,0,0,0,0,0,0,0}; int patternLength_ = 0; byte repeatPattern_ = 0; volatile int triggerNr_; // total # of triggers in this run (0-based) volatile int sequenceNr_; // # of trigger in sequence (0-based) int skipTriggers_ = 0; // # of triggers to skip before starting to generate patterns byte currentPattern_ = 0; const unsigned long timeOut_ = 1000; bool blanking_ = false; bool blankOnHigh_ = true; void setup() { // Higher speeds do not appear to be reliable Serial.begin(57600); pinMode(inPin_, INPUT); pinMode (dataPin, OUTPUT); pinMode (clockPin, OUTPUT); pinMode (latchPin, OUTPUT); pinMode(8, OUTPUT); pinMode(9, OUTPUT); pinMode(10, OUTPUT); pinMode(11, OUTPUT); pinMode(12, OUTPUT); pinMode(13, OUTPUT); // Set analogue pins as input: DDRC = DDRC & B11000000; // Turn on build-in pull-up resistors PORTC = PORTC | B00111111; digitalWrite(latchPin, HIGH); } void loop() { if (Serial.available() > 0) { int inByte = Serial.read(); switch (inByte) { // Set digital output case 1 : if (waitForSerial(timeOut_)) { currentPattern_ = Serial.read(); // Do not set bits 6 and 7 (not sure if this is needed..) currentPattern_ = currentPattern_ & B00111111; if (!blanking_) PORTB = currentPattern_; Serial.print(1, BYTE); } break; // Get digital output case 2: Serial.print(2, BYTE); Serial.print(PORTB, BYTE); break; // Set Analogue output (TODO: save for 'Get Analogue output') case 3: if (waitForSerial(timeOut_)) { int channel = Serial.read(); if (waitForSerial(timeOut_)) { byte msb = Serial.read(); msb &= B00001111; if (waitForSerial(timeOut_)) { byte lsb = Serial.read(); analogueOut(channel, msb, lsb); Serial.print(3, BYTE); Serial.print(channel, BYTE); Serial.print(msb, BYTE); Serial.print(lsb, BYTE); } } } break; // Sets the specified digital pattern case 5: if (waitForSerial(timeOut_)) { int patternNumber = Serial.read(); if ( (patternNumber >= 0) && (patternNumber < SEQUENCELENGTH) ) { if (waitForSerial(timeOut_)) { triggerPattern_[patternNumber] = Serial.read(); triggerPattern_[patternNumber] = triggerPattern_[patternNumber] & B00111111; Serial.print(5, BYTE); Serial.print(patternNumber, BYTE); Serial.print(triggerPattern_[patternNumber], BYTE); break; } } } Serial.print("n:"); break; // Sets the number of digital patterns that will be used case 6: if (waitForSerial(timeOut_)) { int pL = Serial.read(); if ( (pL >= 0) && (pL <= 12) ) { patternLength_ = pL; Serial.print(6, BYTE); Serial.print(patternLength_, BYTE); } } break; // Skip triggers case 7: if (waitForSerial(timeOut_)) { skipTriggers_ = Serial.read(); Serial.print(7, BYTE); Serial.print(skipTriggers_, BYTE); } break; // starts trigger mode case 8: if (patternLength_ > 0) { sequenceNr_ = 0; triggerNr_ = -skipTriggers_; int state = digitalRead(inPin_); PORTB = B00000000; Serial.print(8, BYTE); while (Serial.available() == 0) { int tmp = digitalRead(inPin_); if (tmp != state) { if (triggerNr_ >=0) { PORTB = triggerPattern_[sequenceNr_]; sequenceNr_++; if (sequenceNr_ >= patternLength_) sequenceNr_ = 0; } triggerNr_++; } state = tmp; } PORTB = B00000000; } break; // return result from last triggermode case 9: Serial.print(9, BYTE); Serial.print(triggerNr_, BYTE); break; // Sets time interval for timed trigger mode // Tricky part is that we are getting an unsigned int as two bytes case 10: if (waitForSerial(timeOut_)) { int patternNumber = Serial.read(); if ( (patternNumber >= 0) && (patternNumber < SEQUENCELENGTH) ) { if (waitForSerial(timeOut_)) { unsigned int highByte = 0; unsigned int lowByte = 0; highByte = Serial.read(); if (waitForSerial(timeOut_)) lowByte = Serial.read(); highByte = highByte << 8; triggerDelay_[patternNumber] = highByte | lowByte; Serial.print(10, BYTE); Serial.print(patternNumber, BYTE); break; } } } break; // Sets the number of times the patterns is repeated in timed trigger mode case 11: if (waitForSerial(timeOut_)) { repeatPattern_ = Serial.read(); Serial.print(11, BYTE); Serial.print(repeatPattern_, BYTE); } break; // starts timed trigger mode case 12: if (patternLength_ > 0) { PORTB = B00000000; Serial.print(12, BYTE); for (byte i = 0; i < repeatPattern_ && (Serial.available() == 0); i++) { for (int j = 0; j < patternLength_ && (Serial.available() == 0); j++) { PORTB = triggerPattern_[j]; delay(triggerDelay_[j]); } } PORTB = B00000000; } break; // Blanks output based on TTL input case 20: blanking_ = true; Serial.print(20, BYTE); break; // Stops blanking mode case 21: blanking_ = false; Serial.print(21, BYTE); break; // Sets 'polarity' of input TTL for blanking mode case 22: if (waitForSerial(timeOut_)) { int mode = Serial.read(); if (mode==0) blankOnHigh_= true; else blankOnHigh_= false; } Serial.print(22, BYTE); break; // Gives identification of the device case 30: Serial.println("MM-Ard"); break; // Returns version string case 31: Serial.println(version_); break; case 40: Serial.print(40, BYTE); Serial.print(PINC, BYTE); break; case 41: if (waitForSerial(timeOut_)) { int pin = Serial.read(); if (pin >= 0 && pin <=5) { int val = analogRead(pin); Serial.print(41, BYTE); Serial.print(pin, BYTE); Serial.print(highByte(val), BYTE); Serial.print(lowByte(val), BYTE); } } break; case 42: if (waitForSerial(timeOut_)) { int pin = Serial.read(); if (waitForSerial(timeOut_)) { int state = Serial.read(); Serial.print(42, BYTE); Serial.print(pin, BYTE); if (state == 0) { digitalWrite(14+pin, LOW); Serial.print(0, BYTE); } if (state == 1) { digitalWrite(14+pin, HIGH); Serial.print(1, BYTE); } } } break; } } if (blanking_) { if (blankOnHigh_) { if (digitalRead(inPin_) == LOW) PORTB = currentPattern_; else PORTB = 0; } else { if (digitalRead(inPin_) == LOW) PORTB = 0; else PORTB = currentPattern_; } } } bool waitForSerial(unsigned long timeOut) { unsigned long startTime = millis(); while (Serial.available() == 0 && (millis() - startTime < timeOut) ) {} if (Serial.available() > 0) return true; return false; } // Sets analogue output in the TLV5618 // channel is either 0 ('A') or 1 ('B') // value should be between 0 and 4095 (12 bit max) // pins should be connected as described above void analogueOut(int channel, byte msb, byte lsb) { digitalWrite(latchPin, LOW); msb &= B00001111; if (channel == 0) msb |= B10000000; // Note that in all other cases, the data will be written to DAC B and BUFFER shiftOut(dataPin, clockPin, MSBFIRST, msb); shiftOut(dataPin, clockPin, MSBFIRST, lsb); // The TLV5618 needs one more toggle of the clockPin: digitalWrite(clockPin, HIGH); digitalWrite(clockPin, LOW); digitalWrite(latchPin, HIGH); } /* // This function is called through an interrupt void triggerMode() { if (triggerNr_ >=0) { PORTB = triggerPattern_[sequenceNr_]; sequenceNr_++; if (sequenceNr_ >= patternLength_) sequenceNr_ = 0; } triggerNr_++; } void blankNormal() { if (DDRD & B00000100) { PORTB = currentPattern_; } else PORTB = 0; } void blankInverted() { if (DDRD & B00000100) { PORTB = 0; } else { PORTB = currentPattern_; } } */