> It's possible to use Bresenham with two integers 10,000,000 and
> 32,768 but I found no way to perform all the 24-bit calculations
> on an 8-bit PIC quick enough. Removing the GCD often helps
> but in this case the accumulator remains 3-bytes wide.

Huh?  Dividing 10,000,000 by 4 (to match the PIC instruction timing)
and multiplying 32768 by 2 (since you have to generate both edges),
you want to generate an edge every 2500000/65536 instruction
cycles.

That's every 38 or 39 cycles.  To be precise, 38 instructions
most of the time and 39 instructions 9632/65536 of the time.

Since the divisor is a power of 2, this fits conveniently
into a 16-bit accumulator.  Let me see if I can put the code
together...

cblock 0x20
        gpcopy
        lsb
        msb
        tmp
endc

step    equ d'9632'

loop:                           ; Cycles at end of instruction
        comf    gpcopy,f        ;  1
        movf    gpcopy,w        ;  2
        movwf   GPIO            ;  3

        movlw   8               ;  4
        movwf   tmp             ;  5
delay:
        decfsz  tmp,f           ;  6, 9,12,15,18,21,24,27
        goto    delay           ;  8,11,14,17,20,23,26

        nop                     ; 29

        movlw   step&0xff       ; 30
        addwf   lsb, f          ; 31
        movlw   step>>8         ; 32
        skpnc                   ; 33
          movlw (step>>8)+1     ; 34
        addwf   msb, f          ; 35
        skpc                    ; 36
          goto  loop            ; 38
        goto    loop            ; 39

The minimum length of this loop is 12/13 cycles, but it depends on a
power-of-2 output frequency (after modulo reduction, so you could have
powers of 5 as well).

With some clever unrolling, it can be reduced to 10/11 cycles:
loop:
        clrf    GPIO            ;  1

        movlw   step&0xff       ;  2
        addwf   lsb, f          ;  3
        movlw   step>>8         ;  4
        skpnc                   ;  5
          movlw (step>>8)+1     ;  6
        addwf   msb, f          ;  7
        skpnc                   ;  8
          goto  $+1             ; 10
        movlw   0xff            ; 10/11

        movwf   GPIO            ;  1
        movlw   step&0xff       ;  2
        addwf   lsb, f          ;  3
        movlw   step>>8         ;  4
        skpnc                   ;  5
          movlw (step>>8)+1     ;  6
        addwf   msb, f          ;  7
        skpc                    ;  8
          goto  loop            ; 10
        goto    loop            ; 11

An arbitrary divisor will complicate this somewhat, but not actually
add very much time.  You just need two matched code paths, which add
"step", or "step + 65536-divisor" to the accumulator as appropriate.

There may also be some way to use higher-order Bresenham to reduce things
to 8 bits, at the expense of needing the subroutine stack.

Here, we have 38 instructions most of the time, and 39 instructions
9632/65536 = 301/2048 of the time.  That means that the pattern is
either 5x38+39 or 6x38+39, with the latter happening (2048%301)/301 =
242/301 of the time.

Since we have the 5x38+39 pattern happening 59/301 of the time, you
have 5x(6x38+39)+(5x38+39) some of the time, and 6x(6x38+39)+(5x38+39)
the rest of the time.  My brain is getting tangled figuring out which is
which, but it's one of them (301%59)/59 = 6/59 of the time and
the other 53/59 of the time.  You could use a 1-byte accumulator, or
just open-code that part of the pattern.

_______________________________________________
time-nuts mailing list -- [email protected]
To unsubscribe, go to https://www.febo.com/cgi-bin/mailman/listinfo/time-nuts
and follow the instructions there.

Reply via email to