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.

TMS320F2810: Source code LVDT interface with TMS320F2810

Part Number: TMS320F2810
Other Parts Discussed in Thread: TMS320F280049, , CONTROLSUITE, C2000WARE

Hi there,

I'm looking for the complete project source C Code used in SPRA946 application note.

it's about lvdt interface with DSP.

The DSP was the TMS320F2810. I would like to adapt the code for the TMS320F280049.

Anybody could help me?

Thanks a lot!

Guillaume

  • Guillaume,

    Unfortunately I found out I am not allowed to release source code over the forum. The relevant part of the code is in printed form on pages 23-25 of the Application Report. However, from this and the variable declarations below, you should be able to get something similar running on F280049.

    // variable declarations
    volatile struct IBUFFER SineRec = BUFFER_DEFAULTS; // sine wave table pointers
    int *QuadPoint = NULLADDR; // pointer to quadrature element
    int PWM_duty; // PWM duty cycle
    int ADC_result; // A/D converter result
    int ADC_input; // bipolar left justified ADC reading
    long AvgSum = 0; // running sum
    int AvgSumDelta; // averaging buffer sum adjustment
    int InputOffset; // input offset = average input
    int NormInput; // normalised input reading (offset removed)

    // IQ variables
    _iq InputVoltage = 0; // instantaneous input value
    _iq RefVecReal; // reference vector - real part
    _iq RefVecImag; // reference vector - imaginary part
    _iq InpVecReal; // input vector - real part
    _iq InpVecImag; // input vector - imaginary part
    _iq InpMagnitude; // magnitude of input vector

    // phase detection
    Bool RefSign; // sign of reference signal
    Bool InpSign; // sign of return signal
    Bool InPhase; // signals in phase
    int PhaseCount = 0; // phase detection counter
    int PhaseBuffer[PHASE_BUFFER_LENGTH]; // phase detection buffer
    struct IBUFFER PhbRec = BUFFER_DEFAULTS; // phase buffer pointers

    There will be work involved in porting to the F280049, and you will have to develop an interface board to condition the LVDT signals in a similar way to that described in the report. There is scope to improve performance by taking advantage of the floating point core and the TMU on the newer device.

    Regards,

    Richard
  • Thanks Richard,

    I have developped the generator sine wave with just memory and DAC output + 1st ordre LP filter.
    In the code, i have seen correction function.
    If you are ok, i have some questions about code and functions:

    1- What's difference between input offset removal and OffsetCorrection
    2- In the Timer 2 Interrupt function page 23, where do you calculate the OffsetCorrection variable? Could you give the code?
    3- How did you calculate the gain adjustement and apply the result in GainCorrection variable?

    Thanks a lot for your help!

    Have a great day!

    Regards,

    Guillaume
  • Hi Guillaume,

    1- What's difference between input offset removal and OffsetCorrection

    "offset removal" refers to the AC input from the transducer secondary winding. The de-modulation method used will only work effectively if the AC input is centered on zero. Since our ADC has a range of 0V to +3V, we want the signal centered on +1.5V. In practice the hardware may not do this exaclty, so the software applies a small offset to the measured signal before de-modulation:
    NormInput = (ADC_input - InputOffset) << 4; // normalised ADC reading
    The variable "InputOffset" is computed by averaging the incoming signal over 4 complete AC cycles (160kHz sampling, 5kHz input freq., 128 samples [see AVG_BUFFER_LENGTH definition below]).

    "OffsetCorrection" is the variable I used to correct for any fixed offset in the final position measurement. This would be loaded by the user load when the system is calibrated (see below).


    2- In the Timer 2 Interrupt function page 23, where do you calculate the OffsetCorrection variable? Could you give the code?

    In the code, I just declared it as:
    _iq OffsetCorrection = 4.02; // fixed offset correction

    3- How did you calculate the gain adjustement and apply the result in GainCorrection variable?

    Like the offset, "GainCorrection" is a fixed number the user would determine on transducer calibration. I tested with:
    _iq GainCorrection = 10.3; // fixed gain correction

    The code also allows for a linearity map ("cLinMap" on p.25) to correct for non-linear gain. Along with fixed offset and gain, this would also be stored during calibration. The code interpolates between points in the table to find the offset. A map initialised to zero would be:

    // linearity correction map:
    // entries are signed corrections to "Displacement" in bits
    #pragma DATA_SECTION(cLinMap,"LinearityMap")
    int cLinMap[LINMAP_LENGTH] = {
    0, // [0] -50 mm
    0, // [1] -45 mm
    0, // [2] -40 mm
    0, // [3] -35 mm
    0, // [4] -30 mm
    0, // [5] -25 mm
    0, // [6] -20 mm
    0, // [7] -15 mm
    0, // [8] -10 mm
    0, // [9] -5 mm
    0, // [10] 0 mm
    0, // [11] +5 mm
    0, // [12] +10 mm
    0, // [13] +15 mm
    0, // [14] +20 mm
    0, // [15] +25 mm
    0, // [16] +30 mm
    0, // [17] +35 mm
    0, // [18] +40 mm
    0, // [19] +45 mm
    0 // [20] +50 mm
    };

    static UINT stepSize = (0xFFFF / LINMAP_LENGTH); // size of linearity division
    _iq Stroke; // corrected displacement


    There were some #defines in a header file which are relevant:

    #define SINE_CYCLE_LENGTH 32 // length of sine look-up table
    #define QUADRANT_LENGTH (SINE_CYCLE_LENGTH>>2) // length of one quadrant
    #define QUAD_TABLE_LENGTH (SINE_CYCLE_LENGTH + QUADRANT_LENGTH) // total length of quadrature table
    #define AVG_BUFFER_LENGTH 128 // input averaging buffer
    #define PHASE_BUFFER_LENGTH 32 // length of phase detection buffer
    #define SMOOTHING_BUFFER_LENGTH 512 // length of smoothing buffer
    #define LINMAP_LENGTH 21 // length of linearity map

    // sine wave look-up table
    extern int QuadratureTable[QUAD_TABLE_LENGTH];


    It would have been nice to send you the project, but anyway I hope this clarifies it somewhat. Please do post back if you have further questions.

    Regards,

    Richard

  • Hi Richard,

    Your help is very useful!

    Thanks so much for the code détails.

    The algorithm of the LVDT position is like a True RMS value calculation. I have seen a LVDT interface with DC True RMS converter voltage.

    I post back further question as soon as my project has been more advanced.

    Best regards.

    Guillaume

  • Hi Richard,

    i Have question about the input offset compensation. I have seen the function : NextIntPoint()

    Could you post the code of this function?

    How did you do a small code to make a circular memory without "for" command?

    Best regards

    Guillaume

  • Hi Guillaume,

    The buffer support is done in the buffer.h header file. With apologies for the lengthy post, here is the code in that file:

    /* buffer.h */

    #ifndef GEN_C_BUFFER_H
    #define GEN_C_BUFFER_H

    #include "stdcdefs.h" // standard C definitions

    #define DEFAULT_BUFFER_LENGTH 0x0080 // default buffer length

    // integer buffer structure
    struct IBUFFER {
    int *fptr;
    int *lptr;
    int *dptr;
    };

    // long buffer structure
    struct LBUFFER {
    long *fptr;
    long *lptr;
    long *dptr;
    };

    // _iq type buffer structure
    #ifdef __IQMATHLIB_H_INCLUDED__
    struct IQBUFFER {
    _iq *fptr;
    _iq *lptr;
    _iq *dptr;
    };
    #endif
    // dereference as: *(xxx.fptr) or *(xxx->fptr)
    // buffer_length = (xxx.lptr - xxx.fptr) + 1;

    // default addresses for buffer pointer structs
    #define BUFFER_DEFAULTS { 0x00000000, \
    0x00000000, \
    0x00000000 \
    }
    // use: struct LBUFFER buffername = BUFFER_DEFAULTS;

    // function prototypes
    // 16-bit
    extern void FlushIntBuffer(struct IBUFFER *bufrec);
    extern void AssignIntBuffer(struct IBUFFER *bufrec, int buffer[], UINT buflen);
    inline void LogIntDataPoint(struct IBUFFER *bufrec, int datapoint);
    inline void NextIntPoint(struct IBUFFER *bufrec);

    // 32-bit
    extern void FlushLongBuffer(struct LBUFFER *bufrec);
    extern void AssignLongBuffer(struct LBUFFER *bufrec, long buffer[], UINT buflen);
    inline void LogLongDataPoint(struct LBUFFER *bufrec, long datapoint);
    inline void NextLongPoint(struct LBUFFER *bufrec);

    /*** inline function definitions ***/
    // xxx.dptr points to first unused memory location

    // log 16-bit data to buffer
    // LogDataPoint(&dlog, (long) x);
    inline void LogIntDataPoint(struct IBUFFER *bufrec, int datapoint)
    {
    *(bufrec->dptr) = datapoint; // write data point into buffer
    (bufrec->dptr == bufrec->lptr) ? (bufrec->dptr = bufrec->fptr) : bufrec->dptr++; // modify data pointer
    }

    // modify 16-bit data pointer to next element
    inline void NextIntPoint(struct IBUFFER *bufrec)
    {
    (bufrec->dptr == bufrec->lptr) ? (bufrec->dptr = bufrec->fptr) : bufrec->dptr++; // modify data pointer
    }


    // log 32-bit data to buffer
    // LogDataPoint(&dlog, (long) x);
    inline void LogLongDataPoint(struct LBUFFER *bufrec, long datapoint)
    {
    *(bufrec->dptr) = datapoint; // write data point into buffer
    (bufrec->dptr == bufrec->lptr) ? (bufrec->dptr = bufrec->fptr) : bufrec->dptr++; // modify data pointer
    }


    // modify 32-bit data pointer to next element
    inline void NextLongPoint(struct LBUFFER *bufrec)
    {
    (bufrec->dptr == bufrec->lptr) ? (bufrec->dptr = bufrec->fptr) : bufrec->dptr++; // modify data pointer
    }

    #endif // GEN_C_BUFFER_H

    /* end of file */


    In workisr.c, the lines...

    NextIntPoint((struct IBUFFER *) &SineRec); // align sine table pointer
    PWM_duty = *(SineRec.dptr); // next sine point

    ...just set the line data pointer to the next element in the buffer and extract that data.

    Regards,

    Richard
  • Hi RIchard,

    Thanks! It works fine! So, i 'm working on the modulation part. I have some question about it.

    1- What's IQ format? Have you a description about it?  it's like in quadrature? Did you use ?

    2- In line:   "InputVoltage = (_iq)((long) NormInput<<5);// convert to global IQ format    have you an example with a numercal data in Norminput and the result in InputVoltage?

    3- Why do you need to multiply by 32 the value of NormInput?

    I'll have other questions later on.

    Have a good day!

    Regards

    Guillaume

  • Hi Guillaume,

    IQ math is a library for handling fixed point data in C. The "IQ" stands for "Integer Quotient" - the two parts of the representation. If you download controlSUITE or C2000Ware and navigate to libraries -> math you'll find the library with documentation.

    I used a IQ24 format for most of the variables including InputVoltage, but NormInput is a signed 16-bit integer representing the corrected and left justified 12-bit ADC reading:

    NormInput = (ADC_input - InputOffset) << 4;

    The MSB of NormInput is the sign bit (1 if negative). This is so because ADC_Input is XOR'd with 0x8000 in the third line of the ISR.

    To get this into IQ24 format, it is typecast to a 32-bit _iq and left shifted a further 5 bits:

    InputVoltage = (_iq)((long) NormInput<<5);

    Regards,

    Richard
  • Guillaume,

    If you're migrating to F280049 the IQ math library should make this an easy port, at least for this part of the code - you just have to change the MATH_TYPE in the header file "IQmathLib.h" from IQ_MATH to FLOAT_MATH. It should compile just fine like that (I think).

    Regards,

    Richard