[time-nuts] 32768 Hz from 10 MHz

Orin Eman orin.eman at gmail.com
Fri Feb 3 06:15:11 UTC 2012


On Thu, Feb 2, 2012 at 7:16 PM, Hal Murray <hmurray at megapathdsl.net> wrote:

>
> > 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.
>
> > To generate 32 kHz you have to toggle a pin and calculate if the next
> toggle
> > must be 38 or 39 instructions in the future; all the math must occur
> within
> > 37 instructions. That's why I came up with the binary leap year kind of
> > algorithm; it's as close to math-less as you can get.
>
> You missed the simple way.  Table lookup.  :)
>
> The table is only 256 slots long.
>
> That's toggling between 305 and 306 cycles.  If your CPU uses N clocks per
> instruction, multiply the table size by N.
>



Well, I thought table lookup too, but I figured  a 2048 x 1 table.  Easily
done with a rotating bit and 256 byte table.


Assuming clocking a PIC at 10MHz, you have 2,500,000 instructions per
second.  Since there was talk about time to the next toggle, we have
2,500,000/65536 instructions between toggles, ie 38.1470... instructions.
 The fraction turns out to be 301/2048, so you have to distribute 301 extra
instructions over every 2048 half-periods of the 32768Hz waveform.

Here's what I would do in a mix of C and asm:

unsigned char bitmask = 0x80;
unsigned char index =  0xFF;
unsigned char table[256] = { // Calculate using a spreadsheet or similar };
bit OutputBit;

asm {
loop:
    BCF    STATUS,C
    RLF    bitmask,F
    BTFSS STATUS,C
    GOTO IndexOK
    RLF    bitmask,F           ; restore low bit from carry
    INCF   index,W             ; on to the next byte in the table
    GOTO DoLookup
IndexOK:
    NOP                            ; equalize time in if/else cases
    NOP
    MOVF index,W
DoLookup:
    CALL TableLookup        ; Not defined here, returns value in W

    ANDWF bitmask,W
    BTFSS STATUS,Z
    GOTO  ExtraCycle        ; 1 cycle if skipped, 2 if executed
ExtraCycle:
}
    // Extra delay to get to 38/39 instructions (about 20 instructions if I
counted right)

    OutputBit ^= 1;             ; Toggle output
    goto loop;

This version rotates the mask each time through and increments the index
every 8 times through.  You could increment the index each time through and
rotate the mask when the index rolls over.  That makes calculating the
table harder though.

No doubt I got the sense of the skips wrong or miscounted instructions
somewhere!

Orin.



More information about the Time-nuts_lists.febo.com mailing list