/*********************************************************************
 *
 *                 NTSC TV interface
 *
 *********************************************************************
 * Bruce Land Cornell University
 * June 2014
 * This code uses many cool ideas from
 * Programming 32-bit Microcontrollers in C: Exploring the PIC32
 * by Lucio Di Jasio
 *
 * Uses two Compare units from one timer to do sync and video timing
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * SCK1 is pin 25
 * SDO1 is PPS group 2, map to RPA1 (pin 3)
 * SDI1 is PPS group 2, map to RPB8 (pin 17)
 * SYNC is PortB.0 (pin 4)
 */

#include <plib.h>
#include <xc.h> // need for pps
#include <stdio.h>
#include <stdlib.h>

// Configuration Bit settings
// SYSCLK = 60 MHz (8MHz Crystal/ FPLLIDIV * FPLLMUL / FPLLODIV)
// PBCLK = 30 MHz
// Primary Osc w/PLL (XT+,HS+,EC+PLL)
// WDT OFF
// Other options are don't care
//                       8MHZ                          4MHz               60MHz            30   <-----<---    60MHz
#pragma config FNOSC = FRCPLL, POSCMOD = HS, FPLLIDIV = DIV_2, FPLLMUL = MUL_15, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
#pragma config FSOSCEN = OFF, JTAGEN = OFF
// core frequency we're running at // peripherals at 40 MHz
#define	SYS_FREQ 60000000

// The SPI channel
volatile SpiChannel spiChn = SPI_CHANNEL1 ;	// the SPI channel to use
volatile int spiClkDiv = 6 ;//5 MHz pixel rate => 256 points in 51.2 microSec

// main screen buffer array 256 wide x 200 high = 51200 pixels
// 51200/32 = 1600 integer words
int screen_buffer[1600] ;
volatile int *screen_buffer_addr = screen_buffer ;
volatile int *screen_ptr ;

// The DMA channels
#define DMAchn1 1
#define DMApri0 0

// video timing
#define line_cycles 1905 // 63.5 uSec at 30 MHz Fpb, prescaler=1
#define us_5_cycles 150 // 5 uSec at 30 MHz Fpb, prescaler=1
#define us_13_cycles 390 // beginning of the video DMA burst -- use for centering
#define us_11_cycles 330 // beginning of the video DMA burst -- use for centering
#define us_10_cycles 300 // beginning of the video DMA burst -- use for centering

// video active lines -- 200 total
#define image_start 20
#define image_end image_start+200

// Current line number which is modified
// by a state machine in the timer2 ISR
volatile int LineCount = 0 ;
// ISR driven 1/60 second time
volatile int time_tick_60_hz = 0 ;

// video formatiing variables
//One bit masks for each bit of an INT
unsigned int pos[32] = {0x80000000,0x40000000,0x20000000,0x10000000,0x08000000,0x04000000,0x02000000,0x01000000,
                0x800000,0x400000,0x200000,0x100000,0x080000,0x040000,0x020000,0x010000,
                0x8000,0x4000,0x2000,0x1000,0x0800,0x0400,0x0200,0x0100,
                0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};

#include "ascii_characters.h"
#define top 0
#define left 0
#define right 255
#define bottom 199


//=== fixed conversion macros =========================================
// for 16.16 fixed point
typedef signed int fix ;
#define int2fix(a)   (((fix)(a))<<16)            //Convert char to fix. a is a char
#define fix2int(a)   ((signed int)((a)>>16))    //Convert fix to int. a is an int
#define float2fix(a) ((fix)((a)*65536.0))         //Convert float to fix. a is a float
#define fix2float(a) (((float)(a))/65536.0)       //Convert fix to float. a is an int
//#define multfix(a,b) ((fix)(((( signed long long)(a))*(( signed long long)(b)))>>16)) //multiply two fixed 16.16
#define multfix(a,b) ((fix)(((( signed long)(a))*(( signed long)(b)))>>16)) //multiply two fixed 16.16

// == OC3 ISR ============================================
// VECTOR 14 is OC3 vector -- set up of ipl 3 in main
// vector names from int_1xx_2xx.h
// output compare 3 handler
void __ISR(14, ipl3) OC3Handler(void) // 14
{
   // mPORTBSetBits(BIT_1);
    // Convert DMA to SPI control 
    DmaChnSetEventControl(DMAchn1, DMA_EV_START_IRQ(_SPI1_TX_IRQ)); //
    // clear the timer interrupt flag -- name from
    // http://people.ece.cornell.edu/land/courses/ece4760/PIC32/Microchip_stuff/32-bit-Peripheral-Library-Guide.pdf
    // Table 8.2
    mOC3ClearIntFlag();
   // mPORTBClearBits(BIT_1);  // for profiling the ISR execution time
}

// == Timer 2 ISR =========================================
void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void)
{
    //mPORTBSetBits(BIT_1); // for profiling the ISR execution time
    // update the current scanline number
    LineCount++ ;

    // start the DMA byte blaster to the screen
    if (LineCount >= image_start && LineCount < image_end){
        // set the Chan1 DMA transfer parameters: source & destination address,
        // source & destination size, number of bytes per event
        // 32 bytes / line with 4 bytes per transfer (SPI in 32 bit mode)
        //screen_ptr = screen_buffer + ((LineCount - image_start)<<5) ;
        DmaChnSetTxfer(DMAchn1, (void*)screen_ptr, (void*)&SPI1BUF, 32, 4, 4); //32
        // IRO 17 is the output compare 3 interrupt (See datasheet table 7.1)
        ConfigIntOC3(OC_INT_PRIOR_1 | OC_INT_ON); //3 //
        DmaChnSetEventControl(DMAchn1, DMA_EV_START_IRQ(17)); //
        // turn it on for 32 bytes
        DmaChnEnable(DMAchn1);
        // increment the image memory pointer for the next ISR pass
        screen_ptr += 8; // 8 32-bit words per line
    }
    else ConfigIntOC3(OC_INT_PRIOR_1 | OC_INT_OFF); //turn it off when we dont need to write to video

    // == SYNC state machine ====
    // begin long (Vertical) synch after line 247
    if (LineCount==248) {OC2R = line_cycles - us_5_cycles ;}
    // back to regular sync after line 250
    // the first condition eliminates sync for one line (to avoid duplicate)
    if (LineCount==250) {OC2R = 0 ;}
    if (LineCount==251) {OC2R = us_5_cycles ;}
    // start new frame after line 262 and reset the image memory pointer and
    // update the frame time_tick
    if (LineCount==263) {
        LineCount = 1;
        // reset for the next frame
        screen_ptr = screen_buffer_addr;
        // a general propose time base
        //time_tick_60_hz++;
    }
    if (LineCount==image_end-30) {
        // a general propose time base
        time_tick_60_hz++;
    }
    // clear the timer interrupt flag
    mT2ClearIntFlag();
   // mPORTBClearBits(BIT_1);  // for profiling the ISR execution time
}

//== plot a point =========================================================
//plot one point
//at x,y with color 1=white 0=black 2=invert
#define word_per_line 8
void video_pt(int x, int y, char c) {
	//each line has 18 bytes
	//calculate i based upon this and x,y
	// the word with the pixel in it
	//int i = (x/32) + y*8
	int i = (x >> 5) + y * word_per_line ;
	if (c==1)
	  screen_buffer[i] = screen_buffer[i] | pos[x & 0x1f];
        else if (c==0)
	  screen_buffer[i] = screen_buffer[i] & ~pos[x & 0x1f];
        else
	  screen_buffer[i] = screen_buffer[i] ^ pos[x & 0x1f];
}
// macro version
#define video_pt_m(x,y,c) \
    do{int i = (x >> 5) + y * word_per_line ; \
       if (c==1) \
	  screen_buffer[i] = screen_buffer[i] | pos[x & 0x1f];\
        else if (c==0)\
	  screen_buffer[i] = screen_buffer[i] & ~pos[x & 0x1f];\
        else\
	  screen_buffer[i] = screen_buffer[i] ^ pos[x & 0x1f];\
    } while(0);

//=============================================================================
//plot a line
//at x1,y1 to x2,y2 with color 1=white 0=black 2=invert
//NOTE: this function requires signed chars
//Code is from David Rodgers,
//"Procedural Elements of Computer Graphics",1985
void video_line(int x1, int y1, int x2, int y2, char c) {
	int e;
	signed int dx,dy,j, temp;
	signed char s1,s2, xchange;
        signed int x,y;

	x = x1;
	y = y1;

	//take absolute value
	if (x2 < x1) {
		dx = x1 - x2;
		s1 = -1;
	}

	else if (x2 == x1) {
		dx = 0;
		s1 = 0;
	}

	else {
		dx = x2 - x1;
		s1 = 1;
	}

	if (y2 < y1) {
		dy = y1 - y2;
		s2 = -1;
	}

	else if (y2 == y1) {
		dy = 0;
		s2 = 0;
	}

	else {
		dy = y2 - y1;
		s2 = 1;
	}

	xchange = 0;

	if (dy>dx) {
		temp = dx;
		dx = dy;
		dy = temp;
		xchange = 1;
	}

	e = ((int)dy<<1) - dx;

	for (j=0; j<=dx; j++) {
		video_pt_m(x,y,c);

		if (e>=0) {
			if (xchange==1) x = x + s1;
			else y = y + s2;
			e = e - ((int)dx<<1);
		}

		if (xchange==1) y = y + s2;
		else x = x + s1;

		e = e + ((int)dy<<1);
	}
}

//==============================================================
//return the value of one point
//at x,y with color 1=white 0=black 2=invert
char video_state(int x, int y) {
    //The following construction
    //detects exactly one bit at the x,y location
    // int i = (x>>3) + ((int)y<<4) + ((int)y<<3);
    int i = (x >> 5) + y * word_per_line ;
    return (screen_buffer[i] & pos[x & 0x1f]) != 0 ;
}

//===============================================================
// put a big character on the screen
// c is index into bitmap
void video_putchar(int x, int y, int c) {
    int i;
    int y_pos;
    int j;

    for (i=0;i<7;i++) {
        y_pos = y + i;

        j = ascii[c][i] ;

        video_pt_m(x,   y_pos, (j & 0x80)==0x80);
        video_pt_m(x+1, y_pos, (j & 0x40)==0x40);
        video_pt_m(x+2, y_pos, (j & 0x20)==0x20);
        video_pt_m(x+3, y_pos, (j & 0x10)==0x10);
        video_pt_m(x+4, y_pos, (j & 0x08)==0x08);
    }
}

//=============================================================
// put a string of big characters on the screen
void video_string(int x, int y, char *str) {
	char i;
	for (i=0; str[i]!=0; i++) {
		video_putchar(x,y,str[i]);
		x = x+6;
	}
}

//============================================================
// put a thick character on the screen
// c is index into bitmap
void video_big_putchar(int x, int y, int c) {
    int i;
    int y_pos;
    int j;

    for (i=0; i<7; i=i+1) {
        y_pos = y + i;

        j = ascii[c][i] ;

        video_pt_m(x,   y_pos, (j & 0x80)==0x80);
        video_pt_m(x+1, y_pos, (j & 0x80)==0x80);
        video_pt_m(x+2, y_pos, (j & 0x40)==0x40);
        video_pt_m(x+3, y_pos, (j & 0x40)==0x40);
        video_pt_m(x+4, y_pos, (j & 0x20)==0x20);
        video_pt_m(x+5, y_pos, (j & 0x40)==0x40);
        video_pt_m(x+6, y_pos, (j & 0x10)==0x10);
        video_pt_m(x+7, y_pos, (j & 0x10)==0x10);
        video_pt_m(x+8, y_pos, (j & 0x08)==0x08);
        video_pt_m(x+9, y_pos, (j & 0x08)==0x08);
    }
}

//==================================================================
// put a string of thick characters on the screen
void video_bold_string(int x, int y, char *str) {
	char i;
	for (i=0; str[i]!=0; i++) {
		video_big_putchar(x,y,str[i]);
		x = x+10;
	}
}

// ========================================================================
int	main(void)
{
    // particle animation variables
    #define nSamp 256
    int sample_number=0 ; // index for balls and for next launch
    int v_in[nSamp], v_disp[nSamp], v_disp_save ;
    fix v_fix[nSamp] ;

    // global time
    int time ;
    // some strings
    char cu1[]="Cornell  ECE 4760 -- PIC32 scope";
    char time_string[10] ;

	// Configure the device for maximum performance but do not change the PBDIV
	// Given the options, this function will change the flash wait states, RAM
	// wait state and enable prefetch cache but will not change the PBDIV.
	// The PBDIV value is already set via the pragma FPBDIV option above..
	SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

        //make sure analog is cleared
        //ANSELA =0;
        //ANSELB =0;

        // timer 2 setup for one video line ===========================================
        // Set up timer2 on,  interrupts, internal clock, prescalar 1, compare-value
        // This timer generates the time base for each horizontal video line
        OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_1, line_cycles);
        // set up the timer interrupt with a priority of 2
        ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2);
        mT2ClearIntFlag(); // and clear the interrupt flag
        // zero the system time tick which is updated in the ISR
        time_tick_60_hz = 0;

        // timer 3 setup for adc trigger  ==============================================
        // Set up timer3 on,  no interrupts, internal clock, prescalar 1, compare-value
        // This timer generates the time base for each ADC sample
        #define sample_rate 900000 //500000
        #define timer_match 30000000/sample_rate
        OpenTimer3(T3_ON | T3_SOURCE_INT | T3_PS_1_1, timer_match); //60 is 500 kHz (works at 33 -- is 900 kHz)
        // set up the timer interrupt with a priority of 2
        //ConfigIntTimer3(T3_INT_ON | T3_INT_PRIOR_2);
        //mT3ClearIntFlag(); // and clear the interrupt flag

        // ADC setup ===================================================================
        // trigger on timer3 match
        CloseADC10();	// ensure the ADC is off before setting the configuration

	// define  setup parameters for OpenADC10
	// Turn module on | ouput in integer | trigger mode auto | enable autosample
        // ADC_CLK_AUTO -- Internal counter ends sampling and starts conversion (Auto convert)
        // ADC_CLK_TMR -- triggered off timer3 match
        // ADC_AUTO_SAMPLING_ON -- Sampling begins immediately after last conversion completes; SAMP bit is automatically set
        // ADC_AUTO_SAMPLING_OFF -- Sampling begins with AcquireADC10();
        #define PARAM1  ADC_FORMAT_INTG32 | ADC_CLK_TMR | ADC_AUTO_SAMPLING_ON //ADC_CLK_TMR ADC_CLK_AUTO

	// define setup parameters for OpenADC10
	// ADC ref external  | disable offset test | disable scan mode | do 1 sample | use single buf | alternate mode off
	#define PARAM2  ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_1 | ADC_ALT_BUF_OFF | ADC_ALT_INPUT_OFF
        //
	// Define setup parameters for OpenADC10
        // use peripherial bus clock | set sample time | set ADC clock divider
        // ADC_CONV_CLK_Tcy2 means divide CLK_PB by 2 (max speed)
        // ADC_SAMPLE_TIME_5 seems to work with a source resistance < 1kohm
        // At PB clock 30 MHz, divide by two for ADC_CONV_CLK gives 66 nSec
        #define PARAM3 ADC_CONV_CLK_PB | ADC_SAMPLE_TIME_5 | ADC_CONV_CLK_Tcy2 //ADC_SAMPLE_TIME_15| ADC_CONV_CLK_Tcy2

	// define setup parameters for OpenADC10
	// set AN0 and  as analog inputs
	#define PARAM4	ENABLE_AN0_ANA

	// define setup parameters for OpenADC10
	// do not assign channels to scan
	#define PARAM5	SKIP_SCAN_ALL

	// use ground as neg ref for A | use AN0 for input A
	// configure to sample AN4
	SetChanADC10( ADC_CH0_NEG_SAMPLEA_NVREF | ADC_CH0_POS_SAMPLEA_AN0 ); // configure to sample AN0
	OpenADC10( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5 ); // configure ADC using the parameters defined above

	EnableADC10(); // Enable the ADC

        //=== DMA Channel 0 transfer ADC data to array v_in ================================
        // Open DMA Chan1 for later use sending video to TV
        #define DMAchan0 0
	DmaChnOpen(DMAchan0, DMApri0, DMA_OPEN_DEFAULT);
        DmaChnSetTxfer(DMAchan0, (void*)&ADC1BUF0, (void*)v_in, 4, 1024, 4); //256 32-bit integers
        DmaChnSetEventControl(DMAchan0, DMA_EV_START_IRQ(28)); // 28 is ADC done


        // Compuare match setup for SYNC ===============================================
        //Set up compare match unit to produce sync pulses
        // 5 uSec low
        // or 63.5-5 = 58.5 microSec (2340 ticks) low
        // pulse duration will be controlled in Timer2 ISR
        // #define OpenOC2( config, value1, value2) ( OC2RS = (value1), OC2R = (value2), OC2CON = (config) )
        OpenOC2(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE, line_cycles-1, us_5_cycles);
        // OC2 is PPS group 2, map to RPB5 (pin 14)
        PPSOutput(2, RPB5, OC2);

        // Compare match OC3 setup for video delay =====================================
        // Compare unit for video timing, to delay DMA until end of backporch
        // using the interrupt flag to trigger the first DMA,
        // then use the ISR to change the DMA control to SPI
        // #define OpenOC2( config, value1, value2) ( OC2RS = (value1), OC2R = (value2), OC2CON = (config) )
        // Pulse needs to be TWO cycles long
        OpenOC3(OC_ON | OC_TIMER2_SRC | OC_CONTINUE_PULSE , us_10_cycles+2, us_10_cycles); //
        // turn on ISR so that DMA can covert to SPI control
        ConfigIntOC3(OC_INT_PRIOR_1 | OC_INT_ON); //3 //  
        mOC3ClearIntFlag(); // and clear the interrupt flag

        // SPI configure ==============================================================
        // SCK1 is pin 25 RB14 -- not used here
        // SDO1 is PPS group 2, map to RPA1 (pin 3)
        // SDI1 is PPS group 2, map to RPB8 (pin 17) -- not used here
        // SS1 input is PPS group 1, map to RPB7 (pin 16) for framing -- not used here
        // specify PPS group, signal, logical pin name
        // PPSInput (1, SS1, RPB7);
        PPSOutput(2, RPA1, SDO1);
        // set up i/o
        mPORTBSetPinsDigitalOut(BIT_0 | BIT_1 | BIT_5);
        mPORTBSetBits(BIT_0);

        // divide Fpb by spiClkDiv, configure the I/O ports.
        // 32 bit transfer
         SpiChnOpen(spiChn, SPI_OPEN_ON | SPI_OPEN_MODE32 | SPI_OPEN_MSTEN , spiClkDiv ) ;

        //=== DMA Channel 1 for TV signal ==========================================
        // Open DMA Chan1 for later use sending video to TV
	DmaChnOpen(DMAchn1, DMApri0, DMA_OPEN_DEFAULT);

        // === turn it all on ====================================================
        // setup system wide interrupts  ///
        INTEnableSystemMultiVectoredInt();

        //=== now the application ===============================================
        // Draw the screen boundaries
        video_line(left,top+10, right,top+10, 1); // Title line
        video_line(left,top, right,top, 1); // top
        video_line(right,top, right,bottom, 1); // right
        video_line(right,bottom, left,bottom, 1); // bottom
        video_line(left,top, left,bottom ,1); // left

        // Draw a title
        //Print "CORNELL" message
        video_string(30,top+2,cu1);

        // init voltage display
       // for (sample_number=0; sample_number<nSamp; sample_number++){
       //     v_in[sample_number] = 0 ; //+ (rand()>>10) ; //int2fix(ball%3);ADC1BUF0
       //     v_disp[sample_number] = 100-v_in[sample_number] ;
           // video_pt(sample_number,  v_disp[sample_number],1);
        //}

        time = time_tick_60_hz ;
        // wait to start
        //while(time+600 > time_tick_60_hz){};
        //time = time_tick_60_hz ;
        int trig_1, trig_2, max_ADC, min_ADC, mid_ADC, trig_time;
        // init the trigger state machine
         min_ADC = 500; max_ADC = 500; trig_1 = 50;  trig_2 = 1000;
         // frequency calc
         int i, st, ed;
         char freq_str[16] ;

        #define wait10 asm("nop"); asm("nop");asm("nop"); asm("nop"); asm("nop"); asm("nop");asm("nop"); asm("nop");asm("nop"); asm("nop");

	while(1)
	{
            //mPORTBToggleBits(BIT_1); // for profiling execution time
            mid_ADC = (min_ADC + max_ADC)/2 ;
            trig_2 = 0; trig_1 = 100000; // Always traverse the while
            trig_time = time_tick_60_hz ;
            while(!(trig_2>mid_ADC && trig_1<=mid_ADC)) {
                
                // wait for ADC done
                 while(!(IFS1 & 0x10)) {};
                // first conversion
                // Read the value
                trig_1 = ADC1BUF0 ; //IFS1<1>

                // wait for next one
                while(!(IFS1 & 0x10)) {};
                // second conversion
                // Read the value
                trig_2 = ADC1BUF0 ;

                // do not wait longer than 1/2 second
                if (time_tick_60_hz > trig_time+30) break;
            }
            // start the ADC burst after the trigger is good
            DmaChnEnable(DMAchan0);

            // do not update the screen more than 60/sec
            // wait until the next 1/60 second and ADC transfer done
            #define Chn_busy 0x80
            while((time_tick_60_hz <= time+1) | (DCH0CON & Chn_busy) ){};
            
            // use ISR time-tick to update time stamp
            time = time_tick_60_hz ;
            // erase
            for (sample_number=1; sample_number<=nSamp/2; sample_number++){
               video_line(sample_number,  v_disp[sample_number], sample_number+1,  v_disp[sample_number+1],0);
               // Convert ADC to screen coods
               v_disp[sample_number] =  170-(v_in[sample_number]>>3) ;
            }
            // do the last update
            v_disp_save = v_disp[nSamp/2+1];
            v_disp[nSamp/2+1] =  170-(v_in[nSamp/2+1]>>3) ;
            // draw new
             for (sample_number=1; sample_number<=nSamp/2; sample_number++){
                video_line(sample_number,  v_disp[sample_number], sample_number+1,  v_disp[sample_number+1],1);
            }
            // restore for the next 1/2 fame erase
             v_disp[nSamp/2+1] = v_disp_save ;

            // wait until the next 1/60 second
            while(time_tick_60_hz <= time+1 ){};
            // use ISR time-tick to update time stamp
            time = time_tick_60_hz ;
            // erase
            
            for (sample_number=nSamp/2+1; sample_number<nSamp-2; sample_number++){
               video_line(sample_number,  v_disp[sample_number], sample_number+1,  v_disp[sample_number+1],0);
               // Convert ADC to screen coods
               v_disp[sample_number] =  170-(v_in[sample_number]>>3) ;
            }
            // do the last update
            v_disp[nSamp-1] =  170-(v_in[nSamp-1]>>3) ;
            // draw new
             for (sample_number=nSamp/2+1; sample_number<nSamp-2; sample_number++){
                video_line(sample_number,  v_disp[sample_number], sample_number+1,  v_disp[sample_number+1],1);
            }
             

            // once per second, set the min/max and print the frequency
            if ((time_tick_60_hz % 60) == 0){
                // detect min/max of wave
                if (v_in[sample_number]<min_ADC) min_ADC=v_in[sample_number] ;
                if (v_in[sample_number]>max_ADC) max_ADC=v_in[sample_number] ;
                // get wave period
                st=0; ed=0;
                for (sample_number=0; sample_number<nSamp; sample_number++){
                    if (v_in[sample_number]<mid_ADC && v_in[sample_number+1]>=mid_ADC && st==0 ) st = sample_number;
                    if (v_in[sample_number]<mid_ADC && v_in[sample_number+1]>=mid_ADC && st>0 && sample_number>st+2 && ed==0) ed = sample_number;
                }
                // print the freq
                sprintf(freq_str, "FREQ = %d      ", sample_rate/(ed-st));
                video_string(10,bottom-10, freq_str);
            }
             //time = time_tick_60_hz ;
            //mPORTBClearBits(BIT_1); // for profiling execution time
 	} // while(1)

} // main




