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.

ADC calibration issue with assembly code

Hello.

I am using the DSP320F812 eZdsp to control 2 converters via PWM signals.

The issue is with the calibration, since the calibration is done with unsigned integers, a negative offset or small disturbance will cause the values to spin around and become positive, in this case -1 = 4095.

The gain and offset corrections are made in ADCcalibrationDriver.asm file contained in the associated files

http://focus.ti.com/general/docs/litabsmultiplefilelist.tsp?literatureNumber=spra989a

Here is the last part of the code, where the values from the 16 channels are stored in the registers calibrated. The registers contain values from 0 - 4095

        ....

        .loop   16                                           ; for ch0 to ch15 do:
        MPYU    ACC,T,*XAR7++                ; AH = ADCRESULTn*CalGain            
        SUB     AH,@AR5                             ; AH = ADCRESULTn*CalGain - CalOffset (Q0)
        MOV     *XAR4++,AH                         ; ch = ADCRESULTn*CalGain - CalOffset (Q0)
        .endloop

I need something to hinder the spin around at negative and values > 4095, could this be done using for instance a lowest and highest value limit?

AH = ADCRESULTn*CalGain

if ( AH < lowLimit)

      AH = lowLimit

elseif (AH > highLimit)

       AH = HighLimit)

end

How would one write this condition in assembly code?

  • Has anyone solved this issue?

    I am seeing it now. It looks like raising the REF_HIGH_IDEAL_COUNT and REF_LOW_IDEAL_COUNT values will patch the issue.

  • Hi Salvatorre,

    I think adding an equal amount to both of these counts will continue to calibrate correctly, but with some additional artificial offset equal to whatever was added. I think this is maybe an OK solution, you just have to take it into account for other calculations (which could get messy).

    Alternately, you could do the limit check as specified above. I think you really only need to do the check on the negative side to see if the value under-flowed. If it goes above 4095 I think that is OK, it will just appear as a voltage a little higher than VREFHI. If you are still doing assembly for this operation, it looks like you can just set the OVM (overflow mode) bit to 1 before doing the final subtraction. This will prevent the result from under-flowing.
  • Thanks for the quick response.

    I haven't written assembly code in 8 years and it wasn't for this architecture. I was hoping that there was an updated ADCcalibrationDriver.asm file that addressed this issue and that I wouldn't have to learn assembly again. The latest version I can find is v1.1, but v1.0 is effectively no different. I am patching the problem the following way after I call the ADCcalibrationDriverUpdate(...) function:

    #define UPPER_LIMIT 3071 // 0.75*4095
    #define LOWER_LIMIT 1023 // 0.25*4095

    if(adcCalibrate.ch5 > UPPER_LIMIT && (AdcRegs.ADCRESULT5 >> 4) < LOWER_LIMIT)
    adcCalibrate.ch5 = 0;
    else if (adcCalibrate.ch5 < LOWER_LIMIT && (AdcRegs.ADCRESULT5 >> 4) > UPPER_LIMIT)
    adcCalibrate.ch5 = 0x0FFF;

    However, this takes 20 cycles to complete. 20 * 16 = 320 cycles. With a 150 MHz clock, that means 2.13us. If I am executing at 10 kHz (100us), this is 2% of my execution time. The whole calibration function in assembly only takes 137 cycles (0.913 us).
  • If you want to stick with a C implementation, I think you can just do something along the lines of this after you run the calibration assembly:

    if(ch5 > 4095 * 1.5){ch5 = 0;}

    x1.5 is chosen to be higher than anything that the calibration could produce naturally. As previously stated, I don't think going past 4095 on the high end should be much of a problem, so you can omit that? Otherwise you could do:

    if(ch5 > 4095 * 1.5){ch5 = 0;}
    if(ch5 > 4095){ch5 = 4095;}

    I think it also wouldn't be too hard to find the instruction to set and clear the OVM bit (try this document: spru430f.). I think the issue will be resolved on the low side by setting the OVM bit before doing all the calibration steps. Just restore the bit when all the calibrations have run to avoid unintended side-effects. If you wanted to coerce the high side into range, you would still need to do the C calculation for:

    if(ch5 > 4095){ch5 = 4095;}

    Since the application note and software were written almost 12 years ago, it is unlikely we will open them up and release a new version of either.
  • Devin,

    Thanks for your response.

    I did confirm that there isn't a problem on the high-end since the calibration shouldn't result in a number much higher than 4095. The 16-bit number has plenty of room.

    Thank you for your possible solutions.

    Your solution: if(ch5 > 6142){ch5 = 0;} seems to be best.

    I had previously tried changing the structure of ADC_CALIBRATION_DRIVER_VARS from Uint16 values for ch0..ch15 to int16. This gave me me a very similar solution to yours except I would have if(ch5 < 0){ch5 = 0;} (for each channel used). I do like yours better since I won't have to alter a file that is 12 years old.

    Thanks for spru430f. I actually didn't have that one.

    Thanks!

    Sal

  • Hi Sal,

    You can find supplementary device documentation like the CPU instruction set guide on the "Technical Documents" tab for each device: