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.

LAUNCHXL-F280049C: ADC offset calibration (SDK)

Guru 54808 points
Part Number: LAUNCHXL-F280049C
Other Parts Discussed in Thread: MOTORWARE

It would seem a critical error was made in how the motor SDK (FOC) performs zero offset calibration. According to TRM 13.13.1 Pg.1498 the 512 conversion results are to be divided by a multiple of 16, not 512. This may account for ePWM fault trips randomly occurring when motor ID offset calibration and ABRUPTLY transitions from any previous time wait into next time wait.
Also note another mistake to subtract (adcOffsetMean) from 96 when 112 was specified in the TRM.

1. Why has FE chosen to disqualify the TRM specification for ADC channel offset calibration in the SDK code snip below? 

2. Why would we divide the results by 512 when that is to be the number of converted samples acquired? 

13.13.1 ADC Zero Offset Calibration

Use the following procedure to re-calibrate the ADC offset in 12-bit, single-ended mode:
1. Set ADCOFFTRIM to +112 steps (0x70). This adds an artificial offset to account for negative offset that
may reside in the ADC core.
2. Perform some multiple of 16 conversions on VREFLO (internal connection), accumulating the results
(for example, 32*16 conversions = 512 conversions).

3. Divide the accumulated result by the multiple of 16 (for example, for 512 conversions, divide by 32).

4. Set ADCOFFTRIM to 112 – result from step 3.

    adcOffsetMean = 0;
    adcSum = 0;
    index = 0;
    sampleSize = 512;
    //Calculate average ADC sample value
    adcOffsetMean = adcSum / sampleSize;

    // delay to allow ADCs to power up
    SysCtl_delay(100U);

    EALLOW;
    HWREGH(base + ADC_O_OFFTRIM) = 96 - adcOffsetMean;
    EDIS;

  • Seemingly HAL_runADCZeroOffsetCalibration() is never being called by the SDK, is01_Intro.c or is05_motor_id.c. The ADC channels are not exactly calibrated prior to runOffsetsCalculation() 50% PWM duty cycle occurs. 

    Lab 5 runOffsetsCalculation() does what exactly if the ADC has never been properly calibrated by call to HAL_runADCZeroOffsetCalibration()?  Note the above post divide results 512 (SampleSize) should be divide by 32. Not being critical of SDK only seek to improve the motor ID functionality. 

    13.13.1 ADC Zero Offset Calibration

    Zero offset error is defined as the difference from 0 that occurs when converting a voltage at VREFLO. The zero offset error can be positive or negative. To correct this error, an adjustment of equal magnitude and opposite polarity is written into the ADCOFFTRIM register. The value contained in this register will be applied before the results are available in the ADC result registers. This operation is fully contained within the ADC core, so the timing of the results will not be affected and the full dynamic range of the ADC will be maintained for any trim value.

    Using the GetAdcOffsetTrimOTP(Uint16) function, the ADCOFFTRIM register can be loaded with the factory calibrated offset error correction. The user can modify the ADCOFFTRIM register to compensate for additional offset error induced by the application environment if desired, but this is not typically necessary to achieve datasheet specified performance.

  • HAL_OffsetCal() call was being hijacked by an handle function. CCS IDE can not back track links to inline function calls via CTRL+ hover. And the IDE find function can not detect the first call that invokes the actual function. Yet the calibration of ADC module was not being done correctly omitted as it would fault in the function CCS debug. It's not a matter that calibration was/is not necessary rather that it took time to debug reason for the fault condition. Perhaps chalk this up as on the go engineering?

        // run the device calibration
        HAL_cal(handle);
    //! \brief      Sets up the ADCs (Analog to Digital Converters)
    //! \param[in]  handle  The hardware abstraction layer (HAL) handle
    extern void HAL_runADCZeroOffsetCalibration(const uint32_t base);
    
    
    //! \brief      Executes calibration routines
    //! \details    Values for offset and gain are programmed into OTP memory at
    //!             the TI factory.  This calls and internal function that programs
    //!             these offsets and gains into the ADC registers.
    //! \param[in]  handle  The hardware abstraction layer (HAL) handle
    extern void HAL_cal(HAL_Handle handle);
    void HAL_cal(HAL_Handle handle)
    {
    	/* Pass the base address for each ADC to establish
    	 * an offset calibration for each ADC module */
    	HAL_runADCZeroOffsetCalibration(ADCA_BASE);
    	HAL_runADCZeroOffsetCalibration(ADCB_BASE);
    	HAL_runADCZeroOffsetCalibration(ADCC_BASE);
    
      return;
    } // end of HAL_cal() function

  • As replied to other threads you posted, the HAL_runADCZeroOffsetCalibration is not used in MotorControlSDK, it's just for the previous devices in motorWare.

  • The SDK offset calculation does not do the same thing to ADC as HAL_cal does. So the offsets values SDK came up with after motor ID were uneven prior to HAL_cal. That HAL_cal() calibrates the ADC after factory calibration was run prior to oven cooking solder paste and at what ambient temperature, who even knows. 

  • Please explain what part of SDK function below actually modifies the ADC ADCOFFTRIM  register. It's not a matter of what so much but more a matter of why not and how come. The lab5 function below (offset calculation) is not the same as offset calibration. Best I can tell all it does is zero out many of the FAST estimator motor.vars prior to collecting update motor.vars. So if we end CCS debug session and attempt to launch again with user.h collected motor parameters enable flag (user.h parameters) the motor does not accelerate. ADC offset calibration is the least of the issues in this SDK, though very nicely laid out and coded.   

    void runOffsetsCalculation(void)
    {
        uint16_t cnt;
        float32_t Vin;
        float32_t invVdcbus;
    
        if(motorVars.flagEnableSys == true)
        {
          	/* Clear DACH/L lathes and any
          	 * Trip Zone CBC/OSHT fault flags */
          	HAL_clearPWMfaults(halHandle);
    
            //
            // enable the PWM
            //
            HAL_enablePWM(halHandle);
    
            //SCIprintf(">>Begin OffsetCalc \n");
    
            //
            // set to the half of inverse dc bus voltage
            //
            invVdcbus = 2.0 / adcData.dcBus_V;
    
            //
            // set the 3-phase output PWMs to 50% duty cycle
            //
            pwmData.Vabc_pu.value[0] = 0.0;
            pwmData.Vabc_pu.value[1] = 0.0;
            pwmData.Vabc_pu.value[2] = 0.0;
    
            for(cnt = 0; cnt < USER_NUM_CURRENT_SENSORS; cnt++)
            {
                //
                // reset current offsets used
                //
                motorVars.offsets_I_A.value[cnt] = 0.0;
    
                //
                // run current offset estimation
                //
                FILTER_FO_run(filterHandle_I[cnt],
                              adcData.I_A.value[cnt]);
    
            }
    
            for(cnt = 0; cnt < USER_NUM_VOLTAGE_SENSORS; cnt++)
            {
                //
                // reset voltage offsets used
                //
                motorVars.offsets_V_V.value[cnt] = 0.0;
    
                Vin = adcData.V_V.value[cnt] * invVdcbus;
    
                //
                // run voltage offset estimation
                //
                FILTER_FO_run(filterHandle_V[cnt], Vin);
    
            }
    
            offsetCalcCount++;
    
            if(offsetCalcCount >= offsetCalcWaitTime)
            {
                for(cnt = 0; cnt < USER_NUM_CURRENT_SENSORS; cnt++)
                {
                    //
                    // get calculated current offsets from filter
                    //
                    motorVars.offsets_I_A.value[cnt] =
                            FILTER_FO_get_y1(filterHandle_I[cnt]);
    
                    //
                    // clear current filters
                    //
                    FILTER_FO_setInitialConditions(filterHandle_I[cnt],
                                                  motorVars.offsets_I_A.value[cnt],
                                                  motorVars.offsets_I_A.value[cnt]);
    
                }
    
                for(cnt = 0; cnt < USER_NUM_VOLTAGE_SENSORS; cnt++)
                {
                    //
                    // get calculated voltage offsets from filter
                    //
                    motorVars.offsets_V_V.value[cnt] =
                            FILTER_FO_get_y1(filterHandle_V[cnt]);
    
                    //
                    // clear voltage filters
                    //
                    FILTER_FO_setInitialConditions(filterHandle_V[cnt],
                                                  motorVars.offsets_V_V.value[cnt],
                                                  motorVars.offsets_V_V.value[cnt]);
                }
    
                offsetCalcCount = 0;
                motorVars.flagEnableOffsetCalc = false;
    
                SCIprintf(">>End OffsetCalc \n");
    
                //
                // disable the PWM
                //
                HAL_disablePWM(halHandle);
    
            }
        }
    
        return;
    } // end of runOffsetsCalculation() function
    

  • These offset and gain are calibrated and saved in ROM during the test in the factory, you just need to call the SysCtl_deviceCal() to copy the saved calibration data to the related register. Sorry for confusing you,  the F28004x device doesn't need to run HAL_runADCZeroOffsetCalibration() for the calibration, we will remove this function accordingly in hal.c.

    The runOffsetsCalculation() is used to calibrate the offset of the current and voltage sensing circuit, it's not from the device. Please don't be confused with both functions and have a look at the lab02 section of the instaSPIN lab guide to understand what's the runOffsetsCalculation(). I don't think there is an issue on this function as you mentioned above if you are using the example labs on the TI's EVM kit.