0

I am very new at C programming and I am working on a firmware application for my MCU. This method was working fine when I was using the KEIL compiler (Big Endian) but when I switched to the SDCC compiler (Little Endian) it is not working properly. Can someone please explain what I am doing wrong???

The target device is a Silicon Labs C8051F320 which is based on the 8051 architecture.

unsigned **int** MotorSteps  = 0;     //"Global" variables
unsigned **int** MotorSpeed  = 0;
bit RampUp()
{
    float t = 0;
    t = MotorSteps;
    if ( t < 51 )
    {
        t = (1-((50 - t)/50))*15;   
        t = (t * t);        
        MotorSpeed = 100 + t;           
        return 0;
    }
    else return 1;
}

ADDED: First, I now changed the MotorSteps and MotorSpeed to be unsigned ints. In my debugger, for some reason, if I set a break point at the if-statement line, on the first entrance of this function MotorSteps = 00, so t should get assigned to 0 also but the debugger shows that t=0.031497 (decimal). If I switch the debugger to display in Hex, t = 0x3d010300. It's like t is never getting assigned...

Paul R
  • 208,748
  • 37
  • 389
  • 560
PICyourBrain
  • 9,976
  • 26
  • 91
  • 136
  • 1
    It would help to know what MotorSteps and SetSpeedHz looked like. – Justin Niessner Mar 03 '10 at 19:41
  • It would also help to see the declaration for MotorSpeed. – semaj Mar 03 '10 at 19:46
  • 3
    There's nothing in the code that's endian-dependent. So, what is the problem? – AnT stands with Russia Mar 03 '10 at 19:50
  • Can you be more explicit about "not working properly". Is it setting MotorSpeed incorrectly (and if so, what do you get vs what you expect)? – R Samuel Klatchko Mar 03 '10 at 19:54
  • 1
    I think you're probably going to have to post more of your code. It looks like you've reconstructed your problem by omitting a lot of code (e.g., that 'unsigned int s = 0' isn't used anywhere), which also means that the real problem is likely not apparent. It's not apparent to me at first glance, anyway. – Ben Collins Mar 03 '10 at 19:54
  • 1
    I'd be curious to see the asm listing for the function too. I suspect something is optimized incorrectly. – mocj Mar 03 '10 at 23:24

3 Answers3

3

If MotorSteps = 49 then

(50 - 49) / 50 = 0.02

next

(1 - 0.02) = 0.98

and

0.98 * 15 = 14.7

Squaring this value would set t as

t = 14.7 * 14.7 = 216.09

Finally, the implicit conversion from the float back to the unsigned char overflows the MotorSpeed variable:

MotorSpeed = 100 + 216.09...// Implicitly converts the float t to an unsigned char of 216

The sum of 100 + 216 = 316, of course, overflows an unsigned char and you end up with 316-256 = 60.

This is probably unwanted behavior regardless of the compiler.

semaj
  • 1,555
  • 1
  • 12
  • 25
  • 3
    Actually, assigning a float (or double) to an integral type when the value of the float is outside of the range of the integral type results in undefined behavior, not well-defined modular overflow as you might expect from an unsigned int. So the result may not be 60, and this may account for why this behaves differently in different compilers. – Tyler McHenry Mar 03 '10 at 20:31
2

It's like t is never getting assigned...

There is no reason for the compiler to assign a value of 0 to t in the declaration

float t = 0;

since it immediately gets assigned to MotorSteps on the next line. My guess is the optimizer is ignoring the assignment to zero in the declaration and the debugger is simply displaying the uninitialized value for the memory where t is located on the stack.

You might want to consider getting rid of the formula altogether and using a look up table for the ramp values. It looks like there are only 51 values so the table would be relatively small. The code to look up a value would be much quicker than using the floating point libraries on an 8051.

#define NUM_RAMP_STEPS 51
unsigned char MotorSteps = 0;     //"Global" variables
unsigned char MotorSpeed = 0;
const unsigned char RampTable[NUM_RAMP_STEPS] = {...appropriate values...};
bit RampUp()
{
    if ( MotorSteps < NUM_RAMP_STEPS )
    {
        MotorSpeed = RampTable[MotorSteps];           
        return 0;
    }
    else return 1;
}

At least you could test your integer rather than the float to avoid the floating point libraries unless you need them...

unsigned **int** MotorSteps  = 0;     //"Global" variables
unsigned **int** MotorSpeed  = 0;
bit RampUp()
{
    if ( MotorSteps < 51 )
    {
        float t = MotorSteps;
        t = (1-((50 - t)/50))*15;   
        t = (t * t);        
        MotorSpeed = 100 + t;           
        return 0;
    }
    else return 1;
}
semaj
  • 1,555
  • 1
  • 12
  • 25
0

why did you switch from BE to LE? What is architecture of target device? And by the way what is it?

Anyway, to question. I am pretty sure that problem comes when conversion takes place. Try to trace your code line by line with calculator and try to find when the numbers become unexpected.

Andrey
  • 59,039
  • 12
  • 119
  • 163
  • 2
    I was originally using the KEIL compiler but I reached the limitations of the free version and didn't want to pay for the license so I switched to SDCC which is free and unlimitied... but opposite Endian-ness. – PICyourBrain Mar 04 '10 at 13:33