dsPIC fractional Multiplication Help needed.

Discussion in 'Embedded Systems and Microcontrollers' started by picstudent, Aug 24, 2014.

  1. picstudent

    Thread Starter Well-Known Member

    Feb 3, 2009
    My ADC conversion code (Courtesy This Post)

    Code ( (Unknown Language)):
    1. // Pressure sensor is for 600bar in 0to 5V out - so to get a decimal place I am using 6000 !
    2. PressureinBarWithOneDeciPlace=((((((unsigned long)ADCResultofPSensor*2)+1) *6000) +1024) /2048);
    3. LoadInKNWithOneDeciplace= (unsigned int)((float)PressureinBarWithOneDeciPlace*2.2698006535F);
    I am using dsPIC30F.
    The first statement generates a code which runs in 25 cycles which is reasonable for me.
    But the second line takes around 350 cycles which seems not a informed choice.
    I am not that much familiar in fixed or floating point methods.
    But from my reading it seems to me that there should be some economical methods to multiply by 2.2698... in fixed point library.
    to multiply by 2.2698.. first I left shift once - which completes the multiplication by 2
    now I need to multiply by .2695... using Q15 functions and then add.
    How to do this?
    Can I get a optimum method to implement my task with the help of DSP features of dsPIC30F controller.
  2. MrChips


    Oct 2, 2009
    As a general rule, if I want optimum execution speed I avoid using floating point entirely.

    The fixed point method you choose will depend on the accuracy desired, number of bits used and the range of parameters.

    Multiply by 581 and then divide by 256 (right shift by 8 bits).
    Check to make sure that the multiplication does not result in an overflow, that is, the range of numbers and the number of bits guarantee no overflow.
    picstudent likes this.
  3. MrChips


    Oct 2, 2009
    To give you some more wriggle room you can multiply by 2 first and them add

    Remember, if your processor is byte oriented, dividing by 256 simply means truncating the least significant byte.

    Can your processor handle 24 or 32 bit multiplications?
    picstudent likes this.
  4. MrChips


    Oct 2, 2009
    And just to add to your fixed point computational repertoire, suppose your processor does not have efficient hardware multiplication.

    To multiply by 69, multiply by (64 + 4 + 1).
    picstudent likes this.
  5. picstudent

    Thread Starter Well-Known Member

    Feb 3, 2009
    Thanks for the tips
    My processor is dsPIC30F4011, it is having a fixed point DSP engine, I suppose.
    Regarding multiplication Datasheet says
    "17-bit x 17-bit single-cycle hardware fractional/integer multiplier"

    I think your solution of
    "Multiply by 581 and then divide by 256 (right shift by 8 bits)." is a piece of cake for this processor.
    I have implemented that method in my code
    Code ( (Unknown Language)):
    2. #define PTransMultiConst 6000  // or 5000 depending on transducer
    3. PresureInBarWithOneDeciPlace=
    4.           ((((((unsigned long)PressureTransResult*2)+1)
    5.                 *PTransMultiConst) +1024) /2048);
    6.         Nop();
    7.         LoadInKNWithOneDeciplace=
    8.          (unsigned int)(((unsigned long)PresureInBarWithOneDeciPlace*581)/256);
    Multiply by 581 ND Divide by 256 Takes only 20cycles.
    So compiler also may be using the same thing
    "To multiply by 69, multiply by (64 + 4 + 1). "
    I think the above method can make the code more efficient.
    Thanks for the support
  6. NorthGuy

    Active Member

    Jun 28, 2014
    This is a huge difference in accuracy between

    1. multiplying by 2.2698006535F

    2. multiplying by 581/256 = 2.2695312500 - x = (y*581)>>8;

    3. multiply by 37189/16384 = 2.2698364258 - x = (y*37189L)>>14;

    The question is what accuracy you need.

    You have 16-bit processor, so either #2 or #3 should take 2 instructions (cycles), everything else is C gibberish, which you can keep if it's acceptable, or write your two instructions in asm if it is unacceptable.

    EDIT: My mistake. The shift is crossing bouneries, so it'll probably take 4-6 cycles for #2 and #3 (not 2 as I previously said).

    #3 can also be futher optimized (for this processor only) by pre-multiplying by 4, then you don't need a shift, then it can be done in 3-4 cycles.
    Last edited: Aug 24, 2014
    picstudent likes this.
  7. picstudent

    Thread Starter Well-Known Member

    Feb 3, 2009
    Thanks for the clarifications.
    Actually the solution of "37189/16384" makes me more closer to my constant.
    My constant is already slightly "compromised".
    It is actually (3.1415926*170*170*.1/4000).

    btw I have not done anything in assembly for dsPIC. for PIC16F, I always do in assembly. So that optimization may not be worth the effort in my special case.
    Thanks again