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.

MSP-EXP430FR6989: Questions about TSM_Auto_cal(), generated by FlowESIGUI

Part Number: MSP-EXP430FR6989

Hi all!

My quistions are:

  1. How can I be sure, that this function doesnt end up as a infinite loop?(For example if mathTemp is always smaller than "12", AFE dac value always smaller than 1600?)
  2. What is the "12" value in one of the if statements?
  3. What is cycle width, and why is it defiened as "8"?

My device doesnt detect any rotation(I think I am struggling to find the correct DAC value), is it possible that this is caused by my capacitor?

Maybe the capacity too big? I included the LC sensor parameters and the generated functions first part(second part is same for channel1).

void TSM_Auto_cal(void)
{
	// constant and variable for TSM calibration
#define CYCLE_WIDTH 8      		// which is equal to (ESICLK / freq of LC) - 2
#define LC_THRESHOLD_TSM_CAL 1600
#define CH0_FINISH  BIT0
#define CH1_FINISH  BIT1


	int8_t calStatus = 0;
	int16_t mathTemp;
	uint16_t i;
	findDACParams fparams= {0};

	int8_t ch0Counter;
	int16_t dAC0_sum1, dAC0_sum2;	int8_t ch1Counter;
	int16_t dAC1_sum1, dAC1_sum2;



/**
 * This module is used to find the signal level of LC oscillation for
 * ESICH0, ESICH1, ESICH2 or ESICH3 depending on user selection.
 * This calibration updates calibration delay:
 *
 *     -TSM state 3  -  7  for CH0
 *     -TSM state 13 - 17  for CH1
 *     -TSM state 23 - 27  for CH2
 */

	dAC0_sum1 = dAC0_sum2 = 0;
	fparams.channel0Enabled = true;
	ch0Counter = 0 ;
	dAC1_sum1 = dAC1_sum2 = 0;
	fparams.channel1Enabled = true;                 // 2 LC sensor system
	ch1Counter = 0 ;

/* START of TSM Auto-calibration */

	do{
		// Find DAC threshold using 12-BIT successive approximation
		FindDAC(&fparams);  

		dAC0_sum2 = ESI_getAFE1DACValue(CHANNEL_0_DAC1_UPPER_REGISTER);
		dAC1_sum2 = ESI_getAFE1DACValue(CHANNEL_1_DAC1_UPPER_REGISTER);


		// Channel 0 TSM Auto-calibration
		if(!(calStatus & CH0_FINISH)){

		    if (dAC0_sum2 > LC_THRESHOLD_TSM_CAL)                   // LC_THRESHOLD_TSM_CAL = 1600 
		    {
		        if (dAC0_sum2 > dAC0_sum1)                          
		        {
		            mathTemp = dAC0_sum2 - dAC0_sum1;               
				}
		        else                                                
		        {
					mathTemp = dAC0_sum1 - dAC0_sum2;               
				}

				ch0Counter += 1;                                    

				if (mathTemp > 12)      
				{
				    if (ch0Counter > CYCLE_WIDTH)               
				    {
				        for (i= 0; i< ch0Counter / 2 ; i++)
				        {
				            ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_3,ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_3) - 1); 
						}      
						calStatus |= CH0_FINISH;
						
					}
				    else
				    {
						 ch0Counter = 0;
						 dAC0_sum1 = dAC0_sum2;
					}
				}
				else
				{
					dAC0_sum1 = dAC0_sum2;
				}
			}

			if(!(calStatus&CH0_FINISH)){

				// Determine which high frequency state can increment state
				// duration by 1    
				if(!(ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_3) == ESI_TSM_STATE_DURATION_MAX))       
				{
				    ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_3,ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_3) + 1);
				}
				else if(!(ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_4) == ESI_TSM_STATE_DURATION_MAX))
				{
					ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_4,ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_4) + 1);
				}
				else if(!(ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_5) == ESI_TSM_STATE_DURATION_MAX))
				{
					ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_5,ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_5) + 1);
				}
				else if(!(ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_6) == ESI_TSM_STATE_DURATION_MAX))
				{
					ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_6,ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_6) + 1);
				}
				else if(!(ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_7) == ESI_TSM_STATE_DURATION_MAX))
				{
					ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_7,ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_7) + 1);
				}
				else
				{
					// If all high frequency state have been maxed out,
					// increment ACLK cycle by one and reset repeat cycles for
					// all high frequency time states
					ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_2,ESI_TSM_getTSMStateDuration(ESI_TSM_STATE_REG_2) + 1);
					ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_3, ESI_TSM_STATE_DURATION_MIN);
					ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_4, ESI_TSM_STATE_DURATION_MIN);
					ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_5, ESI_TSM_STATE_DURATION_MIN);
					ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_6, ESI_TSM_STATE_DURATION_MIN);
					ESI_TSM_setTSMStateDuration(ESI_TSM_STATE_REG_7, ESI_TSM_STATE_DURATION_MIN);
					dAC0_sum1 = dAC0_sum2 = 0;
					ch0Counter = 0;
				}
			}
		}
}

Any help is appreciated.

  • Hello Bálint ,

    Thanks for your posting, I have contacted our ESI expert to look into this for you.

    Thanks,

    Yiding 

  • Hello Balint,

    am not sure if you have the Experimenter board. If yes then you can observe the behavior of that function in real live.

    In order to auto calibrate the wheel would need to turn to give the calibration routine some chance to see both situation; one with the metal in front of the coil ant the other without. 

    Without any rotation the calibration would not be able to complete => there you've got the infinite loop, as it cannot complete its job.. To avoid this simply use a timer and on expiration abort the calibration loop with an error message, alternatively modify the calibration function with an additional max loop count. Still you would need to report an error, or indicate to the user that the wheel has to turn for auto calibration.

    The value 12 represents the sensitivity larger values make it less sensitive' the wheel would need to be closer to be detected, smaller numbers make it more sensitive; the heel can be further away. But be careful a too sensitive setting could lead to the effect that the system senses environmental noise as motion. The value 12 has been found to be reasonable to start with.

    I looked at your components for the resonator... hm...  have a look on the table below...

    those are more common, they have been used and are multiply tested.

    As you can see there is always a difference between the calculated values and reality. Components come with tolerances and usually not all parasitic Cs and Ls are considered in the calculation. You also can look into SLAA222x

    have a nice day  Johann

     

     

  • Dear Johann,

    sorry for the delayed response.

    Your answer was very helpful, it helped me clear several things.

    The issue I still need help with: This device cannot provide a full rotation during calibration. As I am doing water metering for low consumption system, I have no way of knowing when will a full rotation circle happen(it might take a month or so).

    I am looking for a way to find an "optimal" DAC value without relying on rotaion. Is it possible to achieve this? 

    I am stuck in function "Set_DAC", this is where the application is waiting for the rotation to happen.  

    I understand that right now this application stays inside the inner do-while.

    Set_DAC function:

    void Set_DAC(void)
    {
    // min 4 ,  max 6;
    #define SEPARATION_FACTOR   				4           
    
    	uint16_t loopCounter = 0;
    	fastParams fsParams= {0};
    
    	gMinDACCH0 = 4096;
    	gMaxDACCH0 = 0;
    
    	
    	gMinDACCH1 = 4096;
    	gMaxDACCH1 = 0;
    
    
    
    	fsParams.range = 5;         //?
    
    	fsParams.channel0Enabled = true;
    	fsParams.channel1Enabled = true;
    
    
    
    	// minimum times 4, maximum 6;
    	gStateSeparation = gNoiseLevel*(SEPARATION_FACTOR-1)+gNoiseLevel/2;
    	
    
    	 // do loop for 1 more second after valid separation detected;               //why?
    	do
    	{
    		// do loop for detection of valid Max-Min separation;
    		do
    		{
    
    		    
    			fsParams.channel0StartingPoint = ESI_getAFE1DACValue(CHANNEL_0_DAC1_UPPER_REGISTER);
    			fsParams.channel1StartingPoint = ESI_getAFE1DACValue(CHANNEL_1_DAC1_UPPER_REGISTER);
    
    
    			
    			FindDAC_Fast_Successive(&fsParams);
    			
    
    			if(fsParams.channel0Enabled ==true)
    			{
    				if(ESI_getAFE1DACValue(CHANNEL_0_DAC1_LOWER_REGISTER) < gMinDACCH0)
    				{
    
    					gMinDACCH0 = ESI_getAFE1DACValue(CHANNEL_0_DAC1_LOWER_REGISTER);
    				}
    
    				if(ESI_getAFE1DACValue(CHANNEL_0_DAC1_UPPER_REGISTER) > gMaxDACCH0)
    				{
    					gMaxDACCH0 = ESI_getAFE1DACValue(CHANNEL_0_DAC1_UPPER_REGISTER);
    				}
    			}
    
    			if(fsParams.channel1Enabled ==true)
    			{
    				if(ESI_getAFE1DACValue(CHANNEL_1_DAC1_LOWER_REGISTER) < gMinDACCH1)
    				{
    					gMinDACCH1 = ESI_getAFE1DACValue(CHANNEL_1_DAC1_LOWER_REGISTER);
    				}
    
    				if(ESI_getAFE1DACValue(CHANNEL_1_DAC1_UPPER_REGISTER) > gMaxDACCH1)
    				{
    					gMaxDACCH1 = ESI_getAFE1DACValue(CHANNEL_1_DAC1_UPPER_REGISTER);
    				}
    			}
    
    
    
    			// To detect the a change due to rotation
    			// if a separation of gStateSeparation is found, a rotation is
    			// detected and keep running for 1 second to find the max and min
    
    			gThresholdH0 = gMaxDACCH0 - gMinDACCH0;
    			gThresholdH1 = gMaxDACCH1 - gMinDACCH1;
    
    
    
    			// check for valid separation
    
    			if(fsParams.channel0Enabled==true)
    			{
    				if (gThresholdH0 > gStateSeparation)
    				{
    					gESIStatusFlag |= VALID_SEPARATION_CH0;
    				}
    			}
    			if(fsParams.channel1Enabled==true)
    			{
    				if (gThresholdH1 > gStateSeparation)
    				{
    					gESIStatusFlag |= VALID_SEPARATION_CH1;
    				}
    			}
    
    			
    		}while (!((gESIStatusFlag&VALID_SEPARATION_CH0)&&(gESIStatusFlag&VALID_SEPARATION_CH1)));
    
    
    		
    		loopCounter++;
    	} while(loopCounter < 468)   ;   // 1 second for 2340Hz using Find_Fast_Successive();
    
    
    	// "+" for INV version, "-" for non-INV version
    
    	if(fsParams.channel0Enabled ==true)
    	{
    		ESI_setAFE1DACValue((gMaxDACCH0 + gMinDACCH0)/2, CHANNEL_0_DAC1_UPPER_REGISTER);
    		// "+" for INV version, "-" for non-INV version
    		ESI_setAFE1DACValue(ESI_getAFE1DACValue(CHANNEL_0_DAC1_UPPER_REGISTER) + gNoiseLevel, CHANNEL_0_DAC1_LOWER_REGISTER);
    		gAFE1Base0 = ESI_getAFE1DACValue(CHANNEL_0_DAC1_UPPER_REGISTER);
    		// "-" for INV version, "+" for non-INV version
    		ESI_setAFE1DACValue(ESI_getAFE1DACValue(CHANNEL_0_DAC1_UPPER_REGISTER) - gNoiseLevel, CHANNEL_0_DAC1_UPPER_REGISTER);
    	}	
    	if(fsParams.channel1Enabled ==true)
    	{
    		ESI_setAFE1DACValue((gMaxDACCH1 + gMinDACCH1)/2, CHANNEL_1_DAC1_UPPER_REGISTER);
    		// "+" for INV version, "-" for non-INV version
    		ESI_setAFE1DACValue(ESI_getAFE1DACValue(CHANNEL_1_DAC1_UPPER_REGISTER) + gNoiseLevel, CHANNEL_1_DAC1_LOWER_REGISTER);
    		gAFE1Base1 = ESI_getAFE1DACValue(CHANNEL_1_DAC1_UPPER_REGISTER);
    		// "-" for INV version, "+" for non-INV version
    		ESI_setAFE1DACValue(ESI_getAFE1DACValue(CHANNEL_1_DAC1_UPPER_REGISTER) - gNoiseLevel, CHANNEL_1_DAC1_UPPER_REGISTER);
    	}
    }
    
    

  • Hello Balint,

    have not had this request yet... will think about some options...

  • The original intend for calibration is to find the best values to differentiate the two states (attenuated, not attenuated). The calibration is usually done at the beginning of the meter's lifetime. Then the meter is integer and cannot be fooled around with anymore. Adding a re-calibration based on no-rotation would open a door for tampering and fraudulence. I understand that you would like to address loss of sensitivity based on aging or other environmental influences, like bending or misalignment. 

    The 'FR6989 device senses the presence of an metal in front of a coil by measuring the attenuation by observing the decay of the oscillation. 

    Theoretically you could write a calibration function that uses a dynamic self adjusting threshold which gets updated whenever a rotation is detected. This could work. Here you would need to interleave the calibration functions whenever a rotation is detected to update the threshold very gently, and only after you successfully identifies a true rotation.  Such a function with self adjusting thresholds we do not have in place since it is not mainstream.

    I further doubt that you will get a meter certification since the mechanism might not been seen as tamper proof.  I attached some slides that address mechanical  problems that could lead to a wide spread of thresholds between the coils. Maybe some mechanical alignment helps.

    To safely pick up the threshold for an self adjusting system I recommend to use a separate coil. Thus you can keep the active measurement function and the adjustment function separate.

    have fun and best regards   

                               Johann

  • Dear Johann,

    Thank you for your feedback, as always it was very helpful.

    Johann Zipperer said:

    The original intend for calibration is to find the best values to differentiate the two states (attenuated, not attenuated). The calibration is usually done at the beginning of the meter's lifetime. Then the meter is integer and cannot be fooled around with anymore.

    Does this mean, that the daily temperature fluctuation is not significant when determining DAC values? 

    Can we use DAC values, that we measured in our office/lab, in the field device? Does it stay relevant for the lifetime of the meter(for e.: 8 years)? 

    Bálint

  • Hello Balint,

    - The daily temperature fluctuation should not have such a strong influence to affect the reading. The same is true for supply voltage, meter's orientation (referring the earth's magnetic field) nor any other environmental influences. It is also clear the further the rotating disk is away from the sensor coils, the weaker is the signal that is picked up. If you lower the hysteretic you make the system more sensitive in general; but also more sensitive to environmental influences.  .

    - The lab/office values can be taken to start; better however are values that are derived when the meter is connected to all the piping; and it is supposed to work in any mounting direction you specify.

    - I've got another suspicion; maybe it's the core material of the coil...  my 470uH coil require 160 turns.... this means the AL-value of the core is rather low. Higher ALs allow a smaller size but the coils suffer on direction sensitivity then used as magnetic antenna. 

    -  With the scan-interface a coil is not operated as an storage inductor, nor a frequency determining element. The coil's magnetic side effect is simply used as a pickup element for a magnetic distortion.=> Please let me know how many turns one of your coils has.

    Johann

  • Dear Johann,

    Johann Zipperer said:

    -  With the scan-interface a coil is not operated as an storage inductor, nor a frequency determining element. The coil's magnetic side effect is simply used as a pickup element for a magnetic distortion.=> Please let me know how many turns one of your coils has.

    I made quite a few changes.

    Firstly, I changed the coils to the same type that TI provides in the sensor board for EVM430-FR96989. I think the turn number is the same as yours.

    Also, I made lots of calibrations to get a average value, to use at initialization.

    I started working with 1 sensor and noticed, that sometimes there were multiple interrupts for a single turn(1 turn, but I received multiple impulses). After I increased the difference between the hysteresis voltage levels the problem seems resolved.

    Currently the application is working with one sensor, but I plan to switch to 2 sensors in the future.

    Thank you very much for your patience and help.

    Bálint

**Attention** This is a public forum