Shop OBEX P1 Docs P2 Docs Learn Events
SX Timers Question — Parallax Forums

SX Timers Question

Craig43Craig43 Posts: 11
edited 2005-02-28 09:39 in General Discussion
I need to count a number of pulses from an external device over a set period of time. My original thought was to use one of the 16 bit timers in the "External Event Mode" to count the pulses, and the second 16 bit timer to interrupt every 50 msec. In the interrupt routine I would then read the value of the first timer and reset it.

But from the data sheet you can configure a timer for External Event counting, but there is no way to read the count .. seems a bit odd. This is the only mode that can count pulses from the external device, but no way to read the count directly, or to even somehow have it copy the count to the capture register. Does anyone know how to do this?

My alternate solution is to turn the problem around and have the External Event Timer count N number of pulses, then tie the PWM output pin to the capture 1 pin on the second timer. Then program the 2nd timer as a Capture/Compare mode and have it interrupt each time the first timer counts N pulses. This will capture the clock ticks from Timer 2 into the capture register which I can then read. Which gives me the amount of time it took to count N pulses from the external device.

This seems a rather round about way to do it, and not what I really wanted.

Thanks,

Craig

Comments

  • Paul BakerPaul Baker Posts: 6,351
    edited 2005-02-26 14:25
    Ok, first off are you using the SX28 or SX48/52? I will assume you are using an SX28. The SX28 has a single 8 bit counter (the RTCC), if you use an external trigger for the RTCC, you are faced with the dilemma of determining when the elapsed period time occurs, this will require an external circuit (or a clever manipulation of the watchdog timer). With that said, you do not need to be able to read RTCC (though I believe you can by setting register $01 to be RTCC in your options). The RTCC generates an interrupt every time it overflows, by setting the RTCC to $FF, the next pulse on the RTCC pin will generate an interrupt, and in the interrupt you increment a software 16bit counter and reset the RTCC to $FF.

    But you may want to consider that instead of using the RTCC, use the external interrupt feature of the Port B pins and use that to increment a 16bit software counter, that way you can use the RTCC (with internal incrementing) to determine when the period of time has elapsed.

    Post Edited (Paul Baker) : 2/26/2005 2:42:52 PM GMT
  • Craig43Craig43 Posts: 11
    edited 2005-02-26 17:33
    Hi Paul,

    Using the SX48, with the two 16 bit general purpose Timers.

    Craig
  • Paul BakerPaul Baker Posts: 6,351
    edited 2005-02-26 20:31
    those can be read using mode $00 through $07, page 12 of http://www.parallax.com/dl/docs/prod/datast/SX4852BD.pdf (mode registers for the 48 and 52 are identical)

    Post Edited (Paul Baker) : 2/26/2005 8:45:18 PM GMT
  • Guenther DaubachGuenther Daubach Posts: 1,321
    edited 2005-02-26 22:09
    Hi,

    Paul is right, these registers can be read but it is a bit tricky as you can't do something like

    mov w, !rb (for timer/counter 1). or
    mov w, !rc (for timer/counter 2).

    Instead, you need to code a

    mov !rb, w (for timer/counter 1), or
    mov !rc, w (for timer/counter 2)

    These instructions actually copy the contents of the timer/counter register into w.

    This is similar to the method how you would "read" the contents of the wakeup pending register - it is also done by a

    mov !rb, w

    but here, the contents of the wakeup pending register and w are exchanged. So you would normally clear w before executing this instruction. After the instruction, the pending bits are cleared, and the last status of the pending bits is available in w. When you apply this to one of the timer/counter registers, the content of w is _not_ copied into the timer/counter register, just w returns the current value.

    Don't forget to setup the Mode register prior to executing a mov !r?, w instruction to select the register you want to read, and note that the MODE #const instruction on all SX types only copies the lower four bits of const into the MODE register. In oder to set bit 4 of MODE in an SX48/52, do a

    mov w, #Const
    mov m, w

    or use the _mode macro:

    _mode MACRO 1
       IFDEF SC48_52
           mov w, #\1
           mov m, w
       ELSE
            mov m, #\1
       ENDIF
    ENDM
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Greetings from Germany,

    G
  • Craig43Craig43 Posts: 11
    edited 2005-02-27 01:58
    Hi Guys,

    I may still be missing something. I looked at Page 12 of the Data sheet and the registers available for a given timer are the compare, capture and control registers .. not the actual counter/timer. This is also indicated on page 29: "The CPU can access the Compare and Capture registers .. The other timer registers are not directly accessible".

    So if I have a 16 bit timer configured for "External Event Mode", which is the only mode which will count external pulses, then there is no way to determine the number of counts in a set period, say 50 msec.

    From what I can see, the only time the contents of the counter is copied to a register is when operating in the Capture/Compare mode .. but unfortunately it clocks the counter from the internal processor .. not the external source.

    I must be missing something because I wouldn't think they would design these wonderfully flexible timers and not provide some method for counting pulses.

    Craig
  • Craig43Craig43 Posts: 11
    edited 2005-02-27 02:17
    Will this work:

    1. I configure Timer 1 for PWM Mode. Assuming the internal clock is running at 4Mhz, I set the prescaler for divide by 4, and then set both the compare registers to a value of 50,000. This will then generate an interrupt with a fixed duty cycle of 50 msec.

    2. Connect the external pulse to Capture register 1 of Timer 1. This assumes then that the capture register will increment on a rising edge of each external pulse.

    3. On the interrupt generated from 1 above, I then read T1CPL and T1CPH to get the number of pulses counted during a 50 msec period. I don't need to reset the capture register because I can take the current value and subtract the previous value (allowing for rollovers).

    The question here is if in "PWM Mode", will the capture register count external pulses. The schematic on page 29 seems to indicate it might .. but not sure who controls that logic gate between the up/down arrow box and the register.


    Craig
  • Guenther DaubachGuenther Daubach Posts: 1,321
    edited 2005-02-27 11:29
    Craig,

    yes you are right - according to the data sheet, there is no way to directly read the timer registers. I agree with you - it would be nice if there would be the possibility to do that. The data sheet gives no information if in PWM mode, the capture register can count external pulses. In "regular" PWM mode, it is supposed that the two registers R1 and R2 hold fixed values that determine the frequency and duty cycle of the PWM signal.

    One way to figure out if R2 can be externally clocked in PWM mode (what I assume) is to setup the timer for PWM mode at a certain duty cycle (say 50%), monitor the generated PWM signal on a scope, and then apply external clock pulses to the Capture2 pin. If the PWM signal changes duty cycle (and frequency) in this case, you're in good shape, and the concept you described should work.

    Another idea would be to use the "regular" RTCC for the timing, i.e. in an ISR triggered by RTCC roll-overs, handle a 50 msec timer. and after 50 msec read the contents of the Capture 1 or Capture 2 register, depending on which input you use to feed in the external pulses to be counted.

    After reading the Capture register, I would clear it instead of subtracting the previous value from the current one because you might get a false result when the Capture register rolls over within a 50 msec period.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Greetings from Germany,

    G
  • RickBRickB Posts: 395
    edited 2005-02-27 16:34
    Another way to determine how many pulses have been counted is this. Tie a normally tristated output pin to your counter input pin. After the count period, toggle the output pin and count the # of pulsees neccessary to cause overflow of the 16 bit counter. Subtract that # from 65536, and you have it. For this to work you have to be able to stop the other pulses.

    Rick
  • Craig43Craig43 Posts: 11
    edited 2005-02-27 18:05
    If the capture registers are not "counters" then I think the easiest alternative is to give up on directly counting the number of pulses in a given period and instead, turn the problem around, determine the length of time for a given number of pulses.

    To do this would require that the first timer be setup to count pulses (External Event mode) and set R1 and R2 to a given pulse count .. say 2500. In addition, setup the other Timer to count internal clock ticks (divided by 4 say). Also, connect the pwm output of timer 1 to the input pin on capture 1 of the second timer.

    Then, when the pulse count on timer 1 matches R1 it will change the output state of the PWM pin, which will cause an interrupt on the capture 1 input pin on timer 2. This also causes the contents of the timer on timer 2 transferred to the capture register. The interrupt service routine can then read the capture register. This would hence give the number of clock ticks for N external pulses.

    The tricky part is because the output signal on Timer 1 is alternatiing between a rising edge and then a falling edge (due to the R1 and then R2 match), the input 'condition' of the capture pin on Timer 2 will have to also be toggled in the interrupt service routine. In other words, the capture pin would first look for a rising pulse and then a falling pulse.

    The software then has additional work to take the "time per N pulses" data and convert this to "N pulses per time". For example, if it takes 4000 clock ticks to count 1000 pulses, then the pulse rate is (4,000,000 / 4,000) x 10 = 10,000 pulses / second.

    I'll go ahead and setup a test program in the SX42 and try to verify all this. A lot of work to get a simple count. Maybe in the next version of the SX42 they will provide a means to either read the contents of the timer register, or setup the capture registers to count external pulses.

    Craig
  • pjvpjv Posts: 1,903
    edited 2005-02-27 19:52
    Hi Craig;

    Am I missing something here, or is this not as simple as it seems??

    Unless the speed of the pulses to be counted are very fast, say faster than 500 KHz, then I believe this can be readily accomplished by running the processor at 50Mhz, and· run an ISR at 1 micro second. In the ISR·poll the input bit to detect a rising edge, and in the next ISR detect a falling edge, then accumulate this rise/fall event to a counter of any desired length.

    At the same time each·ISR entry decrements a timing counter set for 50 milliseconds, being 50,000 (microseconds) ISR entries. When this counter·reaches zero, then transfer the·contents of the pulse counter to a holding register, and clear the pulse counter for the next round.

    If the speed is this high, and input pulses are non symmetrical, then in order to catch the short HI (or LO) time, the ISR will need to be executed faster, and consequently·the 50 millisecond·counters will need to be appropriately scaled.

    If the speed of the pulses is slower, then the processor could be slowed down accordingly.

    The catch in all this is to reliably detect one rising and one falling edge by polling, but this can be readily accomplished; I believe it's all very simple, and one need not worry about using the special counters; they are a bit hairy.

    Peter
  • Craig43Craig43 Posts: 11
    edited 2005-02-27 21:53
    Hi Peter,

    The pulses are in the range of 50,000 to 250,000 per second. The sensor converts magnetic flux to a square wave. So by measuring the frequency you get magnetic flux. Unfortunately the processor board I'm using is fixed to using the internal 4Mhz oscillator.

    So if the frequency is 200k, and the clock is 4,000,000 then there are only 20 clock cycles between pulses .. and that is close to the interrupt latency .. too close to ensure an accurate count.

    It is better for me to have the 16 bit timers counting pules and then while it is busy counting more pulses, I can go ahead and report the results to a host machine. By setting the number of counts between reports I establish the time I have between reports .. and hence cpu cycles.

    I'm thinking of using 2500 for Timer 1 and a divide by 4 for Timer 2. Timer 1 will operate in the PWM mode and R1 and R2 would have 2500 in the registers. At the maximum pulse rate from the sensor, I would get a 'match' on Timer 1 (R1 or R2) 100 times per second.

    Each match will cause an interrupt on Timer 2 (because of a capture 1 event). If Timer 2 is being clocked at the system clock rate / 4 .. then at 4,000,000 clock rate, and 100 events per second, the value in Timer 2 should be about 4,000,000 / 4 / 100 = 10,000 .. which is plenty of resolution.

    At the slowest pulse rate, 50,000/sec, then there will be an event 50,000/2500 = 20 events per second. Timer 2 will then be 4,000,000 / 4 / 20 = 50000, again, lots of resolution.

    The only risk is if the pulse rate out of the sensor is slower than 50,000 .. which the manufacturer says it will not be. But if so, I guess I can always 'download' a value for R1 and R2 which would keep the system within range.

    Craig
  • pjvpjv Posts: 1,903
    edited 2005-02-28 04:57
    Well Craig, my suggestion clearly won't work at 4 MHz clock rate.

    Might you consider patching a 50 Mhz resonator onto the board or is this absolutely out of the question? I fear you might be in for a bit of a rough ride with the vagaries of the little bit "hairy" timer issues.

    I can easily help you with code based on my example.

    Peter
  • Craig43Craig43 Posts: 11
    edited 2005-02-28 08:22
    Hi Peter,

    I think I ran into the "vagaries" of the timers that you mentioned above.

    Here is the code I'm using for test:


    DEVICE SX48,BOR26,OSC4MHZ
    RESET Start
    FREQ 4_000_000

    ; Blink LED

    ; Define all symbols
    eventFlag EQU $0D


    ; *********************************************************************
    ; Interrupt Service Routine
    ; *********************************************************************
    ORG $000
    TISR

    inc eventFlag ; set event flag

    mov m,#$07 ; T1CNTA, read
    mov !rb,w

    mov m,#$17 ; T1CNTA, write
    mov w,#01 ; clear status
    mov !rb,w

    RETI ; return from interrupt


    ; *********************************************************************
    ; Reset Entry Point (Initialization)
    ; *********************************************************************
    Start
    mov w,#$1f
    mov m,w
    mov w,#%11000111 ;Option Register Setup
    mov !OPTION,W
    mov ra, #%00000001 ;Set port A output latch initial state
    mov !ra,#%00001100 ;Set port A input/output direction
    mov !rb,#%11111111 ;Set port B to input direction
    mov !rc,#%11111111 ;Set port C to input direction
    mov !rd,#%11111111 ;Set port D to input direction
    mov !re,#%11111111 ;Set port E to input direction
    clr eventFlag

    ; setup TIMER 1

    mov m,#$16 ; T1CNTB, write
    mov w,#$1C ; div 128, sw timer mode
    mov !rb,w

    mov m,#$17 ; T1CNTA, write
    mov w,#01 ; ovflw int enable
    mov !rb,w

    clrb ra.6 ; turn LED OFF

    mov m,#$10 ; reset Timer 1
    mov !rb,w

    ; *********************************************************************
    ; Main program loop
    ; *********************************************************************
    State1
    test eventFlag
    jz State1
    clr eventFlag
    setb ra.6 ; LED ON

    State2
    test eventFlag
    jz State2
    clr eventFlag
    clrb ra.6 ; LED OFF
    jmp State1


    As you can see it is a simple program that uses two program states to toggle an LED.

    I have verified that setb ra.6 and clrb ra.6 do indeed turn the LED ON and OFF.

    What happens if I run the program above is .. nothing. No LED comes on.

    BUT, if I disable the reset timer instructions and run the program, then the LED does come on, but it never goes off. I also noticed that by changing the prescaler in the Timer register that I can change the amount of time it takes for the LED to come on.

    So I inserted code into the ISR thinking that maybe I have to read the state of the interrupt bits in the Timer register, but that didn't help any. Or by clearing the bits .. but that had no effect either.

    I looked through the sample codes but can't find anything that shows an example of how to use the timers.

    Do you see what's wrong above, or do you have a sample code that shows how to use the timers?

    Craig
  • Craig43Craig43 Posts: 11
    edited 2005-02-28 09:39
    Hi Peter,

    Forget that last post .. I got the code working. There were two problems, first, because the timer registers use 5 bits in the mode register I had to change the way I loaded it, second, even though I didn't want to use the compare registers .. you have to still process the events.

    I changed the code to reflect these two items and everything now works.

    Now to do something more serious with those timers than switching an LED on and off.

    Craig
Sign In or Register to comment.