Searching \ for '[PIC]: Need help with 24F/30F/33F PICs extended pr' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: www.piclist.com/techref/microchip/devices.htm?key=pic
Search entire site for: 'Need help with 24F/30F/33F PICs extended pr'.

Exact match. Not showing close matches.
PICList Thread
'[PIC]: Need help with 24F/30F/33F PICs extended pr'
2008\07\13@050918 by Electron

flavicon
face

[ resending: I forgot the tag, sorry :( ]

Hi,
although my knowledge of the dsPIC (without DSP) is getting better, I am now
faced with a problem I must do absolutely bug free, because otherwise precious
data would be corrupted, so I'm seeking help here.

In short I have 24bits coming from an ADC, and I have to make them 16bits, but
inside a certain range of these 24bits.

So, to say it in pseudo C:

unsigned long int  adc;
unsigned long int  min;
unsigned long int  max;
unsigned short int out;

if (adc<=min) {
  out=0;
} else if (adc>=max) {
  out=65535;
} else {
  out=(adc-min)*65536/(max-min); /* needs 64bit intermediary precision */
}

pretty simple problem, if it wasn't for my knowledge of the MUL instruction
and also because of the necessary extended precision intermediary results,
but MUL and DIV are 16bit/32but instructions only. So the best I've done so
far is (given that adc, min and max are "only" 24bit values after all):

  out=((adc-min)*255)/(((max-min)*255+32768)/65536);

which doesn't need more than the normal usage of the MUL and DIV instructions.

But this is not ideal, how could I perform it in multiprecision, to implement
the "real" formula?

Could anybody help please?

With kind regards,
Mario

2008\07\13@080614 by Tomás Ó hÉilidhe

picon face

Electron wrote:
> So, to say it in pseudo C:
>
> unsigned long int  adc;
> unsigned long int  min;
> unsigned long int  max;
> unsigned short int out;
>
> if (adc<=min) {
>    out=0;
> } else if (adc>=max) {
>    out=65535;
> } else {
>    out=(adc-min)*65536/(max-min); /* needs 64bit intermediary precision */
> }
>  


To scale a 24-Bit value to a 16-Bit value I'd shift 8 places to the right:

   long unsigned Scale24to16(long unsigned original_val)
   {
       return original_val >> 8;
   }

Then to make it more generic:

   long unsigned ScaleYtoX(long unsigned const original_val, unsigned
const y, unsigned const x)
   {
       if (y >= x) return original_val >> y-x;
              else return original_val << x-y;
   }

Now, to complicate it, let's do it within a certain range of the 24-Bit
value. Here's our 24-Bit value:

   111111111111111111111111

Now let's say our 16-Bit value should be crafted from the following
range in the 24-Bit value:
   min = 2048
   max = 4194304

Take the minimum value, and assign the most appropriate high bit, so
2048 becomes bit 11 (where bit 0 is the LSB).
Take the maximum value, and assign the most appropriate high bit, so
4194304 becomes bit 22.
(Yes, they're conveniently chosen)

So that means out 16-Bit value should be taken from the following bits
marked with an x:

   1xxxxxxxxxxxx11111111111

(That's 12 bits)

If the highest bit is set, we know that the number is out of range. If
the lower eleven are set, well they would just give us extra precision
if we wanted it. In the case of turning a 12-Bit figure into a 16-Bit
figure, we can use this extra precision, so that would be:

   1xxxxxxxxxxxxYYYY1111111

So we shift this 7 places to the right to give:

   00000001xxxxxxxxxxxxYYYY

Since we're going to discard values that are too big, we know that that
highest 1 won't be set:

   00000000xxxxxxxxxxxxYYYY

I'm getting sloppy here, but altogether it might be something like:

long unsigned ScaleRangeToX(long unsigned val, unsigned const high_bit,
unsigned low_bit, unsigned const x)
{
   unsigned const initial_bit_range = high_bit - low_bit;

   /* First of all, let's see if the value is outside the range */

   long unsigned const max_value_for_original_value = (1uL << high_bit)
- 1,
                                 min_value_for_original_value = (1uL <<
low_bit) - 1,
                                 max_value_for_return_value = (1uL <<
x) - 1;

   if ( original_value < min_value_for_original_value ) return 0;
   if ( original_value > max_value_for_original_value ) return
max_value_for_final_value;

   /* Now let's see if we can use those extra precision bits */

   unsigned const amount_precision_bits_wasted = 0;

   if (initial_bit_range < x)
   {
       unsigned const amount_extra_precision_bits = x - initial_bit_range;

       if (low_bit   >  amount_extra_precision_bits)
       {
           low_bit  -=  amount_extra_precision_bits;
           amount_precision_bits_wasted = 0;
       }          
       else
       {
           low_bit = 0;
           amount_precision_bits_wasted = amount_extra_precision_bits -
low_bit;
       }
   }

   /* Now clean the value up */

   original_value >>= low_bit - amount_precision_bits_wasted;

   return original_value;
}

The code above was thrown together in 10 minutes while I was eating my
morning porridge so it contains bugs, errors and oversights. One
particular thing I haven't paid attention to is making sure that the
number of places I shift by is less than the number of bits in the type;
for instance, if I want the highest value for 4 bits, I can do:

   (1u << 4) - 1

However, if I do this for 16 bits:

   (1u << 16) -1

then the C Standard says the behaviour is undefined if int is 16-Bit.

If you work with a range that doesn't nicely fit as a power of two, then
I think you'll have to resort to using floating-point arithmetic.

2008\07\13@084443 by olin piclist

face picon face
Electron wrote:
> In short I have 24bits coming from an ADC, and I have to make them
> 16bits, but inside a certain range of these 24bits.
>
> ...
>
> if (adc<=min) {
>    out=0;
> } else if (adc>=max) {
>    out=65535;
> } else {
>    out=(adc-min)*65536/(max-min); /* needs 64bit intermediary
> precision */ }

Take your input value and subtract off MIN.  Now the rest is a scale factor
problem.  If this remaining value is still wider than 16 bits, then left
justify it in a 32 bit number and divide to get the 16 bit result.  If
ADC-MIN always fits in 16 bits, then multiply it by a scale factor such that
the result you want ends up in 16 bits near the high end of the 32 bit
product.


********************************************************************
Embed Inc, Littleton Massachusetts, http://www.embedinc.com/products
(978) 742-9014.  Gold level PIC consultants since 2000.

2008\07\14@010114 by Vitaliy

flavicon
face
Electron wrote:
> although my knowledge of the dsPIC (without DSP) is getting better, I am
> now
> faced with a problem I must do absolutely bug free, because otherwise
> precious
> data would be corrupted, so I'm seeking help here.
>
> In short I have 24bits coming from an ADC, and I have to make them 16bits,
> but
> inside a certain range of these 24bits.

Mario, perhaps I don't fully understand the problem -- can you explain why
you can't simply drop the lower order bits? AFAIK, few applications require
more than 8-bit precision.

Vitaliy

More... (looser matching)
- Last day of these posts
- In 2008 , 2009 only
- Today
- New search...