/*
 * File:        chained framed_spi_DMA.c
 * Bruce Land
 * For use with Sean Carroll's Big Board
 * Adapted from:
 *              main.c by
 * Author:      Syed Tahmid Mahbub
 * Target PIC:  PIC32MX250F128B
 */

// all peripheral library includes
#include <plib.h>
#include <math.h>

#pragma config FNOSC = FRCPLL, POSCMOD = OFF
//#pragma config FNOSC = PRIPLL, POSCMOD = EC, OSCIOFNC = OFF
#pragma config FPLLIDIV = DIV_2, FPLLMUL = MUL_20, FPLLODIV = DIV_2  //40 MHz
#pragma config FPBDIV = DIV_1 // PB 40 MHz
// turn off alternative functions for port pins B.4 and B.5
#pragma config JTAGEN = OFF, DEBUG = OFF
#pragma config FSOSCEN = OFF

// === DAC control vars ===========================================
volatile SpiChannel spiChn = SPI_CHANNEL2 ;	// the SPI channel to use
volatile int spiClkDiv = 2 ; // 20 MHz max speed for this DAC

// table size and timer rate determine frequency
// output freq = (timer rate)/(table size)
#define sine_table_size 256
#define dma_table_size 512
// output value + control info
unsigned short DAC_data1[sine_table_size], raw_sin[sine_table_size] ;
unsigned short DAC_data2[sine_table_size];
unsigned short DMA_table[dma_table_size] ;
// A-channel, 1x, active
#define DAC_config_chan_A 0b0011000000000000
// B-channel, 1x, active
#define DAC_config_chan_B 0b1011000000000000

////////////////////////////////////
// some precise, fixed, short delays
// to use for extending pulse durations on the keypad
// if behavior is erratic
#define NOP asm("nop");
// 20 cycles 
#define wait20 NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;
// 40 cycles
#define wait40 wait20;wait20;
#define wait400 wait40;wait40;wait40;wait40;wait40;wait40;wait40;wait40;wait40;wait40;
//////////////////////////////////// 
// === Main  ======================================================
void main(void) {
 
  // === timer2 =================================
    // Set up timer2 on,  interrupts, internal clock, prescalar 1, toggle rate
    // at 30 MHz PB clock 60 counts is two microsec
    // 100 is 400 ksamples/sec  
    // 400 is 100 ksamples/sec
    // 2000 is 20 ksamp/sec
    OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_1, 100);
	// !!!NO ISR TURNED ON!!!!!

    // === SPI channel for DAC =================
    // divide Fpb by 2, configure the I/O ports. Not using SS in this example
    // 16 bit transfer CKP=1 CKE=1
    // possibles SPI_OPEN_CKP_HIGH;   SPI_OPEN_SMP_END;  SPI_OPEN_CKE_REV
    // For any given peripherial, you will need to match these
    // clk divider set to 2 for 20 MHz
    // FRAMED SPI mode, so SS2 is produced by the SPI hardware
    SpiChnOpen(SPI_CHANNEL2, 
      SPI_OPEN_ON | SPI_OPEN_MODE16 | SPI_OPEN_MSTEN | SPI_OPEN_CKE_REV | SPICON_FRMEN | SPICON_FRMPOL, spiClkDiv);
    // SS1 to RPB10 for FRAMED SPI
    PPSOutput(4, RPB10, SS2);
	// >>> SCK2 is RB15 <<< not on PPS
    // SDO2 (MOSI) is in PPS output group 2, could be connected to RB5 which is pin 14
    PPSOutput(2, RPB5, SDO2);
    
  // === DMA setup for DAC =====================
  // transfer 2 bytes from voltage table to DAC SPI controlled by timer event
  // and repeating indefinitely
    // Open the desired DMA channels.
	// Enable the DEFAULT option on channel 0 
    //    and chain channel 1 to the higher priority
	DmaChnOpen(0, 3, DMA_OPEN_AUTO);
    DmaChnOpen(1, 2, DMA_OPEN_CHAIN_HI); //DMA_OPEN_CHAIN_HI
    
	// set the transfer parameters: source & destination address, source & destination size, 
	// number of bytes per event
    // Setting the last parameter to 2 makes the DMA output two bytes/timer event
    // sine_table_size mult by 2 because the table is SHORT ints
    DmaChnSetTxfer(0, DAC_data1, (void*)&SPI2BUF, sine_table_size*2, 2, 2);
    DmaChnSetTxfer(1, DAC_data2, (void*)&SPI2BUF, sine_table_size*2, 2, 2);

	// set the transfer event control: what event is to start the DMA transfers
        // In this case, timer2
	DmaChnSetEventControl(0, DMA_EV_START_IRQ(_TIMER_2_IRQ));
    DmaChnSetEventControl(1, DMA_EV_START_IRQ(_TIMER_2_IRQ));
	
    DmaChnEnable(0);
    
	// init the DAC table for a sine wave
  // build the sine lookup table
   // scaled to produce values between 0 and 4095 (12 bit)
    int i, s ;
    for (i = 0; i < sine_table_size; i++){
        raw_sin[i] = (int)(2047 * sin((float)i*6.283/(float)sine_table_size) + 2047); //12 bit
        DAC_data1[i] = DAC_config_chan_A | (raw_sin[i] & 0x0fff) ;
        DAC_data2[i] = DAC_config_chan_B | ( (i<128)? 0x0fff : 0 ) ;
    }
	int j=0 ;
    for (i = 0; i < dma_table_size; i=i+2){
        DMA_table[i] = DAC_data1[j] ; 
        DMA_table[i+1] = DAC_data2[j] ;
        j++;
    }
    // set up i/o port pin
    ANSELA =0; // turn off analog on A
    mPORTAClearBits(BIT_0);		//Clear A bits to ensure light is off.
    mPORTASetPinsDigitalOut(BIT_0);    //Set A port as output
    
	while(1){
        //mPORTAToggleBits(BIT_0);
    };
    
  } // main

// === end  ======================================================

