My task is to take a functional program written by my instructor in assembly language and convert it to C language. The program is written for the TI MSP430G2553, and utilizes an attached 4-digit LED display with three side-by-side push-buttons. The display is supposed to start blank. When the right button is pressed, "ECE-3362" will begin to scroll across the display from right to left.
My conversion is 'complete' as far as I can tell and the code compiles with no errors. However, the push-buttons do not have any visible effect and the display remains blank.
I do get a few "Integer conversion resulted in truncation" warnings, but I'm not sure of the effect of this on the functionality of the program. At most I would assume this would cause the display to show the wrong values if part of my constant definitions get truncated.
One part of my code that is particularly suspicious to me is my port2 interrupt service routine at the very bottom (mainly the PB & P2_IFG comparisons). I didn't fully comprehend what was going on in my instructor's assembly version of that section, so something important may have been lost in translation.
I am new to assembly in general, and C as far as microcontrollers go. I was leaning heavily on my instructors example code as a reference. I'll put my code below, and I have my instructor's code on hand if anyone would like to see it.
I know the rules say not to post entire files but as far as I can tell I could have a mistake or more just about anywhere in the program.
My code:
#include <msp430g2553.h>
//-----------------------------------------------------------------------------
// Definition of Constants
//-----------------------------------------------------------------------------
#define TIMER_A0_COUNT_1 2000 //2000
#define TIMER_A1_COUNT_1 50000 //50000
#define MAX_TIMER_COUNT 10 //10
#define LONG_DELAY (0xFFFF) //65535
//definitions of segment positions
#define SEG_A (0x01u) // 00000001 Port pin position P1.0
#define SEG_B (0x02u) // 00000010 Port pin position P1.1
#define SEG_C (0x04u) // 00000100 Port pin position P1.2
#define SEG_D (0x08u) // 00001000 Port pin position P1.3
#define SEG_E (0x10u) // 00010000 Port pin position P1.4
#define SEG_F (0x20u) // 00100000 Port pin position P1.5
#define SEG_G (0x40u) // 01000000 Port pin position P1.6
#define SEG_DP (0x80u) // 10000000 Port pin position P1.7
//since inverted pattern is needed for the display, this defines inverse pattern
#define SEG_A_N ~SEG_A // Port pin position P1.0
#define SEG_B_N ~SEG_B // Port pin position P1.1
#define SEG_C_N ~SEG_C // Port pin position P1.2
#define SEG_D_N ~SEG_D // Port pin position P1.3
#define SEG_E_N ~SEG_E // Port pin position P1.4
#define SEG_F_N ~SEG_F // Port pin position P1.5
#define SEG_G_N ~SEG_G // Port pin position P1.6
#define SEG_DP_N ~SEG_DP // Port pin position P1.7
//NOTE: display board requires INVERSE of these patterns due to Active LOW
#define DIG_3 (0x01u) // 00000001 Port pin position P2.0 (MSdigit)
#define DIG_2 (0x02u) // 00000010 Port pin position P2.1
#define DIG_1 (0x04u) // 00000100 Port pin position P2.2
#define DIG_0 (0x08u) // 00001000 Port pin position P2.3(LSdigit)
#define DP_COM (0x10u) // 00010000 Port pin position P2.4
//since inverted pattern is needed for the display, this defines inverse pattern
#define DIG_3_N ~DIG_3 // Port pin position P2.0 (MSdigit)
#define DIG_2_N ~DIG_2 // Port pin position P2.1
#define DIG_1_N ~DIG_1 // Port pin position P2.2
#define DIG_0_N ~DIG_0 // Port pin position P2.3(LSdigit)
#define DP_COM_N ~DP_COM // Port pin position P2.4
//Pushbutton assignments CORRECTED to compensate for board layout swap
#define PB_0 (0x20u) // 00100000 Port pin position P2.5 RightMost button
#define PB_1 (0x80u) // 10000000 Port pin position P2.7 Middle button
#define PB_2 (0x40u) // 01000000 Port pin position P2.6 LeftMost button
#define SEG_PORT P1OUT
#define DIG_PORT P2OUT
#define PB_PORT P2IN
//NOTE: display bd requires the INVERSE of these patterns due to Active LOW
#define ONE (0x06u) // 00000110
#define TWO (0x5Bu) // 01011011
#define THREE (0x4Fu) // 01001111
#define FOUR (0x66u) // 01100110
#define FIVE (0x6Du) // 01101101
#define SIX (0x7Du) // 01111101
#define SEVEN (0x03u) // 00000111
#define EIGHT (0x7Fu) // 01111111
#define NINE (0x67u) // 01100111
#define ZERO (0x3Fu) // 00111111
//since inverted pattern is needed for the display, this defines inverse pattern
#define ONE_N (~0x06u) // ~00000110
#define TWO_N (~0x5Bu) // ~01011011
#define THREE_N (~0x4Fu) // ~01001111
#define FOUR_N (~0x66u) // ~01100110
#define FIVE_N (~0x6Du) // ~01101101
#define SIX_N (~0x7Du) // ~01111101
#define SEVEN_N (~0x03u) // ~00000111
#define EIGHT_N (~0x7Fu) // ~01111111
#define NINE_N (~0x67u) // ~01100111
#define ZERO_N (~0x3Fu) // ~00111111
//other figures for scrolling display
#define E_N (~0x79u) // ~01111001
#define C_N (~0x39u) // ~00111001
#define DASH_N (~0x40u) // ~01000000
#define BLANK_N (~0x00u) // ~00000000
//------------------------------------------------------------------------------
// Definition of Variables
//------------------------------------------------------------------------------
int DisplayValue = 0; // contains 4 digit value to display in BCD format
// BCDdig3 | BCDdig2 | BCDdig1 | BCDdig0
// xxxx xxxx xxxx xxxx
char CurrentDigitPos = 0; // global variable used by WriteDigitToDisplay ISR
// holds digit position of current digit to write
char CurrentDigitValue = 0; // global variable used by WriteDigitToDisplay ISR
// holds digit value of next digit to write
char StartFlag = 0; // Boolean state flags
char PauseFlag = 0;
char ContinueFlag = 0;
char ScrollingStateFlag = 0;
char PB_0_Mode = 0;
char PB_1_Mode = 0;
char PB_2_Mode = 0;
char Hundred_mS = 0;
char TotalINTCount1 = 0;
int PatternsToScroll[12] = {0x0000, 0x0006, 0x0065, 0x0656, 0x6561, 0x5613,
0x6133, 0x1334, 0x3342, 0x3420, 0x4200, 0x2000};
char PatternsIndex = 0;
int CurrentPattern = 0;
char PatternsLeft = 12;
char SegPatterns[7] = {BLANK_N, DASH_N, TWO_N, THREE_N, SIX_N, C_N, E_N};
//-----------------------------------------------------------------------------
// Functions
//-----------------------------------------------------------------------------
void WriteNextDigitToDisplay(int DisplayValue, char CurrentDigitPos, char CurrentDigitValue)
{
int DisplayValueCopy = 0; // initialize function variable
DIG_PORT |= DIG_0+DIG_1+DIG_2+DIG_3+DP_COM; // eliminate ghosting
if ((CurrentDigitPos - 0) == 0)
{
DisplayValueCopy = DisplayValue;
DisplayValueCopy &= 0x000F;
SEG_PORT = SegPatterns[DisplayValueCopy];
DIG_PORT = DIG_0_N;
CurrentDigitPos++;
}
if ((CurrentDigitPos - 1) == 0)
{
DisplayValueCopy = DisplayValue;
DisplayValueCopy &= 0x00F0;
DisplayValueCopy >>=4; //rra 4 times to get val into LSnibble
SEG_PORT = SegPatterns[DisplayValueCopy];
DIG_PORT = DIG_1_N;
CurrentDigitPos++;
}
if ((CurrentDigitPos - 2) == 0)
{
DisplayValueCopy = DisplayValue;
DisplayValueCopy &= 0x0F00;
DisplayValueCopy = __swap_bytes(DisplayValueCopy);
SEG_PORT = SegPatterns[DisplayValueCopy];
DIG_PORT = DIG_2_N;
CurrentDigitPos++;
}
if ((CurrentDigitPos - 3) == 0)
{
DisplayValueCopy = DisplayValue;
DisplayValueCopy &= 0xF000;
DisplayValueCopy = __swap_bytes(DisplayValueCopy);
DisplayValueCopy >>=4;
SEG_PORT = SegPatterns[DisplayValueCopy];
DIG_PORT = DIG_3_N;
CurrentDigitPos++;
}
if ((CurrentDigitPos - 4) == 0)
{
CurrentDigitPos = 0;
}
}
void delay()
{
for (int i = 0; i < LONG_DELAY; i++);
}
int main( void )
{
//---------------------------------------------------------------------------
// Setup
//---------------------------------------------------------------------------
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
// Setup Port 1 (all outputs for segment display)
P1DIR = SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G + SEG_DP;
// Setup Port 2
P2DIR = 0x1F; // (00011111 : 3MSbits as inputs (pushbuttons) 5LSbits as outputs)
P2OUT = PB_0 + PB_1 + PB_2; // 11100000 or 0xE0 defines pushbutton positions
P2REN |= PB_0 + PB_1 + PB_2; // turn on internal pull-up for the pushbuttons
// Activate the General Purpose Digital I/O mode for P2.6 and P2.7
P2SEL &= ~PB_1 + ~PB_2;
// Setup Port 2 interrupts for the pushbuttons
P2IE |= PB_0 + PB_1 + PB_2;
P2IES |= PB_0 + PB_1 + PB_2;
// Turn off all the segments and digits
SEG_PORT = 0xFF;
DIG_PORT = 0xFF;
// SetupCalibratedClock
// Set up the clock (calibrated mode at 1 MHz)
// Get the calibrated data for the DCO clock
// Set DCO to 1 MHz: (this directly from TI Family Guide page283 and 284
DCOCTL = 0; // Select lowest DCOx and MODx settings
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation
// Set up Timers
// TimerA0
TA0CCR0 = TIMER_A0_COUNT_1; // load a count "up to"value into timer
TA0CTL = TASSEL_2+ID_3 + MC_1; // SMCLK, input div = 8, upmode
TA0CCTL0 = CCIE; // interrupt enabled for Timer0
// TimerA1
TA1CCR0 = TIMER_A1_COUNT_1; // load a count "up to"value into timer
TA1CTL = TASSEL_2+ID_3 + MC_1; // SMCLK, input div = 8, upmode
TA1CCTL0 = CCIE; // interrupt enabled for Timer1
// Start of main program
// Initialize Boolean state flags and some other variables
StartFlag = 0;
PauseFlag = 0;
ContinueFlag = 0;
ScrollingStateFlag = 0;
PB_0_Mode = 0;
PB_1_Mode = 0;
PB_2_Mode = 0;
DisplayValue = 0;
// Clear Interrupt Flags
P1IFG = 0; // clear the Int flag register for Port 1
P2IFG = 0; // clear the Int flag register for Port 2
// Enable General Interrupts
_BIS_SR(GIE); // enable the general interrupts bit
//----------------------------------------------------------------------------
// Top of main program loop structure
//----------------------------------------------------------------------------
while(1) // forever loop
{
// test the Pushbutton mode Boolean variables to see what to do
if ((PB_0_Mode - 1) == 0) // (START CONDITION)
{
// Rightmost button (START)
PB_0_Mode = 0;
ScrollingStateFlag = 1; // make it TRUE
PatternsIndex = 0; // beginning of pattern array
PatternsLeft = 12;
CurrentPattern = PatternsToScroll[PatternsIndex]; // might be redundant
}
if ((PB_1_Mode - 1) == 0) // (CONTINUE CONDITION)
{
// Middle button (CONTINUE)
PB_1_Mode = 0;
ScrollingStateFlag = 1; // make it TRUE
}
if ((PB_2_Mode - 1) == 0) // (PAUSE CONDITION)
{
// Leftmost button (PAUSE)
PB_2_Mode = 0;
ScrollingStateFlag = 0; // make it FALSE
}
else
{
if ((ScrollingStateFlag - 1) == 0)
{
CurrentPattern = PatternsToScroll[PatternsIndex];
DisplayValue = CurrentPattern; // save pattern array element
PatternsIndex++; // move to next element
PatternsLeft--; // one less pattern to display
if ((PatternsLeft - 0) == 0) // done all the patterns --> reset variables
{
PatternsIndex = 0;
CurrentPattern = PatternsToScroll[PatternsIndex]; // might be redundant
PatternsLeft = 12;
}
delay(); // update the scrolling slowly
delay();
}
}
}
return 0;
} // end of MAIN
//------------------------------------------------------------------------------
// Subroutines
//------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
// WriteNextDigitToDisplay
// passed in - DisplayValue, CurrentDigitPos
// returned - nothing
// accomplishes - Writes next digit to the expansion bd display
// uses: R15, global variable CurrentDigitPos, CurrentDigitValue
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
// Interrupt Service Routines
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
// Interrupt Service Routine for Timer_A 1
// Passed in: nothing
// Activated every time TimerA_1 times out
// Updates global variable TotalINTCount1 to keep track of number of TimerA_1
// interrupt events
// Uses: nothing except modifies global variable TotalINTCount
// For this example, set up to trigger every 100 mS
//-------------------------------------------------------------------------------
//Timer0_A0 ISR
#pragma vector=TIMER0_A0_VECTOR // this line tells the C compiler to put
// the start address of the following ISR
// into the Interupt Vector table
__interrupt void Timer_A0_ISR (void) // required syntax for first line of ISR
{
WriteNextDigitToDisplay(DisplayValue, CurrentDigitPos, CurrentDigitValue);
}
//Timer0_A1 ISR
#pragma vector=TIMER1_A1_VECTOR // this line tells the C compiler to put
// the start address of the following ISR
// into the Interupt Vector table
__interrupt void Timer_A1_ISR (void) // required syntax for first line of ISR
{
Hundred_mS++;
TotalINTCount1++;
}
// Port2_ISR
// passed in - nothing
// returned - nothing
// accomplishes - updates global Boolean variables for Pushbutton status
// uses: nothing
//-------------------------------------------------------------------------------
//Port2_ISR
// if we get to here, an interrupt occurred on the Port 2
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
{
if ((PB_0 & P2IFG) == 1)
{
PB_0_Mode |= 1;
PB_1_Mode &= ~1;
PB_2_Mode &= ~1;
}
if ((PB_1 & P2IFG) == 1)
{
PB_0_Mode &= ~1;
PB_1_Mode |= 1;
PB_2_Mode &= ~1;
}
if ((PB_2 & P2IFG) == 1)
{
PB_0_Mode &= ~1;
PB_1_Mode &= ~1;
PB_2_Mode |= 1;
}
P2IFG = 0;
}
Can't post instructor's entire code due to character limit. Here is his port 2 ISR:
; Port2_ISR
; passed in - nothing
; returned - nothing
; accomplishes - updates global Boolean variables for Pushbutton status
; uses: nothing
;-------------------------------------------------------------------------------
Port2_ISR
; if we get to here, an interrupt occurred on the Port 2
bit.b #PB_0, &P2IFG ; PB_0 Pushbutton? (if 1 it is pressed)
jnz PB_0_Case ; it is PB_0
;no so try the next case
bit.b #PB_1, &P2IFG ; PB_1 Pushbutton? (if 1 it is pressed)
jnz PB_1_Case ; it is PB_1
;no so try the next case
bit.b #PB_2, &P2IFG ; PB_2 Pushbutton? (if 1 it is pressed)
jnz PB_2_Case ; it is PB_2
jmp DoneWithPort_2_ISR ; no, so don't do anything
PB_0_Case
bis.b #1, &PB_0_Mode
bic.b #1, &PB_1_Mode ;clear other modes
bic.b #1, &PB_2_Mode
jmp DoneWithPort_2_ISR
PB_1_Case
bis.b #1, &PB_1_Mode
bic.b #1, &PB_0_Mode ;clear other modes
bic.b #1, &PB_2_Mode
jmp DoneWithPort_2_ISR
PB_2_Case
bis.b #1, &PB_2_Mode
bic.b #1, &PB_1_Mode ;clear other modes
bic.b #1, &PB_0_Mode
jmp DoneWithPort_2_ISR
DoneWithPort_2_ISR
clr.b &P2IFG ; clear the flag so system is ready for another interrupt
reti ; return from interrupt
;-------------------------------------------------------------------------------
; end of Port2_ISR
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------