Email: Password: Remember Me | Create Account (Free)

Back to Subject List

Old thread has been locked -- no new posts accepted in this thread
???
01/27/08 11:45
Modified:
  01/27/08 12:13

Read: times


 
#149978 - The art of typecasting
I share this information with You in hopes it will someday save someones sorry ass. It did mine. My ass is still sorry but it is saved ;)

A while ago I build myself a power supply with two stage regulator and decent output power (16 amps @ 60 volts).

The supply has a chopper as the workhorse. It has a very crude output with at least 3 volt ripple. It is unusable as such for anything else but charging the car battery - maybe not even that. However it is optimized for effiency which is well over 80%.

After that there is a second regulator wich takes care of the excessive ripple and also has the current limiting etc.

All this is controlled by a microcontroller which sees that the voltage from the chopper is approximately (very so) 20 volts over the desired voltage. The system measures the current and makes the difference less when a predefined power loss limit is exceeded.

During the tests it appeared that the chopper voltage could for no apparent reason suddenly start fluctuating and it even fried a bunch (bunch == 10) of BUX42 transistors in the post regulator. These are quite durable transistors with good power margin.

It appeared that the power comparison, despite the 32 bit integer got overflowed. It also appeared that the calculation for the final port value went south instead of going west. It all got fixed up after adding typecasts for almost each and every constant. Happily this not only made the code working but it was also smaller.

The root cause was the compiler assumptions over the constants. These are always treated as SIGNED integers if not told othervise. This also applies for intermediate calculation results as in that comparison. This, of course, is highly compiler dependent issue.

If I had coded this with assembler I would have never seen these symptoms and had saved those 10 BUX transistors. So that is ten points to Old'n Trusty Assy.

The original, defunct code:
        volatile    uint16_t    Voltage_meas;
        volatile    uint16_t    Current_meas;
#define MAX_POWER_LOSS          100000

extern  void    PrerOutpTask ( void ) {
    uint32_t    pwmvalue;
    uint16_t    portvalue;

    // See if the maximum power loss is exceeded
     if  ( MAX_POWER_LOSS < Current_meas * (Prereg_meas - Voltage_meas) ) {
        // The max power was exceeded.
        // We need to calculate value that does not exceed it
        // U = P / I
        pwmvalue = (uint32_t)MAX_POWER_LOSS / Current_meas;
        pwmvalue += (Voltage_set + Voltage_off);
    }

    // Since it was not exceeded we set prereg = 20 Volts + Voltage_set
    else {
        pwmvalue = 200 + Voltage_set + Voltage_off;
    }

    // Convert into 8 bit PWM control byte
    pwmvalue *= 255;
    portvalue = pwmvalue / OUT_MAX_PRER;
    if  ( portvalue > 255 ) {
        portvalue = 255;
    }

    // Set the PWM
    OCR2 = portvalue;
}


Modified, working code:
        volatile    uint16_t    Voltage_meas;
        volatile    uint16_t    Current_meas;
#define MAX_POWER_LOSS          100000

extern  void    PrerOutpTask ( void ) {
    uint32_t    pwmvalue;
    uint16_t    portvalue;

    // See if the maximum power loss is exceeded
     if  ( (uint32_t)MAX_POWER_LOSS < (uint32_t)Current_meas * (uint32_t)(Prereg_meas - Voltage_meas) ) {
        // The max power was exceeded.
        // We need to calculate value that does not exceed it
        // U = P / I
        pwmvalue = (uint32_t)MAX_POWER_LOSS / (uint32_t)Current_meas;
        pwmvalue += (uint16_t)(Voltage_set + Voltage_off);
    }

    // Since it was not exceeded we set prereg = 20 Volts + Voltage_set
    else {
        pwmvalue = (uint16_t)200 + Voltage_set + Voltage_off;
    }

    // Convert into 8 bit PWM control byte
    pwmvalue *= (uint16_t)255;
    portvalue = pwmvalue / (uint16_t)OUT_MAX_PRER;
    if  ( portvalue > 255 ) {
        portvalue = 255;
    }

    // Set the PWM
    OCR2 = (uint8_t)(portvalue & 0xFF);
}



List of 28 messages in thread
TopicAuthorDate
The art of typecasting            01/01/70 00:00      
   I'd like to disagree            01/01/70 00:00      
   two comments            01/01/70 00:00      
      Two comments on comments            01/01/70 00:00      
   The Art of correct Constants            01/01/70 00:00      
      int - number of bits unknown            01/01/70 00:00      
         Corrected Art of correct Constants            01/01/70 00:00      
         More assumptions            01/01/70 00:00      
         stdint.h            01/01/70 00:00      
            Or, in the absence of stdint.h...            01/01/70 00:00      
      Const vs #define            01/01/70 00:00      
         Opps!            01/01/70 00:00      
            which may be a reason to prefer #define over const            01/01/70 00:00      
               enum            01/01/70 00:00      
                  Varies            01/01/70 00:00      
                     Know Thy Stuff - enum            01/01/70 00:00      
                        You are right            01/01/70 00:00      
   Know Thy Stuff            01/01/70 00:00      
      And...            01/01/70 00:00      
         I'll pass(cal) on that one :)            01/01/70 00:00      
   Everything in C defaults to int, which is signed            01/01/70 00:00      
   Never overlook lint            01/01/70 00:00      
      before Steve says it...            01/01/70 00:00      
         Pascal            01/01/70 00:00      
            strong typing            01/01/70 00:00      
               why Ada never took off            01/01/70 00:00      
                  Wirth-less            01/01/70 00:00      
               Why ?            01/01/70 00:00      

Back to Subject List