This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

trouble undertanding RETI instruction



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

  • Jaikishan,

    The RETI command will go back to your program from where it was before it was interrupted. In your example the processor isnt doign anything before it is waken up by the timer ISR. I have modified the code a bit, and you can now set a break point and follow the program flow from the RETI command.

    Take a look at the modified example:

     

     

    .text ; Program Start

    ;------------------------------------------------------------------------------

     

     

    RESET

     

    mov.w #0280h,SP ; Initialize stackpointer

    StopWDT

     

    mov.w #WDTPW+WDTHOLD,&WDTCTL ; Stop WDT

    SetupP1

     

    bis.b #001h,&P1DIR ; P1.0 output

    SetupC0

     

    mov.w #CCIE,&CCTL0 ; CCR0 interrupt enabled

     

     

    mov.w #50000,&CCR0 ;

    SetupTA

    mov.w #TASSEL_2+MC_2,&TACTL ; SMCLK, contmode

    bis.w #GIE,SR ; CPU off, interrupts enabled

    Mainloop;

    nop

     

     

     

     

    inc R5 ; just something for the cpu to do

    nop

     

     

    jmp Mainloop ; jump back to main

     

     

    ;-------------------------------------------------------------------------------

    TA0_ISR; Toggle P1.0

     

    ;-------------------------------------------------------------------------------

     

     

    xor.b #001h,&P1OUT ; Toggle P1.0

     

     

    add.w #50000,&CCR0 ; Add Offset to CCR0

     

     

    reti 

    ;------------------------------------------------------------------------------

    ; Interrupt Vectors

    ;------------------------------------------------------------------------------

     

     

    .sect ".reset" ; MSP430 RESET Vector

     

     

    .short RESET ;

     

     

    .sect ".int09" ; Timer_A0 Vector

     

     

    .short TA0_ISR;

     

     

    .end

     

  • the RETI instruction simply does the following: Fetch the word on the stack and push it into the status register, then feth the word now on the stack and push it into the program counter.
    It's that simple.

    It is the opposite part to the rather complex hardware mechanism of entering an ISR, which does put the current program counter on the stack, put the status register on the stack, load the ISRs address from the vector table, wakeup the processor (clear all the LPM mode bits form the status register) if necessary and then enter the proper ISR.

    Basically, RETI can be represented as a combination of POP R2 and POP R0 but as a monolithic instruction, so the processor won't freeze before doing the POP R0 when R2 is loaded with LPM bits set.

    On the latest processors, this is a bit more complex, as the return address has 20 bits, whose upper 4 bits are stored into the status registers unused upper bits before pushing it on stack and extrachted again on POP. Thes keeps the number of stack accesses and the stored bytes on same level as on the 16 bit address devices.

    While this is the answer to your question, I doubt it is the solution of your problem :)

    In the code snippet you posted, your main code runs into the the ISR, what's most certainly not what you want. It won't however, ever reach this point, as you do not clear the CPUOFF bit inside the ISR (not in the status register, but on the stored copy on the stack!), so your main code stops when setting the CPUOFF bit.

    You will, however, see a breakpont (if set) on the following NOP being triggered, as breakpoints are triggered when an instruction is fetched. And the NOP instruction is fetched (but never executed) before the CPUOFF bit is actually set (code pipelining). So the deugger will trigger before the ISR has been ever called.

    Also, with your setup you can control the frequency of the blinking, but not the duty cycle. The interrupts of CCR0 will come equidistant, so the duty cycle is always 50%. Onyl the frequency changes depending on the CCR0 value.

    For a real PWM (there are many other threads available in this forum) you define the PWM frequency with CCR0 and the duty cycle with CCR1..x. And usually, you don't use an ISR for toggling the port pin (as this is subject to latency times) but rather diretly use the OUTMODE feature of the CCRx units, teh the port pin (a fixed one, not freely selectable) is set or reset when the timer reaches CCRx and CCR0, giving you a perfect, jitter-free PWM signal of freely controllable frequency and duty cycle.

  • RETI is not a "POP R1 and POP R0" but a "POP R2 (SR), POP R0 (PC)".

  • You’re right, I’ve corrected this. However, this is a 4-year-old thread.

    And, well, writing “POP R2 (SR)” is ambiguous, as this is a valid instruction too, fetching the top of stack to an indirect memory address. It translates into MOV @R1+, R2(R2); :)

**Attention** This is a public forum