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.

Stopwatch Application on msp430g2553

Other Parts Discussed in Thread: MSP430G2553, MSP430WARE

Hi, I am needing help on my project. It's basically writing code for a stopwatch configuration that will pause or resume when the pushbutton is pressed.

I have it down to stopping it; however, resuming just confuses me.

*Note, I'd really appreciate any help. I don't want this project done for me, but maybe a point in the right direction would be awesome.

Here's my code:

;-------------------------------------------------------------------------------
;
;       HW I/O assignments:
;       P1.0    LED1    (Active HIGH)RED
;       P1.1    LED2    (Active HIGH)GREEN
;       P1.2    not used
;       P1.3    PushButton (Active LOW) (internal Pullup Enabled)
;       P1.4    not used
;       P1.5    not used
;       P1.6    not used
;       P1.7    not used
;
;       P2.0    not used
;       P2.1    not used
;       P2.2    not used
;       P2.3    not used
;       P2.4    not used
;       P2.5    not used
;       P2.6    not used
;       P2.7    not used
;
;
;
;*******************************************************************************
#include  "msp430g2553.h"
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
; Definition of Constants
;-------------------------------------------------------------------------------

LONG_DELAY      EQU     65535  ; max 16 bit value (FFFFh)
SHORT_DELAY     EQU     10000  ;

TIMER_A_COUNT_1 EQU     30000   ; count to value
UPPER_COUNT_LIMIT EQU   20      ; upper bound for counting timer events

LED1RED         EQU     %00000001 ; Port pin position P1.0
LED2GRN         EQU     %01000000 ; Port pin position P1.6

PUSHBUTTON      EQU     %00001000 ; Port pin position P1.3

;-------------------------------------------------------------------------------
; Definition of Variables
;-------------------------------------------------------------------------------
            ORG     0200h   ; start of RAM space (end is at 03FFh) (512 bytes)
                            ; SP will be set to 0400h
StartVars                            

Digit0_1     DB 0           ; holds two LSdigits of BCD result
Digit2_3     DB 0           ; holds two MSdigits of BCD result

TotalCount   DW 0           ; holds total counts of TimerA_0 interrupt events


PatternStateFlag
            DB     0             ;LED pattern state

EndVars
VarsLength EQU $ - StartVars

;-------------------------------------------------------------------------------
;           Start of main program
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
            ORG     0C000h              ; start of program memory 16K space
;-------------------------------------------------------------------------------
RESET       mov.w   #0400h,SP         ; Initialize stackpointer (last RAM + 1)
StopWDT     mov.w   #WDTPW+WDTHOLD,&WDTCTL  ; Stop WDT

SetupP1    bis.b   #LED1RED + LED2GRN,&P1DIR  ; make LED pins outputs

           ; The PushButton is wired to P1.3 (active LOW), so we need to turn
           ; on the internal Pullup Resistor on P1.3 - this is done with P1REN
           ; register
           mov.b    #PUSHBUTTON, &P1REN    ;turn on the internal resistor
           mov.b    #PUSHBUTTON, &P1OUT    ; set the resistor to Pullup mode
           
           ;setup Port 1 interrupts for the pushbutton
           bis.b   #PUSHBUTTON, &P1IE    ; enable interrput for Pushbutton
                                         ; this is where we recognize interrupts
           bis.b   #PUSHBUTTON, &P1IES   ; set edge select for high to low trans
                                         ; detects when I press the button, rather
                                         ; than when we release it
           clr.b   &P1IFG     ; clear the Int flag register for Port 1

SetupTimerA
            mov.w   #TIMER_A_COUNT_1,&TACCR0 ;load a count value into the counter
            mov.w   #CCIE,&TACCTL0        ; enable the timer interrupt

            mov.w   #TASSEL_2+ID_3+MC_1,&TACTL  ; select SMCLK/8, up mode
            ;mov.w   #TASSEL_2+ID_3+MC_2,&TACTL   ; select SMCLK/8, continous mode
            
            ;mov.w   #TASSEL_2+MC_2,&TACTL   ; select SMCLK/8, continous mode
            ;mov.w   #TASSEL_1+MC_2,&TACTL   ; select ACLK, continous mode            
            ; doesn't work mov.w   #TASSEL_0+MC_2,&TACTL   ; select TACLK, continous mode            


            mov  #0, &TotalCount   ; make sure the total count is zero'ed
            
EnableGeneralInterrupts
            bis.b #GIE,SR          ; enable the general interrupts bit
 
Mainloop    
            cmp.b #0,&PatternStateFlag ; compares byte 0 to PatternStateFlag
            jne ToggleClock             ; if we check Pushbutton first we can
                         
            cmp #UPPER_COUNT_LIMIT, &TotalCount ; have we hit the upper limit?
            jge  ResetTotalCount  ; about to overflow TotalCount
            jmp Done               ; OK to continue for now
        
ResetTotalCount
            mov  #0, &TotalCount
            call #TimerDisplay  ; update the display
            jmp Done

ToggleClock
            
            call #ToggleCLK
            jmp Done

Done        jmp     Mainloop                ; Again

;-------------------------------------------------------------------------------
;           End of main code
;-------------------------------------------------------------------------------                                            
                                           
;-------------------------------------------------------------------------------
;           Subroutines
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
ToggleCLK;     Start/Stop Subroutine
;  accomplishes - toggles timer into start/begin state
;                 or stop/pause state
; uses: none
;-------------------------------------------------------------------------------
     ; dint
      clr.w R14
      clr.b &P1IFG    ; clear the flag so system is ready for another interrupt
                    ; doesn't clear automatically
 
                       ; I need to pause, or stop timer here.


      mov.w  #0,&TACCR0               ; set Timer_A mode = stop
      cmp.b #0,PatternStateFlag    ; checking if the button has been pressed again
      jeq ToggleCLK                         ; otherwise keep looping?
      mov.w #1,&TACCR0               ; resume?
      eint
      ret
;-------------------------------------------------------------------------------
TA0_ISR;    TimerA_0 Interrupt Service Routine\
;  accomplishes - toggles Red LED, reloads Timer_A, increments TotalCount
;  uses: none
;-------------------------------------------------------------------------------
            xor.b   #LED2GRN,&P1OUT            ; toggle the Green LED
            ;xor.b   #LED1RED,&P1OUT    ; Toggle the RED LED
            ;add.w   #TIMER_A_COUNT_1,&TACCR0 ; reload the Timer counter
            mov.w    #TIMER_A_COUNT_1,&TACCR0 ; reload the Timer counter
            inc.w &TotalCount      ; keep track of how many of these occur
            reti      ; return from interrupt
;-------------------------------------------------------------------------------
;    End of TimerA_0 Interrupt Service Routine
;---------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; TimerDisplay
;  passed in - nothing
;  returned - nothing
;  accomplishes - toggles Red LED
;  uses: none
;-------------------------------------------------------------------------------
TimerDisplay

            xor.b   #LED1RED,&P1OUT    ; Toggle the RED LED
            
            ret         ; return from subroutine                            ;    
;-------------------------------------------------------------------------------
;    End of TimerA_0 Interrupt Service Routine
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; Port1_ISR
;  passed in - nothing
;  returned - nothing
;  accomplishes - updates PatternStateFlag
;  uses: nothing
;-------------------------------------------------------------------------------
Port1_ISR ; Port 1 Interrupt Service Routine
    ; if we get to here, an interrupt occurred on the Port 1
    bit.b  #PUSHBUTTON, &P1IFG   ; was it the Pushbutton?
    jeq  Done_here        ; no, so don't do anything
    xor.b  #1, &PatternStateFlag    ; yes, toggle the PatternStateFlag
    clr.b &P1IFG    ; clear the flag so system is ready for another interrupt
                    ; doesn't clear automatically, therefore if left off it would
                    ; think we were still having an interrupt and go back to
                    ; Port1_ISR
Done_here
    reti         ; return from interrupt
;-------------------------------------------------------------------------------
;  end of Port1_ISR
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
;           End of all Subroutines
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; Interrupt Vectors
;-------------------------------------------------------------------------------
            ORG     0FFF2h                  ; Timer_A0 Vector
            DW      TA0_ISR                 ; Start address of TA0  ISR

            ORG     0FFE4h                  ; MSP430 Port 1 Interrupt Vector
            DW      Port1_ISR               ; address of Port 1 ISR
            
            ORG     0FFFEh                  ; MSP430 RESET Vector
            DW      RESET
            
            END                         ; end of all code
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------






  • Carlos,

    Cudos for quite well-commented code however what exactly confuses you? Hardly anyone like to go through _all_ the code/logic you provide to understand your problem.

    Just curious: why don't you use C language? It's assembler class or what? ;)

  • Haha thank you for that. I was always taught to comment my code as thoroughly as I can.

    Anyways, here's my problem:

    I can run the application therefore the timer will run, press the pushbutton to stop the timer; however, my goal is to make it act like a stopwatch where I can pause it, and then resume the timer whenever I press the pushbutton again. Does that make sense? I am fairly new to assembly code, and that's what my project is over. Trust me, I would love to use C language haha.

    My LED's here act like timer events, where my GRN LED will flash for 20 events and then the RED LED will turn on for the next 20 events.

    With the code I have presented, I run the application and the LED's do their work. When I press the pushbutton it will pause; however when I press it again it acts a little funky and freezes, of course it has switch bouncing, and it also only flashes the green with no RED LED.

    I barely started this project like a two days ago, so hopefully I can see my error with a good study day on it.

  • Indeed, I've rarely seen such well-documented code. :)

    One thing I noticed: in your P2 ISR, oyu correctly state that it is important to clear the IFG register to avoid endless looping. However, if you somehow neter the ISR and your pushbutton was NOT the cause of the interrupt, you exit the ISR without clearing the IFG register.
    Either teh pushbuttonis the only source for an interrupt (then the check is superfluous), or not (then the other interrupt remains unhandled and - more important - not reset, and you'll run into endless interrupt loop)

    If you have bouncing on the pushbutton, then you might encounter multiple calls to the ISR. Maybe an ever number of calls, which leads to your button press being ignored.

    The order of port initialization is wrong. First set the edge (which may trigger an interrupt), then clear the pending interrupts and finally enable the interrupts. Or you might get bogus interrupts due to configuration. However, this is not important here since GIE is still clear and you enable it later. But if for some reason GIE were already set, you'd have some problems. Can happen easily, when you start to modularize your code.

    dint and eint are aliases for bic.b/bis.b #GIE, SR. Use one or the other, but don't mix both. 8exception: if entering LPM, BIS must be used even though you use dint/eint anywhere else)

    Carlos Rangel said:
          mov.w  #0,&TACCR0               ; set Timer_A mode = stop

    THis won't stop the timer. It sets the capture to 0, so teh tierm will trigger an interrupt on every timer tick, which in tune will spend 100% of the CPU time in the timer ISR.

    You probably meant to clear TACTL0.
    However, setting TACTL0 to 1 a few lines later (there again you use TACCR0) won't reactivate the timer. It will set the TAIFG bit and leave the timer stopped.
    Or you clear TACCTL0, which keeps the timer running, but stops the interrupts. To re-enable them, you'll need to set CCIE again in TACCTL0 (#1 would set CCIFG), just like you did when initializing the timer.

  • Carlos Rangel said:

    ... writing code for a stopwatch configuration that will pause or resume when the pushbutton is pressed.

    I have it down to stopping it; however, resuming just confuses me.

    ...maybe a point in the right direction would be awesome.

     
    There may be something you can use from this MSP430Ware example for the EZ430-CHRONOS kit.
     
    ...MSP430ware_current_version\examples\boards\eZ430-Chronos\Software Projects\Chronos Watch\CCS\Sports Watch\logic\stopwatch.c

**Attention** This is a public forum