This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Powering up the ADC

Hello,

I have trouble using the ADC. Apparently it stems from the function InitADC() not powering up the ADC.

Please see the full code of the program that I am using below. The file DSP281x_Adc.c is as provided in the header file collection. The program is supposed to sample ADCINA0 at 1 kHz. The time base is provided by the general purpose timer 1 in event manager A. A pulse sequence is given to pin PWM1 to confirm that the timer works.

Outputting this signal works as expected as long as InitADC() at the beginning of the main code is commented. If it is not, the 1 kHz signal does not appear at the output. Also, after executing InitADC(), I would expect ADCTRL3 to have the value E6 (bandgap, reference and analog circuitry powered up and clock divider set). This is not the case - the register value is 0 (it is 6 when InitADC() is commented, indicating the setting of the clock divider).

In conclusion, executing InitADC does not power up the ADC as it is supposed to do and further prevents the rest of the code from being executed.

Additional observation that I made: With InitADC() included in the code, upon suspending or terminating the program execution, another code tab opens next to main.c titled "0x3ffc00" or "0x2ec9dd" (it varies) and it says in it

No source available for "0x2ec9dd"

Beneath this message is a View Disassembly… button.

It seems that there is something wrong with the initialization of the ADC by InitADC(). I appreciate your suggestions for possible fixes.

Regards,

Adrian

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

program code:

/*
 * main.c
 *
 * get the ADC working
 * use GP timer 1 of event manager A to provide a time base of f = 1 kHz for sampling
 * input pin for signal: ADCINA0 (analog interface: top left pin, GND: bottom line of pins)
 * output pin for sampling pulse (just to check): PWM1 (I/O pin 9, bottom row fifth pin)
 */
#include "DSP281x_Device.h"
#include "DSP281x_Examples.h"
#include "math.h"

void main() {
    float d=0.05;
    InitSysCtrl();
    InitAdc();
    //InitPieCtrl();
    //InitPieVectTable();
    //InitPeripherals();

// configure pins as peripheral (here: timer) outputs (as opposed to general digital I/O)
    EALLOW;
    GpioMuxRegs.GPAMUX.all=0xFF;
    EDIS;

// GP timer 1 setup -- provides time base for ADC
    EvaRegs.T1CON.bit.FREE=1;        // keep going on emulation suspend bec. ADC still finishes sequence
    EvaRegs.T1CON.bit.SOFT=1;        // ... second part of it
    EvaRegs.T1CON.bit.TMODE=2;        // continuous up-counting mode
    EvaRegs.T1CON.bit.TPS=3;        // input clock prescaler, corresponds to factor 1/8
    EvaRegs.T1CON.bit.TENABLE=1;    // enable timer
    EvaRegs.T1CON.bit.TCLKS10=0;    // use HSPCLK as clock
    EvaRegs.T1CON.bit.TCLD10=0;        // reload compare register T1CMPR at beginning of switching period
    EvaRegs.T1CON.bit.TECMPR=1;        // enable timer compare

    EvaRegs.T1PR=18749;                // period register = 150MHz/1kHz/8-1 (HISPCP = 1, prescaler [TPS] 1/8)
    EvaRegs.T1CMPR=floor(EvaRegs.T1PR*d);    // compare register for GP T1
    EvaRegs.T1CNT=0;                // initialize counter register

// GP timer control register (EVA)
    EvaRegs.GPTCONA.bit.T1CTRIPE=0;    // disable trip function that can drive output to high Z
    EvaRegs.GPTCONA.bit.TCMPOE=1;    // enable compare output
    EvaRegs.GPTCONA.bit.T1TOADC=2;    // start ADC on period match
    EvaRegs.GPTCONA.bit.TCMPOE=1;    // enable timer compare outputs
    EvaRegs.GPTCONA.bit.T1CMPOE=1;    // enable timer 1 compare outputs
    EvaRegs.GPTCONA.bit.T1PIN=1;    // polarity of GP timer 2 (1 = active L, 2 = active H)

// GP timer compare control register (EVA)
    EvaRegs.COMCONA.bit.CENABLE=1;    // enable compare
    EvaRegs.COMCONA.bit.CLD=0;        // reload compare register CMPR at beginning of switching period
    EvaRegs.COMCONA.bit.ACTRLD=0;    // reload action control register at beginning of switching period
    EvaRegs.COMCONA.bit.FCOMPOE=1;    // enable full compare outputs
    EvaRegs.COMCONA.bit.FCMP1OE=1;    // enable full compare 1 outputs (PWM1,2)
    EvaRegs.COMCONA.bit.C1TRIPE=0;    // disable trip function that can drive output to high Z

// compare action control register (EVA)
    EvaRegs.ACTRA.bit.CMP1ACT=1;     // polarity of PWM1 (1 = active L, 2 = active H)

// CMPR1 register
    EvaRegs.CMPR1=floor(EvaRegs.T1PR*d);    // compare register for PWM1

// configure ADC
    AdcRegs.ADCTRL1.bit.SUSMOD=1;        // upon emulation suspend finish ADC sequence
    AdcRegs.ADCTRL1.bit.CPS=0;            // core clock prescaler, factor 1
    AdcRegs.ADCTRL1.bit.CONT_RUN=0;        // start-stop mode (as opposed to continuous conversion)
    AdcRegs.ADCTRL1.bit.SEQ_OVRD=0;        // disable sequencer override, NR
    AdcRegs.ADCTRL1.bit.SEQ_CASC=0;        // dual sequencer mode (as opposed to cascaded mode)
    AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1=1;    // enable interrupt request by SEQ1
    AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1=0;    // interrupt after every EOS (as opposed to every second one)
    AdcRegs.ADCTRL2.bit.EVA_SOC_SEQ1=1;    // event manager A can start conversion sequence
    AdcRegs.ADCTRL3.bit.ADCEXTREF=0;    // use internal reference sources
    AdcRegs.ADCTRL3.bit.ADCCLKPS=3;        // core clock divider, factor 1/6 to get clock below 25 MHz
    AdcRegs.ADCTRL3.bit.SMODE_SEL=0;    // sequential sampling mode (as opposed to simultaneous)

    AdcRegs.ADCMAXCONV.bit.MAX_CONV1=0;    // # of conversions in autoconversion session of SEQ1 = 1
    AdcRegs.ADCCHSELSEQ1.bit.CONV00=0;    // sample ADCINA0

    while(1){
    ;
    }
}

// TI File $Revision: /main/2 $
// Checkin $Date: April 29, 2005   11:11:45 $
//###########################################################################
//
// FILE:    DSP281x_Adc.c
//
// TITLE:    DSP281x ADC Initialization & Support Functions.
//
//###########################################################################
// $TI Release: DSP281x C/C++ Header Files V1.20 $
// $Release Date: July 27, 2009 $
//###########################################################################

#include "DSP281x_Device.h"     // DSP281x Headerfile Include File
#include "DSP281x_Examples.h"   // DSP281x Examples Include File

#define ADC_usDELAY  8000L
#define ADC_usDELAY2 20L

//---------------------------------------------------------------------------
// InitAdc:
//---------------------------------------------------------------------------
// This function initializes ADC to a known state.
//
void InitAdc(void)
{
    extern void DSP28x_usDelay(Uint32 Count);
    
    // To powerup the ADC the ADCENCLK bit should be set first to enable
    // clocks, followed by powering up the bandgap and reference circuitry.
    // After a 5ms delay the rest of the ADC can be powered up. After ADC
    // powerup, another 20us delay is required before performing the first
    // ADC conversion. Please note that for the delay function below to
    // operate correctly the CPU_CLOCK_SPEED define statement in the
    // DSP28_Examples.h file must contain the correct CPU clock period in
    // nanoseconds. For example:

    AdcRegs.ADCTRL3.bit.ADCBGRFDN = 0x3;    // Power up bandgap/reference circuitry
    DELAY_US(ADC_usDELAY);                  // Delay before powering up rest of ADC
    AdcRegs.ADCTRL3.bit.ADCPWDN = 1;        // Power up rest of ADC
    DELAY_US(ADC_usDELAY2);                 // Delay after powering up ADC
}    
//===========================================================================
// No more.
//===========================================================================

  • Can you confirm the ADC clock is enabled in InitSysCtrl()?

    SysCtrlRegs.PCLKCR.bit.ADCENCLK=1

  • Thank you for your answer, Joe.

    Yes, the bit is set in InitPeripheralClocks() that is called by InitSysCtrl().

    When suspending the emulation to check whether the bit is indeed set, I made the following observation: There is a register in the SYSCTRL tree called PCLKCR0. It has the value 0x5D0B, meaning that ADCENCLK (bit 3) is set. Strangely enough though, I cannot find a definition of the register PCLKCR0. In the header file DSP281x_SysCtrl.h it says

    struct SYS_CTRL_REGS {
       union   PCLKCR_REG PCLKCR;    // 12: Peripheral clock control register

    Therefore I am wondering why the zero got attached to the register name. The other registers have just the same names as in the header file.

  • It looks like the problem occurs in the function DELAY_US that is called by InitAdc() and that also comes with the collection of header files for this device. I have added the file DSP281x_usDelay.asm to the project folder. The program jumps in there from InitAdc() and decrements the accumulator by one, but then gets stuck at the command BF or LRETR. The message
    No source available for "0x801b"
    appears.

    To prevent using DELAY_US I replaced the two lines by a for loop with an empty command block, e.g.
    for (i=0;i<=15000;i++){;}
    This one causes a delay of 6.4 ms in the debug build. The other delay is realized likewise. Unfortunately this crude method does not create an appreciable delay in the release build. But as for the debug build, the program at least runs and outputs the pulse sequence that is supposed to indicate when the ADC starts. I am not quite sure whether the ADC works as intended, it seems like it is not, but this might have other causes.

    Conclusion: the DELAY_US function is the one that causes the error. Why could this be?

  • I think your for loop is likely getting optimized out by the compiler in the release build.  You can modify the optimization level or simply perform an ASM/NOP call, i.e. asm(" RPT #255 || NOP");

    You will have to play with the RPT count depending on your system frequency.

    Ultimately it is best if you can use the DELAY_US function and it should work, it is used in many examples.  Perhaps the function was not defined properly or maybe there is a conflict with the .sect being in ramfuncs.  Perhaps change where this function gets stored to another ram location like M0, M1, or L1 (based on you .cmd)

  • Joe Prushing said:
    I think your for loop is likely getting optimized out by the compiler in the release build.  You can modify the optimization level

    Right, the for loop delay works with optimization levels of up to 1 in both the debug and the release builds.



    Joe Prushing said:
    You can simply perform an ASM/NOP call, i.e.
    asm(" RPT #255 || NOP");
    You will have to play with the RPT count depending on your system frequency.

    This command only seems to work properly if the repeat count is 255 or lower. For larger values it does not produce a longer delay. So I have now executed this loop in a for loop, and

    for (i=0;i<2500;i++)
                asm(" RPT #255 || NOP");

    creates a 5 ms delay irrespective whether debug or release mode is selected.



    Joe Prushing said:
    Ultimately it is best if you can use the DELAY_US function and it should work

    Unfortunately I could not get it to work yet.

    In the comments of the file DSP281x_usDelay.asm it says "Call this function by using the DELAY_US(A) macro that is defined in the DSP28_Device.h file." However I cannot find this macro. I am attaching the device.h file:

    // TI File $Revision: /main/5 $
    // Checkin $Date: December 17, 2007   13:36:09 $
    //###########################################################################
    //
    // FILE:   DSP281x_Device.h
    //
    // TITLE:  DSP281x Device Definitions.
    //
    //###########################################################################
    // $TI Release: DSP281x C/C++ Header Files V1.20 $
    // $Release Date: July 27, 2009 $
    //###########################################################################

    #ifndef DSP281x_DEVICE_H
    #define DSP281x_DEVICE_H


    #ifdef __cplusplus
    extern "C" {
    #endif


    #define   TARGET   1
    //---------------------------------------------------------------------------
    // User To Select Target Device:

    #define   DSP28_F2812   TARGET
    #define   DSP28_F2811   0
    #define   DSP28_F2810   0

    //---------------------------------------------------------------------------
    // Common CPU Definitions:
    //

    extern cregister volatile unsigned int IFR;
    extern cregister volatile unsigned int IER;

    #define  EINT   asm(" clrc INTM")
    #define  DINT   asm(" setc INTM")
    #define  ERTM   asm(" clrc DBGM")
    #define  DRTM   asm(" setc DBGM")
    #define  EALLOW asm(" EALLOW")
    #define  EDIS   asm(" EDIS")
    #define  ESTOP0 asm(" ESTOP0")

    #define M_INT1  0x0001
    #define M_INT2  0x0002
    #define M_INT3  0x0004
    #define M_INT4  0x0008
    #define M_INT5  0x0010
    #define M_INT6  0x0020
    #define M_INT7  0x0040
    #define M_INT8  0x0080
    #define M_INT9  0x0100
    #define M_INT10 0x0200
    #define M_INT11 0x0400
    #define M_INT12 0x0800
    #define M_INT13 0x1000
    #define M_INT14 0x2000
    #define M_DLOG  0x4000
    #define M_RTOS  0x8000

    #define BIT0    0x0001
    #define BIT1    0x0002
    #define BIT2    0x0004
    #define BIT3    0x0008
    #define BIT4    0x0010
    #define BIT5    0x0020
    #define BIT6    0x0040
    #define BIT7    0x0080
    #define BIT8    0x0100
    #define BIT9    0x0200
    #define BIT10   0x0400
    #define BIT11   0x0800
    #define BIT12   0x1000
    #define BIT13   0x2000
    #define BIT14   0x4000
    #define BIT15   0x8000



    //---------------------------------------------------------------------------
    // For Portability, User Is Recommended To Use Following Data Type Size
    // Definitions For 16-bit and 32-Bit Signed/Unsigned Integers:
    //

    #ifndef DSP28_DATA_TYPES
    #define DSP28_DATA_TYPES
    typedef int                 int16;
    typedef long                int32;
    typedef long long           int64;
    typedef unsigned int        Uint16;
    typedef unsigned long       Uint32;
    typedef unsigned long long  Uint64;
    typedef float               float32;
    typedef long double         float64;
    #endif


    //---------------------------------------------------------------------------
    // Include All Peripheral Header Files:
    //

    #include "DSP281x_SysCtrl.h"            // System Control/Power Modes
    #include "DSP281x_DevEmu.h"             // Device Emulation Registers
    #include "DSP281x_Xintf.h"              // External Interface Registers
    #include "DSP281x_CpuTimers.h"          // 32-bit CPU Timers
    #include "DSP281x_PieCtrl.h"            // PIE Control Registers
    #include "DSP281x_PieVect.h"            // PIE Vector Table
    #include "DSP281x_Spi.h"                // SPI Registers
    #include "DSP281x_Sci.h"                // SCI Registers
    #include "DSP281x_Mcbsp.h"              // McBSP Registers
    #include "DSP281x_ECan.h"               // Enhanced eCAN Registers
    #include "DSP281x_Gpio.h"               // General Purpose I/O Registers
    #include "DSP281x_Ev.h"                 // Event Manager Registers
    #include "DSP281x_Adc.h"                // ADC Registers
    #include "DSP281x_XIntrupt.h"           // External Interrupts

    #ifdef __cplusplus
    }
    #endif /* extern "C" */

    #endif  // end of DSP281x_DEVICE_H definition


    //===========================================================================
    // No more.
    //===========================================================================



    On the other hand, in DSP281x_Examples.h is a line

    #define DELAY_US(A)  DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L)


    In the DSP281x_Adc.c file where the delay function is called the relevant lines say:

    #define ADC_usDELAY  8000L
    #define ADC_usDELAY2 20L

    DELAY_US(ADC_usDELAY);                  // Delay before powering up rest of ADC
    DELAY_US(ADC_usDELAY2);                 // Delay after powering up ADC



    Joe Prushing said:
    Perhaps the function was not defined properly

    All that I did was adding the file DSP281x_usDelay.asm to the project directory. What else needs to be done?

    I noticed that the line in DSP281x_Examples.h as posted above calls DSP28x_usDelay whereas the file name in which usDelay is saved is DSP281x_usDelay.asm (with the 1 in it). Does this matter?



    Joe Prushing said:
    Perhaps change where this function gets stored to another ram location like M0, M1, or L1 (based on you .cmd)

    The two cmd files F2812.cmd and DSP281x_Headers_nonBIOS.cmd are still as they are provided. What exactly do I have to change in there?

  • The asm("    RPT #255 || NOP") is capped at 256 repetitions because the immediate value in the instruction op-code is 8 bits.  You should be able to combine these by putting them in a loop to get the time you want.  This will not be optimized out by the compiler (unlike an empty loop).