NCO Calculator


Closed Thread
Results 1 to 25 of 25

Thread: NCO Calculator

Hybrid View

  1. #1
    Join Date
    Apr 2014
    Location
    OK
    Posts
    557


    Did you find this post helpful? Yes | No

    Default Re: NCO Calculator

    NCOa.zip

    I'm a bit new to this whole PC programming thing. I spent some time with the NCO Calculator and realized it really needed a bit of refinement. Attached is a cleaner version. Old one still works, but the new one has a few filters that make it more user friendly. The new one expands the Fosc range to include more options.

  2. #2
    Join Date
    Apr 2014
    Location
    OK
    Posts
    557


    Did you find this post helpful? Yes | No

    Default Re: NCO Calculator

    Using Mr. E-Calc, I wanted to calculate values for a PWM frequency using LFINTOSC, which is 32 kHz. I entered 0.031 where it asks for Fosc (MHz) and wouldn't you know it, IT WORKED! Got me thinking about the NCO Calc. I had limited Fosc to 1 MHz on the low end. This updated Version 1.02 lowered the minimum to 1 kHz (0.001 in the Fosc box).

    Nco Calc1_02.zip

  3. #3
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: NCO Calculator

    Hi mpgmike (and gang):

    I like your NCO Calculator app'. Thank you.

    My calculation results are slightly different from those produced by your NCO Calculator. Would you or another forum member have time to help me figure out the problem with my calculations, please?

    I designed a ClockGen IC for a retro 65C02 project a couple years ago using an 8 pin 16F18313 (listing attached below). I used a 32-MHz clock and I used the NCO to generate a 1.8432 MHz clock for an ACIA chip on that project. My NCO calculations were;

    Resolution = 32000000 / 2^20 / 2 = 15.2587890625-Hz
    Phase_Inc = 1843200 / 15.2587890625 = 120795.9552

    Rounding up the phase increment value to 120796 I get the following frequency output;

    Freq_output = 120796 * 15.2587890625 = 1843200.68359375-Hz
    Freq_error = 1843200.68359375 / 1843200 - 1 = ~0.00004%

    Since my phase increment and output frequency values are slightly different than those of the NCO Calculator, I'm wondering if I messed up on my calculations.

    Help appreciated. TIA...

    Cheerful regards, Mike

    Code:
    ;******************************************************************
    ;                                                                 *
    ;    Project: 65C02_Clock                                         *
    ;       File: 16F18313_Clock.asm                                  *
    ;     Author: Mike McLaren, K8LH                                  *
    ;    (C)2016: Micro Application Consultants                       *
    ;           : All Rights Reserved                                 *
    ;       Date: 04-Apr-2016                                         *
    ;                                                                 *
    ;    16F18313 Clock-Gen + Econo-Reset for 65C02 (8-MHz crystal)   *
    ;    produces a 1, 2, 4, or 8 MHz CPU clock and an ACIA clock.    *
    ;                                                                 *
    ;        IDE: MPLABX v3.05                                        *
    ;       Lang: MPASM v5.62 (absolute addressing mode)              *
    ;                                                                 *
    ;******************************************************************
    
            #include <p16F18313.INC>
            errorlevel -302,-311    ; suppress bank warnings
            list st=off             ; symbol table off
            radix dec
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  config settings                                                ~
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
     __CONFIG _CONFIG1, _FEXTOSC_HS & _FCMEN_OFF
     ;
     ; CLKOUTEN_OFF default
     ; CSWEN_ON     default
     ;
     __CONFIG _CONFIG2, _WDTE_OFF & _PPS1WAY_OFF
     ;
     ; MCLRE_ON     default
     ; PWRTE_OFF    default
     ; LPBOREN_OFF  default
     ; BOREN_ON     default
     ; BOREN_LOW    default
     ; STVREN_ON    default
     ; DEBUG_OFF    default
     ;
     __CONFIG _CONFIG3, _LVP_OFF
     ;
     ; WRT_OFF      default
     ;
     __CONFIG _CONFIG4, _CP_OFF & _CPD_OFF
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  variables                                                      ~
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            cblock  0x70            ; common RAM available any bank
    delayhi                         ; DelayCy() subsystem variable
            endc
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  constants                                                      ~
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;
    ;  assign clock and reset pins (RA0..RA2 inclusive).
    ;
    PHI0_clk equ    RA0             ; bit index for RA0 (0)
    ACIA_clk equ    RA1             ; bit index for RA1 (1)
    RESB_out equ    RA2             ; bit index for RA2 (2)
    ;
    ;  associate to "Peripheral Pin Select" output registers.
    ;
    PHI0_PPS equ    RA0PPS+PHI0_clk ; equ RA0PPS
    ACIA_PPS equ    RA0PPS+ACIA_clk ; equ RA1PPS
    RESB_PPS equ    RA0PPS+RESB_out ; equ RA2PPS
    ;
    ;  set 'CLKR_div' constant for desired 65C02 clock frequency.
    ;
    ;               6 ->  0.5-MHz (Fosc / 64)
    ;               5 ->  1.0-MHz (Fosc / 32)
    ;               4 ->  2.0-MHz (Fosc / 16)
    ;               3 ->  4.0-MHz (Fosc / 8)
    ;               2 ->  8.0-MHz (Fosc / 4)
    ;               1 -> 16.0-MHz (Fosc / 2)
    ;
    CLKR_div equ    4               ; 2.0-MHz PHI0 CPU clock
    ;
    ;  set 'NCO1_inc' constant for desired ACIA clock output.
    ;
    ;          2517 ->    38400-Hz (  2400 * 16) @ 0.01659%
    ;          5033 ->    76800-Hz (  4800 * 16) @ 0.00327%
    ;         10066 ->   153600-Hz (  9600 * 16) @ 0.00327%
    ;         20133 ->   307200-Hz ( 19200 * 16) @ 0.00169%
    ;         40265 ->   614400-Hz ( 38400 * 16) @ 0.00079%
    ;         60398 ->   921600-Hz ( 57600 * 16) @ 0.00004%
    ;        120796 ->  1843200-Hz (115200 * 16) @ 0.00004%
    ;        241592 ->  3686400-Hz (230400 * 16) @ 0.00004%
    ;
    NCO1_inc equ    120796          ; 1.8432-MHz (115200 * 16)
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  K8LH DelayCy() subsystem macro generates four instructions     ~
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            radix dec
    clock   equ     32              ; 4, 8, 12, 16, 20 (MHz), etc.
    usecs   equ     clock/4         ; cycles/microsecond multiplier
    msecs   equ     usecs*1000      ; cycles/millisecond multiplier
    dloop   equ     5               ; loop size, 5 to ??? cycles
    ;
    ;  -- loop --  -- delay range --  -- memory overhead ----------
    ;  5-cyc loop, 11..327690 cycles,  9 words (+4 each macro call)
    ;  6-cyc loop, 11..393226 cycles, 10 words (+4 each macro call)
    ;  7-cyc loop, 11..458762 cycles, 11 words (+4 each macro call)
    ;  8-cyc loop, 11..524298 cycles, 12 words (+4 each macro call)
    ;  9-cyc loop, 11..589834 cycles, 13 words (+4 each macro call)
    ;
    DelayCy macro   cycles          ; range, see above
        if (cycles<11)|(cycles>(dloop*65536+10))
            error " DelayCy range error "
        else
            movlw   high((cycles-11)/dloop)+1
            movwf   delayhi
            movlw   low ((cycles-11)/dloop)
            call    uLoop-((cycles-11)%dloop)
        endif
            endm
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  reset vector                                                   ~
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            org     0x0000
    v_reset
            bra     setup           ;                                 |00
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  interrupt vector                                               ~
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            org     0x0004
    v_int
            retfie                  ;                                 |??
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  main setup                                                     ~
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    setup
    ;
    ;  turn off analog functions (all I/O will be digital).
    ;
            banksel ANSELA          ; bank 03                         |03
            clrf    ANSELA          ; analog off, digital I/O         |03
    ;
    ;  setup data direction for 'output' pins (default 'input').
    ;
            banksel TRISA           ; bank 01                         |01
            bcf     TRISA,PHI0_clk  ; set phi0 clock pin as output    |01
            bcf     TRISA,ACIA_clk  ; set acia clock pin as output    |01
            bcf     TRISA,RESB_out  ; set resb reset pin as output    |01
    ;
    ;  clear RESB pin output latch (hold the 65C02 in reset).
    ;
            banksel LATA            ; bank 02                         |02
            bcf     LATA,RESB_out   ; RESB_out = '0'                  |02
    ;
    ;  setup Fosc for 32-MHz (external 8-MHz crystal and 4xPLL).
    ;
            banksel OSCCON1         ; bank 18                         |18
            movlw   b'00010000'     ; -001---- NOSC[2:0], Ext 4xPLL   |18
                                    ; ----0000 NDIV[3:0], Clk Div 1   |18
            movwf   OSCCON1         ; 8-MHz Xtal & 4xPLL -> 32-MHz    |18
    stable
            btfss   OSCCON3,ORDY    ; OSC stable? yes, skip, else     |18
            bra     stable          ; loop (wait until OSC stable)    |18
    ;
    ;  assign PHI0_clk pin (RA0) and ACIA_clk pin (RA1) resources
    ;  via 'Peripheral Pin Select'.
    ;
            banksel PPSLOCK         ; bank 28                         |28
            movlw   0x55            ; PPS unlock sequence             |28
            movwf   PPSLOCK         ;  "                              |28
            movlw   0xAA            ;  "                              |28
            movwf   PPSLOCK         ;  "                              |28
            bcf   PPSLOCK,PPSLOCKED ;  "                              |28
            banksel PHI0_PPS        ; bank 29                         |29
            movlw   b'00011110'     ; assign CLKR (Ref Clock) output  |29
            movwf   PHI0_PPS        ; to the PHI0 clock pin (RA0)     |29
            movlw   b'00011101'     ; assign NCO module output to     |29
            movwf   ACIA_PPS        ; the ACIA clock pin (RA1)        |29
            banksel PPSLOCK         ; bank 28                         |28
            bsf   PPSLOCK,PPSLOCKED ; all done, lock it up            |28
    ;
    ;  setup CLKR (Reference Clock) module for PHI0 CPU Clock.
    ;
            banksel CLKRCON         ; bank 07                         |07
            movlw   0x10|CLKR_div   ; 50% duty cycle & divider bits   |07
            movwf   CLKRCON         ; prep 1, 2, 4, or 8-MHz output   |07
            bsf     CLKRCON,CLKREN  ; enable Reference Clock output   |07
    ;
    ;  setup NCO to generate the ACIA clock.
    ;
            banksel NCO1CON         ; bank 08                         |08
    ;       bcf     NCO1CON,N1PFM   ; fixed duty cycle mode (default) |08
            movlw   b'00000001'     ; N1CKS<1:0> = '01' = Fosc        |08
            movwf   NCO1CLK         ; set NCO clock source            |08
            clrf    NCO1ACCL        ; clear 20-bit phase accumulator  |08
            clrf    NCO1ACCH        ;  "                              |08
            clrf    NCO1ACCU        ;  "                              |08
            movlw   upper(NCO1_inc) ;  "                              |08
            movwf   NCO1INCU        ;  "                              |08
            movlw   high(NCO1_inc)  ;  "                              |08
            movwf   NCO1INCH        ;  "                              |08
            movlw   low(NCO1_inc)   ; setup 20-bit phase increment    |08
            movwf   NCO1INCL        ;  "                              |08
            bsf     NCO1CON,N1EN    ; enable NCO module output        |08
    ;
    ;  complete the 65C02 reset cycle.
    ;
            DelayCy(20*msecs)       ; wait ~20-msecs                  |08
            banksel LATA            ; bank 02                         |02
            bsf     LATA,RESB_out   ; release 65C02 from reset        |02
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  main loop                                                      ~
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    loop
            bra     loop            ; loop forever (until reset)      |02
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  K8LH DelayCy() subsystem 16-bit 'uLoop' timing subroutine      ~
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    a = dloop-1
        while a > 0
            nop                     ; (cycles-11)%dloop entry points  |??
    a -= 1
        endw
    uLoop   addlw   -1              ; subtract 'dloop' loop time      |??
            skpc                    ; borrow? no, skip, else          |??
            decfsz  delayhi,F       ; done?  yes, skip, else          |??
            bra     uLoop-dloop+5   ; do another loop                 |??
            return                  ;                                 |??
    
    ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            end
    Last edited by Mike, K8LH; - 6th May 2018 at 17:59.

  4. #4
    Join Date
    Apr 2014
    Location
    OK
    Posts
    557


    Did you find this post helpful? Yes | No

    Default Re: NCO Calculator

    In the NCO Calc I entered:

    Fosc = 32 MHz
    Frequency = 1,843,200 (didn't use commas in the NCO Calc, added for clarity here)

    What I got in return was:

    NCO Decimal = 120795.84
    NCO HEX = 1D7DC
    Result Rounded Up = 1,843,217.7002
    Result Rounded Down = 1,843,202.4414

    Our results aren't that much different. The project I developed the NCO Calc for is reading within < 0.02 Hz different than calculated with the NCO Calc. Not sure what you got.

  5. #5
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: NCO Calculator

    Hi mpgmike. Thanks for the reply.

    Those are the same numbers I got from NCO Calculator. May I ask how you produced some of those numbers, if you have time, please? I'm concerned that I'm using the wrong formulas for the calculated output frequency and error.

    What formula did you use to produce the 120795.84 phase increment value? My result was 120795.9552 which is ever so slightly different (formula in my previous post).

    What formula do you use to produce "Result Rounded Up" and "Result Rounded Down" values? Are those supposed to be the frequency output when you round the phase increment value to integer values of 120795 or 120796? I'm concerned about my calculations as I came up with an output frequency of 1843200.68359375-Hz (~0.00004% off) using 120796 for the phase increment value.

    If I'm using the wrong calculations I'd like to fix them and update the frequency error comments in my project.

    Thank you for your time and kind consideration.

    Cheerful regards, Mike, K8LH
    Last edited by Mike, K8LH; - 9th May 2018 at 01:48.

  6. #6
    Join Date
    Apr 2014
    Location
    OK
    Posts
    557


    Did you find this post helpful? Yes | No

    Default Re: NCO Calculator

    The basic formula reduces down to:

    NCO Value = (Frequency * 2,097,150) / Fosc

    Building the NCO Calc in Visual Basic, the behind-the-scenes math was:

    NcoDec = (Freq * 2.09715) / Fosc
    NcoDecR = Math.Round(NcoDec, 3)
    FreqDn = Math.Round(((NcoInt * Fosc) / 2.09715), 4)
    FreqUp = Math.Round(((NcoInt1 * Fosc) / 2.09715), 4)

    There's a bit of other code in there, but that's the math.

  7. #7
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default Re: NCO Calculator

    I think I found the problem... 2^21 equals 2097152, not 2097150. When I plug the 2097152 value into your formulas the phase increment and output frequency results match my calculations.

    Thank you so much for helping me verify my calculations are correct.

    Cheerful regards, Mike, K8LH

    Fosc = 32000000
    Freq = 1843200

    NCO Decimal = 120795.9552
    NCO HEX = 1D7DC
    Result Rounded Up = 1843200.68359375
    Result Rounded Down = 1843185.4248046875
    Resolution = 15.2587890625-Hz
    Last edited by Mike, K8LH; - 9th May 2018 at 04:15.

Similar Threads

  1. help with calculator
    By minssss in forum General
    Replies: 3
    Last Post: - 10th November 2009, 00:12
  2. Calculator LCD
    By menze in forum General
    Replies: 0
    Last Post: - 26th June 2006, 21:31
  3. help with my calculator project
    By loayaouad in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 17th May 2005, 07:42
  4. Calculatorīs LCD
    By srspinho in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 4th May 2005, 10:27
  5. Calculator
    By neiron21 in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 1st February 2005, 00:53

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts