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.

MSP430 G2553 ADC Inaccurate: Trailing Zeroes.

Other Parts Discussed in Thread: MSP430G2553

I used a MSP430G2553 to accept analog signal inputs, store the data, and send it via the UART to my computer's serial port.  Everything works well except the ADC.  Sometimes it works well, but more often, it does not.  Often it stores a bunch of trailing zeroes on the ADC value.  I know sampling too quickly is not my problem because I'm on essentially the slowest setting possible.  I suspect it's a grounding/clean power supply/capacitor issue.  When I run my code straight from the MSP430 LaunchPad, the ADC works flawlessly and gives accurate readings, but when I plug the uC into my own device, I will get the trailing-zeroes behavior again.  

The board is two layer, and I know my ground trace from the uC to battery ground is super long.  Is that what is causing the inaccurate ADC values?  Farther down this post I have some test data that shows that the ADC will follow significant value changes, but not closely.  I know it's not just my sensors sticking because the internal temperature sensor does the same trailing zeroes behavior.  Something is causing the ADC to quit prematurely, I think.  

Suggestions?

PCB layout and schematic attached

.

7651.05 Final Schematic.pdf

  • Robert Snell said:
    I know my ground trace from the uC to battery ground is super long.  Is that what is causing the inaccurate ADC values?

    I don't think so. The patterns which clearly appear on the high pressure sensor (and partly on teh low pressure sensor) data seem to indicate a problem on the digital side. It looks like a bit is being sent as 0 where it should be 1, and on certain ranges only.
    Youshould try with a lower baudrate and check the RS232 levels. Your diagram doesn't show the actual value sent through RS232. Seeing the digital values of the diagram dots could be enlightening.
    From an analog problem, I'd expect a more erratic behavior. Or a constant offset/linearity error. Not a pattern like the one shown.

    Alternatively, this can be a software problem. You say 'the ADC works on the LaunchPad', but I guess on the LaunchPad you only test it with a few discrete voltages. Perhaps the problem is already there but you don't see it due to the test conditions.

  • Thanks for the feedback.  I'm confident that the RS232 isn't inherently the problem.  I have collected data on the development board (while it is plugged into usb) and sent the data via (jumper wires over to my empty DIP20 to utilize) my circuit board's RS232 connection to my computer's terminal service to retrieve the data.  The data sent in this way was valid.  Here is a sample of the data collected on my circuit board and sent via USB (1xxx and 2xxx) that matches the graph given previously. The spreadsheet is not completely professional in appearance.  5126.20120420 pcb 3393 vacuum test.xlsx  

    Perhaps my circuit board's power system isn't adequate to handle the RS232 bit-banging?  However, I have had successful spurts of data sent from my circuit board.

    I am also quite confident that the development board does actually store different data than the circuit board, even at room temperature (in the temperature sensing example).  

    Is the issue perhaps a high ESR on my caps?  These are the caps I used: 

    Ref #

    Qty

    Product

    Descriptions

     

     

     

     

    C3 C7

    4

    FK20X7R1C106K

    10uF Ceramic Capacitor

    C5

    2

    BC1038CT-ND

    47pF Capacitor

    C15

    2

    SR151A101JAR

    0.1nF Ceramic Capacitor (2 req.)

    C (all other)

    20

    C320C104K5R5TA

    0.1uF Ceramic Capacitor

  • As I said, the patterns shown seem to indicate that this is a digital problem (the values are shifted down by exactly the same amount or a multiple of it)
    If it were an analog problem, I wouldn't expect bocks of values shifted down by exactly the same amount. I'd rather expect nonlinear scaling, completely erratic values, clipping or such.

    But in your case, there are whole blocks of data which appear moved down by exactly the same amount. As if a digital bit is not being set.

    It looks like the values are going, say, 0x20 to 0x2f but then instead of going to 0x30 they fall back to 0x20 because bit 4 won't  set for some reason.

    This is why suspected your code too. Do you send the exact ADC results, or do you convert them to voltage or pressure values before sending? Maybe there's a problem in your conversion function that leads to a folding effect in the transformation.

  • I agree (if this is what you're refering to) that the conversion to digital doesn't seem to be completing properly and that certain bits are only occasionally being set properly.  That's the 'trailing zeroes' that I was seeing.  And the program code does store the '1xxx' and '2xxx' directly.  I'll include the full source code here:

    8551.Senior Project Final Code.txt
    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    ;*******************************************************************************
    ; Title: Altitude Data Logger
    ; Author: Rob Snell
    ; Date: April 20, 2012
    ; Purpose: Senior Project-Design Problems, Bob Jones University, Spring 2012
    ;
    ; Very basic code shell was MSP320G2xx2 Demo by D. Dang, TI Inc Dec 2010- WDT, Toggle P1.0, Interval Overflow ISR, 32kHz ACLK
    ;*******************************************************************************
    .cdecls C,LIST, "msp430g2553.h"
    .bss Const2,2
    .bss StMemBlk2,2 ; Do not use 'comma one' at the end of these .bss things. They glitched when I tried to use them for byte storage.
    .bss StMemBlk3,2
    .bss StMemBlk4,2
    .bss EndBlkChar1,2
    .bss EndBlkChar2,2
    .bss EndBlkChar3,2
    .bss EndBlkChar4,2
    ;------------------------------------------------------------------------------
    .text ; Program Start
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • Well documented code. :)
    Well, it's assembly code and difficult to understand without plenty of comments, but I've seen assembly code with less than one comment per function. :(

    There are, however, some things I noticed (nothing critical):

    You use R6 for the storage address. You set it in main and use it inside ISRs. This is dangerous. It works in your code, because you never use R6 for somethign else in the whole project, but as soon as the project grows, this may break easily.
    It's better to use a global variable for this. Besides the additional two clock cycles, it makes no difference whether you use a register or a variable. And is safer.

    During interrupts, IRQs are globally disabled. So no need to clear TAIE.

    You could control the ADC by hardware. Use TA0CCR1 as ADC trigger. If you do not set ADC10SHP, it can even control the sampling time.
    Also, you do not need to reprogram the ADC. Just set it to sample a sequence (A4 to A0) with twice the sampling frequency and skip the A1/A2 results. The samples will come in without any need for a timer ISR.  Sampling and conversion will start with the exact timer tick.

    About your problem, well, I don't see an obvious reason. However, you store the values to flash and submit them ina burst on a trigger. It is possible that your flash writing somehow fails. It may be caused by an insufficient power supply (minimum flashing voltage ensured when the flashing process starts drawing its mA?)
    It is possible that due to insufficient power supply, the segments aren't properly erased and soem bits remain '0' or are at the edge of skippign back to '0'.
    Also, did you calculate the maximum programming time? You write to flash word by word. Depending on flash clock etc, this may exceed the maximum programing time of a segment and may cause some bits to switch from 1 to 0.
    You might try to use the ram as (smaller) data buffer isntead of flash and check whether the problem persists.

     

  • Thanks for the thoughtful input.  About the things you propose... I think the flash memory is default "1", so failing to finish the write would seem to leave 1's instead of 0's.  The timing is really generous.  The ADC has virtually the longest possible calculation time, and the flash write doesn't have to work except for once every second or more.  And, the time can't be too long because it works on the development board fine.  

  • Robert Snell said:
    I think the flash memory is default "1", so failing to finish the write would seem to leave 1's instead of 0's

    Yes. However, if the flash hasn't been properly erased (remenber, the flash cells internally store a charge, whcih is an analog value, even if it is turned into a digital one later by sort of a comparator), it may be that cells that were 'erased' to '1' then turn back to '0' again due to e.g. leakage currents during a programming cycle. The programming voltage is applies to all cells of a flash block. If it is applied for too long, all cells my turn from 1 to 0, even if they aren't intended to be programmed and were properly erased previously.

    Robert Snell said:
     The timing is really generous

    The critical part is the total time any programming voltage is applied to a block of flash cells - whether the cell is written to or not.

    You could try collecting one block of data in ram before writing it as a whole in a burst. Sicne your program needs to cope with a slooow erase operation if needed, the additional time of flashing a whole block (128 bytes on 5x devices, 64 on the others, IIRC) or even a whole segment (512 bytes) won't add much to the 'dead time' between two sampling operations. Even less if the flashing is done from a RAM function, so burst mode can be used.

    I once tried to incrementally clear individual bits in a segment (sort of a progress counter) and ended up with bits turnign zero which weren't touched during write at all. Of course I significantly exceeded the maimum cumulative programming time.

    Robert Snell said:
    And, the time can't be too long because it works on the development board fine.  

    I don't know how the flash controller works internally. I don't even know whether it is multi-level flash (using four charge 'ranges' per cell to represent two bits). Difference s in supply voltage and supply voltage stability can make a difference here, so a fragile/out-of-spec oepration may still work in one but fail in another environment. Remember, the specs are the 'safe' area. It doesn't mean that leaving this area will result in immediate and guaranteed failure. Often, things still work most of the time. Until they fail when you don't expect it. :)

  • The reason I don't think it's a flash erase/write problem is that...when I program the uC and run it from the LaunchPad (USB powered) and send the UART out data through my ADM3202 chip to my serial cable into my computer, the data is fine.  That makes me think it's not a software issue but a power supply issue.

  • Robert Snell said:
    That makes me think it's not a software issue but a power supply issue.

    At least it seems to indicate that the power supply is part of the problem. It can still be a software problem but it doesn't appear ont eh LaunchPads power supply. Or it is a power supply problem and your code doesn't properly detect it (e.g. checking for a programming voltage fail signal after doing the flashing, that indicated a significant change in VCC during the flash operation). Or a combination of both.

  • I think I finally solved it!  I wasn't resetting Const2 (which was intended to tell me when I had reached a new segment of memory which needed to be erased before writing to it).  On the first run through the program, Const2 got changed and never replaced.  See fixed code below.  I will be testing to make sure this fixes it for good.  

    ;*******************************************************************************
    ; Title: Altitude Data Logger
    ; Author: Rob Snell
    ; Date: April 20, 2012 //Modified September 13, 2012 RS
    ; Purpose: Senior Project-Design Problems, Bob Jones University, Spring 2012
    ;
    ; Very basic code shell was MSP320G2xx2 Demo by D. Dang, TI Inc Dec 2010- WDT, Toggle P1.0, Interval Overflow ISR, 32kHz ACLK
    ;*******************************************************************************
    .cdecls C,LIST, "msp430g2553.h"
    .bss Const2,2
    .bss StMemBlk2,2 ; Do not use 'comma one' at the end of these .bss things. They glitched when I tried to use them for byte storage.
    .bss StMemBlk3,2
    .bss StMemBlk4,2
    .bss EndBlkChar1,2
    .bss EndBlkChar2,2
    .bss EndBlkChar3,2
    .bss EndBlkChar4,2
    ;------------------------------------------------------------------------------
    .text ; Program Start
    ;------------------------------------------------------------------------------
    RESET mov.w #0280h,SP ; Initialize stackpointer
    mov.w #WDTPW+WDTHOLD,&WDTCTL ; Turn off Watchdog Timer
    CLKSetup mov.b #LFXT1S_2,&BCSCTL3 ; Since XTS is 0 by default, this selects VLOCLK to source ACLK (12 kHz roughly)
    ; Using ACLK for Timer (See Timer_A_Setup) which interrupts and causes ADC
    clr.b &DCOCTL ; Select lowest DCOx and MODx settings (these three lines copied from pp283-4)
    mov.b &CALBC1_1MHZ,&BCSCTL1 ; Set range
    mov.b &CALDCO_1MHZ,&DCOCTL ; Set DCO step + modulation (1 MHz)
    WDTSetup ; mov.w #WDT_ADLY_250,&WDTCTL ; WDT 250ms, ACLK, interval timer
    PortSetup
    mov.b #00001001b,&ADC10AE0 ; Enable analog input on {now A0 (Pin 2, P1.0) and A3 (Pin 5, P1.3)}; should i enable only when sampling?
    bic.b #00000001b,&P2DIR ; Set P2.0 to input mode (for prompting UART transfer)
    bis.b #00000001b,&P2REN ; Enable P2.0 pullup/down resistor
    bic.b #00000001b,&P2OUT ; Set P2.0 internal resistor to pulldown
    bis.b #00000001b,&P2IE ; Enable P2.0 interrupt
    bic.b #00000001b,&P2IES ; Set P2.0 Transition Trigger to 'low-to-high'
    bic.b #00000001b,&P2IFG ; Reset P2.0 Interrupt Flag
    ; bis.b #WDTIE,&IE1 ; Enable WDT interrupt
    bic.b #00111000b,&P2OUT ; Turn off P2.5 & P2.3
    bis.b #00111000b,&P2DIR ; Set P2.5 & (P2.4 for UART out indicator) & P2.3 to output (for indicating which sensor is being stored)
    ;------------------------------------------------------------------------------
    Timer_A_Setup;
    ;------------------------------------------------------------------------------
    bis.w #TASSEL_1+TAIE,&TACTL ; Select ACLK to power Timer A (12kHz) + Enable Interrupt
    mov.w #01000h,&TACCR0 ; Count limit is FFFF is apx 4.8 sec; 7460h for 4.5 hrs; 3393 for ~1 sample/sec
    ;------------------------------------------------------------------------------
    ADC_Setup; Setup ADC functionality
    ;------------------------------------------------------------------------------
    and.w #0fff0h,&ADC10CTL0 ; Allow ADC config, clear int flag, disable int// automatic on system reset //
    and.w #0fdffh,&ADC10CTL0 ; Turn off Reference Output to save power
    bis.w #ADC10SSEL_1,&ADC10CTL1 ; Changed this to select ACLK (~12kHz) instead of /// Select ADC10OSC for ADC clock source (~ 5 MHz)
    bis.w #ADC10DIV_7,&ADC10CTL1 ; Divide clock by 8 (so 625kHz) (for longer sampling period)
    bis.w #CONSEQ_0,&ADC10CTL1 ; Select single-channel single-conversion mode;
    bis.w #SREF_0,&ADC10CTL0 ; Set Vcc and Vss as limits for conversion;
    bis.w #ADC10ON,&ADC10CTL0 ; Enable conversion core
    bis.w #ADC10SHT_3,&ADC10CTL0 ; Use 64 ADC10OSC cycles for sample input (charge sampling capacitor) // Worth looking into again. p552
    bis.w #INCH_10,&ADC10CTL1 ; Set ADC channel to temperature sensor
    bis.w #ADC10IE,&ADC10CTL0 ; Enable ADC interrupts
    bis.w #ENC,&ADC10CTL0 ; End ADC config
    mov #0C400h,R6 ; C400; Start address for ADC data storage (Must be initialized as first address in a segment!)
    mov #0C400h,&Const2 ; C400; Load first segment entry boundary for flash erase procedure (Do not change!)
    mov #0FE00h,R7 ; End (First illegal at end) address for ADC data storage
    ;------------------------------------------------------------------------------
    UART_Setup; Setup Serial Functionality
    ;------------------------------------------------------------------------------
    mov #0D200h,&StMemBlk2 ; Configure Manual Memory Blocks
    mov #0E000h,&StMemBlk3 ;
    mov #0EE00h,&StMemBlk4 ;
    bis.b #UCSWRST,&UCA0CTL1 ; enable UART config
    bis.b #00000100b,&P1SEL ; Configure P1.2 for UART use
    bis.b #00000100b,&P1SEL2 ;
    ; bic.b #UCSWRST,&UCB0CTL1 ; Allow turning off UCB interrupt
    ; bic.b #UC7BIT,&UCA0CTL0 (default 8-bit data mode, no parity)
    bis.b #UCSSEL_3,&UCA0CTL1 ; Clock source is SMCLK (1 MHz)
    mov.b #00h,&UCA0BR1 ; Clear top bits of prescaler
    mov.b #104,&UCA0BR0 ; Copied from byu website. See history mov.b #06h,&UCA0BR0 ; Prescale divide by 6 (UCBRx);;
    mov.b #UCBRS0,&UCA0MCTL ; Copied from byu website mov.b #UCBRF_8+UCOS16,&UCA0MCTL ; Set first stage modulator (to 8) and enable oversampling baud rate generation (fast clock source) [9600 baud];;
    mov R6,R9 ; Set iniitial TX address
    bic.b #UCSWRST,&UCA0CTL1 ; end UART config

    ;------------------------------------------------------------------------------
    Timer_A_Start;
    ;------------------------------------------------------------------------------
    bis.w #MC_1,&TACTL ; Count up to TACCR0
    bis.w #TAIE,&TACTL ; Enable Timer Interrupts
    ;------------------------------------------------------------------------------
    Main_Prog_Run;
    ;------------------------------------------------------------------------------
    Mainloop bis.b #00100000b,&P2OUT ; Initialize P2.5 so toggle is correct
    bic.w #OSCOFF,SR ; Confirm ACLK remains on when LPM3 set in next instruction
    bis.w #LPM3+GIE,SR ; Enter LPM3, interrupts enabled
    nop ; Required only for debugger
    ;------------------------------------------------------------------------------

    ;------------------------------------------------------------------------------
    TIMER_A_ISR; Handle a Timer Overflow
    ;------------------------------------------------------------------------------
    bic.w #TAIE,&TACTL ; Disable Timer Interrupts
    cmp R6,R7 ; Test for last memory location
    jz End_of_Mem
    xor.b #00101000b,&P2OUT ; Toggle P2.5 & P2.3
    bis.w #ENC,&ADC10CTL0 ; End ADC config (ADC enable)
    bis.w #ADC10SC,&ADC10CTL0 ; Start ADC conversion
    bic.w #TAIFG,&TACTL ; Reset interrupt flag
    bis.w #TAIE,&TACTL ; Enable Timer Interrupts
    End_of_Mem reti

    ;------------------------------------------------------------------------------
    ADC10_ISR; Handle an ADC Conversion Completion Event
    ;------------------------------------------------------------------------------
    bic.w #ADC10SC,&ADC10CTL0 ; Reset ADC start condition
    bic.w #ENC,&ADC10CTL0 ; Disable ADC for config purposes
    mov.w ADC10MEM,R5 ; Copy ADC result to R5
    ; bit.w #03000h,&ADC10CTL1 ; Test for data source (bit indicating A3) If A3 in, zf (not set)=0.
    ; ; if zf=0, was inch 3 (pin 5) Low Pressure.
    ; jnz Was_Inch_3
    ; bis.w #01000h,R5 ; Label data sample with channel source (A0, Pin 2, High Pressure)
    ; jmp FlashErase
    Was_Inch_3 bis.w #02000h,R5 ; Label data with #02 for Temp Data; Label data sample with channel source (A3, Pin 5, Low Pressure)
    ;------------------------------------------------------------------------------
    FlashErase; Can only erase 512Mb segments; Must erase before write; Code taken extensively from p320-323
    ;------------------------------------------------------------------------------
    bic.w #LPM3,SR ; Enable main clock, (interrupts turned off b/c EEIEX, EEI are reset, interrupts will be handled after flash done)
    cmp R6,&Const2 ; Compare next write address to each new segment address
    jeq L1 ; If new segment, erase first.
    NewSegTest add #0200h,&Const2 ; Jump to next segment boundary for testing purposes
    cmp #0FE00h,&Const2 ; If next segment entry is the last (0FE00h), next address isn't a new segment
    jeq L3
    cmp R6,&Const2 ; Compare next write address to each new segment address
    jeq L1 ; If new segment, erase first.
    jmp NewSegTest

    ; Flash Erase from within RAM ($03ff to 0200)
    L1 bit #BUSY,&FCTL3 ; Test BUSY
    jnz L1 ; Loop while busy
    mov #FWKEY+FSSEL_1,&FCTL2 ; Use MCLK for the Flash Module (1 MHz)
    mov #FWKEY+00002h,&FCTL2 ; Divide MCLK by 3 (FNx+1) to put freq b/w 250kHz and 450kHz req.
    mov #FWKEY,&FCTL3 ; Clear LOCK
    mov #FWKEY+ERASE,&FCTL1 ; Enable segment erase
    clr &Const2 ; //Was &Const2//Any memory location in that segment;***Must be in same segment as write location
    L2 bit #BUSY, &FCTL3 ; Test BUSY
    jnz L2 ; Loop while busy
    mov #FWKEY+LOCK,&FCTL3 ; Done, set LOCK
    ;-------------------------------------------------------------------------------
    FlashWrite; Write Data in R5 to Flash at address in R6; code taken extensively from p320ff (from within RAM-just extra safety)
    ;-------------------------------------------------------------------------------
    L3 bit #BUSY,&FCTL3 ; Test BUSY
    jnz L3 ; Loop while busy
    mov #FWKEY+FSSEL_1,&FCTL2 ; Use MCLK for the Flash Module (1 MHz)
    mov #FWKEY+00002h,&FCTL2 ; Divide MCLK by 3 (FNx+1) to put freq b/w 250kHz and 450kHz req.
    mov #FWKEY,&FCTL3 ; Clear LOCK
    mov #FWKEY+WRT,&FCTL1 ; Enable write
    mov R5,0(R6) ; Write data in R5 to the address stored in R6
    ; mov @R6,R8 ; For Debugging
    incd R6 ; Double increment R6
    L4 bit #BUSY,&FCTL3 ; Test BUSY
    jnz L4 ; Loop while busy
    mov #FWKEY,&FCTL1 ; Done. Clear WRT
    mov #FWKEY+LOCK,&FCTL3 ; Set LOCK
    ; xor.w #INCH_3,&ADC10CTL1 ; Toggle between ADC channel A0 and A3
    mov #0C400h,&Const2 ; Prepare for next Flash erase by resetting the segment boundary variable
    bis.w #ENC,&ADC10CTL0 ; Enable ADC
    reti

    ;------------------------------------------------------------------------------
    UART_ISR; Execute UART code upon button press
    ;------------------------------------------------------------------------------
    bic.b #00000001b,&P2IE ; Disable P2.0 interrupt
    bic.w #ENC,&ADC10CTL0 ; Stop ADC
    bis.w #MC_0,&TACTL ; Stop Timer A

    mov #0ffffh,R4 ; Setup delay loop

    Delay dec R4 ; Delay resetting the interrupt to prevent keybounce
    jnz Delay
    bis.b #00010000b,&P2OUT ; Turn on P2.4 (UART Indicator)

    BEGIN_UART ;set sync bit
    bit.b #UCBUSY,&UCA0STAT ; Test for transmission in progress.
    jnz END_UART
    bis.b #UCA0TXIFG,&UC0IFG ; Clear all UCA and UCB interrupts
    call #ExtractNum


    END_UART bis.w #ENC,&ADC10CTL0 ; Enable ADC
    bis.w #MC_1,&TACTL ; Start Timer A
    bic.b #00000001b,&P2IFG ; Reset P2.0 Interrupt Flag
    bis.b #00000001b,&P2IE ; Enable P2.0 interrupt
    bic.b #00010000b,&P2OUT ; Turn off P2.4 (UART Indicator)
    reti

    ;------------------------------------------------------------------------------
    ExtractNum; Turn Memory into Hex
    ;------------------------------------------------------------------------------
    TOP_EXTRACT
    cmp R7,R9 ; Test for last memory address
    jz END_BLK_4
    cmp R9,R6 ; Test for last significant memory address
    jz END_CUR_MEM
    cmp &StMemBlk2,R9 ; Test for start manual memory block 2
    jz ST_BLK_2
    cmp &StMemBlk3,R9 ; Test for start manual memory block 3
    jz ST_BLK_3
    cmp &StMemBlk4,R9 ; Test for end manual memory block 4
    jz ST_BLK_4
    EXTRACT_A mov @R9,R8 ; Load data to manipulate
    and #0f000h,R8 ; Isolate most significant dig
    mov #0000Dh,R4 ; Rotate data right 12 times (load loop with 13)
    EXTR_A_LP dec R4
    jz END_A_LP ; If end of counter, exit loop
    clrc
    rrc R8 ; Push data to lowest nybble
    jmp EXTR_A_LP
    END_A_LP cmp #0000ah,R8
    jge LETTER_A ; If dig is letter, manipulate as such
    add #00030h,R8 ; Add 30 to convert the number dig in R8 to ASCII
    jmp WAIT_A
    LETTER_A add #00037h,R8 ; Add 49 to convert the letter dig in R8 to ASCII
    WAIT_A bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_A ; If ready bit not set, keep waiting
    bic.b #UCA0TXIFG,&IFG2 ; Reset ready bit
    SEND_A mov R8,&UCA0TXBUF ; Send this digit
    mov @R9,R8 ; Load data to manipulate
    and #00f00h,R8 ; Isolate second-most significant dig
    clrc
    rrc R8 ; Push data to lowest nybble
    rrc R8
    rrc R8
    rrc R8
    rrc R8
    rrc R8
    rrc R8
    rrc R8
    cmp #0000ah,R8
    jge LETTER_B ; If dig is letter, manipulate as such
    add #00030h,R8 ; Add 30 to convert the number dig in R8 to ASCII
    jmp WAIT_B
    LETTER_B add #00037h,R8 ; Add 49 to convert the letter dig in R8 to ASCII
    WAIT_B bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_B ; If ready bit not set, keep waiting
    bic.b #UCA0TXIFG,&IFG2 ; Reset ready bit
    SEND_B mov R8,&UCA0TXBUF ; Send this digit
    mov @R9,R8 ; Load data to manipulate
    and #000f0h,R8 ; Isolate least significant dig
    clrc
    rrc R8 ; Push data to lowest nybble
    rrc R8
    rrc R8
    rrc R8
    cmp #0000ah,R8
    jge LETTER_C ; If dig is letter, manipulate as such
    add #00030h,R8 ; Add 30 to convert the number dig in R8 to ASCII
    jmp WAIT_C
    LETTER_C add #00037h,R8 ; Add 49 to convert the letter dig in R8 to ASCII
    WAIT_C bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_C ; If ready bit not set, keep waiting
    bic.b #UCA0TXIFG,&IFG2 ; Reset ready bit
    SEND_C mov R8,&UCA0TXBUF ; Send this digit
    mov @R9,R8 ; Load data to manipulate
    and #0000fh,R8 ; Isolate least significant dig
    cmp #0000ah,R8
    jge LETTER_D ; If dig is letter, manipulate as such
    add #00030h,R8 ; Add 30 to convert the number dig in R8 to ASCII
    jmp WAIT_D
    LETTER_D add #00037h,R8 ; Add 49 to convert the letter dig in R8 to ASCII
    WAIT_D bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_D ; If ready bit not set, keep waiting
    bic.b #UCA0TXIFG,&IFG2 ; Reset ready bit
    SEND_D mov R8,&UCA0TXBUF ; Send this digit

    ;Bit test 4 or 5 at beginning of mem loc to determine if print space or not
    mov @R9,R8 ; Load current datum
    bit.w #02000h,R8 ; Check for even or odd
    jnz WAIT_SUFF ; If just printed first word on new line, print space before the next.

    WAIT_SPACE bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_SPACE
    bic.b #UCA0TXIFG,&IFG2 ; Wait, then give data suffix
    SEND_SPACE mov #020h,&UCA0TXBUF ; Send Space 0Dh
    incd R9 ; Move pointer to next memory location
    jmp TOP_EXTRACT

    WAIT_SUFF bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_SUFF
    bic.b #UCA0TXIFG,&IFG2 ; Wait, then give data suffix
    SEND_SUFF mov #0Dh,&UCA0TXBUF ; Send CR 0Dh as SUFFix
    WAIT_PSTSU bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_PSTSU
    bic.b #UCA0TXIFG,&IFG2 ; Wait, then give data suffix
    SEND_SUFF2 mov #0Ah,&UCA0TXBUF ; Send LF 0Ah as SUFFix
    WAIT_PSTSU2 bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_PSTSU2
    incd R9 ; Move pointer to next memory location

    jmp TOP_EXTRACT ; Process next memory location

    ST_BLK_2 mov #045h,&EndBlkChar1 ; "E" End First Memory Block with "ZZZ1"
    mov #04Eh,&EndBlkChar2 ; "N"
    mov #044h,&EndBlkChar3 ; "D"
    mov #031h,&EndBlkChar4 ; "1"
    decd &StMemBlk2 ; So that on next memory output, the device will continue properly past this breakpoint
    jmp END_NUM_SEND

    ST_BLK_3 mov #045h,&EndBlkChar1 ; "E" End Second Memory Block with "ZZZ2"
    mov #04Eh,&EndBlkChar2 ; "N"
    mov #044h,&EndBlkChar3 ; "D"
    mov #032h,&EndBlkChar4 ; "2"
    decd &StMemBlk3 ; So that on next memory output, the device will continue properly past this breakpoint
    jmp END_NUM_SEND
    ST_BLK_4 mov #045h,&EndBlkChar1 ; "E" End Third Memory Block with "ZZZ3"
    mov #04Eh,&EndBlkChar2 ; "N"
    mov #044h,&EndBlkChar3 ; "D"
    mov #033h,&EndBlkChar4 ; "3"
    decd &StMemBlk4 ; So that on next memory output, the device will continue properly past this breakpoint
    jmp END_NUM_SEND
    END_BLK_4 mov #045h,&EndBlkChar1 ; "E" End Fourth Memory Block with "ZZZ4"
    mov #04Eh,&EndBlkChar2 ; "N"
    mov #044h,&EndBlkChar3 ; "D"
    mov #034h,&EndBlkChar4 ; "4"
    mov #0C400h, R9 ; Allows UART button to send the whole memory data serially again.
    jmp END_NUM_SEND
    END_CUR_MEM mov #04Eh,&EndBlkChar1 ; "N" Memory Output Ended at Current Storage Location : Print "NOW!"
    mov #04Fh,&EndBlkChar2 ; "O"
    mov #057h,&EndBlkChar3 ; "W"
    mov #021h,&EndBlkChar4 ; "!"

    END_NUM_SEND
    WAIT_E bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Assimilated from p438
    jz WAIT_E ; If ready bit not set, keep waiting
    bic.b #UCA0TXIFG,&IFG2 ; Reset ready bit
    SEND_E_C1 mov &EndBlkChar1,&UCA0TXBUF ; Send EndBlkChar1
    WAIT_F bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    jz WAIT_F ;
    bic.b #UCA0TXIFG,&IFG2 ;
    SEND_F_C2 mov &EndBlkChar2,&UCA0TXBUF ; Send EndBlkChar2
    WAIT_G bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    jz WAIT_G ;
    bic.b #UCA0TXIFG,&IFG2 ;
    SEND_G_C3 mov &EndBlkChar3,&UCA0TXBUF ; Send EndBlkChar3
    WAIT_H bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    jz WAIT_H ;
    bic.b #UCA0TXIFG,&IFG2 ;
    SEND_H_C4 mov &EndBlkChar4,&UCA0TXBUF ; Send EndBlkChar4
    WAIT_I bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    jz WAIT_I ;
    bic.b #UCA0TXIFG,&IFG2 ;
    SEND_I mov #0Dh,&UCA0TXBUF ; Send CR 0Dh as SUFFix
    WAIT_J bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    jz WAIT_J
    bic.b #UCA0TXIFG,&IFG2 ;
    SEND_J mov #0Ah,&UCA0TXBUF ; Send LF 0Ah as SUFFix
    WAIT_K bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    jz WAIT_K
    ret
    ;------------------------------------------------------------------------------
    ; Interrupt Vectors
    ;------------------------------------------------------------------------------
    .sect ".reset" ; MSP430 RESET Vector
    .short RESET ;
    .sect ".int08" ; Timer_A Vector
    .short TIMER_A_ISR
    .sect ".int05" ; ADC10 Vector
    .short ADC10_ISR
    .sect ".int03" ; Port 2 Vector
    .short UART_ISR ;
    .end

  • Correction.  I also had problems perhaps because of the way I was using my .bss variables.  This code seems to be working properly after several successive runs.

    ;*******************************************************************************
    ; Title: Altitude Data Logger
    ; Author: Rob Snell
    ; Date: April 20, 2012
    ; Purpose: Senior Project-Design Problems, Bob Jones University, Spring 2012
    ;
    ; Very basic code shell was MSP320G2xx2 Demo by D. Dang, TI Inc Dec 2010- WDT, Toggle P1.0, Interval Overflow ISR, 32kHz ACLK
    ;*******************************************************************************
    .cdecls C,LIST, "msp430g2553.h"
    ;.bss Const2,2
    ;.bss StMemBlk2,2 ; Do not use 'comma one' at the end of these .bss things. They glitched when I tried to use them for byte storage.
    ;.bss StMemBlk3,2
    ;;.bss StMemBlk4,2
    ; .bss EndBlkChar1,2
    ;.bss EndBlkChar2,2
    ; .bss EndBlkChar3,2
    ;.bss EndBlkChar4,2
    ;------------------------------------------------------------------------------
    .text ; Program Start
    ;------------------------------------------------------------------------------
    RESET mov.w #0280h,SP ; Initialize stackpointer
    mov.w #WDTPW+WDTHOLD,&WDTCTL ; Turn off Watchdog Timer
    CLKSetup mov.b #LFXT1S_2,&BCSCTL3 ; Since XTS is 0 by default, this selects VLOCLK to source ACLK (12 kHz roughly)
    ; Using ACLK for Timer (See Timer_A_Setup) which interrupts and causes ADC
    clr.b &DCOCTL ; Select lowest DCOx and MODx settings (these three lines copied from pp283-4)
    mov.b &CALBC1_1MHZ,&BCSCTL1 ; Set range
    mov.b &CALDCO_1MHZ,&DCOCTL ; Set DCO step + modulation (1 MHz)
    WDTSetup ; mov.w #WDT_ADLY_250,&WDTCTL ; WDT 250ms, ACLK, interval timer
    PortSetup
    mov.b #00001001b,&ADC10AE0 ; Enable analog input on {now A0 (Pin 2, P1.0) and A3 (Pin 5, P1.3)}; should i enable only when sampling?
    bic.b #00000001b,&P2DIR ; Set P2.0 to input mode (for prompting UART transfer)
    bis.b #00000001b,&P2REN ; Enable P2.0 pullup/down resistor
    bic.b #00000001b,&P2OUT ; Set P2.0 internal resistor to pulldown
    bis.b #00000001b,&P2IE ; Enable P2.0 interrupt
    bic.b #00000001b,&P2IES ; Set P2.0 Transition Trigger to 'low-to-high'
    bic.b #00000001b,&P2IFG ; Reset P2.0 Interrupt Flag
    ; bis.b #WDTIE,&IE1 ; Enable WDT interrupt
    bic.b #00111000b,&P2OUT ; Turn off P2.5 & P2.3
    bis.b #00111000b,&P2DIR ; Set P2.5 & (P2.4 for UART out indicator) & P2.3 to output (for indicating which sensor is being stored)
    ;------------------------------------------------------------------------------
    Timer_A_Setup;
    ;------------------------------------------------------------------------------
    bis.w #TASSEL_1+TAIE,&TACTL ; Select ACLK to power Timer A (12kHz) + Enable Interrupt
    mov.w #00100h,&TACCR0 ; Count limit is FFFF is apx 4.8 sec; 7460h for 4.5 hrs; 3393 for ~1 sample/sec
    ;------------------------------------------------------------------------------
    ADC_Setup; Setup ADC functionality
    ;------------------------------------------------------------------------------
    and.w #0fff0h,&ADC10CTL0 ; Allow ADC config, clear int flag, disable int// automatic on system reset //
    and.w #0fdffh,&ADC10CTL0 ; Turn off Reference Output to save power
    bis.w #ADC10SSEL_1,&ADC10CTL1 ; Changed this to select ACLK (~12kHz) instead of /// Select ADC10OSC for ADC clock source (~ 5 MHz)
    bis.w #ADC10DIV_7,&ADC10CTL1 ; Divide clock by 8 (so 625kHz) (for longer sampling period)
    bis.w #CONSEQ_0,&ADC10CTL1 ; Select single-channel single-conversion mode;
    bis.w #SREF_0,&ADC10CTL0 ; Set Vcc and Vss as limits for conversion;
    bis.w #ADC10ON,&ADC10CTL0 ; Enable conversion core
    bis.w #ADC10SHT_3,&ADC10CTL0 ; Use 64 ADC10OSC cycles for sample input (charge sampling capacitor) // Worth looking into again. p552
    bis.w #INCH_10,&ADC10CTL1 ; Set ADC channel to temperature sensor
    bis.w #ADC10IE,&ADC10CTL0 ; Enable ADC interrupts
    bis.w #ENC,&ADC10CTL0 ; End ADC config
    mov #0C400h,R6 ; C400; Start address for ADC data storage (Must be initialized as first address in a segment!)
    mov #0C400h,R10 ; C400; Load first segment entry boundary for flash erase procedure (Do not change!)
    mov #0FE00h,R7 ; End (First illegal at end) address for ADC data storage
    ;------------------------------------------------------------------------------
    UART_Setup; Setup Serial Functionality
    ;------------------------------------------------------------------------------
    ;mov #0D200h,&StMemBlk2 ; Configure Manual Memory Blocks
    ;mov #0E000h,&StMemBlk3 ;
    ;mov #0EE00h,&StMemBlk4 ;
    bis.b #UCSWRST,&UCA0CTL1 ; enable UART config
    bis.b #00000100b,&P1SEL ; Configure P1.2 for UART use
    bis.b #00000100b,&P1SEL2 ;
    ; bic.b #UCSWRST,&UCB0CTL1 ; Allow turning off UCB interrupt
    ; bic.b #UC7BIT,&UCA0CTL0 (default 8-bit data mode, no parity)
    bis.b #UCSSEL_3,&UCA0CTL1 ; Clock source is SMCLK (1 MHz)
    mov.b #00h,&UCA0BR1 ; Clear top bits of prescaler
    mov.b #104,&UCA0BR0 ; Copied from byu website. See history mov.b #06h,&UCA0BR0 ; Prescale divide by 6 (UCBRx);;
    mov.b #UCBRS0,&UCA0MCTL ; Copied from byu website mov.b #UCBRF_8+UCOS16,&UCA0MCTL ; Set first stage modulator (to 8) and enable oversampling baud rate generation (fast clock source) [9600 baud];;
    mov R6,R9 ; Set iniitial TX address
    bic.b #UCSWRST,&UCA0CTL1 ; end UART config

    ;------------------------------------------------------------------------------
    Timer_A_Start;
    ;------------------------------------------------------------------------------
    bis.w #MC_1,&TACTL ; Count up to TACCR0
    bis.w #TAIE,&TACTL ; Enable Timer Interrupts
    ;------------------------------------------------------------------------------
    Main_Prog_Run;
    ;------------------------------------------------------------------------------
    Mainloop bis.b #00100000b,&P2OUT ; Initialize P2.5 so toggle is correct
    bic.w #OSCOFF,SR ; Confirm ACLK remains on when LPM3 set in next instruction
    bis.w #LPM3+GIE,SR ; Enter LPM3, interrupts enabled
    nop ; Required only for debugger
    ;------------------------------------------------------------------------------

    ;------------------------------------------------------------------------------
    TIMER_A_ISR; Handle a Timer Overflow
    ;------------------------------------------------------------------------------
    bic.w #TAIE,&TACTL ; Disable Timer Interrupts
    cmp R6,R7 ; Test for last memory location
    jz End_of_Mem
    xor.b #00101000b,&P2OUT ; Toggle P2.5 & P2.3
    bis.w #ENC,&ADC10CTL0 ; End ADC config (ADC enable)
    bis.w #ADC10SC,&ADC10CTL0 ; Start ADC conversion
    bic.w #TAIFG,&TACTL ; Reset interrupt flag
    bis.w #TAIE,&TACTL ; Enable Timer Interrupts
    End_of_Mem reti

    ;------------------------------------------------------------------------------
    ADC10_ISR; Handle an ADC Conversion Completion Event
    ;------------------------------------------------------------------------------
    bic.w #ADC10SC,&ADC10CTL0 ; Reset ADC start condition
    bic.w #ENC,&ADC10CTL0 ; Disable ADC for config purposes
    mov.w ADC10MEM,R5 ; Copy ADC result to R5
    ; bit.w #03000h,&ADC10CTL1 ; Test for data source (bit indicating A3) If A3 in, zf (not set)=0.
    ; ; if zf=0, was inch 3 (pin 5) Low Pressure.
    ; jnz Was_Inch_3
    ; bis.w #01000h,R5 ; Label data sample with channel source (A0, Pin 2, High Pressure)
    ; jmp FlashErase
    Was_Inch_3 bis.w #02000h,R5 ; Label data with #02 for Temp Data; Label data sample with channel source (A3, Pin 5, Low Pressure)
    ;------------------------------------------------------------------------------
    FlashErase; Can only erase 512Mb segments; Must erase before write; Code taken extensively from p320-323
    ;------------------------------------------------------------------------------
    bic.w #LPM3,SR ; Enable main clock, (interrupts turned off b/c EEIEX, EEI are reset, interrupts will be handled after flash done)
    cmp R6,R10 ; Compare next write address to each new segment address
    jeq L1 ; If new segment, erase first.
    NewSegTest add #0200h,R10 ; Jump to next segment boundary for testing purposes
    cmp #0FE00h,R10 ; If next segment entry is the last (0FE00h), next address isn't a new segment
    jeq L3
    cmp R6,R10 ; Compare next write address to each new segment address
    jeq L1 ; If new segment, erase first.
    jmp NewSegTest

    ; Flash Erase from within RAM ($03ff to 0200)
    L1 bit #BUSY,&FCTL3 ; Test BUSY
    jnz L1 ; Loop while busy
    mov #FWKEY+FSSEL_1,&FCTL2 ; Use MCLK for the Flash Module (1 MHz)
    mov #FWKEY+00002h,&FCTL2 ; Divide MCLK by 3 (FNx+1) to put freq b/w 250kHz and 450kHz req.
    mov #FWKEY,&FCTL3 ; Clear LOCK
    mov #FWKEY+ERASE,&FCTL1 ; Enable segment erase
    mov #00000h,0(R10) ; Any memory location in that segment;***Must be in same segment as write location
    L2 bit #BUSY, &FCTL3 ; Test BUSY
    jnz L2 ; Loop while busy
    mov #FWKEY+LOCK,&FCTL3 ; Done, set LOCK
    ;-------------------------------------------------------------------------------
    FlashWrite; Write Data in R5 to Flash at address in R6; code taken extensively from p320ff (from within RAM-just extra safety)
    ;-------------------------------------------------------------------------------
    L3 bit #BUSY,&FCTL3 ; Test BUSY
    jnz L3 ; Loop while busy
    mov #FWKEY+FSSEL_1,&FCTL2 ; Use MCLK for the Flash Module (1 MHz)
    mov #FWKEY+00002h,&FCTL2 ; Divide MCLK by 3 (FNx+1) to put freq b/w 250kHz and 450kHz req.
    mov #FWKEY,&FCTL3 ; Clear LOCK
    mov #FWKEY+WRT,&FCTL1 ; Enable write
    mov R5,0(R6) ; Write data in R5 to the address stored in R6
    ; mov @R6,R8 ; For Debugging
    incd R6 ; Double increment R6
    L4 bit #BUSY,&FCTL3 ; Test BUSY
    jnz L4 ; Loop while busy
    mov #FWKEY,&FCTL1 ; Done. Clear WRT
    mov #FWKEY+LOCK,&FCTL3 ; Set LOCK
    ; xor.w #INCH_3,&ADC10CTL1 ; Toggle between ADC channel A0 and A3
    mov #0C400h,R10 ; Prepare for next Flash erase by resetting the segment boundary variable
    bis.w #ENC,&ADC10CTL0 ; Enable ADC
    reti

    ;------------------------------------------------------------------------------
    UART_ISR; Execute UART code upon button press
    ;------------------------------------------------------------------------------
    bic.b #00000001b,&P2IE ; Disable P2.0 interrupt
    bic.w #ENC,&ADC10CTL0 ; Stop ADC
    bis.w #MC_0,&TACTL ; Stop Timer A

    mov #0ffffh,R4 ; Setup delay loop

    Delay dec R4 ; Delay resetting the interrupt to prevent keybounce
    jnz Delay
    bis.b #00010000b,&P2OUT ; Turn on P2.4 (UART Indicator)

    BEGIN_UART ;set sync bit
    bit.b #UCBUSY,&UCA0STAT ; Test for transmission in progress.
    jnz END_UART
    bis.b #UCA0TXIFG,&UC0IFG ; Clear all UCA and UCB interrupts
    call #ExtractNum


    END_UART bis.w #ENC,&ADC10CTL0 ; Enable ADC
    bis.w #MC_1,&TACTL ; Start Timer A
    bic.b #00000001b,&P2IFG ; Reset P2.0 Interrupt Flag
    bis.b #00000001b,&P2IE ; Enable P2.0 interrupt
    bic.b #00010000b,&P2OUT ; Turn off P2.4 (UART Indicator)
    reti

    ;------------------------------------------------------------------------------
    ExtractNum; Turn Memory into Hex
    ;------------------------------------------------------------------------------
    TOP_EXTRACT
    cmp R7,R9 ; Test for last memory address
    jz END_BLK_4
    cmp R9,R6 ; Test for last significant memory address
    jz END_CUR_MEM
    ;cmp &StMemBlk2,R9 ; Test for start manual memory block 2
    ;jz ST_BLK_2
    ;cmp &StMemBlk3,R9 ; Test for start manual memory block 3
    ;jz ST_BLK_3
    ;cmp &StMemBlk4,R9 ; Test for end manual memory block 4
    ;jz ST_BLK_4
    EXTRACT_A mov @R9,R8 ; Load data to manipulate
    and #0f000h,R8 ; Isolate most significant dig
    mov #0000Dh,R4 ; Rotate data right 12 times (load loop with 13)
    EXTR_A_LP dec R4
    jz END_A_LP ; If end of counter, exit loop
    clrc
    rrc R8 ; Push data to lowest nybble
    jmp EXTR_A_LP
    END_A_LP cmp #0000ah,R8
    jge LETTER_A ; If dig is letter, manipulate as such
    add #00030h,R8 ; Add 30 to convert the number dig in R8 to ASCII
    jmp WAIT_A
    LETTER_A add #00037h,R8 ; Add 49 to convert the letter dig in R8 to ASCII
    WAIT_A bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_A ; If ready bit not set, keep waiting
    bic.b #UCA0TXIFG,&IFG2 ; Reset ready bit
    SEND_A mov R8,&UCA0TXBUF ; Send this digit
    mov @R9,R8 ; Load data to manipulate
    and #00f00h,R8 ; Isolate second-most significant dig
    clrc
    rrc R8 ; Push data to lowest nybble
    rrc R8
    rrc R8
    rrc R8
    rrc R8
    rrc R8
    rrc R8
    rrc R8
    cmp #0000ah,R8
    jge LETTER_B ; If dig is letter, manipulate as such
    add #00030h,R8 ; Add 30 to convert the number dig in R8 to ASCII
    jmp WAIT_B
    LETTER_B add #00037h,R8 ; Add 49 to convert the letter dig in R8 to ASCII
    WAIT_B bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_B ; If ready bit not set, keep waiting
    bic.b #UCA0TXIFG,&IFG2 ; Reset ready bit
    SEND_B mov R8,&UCA0TXBUF ; Send this digit
    mov @R9,R8 ; Load data to manipulate
    and #000f0h,R8 ; Isolate least significant dig
    clrc
    rrc R8 ; Push data to lowest nybble
    rrc R8
    rrc R8
    rrc R8
    cmp #0000ah,R8
    jge LETTER_C ; If dig is letter, manipulate as such
    add #00030h,R8 ; Add 30 to convert the number dig in R8 to ASCII
    jmp WAIT_C
    LETTER_C add #00037h,R8 ; Add 49 to convert the letter dig in R8 to ASCII
    WAIT_C bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_C ; If ready bit not set, keep waiting
    bic.b #UCA0TXIFG,&IFG2 ; Reset ready bit
    SEND_C mov R8,&UCA0TXBUF ; Send this digit
    mov @R9,R8 ; Load data to manipulate
    and #0000fh,R8 ; Isolate least significant dig
    cmp #0000ah,R8
    jge LETTER_D ; If dig is letter, manipulate as such
    add #00030h,R8 ; Add 30 to convert the number dig in R8 to ASCII
    jmp WAIT_D
    LETTER_D add #00037h,R8 ; Add 49 to convert the letter dig in R8 to ASCII
    WAIT_D bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_D ; If ready bit not set, keep waiting
    bic.b #UCA0TXIFG,&IFG2 ; Reset ready bit
    SEND_D mov R8,&UCA0TXBUF ; Send this digit

    ;Bit test 4 or 5 at beginning of mem loc to determine if print space or not
    mov @R9,R8 ; Load current datum
    bit.w #02000h,R8 ; Check for even or odd
    jnz WAIT_SUFF ; If just printed first word on new line, print space before the next.

    WAIT_SPACE bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_SPACE
    bic.b #UCA0TXIFG,&IFG2 ; Wait, then give data suffix
    SEND_SPACE mov #020h,&UCA0TXBUF ; Send Space 0Dh
    incd R9 ; Move pointer to next memory location
    jmp TOP_EXTRACT

    WAIT_SUFF bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_SUFF
    bic.b #UCA0TXIFG,&IFG2 ; Wait, then give data suffix
    SEND_SUFF mov #0Dh,&UCA0TXBUF ; Send CR 0Dh as SUFFix
    WAIT_PSTSU bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_PSTSU
    bic.b #UCA0TXIFG,&IFG2 ; Wait, then give data suffix
    SEND_SUFF2 mov #0Ah,&UCA0TXBUF ; Send LF 0Ah as SUFFix
    WAIT_PSTSU2 bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Copied from p438
    jz WAIT_PSTSU2
    incd R9 ; Move pointer to next memory location

    jmp TOP_EXTRACT ; Process next memory location

    ST_BLK_2 ;mov #045h,&EndBlkChar1 ; "E" End First Memory Block with "ZZZ1"
    ;mov #04Eh,&EndBlkChar2 ; "N"
    ;mov #044h,&EndBlkChar3 ; "D"
    ;mov #031h,&EndBlkChar4 ; "1"
    ;decd &StMemBlk2 ; So that on next memory output, the device will continue properly past this breakpoint
    jmp END_NUM_SEND

    ST_BLK_3 ;mov #045h,&EndBlkChar1 ; "E" End Second Memory Block with "ZZZ2"
    ;mov #04Eh,&EndBlkChar2 ; "N"
    ;mov #044h,&EndBlkChar3 ; "D"
    ;mov #032h,&EndBlkChar4 ; "2"
    ;decd &StMemBlk3 ; So that on next memory output, the device will continue properly past this breakpoint
    jmp END_NUM_SEND
    ST_BLK_4 ;mov #045h,&EndBlkChar1 ; "E" End Third Memory Block with "ZZZ3"
    ;mov #04Eh,&EndBlkChar2 ; "N"
    ;mov #044h,&EndBlkChar3 ; "D"
    ;mov #033h,&EndBlkChar4 ; "3"
    ;decd &StMemBlk4 ; So that on next memory output, the device will continue properly past this breakpoint
    jmp END_NUM_SEND
    END_BLK_4 ;mov #045h,&EndBlkChar1 ; "E" End Fourth Memory Block with "ZZZ4"
    ;mov #04Eh,&EndBlkChar2 ; "N"
    ;mov #044h,&EndBlkChar3 ; "D"
    ;mov #034h,&EndBlkChar4 ; "4"
    ;mov #0C400h, R9 ; Allows UART button to send the whole memory data serially again.
    jmp END_NUM_SEND
    END_CUR_MEM ;mov #04Eh,&EndBlkChar1 ; "N" Memory Output Ended at Current Storage Location : Print "NOW!"
    ;mov #04Fh,&EndBlkChar2 ; "O"
    ;mov #057h,&EndBlkChar3 ; "W"
    ;mov #021h,&EndBlkChar4 ; "!"

    END_NUM_SEND
    WAIT_E ;bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send // Assimilated from p438
    ;jz WAIT_E ; If ready bit not set, keep waiting
    ;bic.b #UCA0TXIFG,&IFG2 ; Reset ready bit
    SEND_E_C1 ;mov &EndBlkChar1,&UCA0TXBUF ; Send EndBlkChar1
    WAIT_F ;bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    ;jz WAIT_F ;
    ;bic.b #UCA0TXIFG,&IFG2 ;
    SEND_F_C2 ;mov &EndBlkChar2,&UCA0TXBUF ; Send EndBlkChar2
    WAIT_G ;bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    ;jz WAIT_G ;
    ;bic.b #UCA0TXIFG,&IFG2 ;
    SEND_G_C3; mov &EndBlkChar3,&UCA0TXBUF ; Send EndBlkChar3
    WAIT_H ;bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    ;jz WAIT_H ;
    ;bic.b #UCA0TXIFG,&IFG2 ;
    SEND_H_C4 ;mov &EndBlkChar4,&UCA0TXBUF ; Send EndBlkChar4
    WAIT_I ;bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    ;jz WAIT_I ;
    ;bic.b #UCA0TXIFG,&IFG2 ;
    SEND_I ;mov #0Dh,&UCA0TXBUF ; Send CR 0Dh as SUFFix
    WAIT_J ;bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    ;jz WAIT_J
    ;bic.b #UCA0TXIFG,&IFG2 ;
    SEND_J ;mov #0Ah,&UCA0TXBUF ; Send LF 0Ah as SUFFix
    WAIT_K ;bit.b #UCA0TXIFG,&IFG2 ; Test for ready for next send
    ;jz WAIT_K
    ret
    ;------------------------------------------------------------------------------
    ; Interrupt Vectors
    ;------------------------------------------------------------------------------
    .sect ".reset" ; MSP430 RESET Vector
    .short RESET ;
    .sect ".int08" ; Timer_A Vector
    .short TIMER_A_ISR
    .sect ".int05" ; ADC10 Vector
    .short ADC10_ISR
    .sect ".int03" ; Port 2 Vector
    .short UART_ISR ;
    .end

**Attention** This is a public forum