SX Timers Question
Craig43
Posts: 11
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
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
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
Using the SX48, with the two 16 bit general purpose Timers.
Craig
Post Edited (Paul Baker) : 2/26/2005 8:45:18 PM GMT
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:
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Greetings from Germany,
G
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
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
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
Rick
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
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
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
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
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
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