schmity
Starting Member
- Total Posts : 37
- Reward points : 0
- Joined: 2015/02/01 18:12:41
- Location: 0
- Status: offline
HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
HI GENTS, i'M HAVING ISSUES WITH MY ALGORITHM TO EXTRACT DIGITS FROM 16-BITS COUNTER. I WILL APPRECIATE IF YOU COULD HELP ME FIGURE OUT WHAT IS WRONG WITH IT, OR SUGGEST AN ALTERNATIVE. BASICALLY, I HAVE A DECLARED A 16-BIT COUNTER. COUNTER LOW COUNT FROM 0 TO 255 AND ROLLER OVER AND INCREMENT COUNTER HIGH. I THEN CALLED A SUBROUTINE TO EXTRACT THE RESPECTIVE DIGITS I.E. THOUSANDTH, HUNDREDTH, TENTHS, ONETH. FOR SOME REASONS, THE EXTRACTOR FUNCTION/SUBROUTINE DOES NOT FUNCTION AS EXPECTED. HERE IT'S BELOW. THANK YOU FOR YOUR HELP IN ADVANCE. ;************************************************* ************************************************* ; SHARED VARIABLES DECLARATION ;************************************************* ************************************************* DIG_SHR_VARS UDATA_SHR 0X20 THOUSANDTH RES 1 ;RESERVE ONE BYTE AT ADDRESS 20 HUNDREDTH RES 1 ;RESERVE ONE BYTE AT ADDRESS 21 TENTH RES 1 ;RESERVE ONE BYTE AT ADDRESS 22 ONETH RES 1 ;RESERVE ONE BYTE AT ADDRESS 23 COUNTER RES 2 ;RESERVE TWO BYTES ADDRESS 23-24 ;************************************************* ************************************************* ;EXTRACTING DIGITS FROM 16-BIT COUNTER ;************************************************* ************************************************* DIGIT_FROM_WORD MOVF COUNTER + 1,W ;GET HIGHER BYTE BTFSS STATUS, Z ;IS THE HIGHER BYTE ZER0? GOTO EXTRACT_HUNDTH ;YES, GO TO EXTRACT LOW BYTE EXTRACT_THOUDTH ;EXTRACT HIGHER BYTE DIGIT INCF THOUSANDTH,F DECF COUNTER + 1,F ;DECREMENT HIGHER BYTE BY 1 CLRW ;CLEAR WORKING REGISTER ADDLW .256 ;ADD 256 IORWF COUNTER,F MOVLW .100 GOTO CARRY_SET EXTRACT_HUNDTH MOVF COUNTER,W ;GET LOWER BYTE MOVWF TEMP ;SAVE IN TEMP MOVLW .100 CARRY_SET INCF HUNDREDTH ;INCREMENT THE HUNDREDTH SUBWF TEMP,W ;HUNDREDTH - 100 = 0? BTFSC STATUS,C ;CARRY CLEARED, SKIP NEXT LINE GOTO CARRY_SET ;HUNDREDTH > 100 DECF HUNDREDTH,F ADDWF TEMP,F MOVF COUNTER+1,F ;CHECK IF COUNTER+1 = 0 BFTSC STATUS,Z ;IS COUNTER+1 EQUAL TO 0 GOTO EXTRACT_THOUDTH ; NO EXTRACT_TENTH MOVLW .10 INCF TENTH ;INCREMENT THE HUNDREDTH SUBWF TEMP,W ;HUNDREDTH - 100 = 0? BTFSC STATUS,C ;CARRY CLEARED, SKIP NEXT LINE GOTO EXTRACT_TENTH ;HUNDREDTH > 100 DECF TENTH,F ADDWF TEMP,F EXTRACT_ONETH MOVF TEMP,W MOVWF ONETH ;SAVE RESULT IN ONETH REGISTER RETURN ;************************************************* ************************************************* MAIN ;INITIALIZE VARIABLES TO ZER0 HERE ;CLRF THOUSANDTH ;CLRF HUNDREDTH ;CLRF TENTH ;CLRF ONETH ;CLRF COUNTER ;CLRF COUNTER+1
FOREVER INCF COUNTER,F ;INCREMENT LOW COUNT MOVF COUNTER,W BTFSC STATUS,Z ;CHECK IF LOW COUNT IS ROLLED OVER TO 0 INCF COUNTER+1,F ;YES, INCREMENT HIGHER COUNT CALL DIGIT_FROM_WORD ;EXTRACT DIGITS ;CALL DISPLAY THOUSANDS ;DISPLAY HUNDRETHS ;DISPLAY TENTHS ;DISPLAY ONETH ;CALL DELAY_250MS ;WAIT 250 MILISECONDS GOTO FOREVER ;************************************************* *************************************************
post edited by schmity - 2015/03/19 03:20:44
|
DarioG
Allmächtig.
- Total Posts : 54081
- Reward points : 0
- Joined: 2006/02/25 08:58:22
- Location: Oesterreich
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/20 12:35:13
(permalink)
What is not working exactly? PS: every INCF etc instructions should *always* have the destination specified, i.e. ",F" or ",W"
|
1and0
Access is Denied
- Total Posts : 12108
- Reward points : 0
- Joined: 2007/05/06 12:03:20
- Location: Harry's Gray Matter
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/21 01:26:10
(permalink)
There is so many things wrong with OP's routine that I wouldn't ever attend to fix it. @OP: search for binary to BCD conversion.
|
schmity
Starting Member
- Total Posts : 37
- Reward points : 0
- Joined: 2015/02/01 18:12:41
- Location: 0
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/22 05:38:00
(permalink)
Many thanks, I got it fixed now.
Attachment(s)Attachments are not available: Download requirements not met
|
DarioG
Allmächtig.
- Total Posts : 54081
- Reward points : 0
- Joined: 2006/02/25 08:58:22
- Location: Oesterreich
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/22 09:30:27
(permalink)
ah ah please tell us how
|
schmity
Starting Member
- Total Posts : 37
- Reward points : 0
- Joined: 2015/02/01 18:12:41
- Location: 0
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/22 20:04:53
(permalink)
I used a double dabble "shift and add 3" algorithm to extract the digits. Basically, you shift a 16-bit binary number left and shift a carry bit each time into low byte-> low byte into high byte. Then check the nibble of each byte to see if greater than 5, and add 3 if true, otherwise continue shifting the bytes. The only caveat is, it's a bit slow - takes about 125us to execute or extract 16-bit counter to 5-digit on a micro running 20MHz external clock. Since that execution time is unacceptable to me, I'm working currently on using "divide and mod" algorithm to see if I can reduce execution time. Thanks.
|
cbarn24050
Junior Member
- Total Posts : 102
- Reward points : 0
- Joined: 2015/02/17 17:13:46
- Location: 0
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/22 23:32:26
(permalink)
You can cut the execution time down if you write the shift/add loop in assembler.
|
crosland
Super Member
- Total Posts : 2176
- Reward points : 0
- Joined: 2005/05/10 10:55:05
- Location: Warks, UK
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/23 01:45:35
(permalink)
cbarn24050 You can cut the execution time down if you write the shift/add loop in assembler.
Since the code he posted IS assembler...
|
cbarn24050
Junior Member
- Total Posts : 102
- Reward points : 0
- Joined: 2015/02/17 17:13:46
- Location: 0
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/23 03:13:02
(permalink)
Oh yes so it is!! I guess i'll have to look at it now to see why it's taking so long.
|
cbarn24050
Junior Member
- Total Posts : 102
- Reward points : 0
- Joined: 2015/02/17 17:13:46
- Location: 0
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/23 03:19:13
(permalink)
Well now I've looked at it yet again I see he didn't post the code for the binary to bcd converter.
|
JorgeF
Super Member
- Total Posts : 3345
- Reward points : 0
- Joined: 2011/07/09 11:56:58
- Location: PT/EU @ Third rock from the Sun
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/23 03:46:40
(permalink)
Hi schmity 125us to execute or extract 16-bit counter to 5-digit on a micro running 20MHz external clock. Since that execution time is unacceptable to me, I'm working currently on using "divide and mod" algorithm to see if I can reduce execution time. Thanks.
How did you manage to spend 125uS <=> 625 ASM instructions cycles in that? As for the DIV / MOD algorithm, I guess it will take you a lot more time than the shift-add3. The digit extraction is a convertion from binary to decimal, as 10 is not a power of 2 the division will allways take a long time. By my experience a DIV/MOD is allways much slower than the SHIT-ADD3. But I might be missing some math trick, so I'm waiting to see and learn. Best regards Jorge
|
1and0
Access is Denied
- Total Posts : 12108
- Reward points : 0
- Joined: 2007/05/06 12:03:20
- Location: Harry's Gray Matter
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/23 06:45:07
(permalink)
JorgeF How did you manage to spend 125uS <=> 625 ASM instructions cycles in that? As for the DIV / MOD algorithm, I guess it will take you a lot more time than the shift-add3. The digit extraction is a convertion from binary to decimal, as 10 is not a power of 2 the division will allways take a long time. By my experience a DIV/MOD is allways much slower than the SHIT-ADD3. But I might be missing some math trick, so I'm waiting to see and learn.
625 instruction cycles is slow, even for the shift-add3 method. Dependent on the algorithms and PIC device, div-mod method can be faster than the shift-add3 method but at the expensive of more code space. @OP: Which PIC device? PIC18 has the DAW instruction that can make BCD math easier. I assume speed is more important than space, so how fast do you need it to be?
|
Mysil
Super Member
- Total Posts : 4125
- Reward points : 0
- Joined: 2012/07/01 04:19:50
- Location: Norway
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/23 08:02:55
(permalink)
Hi, In this thread, there is a project containing a 16 bit binary to BCD conversion used in preparing values for display. http://www.microchip.com/forums/FindPost/852526 It is using a "shift and add3" algorithm as found in some old Microchip assembler demo. As inline assembler in XC8 for PIC16, it use nearly 900 instruction cycles including C function call overhead, so is no improvement over what schmity have already been using, but is still much better than C library "utoa(...)" function which have been seen to use between 3300 cycles and 8600 instruction cycles. In the original post in this thread, schmity seem not to try to do general division. Instead doing repeated subtraction using precalculated constants for powers of 10, it could be possible to get away with 36 (or maybe 41) subtractions in the worst case, and less in average. With the following code in C, it has been possible to run a test over all 16 bit values with average 433 instruction cycles including loop and call overhead. /* * Unsigned Binary to Decimal conversion. */ void uBin16_Dec(unsigned char* sptr, unsigned int Arg) { *sptr = 0; while (Arg >= 10000) { Arg -= 10000; *sptr += 1; } sptr++; *sptr = 0; while (Arg >= 1000) { Arg -= 1000; *sptr += 1; } sptr++; *sptr = 0; while (Arg >= 100) { Arg -= 100; *sptr += 1; } sptr++; *sptr = 0; while (Arg >= 10) { Arg -= 10; *sptr += 1; } sptr++; *sptr = (unsigned char)Arg; } Regards, Mysil Code edited to correct program bugs. Mysil
post edited by Mysil - 2015/03/26 07:26:08
|
1and0
Access is Denied
- Total Posts : 12108
- Reward points : 0
- Joined: 2007/05/06 12:03:20
- Location: Harry's Gray Matter
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/23 08:15:30
(permalink)
Mysil ... It is using a "shift and add3" algorithm as found in some old Microchip assembler demo. As inline assembler in XC8 for PIC16, it use nearly 900 instruction cycles including C function call overhead, so is no improvement over what schmity have already been using,
It should take about 1/2 that many instruction cycles in ASM for a PIC16; faster with PIC18. In the original post in this thread, schmity seem not to try to do general division. Instead doing repeated subtraction using precalculated constants for powers of 10, it could be possible to get away with 36 (or maybe 41) subtractions in the worst case, and less in average. With the following code in C, it has been possible to run a test over all 16 bit values with average 433 instruction cycles including loop and call overhead.
Yes, division can be done by repeating subtraction, and it probably takes ~300's instruction cycles in ASM for a PIC16; again, faster with PIC18.
|
i1ctg
Super Member
- Total Posts : 206
- Reward points : 0
- Joined: 2012/10/18 08:43:35
- Location: OMEGNA-VB- ITALY
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/23 09:38:41
(permalink)
this C code is a variant of double dabble for 31 bit it can be reduced to 16 bit changing W=0x8000. I show it as an idea for conversion in assembler. uint32_t double_dabble (uint32_t Fbin) //max 99,999,999 { uint32_t Fbcd, W=0x40000000; while (W) { Fbcd +=(((Fbcd+0x33333333)&0x88888888)>>3)*3; Fbcd<<=1 ; if (Fbin&W) Fbcd++; W >>=1 ; } return Fbcd; }
|
JorgeF
Super Member
- Total Posts : 3345
- Reward points : 0
- Joined: 2011/07/09 11:56:58
- Location: PT/EU @ Third rock from the Sun
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/23 18:45:00
(permalink)
Hi This all question about instruction cycles and my own surprise by the number of instruction cycles the OP measured for the SHIF / ADD3 algorithm, started itching...and itching....and I ended up scratching it. And this is the result, obtained with a PIC16F886 programmed in absolute assembler. Worst case: 554 instruction cycles to convert the value "51190" Best case: 528 instruction cycles converting the value "0" The measurement method was to use TIMER1 (16 bit) to count the instruction cycles and colect the maximum and minimum count values while converting all numbers from 0x0000 ("0") to 0xffff (65535). In case someone is interested in double ckecking or for the sake of curiosity, the ASM source code I used can be found in the attachement. Have fun. Best regards Jorge
post edited by JorgeF - 2015/03/23 18:57:27
Attachment(s)Attachments are not available: Download requirements not met
|
schmity
Starting Member
- Total Posts : 37
- Reward points : 0
- Joined: 2015/02/01 18:12:41
- Location: 0
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/24 02:12:56
(permalink)
GENTS, SORRY I DIDN'T POST THE CODE UTILIZING DOUBLE DABBLE. HERE IT'S. ;******************************************************************************* ; BINARY TO BCD CONVERSION ; IMPLEMENTATION OF DOUBLE DABBLY ALGORITHM ;******************************************************************************* LCD_CONV_BIN2BCD MOVF LCD_POINT,W MOVWF LCD_TEMP_LO ;GET LOWER BYTE MOVF LCD_POINT + 1, W MOVWF LCD_TEMP_HI ;GET LOWER BYTE
CLRF BCD_LOBYTE ;HOLDS BCD FOR ONES AND TENS CLRF BCD_LOBYTE + 1 ;HOLDS BCD FOR HUNDS AND THOUS CLRF BCD_TENTS ;HOLDS BCD FOR TEN THOUSANDS CLRF BCD_WORKING
MOVLW D'03' MOVWF BCD_BITCNT BCD_INIT_SHIFT BCF STATUS,C ;CLEAR CARRY BIT RLF LCD_TEMP_LO,W RLF LCD_TEMP_LO,F ;ROTATE BINARY NUMBER LEFT 3 TIMES RLF LCD_TEMP_HI,F ;ROTATE BINARY NUMBER LEFT 3 TIMES RLF BCD_LOBYTE,F ;NO, JUST ROTATE LEFT DECFSZ BCD_BITCNT ,F ;DECREMENT COUNTER GOTO BCD_INIT_SHIFT
MOVLW D'13' MOVWF BCD_BITCNT BCF STATUS,C ;RLF LCD_TEMP_LO,W BCD_CHECK_REM MOVF BCD_LOBYTE,W ANDLW H'0F' ;CHECK LOWER NIBLE TO SEE IF GREATER THAN 4 SUBLW H'04' BTFSC STATUS,C GOTO BCD_CHECK_TENS MOVLW H'03' ADDWF BCD_LOBYTE,F ;ADD 3 TO IT IF TRUE BCD_CHECK_TENS MOVF BCD_LOBYTE,W ANDLW H'F0' ;CHECK LOWER NIBLE TO SEE IF GREATER THAN 4 SUBLW H'40' BTFSC STATUS,C GOTO BCD_CHCK_HUNDS MOVLW H'30' ;ADD 30h TO HIGH BYTE NIBBLE ADDWF BCD_LOBYTE,F BCD_CHCK_HUNDS MOVF BCD_LOBYTE+1,W ANDLW H'0F' ;CHECK LOWER NIBLE TO SEE IF GREATER THAN 4 SUBLW H'04' BTFSC STATUS,C GOTO BCD_CHCK_THOUS MOVLW H'03' ADDWF BCD_LOBYTE+1,F ;ADD 3 TO IT IF TRUE BCD_CHCK_THOUS MOVF BCD_LOBYTE+1,W ANDLW H'F0' ;CHECK LOWER NIBLE TO SEE IF GREATER THAN 4 SUBLW H'40' ;FORMERLY 50h BTFSC STATUS,C GOTO BCD_CHCK_TENTS MOVLW H'30' ;ADD 30h TO HIGH BYTE NIBBLE ADDWF BCD_LOBYTE + 1,F BCD_CHCK_TENTS MOVF BCD_TENTS,W ANDLW H'0F' ;CHECK LOWER NIBLE TO SEE IF GREATER THAN 4 SUBLW H'04' BTFSC STATUS,C GOTO BCD_SHIFT_BITS ;CARRY IS SET, ROTATE REGISTERS THROUGH CARRY BIT MOVLW H'03' ADDWF BCD_TENTS,F ;ADD 3 TO IT IF TRUE BCD_SHIFT_BITS RLF LCD_TEMP_LO,F ;ROTATE TEMP LOW REMAINING BIT INTO CARRY BIT AND CHECK IT'S ONE RLF LCD_TEMP_HI,F ;ROTATE TEMP LOW REMAINING BIT INTO CARRY BIT AND CHECK IT'S ONE RLF BCD_LOBYTE,F RLF BCD_LOBYTE + 1,F RLF BCD_TENTS,F BCD_CHECK_CNTS DECFSZ BCD_BITCNT,F ;DECREMENT COUNTER GOTO BCD_CHECK_REM MOVF BCD_LOBYTE,W ANDLW H'0F' ;GRAB LOWER NIBBLE ADDLW H'30' ;CONVERT TO ASCII MOVWF LCD_ONES ;SAVE IN LCD_ONES REG ;CLRW SWAPF BCD_LOBYTE,W ;GRAB THE HIGHER NIBBLE ANDLW H'0F' ;EXTRACT THE NIBBLE ADDLW H'30' ;CONVERT TO ASCII MOVWF LCD_TENS ;SAVE IN TENS REG MOVF BCD_LOBYTE + 1,W ;GRAB HIGHER BYTE LOWER NIBBLE ANDLW H'0F' ;EXTRACT THE LOWER NIBBLE ADDLW H'30' ;CONVERT TO ASCII MOVWF LCD_HUNDS ;SAVE IN HUNDS REG ;CLRW SWAPF BCD_LOBYTE + 1,W ;GRAB HIGHER BTYE HIGHER NIBBLE AND CONVERT O LOWER NIBBLE ANDLW H'0F' ;EXTRACT LOWER NIBBLE ADDLW H'30' ;CONVERT TO ASCII MOVWF LCD_THOUS ;SAVE IN THOUS REG MOVF BCD_TENTS,W ;GET TENS LOWER NIBBLE ANDLW H'0F' ;EXTRACT THE LOWER NIBBLE ADDLW H'30' ;CONVERT TO ASCII MOVWF LCD_TENTS ;SAVE IN TENTS REG RETURN ;*******************************************************************************
post edited by schmity - 2015/03/24 02:20:07
|
1and0
Access is Denied
- Total Posts : 12108
- Reward points : 0
- Joined: 2007/05/06 12:03:20
- Location: Harry's Gray Matter
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/24 08:00:02
(permalink)
Your implementation of double dabble is the same as Jorge's which is based too literally on the algorithm described in Wikipedia's article of Double Dabble and as a result takes more execution time and memory spaces. Here's a more efficient implementation of double dabble for PIC16 devices: ; ; 16-bit Binary To 5-digit Packed BCD ; ; input = binH:binL = 16-bit binary number ; output = bcdU:bcdH:bcdL = 5-digit packed BCD number ; Bin16ToBCD5 clrf bcdL ; clear bcd result clrf bcdH clrf bcdU movlw .16 ; 16 bits counter movwf count goto bcd0 ; branch to reduce 16 Tcy bcd_lp movlw 0x33 ; adjust Tens:Ones digits addwf bcdL btfsc bcdL,3 andlw 0xF0 btfsc bcdL,7 andlw 0x0F subwf bcdL movlw 0x33 ; adjust Thou:Hund digits addwf bcdH btfsc bcdH,3 andlw 0xF0 btfsc bcdH,7 andlw 0x0F subwf bcdH ; movlw 0x03 ; adjust TenK digit ; addwf bcdU ; btfss bcdU,3 ; subwf bcdU bcd0 rlf binL ; shift out a binary bit rlf binH rlf bcdL ; into bcd result (double) rlf bcdH rlf bcdU decfsz count ; repeat for all bits goto bcd_lp return ; exit
which takes 32 28 words of program memory and executes in 409 349 isochronous instruction cycles (Tcy) including call. As I said earlier the division-by-subtraction method should be faster at 300's Tcy, and there're other methods that are even faster at 200's Tcy. <edit> Shaved 60 cycles and 4 words off the code -- see Post #38.
post edited by 1and0 - 2015/03/25 22:21:36
|
JorgeF
Super Member
- Total Posts : 3345
- Reward points : 0
- Joined: 2011/07/09 11:56:58
- Location: PT/EU @ Third rock from the Sun
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/24 11:59:11
(permalink)
Hi Wow, I'm saving this one for future reference. Somehow this algorithm makes me remember the DAA (decimal adjust accumulator) of the Intel80xx range of processors. As a matter of fact is the first time I heard (see) the term "Double Dabble". I've been using this algorithm, under the name of "SHIFT/ADD3" since around 1981, when I was at the University learning i8085 ASM on an Intel SDK-85. I think that using integer division by 10 will take more time since we need to run a 16bit by 8bit division at least 4 times, to extract the 5 digits. Or am I missing something here? Best regards Jorge
post edited by JorgeF - 2015/03/24 12:08:39
|
Mysil
Super Member
- Total Posts : 4125
- Reward points : 0
- Joined: 2012/07/01 04:19:50
- Location: Norway
- Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?
2015/03/24 14:41:06
(permalink)
Hi, Playing with the code and test program contributed by JorgeF, and code shown by 1and0 today, I have noticed some properties of the double dabble algorithm. Jorge noticed the fact that the first 2 sequences of shifts will never cause a "add 3" adjustment to be needed. Then the most significant nibble in result will not achieve a value that will need a adjustment either. Modifying 1and0's code, it has been possible to run the algorithm in 315 instruction cycles. Regards, Mysil
|