diff options
author | Hans-Christoph Steiner <eighthave@users.sourceforge.net> | 2007-03-01 05:39:49 +0000 |
---|---|---|
committer | Hans-Christoph Steiner <eighthave@users.sourceforge.net> | 2007-03-01 05:39:49 +0000 |
commit | 7fc245694ab0cbb8d3fb516b18548e9246736c18 (patch) | |
tree | b88529d51a932c13bc18e791a0b7dd901a625017 /Pd_firmware | |
parent | 0b71f5237195b387f240469e3ca403382c8e8830 (diff) |
analog input is kind of working; pinMode is working; digital output is working; things are timer driven now
svn path=/trunk/externals/hardware/arduino/; revision=7453
Diffstat (limited to 'Pd_firmware')
-rw-r--r-- | Pd_firmware/Makefile | 8 | ||||
-rw-r--r-- | Pd_firmware/Pd_firmware.pde | 231 | ||||
-rw-r--r-- | Pd_firmware/press.wav | bin | 37568 -> 0 bytes |
3 files changed, 156 insertions, 83 deletions
diff --git a/Pd_firmware/Makefile b/Pd_firmware/Makefile index dada33c..0e4fdc7 100644 --- a/Pd_firmware/Makefile +++ b/Pd_firmware/Makefile @@ -43,7 +43,7 @@ # 7. Type "make upload", reset your Arduino board, and press enter to # upload your program to the Arduino board. # -# $Id: Makefile,v 1.3 2007-02-28 04:10:41 eighthave Exp $ +# $Id: Makefile,v 1.4 2007-03-01 05:39:49 eighthave Exp $ PORT = /dev/tty.usbserial-1* TARGET = Pd_firmware @@ -95,7 +95,7 @@ AVRDUDE_PROGRAMMER = stk500 AVRDUDE_PORT = $(PORT) AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ - -b $(UPLOAD_RATE) + -b $(UPLOAD_RATE) -q -V # Program settings CC = avr-gcc @@ -123,7 +123,7 @@ ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) # Default target. all: build - qtplay press.wav + say "press the button" make upload build: applet_files elf hex @@ -231,7 +231,7 @@ depend: # for emacs etags: make etags_`uname -s` - etags applet/*.cpp \ + etags *.pde \ $(ARDUINO_SRC)/*.[ch] \ $(ARDUINO_SRC)/*.cpp \ $(ARDUINO)/lib/targets/libraries/*/*.[ch] \ diff --git a/Pd_firmware/Pd_firmware.pde b/Pd_firmware/Pd_firmware.pde index a0ca913..775e010 100644 --- a/Pd_firmware/Pd_firmware.pde +++ b/Pd_firmware/Pd_firmware.pde @@ -42,8 +42,6 @@ /* * TODO: debug hardware PWM - * TODO: convert all non-frequent messages to SysEx (version, pinMode, report enable, etc) - * TODO: convert to MIDI protocol using SysEx for longer messages * TODO: add pulseOut functionality for servos * TODO: add software PWM for servos, etc (servo.h or pulse.h) * TODO: redesign protocol to accomodate boards with more I/Os @@ -52,22 +50,25 @@ * protocol, but will only support specific devices, like ultrasound * rangefinders or servos) * TODO: add "pinMode all 0/1" command + * TODO: try using PIND to get all digitalIns at once * TODO: add cycle markers to mark start of analog, digital, pulseIn, and PWM * TODO: use Program Control to load stored profiles from EEPROM */ -/* cvs version: $Id: Pd_firmware.pde,v 1.24 2007-02-22 06:16:43 eighthave Exp $ */ +/* cvs version: $Id: Pd_firmware.pde,v 1.25 2007-03-01 05:39:49 eighthave Exp $ */ -/*========================================================================== +/*============================================================================== * MESSAGE FORMATS - *==========================================================================*/ + *============================================================================*/ -/*---------------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * MAPPING DATA TO MIDI * * This protocol uses the MIDI message format, but does not use the whole - * protocol. Most of the command mappings here will not make sense in terms - * of MIDI controllers and synths. + * protocol. Most of the command mappings here will not be directly usable in + * terms of MIDI controllers and synths. It should co-exist with MIDI without + * trouble and can be parsed by standard MIDI interpreters. Just some of the + * message data is used differently. * * MIDI format: http://www.harmony-central.com/MIDI/Doc/table1.html * @@ -87,67 +88,78 @@ /* proposed extensions using SysEx * - * type SysEx start command data bytes SysEx stop - * --------------------------------------------------------------------------- - * pulse I/O 0xF0 0xA0 five 7-bit chunks, LSB first 0xF7 - * shiftOut 0xF0 0xB0 + * type SysEx start command data bytes SysEx stop + * ----------------------------------------------------------------------------- + * pulse I/O 0xF0 0xA0 five 7-bit chunks, LSB first 0xF7 + * shiftOut 0xF0 0xF5 dataPin; clockPin; 7-bit LSB; 7-bit MSB 0xF7 */ -/*---------------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * DATA MESSAGES */ /* two byte digital data format - * ---------------------- - * 0 digital data, 0x90-0x9F, (x & 0x0F) to get port base number + * ---------------------------- + * 0 digital data, 0x90-0x9F, (MIDI NoteOn, but different data usage) * 1 digital pins 0-6 bitmask * 2 digital pins 7-13 bitmask */ /* analog 14-bit data format - * ---------------------- - * 0 analog pin, 0xE0-0xEF, (x & 0x0F) for pin number + * ------------------------- + * 0 analog pin, 0xE0-0xEF, (MIDI Pitch Wheel) * 1 analog least significant 7 bits * 2 analog most significant 7 bits */ +/* version report format + * Send a single byte 0xF9, Arduino will reply with: + * ------------------------------------------------- + * 0 version report header (0xF9) (MIDI Undefined) + * 1 minor version (0-127) + * 2 major version (0-127) + */ + /* pulseIn/Out (uses 32-bit value) - * ---------------------- - * 0 START_SYSEX (0xF0) - * 1 pulseIn (0xFD) + * ------------------------------- + * 0 START_SYSEX (0xF0) (MIDI System Exclusive) + * 1 pulseIn/Out (0xA0-0xAF) * 2 bits 0-6 (least significant byte) * 3 bits 7-13 * 4 bits 14-20 * 5 bits 21-27 * 6 bits 28-34 (most significant byte) - * 7 END_SYSEX (0xF7) + * 7 END_SYSEX (0xF7) (MIDI End of SysEx - EOX) */ -/* version report format - * Send a single byte 0xF9, Arduino will reply with: - * ---------------------- - * 0 version report header (0xF9) (MIDI Undefined) - * 1 minor version (0-127) - * 2 major version (0-127) +/* shiftIn/Out (uses 8-bit value) + * ------------------------------ + * 0 START_SYSEX (0xF0) + * 1 shiftOut (0xF5) + * 2 dataPin (0-127) + * 3 clockPin (0-127) + * 4 bits 0-6 (least significant byte) + * 5 bit 7 (most significant bit) + * 6 END_SYSEX (0xF7) */ -/*---------------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * CONTROL MESSAGES */ /* set digital pin mode - * ---------------------- + * -------------------- * 1 set digital pin mode (0xF4) (MIDI Undefined) * 2 pin number (0-127) * 3 state (INPUT/OUTPUT, 0/1) */ /* toggle analogIn reporting by pin - * ---------------------- + * -------------------------------- * 0 toggle digitalIn reporting (0xC0-0xCF) (MIDI Program Change) * 1 disable(0)/enable(non-zero) */ /* toggle digitalIn reporting by port pairs - * ---------------------- + * ---------------------------------------- * 0 toggle digitalIn reporting (0xD0-0xDF) (MIDI Aftertouch) * 1 disable(0)/enable(non-zero) */ @@ -157,9 +169,9 @@ * 0 request version report (0xF9) (MIDI Undefined) */ -/*========================================================================== +/*============================================================================== * MACROS - *==========================================================================*/ + *============================================================================*/ /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. This number can be queried so that host @@ -169,7 +181,7 @@ #define MINOR_VERSION 0 // for backwards compatible changes /* total number of pins currently supported */ -#define TOTAL_ANALOG_PINS 16 +#define TOTAL_ANALOG_PINS 6 #define TOTAL_DIGITAL_PINS 14 // for comparing along with INPUT and OUTPUT @@ -187,9 +199,14 @@ #define REPORT_VERSION 0xF9 // report firmware version #define SYSTEM_RESET 0xFF // reset from MIDI -/*========================================================================== +/*============================================================================== * GLOBAL VARIABLES - *==========================================================================*/ + *============================================================================*/ + +// circular buffer for receiving bytes from the serial port +#define RINGBUFFER_MAX 64 // must be a power of 2 +byte ringBuffer[RINGBUFFER_MAX]; +byte readPosition=0, writePosition=0; // maximum number of post-command data bytes (non-SysEx) #define MAX_DATA_BYTES 2 @@ -198,9 +215,12 @@ byte waitForData = 0; byte executeMultiByteCommand = 0; // command to execute after getting multi-byte data byte storedInputData[MAX_DATA_BYTES] = {0,0}; // multi-byte data -/* this int serves as a bit-wise array to store pin status - * 0 = INPUT, 1 = OUTPUT */ -int digitalPinStatus = 0; +byte previousDigitalInputHighByte = 0; +byte previousDigitalInputLowByte = 0; +byte digitalInputHighByte = 0; +byte digitalInputLowByte = 0; +unsigned int digitalPinStatus = 65535;// bit-wise array to store pin status 0=INPUT, 1=OUTPUT + /* this byte stores the status off whether PWM is on or not * bit 9 = PWM0, bit 10 = PWM1, bit 11 = PWM2 @@ -208,14 +228,27 @@ int digitalPinStatus = 0; int pwmStatus = 0; /* bit-wise array to store pin reporting */ -unsigned int analogPinsToReport = 65536; +unsigned int analogPinsToReport = 65535; +/* for reading analogIns */ +byte analogPin = 0; +int analogData; +/* interrupt variables */ +volatile int int_counter = 0; // ms counter for scheduling -/*========================================================================== +/*============================================================================== * FUNCTIONS - *==========================================================================*/ + *============================================================================*/ +/* ----------------------------------------------------------------------------- + * output the version message to the serial port + */ +void printVersion() { + Serial.print(REPORT_VERSION, BYTE); + Serial.print(MINOR_VERSION, BYTE); + Serial.print(MAJOR_VERSION, BYTE); +} -/* ------------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * output digital bytes received from the serial port */ void outputDigitalBytes(byte pin0_6, byte pin7_13) { @@ -223,6 +256,7 @@ void outputDigitalBytes(byte pin0_6, byte pin7_13) { int mask; int twoBytesForPorts; +// this should be converted to use PORTs twoBytesForPorts = pin0_6 + (pin7_13 << 7); for(i=0; i<14; ++i) { mask = 1 << i; @@ -232,13 +266,13 @@ void outputDigitalBytes(byte pin0_6, byte pin7_13) { } } -/* ------------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * processInput() is called whenever a byte is available on the * Arduino's serial port. This is where the commands are handled. */ void processInput(int inputData) { int command, channel; - + // a few commands have byte(s) of data following the command if( (waitForData > 0) && (inputData < 128) ) { waitForData--; @@ -250,10 +284,12 @@ void processInput(int inputData) { channel = inputData & 0x0F; // get channel from command byte break; case DIGITAL_MESSAGE: - outputDigitalBytes(storedInputData[1], storedInputData[0]); - break; + outputDigitalBytes(storedInputData[1], storedInputData[0]); // (LSB, MSB) + break; case SET_DIGITAL_PIN_MODE: - setPinMode(storedInputData[1], storedInputData[0]); + setPinMode(storedInputData[1], storedInputData[0]); // (pin#, mode) + //if(storedInputData[0] == INPUT) // enable input if set to INPUT + // TODO: enable REPORT_DIGITAL_PORTS break; case REPORT_ANALOG_PIN: break; @@ -261,7 +297,7 @@ void processInput(int inputData) { break; } executeMultiByteCommand = 0; - } + } } else { // remove channel info from command byte if less than 0xF0 if(inputData < 0xF0) { @@ -285,16 +321,14 @@ void processInput(int inputData) { // this doesn't do anything yet break; case REPORT_VERSION: - Serial.print(REPORT_VERSION, BYTE); - Serial.print(MINOR_VERSION, BYTE); - Serial.print(MAJOR_VERSION, BYTE); + printVersion(); break; } } } -/* ------------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * this function checks to see if there is data waiting on the serial port * then processes all of the stored data */ @@ -304,11 +338,11 @@ void processInput(int inputData) { * Therefore, it only checks for input once per cycle of the serial port. */ void checkForInput() { - if(Serial.available()) - processInput( Serial.read() ); + while(Serial.available()) + processInput( Serial.read() ); } -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /* this function sets the pin mode to the correct state and sets the relevant * bits in the two bit-arrays that track Digital I/O and PWM status */ @@ -316,6 +350,7 @@ void setPinMode(byte pin, byte mode) { if(mode == INPUT) { digitalPinStatus = digitalPinStatus &~ (1 << pin); pwmStatus = pwmStatus &~ (1 << pin); + digitalWrite(pin,LOW); // turn off pin before switching to INPUT pinMode(pin,INPUT); } else if(mode == OUTPUT) { @@ -331,27 +366,49 @@ void setPinMode(byte pin, byte mode) { // TODO: save status to EEPROM here, if changed } -// ========================================================================= +// ============================================================================= // used for flashing the pin for the version number void pin13strobe(int count, int onInterval, int offInterval) { byte i; + pinMode(13, OUTPUT); for(i=0; i<count; i++) { + delay(offInterval); digitalWrite(13,1); delay(onInterval); digitalWrite(13,0); - delay(offInterval); } } -/*========================================================================== +// ----------------------------------------------------------------------------- +/* handle timer interrupts - Arduino runs at 16 Mhz, so we have 1000 Overflows + * per second... 1/ ((16000000 / 64) / 256) = 1 / 1000 */ +ISR(TIMER2_OVF_vect) { + int_counter++; +}; + +/*============================================================================== * SETUP() - *==========================================================================*/ + *============================================================================*/ void setup() { byte i; // TODO: load state from EEPROM here - Serial.begin(115200); // 9600, 14400, 38400, 57600, 115200 + Serial.begin(57600); // 9600, 14400, 38400, 57600, 115200 + + /* set up timer interrupt */ + //Timer2 Settings: Timer Prescaler /64, + TCCR2 |= (1<<CS22); + TCCR2 &= ~((1<<CS21) | (1<<CS20)); + // Use normal mode + TCCR2 &= ~((1<<WGM21) | (1<<WGM20)); + // Use internal clock - external clock not used in Arduino + ASSR |= (0<<AS2); + //Timer2 Overflow Interrupt Enable + TIMSK |= (1<<TOIE2) | (0<<OCIE2); +// RESET_TIMER2; + sei(); + /* TODO: send digital inputs here, if enabled, to set the initial state on the * host computer, since once in the loop(), the Arduino will only send data on @@ -369,31 +426,47 @@ void setup() { delay(500); pin13strobe(10,5,20); // separator, a quick burst delay(1000); + printVersion(); + for(i=0; i<TOTAL_DIGITAL_PINS; ++i) { setPinMode(i,OUTPUT); } } -/*========================================================================== +/*============================================================================== * LOOP() - *==========================================================================*/ + *============================================================================*/ void loop() { - int i; // counter for analog pins - int analogData; - - checkForInput(); - /* get analog in, for the number enabled */ - for(i=0; i<TOTAL_ANALOG_PINS; ++i) { - checkForInput(); - //if( analogPinsToReport & (1 << i) ) { - analogData = analogRead(i); - /* These two bytes get converted back into the whole number on host. - Highest bits should be zeroed so the 8th bit doesn't get set */ - checkForInput(); - Serial.print(ANALOG_MESSAGE + i, BYTE); - Serial.print(analogData % 128, BYTE); // mod by 32 for the small byte - Serial.print(analogData >> 7, BYTE); // shift high bits into output byte + +/* DIGITALREAD - as fast as possible, check for changes and output them to the + * FTDI buffer using serialWrite) */ + +// this should use _SFR_IO8() + + if(int_counter > 3) { + + +/* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle all + * serialReads at once, i.e. empty the buffer */ + checkForInput(); + +/* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over 60 + * bytes. use a timer to sending an event character every 4 ms to trigger the + * buffer to dump. */ + +/* ANALOGREAD - right after the event character, do all of the analogReads(). + * These only need to be done every 4ms. */ +// for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) { + for(analogPin=0;analogPin<2;analogPin++) { + //if( analogPinsToReport & (1 << analogPin) ) { + analogData = analogRead(analogPin); + Serial.print(ANALOG_MESSAGE + analogPin, BYTE); + // These two bytes converted back into the 10-bit value on host + Serial.print(analogData & 127, BYTE); // same as analogData % 128 + Serial.print(analogData >> 7, BYTE); + analogPin = (analogPin++) % TOTAL_ANALOG_PINS; //} - checkForInput(); + } + int_counter = 0; // reset ms counter } } diff --git a/Pd_firmware/press.wav b/Pd_firmware/press.wav Binary files differdeleted file mode 100644 index dfb181b..0000000 --- a/Pd_firmware/press.wav +++ /dev/null |