BasicMicro - Forums

www.basicmicro.com
It is currently Mon May 21, 2012 8:07 pm

All times are UTC - 8 hours [ DST ]




Post new topic Reply to topic  [ 9 posts ] 
Author Message
 Post subject: Interrupts, timmers and tasks
PostPosted: Tue Nov 01, 2011 2:05 pm 
Offline
Master

Joined: Sun Oct 05, 2008 9:40 am
Posts: 111
My plan is the following:

Send gps data string 1 per second
Send telemetry data string 1 per second but .5 s after gps string
Sample and intergrate accel at 100 Hz

To send the data I must first aquire the data. The data will be aquired through tasks like in the above example. Each task will clear the currentstate var and if required set the new state. Every 500ms the interrupt will set currentstate to start processing the data needed for the relevant string.

During downtime the imu FIFO will be transfered to eeprom if data exists

One problem I foresee is that gps uses bitbang serial wich means I have to disable interrrupts once per second for around 23ms. This will cause a problem when intergateing accel as it is dependant on a time factor.

One possable solution being to manually set the time factor at this point. (example timestep = timestep + .023). Or is it possable to set a timmer to actually time how long the interrups where disabled.


Top
 Profile  
 
 Post subject: Re: Interrupts, timmers and tasks
PostPosted: Tue Nov 01, 2011 2:09 pm 
Offline
Master

Joined: Sun Oct 05, 2008 9:40 am
Posts: 111
I have modified the interrupt example from the manual to help clarify and test this aproach

Code:
;calculates the number of interrupts per 1/100th of a second
;as a floating point constant.

interval fcon MHZ/100/256/128

CurrentState var byte         'Variable to hold current state flag
CurrentState = 0

flag1 var CurrentState.bit0      'Each flag aliased to bit of current state variable
flag2 var CurrentState.bit1
flag3 var CurrentState.bit2
flag4 var CurrentState.bit3
flag5 var CurrentState.bit4

StatePlusOne var byte         'Variable to hold state flag during interrupt
StatePlusOne = 0

counter var float         
counter = 0.0

milliseconds var long
milliseconds = 0

low p3      'Set starting state
low p4
low p5
low p6

TCRV0 = 0x03 ;Sets Timer V to count once every 128 OSC clocks
TCRV1 = 0x01

;Tells the processor where to jump to when the timer V
;overflow interrupt triggers.

ONINTERRUPT TIMERVINT_OVF,handler

ENABLE TIMERVINT_OVF ;enables the timer V overflow interrupt
ENABLE ;enables interrupts in general



while 1                           'If no tasks to perform program will sit in this while loop   
   
      
      'This will become task routine to read and intergrate accel
               
      while flag3 = 1                  'Check if task needs to be done
      
         toggle p4                     'Do Task                                    
         CurrentState = StatePlusOne          'Current task complet set state back
         
      wend

      'Overall task is to turn leds on This is broken down into individual tasks
      'This is where gps data will be gathered and sent
      
      while flag1 = 1                  'Check if task needs to be done

         high p5                        'Do Task
         CurrentState = 0                'Current task complet clear state
         flag2 = 1                     'Set to next task
         
      wend

      while flag2 = 1                  'Check if task needs to be done

         high p3                        'Do Task
         CurrentState = 0               'Current task complet clear state
         
      wend

      'Overall task is to turn leds off. This is broken down into individual tasks
      'This is where telemetry data will be gathered and sent
      
      while flag4 = 1                  'Check if task needs to be done

         low p5                        'Do Task
         CurrentState = 0               'Current task complet set to next state
         flag5 = 1                     'Set to next task
         
      wend

      while flag5 = 1                  'Check if task needs to be done

         low p3                        'Do Task
         CurrentState = 0               'Current task complet set to next state
            
      wend
      
      'This will run when no other tasks are needed
      'This is where the IMU fifo will be read and saved to eeprom
      
      toggle p6                     'Default state or lowest priority task.
                                    'This gets done if there is nothing to do or once per cycle         
wend



handler
;this interrupt is executed once per 256*128 clock cycles

counter = counter + 1.0                  
                                 'Interrupt needs to be processed first so the current state gets postponed
stateplusone = currentstate                  'This is done by setting stateplusone to the current state                                 
                                 
if(counter>interval)then               'Will trigger task at 100 HZ

   counter=counter-interval
   milliseconds = milliseconds + 10   
   flag3 = 1
   
else

   if(milliseconds = 500)then               'Will Set leds low for .5 sec
      currentstate = 0
      flag1 = 1

   elseif (milliseconds >= 1000)            'Will Set leds high for .5 sec
      currentstate = 0
      flag4 = 1
      milliseconds = milliseconds - 1000
      
   endif

endif

resume


The led on p3 is dependent on its task being set buy that of another task so as long as the exicution time of the accumulated tasks is less than 500ms this should be fine.

Suggestions and comments please.


Top
 Profile  
 
 Post subject: Re: Interrupts, timmers and tasks
PostPosted: Tue Nov 01, 2011 5:42 pm 
Offline
Site Admin
User avatar

Joined: Thu Mar 01, 2001 11:00 am
Posts: 903
Location: Temecula, CA
You could setup a timer interrupt that only handles time and then to make it have the least impact you could us an ONASMINTERRUPT instead of a basic ONINTERRUPT. This could bring down your timing interrupt int as little as 40 or 50 instruction cycles so you wouldn't ever need to turn it off.

You could also time how long your interrupts are off as long as they are off no long than the time it would take to overflow the timer register. But you get into complications if you also wan to use that same timer for interrupts9Have to save the current value, clear the timer register, turn off interrupts, execute the serin, then reset the timer register to the previous value+time used when interrupts were off, re-enable interrupts, and if there would have been an over flow during the interrupt off time, for the interrupt handler to fire...

It gets complicated. :)

_________________
Tech Support
Basic Micro - Robotic Technology Evolved


Top
 Profile  
 
 Post subject: Re: Interrupts, timmers and tasks
PostPosted: Tue Nov 01, 2011 7:25 pm 
Offline
Master

Joined: Sun Oct 05, 2008 9:40 am
Posts: 111
Quote:
You could setup a timer interrupt that only handles time and then to make it have the least impact you could us an ONASMINTERRUPT instead of a basic ONINTERRUPT. This could bring down your timing interrupt int as little as 40 or 50 instruction cycles so you wouldn't ever need to turn it off.



So if the ISR is quick enough I do not need to disable interrupts to protect serin/serout serial? And to achieve this I need to implement an ONASMINTERRUPT and should only deal with keeping time?

So I should go back to something like this but in asm

Code:
handler
;this interrupt is executed once per 256*128 clock cycles

counter = counter + 1.0         
                                                                     
if(counter>interval)then               'Will trigger task at 100 HZ

   counter=counter-interval
   milliseconds = milliseconds + 10   
   flag3 = 1

endif

resume


Top
 Profile  
 
 Post subject: Re: Interrupts, timmers and tasks
PostPosted: Tue Nov 01, 2011 7:53 pm 
Offline
Master

Joined: Tue Nov 21, 2006 9:34 am
Posts: 528
What I have found with interrupts, and serout/serin, that if you are doing any speeds > 9600 baud, any interrupt will for sure screw it up, if it happens at the wrong time. Even at 9600 baud it will screw it up from time to time. I have found this with even real simple interrupts.

I am not sure which processor you are using, but if I assume a BAP40/Arc32/Bap64 which runs at 20mhz, I believe your TimerV will overflow about 610 times per second, which is about 6 times faster than you want... You could use TimerB1 and divide the clock by 256 or 512 instead if you wish to reduce this... down some more...

In the phoenix code we don't need a very high resolution for the timer, so I use the TimerA or TimerB1 depending on processor and I do a divide by 8192, so we only need to process about 9.5 interrupts per second. With that it is easy to setup the code to disable the interrupt just before a serout and reenable it after and know I won't lose anything. I also have some simple functions that grab the current clock time and then later grab the clock again and see if the delta exceeds some delta...

Example for Bap28:
Code:
;====================================================================
lTimerCnt         var long   

;--------------------------------------------------------------------
;[TIMER INTERRUPT INIT]
TIMERINT   con   TIMERAINT
ONASMINTERRUPT TIMERAINT, HANDLE_TIMERA_ASM

;--------------------------------------------------------------------
;[InitServoDriver] - Initializes the servo driver including the main timer used in the phoenix code
InitTimer:
;Timer
; Timer A init, used for timing of messages and some times for timing code...
  TIMERINT   con   TIMERAINT

  WTIMERTICSPERMSMUL con 64   ; BAP28 is 16mhz need a multiplyer and divider to make the conversion with /8192
  WTIMERTICSPERMSDIV con 125  ;
  TMA = 0   ; clock / 8192               ; Low resolution clock - used for timeouts...
  ENABLE TIMERINT
return

;==============================================================================
;[Handle_Timer_asm] - Handle timer A overflow in assembly language.  Currently only
;used for timings for debuging the speed of the code
;Now used to time how long since we received a message from the remote.
;this is important when we are in the NEW message mode, as we could be hung
;out with the robot walking and no new commands coming in.
;==============================================================================
BEGINASMSUB
HANDLE_TIMERA_ASM
   push.l    er1                  ; first save away ER1 as we will mess with it.
   bclr    #6,@IRR1:8               ; clear the cooresponding bit in the interrupt pending mask
   mov.l    @LTIMERCNT:16,er1      ; Add 256 to our counter
   add.l   #256,er1
   mov.l    er1, @LTIMERCNT:16
   pop.l    er1
   rte
ENDASMSUB

return      ; Put a basic statement before...
;==============================================================================
;[GetCurrentTime] - Gets the Timer value from our overflow counter as well as the TCA counter.  It
;                makes sure of consistency. That is it is very possible that
;                after we grabbed the timers value it overflows, before we grab the other part
;                so we check to make sure it is correct and if necessary regrab things.
;==============================================================================
GetCurrentTime:
  lCurrentTime = lTimerCnt + TCA
   
  ; handle wrap
  if lTimerCnt <> (lCurrentTime & 0xffffff00) then
   lCurrentTime = lTimerCnt + TCA
  endif

return lCurrentTime
;-------------------------------------------------------------------------------------
;[ConvertTimeMS]
_ttconv   var   long
ConvertTimeMS[_ttconv]:
   return (_ttconv * WTIMERTICSPERMSMUL)/WTIMERTICSPERMSDIV



Usage is pretty easy:
Code:
  'Start time
  GOSUB GetCurrentTime[], lTimerStart
...
      GOSUB GetCurrentTime[], lTimerEnd   
      GOSUB ConvertTimeMS[lTimerEnd-lTimerStart], CycleTime

Could simplify this some more... The Bap40/64 versions are about the same, except some of the register names changes...
TCA -> TCB1...

Also the Conversion factor constants change:
Code:
  WTIMERTICSPERMSMUL con 256   ; Arc32 is 20mhz need a multiplier and divider to make the conversion with /8192
  WTIMERTICSPERMSDIV con 625  ;


Hope that helps
Kurt


Top
 Profile  
 
 Post subject: Re: Interrupts, timmers and tasks
PostPosted: Wed Nov 09, 2011 7:10 am 
Offline
Master

Joined: Sun Oct 05, 2008 9:40 am
Posts: 111
Help it does.

How are you deriving the conversion factor constants?


Top
 Profile  
 
 Post subject: Re: Interrupts, timmers and tasks
PostPosted: Wed Nov 09, 2011 7:25 am 
Offline
Master

Joined: Tue Nov 21, 2006 9:34 am
Posts: 528
The constants.
On the Bap28 running at 16mhz, there are:
16000000/1000= 16000 clock cycles per ms. The timer is incrementing every 8192 clock cycles

16000/8192 = 2000/1024 = 250/128 = 125/64

You do the same for Bap40 or Arc32, except that it runs at 20mhz
20000/8192.... = 625/256 (which makes sense as 20/16 = 5/4)...

Kurt


Top
 Profile  
 
 Post subject: Re: Interrupts, timmers and tasks
PostPosted: Wed Nov 09, 2011 5:47 pm 
Offline
Master

Joined: Sun Oct 05, 2008 9:40 am
Posts: 111
Code:
ONASMINTERRUPT TIMERVINT_OVF, HANDLE_TIMERVINT_ASM


When I try this I get unknown command in referance to TIMERVINT_OVF. I can get timer V to work with a basic interrupt but not an asm int.


Top
 Profile  
 
 Post subject: Re: Interrupts, timmers and tasks
PostPosted: Wed Nov 09, 2011 6:03 pm 
Offline
Master

Joined: Tue Nov 21, 2006 9:34 am
Posts: 528
With Basic interrupts, the basic subsystem takes care of figuring out what caused the interrupt. That is with TimerV, there are actually 3 different interrupt conditions (overflow, CMEA, CMEB). These all use the same interrupt vector on the processor and the system checks to see which one caused the interrupt.

In ASM you have to do this yourself.

So: the proper syntax is:
Code:
ONASMINTERRUPT TIMERVINT, HANDLE_TIMERVINT_ASM


So from an extract of some code I have in the DIY transmitter...
Code:
BEGINASMSUB
TASOIHANDLER:
   push.w   r3               ; save away...
   push.w   r2                ; first save away registers we will touch
   push.w   r1               ;
   
   bclr.b   #6, @TCSRV:8      ; clear out the interrupt bit so it can happen again
;   andc   #0x7f,ccr               ; allow other interrupts to happen while processing this one???

... ; then at the end...
   
   pop.w   r1               ; restore back the registers we used to the caller
   pop.w   r2
   pop.w   r3

   rte                     ; and return from the exception.

ENDASMSUB


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC - 8 hours [ DST ]


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group

phpBB SEO