EmbeddedRelated.com
Forums

trouble understanding RETI instruction

Started by jack_e September 30, 2010
Hi

I am having trouble understanding RETI instruction. Being a novice at
MSP430 architecture, have begun exploring by writing simple snippets. I am
trying to blink a LED using a timer. I want to control the dutycycle of the
flashing. 
My query is that after exiting the ISR on RETI, which instruction does the
control flow go to. Have tried debugging via different methods but its
still unclear. Here is my code. PLzz help. 
;*****************************************************************************
            .cdecls C,LIST,"msp430x11x1.h" ; Include device header file

;*****************************************************************************
;----------------------------------------------------------------------------
            .text                           ; Progam Start
;-----------------------------------------------------------------------------
RESET       mov.w   #300h,SP                ; Initialize stackpointer
StopWDT     mov.w   #WDTPW+WDTHOLD,&WDTCTL  ; Stop WDT
SetupP1     bis.b   #04h,&P2DIR            ; P1.0 output
SetupC0     mov.w   #CCIE,&CCTL0            ; CCR0 interrupt enabled
            mov.w   #0ffffh,&CCR0            ;
SetupTA     mov.w   #TASSEL_2+MC_2,&TACTL   ; SMCLK, contmode
                                            ;						
    	bis.w   #CPUOFF+GIE,SR          ; CPU off, interrupts enabled
            nop 
;-----------------------------------------------------------------------------
TA0_ISR;    Toggle P1.0
;-----------------------------------------------------------------------------
            xor.b   #04h,&P2OUT             ; Toggle P1.0
           add.w   #10,&CCR0            ; Add Offset to CCR0
             reti     
;-----------------------------------------------------------------------------
;           Interrupt Vectors
;-----------------------------------------------------------------------------
            .sect   ".reset"                ; MSP430 RESET Vector
            .short  RESET                   ;
	    .sect   ".int09"                
            .short  TA0_ISR                
	    .end
 

	   
					
---------------------------------------		
Posted through http://www.EmbeddedRelated.com
On Thu, 30 Sep 2010 06:27:42 -0500, "jack_e"
<jaikishan.daryanani@n_o_s_p_a_m.gmail.com> wrote:

>Hi > >I am having trouble understanding RETI instruction. Being a novice at >MSP430 architecture, have begun exploring by writing simple snippets. I am >trying to blink a LED using a timer. I want to control the dutycycle of the >flashing. >My query is that after exiting the ISR on RETI, which instruction does the >control flow go to.
It goes to where it would have gone, had the interrupt not happened. When an interrupt occurs, the program counter (which is the address of the next instruction to be executed) is pushed onto the stack, followed by the status register. The interrupt code is executed and then, triggered by the RETI instruction, the status register and program counter are restored from the stack and execution continues. -- Rich Webb Norfolk, VA
On 30 Set, 13:27, "jack_e" <jaikishan.daryanani@n_o_s_p_a_m.gmail.com>
wrote:

> My query is that after exiting the ISR on RETI, which instruction does the > control flow go to. Have tried debugging via different methods but its > still unclear. Here is my code. PLzz help.
The Program Counter return to where it was before the ISR. To understand exactly what happens you have to read the datasheet of the MSP430. Bye Jack
On Thu, 30 Sep 2010 06:27:42 -0500, "jack_e"
<jaikishan.daryanani@n_o_s_p_a_m.gmail.com> wrote:

> My query is that after exiting the ISR on RETI, which > instruction does the control flow go to.
On the vague hope that this isn't homework, or that if it is you will still actually learn from the process and retain the answer, here is what happens: You are setting the processor to sleep (shutting it off.) Once that instruction is fetched, to be executed, the program counter (PC register, or R0) is set to the following instruction _before_ the CPU actually stops. So right then, the PC register points to the NOP instruction in your code. Then it stops. It just sits there, waiting. (Note that you've also set up the stack pointer, R0, to point into memory, too, and that the control bits that placed the CPU to sleep in the first place reside in the status register, R2.) So, you've got the stack pointer R1 pointing into RAM, the program counter R0 pointing at the NOP, and you've just changed the status register R2 so that the processor is forced to stopped running. However, the timer keeps on running. At some later point in time, the timer initiates an interrupt. When that happens, two registers, R0 and R2, are automatically added to the stack (which means that R1 is used as a memory pointer and automatically adjusted, as well.) Then the program counter, after having been saved onto the stack, is modified to the value located in the associated interrupt vector (you've added that with the 'short' pointer in your code and it resides in the flash memory) and the status register, R2, is modified so that the processor starts running, again. This causes the first instruction in the interrupt vector code to be executed. When that code gets to the RETI, it restores the values of R0 and R2 from the stack (where R1 points, modifying R1 also during this process.) R0 will now point back at the NOP instruction. However, since R2 was just restored and since the saved value has the old settings where you'd ordered the CPU asleep, the CPU stops running again and does NOT attempt to run the NOP. There it sits until the timer starts another interrupt event and the process repeats. Jon
> When that code gets to the RETI, it restores the values of R0 > and R2 from the stack (where R1 points, modifying R1 also > during this process.) R0 will now point back at the NOP > instruction. However, since R2 was just restored and since > the saved value has the old settings where you'd ordered the > CPU asleep, the CPU stops running again and does NOT attempt > to run the NOP. There it sits until the timer starts another > interrupt event and the process repeats. > > Jon
Are you sure? I am not familiar with MSP430, but i could imagine, that with the RETI it jumps to the nop and then runs again into the ISR routine, which surely is not wanted. With the next reti, it does something unknown or undefined. I would think, it should be somthing like the following: --------------------snip------------------------------------------------- Blub: ;Label for the jump bis.w #CPUOFF+GIE,SR ; CPU off, interrupts enabled nop jmp Blup ; endless loop to avoid running in the ISR ;----------------------------------------------------------------------------- TA0_ISR; Toggle P1.0 ;----------------------------------------------------------------------------- xor.b #04h,&P2OUT ; Toggle P1.0 add.w #10,&CCR0 ; Add Offset to CCR0 reti ;----------------------------------------------------------------------------- ----------------------snip----------------------------------- best regards Stefan
On Thu, 30 Sep 2010 15:45:39 +0200, Stefan Brr&#4294967295;ring
<stefan___@broering.de> wrote:

>> When that code gets to the RETI, it restores the values of R0 >> and R2 from the stack (where R1 points, modifying R1 also >> during this process.) R0 will now point back at the NOP >> instruction. However, since R2 was just restored and since >> the saved value has the old settings where you'd ordered the >> CPU asleep, the CPU stops running again and does NOT attempt >> to run the NOP. There it sits until the timer starts another >> interrupt event and the process repeats. >> >> Jon > >Are you sure? I am not familiar with MSP430, but i could imagine, that >with the RETI it jumps to the nop and then runs again into the ISR >routine, which surely is not wanted. ><snip>
I'm pretty sure, yes. Having written such code on the MSP430 and being somewhat familiar with the cpu. The code example I read, if I read it correctly, was probably working -- in so far that the interrupts operated without causing the PC register to run amok.
>With the next reti, it does >something unknown or undefined.
No, it works as I described it working. Fairly nifty. Jon
>I would think, it should be somthing like the following: ><snip>
Jon
On 09/30/2010 04:27 AM, jack_e wrote:
> Hi > > I am having trouble understanding RETI instruction. Being a novice at > MSP430 architecture, have begun exploring by writing simple snippets. I am > trying to blink a LED using a timer. I want to control the dutycycle of the > flashing. > My query is that after exiting the ISR on RETI, which instruction does the > control flow go to. Have tried debugging via different methods but its > still unclear. Here is my code. PLzz help. > ;***************************************************************************** > .cdecls C,LIST,"msp430x11x1.h" ; Include device header file > > ;***************************************************************************** > ;---------------------------------------------------------------------------- > .text ; Progam Start > ;----------------------------------------------------------------------------- > RESET mov.w #300h,SP ; Initialize stackpointer > StopWDT mov.w #WDTPW+WDTHOLD,&WDTCTL ; Stop WDT > SetupP1 bis.b #04h,&P2DIR ; P1.0 output > SetupC0 mov.w #CCIE,&CCTL0 ; CCR0 interrupt enabled > mov.w #0ffffh,&CCR0 ; > SetupTA mov.w #TASSEL_2+MC_2,&TACTL ; SMCLK, contmode > ; > bis.w #CPUOFF+GIE,SR ; CPU off, interrupts enabled > nop > ;----------------------------------------------------------------------------- > TA0_ISR; Toggle P1.0 > ;----------------------------------------------------------------------------- > xor.b #04h,&P2OUT ; Toggle P1.0 > add.w #10,&CCR0 ; Add Offset to CCR0 > reti > ;----------------------------------------------------------------------------- > ; Interrupt Vectors > ;----------------------------------------------------------------------------- > .sect ".reset" ; MSP430 RESET Vector > .short RESET ; > .sect ".int09" > .short TA0_ISR > .end >
_Always_, the action of an interrupt is to save enough of the processor state that you can run some sort of an ISR and then return in a way that _only_ disturbs the interrupted code by stealing some time from it. A processor that has an interrupt process that does not save all this necessary information (and it can be a startlingly small set, leaving much to the programmer), is known colloquially among engineers as "a @#$%ed up piece of *&%^", and if it happens to make it into silicon it doesn't make it onto the market. _Usually_ when the processor gets interrupted it finishes whatever instruction it's executing, then branches*. When it finishes the interrupt it returns to the instruction just after the one that was in process when the interrupt was noted. If I'm reading your code correctly, you do some set up, then you put the processor to sleep. When your interrupt happens the processor will be at the "bis.w" instruction, so it'll return to the nop. Since you're missing a loop instruction to branch back to the "bis.w" instruction, your code will then erroneously fall through to the ISR which will get executed, including the reti instruction. Since the various registers will at this point have obsolete or random values in them, the reti instruction will do Bad Things, and your code will go nuts. * In a pipelined processor, this used to mean that the pipeline gets flushed, at the cost of some execution time. This probably still happens unless the chip designer is insane. -- Tim Wescott Wescott Design Services http://www.wescottdesign.com Do you need to implement control loops in software? "Applied Control Theory for Embedded Systems" was written for you. See details at http://www.wescottdesign.com/actfes/actfes.html
On Thu, 30 Sep 2010 08:32:45 -0700, Tim Wescott
<tim@seemywebsite.com> wrote:

>When your interrupt happens the processor will be >at the "bis.w" instruction, so it'll return to the nop. Since you're >missing a loop instruction to branch back to the "bis.w" instruction, >your code will then erroneously fall through to the ISR which will get >executed, including the reti instruction.
Actually, no. The CPU control resides in the status register. The code uses an instruction, prior to the NOP, to turn off the CPU. When the interrupt takes place, this status register (and the cpu control bits) gets placed on the stack. The CPU is turned on and the interrupt serviced. However, when the RETI takes place, the status register is reloaded from the stack, changing the cpu control bits back to sleeping mode... on the NOP, again. It just stops, is all, and waits. It doesn't fall through. I can provide some (nearly identical) operating code that I've written for the MSP430, if you have an MSP430 system floating about and want to test the idea. Jon
> Since you're > missing a loop instruction to branch back to the "bis.w" instruction, > your code will then erroneously fall through to the ISR which will get > executed, including the reti instruction. Since the various registers > will at this point have obsolete or random values in them, the reti > instruction will do Bad Things, and your code will go nuts. >
Thats just the same, what i would believe as i mentioned in the other post. But i am not yet familiar with MSP430, just got the launchpad from TI. But Jon seam to be sure, that the processor will go back to sleep mode after the RETI before executing the nop. Best regards Stefan
Tim Wescott wrote:
> On 09/30/2010 04:27 AM, jack_e wrote: >> Hi >> >> I am having trouble understanding RETI instruction. Being a novice at >> MSP430 architecture, have begun exploring by writing simple snippets. >> I am >> trying to blink a LED using a timer. I want to control the dutycycle >> of the >> flashing. >> My query is that after exiting the ISR on RETI, which instruction does >> the >> control flow go to. Have tried debugging via different methods but its >> still unclear. Here is my code. PLzz help. >> ;***************************************************************************** >> >> .cdecls C,LIST,"msp430x11x1.h" ; Include device header file >> >> ;***************************************************************************** >> >> ;---------------------------------------------------------------------------- >> >> .text ; Progam Start >> ;----------------------------------------------------------------------------- >> >> RESET mov.w #300h,SP ; Initialize stackpointer >> StopWDT mov.w #WDTPW+WDTHOLD,&WDTCTL ; Stop WDT >> SetupP1 bis.b #04h,&P2DIR ; P1.0 output >> SetupC0 mov.w #CCIE,&CCTL0 ; CCR0 interrupt enabled >> mov.w #0ffffh,&CCR0 ; >> SetupTA mov.w #TASSEL_2+MC_2,&TACTL ; SMCLK, contmode >> ; >> bis.w #CPUOFF+GIE,SR ; CPU off, interrupts enabled >> nop >> ;----------------------------------------------------------------------------- >> >> TA0_ISR; Toggle P1.0 >> ;----------------------------------------------------------------------------- >> >> xor.b #04h,&P2OUT ; Toggle P1.0 >> add.w #10,&CCR0 ; Add Offset to CCR0 >> reti >> ;----------------------------------------------------------------------------- >> >> ; Interrupt Vectors >> ;----------------------------------------------------------------------------- >> >> .sect ".reset" ; MSP430 RESET Vector >> .short RESET ; >> .sect ".int09" >> .short TA0_ISR >> .end >>
[ snip ]
> If I'm reading your code correctly, you do some set up, then you put the > processor to sleep. When your interrupt happens the processor will be > at the "bis.w" instruction,
It is my understanding that the "bis.w" causes the MSP430 to enter the "LPM0" low-power mode, in which the program does not run (SR.CPUOFF is set). The PC is left pointing at the next instruction, the "nop". The "nop" is not executed, since the program does not run. If the processor can be said to "be" anywhere, it "is" at the "nop", since the PC points to the "nop". When the interrupt happens, the processor stores the PC and the SR (the status register) on the stack, clears the SR bits CPUOFF and GIE to let the program run and to disable interrupts, and enters the interrupt handler.
> so it'll return to the nop.
When the interrupt handler executes RETI, the processor pops the SR and PC off the stack. If the interrupt handler did not modify the stacked values, the processor goes back to LPM0 mode (program stopped) with the PC still pointing at the "nop". The "nop" is not executed. New interrupts can come in, and be handled, and the processor always returns to sleep at the "nop".
> Since you're > missing a loop instruction to branch back to the "bis.w" instruction, > your code will then erroneously fall through to the ISR which will get > executed, including the reti instruction.
For that to happen, the interrupt handler would have to change the stacked SR by turning off its CPUOFF bit, for example by "bic #CPUOFF,0(SP)". If that were done, the RETI would restore the PC to point at the "nop" and restore the SR with CPUOFF cleared, meaning that the processor would continue to execute from the "nop" (and fall through to the ISR in this code). Changing the stacked SR is the normal way to make a sleeping MSP40 program wake up after an interrupt, but of course the resumption point should then contain some useful code, and not be as in the OP's case. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .