Hot!HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER?

Page: << < ..6789 Showing page 9 of 9 - Powered by APG vNext Trial
Author
NorthGuy
Super Member
  • Total Posts : 4881
  • Reward points : 0
  • Joined: 2014/02/23 14:23:23
  • Location: Northern Canada
  • Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER? 2015/04/10 14:37:05 (permalink)
0
I have an idea, but it would take some time to implement, which I don't have at the moment :(
 
I think the weak point is 9 cycles where r is compared to 1000 and corrected. My idea is to let it proceed as it is, do the conversion of (hund:tens:ones) in which hund will come out as a number between 0 and 19 (most likely a shorter range), then compare hund to 10, correct thou, and then do the conversion of (tenk:thou). This way, the 9-cycle comparison/correction will have to be 8-bit as opposed to current 16-bit, thereby saving 4 instructions.
 
This is not an easy change because it would require re-working division by 100, or perhaps even replacing it with division by 10, but even if it costs couple more cycles, it still will be a gain in the end.
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/04/11 01:20:27 (permalink)
0
hy guys
the contest continue  
the bar is fixed at 40 Tcy
1and0
Access is Denied
  • Total Posts : 8005
  • 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/04/11 04:45:42 (permalink)
0
NorthGuy
I have an idea, but it would take some time to implement, which I don't have at the moment :(

I also do not have much time at the moment, but here's my first attempt at implementing your idea.  With this method, instead of comparing r to 1000 it has to compare r to 100, correct hund, and then compare hund to 10 and correct thou.  It ends up taking the same maximum Tcy.  Maybe you guys can improve it.  There has to be a fast way to get exact quotient without correction.
;
; 16-bit Unsigned Binary To 5-digit BCD Conversion (For PIC18)
;
; input  = binH:binL                = 16-bit binary number
; output = tenk:thou:hund:tens:ones = 5-digit unpacked BCD number
;
;  cycle = 50 maximum   , for  1668 ( 3%) binary numbers
;        = 48 average
;        = 48 minimum   , for 37380 (57%) binary numbers
;  size  = 49 words
;
Bin16ToBCD5
        movf    binH,w          ; q = 4*(n >> 8)  , where n = binary number
        mullw   .4              ;                         q = quotient
        addwf   PRODH,w         ; q = (q >> 8) + (n >> 8) <= 258
       
        andlw   b'11111100'     ; clear bit1 for mullw/rlcf, bit0 for rrcf
        rrcf    WREG            ; (q >> 1) to reduce to 8-bit
        mullw   .250            ;
        rrcf    WREG            ; q = n / 1000 = (q >> 2)
        movwf   thou            ;   = n * (4/256/256 + 1/256) / 4 = 0..64
       
        rlcf    PRODL,w         ; 1000*q
        rlcf    PRODH           ;
        subwf   binL            ; r = n % 1000 = n - 1000*q
        movf    PRODH,w         ;                 , where r = remainder
        subwfb  binH            ;
;-------
        movf    binL,w          ; q = (r >> 4)
        andlw   0xF0            ;
        iorwf   binH,w          ;
        swapf   WREG            ;
       
        mullw   .41             ; q = q * 41/256
        movf    PRODH,w         ;
        movwf   hund            ; hund = r / 100 = (r >> 4) * 41/256 <= 19
       
        mullw  .100             ; 100*hund
        movf   PRODL,w          ;
        subwf  binL             ; r = r % 100 = r - 100*hund
;       movf   PRODH,w          ; discard high byte
;       subwfb binH             ;
       
        movlw  .100             ; if (r >= 100)
        subwf  binL,w           ; {
        bnc    qhh              ;
        movwf  binL             ;   r -= 100
        incf   hund             ;   hund++
qhh                             ; }
        movf   hund,w           ; if (hund >= 10)
        addlw  -.10             ; {
        bnc    qkk              ;
        movwf  hund             ;   hund -= 10
        incf   thou             ;   thou++
qkk                             ; }
;-------
        incf    thou,w          ; divide q by 10
        mullw   .51             ;
        rrcf    PRODH,w         ;
        movwf   tenk            ; tenk = q / 10
       
        mullw   .10             ; 10*tenk
        movf    PRODL,w         ;
        subwf   thou            ; thou = q % 10 = q - 10*tenk
;
        incf    binL,w          ; divide r by 10
        mullw   .51             ;
        rrcf    PRODH,w         ;
        movwf   tens            ; tens = r / 10
       
        mullw   .10             ; 10*tens
        movf    PRODL,w         ;
        subwf   binL,w          ;
        movwf   ones            ; ones = r % 10 = r - 10*tens
        return                  ; exit

1and0
Access is Denied
  • Total Posts : 8005
  • 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/04/11 04:49:35 (permalink)
+1 (1)
i1ctg
hy guys
the contest continue  
the bar is fixed at 40 Tcy

Wow! grin: grin
NorthGuy
Super Member
  • Total Posts : 4881
  • Reward points : 0
  • Joined: 2014/02/23 14:23:23
  • Location: Northern Canada
  • Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER? 2015/04/11 08:11:54 (permalink)
+2 (2)
I would suggest this for the beginning. Just typed in, no tests. IMHO, this is completely equivalent to first 8 instructions.
 
movf binH,w
mullw .65
movf PRODH,w ; approximate division by 1000 or 65/65536
movwf thou
addwf PRODH,w ; (thou << 1), also cleans carry
mullw .250

 
This saves 2 instructions/cycles.
1and0
Access is Denied
  • Total Posts : 8005
  • 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/04/11 08:42:49 (permalink)
0
NorthGuy
I would suggest this for the beginning. Just typed in, no tests. IMHO, this is completely equivalent to first 8 instructions.
movf binH,w
mullw .65
movf PRODH,w ; approximate division by 1000 or 65/65536
movwf thou
addwf PRODH,w ; (thou << 1), also cleans carry
mullw .250

This saves 2 instructions/cycles.

Excellent!!!  It works.
 
NorthGuy
Super Member
  • Total Posts : 4881
  • Reward points : 0
  • Joined: 2014/02/23 14:23:23
  • Location: Northern Canada
  • Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER? 2015/04/11 11:58:26 (permalink)
0
1and0
There has to be a fast way to get exact quotient without correction.


Not much luck. Looks like to get exact quotient you need to do 655/65536, which means 16-by-16 multiplication. Even though you can drop the high byte completely, which reduces necessary carries, it is hard to get rid of carries from lower bytes.
 
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/04/12 12:28:15 (permalink)
0
no luck here too, I'm working with this algorithm
very promising   but I can not go below 50
 

        movwf binH,W
        mullw .64 ;PRODH = 0 .. 63
        movf PRODH,W
        movwf thou ; +0 .. -2
        mullw .24 ;1024 - 1000
        movf PRODL,W ;
        addwf binL,f
        movf binH,w
        andlw 0x03
        addwfc PRODH,W ;binHL = 0 ... 2565
        movwf binH
      

 
whether there will be news i post here.   greetings   
NorthGuy
Super Member
  • Total Posts : 4881
  • Reward points : 0
  • Joined: 2014/02/23 14:23:23
  • Location: Northern Canada
  • Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER? 2015/04/12 14:19:33 (permalink)
0
As the first division stands now, the remainder (r) is confined to 0 to 1767 range. When dividing by 100, these all give the exact result (0 to 17):
 
(r&0xffe)*41>>12
(r>>1)*82>>12
(r>>2)*41>>10
(r>>2)*164>>12
 
I tried some of them, but didn't succeed right away.
1and0
Access is Denied
  • Total Posts : 8005
  • 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/04/12 16:24:41 (permalink)
+1 (1)
NorthGuy
(r>>2)*164>>12

My code in Post #160 does this when dividing r by 100.
 
<edit> All four of your equations require more than an 8x8 multiply.  An 8x8 with addition of high byte should work.
post edited by 1and0 - 2015/04/12 16:57:48
NorthGuy
Super Member
  • Total Posts : 4881
  • Reward points : 0
  • Joined: 2014/02/23 14:23:23
  • Location: Northern Canada
  • Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER? 2015/04/12 17:53:55 (permalink)
+1 (1)
Good idea. I tried it. This would take 7 cycles, which can replace 4 of your instructions beginning from "mullw .164". Theoretically, it should give 1 cycle gain because it saves 4 instructions on ajustment. Although I feel this piece could be improved.
 

mullw .41 ; multiply
movf PRODH,w
btfsc binH,0 ; add extra byte if needed
addlw .41
mullw .64 ; shift right 2 pos
movf PRODH,w
movwf hund ; save the result

 
1and0
Access is Denied
  • Total Posts : 8005
  • 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/04/13 07:26:09 (permalink)
0
Very nice!  That saves one cycle.  Place the compare hund to 10 and correct thou after "mullw .100" saves another cycle, resulting in the following that executes in 46 maximum instruction cycle.
;
; 16-bit Unsigned Binary To 5-digit BCD Conversion (For PIC18)
;
; input  = binH:binL                = 16-bit binary number
; output = tenk:thou:hund:tens:ones = 5-digit unpacked BCD number
;
;  cycle = 46 maximum   , for 25880 (39%) binary numbers
;        = 45 average
;        = 45 minimum   , for 39656 (61%) binary numbers
;  size  = 45 words
;
Bin16ToBCD5
        movf    binH,w          ; q = (n >> 8)*65  , where n = binary number
        mullw   .65             ;                          q = quotient
        movf    PRODH,w         ;
        movwf   thou            ; thou = n / 1000 = (n >> 8)*65/256 = 0..64
       
        addwf   WREG            ; 1000*thou, clear carry       
        mullw   .250            ;
        rlcf    PRODL,w         ;
        rlcf    PRODH           ;
       
        subwf   binL            ; r = n % 1000 = n - 1000*thou = 0..1767
        movf    PRODH,w         ;                  , where r = remainder
        subwfb  binH            ; r(max) occurs at binH:L = 64767
;-------
        rrcf    binH            ; divide r by 100   (r <= 1767 = 0x6E7)
        rrcf    binL,w          ;    1/100 =~ 1/4 * 41/1024
        rrcf    binH            ;          = 0.010009766
        rrcf    WREG            ; (r >> 2) to reduce to 9-bit
       
        mullw   .41             ; multiply
        movf    PRODH,w         ; (r >> 2)*41
        btfsc   binH,0          ; add high byte if needed
        addlw   .41             ; to handle bit 9
       
        mullw   .64             ; shift right 2+8 to divide by 1024
        movf    PRODH,w         ;
        movwf   hund            ; hund = (r >> 2)*41/1024 = 0..17
        mullw   .100            ; 100*(r / 100) = 100*hund
       
        addlw   -.10            ; if (hund >= 10)
        bnc     q100            ; {
        movwf   hund            ;   hund -= 10
        incf    thou            ;   thou++
q100                            ; }
        movf    PRODL,w         ; discard high byte
        subwf   binL            ; r =  r % 100 = r - 100*(r / 100)
;-------
        incf    binL,w          ; divide r by 10
        mullw   .51             ;
        rrcf    PRODH,w         ;
        movwf   tens            ; tens = r / 10
       
        mullw   .10             ; 10*tens
        movf    PRODL,w         ;
        subwf   binL,w          ;
        movwf   ones            ; ones = r % 10 = r - 10*tens
;
        incf    thou,w          ; divide thou by 10
        mullw   .51             ;
        rrcf    PRODH,w         ;
        movwf   tenk            ; tenk = thou / 10
       
        mullw   .10             ; 10*tenk
        movf    PRODL,w         ;
        subwf   thou            ; thou = thou % 10 = thou - 10*tenk
        return                  ; exit

I also feel some more improvement can be made.
 
Nikolay_Po
Super Member
  • Total Posts : 1680
  • Reward points : 0
  • Joined: 2012/04/01 13:49:27
  • Location: Russia, Novorossiysk
  • Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER? 2015/05/30 23:34:49 (permalink)
+1 (1)
As a continue for http://www.microchip.com/forums/FindPost/855132, for PIC24/dsPIC. The code in that post contains a bug: the sequence 0,1,2,3..65534,65535 gives a result 0,0,1,2..65533,65534. Here is corrected version:
 
void itoa16asm(uint16_t Value, uint8_t Decimal[]) { //Assembly conversion from
    //16 bit unsigned integer to 5 decimal digits.
    //Initial code from here: http://www.microchip.com/forums/FindPost/855132
    //correction idea from here: http://www.microchip.com/forums/FindPost/694830
    //W0 contains the value to convert, W1 contains the destination for decimal
    //digits.
    asm("mul.uu w0,#0x0006,w2");
    asm("mov #0x8DB9,w4");
    asm("mul.uu w0,w4,w4");
    asm("add w5,w2,w2");
    asm("addc.b w3,#0,[w1++]");
    asm("inc w2,w2");
    asm("mul.uu w2,#10,w2");
    asm("mov.b w3,[w1++]");
    asm("mul.uu w2,#10,w2");
    asm("mov.b w3,[w1++]");
    asm("mul.uu w2,#10,w2");
    asm("mov.b w3,[w1++]");
    asm("mul.uu w2,#10,w2");
    asm("mov.b w3,[w1++]");
}

 
The code seems to be OK for XC16 v1.24. But I haven't tested it extensively.
post edited by Nikolay_Po - 2015/05/30 23:37:33
Mysil
Super Member
  • Total Posts : 2760
  • Reward points : 0
  • Joined: 2012/07/01 04:19:50
  • Location: Norway
  • Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER? 2018/06/07 14:09:18 (permalink)
+1 (1)
Hi,
Here is a collection of functions discussed in this thread, callable from XC8, XC16 and XC32
Assembly code is wrapped as inline assembly in C.
There are functions for conversion from unsigned Binary to array of Decimal digits,
and functions for conversion from unsigned Binary to Character string, for 8 bit, 16 bit, 24 bit and 32 bit type.
 
Conversion from 8 bit and 16 bit variables are done by assembly code by multiplication scaling,
except for PIC16 devices, where binary search and subtraction is used.
24 bit and 32 bit code is more primitive, using repeated subtraction in C code.
 
Functions may be used by importing one or more .c source files from the upper directory in .zipfile. 
Subdirectories have some test and example code, and some library projects.
 
Code have been tested on some various PIC12, PIC16, PIC18, a single PIC24, and a couple of PIC32 devices.
 
Regards,
   Mysil
 
Edit: Correcions in code, see message #180:
   Mysil
post edited by Mysil - 2018/06/15 13:18:49
JorgeF
Super Member
  • Total Posts : 3039
  • 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? 2018/06/07 14:34:32 (permalink)
0
Hi
 
Great!
For sure it took more than a few hours to sum it all up.
Thank you Mysil.

Best regards
Jorge
 
I'm here http://picforum.ric323.com too!
And it works better....
1and0
Access is Denied
  • Total Posts : 8005
  • 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? 2018/06/09 21:26:34 (permalink)
0
@Mysil, very nice collection. For the PIC18, attached Bin16ToDec.c saves 1 instruction/cycle and Bin16ToChar.c saves 2 instructions/cycles.
 

Attachment(s)

Attachments are not available: Download requirements not met
Mysil
Super Member
  • Total Posts : 2760
  • Reward points : 0
  • Joined: 2012/07/01 04:19:50
  • Location: Norway
  • Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER? 2018/06/10 05:08:33 (permalink)
0
Thanks,
I will include those corrections in the collection.
 
Have also noted some inconsistencies between the header file and some source files in zipfile in message #174, but have not been able to rebuild the example for XC8 after updating MPLAB X to 4.20.
 
   Mysil
post edited by Mysil - 2018/06/10 05:11:08
1and0
Access is Denied
  • Total Posts : 8005
  • 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? 2018/06/10 09:35:03 (permalink)
0
I just took a look at your 8-bit binary conversion code and it is based on the 16-bit binary code in this thread. I have not timed those code, but I think Post #31 here is more efficient at 16 cycles. There might be faster versions yet, as speed was not the goal there.
1and0
Access is Denied
  • Total Posts : 8005
  • 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? 2018/06/11 08:27:14 (permalink)
0
Got some free time. Here's an uBin8_Char.c for the PIC18,
void uBin8_Char  (unsigned char Bin, char * Character)
{
    unsigned char bin = WREG;
    FSR0 = (unsigned int) Character;

  #asm
    #define ones (uBin8_Char@bin)

        mullw   164         ; divide by 100
        movf    PRODH,w     ;
        mullw   4           ;
        movf    PRODH,w     ;
        mullw   100         ; multiply by 100
        addlw   '0'         ;
        movwf   POSTINC0    ; save "huns", 0..2

        movf    PRODL,w     ;
        subwf   ones        ; ones -= (huns*100), 0..99

        incf    ones,w      ; divide by 10
        mullw   51          ;
        rrcf    PRODH,w     ;
        mullw   10          ; multiply by 10
        addlw   '0'         ;
        movwf   POSTINC0    ; save "tens", 0..9

        movf    PRODL,w     ;
        subwf   ones,w      ; ones -= (tens*10), 0..9
        addlw   '0'         ;
        movwf   POSTINC0    ; save "ones", 0..9

        clrf    INDF0       ; null terminator
  #endasm
}

Remove the addlw '0' and null terminator for uBin8_Dec().

<edit> Changed the type of *Character to plain char.
post edited by 1and0 - 2018/06/12 05:26:36
Mysil
Super Member
  • Total Posts : 2760
  • Reward points : 0
  • Joined: 2012/07/01 04:19:50
  • Location: Norway
  • Status: offline
Re: HOW TO EXTRACT DIGITS FROM 16-BIT COUNTER? 2018/06/13 03:05:05 (permalink)
0
Here is updated collection of conversion functions from unsigned binary to decimal array and character string.
Code from 1and0 for 8 bit binary to 3 digit character is used, it improve timing with 10 instruction cycles for each call.
There is also assembly code for 8 bit conversions for PIC24HJ..., dsPIC33FJ... and PIC32M...
 
Regards,
   Mysil
 
Edit, corrected code attached.
I made a mistake in merging code from 1and0 message #179, there was 1 instruction too much.
Data type for character string result changed to plain char type for functions returning 'ascii' character string.
Functions returning array of decimal digits are still use uint8_t  type.
XC8 may not make much notice, XC16 seem to be more picky.
 
There are test program projects attached for PIC16 & PIC18 using XC8, and for PIC24 & dsPIC33FJ using XC16.
Source code for unsigned Binary to Decimal conversion is the same, as well as source code for test example.
Projects and Configbits are different.
Source code file for test application contain time measurements for those devices that have been tried.
 
   Mysil
post edited by Mysil - 2018/06/15 13:14:58

Attachment(s)

Attachments are not available: Download requirements not met
Page: << < ..6789 Showing page 9 of 9 - Powered by APG vNext Trial
Jump to:
© 2018 APG vNext Trial Version 4.5