| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| joshkeys 
 
 
 Joined: 16 Aug 2005
 Posts: 37
 Location: Fredericton,NB
 
 
			        
 
 | 
			
				| Understanding ASM Interrupt setup |  
				|  Posted: Tue Dec 12, 2006 8:02 pm |   |  
				| 
 |  
				| Hi there, I am using a PIC12F675 and have set up an interrupt via the timer 0 overflow. After compiling the program, I was going through the ASM code used to implement the interrupt and am a little confused by a few of the lines as below. 
 
  	  | Code: |  	  | .
 .
 .
 0004:  BTFSC  03.5
 0005:  GOTO   00A         (1)
 0006:  MOVWF  22
 0007:  SWAPF  03,W        (2)
 0008:  MOVWF  23
 0009:  GOTO   00F
 000A:  BCF    03.5
 000B:  MOVWF  22
 000C:  SWAPF  03,W        (2)
 000D:  MOVWF  23
 000E:  BSF    23.1        (3)
 000F:  MOVF   0A,W
 0010:  MOVWF  27
 0011:  CLRF   0A
 0012:  BCF    03.7
 0013:  SWAPF  22,F        (2)
 0014:  MOVF   04,W
 0015:  MOVWF  24
 0016:  MOVF   20,W
 0017:  MOVWF  25
 0018:  MOVF   21,W
 0019:  MOVWF  26
 .
 .
 .
 (Code goes on to check for what interrupt was activated and go to the appropriate ISR, and then when returned from it to reload all of the registers to there original state)
 
 | 
 
 (1) So first of all, the starting code seems like a waste of memory. It checks to see if the bank is set to 0 or 1, and does the nearly the same operation for either case (The exception being my third question). Would it not be more feasible to just set the bank to 0 and then proceed instead of setting up 2 scenarios.
 
 
 (2) Basically the status register in 2 cases and W registeris in one case are copied to a temporary interrupt register, but the LSB and MSB are swapped. I cannot seem to make sense of this. Can anyone explain why this is done, i am probably staring right at the answer, but am not sure.
 
 
 (3) For some reason, bit 1 of the temporary register is set. The register contains the swapped bits of the status register.
 
 
 Thanks for any help in advanced!
 
 Thanks,
 Josh Keys
 |  |  
		|  |  
		| ckielstra 
 
 
 Joined: 18 Mar 2004
 Posts: 3680
 Location: The Netherlands
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Dec 13, 2006 6:49 am |   |  
				| 
 |  
				| (2) Using the swap instruction is a common used trick in PIC assembly for copying register contents without modifying the status register flags. 
 (1) What is happening here is that the Working and Status registers are saved for restoration at the interrupt end. A chicken and egg problem is that you will modify the W-register when saving the status register, but the W-register can only be saved to a known location by selecting the correct memory bank in the Status register first. The CCS solution is to enter different code paths, one for each bank register bit.
 
 Maybe other solutions are possible but I don't see an obvious one.
 
 Note: Data of the status register is saved with the two nibbles swapped, but for temporary data storage this is no problem. At the end of the interrupt handler the register is restored using a swap instruction again.
 
 (3) In (1) the status of the bank select register was memorized by splitting the program flow in two almost identical sections. Here in (3) the bank select bit is finally written to the saved status register.
 |  |  
		|  |  
		| joshkeys 
 
 
 Joined: 16 Aug 2005
 Posts: 37
 Location: Fredericton,NB
 
 
			        
 
 | 
			
				| Thanks |  
				|  Posted: Wed Dec 13, 2006 10:13 am |   |  
				| 
 |  
				| It all makes sense now.. I guess I overlooked that you need to also save the status of the bank you were at when going to an interrupt, hence the need for 2 cases. And the swap thing just threw me for a loop.. clever little trick, easy once you know why they use it  Thanks for the help! It drives me crazy when I cannot understand why something was done! 
 Josh Keys
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Dec 13, 2006 10:17 am |   |  
				| 
 |  
				| This may be helpful to you.   Back in May 2000 on the old CCS board, Stefan Daystrom wrote up an explanation of how the CCS interrupt
 dispatcher code works.   It used to be in the old archives, but I think
 they've been taken down.   However I kept a copy on my local machine,
 and I've re-posted it below.   The code is not exactly the same as the
 modern compiler code, but his explanations should still help you.
 
 For each section of code, his explanation is posted below the code.
 It starts off with someone asking a question about the CCS interrupt
 dispatcher code:
 
  	  | Quote: |  	  | I have to write a In Service Routine as fast as possible for PIC16C74B.
 I tried to use the #INTxxx directive but it generated a long code at
 address 0004. This code is too long for my application. For this reason
 I have to use the #INT_GLOBAL directive, but I am afraid about it.
 Have anybody used this directive ?
 
 I tried to understand the code generate by #INTxxx directive to use in
 my Global In Service Routine, but some lines seem without meaning.
 Why is this code so long ?   Can anybody explain this code ?
 
 | 
 Yes. Look below for interspersed comments:
 
 Code generated at address 0004 using the #int_rda directive
 before the ISR:
 
  	  | Code: |  	  | : 0004 1D8A 00005 BTFSS 0A,3 : 0005 120A 00006 BCF 0A,4
 : 0006 198A 00007 BTFSC 0A,3
 : 0007 160A 00008 BSF 0A,4
 | 
 Backs up the one bit of PCLATH that matters on
 a PIC16C74 to an unused bit of PCLATH (for now).
 
 
 
  	  | Code: |  	  | : 0008 118A 00009 BCF 0A,3
 | 
 Clears the one used bit of PCLATH, since we're on page 0.
 
 
 
  	  | Code: |  	  | : 0009 1A83 00010 BTFSC 03,5
 : 000A 280F 00011 GOTO 00F
 : 000B 00A5 00012 MOVWF 25
 : 000C 0E03 00013 SWAPF 03,W
 : 000D 00A6 00014 MOVWF 26
 : 000E 2814 00015 GOTO 014
 : 000F 1283 00016 BCF 03,5
 : 0010 00A5 00017 MOVWF 25
 : 0011 0E03 00018 SWAPF 03,W
 : 0012 00A6 00019 MOVWF 26
 : 0013 14A6 00020 BSF 26,1
 | 
 Saves the W and STATUS registers in a tricky way
 that's a bit differnt from Microchip's suggested
 way (in "Context Saving During Interrupts" in the
 PIC16C6X or PIC16C7X data book). The compiler
 does it this way to save RAM over Microchip's
 way, at the expense of a little more ROM used.
 Microchip's way requires knowing that the place
 where W is saved is one of several addresses in
 the same relative place in every available bank;
 since the compiler doesn't allocate memory that
 way, Microchip's way would be incompatible with
 compiler use, so you'd have to use the same
 method that the compiler is using here.
 
 
 
  	  | Code: |  	  | : 0014 080A 00021 MOVF 0A,W
 : 0015 00AD 00022 MOVWF 2D
 | 
 Backs up PCLATH for real.
 
 
 
  	  | Code: |  	  | : 0016 0EA5 00023 SWAPF 25,F
 | 
 Swaps the nibbles of the saved W, so that it
 can restore it later with a single 'SWAPF 25,W'
 instruction that won't disturb the STATUS register.
 
 
 
  	  | Code: |  	  | : 0017 0804 00024 MOVF 04,W
 : 0018 00A7 00025 MOVWF 27
 | 
 Backs up the FSR.
 
 
 
  	  | Code: |  	  | : 0019 0820 00026 MOVF 20,W
 : 001A 00A8 00027 MOVWF 28
 : 001B 0821 00028 MOVF 21,W
 : 001C 00A9 00029 MOVWF 29
 : 001D 0822 00030 MOVF 22,W
 : 001E 00AA 00031 MOVWF 2A
 : 001F 0823 00032 MOVF 23,W
 : 0020 00AB 00033 MOVWF 2B
 : 0021 0824 00034 MOVF 24,W
 : 0022 00AC 00035 MOVWF 2C
 | 
 Backs up compiler temporary variables.
 How many there are can vary as you add things to
 the program. If you were doing the #INT_GLOBAL,
 you'd have to figure out yourself what temporary
 variables the C code used in your interrupt
 might be using by very carefully analyzing the
 generated assembly of all code explicitly or
 implicitly called from your C interrupt code,
 and back those up. And, of course, make sure
 you allocated the variables you back up into so
 that no C memory allocation can clobber them.
 
 
 
  	  | Code: |  	  | : 0023 1283 00036 BCF 03,5
 | 
 We're already in RAM bank 0, so the above line
 seems unnecessary (unless something not shown
 here can to a GOTO 023).
 
 
 
  	  | Code: |  	  | : 0024 1E0B 00037 BTFSS 0B,4
 : 0025 2828 00038 GOTO 028
 : 0026 188B 00039 BTFSC 0B,1
 : 0027 2840 00040 GOTO 040
 | 
 If INTE is FALSE or INTF is FALSE (both in INTCON),
 there's no interrupt, so drops down to 0028 below.
 Otherwise it branches to the last bit of
 interrupt initialization at 0040.
 
 
 Upon completion of interrupt code, it starts
 returning from interrupt here:
 
  	  | Code: |  	  | : 0028 0827 00041 MOVF 27,W
 : 0029 0084 00042 MOVWF 04
 : 002A 0828 00043 MOVF 28,W
 : 002B 00A0 00044 MOVWF 20
 : 002C 0829 00045 MOVF 29,W
 : 002D 00A1 00046 MOVWF 21
 : 002E 082A 00047 MOVF 2A,W
 : 002F 00A2 00048 MOVWF 22
 : 0030 082B 00049 MOVF 2B,W
 : 0031 00A3 00050 MOVWF 23
 : 0032 082C 00051 MOVF 2C,W
 : 0033 00A4 00052 MOVWF 24
 : 0034 082D 00053 MOVF 2D,W
 : 0035 008A 00054 MOVWF 0A
 : 0036 1A0A 00055 BTFSC 0A,4
 : 0037 158A 00056 BSF 0A,3
 : 0038 120A 00057 BCF 0A,4
 : 0039 0E26 00058 SWAPF 26,W
 : 003A 0083 00059 MOVWF 03
 : 003B 1283 00060 BCF 03,5
 : 003C 0E25 00061 SWAPF 25,W
 : 003D 18A6 00062 BTFSC 26,1
 : 003E 1683 00063 BSF 03,5
 | 
 The above restores all the stuff that was backed
 up above. Exactly how is left as user exercise. :)
 
 
 
  	  | Code: |  	  | : 003F 0009 00064 RETFIE | 
 The actual return from interrupt instruction.
 
 
 The code below was jumped to from 0027 above:
 
  	  | Code: |  	  | : 0040 118A 00065 BCF 0A,3 | 
 For the GOTO 040 at 0027 to have worked, bit 3
 of PCLATH would already have to be clear, so why
 is it being recleared here? :)
 
 
 
  	  | Code: |  	  | : 0041 286A 00066 GOTO 06A | 
 Goes off to run the C code you wrote in the
 interrupt.
 
 
 In summary: There are only two instructions
 that seem totally unnecessary above. Then
 depending on your specific interrupt code,
 perhaps not ALL the stuff that's being backed
 up would need to be backed up, but you'd have
 to careful analysis to make sure of that. Besides
 some of the C temporary variables, the most
 likely register it backs up that MIGHT not be
 used in your interrupt code is FSR.
 
 But unless you can get rid of quite a few
 temporary variables from being in need of backup,
 I don't see a whole lot of tightening up of this
 code you could do if your ISR is going to be
 written in C. If you write it ALL in assembler
 and can therefore make sure it doesn't use ANY
 of C's temporary varilabes, doesn't use PCLATH,
 doesn't use FSR, etc, only THEN can you shave
 it down quite a bit...
 |  |  
		|  |  
		| joshkeys 
 
 
 Joined: 16 Aug 2005
 Posts: 37
 Location: Fredericton,NB
 
 
			        
 
 | 
			
				| Thanks |  
				|  Posted: Thu Dec 14, 2006 1:01 pm |   |  
				| 
 |  
				| Thanks PCM Programmer, excellent resource. 
 Josh
 |  |  
		|  |  
		|  |  
  
	| 
 
 | 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 vote in polls in this forum
 
 |  
 Powered by phpBB © 2001, 2005 phpBB Group
 
 |