Other Parts Discussed in Thread: CONTROLSUITE
Tool/software: Code Composer Studio
Hello,
I am using the LAUNCHXL-F28379D microcontroller EVM along with an AD9833 waveform generator. I am currently at the stage where I am just trying to make sure that my ADC can effectively sample the sine waves that I am generating with the AD9833 but have run into some trouble. I am essentially just using the adc_soc_continuous_cpu01 example from ControlSuite combined with some of the SPI commands from the spi_loopback_cpu01 example. I know that my SPI communication with the waveform generator is operating properly because when I command a 5kHz signal, I can see the following on an Oscilloscope:
(note that the Oscilloscope probe is set to 1:10 amplification and the actual peak-peak value is only .66V)
Essentially when I try to return the same plot using the ADC, the waveform I get is a mess. I believe I have all my settings correct to guarantee the highest sampling rate I can (SYSCLK = 200MHz, ADCCLK = 50MHz) but from what I can tell, it appears that the ADC is sampling much less frequently than that, since it only takes about 20 samples to capture a full period of the 5kHz waveform.
Below is the code I am using, apologies if it is a bit messy:
//########################################################################### // FILE: Example_28X7xSpi_FFDLB.c // TITLE: SPI Digital Loop Back program. // //! \addtogroup cpu01_example_list //! <h1>SPI Digital Loop Back</h1> //! //! This program uses the internal loop back test mode of the peripheral. //! Other then boot mode pin configuration, no other hardware configuration //! is required. Interrupts are not used. //! //! A stream of data is sent and then compared to the received stream. //! The sent data looks like this: \n //! 0000 0001 0002 0003 0004 0005 0006 0007 .... FFFE FFFF \n //! This pattern is repeated forever. //! //! \b Watch \b Variables \n //! - \b sdata , sent data //! - \b rdata , received data // //########################################################################### // $TI Release: F2837xD Support Library v100 $ // $Release Date: Mon Dec 9 12:58:09 CST 2013 $ //########################################################################### #include "F28x_Project.h" // Device Headerfile and Examples Include File #include "math.h" //definitions for selecting ADC resolution #define RESOLUTION_12BIT 0 //12-bit resolution #define RESOLUTION_16BIT 1 //16-bit resolution (not supported for all variants) //definitions for selecting ADC signal mode #define SIGNAL_SINGLE 0 //single-ended channel conversions (12-bit mode only) #define SIGNAL_DIFFERENTIAL 1 //differential pair channel conversions //buffer for storing conversion results (size must be multiple of 16) #define RESULTS_BUFFER_SIZE 256 Uint16 AdcaResults[RESULTS_BUFFER_SIZE]; Uint16 resultsIndex; // Prototype statements for functions found within this file. // __interrupt void ISRTimer2(void); void take_adc_conversion(void); void ConfigureADC(void); void SetupADCContinuous(Uint16 channel); void delay_loop(void); void spi_xmit(Uint16 a); void spi_fifo_init(void); void spi_init(void); void error(void); void declareFrequency(double freq); Uint16 rdata; // received data Uint16 sdata1; Uint16 sdata2; Uint16 sdata3; Uint16 sdata4; Uint16 sdata5; float refFreq = 25000000.0; int MSB; int LSB; int i; long freqWord; float myPower = 268435456.0; //2^28 float desiredFreq = 5000.0; void main(void) { // Step 1. Initialize System Control: // PLL, WatchDog, enable Peripheral Clocks // This example function is found in the F2837xD_SysCtrl.c file. InitSysCtrl(); // Step 2. Initialize GPIO: // This example function is found in the F2837xD_Gpio.c file and // illustrates how to set the GPIO to it's default state. //This is needed to set ADC GPIOs InitGpio(); // Skipped for this example // Setup only the GP I/O only for SPI-A functionality // This function is found in F2837xD_Spi.c InitSpiaGpio(); // Step 3. Clear all __interrupts and initialize PIE vector table: // Disable CPU __interrupts DINT; // Initialize PIE control registers to their default state. // The default state is all PIE __interrupts disabled and flags // are cleared. // This function is found in the F2837xD_PieCtrl.c file. InitPieCtrl(); // Disable CPU __interrupts and clear all CPU __interrupt flags: IER = 0x0000; IFR = 0x0000; // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). // This will populate the entire table, even if the __interrupt // is not used in this example. This is useful for debug purposes. // The shell ISR routines are found in F2837xD_DefaultIsr.c. // This function is found in F2837xD_PieVect.c. InitPieVectTable(); //Configure the ADC and power it up ConfigureADC(); //Setup the ADC for continuous conversions on channel 0 SetupADCContinuous(3); //Enable global Interrupts and higher priority real-time debug events: EINT; // Enable Global interrupt INTM ERTM; // Enable Global realtime interrupt DBGM //Initialize results buffer for(resultsIndex = 0; resultsIndex < RESULTS_BUFFER_SIZE; resultsIndex++) { AdcaResults[resultsIndex] = 0; } resultsIndex = 0; // Step 4. Initialize all the Device Peripherals: // This function is found in F2837xD_InitPeripherals.c // InitPeripherals(); // Not required for this example spi_fifo_init(); // Initialize the Spi FIFO spi_init(); // init SPI // Step 5. User specific code: // Interrupts are not used in this example. delay_loop(); declareFrequency(desiredFreq); //Take ADC conversions forever for all of time do{ take_adc_conversion(); }while(1); } // Step 7. Insert all local Interrupt Service Routines (ISRs) and functions here: void declareFrequency(double freq) { //Converts desired frequency into MSB and LSB commands for Freq0 register on AD9833 freqWord = (freq * myPower) / refFreq; MSB = (int)((freqWord & 0xFFFC000) >> 14); //Only lower 14 bits are used for data LSB = (int)(freqWord & 0x3FFF); //Set control bits 15 ande 14 to 0 and 1, respectively, for frequency register 0 LSB |= 0x4000; MSB |= 0x4000; Uint16 sdata1 = 0x2100; //Resets AD9833 Uint16 sdata2 = LSB; //Freq0 register write LSBs Uint16 sdata3 = MSB; //Freq0 register write MSBs Uint16 sdata4 = 0xC000; //Phase register write Uint16 sdata5 = 0x2000; //Release reset for(i = 1; i < 6; i++) { // Transmit data spi_xmit(sdata1); // Wait until data is received while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { } //while(SpiaRegs.SPISTS.bit.INT_FLAG !=1) {} // Check against sent data rdata = SpiaRegs.SPIRXBUF; if(rdata != sdata1) error(); sdata1 = sdata2; sdata2 = sdata3; sdata3 = sdata4; sdata4 = sdata5; delay_loop(); } } void delay_loop() { long i; for (i = 0; i < 200; i++) {} } void error(void) { asm(" ESTOP0"); // Test failed!! Stop! for (;;); } void spi_init() { SpiaRegs.SPICCR.all =0x0004F; // Reset on, rising edge, 16-bit char bits SpiaRegs.SPICTL.all =0x0006; // Enable master mode, normal phase, // enable talk, and SPI int disabled. SpiaRegs.SPIBRR =0x007F; SpiaRegs.SPIPRI.bit.TRIWIRE = 1; //Enable 3 wire mode SpiaRegs.SPICCR.all =0x00DF; // Relinquish SPI from Reset SpiaRegs.SPIPRI.bit.FREE = 1; // Set so breakpoints don't disturb xmission } void spi_xmit(Uint16 a) { SpiaRegs.SPITXBUF=a; } void spi_fifo_init() { // Initialize SPI FIFO registers SpiaRegs.SPIFFTX.all=0xE040; SpiaRegs.SPIFFRX.all=0x2044; SpiaRegs.SPIFFCT.all=0x0; } void take_adc_conversion() { //enable ADCINT flags AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; AdcaRegs.ADCINTSEL1N2.bit.INT2E = 1; AdcaRegs.ADCINTSEL3N4.bit.INT3E = 1; AdcaRegs.ADCINTSEL3N4.bit.INT4E = 1; AdcaRegs.ADCINTFLGCLR.all = 0x000F; //initialize results index resultsIndex = 0; //software force start SOC0 to SOC7 AdcaRegs.ADCSOCFRC1.all = 0x00FF; //keep taking samples until the results buffer is full while(resultsIndex < RESULTS_BUFFER_SIZE) { //wait for first set of 8 conversions to complete while(0 == AdcaRegs.ADCINTFLG.bit.ADCINT3); //clear both INT flags generated by first 8 conversions AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; AdcaRegs.ADCINTFLGCLR.bit.ADCINT3 = 1; //save results for first 8 conversions // //note that during this time, the second 8 conversions have //already been triggered by EOC6->ADCIN1 and will be actively //converting while first 8 results are being saved AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT0; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT1; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT2; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT3; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT4; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT5; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT6; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT7; //wait for the second set of 8 conversions to complete while(0 == AdcaRegs.ADCINTFLG.bit.ADCINT4); //clear both INT flags generated by second 8 conversions AdcaRegs.ADCINTFLGCLR.bit.ADCINT2 = 1; AdcaRegs.ADCINTFLGCLR.bit.ADCINT4 = 1; //save results for second 8 conversions // //note that during this time, the first 8 conversions have //already been triggered by EOC14->ADCIN2 and will be actively //converting while second 8 results are being saved AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT8; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT9; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT10; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT11; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT12; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT13; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT14; AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT15; } //disable all ADCINT flags to stop sampling AdcaRegs.ADCINTSEL1N2.bit.INT1E = 0; AdcaRegs.ADCINTSEL1N2.bit.INT2E = 0; AdcaRegs.ADCINTSEL3N4.bit.INT3E = 0; AdcaRegs.ADCINTSEL3N4.bit.INT4E = 0; //at this point, AdcaResults[] contains a sequence of conversions //from the selected channel //software breakpoint, hit run again to get updated conversions //asm(" ESTOP0"); } //Write ADC configurations and power up the ADC for both ADC A and ADC B void ConfigureADC(void) { EALLOW; //write configurations AdcaRegs.ADCCTL2.bit.PRESCALE = 6; //set ADCCLK divider to /4 AdcaRegs.ADCCTL2.bit.RESOLUTION = RESOLUTION_12BIT; AdcaRegs.ADCCTL2.bit.SIGNALMODE = SIGNAL_SINGLE; //Set pulse positions to late AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; //power up the ADC AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; //delay for 1ms to allow ADC time to power up DELAY_US(1000); EDIS; } //setup the ADC to continuously convert on one channel void SetupADCContinuous(Uint16 channel) { Uint16 acqps; //determine minimum acquisition window (in SYSCLKS) based on resolution if(RESOLUTION_12BIT == AdcaRegs.ADCCTL2.bit.RESOLUTION){ acqps = 14; //75ns } else { //resolution is 16-bit acqps = 63; //320ns } EALLOW; AdcaRegs.ADCSOC0CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC1CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC2CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC3CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC4CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC5CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC6CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC7CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC8CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC9CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC10CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC11CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC12CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC13CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC14CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC15CTL.bit.CHSEL = channel; //SOC will convert on channel AdcaRegs.ADCSOC0CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC1CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC2CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC3CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC4CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC5CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC6CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC7CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC9CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC10CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC11CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC12CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC13CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC14CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCSOC15CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles AdcaRegs.ADCINTSEL1N2.bit.INT1E = 0; //disable INT1 flag AdcaRegs.ADCINTSEL1N2.bit.INT2E = 0; //disable INT2 flag AdcaRegs.ADCINTSEL3N4.bit.INT3E = 0; //disable INT3 flag AdcaRegs.ADCINTSEL3N4.bit.INT4E = 0; //disable INT4 flag AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 0; AdcaRegs.ADCINTSEL1N2.bit.INT2CONT = 0; AdcaRegs.ADCINTSEL3N4.bit.INT3CONT = 0; AdcaRegs.ADCINTSEL3N4.bit.INT4CONT = 0; AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 6; //end of SOC6 will set INT1 flag AdcaRegs.ADCINTSEL1N2.bit.INT2SEL = 14; //end of SOC14 will set INT2 flag AdcaRegs.ADCINTSEL3N4.bit.INT3SEL = 7; //end of SOC7 will set INT3 flag AdcaRegs.ADCINTSEL3N4.bit.INT4SEL = 15; //end of SOC15 will set INT4 flag //ADCINT2 will trigger first 8 SOCs AdcaRegs.ADCINTSOCSEL1.bit.SOC0 = 2; AdcaRegs.ADCINTSOCSEL1.bit.SOC1 = 2; AdcaRegs.ADCINTSOCSEL1.bit.SOC2 = 2; AdcaRegs.ADCINTSOCSEL1.bit.SOC3 = 2; AdcaRegs.ADCINTSOCSEL1.bit.SOC4 = 2; AdcaRegs.ADCINTSOCSEL1.bit.SOC5 = 2; AdcaRegs.ADCINTSOCSEL1.bit.SOC6 = 2; AdcaRegs.ADCINTSOCSEL1.bit.SOC7 = 2; //ADCINT1 will trigger second 8 SOCs AdcaRegs.ADCINTSOCSEL2.bit.SOC8 = 1; AdcaRegs.ADCINTSOCSEL2.bit.SOC9 = 1; AdcaRegs.ADCINTSOCSEL2.bit.SOC10 = 1; AdcaRegs.ADCINTSOCSEL2.bit.SOC11 = 1; AdcaRegs.ADCINTSOCSEL2.bit.SOC12 = 1; AdcaRegs.ADCINTSOCSEL2.bit.SOC13 = 1; AdcaRegs.ADCINTSOCSEL2.bit.SOC14 = 1; AdcaRegs.ADCINTSOCSEL2.bit.SOC15 = 1; } //=========================================================================== // No more. //===========================================================================
Any tips or advice at all would be appreciated. Thank you!
Austin Allen