;******************************************************************************* ; 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 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.w #WDTPW+WDTHOLD,&WDTCTL ; Turn off Watchdog Timer 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 #03393h,&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_0,&ADC10CTL1 ; 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_0,&ADC10CTL1 ; Set ADC channel to A0 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 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 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) NewSegTest cmp R6,&Const2 ;Compare next write address to each new segment address jeq L1 add #0200h,&Const2 cmp #0FE00h,&Const2 ; If next segment entry is the last (0FE00h), next address isn't a new segment jeq L3 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 ; 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 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" 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