Timer Tick on the Atom Pro

As per your comments I have started this up as a different thread.

Yes I would very much appreciate seeing different versions of timer ticks for the Atom Pro. Yes the TV Brat code was the first good example I have seen for using interrupts on the Pro.

I have had a lot of fun working with my brat. However it was with this code that I started having some problems with doing serial communcations with an LCD Display or to the debug terminal. To get around this I ended up enableing and disabling the interrupts. An example of this is:

[code]

; Main LCD output function
;
line var sbyte
fPad var byte
LCD_Print[line, fPad]
DISABLE WKPINT_3
DISABLE TIMERAINT

if line = 1 then
	gosub LCD_WriteCommand[0x80]
elseif line = 2		
	gosub LCD_WriteCommand[0xC0]
endif
		
Pause(1)

for line = 0 to 14	; try now to write to last position as it appears to autoscroll...
	if fPad <> 2 and LCD_String(line) > 0  and LCD_String(line) <> "|" then
		serout LCDPIN, LCD_BAUD, [LCD_String(line)]
	else
		if fPad = 0 then
			goto LCDP_Enable
		endif
		fPad = 2
		serout LCDPIN, LCD_BAUD, " "]
	endif
	Pause(1)
next

LCDP_Enable
ENABLE WKPINT_3
ENABLE TIMERAINT

return[/code]

I should retest this with the latest IDE to see if the lower overhead for HSERVO may have improved this. Also It would be interesting to rewrite some of the brat code to use the timer without interrupts to see if this would solve it as well.

Kurt,
have you tried using the hardware HSEROUT? I’m interested since I use it and I haven’t had any problems, but my timing may not be as critical as yours…
-Drew

Nope, not yet. That is what I would do if I needed to have a consistent timer tick. I was able to get away with disabling the timer when I was doing communciations with either the LCD or over S_IN and S_OUT. So far when I had the BRAT communicate over S_OUT I found that 2400 baud worked OK and so far I have kept it that way.

When I get some time, I will break down MY brat and move the servos to the lower number servo pins, which will reduce the overhead of the HSERVO commands. Maybe AcidTech’s improvements here may have been enough to make 9600 baud work reliably. If not I could easily move the LCD to the hardware UART. Or I might try what AcidTech suggested and modify his code for handling the IRPD interrupt to only use one of the hardware timers without the timer interrupt to see if this improves things.

Are you using the WKPINT to interrupt for the IR remote? I was going to use two of those pins for the encoders but if it screws up I2C I can’t… It’s clocked so I can see why it SHOULD work, still have to play with it.
My primary need for a tick is to time out a state (leaky integrator thingy). I’m using a loop counter for now.

I will be starting to program to use encoders soon, but I am planning to use the capture inputs (1 for each encoder). The capture inputs seem to be a great match for things like encoders. :slight_smile:

8-Dale

I tried to reply to this yesterday but accidently hit “Back” and lost me whole post. I’ll try again today.

The simplest method to setup a timer is using TimerW. You can either use an interrupt system or you can use a polling system to keep track of used time. First the polling example.

[code]
TCRW = 0 ;clears TCNT and sets the timer to inc every clock cycle
TMRW = 0x80 ;starts the timer counting

main
goto main

ticks var long
currenttick var long
waitticks [ticks]
TCNT = 0 ;clear TimerW count
TSRW.bit7=0 ;clear TimerW OVF flag
currenttick = 0 ;Clear currenttick
do
currenttick.word0 = TCNT
if(TSRW.bit7)then ;if OVF flag is set add 0x10000 to currentticks and clear OVF flag
currenttick=currenttick+0x10000
TSRW.bit7=0
endif
while(ticks<currenttick)
return[/code]

This subroutine will wait up to 2^32 cycles. It’s accuracy is whatever the total clock cycles used up inside the do…while loop is or less. It will handle delays upto 4.47 minutes. Adjusting how often TimerW increments will increase the max time you can delay but reduce your accuracy.

Written in H8-300 assembly:

;assume er0 holds ticks
;er1 will be out currenttick
waitticks:                                  ;6 entry
   mov.l #0,er1                          ;2 clear currenttick
   mov.w r1,@TCNT:16               ;4(12) clear TCNT
waittickslp:
   mov.w @TCNT:16,r1               ;6 get TCNT
   mov.b @TSRW:8,r2l	               ;4 Get Flags
   btst #7,r2l                             ;2 If OVF flag is clear
   bne waitticksskip1:8               ;4(16) goto waitticksskip1
   bclr #7,r2l                             ;2 clear OVF
   mov.b r2l,@TSRW:8	               ;4 save TSRW
   inc.w #1,e1                           ;2 increment high 16bits of currenttick
   bra waitticksskip2:8	               ;4(12)
waitticksskip1:
   bra .+2:16                             ;6 waste 12 clock cycles
   bra .+2:16                             ;6(12)
waitticksskip2
   cmp.l er0,er1                         ;4 compare currenttick with ticks
   blt waittickslp:8                      ;4(8) goto waitticks
   rts                                         ;8

You’ll notice that even in assembly code you’ll have a 36 clock cycle loop which makes your resolution 36 clock cycles. There are tricks around that but they add about three times the over head. So instead of 20 cycles of overhead you’d endup with approx 60 cycles(maybe alot more since I’m doing this from memory).

I’ll add an example for the interrupt based waitticks tomorrow.

Looks nice.

Your assembly code has a bit more consistent in the timing then the C code. If that was not important you could easily shave off a bit. (bra before waitticskskip1 and the two bras after it. which would make your assembly language match your C code.

Thanks

Yes I could but I’ve gotten so use to making my assembly code symetric I do it without thinking. So drop the simmetry code and you’ll have a basic loop of 24 cycles.

To do pretty much the same thing as the MBasic example above using an interrupt:

[code]TCRW = 0 ;clears TCNT and sets the timer to inc every clock cycle
TMRW = 0x80 ;starts the timer counting

ONINTERRUPT TIMERW_OVF,HandleInt
ENABLE ;allow interrupts, but does not enable any particular one
main
goto main

ticks var long
currenttick var long
waitticks [ticks]
currenttick = 0 ;Clear currenttick
TCNT = 0
ENABLE TIMERW_OVF ;enable timerw overflow interrupt
do
currenttick.word0 = TCNT
while(ticks<currenttick)
DISABLE TIMERW_OVF ;disable timerw overflow interrupt
return

handleint
currenttick=currenttick+0x10000
resume[/code]

This is a very simple example and not very useful. I’d use the non interrupt based version instead if all I wanted to do was wait a certain number of ticks. The timer interrupt would be better suited for keeping track of time in many places all at once.

The timer tick code with the use of TimerW works well. There is probably a boundry condition in the waitticks code that may have a problem, which I will try to explain later. However TimerW is used in the HSERVO sub-system, and so if choose to use HSERVO then you will probably need to convert to an 8 bit timer, such as timerA.

In my current project I am trying to measure the pulse widths for the 6 channels of an HITEC receiver, using WKP0-WKP5(P0-P5) on the BAP. When I was using TimerW I had the counter count with Clk/8 and the code looked like it was computing the pulses reasonably well. However when I used TimerA with an interrupt to process overflows to get a count greater than 256, the code was not generating overly consistently. It worked better when I used the counter of CLK/32.

The interrupt functions currently look something like:

[code]handle_intp0
if fProcessingPulses = FALSE then
If (IEGR2 & 0x01) then ; process rising edge
; need to reset timer
TMA = 0xc ; reset timer
TMA = 0x6 ; clk/32
iOverflowTime = 0
fPulseTimingsBusy = 1
IEGR2.bit0 = 0 ;interrupt on a falling edge.
else
aiPulseTimings(0) = iOverflowTime + TCA
IEGR2.bit0 = 1 ;interrupt on a falling edge.
endif
endif
resume

handle_intp1
if fPulseTimingsBusy then
aiPulseTimings(1) = iOverflowTime + TCA
endif
resume

handle_intp2
if fPulseTimingsBusy then
aiPulseTimings(2) = iOverflowTime + TCA
endif
resume

handle_intp3
if fPulseTimingsBusy then
aiPulseTimings(3) = iOverflowTime + TCA
endif
resume

handle_intp4
if fPulseTimingsBusy then
aiPulseTimings(4) = iOverflowTime + TCA
endif
resume

handle_intp5
if fPulseTimingsBusy then
aiPulseTimings(5) = iOverflowTime + TCA
fPulseDataValid = TRUE
fPulseTimingsBusy = FALSE
endif
resume

handle_timera
iOverflowTime = iOverflowTime + 256
resume[/code]

I believe the problem is that at CLK/8 there is a Timer A overflow interrupt every 2048 clocks and and CLK/32 every 8192 clocks. I believe that the overflow interrupt is at a lower priority than the WKP interrupt. So it is very possible that when in my code I am handling an WKP3 interrupt there may be a pending TimerA overflow and as such my Overflow time will be off by at least 256. It may also be possible where we could get multiple higher priority interrupts WKP INTP0… and possibly be off by multiples of 256? I am sorry if my explanation is not very good.

What I am trying to now to fix this is to try to see if there is a pending timer interrupt and process it during the WKP interrupt. Something like:

[code]handle_intp1
if fPulseTimingsBusy then
if (irr1.bit6) then ; pending interrupt?
irr1.bit6 = 0
iOverflowTime = iOverflowTime + 256
endif

	aiPulseTimings(1) = iOverflowTime + TCA
endif
resume

[/code]
This shortens the window. The only problem could be that TCA wraps around just during or after the testing if irr1.bit6. This is small window. I suppose I could add in some additional tests. Like maybe save away TCA to use as the first instruction of the interrupt handler and if irr1.bit6 is set and the TCA is lower than the save value I know I probably wrapped within the handler.

Anyone else have some suggestions?

Thanks

Interrupt priority is almost a non factor on the Hitachi. There is an order of priority but the only time it is taken into account is if two ints trigger almost simultaneously. The int with the lower int number(see hitachi hardware manual) wins. Most of the time you will not run into this problem. What you will run into is the fact that the interrupt system disables all other interrupts while processing an interrupt.

So if you are in your WKP int for a long time you can cause the overflow int to trigger late. If you are in the WKP int long enough you could even loose an OVF int all together(because another OVF triggered before the first was processed). Your workaround is almost what I suggest.

Instead re-enable ints when you enter the WKP int handler(s) so if it does over flow while in the WKP int you will jump to the OVF int to handle the overflow. I haven’t tried this with your code but it should work.

Use the Enable command without araguments to re-enable all ints. You may also try just re-enabling the OVF int. I don’t know if that will work but it’s the better option. If you re-enable all ints you could get run over by other WKP ints being triggered.

Thanks Nathan,

That is what I thought about the Hitachi, I did read that they are prioritized by vector order and WKP has a slightly higher priority then the timer overflow. I will try reenabling the interrupts in the function as I am not concerned about WKP interrupts stacking up. They are coming up sequentially with the servo cooresponding pulse width time difference between them.

Once I get that to work, I may for the fun of it try and see if the ONASMINTERRUPT works for the timer overflow.

Thanks again