Menu

Trying to Count a Frequency with a GPS Pulse

Help
2022-08-12
2022-08-24
1 2 > >> (Page 1 of 2)
  • Jeff Weinmann

    Jeff Weinmann - 2022-08-12

    Hello,

    I have an input frequency of 7 Mhz on PortC.4

    I am also using a GPS which has Pulse Per Second output on PortC.3 to get me an accurate 1PPS.

    I want to count how many pulses on PortC.4 that occur between pulses on PortC.3 (accurate 1 second GPS pulses) to hopefully get an accurate frequency in HZ.

    Hardware wise I'm not sure if I should have pull-down resistor's on both the GPS and frequency line.

    I have an interrupt routine setup to interrupt when Timer1 overflows then I'm adding 65536 to the counter.

    I think I am close but not getting the correct answer. I'm getting like 31250 counts. What I'm not sure of is the proper setup of timer1 and If I'm counting overflows correctly.

    Can anyone assist? I know this chip is familiar to Evan as he has featured a similar MCU in his YouTube instruction videos, and I'm showing only the critical parts of the code:

    #CHIP PIC18F16Q40  'Compiler indicates its using the 64Mhz Internal oscillator
    #option explicit
    
    
        'Generated by PIC PPS Tool for Great Cow Basic
        'PPS Tool version: 0.0.6.2
        'PinManager data: Not available (3)
        'Generated for 18f16q40
        '
        'Template comment at the start of the config file
        '
        #startup InitPPS, 85
        #define PPSToolPart 18f16q40
    
        Sub InitPPS
    
                'Module: TMR1
                T1CKIPPS = 0x0014    'RC4 > T1CKI
    
                'Module: TMR2 pin direction
                DIR PortC.3 In    'GPS Pulse Input
                DIR PortC.4 In    'Si5351a Clock input
        End Sub
    
    
        Dim TimerValue as Long
        Dim FrequencyCount as Long
    
    
        'Initialize timer 1  (Should I use a prescaler?? currently 1:1 
        InitTimer1 ExtOsc,0
    
        On Interrupt Timer1Overflow Call IncCounter
    
    
        MainLoop:
        Do Forever
            ClearTimer 1
    
            'Wait for GPS Pulse
            Wait Until PORTC.3 = On
            StartTimer 1
            FrequencyCount = 0
            TimerValue = 0
    
            Wait Until PORTC.3 = Off
    
            'Wait until GPS PULSE comes back after 1 second
            Wait Until PORTC.3 = On
    
            StopTimer 1
    
            'Read Timer1
            TimerValue = FrequencyCount + Timer1
    
            comport=2
            HSerPrint str32(TimerValue),2
            HSerSend 13,2
            HSerSend 10,2
            comport=1
      Loop
    
      Sub IncCounter
            FrequencyCount = FrequencyCount + 65536
      End sub
    

    thanks ! any help is appreciated.

    Jeff

     

    Last edit: Jeff Weinmann 2022-08-12
  • William Roth

    William Roth - 2022-08-12

    Timer1 is a 16-bit timer, meaning it will overflow after 65535 pulses. You are wanting to count ~7,000,000 pulses over a time of ~1 second, so you are counting overflows and adding remainders and such. This is not an ideal method given the capability of the chip.

    I would suggest you open the datasheet to Chapter 27 (Page 398) and familiarize yourself with the "Signal Measurement Timer". This is a 24-bit Timer that can count up to 16,777,215 pulses and has several modes of operation. I suggest you use the "Gated Counter Mode" Where the 1Hz pulse gates the timer on/off. The timer automatically starts when the "gate" goes high and a result is returned when the gate goes low. An interrupt can be set to trigger when the count is done

    If after studying the SMT section of the datasheet and trying it out as best you can, and if you are still lost, let us know and more information can be provided.

    William

     
    • Jeff Weinmann

      Jeff Weinmann - 2022-08-13

      Thank you for your kind assistance!

      I've read up on chapter 27 and I've gotten a better (not complete) understanding of how to use the SMT.

      Here is the state of the code below. I've added the SMT signal and window input pins via the PPS tool, and tried to document what I think I know.

      I'm pretty sure I set the mode to be 'Gated Counter'.

      The code runs but I get a bunch of 0's then some numbers. but I do see the numbers change when a GPS pulse does occur. I'm not sure how to set the interrupt so I have a loop until for now.

      I think the bones are there, I just need a little push.

      Jeff

        #startup InitPPS, 85
          #define PPSToolPart 18f16q40
      
          Sub InitPPS
      
                  'Module: I2C1
                  RB6PPS = 0x0021    'SCL1 > RB6
                  I2C1SCLPPS = 0x000E    'RB6 > SCL1 (bi-directional)
                  RB4PPS = 0x0022    'SDA1 > RB4
                  I2C1SDAPPS = 0x000C    'RB4 > SDA1 (bi-directional)
      
                  'Module: SMT1
                  SMT1SIGPPS = 0x0014    'RC4 > SMT1SIG
                  SMT1WINPPS = 0x0013    'RC3 > SMT1WIN
                  DIR PortC.4 In    'Si5351a Clock input
                  Dir PortC.3 In    'PPS from GPS
      
      
                  'Module: UART1
                  RC6PPS = 0x0010    'TX1 > RC6
                  U1RXPPS = 0x0017    'RC7 > RX1
                  'Module: UART2
                  RC0PPS = 0x0013    'TX2 > RC0
                  U2RXPPS = 0x0011    'RC1 > RX2
      
                   'Module: UART pin directions
                  Dir PORTC.6 Out    ' Make TX1 pin an output
                  Dir PORTC.7 In    ' Make RX1 pin an input
                  Dir PORTC.0 Out    ' Make TX2 pin an output
                  Dir PORTC.1 In    ' Make RX2 pin an input
          End Sub
      
      
      'Signal Measurement Timer Setup
      'SMT1CON0 - Control Register
      'BIT    NAME                            VALUE
      '7      EN    -SMT Enable                 1 = SMT is enabled, 0 = SMT is disabled
      '6      NA
      '5      STP   -SMT Counter Halt Enable    1 = When SMT1TMR = SMT1PR Counter remains at SMT1PR period match interrupt occurs when clocked, 0 = When SMT1TMR = SMT1PR Counter resets to 0x000000
      '4      WPOL  -SMT window input Polarity  1 = window input is active low/falling edge enabled, 0 = windo input is active high/rising edge enabled
      '3      SPOL  -SMT Signal Input Polarity  1 = SMT_signal input is active-low/falling edge enabled, 0 = rising edge enabled
      '2      CPOL  -SMT Clock Input Polarity   1 = SMT1TMR increments on falling edge of selected clock signal, 0 = increments on rising edge of clock signal
      '1      PS    - SMT Prescale Select       1 1:8   1 1:4  0 1:2  0 1:1
      '0      PS    - SMT Prescale Select       1       0      1      0
      
      'Enable SMT
      SMT1CON0.7 = 1
      
      
      
      'SMT1CON1 - 2nd Control Register
      'BIT    NAME                            VALUE
      '7      GO    -SMT GO Data Aquisition     1 = Incrementing/Enabled, 0 = Incrementing,Disabled
      '6      REPEAT-SMT Repeat Acquisiton      1 = Repeat Data Aquisition Enabled, 0 = Aquisition Disabled
      '5      NA
      '4      NA
      '3      MODE  -SMT Operation Mode Select  1 Windowed Counter  1 Gated Counter 1 Counter 0 Time of Flight  0 Gated Window Measurement  0 Windowed Measurement ....etc
      '2      MODE  -SMT Operation Mode Select  0                   0               0         1                 1                           1
      '1      MODE  -SMT Operation Mode Select  1                   0               0         1                 0                           0
      '0      MODE  -SMT Operation Mode Select  0                   1               0         0                 1                           0
      
      'Select Gated Counter Mode
      SMT1CON1.3 = 1
      SMT1CON1.2 = 0
      SMT1CON1.1 = 0
      SMT1CON1.0 = 1
      
      'Stop Counting for now
      SMT1CON1.7 = 0
      
      'I'm not using the clock? taking default o FOSC/4
      SMT1CLK = 0
      
      'SMT Window Signal Selection - I'm pretty sure I'm taking the default of 0=SMT1WINPPS or the GPS 1PPS Signal on PORTC.3
      SMT1WIN = 0
      
      'SMT Signal Selection - I'm pretty sure I'm taking the default of 0=SMG1SIG or the 7Mhz signal on PORTC.4
      SMT1SIG = 0
      
      'SMT Timer Register
      SMT1TMR = 0
      
      
      
      
      
      MainLoop:
      
      'The SMTxTMR register is the 24-bit counter/timer used for measurement in each of the modes of the SMT. Setting
      'the RST bit clears the SMTxTMR register to 0x000000. It can be written to and read by software. It is not guarded for
      'atomic access, therefore reads and writes to the SMTxTMR register must be made only when GO = 0.
      SMT1TMR = 0
      
      'The counter can be prevented from resetting at the end of the timer period by using the STP bit. When STP = 1,
      'the SMTxTMR will stop and remain equal to the SMTxPR register. When STP = 0, the SMTxTMR register resets to
      '0x000000 at the end of the period.
       STP1 = 1
      
      
      
        Do Forever
      
              'Setting the RST bit clears the SMT1TMR Register to 0
              SMT1TMR = 0
              'The counter can be prevented from resetting at the end of the timer period by using the STP bit. When STP = 1,
              'the SMTxTMR will stop and remain equal to the SMTxPR register.
              STP = 1
              SMT1GO = 1
      
              'Go Status: Timer run status is indicated by the TS bit. The TS bit is delayed in time by synchronizer delays in
              'non-counter modes.
              Do Until TS = 0
                'I'm not sure how to set the Interrupt for SMT.  If you can help in this area much appreciated.
      
                'Print out value of SMT1Timer
                comport=2
                HSerPrint str32(SMT1TMR),2
                HSerSend 13,2
                HSerSend 10,2
                comport=1
      
              Loop
        Loop
      
       

      Last edit: Jeff Weinmann 2022-08-13
  • Chris Roper

    Chris Roper - 2022-08-12

    You may also find Bresenham's Algorithm useful.
    Here is a goods explanation and example code, but not in GCBASIC so you would need to adapt the algorithm.

    https://www.romanblack.com/one_sec.htm

    Cheers
    Chris

     
  • Jeff Weinmann

    Jeff Weinmann - 2022-08-14

    I decided to refer to and older project where I did something very similar using Timer1. I'm satisfied enough with the results and I'm only 2 to 3 Hertz off the measured frequencies with my scope and commercial frequency counter.

    Method:

    1) Set the frequency to be measured to 2Mhz
    2) Count the frequency using the below code
    3) Take the difference between measured and actual
    4) Apply a scale factor by taking desired frequency / 2Mhz

    Example: 14Mhz / 2 Mhz is a scale factor of 7 so if my difference in frequency at 2Mhz is 27, My difference I will apply at 14Mhz is : 189. I do have to pay attention whether the difference is positive or negative

    Here is what I did in code:

    ~~~
    startup InitPPS, 85
    define PPSToolPart 18f16q40

    Sub InitPPS
    
            'Module: I2C1
            RB6PPS = 0x0021    'SCL1 > RB6
            I2C1SCLPPS = 0x000E    'RB6 > SCL1 (bi-directional)
            RB4PPS = 0x0022    'SDA1 > RB4
            I2C1SDAPPS = 0x000C    'RB4 > SDA1 (bi-directional)
    
            'Module: SMT1
            'SMT1SIGPPS = 0x0014    'RC4 > SMT1SIG
            'SMT1WINPPS = 0x0013    'RC3 > SMT1WIN
    
            'Module: TMR1
            T1CKIPPS = 0x0014    'RC4 > T1CKI
    
            'Module: UART1
            RC6PPS = 0x0010    'TX1 > RC6
            U1RXPPS = 0x0017    'RC7 > RX1
            'Module: UART2
            RC0PPS = 0x0013    'TX2 > RC0
            U2RXPPS = 0x0011    'RC1 > RX2
    
    
            'Module: UART pin directions
            Dir PORTC.6 Out    ' Make TX1 pin an output
            Dir PORTC.7 In    ' Make RX1 pin an input
            Dir PORTC.0 Out    ' Make TX2 pin an output
            Dir PORTC.1 In    ' Make RX2 pin an input
            DIR PortC.4 In    'Si5351a Clock input
            Dir PortC.3 In    'PPS from GPS
    End Sub
    

    ;Setup Timer1 for frequency counter
    InitTimer1 Ext, PS1_1
    On Interrupt Timer1Overflow Call IncCounter

    Offset = 0

    Do Forever

        ClearTimer 1
        FrequencyCount = 0
        Wait Until PORTC.3 = 1 'GPS Pulse on
        StartTimer 1
    
        Wait Until PORTC.3 = 0 'GPS Pulse off
        Wait Until PORTC.3 = 1 'GPS Pulse on
    
        StopTimer 1
    
        FrequencyCount = FrequencyCount + Timer1
    
        'The difference in frequency when compared to a frequency counter is spot on.
        'Divide the Target frequency by 2 Mhz and the frequency deviation is close enough!
    
        'Avoid Negative Number
        if FrequencyCount > 2000000 then
          TempLong = FrequencyCount - 2000000
          Offset = CW_Frequency / 2000000  * TempLong
          Offset = Offset * -1
        else if FrequencyCount = 2000000 then
          Offset = 0
        else
          TempLong = 2000000 - FrequencyCount
          Offset = CW_Frequency / 2000000  * TempLong
        end if
    
    
        TempString = str32(FrequencyCount)
    
        comport=2
        HSerPrint "Frequency Count = ", 2
        HSerPrint TempString, 2
        HSerPrint " Deviation = " + StrInteger(Offset), 2
        HSerSend 13,2
        HSerSend 10,2
        comport=1
    

    EndLoop:
    Loop

    Sub IncCounter
    FrequencyCount = FrequencyCount + 65536
    End sub

    ~~~

     

    Last edit: Jeff Weinmann 2022-08-14
    • Anobium

      Anobium - 2022-08-14

      You make it look easy. Well done.

      Can you the program? the code above does not compile. I just tried. Vars are missing, and other key things. Thank you.

       
      • Jeff Weinmann

        Jeff Weinmann - 2022-08-14

        This compiles, but you will need a GPS with PPS out and signal source of 2Mhz:

        #CHIP PIC18F16Q40
        #CONFIG LVP=ON
        #option explicit
        
        #Include <SMT_Timers.h>
        
        #startup InitPPS, 85
        #define PPSToolPart 18f16q40
        
        Sub InitPPS
            'Module: I2C1
            RB6PPS = 0x0021    'SCL1 > RB6
            I2C1SCLPPS = 0x000E    'RB6 > SCL1 (bi-directional)
            RB4PPS = 0x0022    'SDA1 > RB4
            I2C1SDAPPS = 0x000C    'RB4 > SDA1 (bi-directional)
        
            'Module: TMR1
            T1CKIPPS = 0x0014    'RC4 > T1CKI
        
            'Module: UART1
            RC6PPS = 0x0010    'TX1 > RC6
            U1RXPPS = 0x0017    'RC7 > RX1
            'Module: UART2
            RC0PPS = 0x0013    'TX2 > RC0
            U2RXPPS = 0x0011    'RC1 > RX2
        
        
            'Module: UART pin directions
            Dir PORTC.6 Out    ' Make TX1 pin an output
            Dir PORTC.7 In    ' Make RX1 pin an input
            Dir PORTC.0 Out   ' Make TX2 pin an output
            Dir PORTC.1 In    ' Make RX2 pin an input
            DIR PortC.4 In    '2Mhz Frequency input
            Dir PortC.3 In    'PPS from GPS
        End Sub
        
        #Define LED PORTB.7
        Dir LED Out       'LED PORTB.7
        
        'USART settings for UART1 and UART2
        #define USART_BAUD_RATE 9600
        #define USART_BLOCKING
        #define USART_TX_BLOCKING
        
        #define USART2_BAUD_RATE 9600
        '#define USART2_BLOCKING
        '#define USART2_TX_BLOCKING
        '#define USART_DELAY OFF
        
        Dim TempString as string
        Dim TempLong as Long
        Dim TimerValue as Word
        Dim FrequencyCount as Long
        Dim FrequencyLow as Long
        Dim Offset as Integer              'Frequency Offset from Calibration
        
        Dim TargetFrequency as Long   'The frequency to apply the offset to
        
        
        'Setup Timer1 for frequency counter
        InitTimer1 Ext, PS1_1
        
        'Interrupt routine
        On Interrupt Timer1Overflow Call IncCounter
        
        
        
        TargetFrequency = 7000000     'Target Frequency to be addjusted
        Offset = 0
        
        
        
        MainLoop:
          Do Forever
                '*** This Program wont do anything unless there is a GPS MODULE WITH A FIX AND PULSING ****
                'This program will need:
                '1)A GPS Pulse Per Second Output Attached to PORTC.3 pin
                '2)A not quite accurate input signal of 2Mhz - this will be compared to what the Timer1 Counter + the GPS Gate comes up with
                '3)Terminal info sent out on COM2 (PORTC.0 and PORTC.1)
        
                ClearTimer 1
                FrequencyCount = 0
                Wait Until PORTC.3 = 1 'GPS Pulse on
                StartTimer 1
        
                Wait Until PORTC.3 = 0 'GPS Pulse off - we have to look for this GPS ON/OFF sequence to proceed
                Wait Until PORTC.3 = 1 'GPS Pulse on - The Second Pulse gives us our 1 second window or gate.
                                       'If the GPS misses a pulse the reading is inaccuate.
                StopTimer 1
        
                FrequencyCount = FrequencyCount + Timer1
        
                'The difference in frequency when compared to a frequency counter is spot on.
                'Divide the Target frequency by 2 Mhz and the frequency deviation is close enough!
        
                'Avoid Negative Number
                if FrequencyCount > 2000000 then
                  TempLong = FrequencyCount - 2000000
                  Offset = TargetFrequency / 2000000  * TempLong
                  Offset = Offset * -1
                else if FrequencyCount = 2000000 then
                  Offset = 0
                else
                  TempLong = 2000000 - FrequencyCount
                  Offset = TargetFrequency / 2000000  * TempLong
                end if
        
        
                TempString = str32(FrequencyCount)
        
                comport=2
                HSerPrint "Frequency Count = ", 2
                HSerPrint TempString, 2
                HSerPrint " Offset = " + StrInteger(Offset), 2
                HSerSend 13,2
                HSerSend 10,2
                comport=1
        
                'Wait aprox 1/2 second between pulses to capture next one
                Wait 500 ms
        Loop
        
        
        
        'Interrupt Routine
        Sub IncCounter
                FrequencyCount = FrequencyCount + 65536
        End sub
        
         
  • Anobium

    Anobium - 2022-08-15

    Thank you. I just compiled in the latest/updated compiler. All was good.

    Nice piece of code.

    Consider adding the following to optimise your code. This will

    #DEFINE USE_TIMER0 FALSE
    #DEFINE USE_TIMER1 TRUE
    #DEFINE USE_TIMER2 FALSE
    #DEFINE USE_TIMER3 FALSE
    #DEFINE USE_TIMER4 FALSE
    

    This will improve overall program performance and make the code a bit smaller.

    Evan

     
    • Jeff Weinmann

      Jeff Weinmann - 2022-08-15

      Thank you for all the videos that are specific to this chip family! makes it much easier when you repetitively demonstrate through your videos the setup of these things.

      I'm a bit weary of trying to find a chip that will suit my needs (and is available!). I'm downsizing from the 40 pin monsters. I have just enough, with 20 pins. And the smaller size allows me to go back to old school DIP chips allowing for quick swap out.

      Maybe someday I'll go back to a SMT PIC, but It will definitely be this chip in an SOIC package.

      thanks again,

      Jeff

       
      • Anobium

        Anobium - 2022-08-15

        Pleasure!

         
  • William Roth

    William Roth - 2022-08-16

    I went ahead a setup a PIC18F16Q41 to demonstrate how the Signal Measurement Timer (SMT) can be used in this case. I used a PIC18F27Q43 to emulate the GPS 7MHz signal using its Numerically Controlled Oscillator(NCO) and to supply the 1 second pulse. I put a switch on the 18F27Q43 that when pressed "gates" the SMT on the PIC18F26Q41,

    Here is the demo code:

     #CHIP 18F16Q41, 4
     #CONFIG LVP = ON
     #CONFIG MCLRE = ON
    
     #OPTION EXPLICIT
    
     #STARTUP InitPPS, 85
    
     #DEFINE USART_BAUD_RATE 9600
     #DEFINE USART_TX_BLOCKING
    
     Wait 400 ms
     Hsersend 12   'clear terminal (Using CoolTerm as Terminal)
     Wait 100 ms
     Hserprint "Starting Counter Test" : HSerprintCRLF 2
    '===========================================================
    
    Dir PORTC.3 IN    ' 7.0 MHz Input  ( External 7 MHz Clock)
    Dir PORTC.1 IN    ' SMT Gate Input (1 sec signal)
    
    Dim DUMMY as Byte : Dummy = 0
    Dim PulseCount Alias DUMMY,SMT1TMRU,SMT1TMRH,SMT1TMRL AS LONG
    
    'Gated Counter Single Acquisition Mode
    'Acquisition Starts when 1 s Gate goes high
    'Acqisition Stops when 1 s Gate goes low and triggers Interrupt
    'Counts pulses on PortC.3 for 1 sec
     SMT1CON1 = 0b00001001  'Set Mode to Gated counter
     SMT1CON0_EN = 1        'Enable SMT Peripheral
     SMT1GO = 1             'Ready for 1 s Gate on C.1
    
    'Interrupt 1 sec data acquisition completes
    On INterrupt SMT1PulseWidthAcquired Call ShowPulseCount
    
    'Main Loop
    Do
        'Waiting for interrupt
    loop
    
       '==================  Subs & Functions==========================
    Sub ShowPulseCount
           HSerprint PulseCount : HSerprintCRLF
           PulseCount = 0 ' Clear SMT1 TIMER/Counter
           SMT1GO = 1     ' Enable Next Acquisition
    End SUB
    
    Sub InitPPS
            'Module: SMT1
            SMT1SIGPPS = 0x000F    'RB7 > SMT1SIG
            SMT1WINPPS = 0x0016    'RC6 > SMT1WIN
    
            'Module: UART pin directions
            Dir PORTB.4 Out    ' Make TX1 pin an output
            'Module: UART1
            RB4PPS = 0x0010    'TX1 > RB4
    End Sub
    '=====================================================================
    

    Enjoy

    William

     

    Last edit: William Roth 2022-08-16
    • Jeff Weinmann

      Jeff Weinmann - 2022-08-16

      William,

      Very nice! I will be testing out today. I understood most of the code and the one brick wall that was stopping me from moving forward with SMT was this line you wrote:

      On INterrupt SMT1PulseWidthAcquired Call ShowPulseCount

      The actual Interrupt name of 'SMT1PulseWidthAquired'. I had no idea where to look for that.

      SMT is definitely the way to go as I may have to sample frequencies as high as 50Mhz (the 6 meter Ham band) .

      Another question: I dont see an #include smt_timers.h in the code. Is it picking up the reserved words automatically?

      I will let you know how the implementation goes. What an amazing little chip the Q line is.

      Thanks again for your help,

      Jeff

       
  • William Roth

    William Roth - 2022-08-16

    Hi Jeff

    I did not include smt_timers.h because that library does not support Gated Counter Mode and was therefore not needed. I set all the registers manually and created the necessary Long Variable as an alias.

    You can find the interrupts by opening the PicInfo Tool then look at the interrupts tab. In this case you would have also needed to look at the datasheet to determine which of the two to use.

    As far as counting pulses at 50 MHz I am not sure if the SMT can handle that speed. My signal generator is packed away in the closet and not accessible right now. You may need to divide the 50Mhz signal by 2, 4, or 8 first. But please when you try that let us know how it works.

    As far as the 18FQ chips go, these have nearly every peripheral you might need and are generally less expensive than the older PICs.

    Note that I used 4MHz as the Chip Speed. However the code will work at 8,16,32,or 64 MHz with no other changes required to the code.

    William

     

    Last edit: William Roth 2022-08-16
  • Anobium

    Anobium - 2022-08-16

    Bill, post the q43 - this looks like a good demo to put in GitHub.

     
  • William Roth

    William Roth - 2022-08-16

    Here is the 18F27Q43 Code that was used to generate the 7 MHz signal and the 1 second gate. It is nothing special. The NCO is great for generating odd & precise frequencies.

     #CHIP 18F27Q43, 32
     #CONFIG LVP = ON
     #CONFIG MCLRE = ON
     #startup InitPPS, 85
     #OPTION EXPLICIT
    
     Wait 400 ms   ;stabilize
    
     #DEFINE Gate PortC.6
     DIR PORTC.6 OUT
    
     #DEFINE SWITCH PORTC.3
     Dir PORTC.3 IN
    
     Dim Dummy : Dummy = 0
     DIM NCO1_INC Alias Dummy, NCO1INCU,NCO1INCH, NCO1INCL as LONG
    
     NCO1_INC = 457988     'Equates to 7 Mhz ( adjust as needed)
     NCO1CLK = 0b00000000  'Default  (FOSC)
     NCO1CON.7 = 1         'Start NCO Oscillator
    
     Do
           Wait Until Switch = ON
           Set Gate On
           Wait 1001700 us  'precice 1 second delay per scope
           Set Gate Off
     Loop
    
    '==================  Subs & Functions==========================
     Sub InitPPS
    
         'Module: NCO1
         RC4PPS = 0x003F    'NCO1 > RC4
         Dir PortC.4 Out
    
    
     End Sub
    '=====================================================================
    
     

    Last edit: William Roth 2022-08-16
  • William Roth

    William Roth - 2022-08-16

    Attached is a crude schematic of the test setup.

     
    • Jeff Weinmann

      Jeff Weinmann - 2022-08-16

      Nice simulation.

      One thing I did notice when counting on my end is that I'm losing the last digit of the Pulse count. So in the interrupt, I printed the Upper, High and Low bytes of the SMT count:

      'Interrupt routine
      Sub ShowPulseCount
             comport = 2
             HSerprint PulseCount,2
             'HSerPrint SMT1TMRL,2
             'HSerPrint SMT1TMRU,2
             'HSerPrint SMT1TMRH,2
             HSerprintCRLF,2
             comport = 1
      
      
             PulseCount = 0 ' Clear SMT1 TIMER/Counter
             SMT1GO = 1     ' Enable Next Acquisition
      End SUB
      

      These are the results I get:

      L = 56
      H = 704056190
      U = 70405610
      Pulsecount = 704056 < missing the last digit

      FYI, I'm using a Northern Software programmer and its UART connection. Strange. I don't see why the last digit in the count is not showing. I tried:

      Tempstring = str32(Pulsecount)

      and its still just 6 digits.

      Northern software has a command prompt utility called 'nsuart' that I can monitor the traffic (see attached)

      Really weird.

      Also I'm not quite sure how the variables Pulsecount is dimensioned:

      Dim DUMMY as Byte : Dummy = 0
      Dim PulseCount Alias DUMMY,SMT1TMRU,SMT1TMRH,SMT1TMRL AS LONG
      

      this suggested to me that PulseCount is dimensioned as a Byte since Dummy is a Byte?

      Jeff

       

      Last edit: Jeff Weinmann 2022-08-16
  • William Roth

    William Roth - 2022-08-17

    Hi Jeff

    PulseCount is dimensioned as a "Long" Variable. A long is 32 bits with each of the 4 bytes in the list being 8 bits. Dummy is a place holder for the "extended" byte. It must be zero. The other bytes of PulseCount are aliased to the SMT1TMRU/H/L registers. These three bytes make up the 24-bit timer counter variable called "PulseCount". You can read up about Variables and Aliasing in the GCB help. Open the Help ===> Variable operations ===> Dim

    Your print out of the individual bytes suggests that something is likely amiss in your program. However, it could be a serial or terminal issue . The maximum value of each of the bytes that make up "PulseCount" is 255. yet you are showing values that are inconsitent with byte values. The test program I posted works correcty here.

    We will need to see your complete GCB program that is failing, as well as the ASM to see what's going on.

    In the mean time for testing and debug purposes you may want to try a different Terminal Application. You may also want to try using TX1 instead of TX2 to see if that makes any difference but I doubt it will.

    William

     
    • Jeff Weinmann

      Jeff Weinmann - 2022-08-17

      William,

      I changed the value of PulseCount:

      'Interrupt routine
      Sub ShowPulseCount
             comport = 2
      
             'Manually change Pulsecount to a value I'm expecting
             PulseCount = 7040123
      
             HSerprint PulseCount,2
             HSerPrintCRLF,2
             comport = 1
             PulseCount = 0 ' Clear SMT1 TIMER/Counter
             SMT1GO = 1     ' Enable Next Acquisition
      End SUB
      

      The value of 7040123 went through the UART2 without a problem.
      I changed the PulseCount back to the SMTValues and the return goes back to 6 digits.

      attached is the entire program with all the extra GPS and Si5351 (clock gen) stuff in it, but your interrupt and variables are used for deriving the PulseCount.

      Thanks and feel free to markup my code!

      Jeff

       

      Last edit: Jeff Weinmann 2022-08-17
  • William Roth

    William Roth - 2022-08-18

    I cannot debug this due to the complexity of the code and the fact that I do not have the gps module or the si clock device.

    My suggestion is to strip the code down to a bare minimum where the GPS is providing a consistent frequency and the clock is providing the 1 sec gate signal. Then Test. This means
    removing everything not related to providing a 7 MHz clock and a 1 sec gate.
    When you get this working start adding back sections of code one at a time until it fails. This is a standard/ troubleshoooting method.

    When a Long variable is defined:

        Dim MyLongvar as Long
    

    There is absolutely no need to define the bytes that make up the variable. The compiler does this automatically. I am not sure how this will affect memory allocation. So let the compiler assign the bytes for the Long Variable. See your variable "MS0P1 " and others.

          *** Dont do this ! *** 
      Dim MyLongVar as Long     ;Ok
      Dim MyLongVar_E           ; Not recommended !
       Dim MyLongVar_U           ; Not recommended !
       Dim MyLongVar_H           ; Not recommended !
    

    If you want to work with the individual bytes in a Long Variable one trick is to us Aliasing and dim the individual bytes like this.

    Dim  LV_ExtByte LV_UpByte,  LV_HiByte,  LV_LoByte as Byte  
    DIM LongVar as LONG Alias LV_ExtByte,  LV_UpByte,  LV_HiByte,  LV_LoByte
    LongVar = 0  ' initalize variable to assure it is allocated in ASM
    

    Do not use _E , _U or _H in byte variable names as these are reserved

    Single letter variables are not recommended:
    Suggest you cange "I" to "II" or something else like "index". Meaningful variable names are preferred, especially if others will be working with the code.

    You have dimmed "I" as Long variable. I cannot see in your code where I will ever be greater than 65535 but I could have missed something. Use a Word instead to save memory unless indeed "I" could be greater than 65535.

    Also, by not specifically providing a clock speed with #Chip the speed defaults to the chips maximum of 64Mhz. Is this really what you want? I would suggest slowing it down a bit for development. Then if you really need 64Mhz you can change it.

    #chip 18F16Q40, 32
    

    William

     

    Last edit: William Roth 2022-08-18
    • Jeff Weinmann

      Jeff Weinmann - 2022-08-18

      William,

      Thanks for taking a look at it.

      I've tried several other frequency bands and the last digit truncation is consistent If I simply multiply the result I'm getting by 10 I'm accurate to within 10 Hertz, which is completely fine for my project. I will circle back to this as the workaround will for now get me answers that are close enough.

      Thanks for taking a look

       
    • Jeff Weinmann

      Jeff Weinmann - 2022-08-19

      Looking at the pulsecount issue a little further I gathered what I believe are the correct values coming back from the counter gate:

      SMT1TMRU: Accesses the upper byte TMR[23:16] ==> 21 decimal
      SMT1TMRH: Accesses the high byte TMR[15:8] ==> 130 decimal
      SMT1TMRL: Accesses the low byte TMR[7:0] ==> 174 decimal

      'I also checked the capture values and they are exactly the same as above
      SMTxCPRU: Accesses the upper byte CPR[23:16]
      SMTxCPRH: Accesses the high byte CPR[15:8]
      SMTxCPRL: Accesses the low byte CPR[7:0]

      Converting to binary and combining bytes to get [23:0]:

      <----21---> <--130---> <--174--->
      0001 0101 1000 0010 1010 1110

      The decimal value for the above is:

      1,409,710 which is off by a factor of 10:

      It should be 14,097,100

      If the DUMMY is always zero it shouldn't affect the answer [31:24]

      Both my scope and frequency counter are counting close to 14,097,100 so that frequency is real.

      Is there some type of resolution issue possibly with the chip or GCB config issue with PIC18F16Q40? I guess I could get a hold of the chip that you are testing with to see if I get the same result.

      Just trying to look a little deeper.

      Jeff

       

      Last edit: Jeff Weinmann 2022-08-19
  • William Roth

    William Roth - 2022-08-19

    I am using a PIC18F16Q41 which has the exact same SMT peripheral as your 18F16Q40 so I would not think there is any value in changing chips. Evan and I discussed this and I will be doing some further testing using your code , but injecting the 7Mhz clock and the 1 sec gate from an external source.

    However your main loop code calls a subroutine called "get_val" that uses "HserRecieve", which has been defined as a blocking command. This means that program flow will hang there if no serial data is received. I have no clue what that serial data is or where is comes from so it is difficult to emulate. I could also inject serial data if I knew what the program is expecting.
    Lets see what I can come up with over the weekend as I want to see what happens when the interrupt occurs while waiting on or processing serial data via HserReceive.

    Edit: I now see that it is looking for $GPGGA before moving on to start counting commas and other stuff. So I think I can injsct serial data to fake it out, at least for a while.

    Can you please post screen shots from your scope of the 7Mhz signal and the 1 sec pulse?

    William

     

    Last edit: William Roth 2022-08-19
    • Jeff Weinmann

      Jeff Weinmann - 2022-08-20

      Yes get_val is looking for NMEA from the GPS module. This is a constant stream of data coming out of the module, sending data out once per second basically the whole do forever loop is counting on this. you can basically remark out the entire Do forever loop as its parsing GPS data (GPS TIME, Status, GPS Location) continuously.

      TX_OFF() and TX_ON() just turn my7Mhz clock source off and on they can be remmed out too

      All the EPreads are not of consequence either i dont think.

      Attached is my Dev board FYI

      Jeff

       

      Last edit: Jeff Weinmann 2022-08-20
  • William Roth

    William Roth - 2022-08-20

    Hi Jeff,

    I have found what I think to be a bug in the USART.h library that is likely causing this issue.

    It appears that there is a system variable conflict when USART1 and USART2 are both used in a program. I have not yet dug deep into the USART.h library so I have no definite answer/resolution.

    This bug only appears when 2 (or more) USARTs are used in a program. It affects WORD and INTEGER variables and likely LONG Variables.

    I will be writing up a bug report and sending it to the boss after I get some sleep.

    William

     

    Last edit: William Roth 2022-08-20
1 2 > >> (Page 1 of 2)

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.