// MIDI Filter /* VPP | 1 18 | 3.3V midi ch 0 | 2 17 | GND midi ch 1 | 3 16 | LED Out midi ch 2 | 4 15 | -> MIDI Out midi ch 3 | 5 14 | VCAP XTAL | 6 13 | GND XTAL | 7 12 | Send Next Channel Also ICSP | 8 11 | Spare Input ICSP | 9 10 | <- MIDI in */ #include #include // FBS #pragma config BWRP = WRPROTECT_OFF // Boot Segment Write Protect (Boot Segment may be written) #pragma config BSS = NO_FLASH // Boot Segment Program Flash Code Protection (No Boot program Flash segment) // FGS #pragma config GWRP = OFF // General Code Segment Write Protect (User program memory is not write-protected) #pragma config GSS = OFF // General Segment Code Protection (User program memory is not code-protected) // FOSCSEL #pragma config FNOSC = PRI // Oscillator Mode (Primary Oscillator (XT, HS, EC)) #pragma config IESO = OFF // Internal External Switch Over Mode (Start-up device with user-selected oscillator source) // FOSC #pragma config POSCMD = HS // Primary Oscillator Source (HS Oscillator Mode) #pragma config OSCIOFNC = ON // OSC2 Pin Function (OSC2 pin has digital I/O function) #pragma config IOL1WAY = OFF // Peripheral Pin Select Configuration (Allow Multiple Re-configurations) #pragma config FCKSM = CSDCMD // Clock Switching and Monitor (Both Clock Switching and Fail-Safe Clock Monitor are disabled) // FWDT #pragma config WDTPOST = PS32768 // Watchdog Timer Postscaler (1:32,768) #pragma config WDTPRE = PR128 // WDT Prescaler (1:128) #pragma config WINDIS = OFF // Watchdog Timer Window (Watchdog Timer in Non-Window mode) #pragma config FWDTEN = OFF // Watchdog Timer Enable (Watchdog timer enabled/disabled by user software) // FPOR #pragma config FPWRT = PWR8 // POR Timer Value (8ms) #pragma config ALTI2C = OFF // Alternate I2C pins (I2C mapped to SDA1/SCL1 pins) // FICD #pragma config ICS = PGD2 // Comm Channel Select (Communicate on PGC2/EMUC2 and PGD2/EMUD2) #pragma config JTAGEN = OFF // JTAG Port Enable (JTAG is Disabled) //Midi Status Messages #define SYSTEM_EXCLUSIVE 0xF0 #define MIDI_TIME_CODE 0xF1 #define SONG_POS 0xF2 #define SONG_SELECT 0xF3 #define TUNE_REQUEST 0xF6 unsigned int midiChannelNumber; unsigned int sendNextChannelAlso = 0; unsigned int sendingThisMessage = 0; unsigned char garbage; #define BUFFER_SIZE 256 volatile unsigned char midiBuffer[BUFFER_SIZE]; volatile unsigned int putCounter = 0; volatile unsigned int getCounter = 0; volatile unsigned int midiByteToProcess; void __attribute__ ((interrupt, no_auto_psv)) _U1RXInterrupt(void){ //LATBbits.LATB15 ^= 1; if(U1STAbits.FERR){ if(U1STAbits.URXDA) { garbage = U1RXREG; } IFS0bits.U1RXIF =0; } else if(U1STAbits.OERR){ garbage = U1RXREG; U1STA = 0x480; U1STA = 0x490; if(IFS0bits.U1RXIF) garbage = U1RXREG; IFS0bits.U1RXIF = 0; } else { midiBuffer[putCounter] = U1RXREG; putCounter++; if(putCounter == BUFFER_SIZE) { putCounter = 0; } IFS0bits.U1RXIF =0; } } void _DefaultInterrupt(void){ while(1); } void __attribute__ ((interrupt, no_auto_psv)) _T1Interrupt(void) { IFS0bits.T1IF = 0; /* Clear Left Channel Interrupt Flag */ if(PORTBbits.RB9){ sendNextChannelAlso = 0; } else sendNextChannelAlso = 1; midiChannelNumber = ((PORTB & 0b11)<<2) + (PORTA & 0b11); midiChannelNumber ^= 0b1111; LATBbits.LATB15 ^= 1; } inline void ProcessMidi(){ if(midiByteToProcess & 128){ //STATUS MESSAGE //status messages that are bigger or equal to 0xF0 //are system messages, not channel messages //This includes things such as timing clocks and Start/Stop //song messages if(midiByteToProcess >= 0xF0){ sendingThisMessage = 1; U1TXREG = (0xff & midiByteToProcess); //WARNING!!! look at below - need to recheck sendingThisMessage = 0; } else if( (midiByteToProcess & 0x0f) == midiChannelNumber ){ sendingThisMessage = 1; U1TXREG = (0xff & midiByteToProcess); } else if( (midiByteToProcess & 0x0f) == (midiChannelNumber+1) ){ if(sendNextChannelAlso){ sendingThisMessage = 1; U1TXREG = (0xff & midiByteToProcess); } else { sendingThisMessage = 0; //not sending next ch } } else { sendingThisMessage = 0; } } else { //databyte if(sendingThisMessage){ U1TXREG = (0xff & midiByteToProcess); } } } void Init(){ LATA = LATB = 0; PORTA = PORTB = 0; TRISA = TRISB = 0; ADPCFG = 0xff; //Disable ADC inputs //MIDI Channel Switch Inputs TRISAbits.TRISA0 = 1; TRISAbits.TRISA1 = 1; TRISBbits.TRISB0 = 1; TRISBbits.TRISB1 = 1; //Enable weak pull-ups CNPU1bits.CN2PUE = 1; CNPU1bits.CN3PUE = 1; CNPU1bits.CN4PUE = 1; CNPU1bits.CN5PUE = 1; //Next Channel Switch Input TRISBbits.TRISB9 = 1; CNPU2bits.CN21PUE = 1; //Spare Switch Input TRISBbits.TRISB8 = 1; CNPU2bits.CN22PUE = 1; //Set RP7 as RX input RPINR18bits.U1RXR = 0b00111; TRISBbits.TRISB7 = 1; //RP14 is tied to UART Tx (00011) RPOR7bits.RP14R = 0b00011; U1MODE = 0; U1BRG = 7; /* baud rate = Fcy / (16*(U1brg + 1)) U1brg = ( Fcy / (16 * baud rate) ) - 1 */ IFS0bits.U1RXIF = 0; IEC0bits.U1RXIE = 1; U1MODEbits.UARTEN = 1; U1STAbits.UTXEN = 1; //must come after uarten } int main( void ){ Init(); TMR1 = T1CON = 0; T1CONbits.TCKPS = 0b01; IFS0bits.T1IF = 0; // Clear Timer1 Interrupt Flag IEC0bits.T1IE = 1; // Enable Timer1 interrupt asm("BSET T1CON, #15");// ; Turn ON the module garbage = U1RXREG; garbage = U1RXREG; garbage = U1RXREG; garbage = U1RXREG; while(1==1){ if(putCounter != getCounter){ midiByteToProcess = midiBuffer[getCounter]; getCounter++; if(getCounter==BUFFER_SIZE) getCounter=0; ProcessMidi(); } asm("PWRSAV #1"); //Sleep! } return 0; }