| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| benoitstjean 
 
 
 Joined: 30 Oct 2007
 Posts: 590
 Location: Ottawa, Ontario, Canada
 
 
			    
 
 | 
			
				| PIC24EP512 - Disable interrupt within its own interrupt |  
				|  Posted: Tue Feb 16, 2021 8:05 pm |   |  
				| 
 |  
				| Compiler: 5.026 Device: PIC24EP512GP806
 
 Hi all,
 
 I realize this is probably a redundant / common question and I will admit I feel like an amateur asking this because I know I've read about this topic elsewhere but searching this forum returns way too many results (and my patience is growing thin). Anyhow....
 
 This is my interrupt routine:
 
 
  	  | Code: |  	  | #INT_RDA LEVEL=7 void My_RDA_Interrupt( void )
 {
 // Code here
 }
 | 
 
 When the interrupt is entered, should I call disable_interrupts( INT_RDA ); and just before exiting, call enable_interrupts( INT_RDA ); like this:
 
 
  	  | Code: |  	  | #INT_RDA LEVEL=7 void My_RDA_Interrupt( void )
 {
 disable_interrupts( INT_RDA );
 
 // Code here
 
 enable_interrupts( INT_RDA );
 }
 | 
 
 Is there any value in doing this? Or is it just redundant code because it is already done internally (sorry, I don't speak assembly language)?
 
 In other words, when any interrupt occurs, is _that_ interrupt automatically disabled when the code jumps into the ISR and re-enabled when the ISR is exit? Or is this something I must manage?
 
 Thanks.
 
 Ben
 |  |  
		|  |  
		| newguy 
 
 
 Joined: 24 Jun 2004
 Posts: 1924
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Feb 16, 2021 8:52 pm |   |  
				| 
 |  
				| Putting in the extra disable and then enable interrupt is redundant because while the ISR is being executed, that particular interrupt can't be interrupted again by that same source (RDA in your example). If you have a processor that supports interruptible interrupts, and you don't want a particular higher priority interrupt to be able to interrupt a lower priority interrupt, then you can add code like you've shown to prevent that. 
 The confusing part is the hidden code the compiler automatically adds for each interrupt to clear that interrupt.
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19967
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Feb 17, 2021 1:55 am |   |  
				| 
 |  
				| It is both simpler and more complex than you may think. 
 By default, the compiler does not clear the interrupt till you exit the handler.
 There is no 'stacking' of interrupt bits, so the already set bit can't get
 set again while you are in the handler.
 
 Now there are situations, where you might deliberately 'want' to let the
 interrupt become set again. This is handled by coding like:
 
  	  | Code: |  	  | #INT_RDA CLR_FIRST
 void My_RDA_Interrupt( void )
 {
 //handler code
 }
 
 | 
 This then clears the interrupt at the entry point to the handler. With this,
 the interrupt can become triggered again. Normally you would want this,
 if you wanted to ensure an event cannot be missed. However on the
 PIC16/18 you then need to be careful, since in fact the RDA interrupt
 cannot actually be cleared, until the character has been read. So on these
 chips you instead have to behave like:
 
  	  | Code: |  	  | #INT_RDA NOCLEAR
 void My_RDA_Interrupt( void )
 {
 chr=getc(); //physically get the character
 clear_interrupt(INT_RDA); //then immediately clear the interrupt
 //now the rest of the handler code
 }
 
 | 
 
 So here, you physically handle the 'event' (get the character), 'ASAP', and
 clear the interrupt just one instruction later, which then allows the
 interrupt to trigger again after this point.
 Now the interrupt bit being set at the exit of the routine, then simply means
 that the routine will then be called again. Throughout the handling, the
 physical chip hardware 'makes sure' an interrupt cannot be called inside
 itself. On the PIC16/18, as soon as an interrupt is called the GIE bit
 (for the applicable 'level' on the PIC18), gets turned off when an interrupt
 is called, and is not re-enabled until the RETFIE at the end of the handler.
 On the PIC24/30/33, it is instead handled by the processor priority
 mechanism. An interrupt can only interrupt code that is at a lower priority
 level than the CPU is currently running. The normal CPU code is level0.
 Note the 'lower', not 'equal'. This is why if you assign an interrupt to
 level0, it is effectively disabled, since it can never actually interrupt
 anything. Now in your interrupt at level7, it can only be interrupted by
 trap events (so things like address errors), not by any other user interrupt
 (since they will all be 'below' this level), including itself, since the level
 is the same.
 
 There is though another 'caveat' here.
 In the PIC24/30/33, there is a character buffer for the RDA event,
 that is several characters deep. The interrupt will not re-trigger if
 another character arrives in the buffer before an existing character
 is read. So on these, the RDA handler needs to be coded as:
 
 
  	  | Code: |  	  | #INT_RDA
 void character(void)
 {
 uint16_t chr;
 //receive characters from serial
 do
 {
 chr=fgetc(RDAROURCE); //whatever your stream name is
 //your handler code to save character here
 } while (kbhit(RDAROURCE));
 }
 
 | 
 
 Otherwise characters can gradually build in the receive hardware buffer.
 |  |  
		|  |  
		| benoitstjean 
 
 
 Joined: 30 Oct 2007
 Posts: 590
 Location: Ottawa, Ontario, Canada
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Feb 18, 2021 1:11 pm |   |  
				| 
 |  
				| Fair enough, thanks for the detailed info, I will look into it. 
 Cheers,
 
 Ben
 |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |