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.

TM4C129 - Strange problem with variables

Hello, I came on a strange problem with variable in TM4C129 TI-RTOS project.

Consider this function:

Void FanRegFxn(UArg arg0, UArg arg1) //Vstupna velicina z Main je Power v % - vykon menica 0 - 100%
{
    PWM_Handle pwm7;
    PWM_Params params;
    extern volatile float Temp_MainTX, Temp_AuxTX, Temp_MainHB, Temp_AuxHB, TempPower;
    extern volatile float Power, I_Bat, I_Bat_avg;

    extern volatile float Temp; //zmerana teplota
    //float	TempPower1 = 0;
    //float	argExp = 0;
    float   FanPwmPeriod = 72;      // Period and duty in microseconds
    float   duty = 0;
    extern volatile float dutypct;
    float TempPower1 = 0;

    PWM_Params_init(&params);
    params.period = FanPwmPeriod;
    params.polarity = PWM_POL_ACTIVE_LOW;
    pwm7 = PWM_open(PWM7, &params);
    if (pwm7 == NULL) {
    System_abort("PWM7 did not open");
    }

    /* Loop forever adjusting the PWM duty */
    while (1) {

    	AMeasTempFxn(); // meranie teploty

    	Temp = fmaxf(fabsf(Temp_MainTX),fabsf(Temp_MainHB)); // zistenie najvyssej teploty zo vsetkych senzorov. Rozopnuta poistka dava -100°C preto fabsf.
    	Temp = fmaxf(Temp,fabsf(Temp_AuxHB));
    	//Temp = fmaxf(Temp,fabsf(Temp_AuxTX));

    	TempPower1 = TempPower;

    	TempPower = (0.9*TempPower1+0.1*Temp);

        	if (TempPower > 110)
        	{        	
        			SystemMode = 0; ErrorCode = 5;

        	} //overtemperature shutdown - vypnute na testovanie

    	//ZAPINANIE/VYPINANIE:

        //PWM_setDuty(pwm6, duty) // toto sa tyka PWM6 (Speaker_PWM)

    	if (TempPower < 30.0) {
    	    GPIOPinWrite(GPIO_PORTK_BASE,GPIO_PIN_6,0);// Turn off fans
    	    dutypct = 0; // Set zero duty
    	}
    	else if (TempPower > 35.0)
    	{
    		GPIOPinWrite(GPIO_PORTK_BASE,GPIO_PIN_6,GPIO_PIN_6);// Turn on fans
    		dutypct = 1.0; // <40°C = 1% aby sme videli ze idu
    	};

    	//REGULACIA:

    	if (TempPower > 40.0) {
    			if (TempPower < (60.0))
    			{
    				dutypct = (TempPower - 40.0) * 5;
    			}
    			else
    			{
    				dutypct = 100.0; // >45°C = 100%

    			};
    	}
    	else if (TempPower > 35.0) dutypct = 1.0;

    	duty = ((dutypct/100.0)*FanPwmPeriod);
        if (pwm7) {
            PWM_setDuty(pwm7, duty);
        }

        System_printf("TempPower °C= %f\n",TempPower1);

        System_flush();

        Task_sleep((UInt) arg1);

    }
}

The function is to measure four temperatures, get the highest of them, smooth it out and set up fan speed accordingly. If temperature is too high, turn off the system and set error code.

Everything works, except the smoothing of the values. This is an inverter project and at higher powers, I get some noise at the thermistor lines that needs to be removed. The simplest way I thought of was to take 9/10th of the old maximum temperature (TempPower variable) and one tenth of new maximum temperature (Temp variable):

TempPower = (0.9*TempPower+0.1*Temp);

But when I do that, or anything similar, I get an (error) instead of the expected value. Also, when I debug and break before that point, I can not Step Into that. It just skips over that row. I tried to modify it in a way that I do not read and overwrite TempPower on the same row:

float TempPower1 = 0;
...
    	TempPower1 = TempPower;
    	TempPower = (TempPower1+Temp);


But still the same problem persists. And on the Variables view, there are these red warnings about invalid register indexes. What is causing them?

I do similar averaging with voltages and other variables in other function and it works as expected.

What could be the problem here?

Thanks in advance for help.

  • user4016414 said:
    But when I do that, or anything similar, I get an (error) instead of the expected value.

    What do you mean by error?

    Robert

  • Dear Robert, I would also like to know what the MCU means by that. I can see only what is displayed on the console in the attached screenshot, and the red Invalid Register Number warnings.
    Even if I list it on the webpage served from the MCU, the same string "(error)" instead of a number appears.
  • OK, first, the MCU is not giving you that your IDE is. That is an important distinction.
    Second, Is this happening at a breakpoint (I assume so)? Where is this breakpoint?

    Robert

    You've got some rather odd programming structure there. I don't think it's a problem but it is strange.
  • It is happening regardless of breakpoint or not, but in this case the breakpoint was set at line 859 as can be seen from the screenshot. It happens also in real application with debugger disconnected, when it calculates duty cycle for fans PWM from the TempPower value. The fans just spin at 100% speed and the webpage shows the same "(error)" only, instead of the expected averaged TempPower value.

  • user4016414 said:
    It is happening regardless of breakpoint or not

    Since most are locals, you wouldn't expect the debugger to have valid values while running.

    Robert

  • Most are locals? What do you mean by that? TempPower, input temperature values and most other variables are defined at the top of the file as Volatile ...
  • Let's also point out another elephant.

    You're breakpointing (or worse single stepping) power electronics code??!

    Robert
  • user4016414 said:
    Most are locals? What do you mean by that? TempPower, input temperature values and most other variables are defined at the top of the file as Volatile ...

    As locals. They are defined inside a function.

    Mind you, volatile float seems almost an oxymoron and you are violating volatile by displaying them in a debug window.

    Why are they volatile in any case?

    Robert

  • Sorry, missed the extern, where are they actually defined?

    Robert
  • Robert Adsett said:
    Sorry, missed the extern, where are they actually defined?
     

    Actually, only temp is non-local.

    Robert

  • Robert, I got your point but don't worry, I am not that stupid. Yes I am breakpointing, but this is safe - HW is only a control board with sensors but no power stages attached. And in any case I have set the MCU to inhibit PWM outputs when debugger halts it.
    Please let's get back to my problem, I believe it has nothing to do with breakpoints or debugging methods.
  • If I understand this correctly, when I define something at the beginning of the file, i.e. before any Tasks or Init or Main, it is global, not local. So my variables are defined at the beginning of the file. For the reason that I need to access most of them from more than one task.
    So in this FanRegFxn task for example, I take those four temperatures which are measured by ADC routine in another task, every second. I could use another method maybe it would be more efficient, but hey it works and it is simple.. Only problem I need to solve is with the TempPower variable in this FanRegFxn task ...
  • user4016414 said:
    Please let's get back to my problem, I believe it has nothing to do with breakpoints or debugging methods

    I'm not convinced, but in any case I'd do something simpler. Especially since it's filter code and you appear to have no trouble with time. Just log the intermediate values and bring them into a spreadsheet. I suspect you'll find the IDE behaviour is a red herring.

    Robert

  • user4016414 said:
    If I understand this correctly, when I define something at the beginning of the file, i.e. before any Tasks or Init or Main, it is global, not local.
    Every one of the highlighted variables is local
    Void FanRegFxn(UArg arg0, UArg arg1) //Vstupna velicina z Main je Power v % - vykon menica 0 - 100%
    {
        PWM_Handle pwm7;
        PWM_Params params;
        extern volatile float Temp_MainTX, Temp_AuxTX, Temp_MainHB, Temp_AuxHB, TempPower;
        extern volatile float Power, I_Bat, I_Bat_avg;
        extern volatile float Temp; //zmerana teplota
        //float TempPower1 = 0;
        //float argExp = 0;
        float   FanPwmPeriod = 72;      // Period and duty in microseconds
        float   duty = 0;
        extern volatile float dutypct;
        float TempPower1 = 0;
    The compiler can optimize access and reallocate as needed (no volatile to restrict access).
    user4016414 said:
    So my variables are defined at the beginning of the file. For the reason that I need to access most of them from more than one task.
    That doesn't explain why you have them as volatile.
    Robert
  • user4016414 said:
    So in this FanRegFxn task for example, I take those four temperatures which are measured by ADC routine in another task, every second.

    And if you are interrupted part way through an update?

    Robert

  • OK you may be right, but I do not care what IDE shows or not. I only started to debug and breakpoint it when I discovered it is not working in real application. So all I need is that the line

    TempPower = (0.9*TempPower1+0.1*Temp);

    starts working as it should.
    For example, this is how I calculate the voltage averages and it works flawlessly:

    result = (result + 4*V_Bat)*0.2;
  • Every one of the highlighted variables is local

    Yep, that is true.

  • Like I said log it. You have printf statements in it already so you are clearly not worried about execution time.

    print Temp, TempPwer1 and TempPower on each cycle

    Grab a few 10's of samples

    Import into a spreadsheet (just format your print as a CSV) and compare what you get to what you expect.

    I expect you will find either
    - it's working and the problem lies elsewhere or
    - what you are calculating and what you think you are calculating are not the same.

    Robert
  • Well to be honest I seen that in another code and thought I need to have them volatile so that other functions can access that. Do you think I can remove Volatile and it will work the same way? Maybe a stupid question - I am not very experienced in C programming, sorry..
    For the interrupt question - It should not happen since the tasks that need these variables have higher priorities than the ones updating them.
  • Robert. There is nothing to log, since the very first time I try to modify the TempPower by doing some calculation, it outputs that Error.
    Only thing that can be done is to assign the TempPower the value of some other variable, like

    TempPower = Temp
    and even TempPower = Temp + Temp works.
    But as soon as I, for example, do TempPower = 2*Temp , I get that Error.
  • user4016414 said:
    It should not happen since the tasks that need these variables have higher priorities than the ones updating them

    So the read can interrupt part way through an update.

    user4016414 said:
    Do you think I can remove Volatile and it will work the same way?

    Too many volatiles is almost as bad as too few.

    All volatile guarantees is that each access to a volatile variable will occur and in the order specified (reads and writes are not optimized or duplicated or reordered).

    There's subtle points about what order means etc.. but that is the meat of it.

    There is no assurance that reads or writes will be atomic or that any other property is preserved. A write to a word for instance could be done as two bytes even for a volatile

    .

    Robert

  • Robert Adsett said:

    So the read can interrupt part way through an update.

    Actually, you are right ... But does the update last more than one clock cycle? If not, it should not be a problem I believe...

    I have a semaphore implemented in the ADC routine, as more tasks are using it and I need to assure that every task starts using ADC only when semaphore is posted ... If needed I can also implement something like that in FanRegFxn.

    EDIT> I did forget it but here, I call the function that overwrites the input variables - AMeasTempFxn() - in the regulation task itself:

    /* Loop forever adjusting the PWM duty */
        while (1) {
    
            AMeasTempFxn(); // meranie teploty
    
            Temp = fmaxf(fabsf(Tmp_MainTX),fabsf(Tmp_MainHB)); // zistenie najvyssej teploty zo vsetkych senzorov. Rozopnuta poistka dava -100°C preto fabsf.
            Temp = fmaxf(Temp,fabsf(Tmp_AuxHB));
            //Temp = fmaxf(Temp,fabsf(Tmp_AuxTX));

    So it can not happen that reads or writes are interrupted.

    So when I remove the Volatile word, from any variable declaration, and if some task will loop checking its value and doing samething based on that (like regulate fan speed) while some other task will modify it (like ADC measurement), the first task may not notice the second task changed the variable value, is that so? This situation happens many times in my code ... So what could be the exit from this? Reduce the number of Volatile variables? What is the actual limit?

  • Btw. Now I tried to redefine about five global variables that I do not modify in any task (only set it up at var. declaration), without Volatile, and it did not change anything ...
  • There's no limit to the number of volatiles, at least not practically.

    Robert
  • Yes, an update could easily take more than a single cycle, floats especially could be using rmw operations.

    Robert
  • PROBLEM SOLVED!

    Robert, I thought again about your advice to log. I noticed that even when I do TempPower1 = Temp the first value is Error. Next values however are OK. So I also uncommented my other System_Printf's for all four input temperatures. And, surprisingly, they were all errors at first cycle! I did never notice this in real life, because it happens on power-up only and I need to actually switch the device on with a button to start the power electronics which generate heat and needs to be cooled by that FanRegFxn().

    I realized that this is Task0, and even there are higher priority tasks in the RTOS, this one would run first and will use the ADC as first one. So I simply added a Task_sleep(1000); before the while(1) loop in FanRegFxn() and now I have very nice readings with all temperatures are averaged:

    [CORTEX_M4_0] Service Status: DHCPC    : Enabled  :          : 000
    Service Status: HTTP     : Enabled  :          : 000
    Service Status: DHCPC    : Enabled  : Running  : 000
    Tmp_MainTX °C= -20.1370
    Tmp_MainHB °C= 5.9903
    Tmp_AuxTX °C= -20.1370
    Tmp_AuxHB °C= 4.9775
    Temp °C= 20.1370
    TempPower °C= 20.1370
    Tmp_MainTX °C= -36.2473
    Tmp_MainHB °C= 10.9650
    Tmp_AuxTX °C= -36.2473
    Tmp_AuxHB °C= 8.9621
    Temp °C= 36.2473
    TempPower °C= 36.2473
    Tmp_MainTX °C= -49.1349
    Tmp_MainHB °C= 14.9864
    Tmp_AuxTX °C= -47.7869
    Tmp_AuxHB °C= 12.1472
    Temp °C= 49.1349
    TempPower °C= 49.1349
    Tmp_MainTX °C= -58.0969
    Tmp_MainHB °C= 18.2531
    Tmp_AuxTX °C= -58.3665
    Tmp_AuxHB °C= 14.6954
    Temp °C= 58.0969
    TempPower °C= 58.0969
    Tmp_MainTX °C= -66.6153
    Tmp_MainHB °C= 20.8460
    Tmp_AuxTX °C= -66.8310
    Tmp_AuxHB °C= 16.7289
    Temp °C= 66.6153
    TempPower °C= 66.6153
    Tmp_MainTX °C= -73.4300
    Tmp_MainHB °C= 22.9267
    Tmp_AuxTX °C= -72.2545
    Tmp_AuxHB °C= 18.3558
    Temp °C= 73.4300
    TempPower °C= 73.4300
    Tmp_MainTX °C= -78.8817
    Tmp_MainHB °C= 24.5951
    Tmp_AuxTX °C= -76.5933
    Tmp_AuxHB °C= 19.6572
    Temp °C= 78.8817
    TempPower °C= 78.8817
    Tmp_MainTX °C= -83.2431
    Tmp_MainHB °C= 25.9558
    Tmp_AuxTX °C= -81.4124
    Tmp_AuxHB °C= 20.6984
    Temp °C= 83.2431
    TempPower °C= 83.2431
    Tmp_MainTX °C= -86.7315
    Tmp_MainHB °C= 27.0184
    Tmp_AuxTX °C= -85.2670
    Tmp_AuxHB °C= 21.5438
    Temp °C= 86.7315
    TempPower °C= 86.7315
    Tmp_MainTX °C= -89.5223
    Tmp_MainHB °C= 27.8512
    Tmp_AuxTX °C= -88.3506
    Tmp_AuxHB °C= 22.2275
    Temp °C= 89.5223
    TempPower °C= 89.5223
    Tmp_MainTX °C= -91.7542
    Tmp_MainHB °C= 28.5239
    Tmp_AuxTX °C= -90.8169
    Tmp_AuxHB °C= 22.7720
    Temp °C= 91.7542
    TempPower °C= 91.7542
    Tmp_MainTX °C= -93.5397
    Tmp_MainHB °C= 29.0707
    Tmp_AuxTX °C= -91.4418
    Tmp_AuxHB °C= 23.2001
    Temp °C= 93.5397
    TempPower °C= 93.5397
    Tmp_MainTX °C= -94.9688
    Tmp_MainHB °C= 29.5341
    Tmp_AuxTX °C= -93.2905
    Tmp_AuxHB °C= 23.5451
    Temp °C= 94.9688
    TempPower °C= 94.9688
    Tmp_MainTX °C= -96.1121
    Tmp_MainHB °C= 29.8745
    Tmp_AuxTX °C= -94.7694
    Tmp_AuxHB °C= 23.8137
    Temp °C= 96.1121
    TempPower °C= 96.1121
    Tmp_MainTX °C= -97.0260
    Tmp_MainHB °C= 30.1361
    Tmp_AuxTX °C= -95.9519
    Tmp_AuxHB °C= 24.0335
    Temp °C= 97.0260
    TempPower °C= 97.0260
    Tmp_MainTX °C= -97.7572
    Tmp_MainHB °C= 30.3734
    Tmp_AuxTX °C= -95.5498
    Tmp_AuxHB °C= 24.2167
    Temp °C= 97.7572
    TempPower °C= 97.7572
    Tmp_MainTX °C= -96.9962
    Tmp_MainHB °C= 30.5277
    Tmp_AuxTX °C= -96.5782
    Tmp_AuxHB °C= 24.3411
    Temp °C= 96.9962
    TempPower °C= 96.9962
    

    Voilla! For some reason the ADC needs some time after its initialization before outputting reasonable values. And since my filtering always takes previous values, the errorneous first value got perpetrated to all subsequent, wannabe-averaged values.

    Thanks in advance Robert! You pointed me in the right direction.

    Could you please also take a short look on my other problem with timers?

    e2e.ti.com/.../1921464

    Thanks!

  • You are assuming that error is not just an artifact of the IDE or the way you are using it. Logging will show you what is happening, most importantly it will give you a 'real time' snapshot with the real feedback something that breakpoints cannot do. And since you already have print statements working it's simple to add.

    Robert
  • Have you waited for the a/ d to finish initializing before usin
    Also, your sensor output circuitry may need time to stabilize, as could your references and analog supplies.

    Robert
  • Ahem, before using it?

    Robert
  • I thought the driver will take care of that...

    This is the init sequence...

    void EK_TM4C129EXL_initADC(void)
    {
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    	GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    	//ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
    	//ADCSequenceConfigure(ADC1_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
    	//ADCSequenceStepConfigure(ADC1_BASE, 3, 0, ADC_CTL_CH15 | ADC_CTL_IE | ADC_CTL_END);
    	//ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH1 | ADC_CTL_IE | ADC_CTL_END);
    	//doplnit dalsie sequences pre kazdy ADC0 a ADC1 pin
    	//ADCSequenceEnable(ADC0_BASE, 3);
    	//ADCSequenceEnable(ADC0_BASE, 3);
    	//ADCSequenceEnable(ADC1_BASE, 3);
    	//ADCIntClear(ADC0_BASE, 3);
    	//ADCIntClear(ADC1_BASE, 3);
    	ADCReferenceSet(ADC0_BASE, ADC_REF_EXT_3V);
    	ADCReferenceSet(ADC1_BASE, ADC_REF_EXT_3V);
    }

    And after that I even do several other peripherals initializations, like

        Board_initI2C();
        Board_initEMAC();
        Board_initTIMER();

    .

    Analog circuitry would not be a problem - it is all simply thermistor - resistor voltage dividers. Referecne ditto - the board is up for several hours now ..

    I think it just needed some delay or something ... glad it is solved, it had puzzled me for a month or so.

  • Notice there's no check in the init to verify completion.

    All analog and thermal circuits have time delays. From your description I'd be worried about impedance matching as well. A/ds are not high impedance inputs, they will be affected by resistor chains and dividers.

    Robert
  • Search the tag bookshelf for some references on the care and feeding of a/ds.

    Robert

    nothing can be considered solved until you understand the root cause. Maybe only tentatively then
  • Yes, this TM4C does not have buffered ADC inputs and at first, its rather low input impedance was a problem. But as I do not need very rapid measurements, lenghtening the S&H window solved this so now I have a measurement error under 1% on all inputs. Solved long time ago.