/* ** Control logic for Goldilocks DAC ** www.myprius.co.za ** 2012, AJ BREDEKAMP */ #include #define FIFO_SIZE 2 // storage locations in FIFO unsigned int FIFO_L[FIFO_SIZE]; //buffer holding LEFT samples [0];[1] unsigned int FIFO_R[FIFO_SIZE]; //buffer holding RIGHT samples [0];[1] volatile int FIFO_WRITE = 0; //read/write at opposite locations volatile int FIFO_READ = 1; //both FIFO_L and FIFO_R will use the same pointers to make sure they remain synchronized void __attribute__((__interrupt__, no_auto_psv)) _T3Interrupt(void) { FIFO_READ = FIFO_READ ^ 1; SPI1BUF = FIFO_L[FIFO_READ]; SPI2BUF = FIFO_R[FIFO_READ]; IFS0bits.T3IF = 0; // Clear Timer3 Interrupt Flag } void __attribute__((__interrupt__, no_auto_psv)) _DCIInterrupt(void) { /* if (_RB15 == 0) FIFO_L[FIFO_WRITE]= RXBUF0; else FIFO_R[FIFO_WRITE]= RXBUF0; FIFO_WRITE = FIFO_WRITE ^ 1; */ IFS3bits.DCIIF = 0; } int main() { // Initializations---------------------------------------------------------------------------------------- FIFO_L[0] = 0b0111111111111110; // dummy data for testing FIFO_R[0] = 0b0101011100010010; // FIFO_L[1] = 0b0000000000000000; // FIFO_R[1] = 0b0000000100000000; // // Set Oscillator Configuration for 33.8688 MIPS OSCCON = 0x0300; // 01100000000 --> Primary oscillator (XT, HS, EC) with PLL CLKDIV = 0x0000; PLLFBD = 0x001E; // 11110 --> /32 PLLDIV DAC1CONbits.DACEN = 0; // Disable DAC AD1CON1bits.ADON = 0; // Disable ADC AD1PCFGL = 0b0001111111111111; // Select analog port pins as digital I/O pins (AD1PCFGH<15:0> or AD1PCFGL<15:0>) // --------------------------------------------------- // *************************************************** // PERIPHERAL PINS------------------------------------ // Configure Peripheral pin select registers TRISB = 0b0000000001110000; // RPOR1bits.RP3R = 7; // SPI1 - SDO1 00111 RP3 tied to SPI1 Data Output, RP3R<4:0> - LEFT Audio data out RPOR4bits.RP9R = 8; // SPI1 - SCK1 01000 RP9 tied to SPI1 Clock Output RPOR1bits.RP2R = 10; // SPI2 - SDO2 01010 RP2 tied to SPI2 Data Output, RP2R<4:0> - RIGHT Audio data out // SPI2 - SCK2 01011 RP4 tied to SPI2 Clock Output NOT USED RPOR4bits.RP8R = 18; // OC1 10010 RP8 tied to Output Compare 1, RP8R<4:0> - CLOX RPOR3bits.RP7R = 19; // OC2 10011 RP7 tied to Output Compare 2, RP7R<4:0> - STR1 RPINR24bits.CSCKR = 6; // DCI Serial Clock Input CSCK RPINR24 CSCKR<4:0>, RP6 - BCK RPINR24bits.CSDIR = 5; // DCI Serial Data Input CSDI RPINR24 CSDIR<4:0>, RP5 - PCM DATA IN RPINR25bits.COFSR = 4; // DCI Frame Sync Input COFS RPINR25 COFSR<4:0>, RP4 - LRCK // Configure SPI1 and SPI2 modules IFS0bits.SPI1IF = 0; // Clear the Interrupt Flag IEC0bits.SPI1IE = 0; // Disable the Interrupt SPI1CON1 = 0b0000011100111001; // Primary Prescale 16:1,Secondary prescale 2:1,Master Mode ENABLE,16 bit mode, / 16 ; SPI1CON2 = 0x0000; SPI1STAT = 0x8000; // enable SPI port IFS0bits.SPI1IF = 0; // Clear the Interrupt Flag IEC0bits.SPI1IE = 0; // Disable the Interrupt IFS2bits.SPI2IF = 0; // Clear the Interrupt Flag IEC2bits.SPI2IE = 0; // Disable the Interrupt SPI2CON1 = 0b0000011100111001; // Primary Prescale 16:1,Secondary prescale 2:1,Master Mode ENABLE,16 bit mode, / 16 ; SPI2CON2 = 0x0000; SPI2STAT = 0x8000; // enable SPI port IFS2bits.SPI2IF = 0; // Clear the Interrupt Flag IEC2bits.SPI2IE = 0; // Disable the Interrupt // ---------------------------------------------------- // **************************************************** // OUTPUT COMPARE MODULES------------------------------ // Setup Output Compare Module 1 for Toggle Mode -- OUTPUT = Fs x 384 = 16934400 Hz/4 = 4233600 Hz // Used to clock SAA7030 Digital Filter --> CLOX // Associated with Timer 2 OC1CONbits.OCM = 0b000; // Disable Output Compare Module OC1CONbits.OCM = 0b010; // Define Initial State for OC1 Pin (High if OCM=0b010) OC1CONbits.OCM = 0b000; // Disable Output Compare Module OC1CONbits.OCTSEL = 0; // Select Timer2 as output compare time base OC1R = 0; // Load the Compare Register Value IPC0bits.OC1IP = 0x01; // Set Output Compare 1 Interrupt Priority Level IFS0bits.OC1IF = 0; // Clear Output Compare 1 Interrupt Flag IEC0bits.OC1IE = 0; // Disable Output Compare 1 interrupt OC1CONbits.OCM = 0b011; // Select the Output Compare mode, Toggle Mode // Setup Output Compare Module 2 in Continuous Pulse mode // Used for SAA7030 STR1 strobe, frequency 44.1kHz. Rising edge follows completion of SAA7030 input data stream // Associated with Timer 3 OC2CONbits.OCM = 0b000; // Disable Output Compare Module OC2CONbits.OCTSEL = 1; // Select Timer 3 as output compare time base OC2R = 1435; // Load the Compare Register Value for rising edge OC2RS = 1485; // Load the Compare Register Value for falling edge IPC1bits.OC2IP = 0x01; // Set Output Compare 2 Interrupt Priority Level IFS0bits.OC2IF = 0; // Clear Output Compare 2 Interrupt Flag IEC0bits.OC2IE = 0; // Disable Output Compare 2 interrupt OC2CONbits.OCM = 0b101; // Select the Output Compare mode, Continuous Pulse mode // ---------------------------------------------------- // **************************************************** // TIMERS---------------------------------------------- // Initialize and enable Timer2 // Clock Timer 2 from internal clock source Fosc T2CONbits.TON = 0; // Disable Timer T2CONbits.TCS = 0; // Select internal instruction cycle clock T2CONbits.TGATE = 0; // Disable Gated Timer mode T2CONbits.TCKPS = 0b00; // Select 1:1 Prescaler TMR2 = 0x00; // Clear timer register PR2 = 7; // Load the period value, Timer is reset on period match // This value takes Fosc (33.8688MHz) and divide by 8 --> 4.2336MHz --> CLOX of SAA7030 IPC1bits.T2IP = 0x01; // Set Timer2 Interrupt Priority Level IFS0bits.T2IF = 0; // Clear Timer2 Interrupt Flag IEC0bits.T2IE = 0; // Disable Timer2 interrupt // Initialize and enable Timer3 // Clock Timer 3 from internal clock source Fosc T3CONbits.TON = 0; // Disable Timer T3CONbits.TCS = 0; // Select internal instruction cycle clock T3CONbits.TGATE = 0; // Disable Gated Timer mode T3CONbits.TCKPS = 0b00; // Select 1:1 Prescaler TMR3 = 0x00; // Clear timer register PR3 = 1535; // Load the period value, Timer is reset on period match // This value takes Fosc (33.8688MHz) and divide by 768 --> 44.1kHz IPC2bits.T3IP = 0x01; // Set Timer3 Interrupt Priority Level IFS0bits.T3IF = 0; // Clear Timer3 Interrupt Flag IEC0bits.T3IE = 1; // Enable Timer3 interrupt /*In this section we will set up the DCI module for I2S operation to interface with a DIR9001 SPDIF decoder receiving data at 44.1kHz STEREO The timing diagram is provided in Fig 1 below: FIGURE 1 _________________________________ | | | COFS: | |_______________________________| _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ CSCK:_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |<--------Right Channel Data--->|<----Left Channel Data-------->| |<---16bits---->| |<---16bits---->| | |<---RXBUF0---->| |<---RXBUF0---->| | |<--TimeSlot0-->| |<--TimeSlot0-->| | |<-----------1 Frame----------->|<-----------1 Frame----------->| |<--------------------1/Fs = 22.67 microseconds---------------->|*/ DCICON1bits.CSCKD = 1; // Serial Bit Clock (CSCK pin) is input DIR9001 controls data transfer DCICON3 = 0; // Set up CSCK Bit Clock Frequency (disabled) DCICON1bits.COFSM = 1; // Frame Sync Signal set up for I2S mode DCICON1bits.COFSD = 1; // Frame Sync Signal is input DIR9001 controls data transfer DCICON1bits.CSCKE = 1; // Data changes on falling edge sampled on rising edge of CSCK, from DIR9001 data sheet DCICON2bits.WS = 15; // Data word size is 16 bits DCICON2bits.COFSG = 0; // Data frame has 1 word DCICON1bits.CSDOM = 0; // TSCONbits.TSE0 = 0; // Transmit on Time Slot 0 DISABLED RSCONbits.RSE0 = 1; // Receive on Time Slot 0 DCICON2bits.BLEN = 0; // One data word will be buffered between interrupts IFS3bits.DCIIF = 0; // DCIIF: DCI Event Interrupt Flag Status bit IEC3bits.DCIIE = 0; // DCIIE: DCI Event Interrupt Enable bit DCICON1bits.DCIEN = 1; // Enable DCI //Activate Timers T2CONbits.TON = 1; // Start Timer2 T3CONbits.TON = 1; // Start Timer3 // Main Loop --------------------------------------------------------------------------------------------- while(1) { //Nothing is done here. Everything is interrupt driven } return 0; } // main //END --------------------------------------------------------------------------------------------------------