Low frequency multiplier... Suggestions/info needed.


Closed Thread
Results 1 to 13 of 13
  1. #1
    Join Date
    Jun 2011
    Location
    Tolland, CT, USA
    Posts
    5

    Default Low frequency multiplier... Suggestions/info needed.

    I need to take a variable input frequency (5 volt square waves) from below 10Hz to about 2Khz and multiply it by roughly two. I then need to take the result and sequence it amongst three LEDs. (I.E. LED 1 on with 2 and 3 off, then LED 2 on with 1 and 3 off, then LED 3 on with 1 and 2 off). This process is to repeat constantly and at no time will all LEDs be off (except blanking below 10 Hz if the PIC flips out and can't handle frequencies below 10Hz). With that said, the code needs to be able to be tailored at will to allow for slight variations to be programmed as the ratio isn't always going to be 1:2. It may be 1:2.25 or even 1:1.75. I have been told that the 12F675 will do the job and I have been trying to figure out how to achieve this seemingly impossible feat. I have Picbasic Pro, a PICKIT 2, PICKIT 3 and few assorted PICs. I have to admit that I am a newbie but I have been able to write simple code to sequence the LED's. However, when it comes to the the frequency multiplier I am soooo lost. If anyone could suggest a way to do this and point me in the right direction I would more than appreciate it. Cheers!

  2. #2
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,517


    Did you find this post helpful? Yes | No

    Default Re: Low frequency multiplier... Suggestions/info needed.

    Hi,
    That can be done but I don't think I'd use 12F675. Instead I'd look for a PIC with a CCP-module (which I'd use to measure the frequency) and then an additional timer to generate the "doubled" frequency. I took a quick look and the 12F615/617 could work.

    If the dutycycle of the input signal is 50% you only need to measure half a period (positive or negative) which is easy to do, if it's not 50% it gets a little bit trickier but still very much doable with the CCP module. Get the captured value from the CCP-module, apply your math and load the 'other' timers register with the correct value so that it overflows and generates an interrupt at the correct interval. In the timers inerrupt service routine reload the timer and "step" your pattern.

    I'd definitley use Darrel Taylor's Instant Interrupt routines (because I suck at ASM).

    What kind of resolution are we talking about? The timer used for the CCP module is 16 bits wide, at 4MHz that means it can "measure" up to ~65.5ms (with 1us resolution) which is enough if the duty cycle if the inout signal is 50%. If not you need to use the prescaler which "extends" the measurable time but decreases the resoultion by the same ratio.

    With that said there are always more than one way. Does the frequency need to be updated "immediately" or is it OK to only update it once per "cycle"? One way to do it with the '675 might be to use one of timers to "manually" measure the input frequency (polling the input, starting and stopping the timer manually) and the other to genereate the "new" frequency.

    /Henrik.

  3. #3
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,517


    Did you find this post helpful? Yes | No

    Default Re: Low frequency multiplier... Suggestions/info needed.

    Hello again,
    Although I still think a PIC with a CCP module would be "better" suited I gave the 12F675 a chance and came up with the following idea.
    Code:
     
    '****************************************************************
    '*  Name    : FrequencyScaler.pbp                               *
    '*  Author  : Henrik Olsson                                     *
    '*  Notice  : Copyright (c) 2011 Henrik Olsson                  *
    '*          : No Rights Reserved                                *
    '*  Date    : 2011-06-21                                        *
    '*  Version : 1.0                                               *
    '*  Notes   : Untested, provided as a starting point.           *
    '*          :                                                   *
    '****************************************************************
    ' We need the TMR0 prescaler, therefor it can't be used for the WDT.
    ' Make sure to turn WDT OFF in CONFIGs.
     
    DEFINE NO_CLRWDT 1 
    DEFINE OSC 4                        ' 4Mhx x-tal
     
    ' The lower value ScaleFactor is the higher the output frequency will
    ' become. (It scales down the period time). To multiply the frequency by
     
    ' 1.75 set ScaleFactor to 65536/1.75 = 37449 (Minimum allowed input frequency: 8.8Hz)
    ' 2.00 set ScaleFactor to 65536/2.00 = 32768 (Minimum allowed inout frequency: 7.6Hz)
    ' 2.25 set ScaleFactor to 65536/2.25 = 29127 (Minimum allowed input frequency: 6.8Hz)
     
    ' The minimum output frequency is 1 / 0.065536 = 15.258Hz meaning that
    ' the minimum input frequency is (1 / 0.065536) * (ScaleFactor / 65536).
    ' There is NO error checking, overflowing the calculation by inputting a
    ' lower frequency WILL make the output behave accordingly. 
     
    ScaleFactor     CON 32768           ' Scalefactor
    InputSignal     VAR GPIO.0          ' The input signal is connected here.
     
    AquireState     VAR BYTE            ' State machine variable, keep track of what we' re doing.
    Waiting         CON 0               ' States.
    FirstHalf       CON 1
    SecondHalf      CON 2
     
    Input_Period    VAR WORD   ' Period of input signal, in timer ticks.
    Output_Period   VAR WORD   ' Period of output signal, same "scale" as input.
    TMR0_Reload     VAR BYTE            ' Reload value for TMR0 to get correct output frequency
    FudgeFactor     VAR BYTE            ' For finetuning.
    StepCount       VAR BYTE            ' Used to "step thru" the output pattern.
    Running         VAR BIT             ' Gets set to 1 after getting our first sample
    OldPinState     VAR BIT             ' Previous state of input signal.
     
    CLEAR
     
    ' The lowest expected input frequency is 10Hz. At 4Mhz that's 100000 ticks which
    ' won't fit in the 16bit wide TMR1. We must use a prescaler of 1:2 - lowest
    ' possible frequency is then ~7.6Hz.
     
    T1CON.5 = 0                        ' TMR1 presecaler 1:2
    T1CON.4 = 1
     
    ' We will work with the TMR0 prescaler later but for now make sure
    ' it's assigned to TMR0 with a ratio of 1:1.
     
    OPTION_REG.5 = 0                            ' TMR0 clocked from Fosc/4
    OPTION_REG.3 = 0                            ' TMR0 prescaler assigned to TMR0
     
    OldPinState = InputSignal                   ' Initial state of input signal.
    ' ------------------------------------------------------------------------------
    ' ------------- Main routine implemented as a state machine --------------------
    ' ------------------------------------------------------------------------------
    Main:
        ' First we wait for a transition on the input pin.
        If (AquireState = WAITing) AND (OldPinState != InputSignal) THEN
            OldPinState = InputSignal           ' Remember the pin state.
            GOSUB StartAquiring                 ' Start the clock
            AquireState = FirstHalf             ' Getting first half of period.
        ENDIF
     
        ' Then we wait for a second transition on the input pin.
        If (AquireState = FirstHalf) AND (OldPinState != InputSignal) THEN
            OldPinState = InputSignal           ' Remember the pin state
            AquireState = SecondHalf            ' Getting second half of period.
        ENDIF
     
        ' Finally we wait for a third transition on the input pin. When
        ' that transition occurs we have "captured" both the high and low
        ' "halfcycle" of the input signal.
        If (AquireState = SecondHalf) AND (OldPinState != InputSignal) THEN
            OldPinState = InputSignal           ' Remember the pin state
            GOSUB StopAquiring                  ' Stop the clock and calculate
            AquireState = Waiting               ' Wait for next transition.
        ENDIF
     
        ' At the same time we're looking at the TMR0 interrupt flag to
        ' determine if it's time to do something with the outputs.
        IF (Running = 1) AND (INTCON.2 = 1) THEN
            GOSUB DoDatThing
        ENDIF
    Goto Main
     
    ' -----------------------------------------------------------------------------
    StartAquiring:
        TMR1H = 0                              ' Reset timer 1 count.
        TMR1L = 0
        T1CON.0 = 1                            ' Start TMR1
    RETURN
    ' -----------------------------------------------------------------------------
     
    ' -----------------------------------------------------------------------------
    StopAquiring:
        T1CON.0 = 0                             ' Stop TMR1
        Input_Period.HighByte = TMR1H
        Input_Period.LowByte = TMR1L            ' Get TMR1 count.
     
    ' Now apply the math to get our desired output period. Because of the TMR1 prescale
    ' ratio of 1:2 Input_Period now ranges from 50000 (=10Hz) to 250 (=2000Hz). 
    ' We need to account for that 1:2 ratio and we do that by multiplying the scaled value by
    ' by 2 resulting in a period time ticks. 
     
            Output_Period = Input_Period ** ScaleFactor       ' Scale the value
            Output_Period = Output_Period << 1                ' Account for TMR1 prescaler
     
    ' If this is the very first period captured we enable
    ' the "output frequency generator".
        If Running = 0 then
            TMR0 = 0        ' Reset TMR
            INTCON.2 = 0    ' Reset interrupt flag.
            GOSUB DoDatThing
            Running = 1
        ENDIF
     
    RETURN
    ' -----------------------------------------------------------------------------
     
    ' -----------------------------------------------------------------------------
    DoDatThing:
        INTCON.2 = 0    ' Reset interrupt flag.
     
    ' We have a problem in that Output_Period now contains a value ranging from
    ' 50000 to 250 for 20 to 4000Hz respectively. TMR0 is only 8bits wide so we must
    ' use its prescaler to get enough time out of it. The problem with that that to
    ' to able to "fit" 50000 ticks we must use a prescale ratio of 1:256 but then
    ' the resoultion at the higher frequencies becomes terrible. For this reason
    ' we select a suitable prescaler ratio based on the actual output period.
    ' This gives as good resolution at the top end at the same time as it allows
    ' us a wide range of output frequencies.
     
    Select case Output_Period
     
        Case IS < 256
        ' Set prescaler to 1:1 (prescaler assigned to WDT). Datasheet mentions
        ' special attention is needed when doing this - investigate further !
            OPTION_REG = OPTION_REG & %11111000
            'Output_Period = Output_Period >> 0     ' Don't divide anything 
     
        Case IS < 512
        ' Precalser 1:2
            OPTION_REG = OPTION_REG & %11110000
            Output_Period = (Output_Period +1 ) >> 1      ' Divide by 2
     
        Case IS < 1024
        ' Prescaler 1:4
            OPTION_REG = OPTION_REG & %11110001
            Output_Period = (Output_Period + 2) >> 2      ' Divide by 4
     
        Case IS < 2048
        ' Prescaler 1:8
            OPTION_REG = OPTION_REG & %11110010
            Output_Period = (Output_Period + 4) >> 3      ' Divide by 8   
     
        Case IS < 4096
        ' Presacler 1:16
            OPTION_REG = OPTION_REG & %11110011
            Output_Period = (Output_Period + 8) >> 4      ' Divide by 16
     
        CASE IS < 8192
        ' Prescaler 1:32
            OPTION_REG = OPTION_REG & %11110100
            Output_Period = (Output_Period + 16) >> 5      ' Divide by 32    
     
        Case IS < 16384
        ' Prescaler 1:64
            OPTION_REG = OPTION_REG & %11110101
            Output_Period = (Output_Period + 32) >> 6      ' Divide by 64    
     
        Case IS < 32768
        ' Prescaler < 1:128
            OPTION_REG = OPTION_REG & %11110110
            Output_Period = (Output_Period + 64) >> 7      ' Divide by 128
     
        Case else
        ' Prescaler < 1:256
            OPTION_REG = OPTION_REG & %11110111
            Output_Period = (Output_Period + 128) >> 8      ' Divide by 256
     
        END SELECT
     
        ' Now we have a TMR0 prescaler suitable for the output period we want and
        ' we have scaled down the value in Output_Period to fit the 8bit wide TMR0.
        ' Let's say out Output_Period initially was 12345. That would make the 
        ' above code set TMR0 prescaler to 1:64 and then do (12345 + 32) / 64 = 193.
        ' Adding 32 rounds of the otherwise truncated result to the nearest integer.
        ' At times there WILL be a slight error though. In this case the true output
        ' period is 12345us but we'll get 34*193=12352 instead.
     
        ' Because TMR0 interrupts on overflow we now need to subtract our period
        ' value from 256 and load that value into TMR0.
     
        TMR0_Reload = (256 - Output_Period) + FudgeFactor
     
        ' Temporarily stop TMR0 by switching its clock source to GP2. Reload it
        ' with the calculated value and the restart it. By adding the reload value
        ' instead of overwriting TMR0 we account for the time passed before 
        ' actually getting to this part of the code.
     
        OPTION_REG.5 = 1            ' Stop
        TMR0 = TMR0 + TMR0_Reload   ' Reload
        OPTION_REG.5 = 0            ' Start
     
    ' -----------------------------------------------------------------------------
    ' This is where the actual output switching gets done.
    ' Just example here, do whatever but remeber to set TRIS accordingly.
    ' Also look out for RMW issues.
    ' -----------------------------------------------------------------------------
     
        Select Case StepCount
        Case 0
            GPIO.1 = 1
            GPIO.2 = 0
            GPIO.3 = 0
     
        Case 1
            GPIO.1 = 0
            GPIO.2 = 1
            GPIO.3 = 0
     
        Case 2
            GPIO.1 = 0
            GPIO.2 = 0
            GPIO.3 = 1
     
        End SELECT
     
        StepCount = StepCount + 1
        If StepCount = 3 then StepCount = 0
     
    RETURN
    It compiles without errors (to just about half the space of the 12F675) but I currently have no way of actually testing it so that's up to anyone.

    Because the input and TMR0 interrupt flag are monitored in software there will be some jitter both in the measured input period time AND in the generated output frequency. The change in output signal frequency will always "lag" the change in input signal frequency by 1.5 cycles, I don't know if that's OK or not.

    I commented the heck out of the code in hopes it would make sense. In case it doesn't, just ask and I'll try to explain why I thought that would be a good idea.... Again, this is untested code but perhaps it can serve as a starting point.

    /Henrik.

  4. #4
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency multiplier... Suggestions/info needed.

    Wow Henrik...you really went the extra mile there - top man!

    Without wanting to hijack the thread, if you weren't constrained by the relatively low featured pic .....do you (or anyone else with experience) think it would be possible to detect pitch quickly - then output a multiple of it (say between 20.xxx% & 100%), so for example...

    if incoming frequency is 110Hz ('A' note)- then output 138.591 Hertz ('C#' note)

    Rather than using a LUT, I reckon I really need to multpily the incoming frequency ....becuase for sure there'll be occasions when the arriving frequencies are not quite as expected (instrument not in tune).

    Would such granularity be achievable? (eg detect the incoming frequency to XXX.yyy resolution then multiply by say 25.xxx%!)
    Last edited by HankMcSpank; - 22nd June 2011 at 01:00.

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,517


    Did you find this post helpful? Yes | No

    Default Re: Low frequency multiplier... Suggestions/info needed.

    Hi,
    Pitch = frequency, right? If so that is exactly what the above code is supposed to do. Though it could be tweaked to measure half a period instead of a full.

    What kind of performance to expect (and how or even IF to do to it) depends on the dynamic range you want. Is it 110-1100Hz or 11 to 11000Hz?

    Say you're running at 4Mhz, at 20Hz one half-period is 25ms or 25000 ticks - pretty good and you've got plenty of resolution as one tick equals a change in frequency of 20/25000=0.0008Hz ( I wonder if you can hear that? ).

    But go up an order of magnitude, or two, and do the math at 2kHz. Now a half cycle is 1/2000/2=250us and the resolution drops conciderably. One tick now equals a change in frequency of 2000/250=8Hz. At 10kHz all you'll get is 50ticks per half cycle and the resolution has now dropped to 1 tick per 200Hz - that kind of sucks.

    Run the PIC at 40MHz instead of 4 and get 10 times the resolution. But then the problem comes at the low end where the timer register will overflow. I guess that could be handled by counting the number of overflows though.

    So, it depends on the range you want/need and what kind of resolution and accuracy you need. 138Hz probably, 138.5 perhaps, 138.59 maby, 138.591.... you get the idea.

    There might be OTHER ways of doing it though - which I haven't thought about. But lets not mess this thread up, if you want to discuss this further may I kindly suggest we bring it to a new thread.

    /Henrik.

  6. #6
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency multiplier... Suggestions/info needed.

    Thanks Henrik... I'm not sure on the precision until I actually try the results on a guitar.... but at a guess I'd need measure the input 82Hz through 1500hz to say 0.1% accuracy .....and then multiply the output upto a top frequency 3000Hz at a similar accuracy.

    but as you rightly say, rather than muddy this one, I'll start a new thread!

  7. #7
    Join Date
    Apr 2011
    Posts
    53


    Did you find this post helpful? Yes | No

    Default Re: Low frequency multiplier... Suggestions/info needed.

    Would it be off-course to suggest you use discrete circuitry to detect the rising and falling edges of the squarewave and output a pulse at the detection of each?

  8. #8
    Join Date
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924


    Did you find this post helpful? Yes | No

    Default Re: Low frequency multiplier... Suggestions/info needed.

    Quote Originally Posted by kellyseye View Post
    Would it be off-course to suggest you use discrete circuitry to detect the rising and falling edges of the squarewave and output a pulse at the detection of each?
    That would be like asking someone to blink a LED without using a MCU... What nerve
    Dave
    Always wear safety glasses while programming.

  9. #9
    Join Date
    Jun 2011
    Location
    Tolland, CT, USA
    Posts
    5


    Did you find this post helpful? Yes | No

    Cool Re: Low frequency multiplier... Suggestions/info needed.

    Henrick,

    Thank you very much for the suggestions and the information. You understand my problem that I need to solve very well.

    I apologize for the delay in my reply. I am "on call" for field service work and am sometimes away for days. I will look at your suggestions and the code more closely. Because I am far from an expert it will take much research on my part to decipher the things you have said. After that I shall attempt to build on it. However, you have given me a place to start and it will force me to learn what is necessary to make the project happen. I will let you know when I have things sorted out. Thank you again! Jim.

    Quote Originally Posted by HenrikOlsson View Post
    Hello again,
    Although I still think a PIC with a CCP module would be "better" suited I gave the 12F675 a chance and came up with the following idea.
    Code:
     
    '****************************************************************
    '*  Name    : FrequencyScaler.pbp                               *
    '*  Author  : Henrik Olsson                                     *
    '*  Notice  : Copyright (c) 2011 Henrik Olsson                  *
    '*          : No Rights Reserved                                *
    '*  Date    : 2011-06-21                                        *
    '*  Version : 1.0                                               *
    '*  Notes   : Untested, provided as a starting point.           *
    '*          :                                                   *
    '****************************************************************
    ' We need the TMR0 prescaler, therefor it can't be used for the WDT.
    ' Make sure to turn WDT OFF in CONFIGs.
     
    DEFINE NO_CLRWDT 1 
    DEFINE OSC 4                        ' 4Mhx x-tal
     
    ' The lower value ScaleFactor is the higher the output frequency will
    ' become. (It scales down the period time). To multiply the frequency by
     
    ' 1.75 set ScaleFactor to 65536/1.75 = 37449 (Minimum allowed input frequency: 8.8Hz)
    ' 2.00 set ScaleFactor to 65536/2.00 = 32768 (Minimum allowed inout frequency: 7.6Hz)
    ' 2.25 set ScaleFactor to 65536/2.25 = 29127 (Minimum allowed input frequency: 6.8Hz)
     
    ' The minimum output frequency is 1 / 0.065536 = 15.258Hz meaning that
    ' the minimum input frequency is (1 / 0.065536) * (ScaleFactor / 65536).
    ' There is NO error checking, overflowing the calculation by inputting a
    ' lower frequency WILL make the output behave accordingly. 
     
    ScaleFactor     CON 32768           ' Scalefactor
    InputSignal     VAR GPIO.0          ' The input signal is connected here.
     
    AquireState     VAR BYTE            ' State machine variable, keep track of what we' re doing.
    Waiting         CON 0               ' States.
    FirstHalf       CON 1
    SecondHalf      CON 2
     
    Input_Period    VAR WORD   ' Period of input signal, in timer ticks.
    Output_Period   VAR WORD   ' Period of output signal, same "scale" as input.
    TMR0_Reload     VAR BYTE            ' Reload value for TMR0 to get correct output frequency
    FudgeFactor     VAR BYTE            ' For finetuning.
    StepCount       VAR BYTE            ' Used to "step thru" the output pattern.
    Running         VAR BIT             ' Gets set to 1 after getting our first sample
    OldPinState     VAR BIT             ' Previous state of input signal.
     
    CLEAR
     
    ' The lowest expected input frequency is 10Hz. At 4Mhz that's 100000 ticks which
    ' won't fit in the 16bit wide TMR1. We must use a prescaler of 1:2 - lowest
    ' possible frequency is then ~7.6Hz.
     
    T1CON.5 = 0                        ' TMR1 presecaler 1:2
    T1CON.4 = 1
     
    ' We will work with the TMR0 prescaler later but for now make sure
    ' it's assigned to TMR0 with a ratio of 1:1.
     
    OPTION_REG.5 = 0                            ' TMR0 clocked from Fosc/4
    OPTION_REG.3 = 0                            ' TMR0 prescaler assigned to TMR0
     
    OldPinState = InputSignal                   ' Initial state of input signal.
    ' ------------------------------------------------------------------------------
    ' ------------- Main routine implemented as a state machine --------------------
    ' ------------------------------------------------------------------------------
    Main:
        ' First we wait for a transition on the input pin.
        If (AquireState = WAITing) AND (OldPinState != InputSignal) THEN
            OldPinState = InputSignal           ' Remember the pin state.
            GOSUB StartAquiring                 ' Start the clock
            AquireState = FirstHalf             ' Getting first half of period.
        ENDIF
     
        ' Then we wait for a second transition on the input pin.
        If (AquireState = FirstHalf) AND (OldPinState != InputSignal) THEN
            OldPinState = InputSignal           ' Remember the pin state
            AquireState = SecondHalf            ' Getting second half of period.
        ENDIF
     
        ' Finally we wait for a third transition on the input pin. When
        ' that transition occurs we have "captured" both the high and low
        ' "halfcycle" of the input signal.
        If (AquireState = SecondHalf) AND (OldPinState != InputSignal) THEN
            OldPinState = InputSignal           ' Remember the pin state
            GOSUB StopAquiring                  ' Stop the clock and calculate
            AquireState = Waiting               ' Wait for next transition.
        ENDIF
     
        ' At the same time we're looking at the TMR0 interrupt flag to
        ' determine if it's time to do something with the outputs.
        IF (Running = 1) AND (INTCON.2 = 1) THEN
            GOSUB DoDatThing
        ENDIF
    Goto Main
     
    ' -----------------------------------------------------------------------------
    StartAquiring:
        TMR1H = 0                              ' Reset timer 1 count.
        TMR1L = 0
        T1CON.0 = 1                            ' Start TMR1
    RETURN
    ' -----------------------------------------------------------------------------
     
    ' -----------------------------------------------------------------------------
    StopAquiring:
        T1CON.0 = 0                             ' Stop TMR1
        Input_Period.HighByte = TMR1H
        Input_Period.LowByte = TMR1L            ' Get TMR1 count.
     
    ' Now apply the math to get our desired output period. Because of the TMR1 prescale
    ' ratio of 1:2 Input_Period now ranges from 50000 (=10Hz) to 250 (=2000Hz). 
    ' We need to account for that 1:2 ratio and we do that by multiplying the scaled value by
    ' by 2 resulting in a period time ticks. 
     
            Output_Period = Input_Period ** ScaleFactor       ' Scale the value
            Output_Period = Output_Period << 1                ' Account for TMR1 prescaler
     
    ' If this is the very first period captured we enable
    ' the "output frequency generator".
        If Running = 0 then
            TMR0 = 0        ' Reset TMR
            INTCON.2 = 0    ' Reset interrupt flag.
            GOSUB DoDatThing
            Running = 1
        ENDIF
     
    RETURN
    ' -----------------------------------------------------------------------------
     
    ' -----------------------------------------------------------------------------
    DoDatThing:
        INTCON.2 = 0    ' Reset interrupt flag.
     
    ' We have a problem in that Output_Period now contains a value ranging from
    ' 50000 to 250 for 20 to 4000Hz respectively. TMR0 is only 8bits wide so we must
    ' use its prescaler to get enough time out of it. The problem with that that to
    ' to able to "fit" 50000 ticks we must use a prescale ratio of 1:256 but then
    ' the resoultion at the higher frequencies becomes terrible. For this reason
    ' we select a suitable prescaler ratio based on the actual output period.
    ' This gives as good resolution at the top end at the same time as it allows
    ' us a wide range of output frequencies.
     
    Select case Output_Period
     
        Case IS < 256
        ' Set prescaler to 1:1 (prescaler assigned to WDT). Datasheet mentions
        ' special attention is needed when doing this - investigate further !
            OPTION_REG = OPTION_REG & %11111000
            'Output_Period = Output_Period >> 0     ' Don't divide anything 
     
        Case IS < 512
        ' Precalser 1:2
            OPTION_REG = OPTION_REG & %11110000
            Output_Period = (Output_Period +1 ) >> 1      ' Divide by 2
     
        Case IS < 1024
        ' Prescaler 1:4
            OPTION_REG = OPTION_REG & %11110001
            Output_Period = (Output_Period + 2) >> 2      ' Divide by 4
     
        Case IS < 2048
        ' Prescaler 1:8
            OPTION_REG = OPTION_REG & %11110010
            Output_Period = (Output_Period + 4) >> 3      ' Divide by 8   
     
        Case IS < 4096
        ' Presacler 1:16
            OPTION_REG = OPTION_REG & %11110011
            Output_Period = (Output_Period + 8) >> 4      ' Divide by 16
     
        CASE IS < 8192
        ' Prescaler 1:32
            OPTION_REG = OPTION_REG & %11110100
            Output_Period = (Output_Period + 16) >> 5      ' Divide by 32    
     
        Case IS < 16384
        ' Prescaler 1:64
            OPTION_REG = OPTION_REG & %11110101
            Output_Period = (Output_Period + 32) >> 6      ' Divide by 64    
     
        Case IS < 32768
        ' Prescaler < 1:128
            OPTION_REG = OPTION_REG & %11110110
            Output_Period = (Output_Period + 64) >> 7      ' Divide by 128
     
        Case else
        ' Prescaler < 1:256
            OPTION_REG = OPTION_REG & %11110111
            Output_Period = (Output_Period + 128) >> 8      ' Divide by 256
     
        END SELECT
     
        ' Now we have a TMR0 prescaler suitable for the output period we want and
        ' we have scaled down the value in Output_Period to fit the 8bit wide TMR0.
        ' Let's say out Output_Period initially was 12345. That would make the 
        ' above code set TMR0 prescaler to 1:64 and then do (12345 + 32) / 64 = 193.
        ' Adding 32 rounds of the otherwise truncated result to the nearest integer.
        ' At times there WILL be a slight error though. In this case the true output
        ' period is 12345us but we'll get 34*193=12352 instead.
     
        ' Because TMR0 interrupts on overflow we now need to subtract our period
        ' value from 256 and load that value into TMR0.
     
        TMR0_Reload = (256 - Output_Period) + FudgeFactor
     
        ' Temporarily stop TMR0 by switching its clock source to GP2. Reload it
        ' with the calculated value and the restart it. By adding the reload value
        ' instead of overwriting TMR0 we account for the time passed before 
        ' actually getting to this part of the code.
     
        OPTION_REG.5 = 1            ' Stop
        TMR0 = TMR0 + TMR0_Reload   ' Reload
        OPTION_REG.5 = 0            ' Start
     
    ' -----------------------------------------------------------------------------
    ' This is where the actual output switching gets done.
    ' Just example here, do whatever but remeber to set TRIS accordingly.
    ' Also look out for RMW issues.
    ' -----------------------------------------------------------------------------
     
        Select Case StepCount
        Case 0
            GPIO.1 = 1
            GPIO.2 = 0
            GPIO.3 = 0
     
        Case 1
            GPIO.1 = 0
            GPIO.2 = 1
            GPIO.3 = 0
     
        Case 2
            GPIO.1 = 0
            GPIO.2 = 0
            GPIO.3 = 1
     
        End SELECT
     
        StepCount = StepCount + 1
        If StepCount = 3 then StepCount = 0
     
    RETURN
    It compiles without errors (to just about half the space of the 12F675) but I currently have no way of actually testing it so that's up to anyone.

    Because the input and TMR0 interrupt flag are monitored in software there will be some jitter both in the measured input period time AND in the generated output frequency. The change in output signal frequency will always "lag" the change in input signal frequency by 1.5 cycles, I don't know if that's OK or not.

    I commented the heck out of the code in hopes it would make sense. In case it doesn't, just ask and I'll try to explain why I thought that would be a good idea.... Again, this is untested code but perhaps it can serve as a starting point.

    /Henrik.

  10. #10
    Join Date
    Jun 2011
    Location
    Tolland, CT, USA
    Posts
    5


    Did you find this post helpful? Yes | No

    Default Re: Low frequency multiplier... Suggestions/info needed.

    Henrik,

    Unfortunately the duty cycle of the source is not a perfectly symmetrical square wave although I believe it to be of a constant duty cycle.

    I have done some research on Darryl Taylors routines and am trying to fit this into what I am learning. Thank you for sending me in that direction.

    1 us is more than enough resolution one update per input cycle would be great. However, I am more concerned in the lag time in the propagation at such low frequencies. In the back of my mind I am thinking that it will be horrific with a 10Hz input. Will the PIC really be able to propagate in one cycle with a 10Hz and lower signal? If so, it would be better than I ever imagined possible. In the past I have built a crude frequency doubler with a couple of flip flops and the jitter was unacceptable. This setup also taught me that I Need to stray slightly from the !:2 ratio. I really don't know what I will need in terms of numerical specification but I have a test setup that I can run real time tests and see the result. The system is for a motorbike fuel injection system which I can monitor with a diagnostic scope on a dyno.

    And I thank you again! Jim.


    Quote Originally Posted by HenrikOlsson View Post
    Hi,
    That can be done but I don't think I'd use 12F675. Instead I'd look for a PIC with a CCP-module (which I'd use to measure the frequency) and then an additional timer to generate the "doubled" frequency. I took a quick look and the 12F615/617 could work.

    If the dutycycle of the input signal is 50% you only need to measure half a period (positive or negative) which is easy to do, if it's not 50% it gets a little bit trickier but still very much doable with the CCP module. Get the captured value from the CCP-module, apply your math and load the 'other' timers register with the correct value so that it overflows and generates an interrupt at the correct interval. In the timers inerrupt service routine reload the timer and "step" your pattern.

    I'd definitley use Darrel Taylor's Instant Interrupt routines (because I suck at ASM).

    What kind of resolution are we talking about? The timer used for the CCP module is 16 bits wide, at 4MHz that means it can "measure" up to ~65.5ms (with 1us resolution) which is enough if the duty cycle if the inout signal is 50%. If not you need to use the prescaler which "extends" the measurable time but decreases the resoultion by the same ratio.

    With that said there are always more than one way. Does the frequency need to be updated "immediately" or is it OK to only update it once per "cycle"? One way to do it with the '675 might be to use one of timers to "manually" measure the input frequency (polling the input, starting and stopping the timer manually) and the other to genereate the "new" frequency.

    /Henrik.

  11. #11
    Join Date
    Jun 2011
    Location
    Tolland, CT, USA
    Posts
    5


    Did you find this post helpful? Yes | No

    Thumbs up Re: Low frequency multiplier... Suggestions/info needed.

    Henrik,

    Thank you very much for taking the time and making the effort to come up with the code. I am very anxious to work with it and I certainly will let you know what I find. Hopefully I won't have too many questions. I will try to do research before asking. Jim.

  12. #12
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,517


    Did you find this post helpful? Yes | No

    Default Re: Low frequency multiplier... Suggestions/info needed.

    Hi Jim,

    > Unfortunately the duty cycle of the source is not a perfectly symmetrical square wave although I believe it to be of a constant duty cycle.

    As long as the duty cycle is fixed it doesn't have to be 50%, if you know the dutycycle ratio is 37% or whatever it would be enough to measure either the positive or negative half of the cycle and then calculate the period time. However, if the dutycycle isn't fixed then it obvoiusly won't work. The code I posted above measures a complete cycle so it doesn't matter if the dutycycle changes, as long as it stays within reason (like 5-95% or something).


    > I have done some research on Darryl Taylors routines and am trying to fit this into what I am learning. Thank you for sending me in that direction.

    Yes, Darrels routines are by far the easiest/best way to get PBP interrupts going without having to live with the limitations of ON INTERRUPT. I initially tried using DT-INTS and another aproach on the 12F675 but unfortunately the device doesn't have enough RAM, that's why I ended up with the code I posted. So if you're going to use DT-INTS pick a PIC with more RAM then 12F675.


    > 1 us is more than enough resolution one update per input cycle would be great. However, I am more concerned in the lag time in the propagation at such low frequencies.

    1us is the resoultion of the timer generating the outputting frequency, because the software (in the code above) polls the interrupt flag as it loops around the "accuarcy" will be less than 1us. With the above code the output changes ~1.5 cycles after the input changes, it doesn't matter if the frequency is 10Hz or 2000Hz. So if you have a steady input of 10Hz and it instantly changes to 11Hz there will be a delay of (1/11)*1.5=136ms before the output changes from 20 to 22Hz.

    That 1.5 cycle delay is worst case, it depends on "where" during the cycle the input frequency actually changes. If the input happens to change just before the measruement is going to start the delay will be ~1 cycle instead.

    Again, all this is with the above code, if you go for a PIC with a CCP module you can probably get that down to 1 cycle and if you "decide" that the dutycycle isn't going to change then perhaps it could be 1/2 cycle.

    There are a lot of ways of doing this, it's just a matter of deciding which one fits the purpose best.

    /Henrik.

  13. #13
    Join Date
    Jun 2011
    Location
    Tolland, CT, USA
    Posts
    5


    Did you find this post helpful? Yes | No

    Default Re: Low frequency multiplier... Suggestions/info needed.

    Henrik,

    I couldn't have asked for a better education. Thank you, I more than appreciate all of the information you have put forth. I shall work on it over the following weeks and hopefully gain a better understanding of "code" at the same time. I will let you know what happens. Jim.

Members who have read this thread : 1

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