HINT1 and Timer overflow 20x2

ol boy

Member
I built a 4R70W Ford transmission controller a few years back and its been working flawlessly. Using a 20x2, measuring input pulses from a speed sensor over a set amount of time. That time give me a 1 to 1 ratio for pulses to MPH. On 2 occasions the controller locked up and defaulted in what ever the last gear was, 4th gear so far. The only thing I can think of that would cause to code to stop running the main loop is if it get stuck in the interrupt routine. What happens if the timer overflow happens while the interrupt routine in servicing an input pulse or both an input pulse and timer overflow happen within the same machine cycle?

I've include just the header info and the interrupt routine. Is there a better way to read the input pulses and have the timer overflow flag capture the time?

thanks Ryan

Code:
'4R70W beta3.5.4bt  PIXACE 20x2   6 Aug, 2014 ((1243 bytes flash), 38 bytes of RAM, 7 bytes PROM)
eeprom 0, (1,255,2,1,3,182,3)  '511,513,950,3  
setfreq m8					'set ferq to 8MHz
let dirsc = %00110000			'set portC as inputs C.5 PWM output
let dirsb = %11111110               'set portB as outputs, B.0 HINT input
let adcsetup = %0000001000000000	'set ADC ports 9,  c.1
hintsetup %00000010	'falling egde trigger on B.0 input
setintflags or %10000010, %10000010  'hardware interrupt INT1, Timer over flow flag 
hsersetup b115200_8, %00001		'enable serial io for bluetooth coms background receive %00001
hpwm pwmdiv16, 0, 0, %0010, 249, 250		'500 hz 50% = 500 1000 = 100%

'*******INTERRUPT ROUTINE********************************
interrupt:
if toflag = 1 then			'check if interrupt was caused by toflag.
  	settimer off			'turn off timer
  	mph = w15				'load w15 to MPH
  	let w15 = 0				'clear w15 value to zero
  	let toflag = 0   			'clear over flow flag
  	
elseif w15 = 0 then			'on first hardware input w15 will still be zero
	inc w15				'increment w15
	let hint1flag = 0	 		'clear hardware flag
	let timer = 65535			'preloads timer to overflow and set toflag when minor ticks finish counting
  	settimer 54535			'enable timer 0.352 seconds
else
	inc w15				'increment w15 
	let hint1flag = 0	 		'clear hardware flag
endif

 setintflags or %10000010, %10000010  'hardware interrupt INT1, Timer over flow flag	
  return
 

PhilHornby

Senior Member
The only thing I can think of that would cause to code to stop running the main loop is if it get stuck in the interrupt routine. What happens if the timer overflow happens while the interrupt routine in servicing an input pulse or both an input pulse and timer overflow happen within the same machine cycle?
My interpretation of what happens, is: the interrupts get detected and 'remembered' by the Picaxe firmware as 'flags'; the Picaxe Basic ISR is called while ever any of the flags are set, once the 'return' is executed. So effectively, they get 'queued-up' and the ISR is called multiple times until it's dealt with them all. In this thread, I postulated that it's better to loop back to the despatcher and deal with all interrupt conditions before returning- especially if there are overheads such as PUSHRAM/POPRAM employed to free up variables to use in the ISR.

There doesn't seem to be any scope for getting stuck, in your existing ISR...but if 65536 consecutive Hint1s were to occur before the Timer overflowed, it could overflow your flag (W15) and start the Timer again. That scenario is probably highly unlikely ... but maybe it's just likely enough to occur once every few years ... or maybe it's 'noise' on the line?
 

inglewoodpete

Senior Member
I had an experience with interrupt lock-ups a few years when using a timer interrupt in a 28X2. I can suggest two areas where you could look for the source of your problem.

The first is how you handle timer interrupts. If the interrupt is caused by the Timer, then it is important to clear the TOFlag as soon as possible after entering the interrupt service routine, just in case it is set again before exiting the routine. Have a look at the discussion of my case here.

As Phil mentions above, the other source of spurious lockups is electrical noise. This noise could be sourced from both outside and within the PIC. Ensure you have suitable capacitance physically close to the chip power legs. Since almost all inputs have substrate protection diodes which connect to the power rails, ensure any connected to the vehicle's power have additional protection. Also, avoid using the PIC's Vpp programming pin (leg 4/pin C.6 on a 20X2) as an input since it does not have in-built over-voltage protection.
 

ol boy

Member
Thanks for the advice. I didn't know I could check for other interrupt flags while still in the ISR. I might have to add that to the ISR. I was trying to make the ISR as short as possible since I have a lot of stuff going on in the main loop and didn't want to slow it down too much. I have several shift delays and torque converter lock up delays using the main loop speed to increment a counter variable.

I wish in the 20x2 I could read the minor ticks in between hint1 inputs. I think that's only available in the 28x2. I wouldn't need a timer overflow flag at that point. Or if I did it would be used to detect a speed of zero as the minor ticks would count up to 65535 if the input pulses stopped.

Is there a better/shorter way to count the input pulses with in a set time frame and not slow up the main loop in the process? The count command kills me as it just sits there and counts for the time period.
 

inglewoodpete

Senior Member
Keeping an interrupt routine as short as possible is a good idea.

I don't think you can access the minor tick count on any PICAXE, unless it is available via an SFR (PeekSFR). It is just the external counter mode that is available on the 28X2 and 40X2.

Sometimes the simplest solution is to add an 08M2 dedicated to the counting/timing of pulses and providing the latest data to the main processor via a serial connection. I used that method to handle an anemometer while the main processor did the heavy lifting of number crunching and outputting DMX512 protocol at 250kbits/second.
 

hippy

Technical Support
Staff member
It can get tricky to work out what could be going wrong when there is a complicated code with multiple internal and software interrupts all happening together. Especially if the problem only manifests itself 'once in a blue moon'. Issues which are consistent, easily and frequently repeatable are much easier to track down.

It is often hard to even tell where the problem may lie, whether it is the interrupt routine locking up ( though like PhilHornby I cannot see any reason that would happen ), or somewhere else, some unusual combination which causes or prevents something which cascades to becoming a bigger problem.

In this case it might not be the interrupt routine, but perhaps something to do with background serial handling, though that's only a guess. The problem is that without the full code it is difficult to say, and the full code is probably too complicated to analyse without being intimately familiar with it.

There are things one could perhaps do; check the 'w15' in the interrupt to see if it is getting higher than expected and reset the timer to get things back into kilter - though that assumes it's a missing timer interrupt which it may not be.

One could forego the timer interrupt, just use the HINT interrupt, and check the 'timer' value before deciding if the interrupt should increment 'w15' or should cause a reset/restart of the timer. The fewer interrupts there are the less likely conflicts could occur.

The following counts button pushes via HINT1 during a 5 second period on a 28X2 and it could probably be modified for your own counting -

Code:
#Picaxe 28X2
#Terminal 9600

; HINT1 = leg 22, B.1 on 28X2

Symbol TIMEOUT  = 5                ; Count for 5 seconds

Symbol irqCount = w0
Symbol nowCount = w1
Symbol newFlag  = w2

PowerOnReset:
  HintSetup %00000010              ; HINT1
  timer = TIMEOUT + 1              ; Force timer reset in next loop
  Do
   If newFlag = 0 Then
     If timer > TIMEOUT Then
       SetIntFlags OFF
       Gosub Interrupt
     End If
   Else
     newFlag = 0
     SerTxd( #nowCount, " " )
    End If
  Loop

Interrupt:
  if timer < TIMEOUT Then
    inc irqCount
  Else
    SetTimer OFF
    nowCount = irqCount
    irqCount = hint1Flag
    timer = 0
    SetTimer T1S_8
    newFlag = 1
  End If
  hint1flag = 0
  SetIntFlags %00000010, %00000010 ; Interrupt on HINT1
  Return
 

ol boy

Member
So I can check for a timer overflow without using the interrupt? Enter the routine with if toflag = 0 then, Inc w15, ..... else if, set timer to 65535, ..... endif
 

ol boy

Member
In the main loop the program does an ADC sample of the throttle position sensor and we do math to create the zero to 100% range in 1% units, then we apply a slope formula against the MPH to find a calculated TPS value. If the measured TPS value falls below the calculated value we up shift to the next gear or down shift. Gears 2 and 3 each have 3 slopes, up shift, down shift and TCC lock up. 4th gear only has down shift and TCC lock up. 1st gear only has an up shift slope as there is no TCC lock up in 1st and you can't down shift lower than first. The serial input over bluetooth is actually bigger than the trans code it's self. As long as there isn't any data sitting in the scratch pad and the hserflag is zero, we skip right past that portion of code. I haven't used the serial input for nearly a year now.

So I came up with this.

Code:
'in the main loop I check to see if the vehicle speed is zero by looking for a toflag and timer looping up past a value of 1'
'car stopped for more than 1ish seconds, stop timer and wait until moving again.

if toflag = 1 and timer >= 1 then       'check for flag set and a timer running away
  mph = 0                                     ' zero out mph
  intcount = 0                               'zero out interrupt input counter
  settimer off                                'stop timer from running way
  let toflag = 0                              'reset toflag
  let timer = 65535 ' might not need to do this as it will get reloaded in the interrupt routine
endif 

'**********************interrupt*********************************
interrupt:
inc intcount                         'count entry into ISR as a hint1 input
if intcount = 1 then               'on first entry start timer
  let timer = 65535                'preload to 65535
  settimer = 54535                'preload to give 0.352 sec timer
elseif toflag = 1 then             'if timer has elapsed between interrupts then stop counting
  settimer off                        'stop timer
  mph = intcount                   'move intcount to mph
  intcount = 0                       'clear intcount
  let toflag = 0                      'clear toflag
endif

let hint1flag =  0                                  'reset the hint1 flag
setintflags %00000010, %00000010         'reset flags
return                                                'done
I hope this ISR provides a better mph value. I'll try to test it out this weekend.
Improvements or comments are welcomed.

Thanks Ryan
 

ol boy

Member
I finally got the new IRS flashed tonight. I'm happy to report that it's working! See how tomorrow morning goes.
 
Top