Menu

SMT timer example how is period calculated.

2026-01-30
2026-01-30
  • Roger Jönsson

    Roger Jönsson - 2026-01-30

    In this example at: https://gcbasic.sourceforge.io/help/_smt_timers.html

    How do one arrive at 1.000s and 4.600s (with the 32MHz clock)?

    BTW the second SETSMT1PERIOD should be SETSMT2PERIOD?

      #Chip 16F18855, 32
        #option explicit
        #Include <SMT_Timers.h>
        #config CLKOUTEN_ON
    
        ...
    
        SETSMT1PERIOD ( 4045000 )        ' 1.000s period with the parameters of SMT_FOSC and SMTPres_1 within the clock variance of the interclock
                                          ' a perfect internal clock would be 4000000
    
         SETSMT1PERIOD ( 9322401 )        ' 4.600s period with the parameters of SMT_FOSC4 and SMTPres_8
    
         InitSMT1(SMT_FOSC,SMTPres_1)
         InitSMT2(SMT_FOSC4,SMTPres_8)
    
         ...
    
     
  • Anobium

    Anobium - 2026-01-30

    Is the question 'how to do the SMT calcs'?

    I will correct the Help.


     
  • Roger Jönsson

    Roger Jönsson - 2026-01-30

    Yes. While trying to figure it out I stalled at:

    If
    InitSMT1(SMT_FOSC,SMTPres_1) and SETSMT1PERIOD ( 4045000 ) -> 1s period
    How can
    InitSMT2(SMT_FOSC4,SMTPres_8) and SETSMT2PERIOD ( 9322401 ) -> 4,6s period

    The code was at some point changed from doing something else than just blinking LEDD2 and LEDD3?

     
  • Anobium

    Anobium - 2026-01-30

    Bill Roth was the expert on SMT. He passed away last year. :-(


    The most relevant application note / technical brief for it is TB3129 – "Signal Measurement Timer on PIC MCUs".

    Direct PDF URL:
    https://ww1.microchip.com/downloads/en/appnotes/90003129a.pdf

    This document explains the SMT module's features, configuration, modes (like period/duty cycle measurement, time-of-flight, etc.), and code examples.

    If you're looking for something more specific (e.g., auto-calibration using SMT in AN2030):
    https://ww1.microchip.com/downloads/en/Appnotes/00002030A.pdf

     
  • Anobium

    Anobium - 2026-01-30

    Looking at the GCBASIC demos by BillR, the timer calculation is based on creating a 1-second interrupt interval using the SMT1 (Signal Measurement Timer) module.

    '''--------------------------------------------------------------------------------------------------------------------------------
    '''A Debug Program for SMTTimers.h
    ''' WilliamR
    '
     #chip 16f18855, 32
     #option explicit
    
     #include <smt_timers.h>
    
     WAIT 500 MS
    
    
      DIR PortC.3 OUT 'LED
    
    
     'Tune internal OSC for best accuracy so
     'that 1,000,000 timer ticks = 1,000,000 us
     OSCTUNE = 0b11111100
    
     'FOSC4 = 8MHz / 8 =  1MHz
      InitSMT1(SMT_FOSC4,SMTPres_8)  '1 MHz
    
     'Period = 1,000,000 microseconds (1 Second)
     SETSMT1PERIOD(1000391)  'Fine tune here as necessary
    
     'Interrupt every second and  blink LED for 100 ms
     On Interrupt SMT1Overflow Call BlinkLED
    
     'Start the 24-bit SMT1 timer
     STARTSMT1
    
    '// After making changes,  Chip must run for at least
    '// 1 minute after POR or Reset before an accuraate measurement
    '// can be taken. This Particular chip seems to slowing increase in
    '// speed over the first 30 sec to 1 minute
    
    MAIN:
    
      Do
    
      '// waiting for interrupt...
    
      Loop
    
    ENDMAIN:
    
    
    Sub BlinkLED
       Set PORTC.3 On
       Wait 100 ms
       Set PortC.3 Off
    End sub
    

    Here's my breakdown:

    Timer Calculation Basis

    Clock Source Configuration:
    - Main oscillator: 32 MHz (from #chip 16f18855, 32)
    - Timer uses FOSC/4 = 32MHz / 4 = 8 MHz
    - Prescaler divides by 8: 8 MHz / 8 = 1 MHz timer clock

    Timer Tick Rate:
    - At 1 MHz, each timer tick = 1 microsecond
    - For a 1-second period, you'd theoretically need 1,000,000 ticks

    The Key Value:

    SETSMT1PERIOD(1000391)  'Fine tune here as necessary
    

    This sets the timer to count 1,000,391 ticks instead of 1,000,000. The extra 391 ticks (0.0391% adjustment) compensates for:

    1. Internal oscillator inaccuracy - The PIC's internal oscillator isn't perfectly 32 MHz
    2. OSCTUNE adjustment - The code sets OSCTUNE = 0b11111100 to fine-tune the oscillator frequency
    3. Temperature/voltage drift - As noted in the comments, the chip's speed changes over the first 30-60 seconds after power-on

    Summary

    The timer is configured to tick at exactly 1 MHz (1 tick per microsecond), and the period value of 1,000,391 is empirically tuned to achieve an accurate 1-second interrupt interval despite internal oscillator variations. The developer likely measured the actual timing and adjusted this value until the LED blinked precisely once per second.

     
  • Anobium

    Anobium - 2026-01-30

    My analysis of Bill's other demo.

    '''--------------------------------------------------------------------------------------------------------------------------------
    '''A Debug Program for SMTTimers.h
    ''' WilliamR
    '
     #chip 16f18855, 32
     #option explicit
     #include <smt_timers.h>
    
     WAIT 500 MS
    
     DIR PortC.3 OUT 'LED
    
    
     'Tune internal OSC for best accuracy so
     'that 1,000,000 timer ticks = 1,000,000 us
     OSCTUNE = 0b11111100
    
    
      InitSMT1(SMT_FOSC,SMTPres_1)  '1 MHz
     'Period = 1,000,000 microseconds (1 Second)
     SETSMT1PERIOD(16000000)  'Fine tune here as necessary
    
     'Interrupt every second and  blink LED for 100 ms
     On Interrupt SMT1Overflow Call BlinkLED
    
     'Start the 24-bit SMT1 timer
     STARTSMT1
    
    '// After making changes,  Chip must run for at least
    '// 1 minute after POR or Reset before an accuraate measurement
    '// can be taken. This Particular chip seems to slowing increase in
    '// speed over the first 30 sec to 1 minute
    
    
    
    
    MAIN:
    
    '''  Pick Your Poison
    '''  Seven Different Ways to get 1 second Period
      Do
         ' 1HZ
          SETSMT1PERIOD(8000000)
          InitSMT1(SMT_FOSC4,SMTPres_1)
          ClearSMT1
          StartSMT1
          Wait 10 s
          StopSMT1
          Wait 2 s
    
          'Also  1 hz
          SETSMT1PERIOD(2000000)
          InitSMT1(SMT_FOSC4,SMTPres_4)
          CLEARSMT1
          StartSMT1
          Wait 10 s
          StopSMT1
          Wait 2 s
    
         ' Also 1 Hz
          SETSMT1PERIOD(1000000)
          InitSMT1(SMT_FOSC4,SMTPres_8)
          ClearSMT1
          StartSMT1
          Wait 10 s
          StopSMT1
          Wait 2 s
    
          ' Also 1 Hz
          SETSMT1PERIOD(4000000)
          InitSMT1(SMT_HFINTOSC,SMTPres_8) '16/2
          ClearSMT1
          StartSMT1
          Wait 10 s
          StopSMT1
          Wait 2 s
    
         ' Also 1 Hz
          SETSMT1PERIOD(500000)
          InitSMT1(SMT_MFINTOSC,SMTPres_1)
          ClearSMT1
          StartSMT1
          Wait 10 s
          StopSMT1
          Wait 2 s
    
    
         ' Also 1 Hz
          SETSMT1PERIOD(31500)
          InitSMT1(SMT_MFINTOSC_16,SMTPres_1)
          ClearSMT1
          StartSMT1
          Wait 10 s
          StopSMT1
          Wait 2 s
    
         ' Also 1 Hz
          SETSMT1PERIOD(31500)
          InitSMT1(SMT_LFINTOSC,SMTPres_1)
          ClearSMT1
          StartSMT1
          Wait 10 s
          StopSMT1
          Wait 2 s
    
      Loop
    
    ENDMAIN:
    
    
    Sub BlinkLED
       Set PORTC.3 On
       Wait 100 ms
       Set PortC.3 Off
    End sub
    

    This code demonstrates seven different timer configurations that all achieve the same 1-second period, using different clock sources and prescaler combinations. Here's the analysis:

    Initial Configuration (unused in main loop)

    InitSMT1(SMT_FOSC,SMTPres_1)
    SETSMT1PERIOD(16000000)
    
    • Clock: FOSC = 32 MHz, no prescaler
    • Period: 16,000,000 ticks = 0.5 seconds (this appears to be a setup artifact, not actually used)

    The Seven "1 Hz" Configurations

    1. FOSC/4, Prescaler 1:1

    SETSMT1PERIOD(8000000)
    InitSMT1(SMT_FOSC4,SMTPres_1)
    
    • Clock: 32 MHz / 4 = 8 MHz
    • Timer rate: 8 MHz (no prescaler)
    • Period: 8,000,000 ticks ÷ 8 MHz = 1 second

    2. FOSC/4, Prescaler 1:4

    SETSMT1PERIOD(2000000)
    InitSMT1(SMT_FOSC4,SMTPres_4)
    
    • Clock: 32 MHz / 4 = 8 MHz
    • Prescaler: ÷4 → 2 MHz
    • Period: 2,000,000 ticks ÷ 2 MHz = 1 second

    3. FOSC/4, Prescaler 1:8

    SETSMT1PERIOD(1000000)
    InitSMT1(SMT_FOSC4,SMTPres_8)
    
    • Clock: 32 MHz / 4 = 8 MHz
    • Prescaler: ÷8 → 1 MHz
    • Period: 1,000,000 ticks ÷ 1 MHz = 1 second

    4. HFINTOSC, Prescaler 1:8

    SETSMT1PERIOD(4000000)
    InitSMT1(SMT_HFINTOSC,SMTPres_8)
    
    • Clock: HFINTOSC = 16 MHz (internal high-frequency oscillator)
    • Prescaler: ÷8 → 2 MHz
    • Comment says "16/2" but it's actually 16÷8=2 MHz
    • Period: 4,000,000 ticks ÷ 2 MHz = 2 seconds (or typo, should be 2,000,000 for 1 sec)

    Note: This appears to have an error - should be 2,000,000 for 1 second.

    5. MFINTOSC, Prescaler 1:1

    SETSMT1PERIOD(500000)
    InitSMT1(SMT_MFINTOSC,SMTPres_1)
    
    • Clock: MFINTOSC = 500 kHz (internal medium-frequency oscillator)
    • Period: 500,000 ticks ÷ 500 kHz = 1 second

    6. MFINTOSC/16, Prescaler 1:1

    SETSMT1PERIOD(31500)
    InitSMT1(SMT_MFINTOSC_16,SMTPres_1)
    
    • Clock: 500 kHz / 16 = 31.25 kHz
    • Period: 31,500 ticks ÷ 31.25 kHz = 1.008 seconds

    Note: Should be 31,250 for exactly 1 second; 31,500 is empirically tuned.

    7. LFINTOSC, Prescaler 1:1

    SETSMT1PERIOD(31500)
    InitSMT1(SMT_LFINTOSC,SMTPres_1)
    
    • Clock: LFINTOSC = 31 kHz (internal low-frequency oscillator, typically ~31.25 kHz)
    • Period: 31,500 ticks ÷ 31.25 kHz ≈ 1.008 seconds

    Note: The 31.5 kHz assumed frequency accounts for typical LFINTOSC variation.


    Summary

    This is a test/calibration program showing multiple ways to achieve ~1 second timing:
    - High-speed sources (FOSC, FOSC/4, HFINTOSC) use large period counts
    - Low-speed sources (LFINTOSC, MFINTOSC) use smaller period counts
    - The empirical tuning (e.g., 31,500 vs theoretical 31,250) compensates for internal oscillator inaccuracies
    - The OSCTUNE setting adjusts the main oscillator for better accuracy
    - Configuration #4 appears to have a calculation error (should be 2,000,000, not 4,000,000)

     
  • Roger Jönsson

    Roger Jönsson - 2026-01-30

    Ouch! :(

    -A moment of silence-

    While you replied I had hooked it up and got it working on 18F57Q84. I should have done that sooner and not kept staring at the code example...
    And yes the code has probably been chopped up and changed. That is why the figures didn't make sense. I could remove #config CLKOUTEN_ON which added to the confusion as I saw no purpose. SMT_FOSC didn't work on this chip while changing to FOSC did.

    This could be the sample clock that I have been looking for. High resolution and no startup procedure for each revolution (like the 16bit clock).

    This works as expected (32000000/4000000/2=4Hz):

     #Chip 18F57q84, 32
    #option explicit
     #Include <SMT_Timers.h>
    
    Dir PORTA.0 OUT
    
    SETSMT1PERIOD ( 4000000 )        ' 0.25s complete on-off period
    InitSMT1(FOSC,SMTPres_1)
    On Interrupt SMT1Overflow Call BlinkLED
    StartSMT1
    
    Do
        '// Waiting for interrupts
    LOOP
    
    Sub BlinkLED
        PORTA.0 = !PORTA.0
    End SUB
    
     

    Last edit: Roger Jönsson 2026-01-30
  • Anobium

    Anobium - 2026-01-30

    It is a great method!!

     
  • Roger Jönsson

    Roger Jönsson - 2026-01-30

    Yes, but I wish I had recorded it. I could have released it as a movie: "Staring at code".

     
    • Anobium

      Anobium - 2026-01-30

      I have seen that movie!! :-)

       

Log in to post a comment.