Floating Point and long word with a PICAXE

caver451

New Member
My current project involves taking the 18-bit output from an MCP3421 and performing some floating point calculations. I spent quite a bit of effort on the sensor side of things to ensure high precision, and I hate the thought of discarding that precision in the PICAXE! My research has uncovered the uM-FPU as a possible solution to my problem.

Anyone mind commenting on their experience with the uM-FPU? Are there any other options I might want to consider?

I started this milliohm meter project as a vehicle for learning more about op-amps, instrumentation, and micro controllers, as well as more advanced electronics techniques in general. My goodness, it sure looks like I picked the perfect project! ;-)

-Robert
 

westaust55

Moderator
My current project involves taking the 18-bit output from an MCP3421 and performing some floating point calculations. I spent quite a bit of effort on the sensor side of things to ensure high precision, and I hate the thought of discarding that precision in the PICAXE! My research has uncovered the uM-FPU as a possible solution to my problem.

Anyone mind commenting on their experience with the uM-FPU? Are there any other options I might want to consider?
Have you tried a search of the PICAXE forum for information.

Have a read of my basic tutorial on getting started with the uM-FPU V2 here: http://www.picaxeforum.co.uk/showthread.php?15195-Adding-a-uM-FPU-V2-chip-to-your-PICAXE

You will need to program the math function blocks into the uM-FPU if you wish to keep the PICAXE program size down and the speed reasonable. Otherise your PICAXE (or any other microcontroller) program spends a lot of time passing values and commands to the FPU chip.

There have been some past posts here about the V3.1 FPU chip as well - faster internal maths and some extra features such as GPS string parsing.
MicroMega have also just released a new uM-FPU65

Rev Ed's online store TechSupplies and some other sources (eg Sparkfun ) sell the FPU V2 and FPU V3.1 chips.
 

caver451

New Member
Have you tried a search of the PICAXE forum for information.

Have a read of my basic tutorial on getting started with the uM-FPU V2 here: http://www.picaxeforum.co.uk/showthread.php?15195-Adding-a-uM-FPU-V2-chip-to-your-PICAXE
Bookmarked! That's the kind of practical, real world information I was looking for! The uM-FPU v2 doesn't appear to be widely available anymore, unfortunately; everyone I've checked seems to only carry the newer chip. I appreciate the information!

I did some soul searching on the topic, and after a little math, decided to stick with using the MCP3421 in 16-bit mode instead of 18-bit mode. The extra resolution really doesn't buy me anything. Since I'm only handling 16-bit data, my full-scale value is 32766, with the LSB representing 62.5 uV. Obviously I can't simply do 32766 * 62.5, because not only is that a floating point operation, but it overflows a word. But do I really want to be working in uV ? If I divide uV by 100, I will always be within a word. So here is what I did, without using floating point and without using long words but at the same time keeping a resolution of 100uV :

If I received a value of 4036 from my ADC, that corresponds to 252250 uV:

First get the scaled down value using 62uV for the LSB:

4036 / 100 * 62 = 2480
4036 // 100 * 62 / 100 = 22
2480 + 22 = 2502

Second get the scaled down value using 63uV for the LSB:

4036 / 100 * 63 = 2520
4036 // 100 * 63 / 100 = 22
2520 + 22 = 2544

Average both scaled down values:

2502 + 2544 / 2 = 2523

Then simply convert the scaled down value to mV:

2523 / 10 = 252
2523 // 10 = 3

252.3mV is the final value, which is well within range of error for the ADC based on the mV measured with my DMM. Not once did I use floating point. Not once did I use more than a word. Yay! Obviously I lucked out because I was dealing with 62.5, but I'm still tickled it worked out so well!

Here is the code, in all its amateur glory... ;-)

Symbol Lo = b0
Symbol Hi = b1
Symbol Config = b2
Symbol SlaveAdr_2 = b3
Symbol ADVal = w2
Symbol ADVal_cv_hi = w3
Symbol ADVal_cv_lo = w4
Symbol ADVal_cv_1 = w6
Symbol ADVal_cv_2 = w7
Symbol ADVal_cv = w8
Symbol ADVal_mv = w9
Symbol ADVal_mv_fr = w10

pause 500
serout B.7,T9600,( 0xFE,0x51 )
serout B.7,T9600,( "Initializing....")

SlaveAdr_2 = $68 + $00 ' set adr to 0110 1011
SlaveAdr_2 = SlaveAdr_2 * 2
Hi2cSetup I2CMaster, SlaveAdr_2, I2CSlow, I2CByte


Pause 2000

Do
Hi2cout [SlaveAdr_2], ($88) ' config register %1000 1000
Hi2cin [SlaveAdr_2], (Hi, Lo, Config)
ADVal = Hi * 256 + Lo

ADVal_cv_hi = ADVal / 100 * 62
ADVal_cv_lo = ADVal // 100 * 62 / 100
ADVal_cv_1 = ADVal_cv_hi + ADVal_cv_lo

ADVal_cv_hi = ADVal / 100 * 63
ADVal_cv_lo = ADVal // 100 * 63 / 100
ADVal_cv_2 = ADVal_cv_hi + ADVal_cv_lo

ADVal_cv = ADVal_cv_1 + ADVal_cv_2 / 2

ADVal_mv = ADVal_cv / 10
ADVal_mv_fr = ADVal_cv // 10

serout B.7,T9600, ( 0xFE,0x45,0x40, " " )
serout B.7,T9600, ( 0xFE,0x45,0x00, " " )

if ADVal = 32767 Then
serout B.7,T9600, ( 0xFE, 0x45,0x00, "Range Overflow" )
Else
serout B.7,T9600, ( 0xFE,0x45,0x00, #ADVal_mv,".",#AdVal_mv_fr, " m",0xF4 )
EndIf

serout B.7,T9600, ( 0xFE,0x45,0x40 )
serout B.7,T9600, ( "ADV=", #ADVal )
Pause 500
Loop
I'm liking these little PICAXE's more and more... :)

-Robert
 
Last edited:

srnet

Senior Member
18bit AD can be quite difficult in any case.

Thats 8uV from the 2.048 referance.

And the drift in the 2.048 referance is 31uV per degree C.
 

MartinM57

Moderator
You will need absolutely spot on construction techniques (power supply, layout, decoupling, wiring, grounding, screening etc) to get any useful info beyond around 12 bits. You could probably simplify the maths further given that....and also, going forward, be clear in your mind about the difference between resolution and accuracy :)
 

caver451

New Member
You will need absolutely spot on construction techniques (power supply, layout, decoupling, wiring, grounding, screening etc) to get any useful info beyond around 12 bits. You could probably simplify the maths further given that....and also, going forward, be clear in your mind about the difference between resolution and accuracy :)
Oh boy, am I painfully aware of this! I concentrated heavily on the current reference, all using precision components with excellent temperature coefficients. My voltage reference is rated for 1.0 ppm/C, and my reference resistor is 10 ppm/C. The current reference trimmed out to 10.00 mA on my fluke, and has been rock solid. I'm feeding the sense from my 4-wire kelvin probe to an LMP8358 programmed for a gain of 100. I admit, however, that I have not yet fully calculated my expected accuracy, so perhaps displaying a resolution of 100uV might be a bit optimistic under the circumstances. ;-)

There were pros and cons to picking the ADC I did. Size, price, ease of use, price... In retrospect, there may have been better choices. I may have been better off with one that could accept an external voltage reference, for example...

I am very open to any suggestions, warnings, friendly mocking, or any combination of the three. :)

-Robert
 

westaust55

Moderator
I did some soul searching on the topic, and after a little math, decided to stick with using the MCP3421 in 16-bit mode instead of 18-bit mode. The extra resolution really doesn't buy me anything. Since I'm only handling 16-bit data, my full-scale value is 32766, with the LSB representing 62.5 uV. Obviously I can't simply do 32766 * 62.5, because not only is that a floating point operation, but it overflows a word. But do I really want to be working in uV ? If I divide uV by 100, I will always be within a word. So here is what I did, without using floating point and without using long words but at the same time keeping a resolution of 100uV :

If I received a value of 4036 from my ADC, that corresponds to 252250 uV:

First get the scaled down value using 62uV for the LSB:

4036 / 100 * 62 = 2480
4036 // 100 * 62 / 100 = 22
2480 + 22 = 2502
You could try some rationalisation:

4036 / 100 * 62 = 4035 / 4 *25 with the value ten times the answer giving in effect one greater digit.

4036/ 4 * 25 = 25225 representing 2522.5 (actual is 2522.5)


BUT then, for the max value is 32766, so by PICAXE:
32766 / 4 * 25 = 204775 representing 20477.5 (actual is 20478.75) - too many digits so overflow :(

Using your double calc method you will get 20478.
 
Last edited:

caver451

New Member
You could try some rationalisation:

4036 / 100 * 62 = 4035 / 4 *25 with the value ten times the answer giving in effect one greater digit.

4036/ 4 * 25 = 25225 representing 2522.5 (actual is 2522.5)


BUT then, for the max value is 32766, so by PICAXE:
32766 / 4 * 25 = 204775 representing 20477.5 (actual is 20478.75) - too many digits so overflow :(

Using your double calc method you will get 20478.
Ah, thank you! All my old math is slowly coming back to me! :)

4036 / 100 = 40 * 125 / 2 = 2500
4036 // 100 = 36 * 125 /2 = 2250 / 100 = 22
2500 + 22 = 2522 ( representing 252.2 ; average method got 252.3 )

32766 / 100 = 327 * 125 / 2 = 20437
32766 // 100 = 66 * 125 / 2 = 4125 / 100 = 41
20437 + 41 = 20478 ( representing 2047.8 ; averaging method got 2047.7 )

Rationalizing 62.5 as 125/2 fits allows the calculations to fit in a single world, avoids using floating point math, and greatly reduces the amount of calculations. Not sure if it is a little more accurate or a little less accurate. :)
 

Armp

Senior Member
Since I'm only handling 16-bit data, my full-scale value is 32766, with the LSB representing 62.5 uV. Obviously I can't simply do 32766 * 62.5, because not only is that a floating point operation, but it overflows a word. But do I really want to be working in uV ? If I divide uV by 100, I will always be within a word. So here is what I did, without using floating point and without using long words but at the same time keeping a resolution of 100uV :

If I received a value of 4036 from my ADC, that corresponds to 252250 uV:

Your expression can be rewritten as ADC * (.625 * 2^16) / 2^16 or ADC * 40960/ 2^16.

Then V = ADC**40960 gives 20478 for ADC = 32766, and 2522 for ADC = 4036

I don't understand why your 16 bit FSV is 32766 rather than 65535?

EDIT - Need more precision, then try this:

Code:
Symbol ADC =w0
Symbol mV  =w1
Symbol uV  =w2

ADC = 32766 

mV =w0/16        ' 16 steps/mV
uV =w0//16*125/2  ' Remainder * 62.5uV

'32766 gives 2047mV + 875uV
' 4036 gives 252mV + 250uv
 
Last edited:

hippy

Ex-Staff (retired)
I don't understand why your 16 bit FSV is 32766 rather than 65535?
It's a two's complement differential result so +32767/-32768 but in this application I would guess is never negative. Now why FSV is 32766 rather than 32767 ...
 

Armp

Senior Member
Looks like 32767 indicates the ADC has overflowed..

Code:
If ADVal = 32767 Then
        serout B.7,T9600, ( 0xFE, 0x45,0x00, "Range Overflow" )
 
Last edited:

caver451

New Member
Your expression can be rewritten as ADC * (.625 * 2^16) / 2^16 or ADC * 40960/ 2^16.

Then V = ADC**40960 gives 20478 for ADC = 32766, and 2522 for ADC = 4036

I don't understand why your 16 bit FSV is 32766 rather than 65535?

EDIT - Need more precision, then try this:

Code:
Symbol ADC =w0
Symbol mV  =w1
Symbol uV  =w2

ADC = 32766 

mV =w0/16        ' 16 steps/mV
uV =w0//16*125/2  ' Remainder * 62.5uV

'32766 gives 2047mV + 875uV
' 4036 gives 252mV + 250uv
This is gorgeous, thank you! 1000uV / 62.5uV = 16 steps per mV. The math goes from the twisted ramblings of a madman to a couple of simple statements which offers more precision without resorting to long words or floating point.

I've learned so much in such a short period of time! The experience found on this forum is priceless!
 

Armp

Senior Member
No prob. You're not the first to confuse 'Real' numbers with floating point!
 
Last edited:

westaust55

Moderator
It's a two's complement differential result so +32767/-32768 but in this application I would guess is never negative. Now why FSV is 32766 rather than 32767 ...
From the datasheet, %011111111111111111 in 18 bit mode is used to indicate Vin > Vref (ie over voltage situation)
so for 16 bit mode, %0111111111111111 would be for the same purpose
 
Last edited:
Top