Searching \ for '[PIC]: A/D converter sorted!' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: massmind.org/techref/microchip/ios.htm?key=a%2Fd
Search entire site for: 'A/D converter sorted!'.

Exact match. Not showing close matches.
PICList Thread
'[PIC]: A/D converter sorted!'
2002\01\25@232144 by Benjamin Bromilow

flavicon
face
[sorry about duplication everyone, forgot the tag first time round]

Hi all,

I found the problem lay in my use of the Carry flag. I had based my
interpolation procedure upon the Microchip maths app note. However I had
extended it to 24 bits. The problem lay in my use of the Carry flag. I
expected (read assumed) that when a register was incremented beyond FF to 00
that not only the Z  flag but also the C flag would be brought high. It
appears not!! My extended precision division was therefore based around a
dodgy subtraction procedure- bound to fail :) That one goes on my list of
gotchas......
I'm pretty sure that the code has other examples of this gotcha in... but
it's 04:20 local time and time for some zzzzZZZZZs.

Ben
I guess that 99.9% was a little too confident....

--
http://www.piclist.com#nomail Going offline? Don't AutoReply us!
email spam_OUTlistservTakeThisOuTspammitvma.mit.edu with SET PICList DIGEST in the body


2002\01\28@094634 by o-8859-1?Q?K=FCbek_Tony?=

flavicon
face
Hi,

Benjamin Bromilow wrote:
<snip>
extended it to 24 bits. The problem lay in my use of the Carry flag. I
expected (read assumed) that when a register was incremented beyond FF to 00
that not only the Z  flag but also the C flag would be brought high. It
appears not!! My extended precision division was therefore based around a
dodgy subtraction procedure- bound to fail :) That one goes on my list of
gotchas......
<snip>

Carry flag should be set at *overflow* else it would have little use :)
*HOWEVER* subtraction needs 'special' attention to the carry/zero flag as
'all is not what it seems' ( at least for me it isn't ) :)

From the manual= C:Carry/inv(Borrow)  bit,<snip> for inv(Borrow) the
polarity is reversed<snip>

I've done alot of adding/subtracting/comparing maths for signed/unsigned
8,16 and 24 bit values
and I can still recall the headbanging for the subtraction carry/zero flag
issues.

Please post the snippet in question and we can point out why the maths
appeared non working ( or were non-working ).

/Tony

--
http://www.piclist.com hint: The list server can filter out subtopics
(like ads or off topics) for you. See http://www.piclist.com/#topics


2002\01\28@150605 by Benjamin Bromilow

flavicon
face
From: "K|bek Tony" <.....tony.kubekKILLspamspam@spam@FLINTAB.COM>

> Carry flag should be set at *overflow* else it would have little use :)

My thinking was that on running the following code, the carry flag would be
set. Going through MP-SIM shows that it isn't..... (at least not on a 16F877
anyway)

movlw 0xFF
movwf Divin1
incf Divin1,F                        ; ie overflow from 0xFF to 0x00
btfss STATUS,C                ; If carry set then skip
nop ; C flag is not set *1
nop ; C flag is set (works)

When I test the above it goes to *1......

The actual code is as follows. As part of a division routine it subtracts
Divisor[3]:[2]:[1] from Divin[3]:[2]:[1]. If it subtracts without a carry,
the routine returns with C=1 and the new result in Divin. If a carry
results, it returns with C=0 and the old result in Divin.....

SUBC
;1 stack
movf Divin3,W
movwf Divtemp3
movf Divin2,W
movwf Divtemp2 ; sort out temporary registers
movf Divin1,W
movwf Divtemp1

movf Divisor1,W
subwf Divtemp1,F ; subtract LSB
movf Divisor2,W ; get ready for next subtract
btfss STATUS,C ; if no borrow skip increment
incfsz Divisor2,W ; increment of divisor
subwf Divtemp2,F ; this sub is skipped if sub'd to zero
movf Divisor3,W ; next one ready
btfss STATUS,C ; if no borrow skip INC
incfsz Divisor3,W
subwf Divtemp3,F
btfss STATUS,C ; if carry=1 then no borrow so SUB okay
return

movf Divtemp3,W
movwf Divin3
movf Divtemp2,W ; restore old values and return (C=0)
movwf Divin2
movf Divtemp1,W
movwf Divin1
return


So it's not the best bit of code ever written but it demonstrates what I
expected to happen!!!

Ben

--
http://www.piclist.com hint: The list server can filter out subtopics
(like ads or off topics) for you. See http://www.piclist.com/#topics


2002\01\29@054922 by o-8859-1?Q?K=FCbek_Tony?=

flavicon
face
Hi,(sorry long post, code included )

Benjamin Bromilow wrote:
<snip>
>
> movlw 0xFF
> movwf Divin1
> incf Divin1,F                        ; ie overflow from 0xFF to 0x00
> btfss STATUS,C                ; If carry set then skip
> nop ; C flag is not set *1
> nop ; C flag is set (works)

Yes this is correct, in the manual it clearly states that INCF only affects
the zero flag. ( at least for the 16xx series ).
So in this case, after the operation INCF an overflow is always detected
by checking the zeroflag.  Thats one of the reasons you also have the INCFSZ
instruction.
For the 18 series ( and perhaps others, i don't know ) the INCF actually
affect
also the C,DC,N,OV flags.
I know this is somewhat illogical but it's clearly stated in the manual,
also
this is what i meant with my previous statement, headbanging :)

{Quote hidden}

Hmmm that's odd, this is what I have ( and it works ! )

;++++++++++++
;
; SUB_24_FROM_24 - Subtracts a 24 bit variable from a 24 bit variable
; Formula: ARG2_24 = ARG2_24 - ARG1_24
; arguments must point to most significant bits, arg1_24+2 and arg2_24+2 is
lsb's
;
SUB_24_FROM_24 MACRO    ARG1_24,ARG2_24

       MOVF    LOW(ARG1_24+2),W        ; get lowest byte source
       SUBWF   LOW(ARG2_24+2),F        ; subtract from lowest byte dest

       MOVF    LOW(ARG1_24+1),W        ; get middle byte
       SKPC                            ;  if overflow
          INCFSZ       LOW(ARG1_24+1),W ; decrease source
               SUBWF   LOW(ARG2_24+1),F ; and subtract to dest.

       MOVF    LOW(ARG1_24),W  ; get highest byte
       SKPC
          INCFSZ       LOW(ARG1_24),W
               SUBWF   LOW(ARG2_24),F
       ENDM

From what I gather the subtraction is performed excately as yours.
However the actual division routine is not included and I guess that there
could be 'something' about the interpretation of the 'carry' when returning.
Here's an 40 by 23 bit division routine that I know works, see if you can
spot
anything that differs from your implementation.
Credit should go to Nikolai Golovchenko, as the routine surfaced by his
guidance.
It's an variant of his 24 by 16 bit division routine at:
www.piclist.com/techref/microchip/math/div/24by16.htm
( mine not fully omptimized, exerzise for the reader :) )

; ***********************************************************************
; DIVIDE_ARG1LHbyARG2_40by23 - Unsigned routine to divide a 40 bit number
with a 23 bit number
; result upto 40 bits !
;
; Formula:      ARG1_48L:H (top byte ignored) = ARG1_48L:H / ARG2_24
;
; Routine uses 'non-restoring' method there each loop only performs *one*
; addition or subtraction each time.
; Subtract from remainder if remainder is positive or zero and add to
remainder if remainder is negative.
; This way saves alot of cycles but requires that the sign of the remainder
must be kept somewhere
; in this routine the top bit of reaminder is use for that purpose and hence
the 40by23 limitation.
; Normally one would do both subtraction and addition in each loop.
;
; Format:       Little endian, Ram = msb, Ram+x = lsb ( where x=bytesize-1)
; Ram used:     ARG1_48H and ARGH1_48L (Dividend) 5 bytes ( 40 bits ), where
top byte is ignored
;               ARG2_24 (Divisor) 3 bytes ( 23 bits, top bit used for temp
sign save )
;               Temp 3 bytes
;               MathBitCount 1 byte for loop counting ( and temp. saving of
carry )
;
; ARG2_24 is preserved
; ARG1_48H:L holds result
; Returns with zero in W if failed ( division with zero )
; Else returns with one in w
;
DIVIDE_ARG1LHbyARG2_40by23
       GLOBAL  DIVIDE_ARG1LHbyARG2_40by23
       ; Test for zero division
       MOVF    ARG2_24,W
       IORWF   ARG2_24+1,W
       IORWF   ARG2_24+2,W
       BTFSC   STATUS,Z
       RETLW   0x00    ; divisor = zero, not possible to calculate return
with zero in w

       ; prepare 24 bit temp variable
       CLRF    Temp
       CLRF    Temp+1
       CLRF    Temp+2


       MOVLW   D'40'           ; initialize bit counter
       MOVWF   MathBitCount

       BSF     STATUS,C        ; set carry at entry
DIVIDE_40by23_LOOP
       ; a) first time carry set
       ; b) every other bit carry contains the result of
       ;    last subtraction ( division ).
       ; shift in carry as lowest bit
       RLCF    ARG1_48L+2,F
       RLCF    ARG1_48L+1,F
       RLCF    ARG1_48L,F
       RLCF    ARG1_48H+2,F
       RLCF    ARG1_48H+1,F

       ; shift in highest bit from dividend through carry in temp
       RLCF    Temp+2,F
       RLCF    Temp+1,F
       RLCF    Temp,F


       MOVF    ARG2_24+2,W             ; get LSB of divisor
       BTFSS   ARG1_48L+2,0    ; check lowest bit of dividend
       GOTO    DIVIDE_40by23_ADD

       ; subtract 23 bit divisor from 24 bit temp
       SUBWF   Temp+2,F                ; subtract

       MOVF    ARG2_24+1,W             ; get middle byte
       SUBWFB  Temp+1,F                ; and subtract from dest.

       MOVF    ARG2_24,W               ; get top byte
       SUBWFB  Temp,F          ; and subtract from dest.
       GOTO    DIVIDE_40by23_SKIP      ; carry was set, subtraction ok,
continue with next bit

DIVIDE_40by23_ADD
       ; result of subtraction was negative restore temp
       ADDWF   Temp+2,F                ; add it to the lsb of temp

       MOVF    ARG2_24+1,W             ; get middle byte
       ADDWFC  Temp+1,F                ; and add it if not zero in that
case Product+Multipland=Product

       MOVF    ARG2_24,W               ; get top byte
       ADDWFC  Temp,F          ; and add

DIVIDE_40by23_SKIP
       DECFSZ  MathBitCount,F  ; decrement loop counter
       GOTO    DIVIDE_40by23_LOOP      ; another run
       ; finally shift in the last carry
       RLCF    ARG1_48L+2,F
       RLCF    ARG1_48L+1,F
       RLCF    ARG1_48L,F
       RLCF    ARG1_48H+2,F
       RLCF    ARG1_48H+1,F
     RETLW   0x01    ; done



Oh, that's right, uses 18xx instr. replace:
       SUBWFB  Temp,F  ; and subtract from dest.**
with:

       SKPC                            ;  if overflow ( from prev.
subtraction )
          INCFSZ       ARG2_24,W       ; increase source
               SUBWF   Temp,F  ; and subtract from dest.

and:
       ADDWFC  Temp+1,F        ; and add it if not zero in that case
Product+Multipland=Product**
with:
       BTFSC   STATUS,C                ; check carry for overflow from
previous addition
       INCFSZ  ARG2_24+1,W     ; if carry set we add 1 to the source
       ADDWF   Temp+1,F                ; and add it if not zero in that
case Product+Multipland=Product

If using 16xx series


/Tony

--
http://www.piclist.com hint: The PICList is archived three different
ways.  See http://www.piclist.com/#archives for details.


2002\01\29@144944 by Benjamin Bromilow

flavicon
face
Hi Tony,

I think I'm going to have to work on my code after eating some fish (brain
food)! It's too clever for me at the moment. It appears to work and yet
looking back on it I can't work out why it should in all situations... I
have a sneaking suspision that there are errors in it........

Ben

--
http://www.piclist.com hint: The PICList is archived three different
ways.  See http://www.piclist.com/#archives for details.


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