Debugging

anticipate

Before we release our code we have to anticipate all possible sources of error. GUI code may fail miserably leading to nuisance, embedded code may fail miserably leading to unimaginable losses. Yes, I want to terrify you cause we usually think we have finished by the time we see something working. We should constantly strive towards better code. By the way, I remain open to any suggestions / corrections. OK, let's try to identify possible errors.

  • First of all, when we send a Reset signal, it is not for sure that our thermo will be present. Our thermo might be dead.
  • Also, after sending a command to our thermo there is a possibility that we will never get a reply. Think of adding timeouts.
  • But again, even if we get a temperature measurement, it might be erroneous. The CRC stands there for this purpose.
  • Finally, our code may fail without glory, unexpectedly. Micros do fail. Yes, a nasty thing thus, we use the Watchdog timer.

What we are going to do is introduce error codes. In case one of them appears we can display it, say "E2" for example. At least, when your customers call you with maddening claims, telling you there is an "E2" coming out instead of temperature, you will know which routine has failed you. So ...


/// Globals ///////////
static volatile u8 error=0;
static u8 RAM[9];

/// Prototypes ////////
u8 GetT(u8 *data);

int main(void)
{
    //{...}

    error = GetT(RAM);

    if (!error) DispTemp(temp);   
    else DispErr(error);

    //{...}
}
 

The final code may not be exactly as the above but, you see what I mean, the GetT routine has to return the error code. If it is 0, there is no problem, we can display temperature, else, we display the error code. Temperature has to be set by the routine somehow so, you may use pointers or declare it global. Start writing the final GetT routine!

Before getting your hands dirty, look at the following trick which is common for embedded systems. Usually microcontrollers have to poll external devices, waiting for an event to occur. In our case we have to wait for temperature conversion. The common practice here is to utilize either a timer or a variable, which by expiring will indicate failure. See the following example and you will get the idea.


// Convert Temperature
wTxbyte(convertT);                     
// Read a byte - Initialize timeout variable
convflag=wRxbyte(); timeout=0;
// Poll for convertion complete or timeout
while (!convflag && timeout<200)
{
    Delay(1000);
    convflag=wRxbyte(); // Read a byte
    timeout++;
}

// if (!convflag) convertT timed out
// else convertT is OK

 

We start by requesting temperature conversion, then instead of delaying we read a byte. As you expect, this is too fast for our thermo which will return 0. We initialize the timeout variable and we enter the loop. We will get out of the loop when one out of the two conditions is met. Either the thermo will respond or timeout will occur. In the loop, we keep polling the thermo patiently but, we advance our timeout variable. After the end of the loop, we check what we've got. Please, do the same for the skipROM command. I am not sure what it returns or how quickly the thermo responds. By the way, think if the Delay is needed or not. If conversion is completed as expected what is the value of timeout?

Now, regarding the Reset signal, we have to be sure that our thermometer will respond. It is straight forward.


// Reset Signal
temp = Reset1Wire();

// if (!Reset1Wire()) then no thermo is present
// else there is one
 

Nice, we have increased our code's reliability, I would be glad if you could rewrite your GetT routine to return an error code, 0 for none and set the global temperature variable. The latter should be passed by reference so use pointers. Beware with its declaration. The last think you should notice is that if a thermo is not present, it will never do temperature conversion, but your error code may be altered. So, do it in steps and after each step if there is an error return.

 
 
victor@avrtutor.com