;******************************************************************** ; S Gupta ; March 25,2000 ; Copyright S Gupta, 2000 ; DSS2.asm ; Implements a digital storage scope on ADuC812 ; It uses DMA mode of operation in conjunction with Timer 2 ; ADC channel 0 is the default channel used ;******************************************************************** $MOD812 ; use 8052&ADuC812 predefined symbols ; ====================================================================== ; EQUATES ; ====================================================================== DMA_Init EQU 10h ; Data to be loaded in high byte of ; external memory word ; ---------------------------------------------------------------- ; ====================================================================== ; Variables ; ====================================================================== BSEG ORG 30H DMA_Flag: DBIT 1 DSEG ORG 0060h Flag: DS 1 ; Status flag Num_Of_Samples: DS 1 ; Number of ADC pages (# of samples x 256) Start_Adrs_H: DS 1 ; Starting address hi byte Start_Adrs_L: DS 1 ; Starting address lo byte Stop_Adrs_H: DS 1 ; Last address hi byte Stop_Adrs_L: DS 1 ; Last address lo byte Temp1: DS 1 ; Temperary variable Temp2: DS 1 ; Temperary variable ; ---------------------------------------------------------------- ; ====================================================================== ; DEFINE Code segment ; ====================================================================== CSEG ORG 0000h JMP Start ; jump to main program ; ________________________________________________________________ ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ADC ISR ; This subroutine is reached when the DMA operation is complete ; ; Entry: ; DMA_Flag = 0 ; TR2 = 1 ; ; Exit: ; DMA_Flag = 1 ; TR2 = 0; ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ADC_ISR: ORG 0033h ; (ADC ISR) CLR TR2 ; stop conversions by stopping timer2 CLR Dma_Flag ; Clear software flag bit to indicate ; that conversion is over RETI ; ---------------------------------------------------------------- ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Main Program ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ORG 0050h Start: CALL INIT ; Initialize the device CALL SIGN_ON ; Send the first message AGAIN: CALL GET_CMD ; Receive a valid command CALL CONFIG_XMEM ; Initialize external memory CALL CONFIG_DMA ; Set up DMA operation Wait_For_DMA: JB DMA_Flag, Wait_For_DMA ;Wait or do something useful CALL SEND_DATA ; Transmit the recorded data JMP AGAIN ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ; ---------------------------------------------------------------------- ; |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB INIT ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ INIT: ; Initialize stack pointer MOV SP,#0CFH ; Allow 48 bytes for stack ; Initialize serial port MOV A,PCON ; Read PCON register SETB ACC.7 ; Set PMOD bit for high baud rate MOV PCON,A ; Restore PCON MOV SCON,#52H ; Serial port mode 1 ; REN = 1 Receiver enabled ; TI = 1 Set transmitter to be ; in ready state MOV TH1,#0FDH ; 9600 Baud MOV TMOD,#20H ; Select auto reload mode (2) for timer 1 SETB TR1 ; Start Timer1 RET ; ---------------------------------------------------------------- ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB CONFIG_XMEM ; ; This subroutine will set up external memory for DMA operation ; Entry: ; R7 = # of pages (256) of conversions ; ; Used: ; A ; DPTR ; R7 (Not modified) ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CONFIG_XMEM: ; First write the ADC channel # in high byte of external memory ; and clear low byte MOV DPTR,#0000H ; Set Data Pointer to 0 CONFIG_XMEM_2: MOV A,#DMA_Init ; Load high byte of xmem with init data MOVX @DPTR,A INC DPTR CLR A ; clear low byte of xmem MOVX @DPTR,A INC DPTR MOV A,R7 ; Acc = # of pages of conversion CJNE A,DPH,CONFIG_XMEM_2 MOV A,#DMA_Init ; Terminating sequence MOVX @DPTR,A INC DPTR CLR A MOVX @DPTR,A INC DPTR MOV A,#0F0H ; Last byte in xmem MOVX @DPTR,A ; External memory has now been properly ; set up for the required # of ADC scan RET ; ----------------------------------------------------------------- ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB CONFIG_DMA ; ; This subroutine will configure ADC and Timer 2 for DMA operation ; Entry: ; R6 = Time Scale Divisions ; ; Call: ; GET_TIMER_CLICKS ; ; Uses: ; DMAL,DMAH,DMAP ; RCAP2,Timer2 ; ADCCON1,ADCCON2 ; EA,EADC ; DMA_Flag ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CONFIG_DMA: MOV DMAL,#00H ; Set 24 bit DMA pointer to the start MOV DMAH,#00H ; of external memory MOV DMAP,#00H ; Set up Timer 2 for auto reload operation CALL GET_TIMER_CLICKS MOV RCAP2L,R4 ; Load low byte of Sampling interval MOV RCAP2H,R5 ; Load high byte of Sampling interval ; Do not load the timer TL2 and TH2, as after initial delay ; the correct sampling interval will result. ; Set up ADC MOV ADCCON1, #064H ; Power up ADC ; ADC CLK = MCLK / 4 ; Acquisition time = 1 ADC CLK ; Net conversion time = 6.5 usec ; Timer 2 overflow to be used as ADC trigger MOV ADCCON2,#40H ; Enable DMA mode ; Channel 0 SETB EADC ; Enable ADC interrupt. ; Set by DMA at the end of scan SETB EA ; Enable global interrupt bit SETB DMA_Flag ; Set the software flag to indicate that ; DMA operation is taking place ; Can be used by main CPU core to ; prevent from interrupting DMA operation. SETB TR2 ; Start Timer2 operation RET ; ---------------------------------------------------------------- ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB GET_CMD ; ; This subroutine will accept a valid command ; Entry: ; ; EXIT: ; R6 = Timer Clicks (0-F) ; R7 = # of pages (256 Byte) of conversion (1-F) ; ; Used: ; A ; R6, R7 ; Call: ; GET_CMD_PROMPT ; GET_CHAR ; ASCII_2_HEX ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GET_CMD: CALL SEND_CMD_PROMPT ; Send a prompt CALL GET_CHAR CJNE A,#'$',GET_CMD ; Is it '$' sign? If not repeat ; Leading '$' char received ; Wait for T char to specify timer clicks CALL GET_CHAR CJNE A,#'T',GET_CMD ; Is it 'T' sign? If not goto begining CALL GET_CHAR ; Get timer base clicks char CALL ASCII_2_HEX ; Convert to hexadecimal digit MOV R6,A ; R6 = Timer Base clicks GET_CMD_1: CALL GET_CHAR ; Get another comd char CJNE A,#'N',GET_CMD ; Is it 'N' sign? If not repeat CALL GET_CHAR ; Get ASCII char for # of pages CALL ASCII_2_HEX ; Convert to a hexadecimal digit MOV R7,A ; R7 = # of Pages of A/D scan ANL A,R7 ; Test, if the number is equal to 0 JZ GET_CMD ; If it is zero then get a new cmd RET ; --------------------------------------------------------------- ; ++++++**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB GET_TIMER_CLICKS ; ; This subroutine will accept a hexa digit and return a 16 bit time count ; value as set in a table. ; ; Entry: ; R6 = Hex digit ; Exit: ; R4 = Low byte of timer count ; R5 = High byte of timer count ; Used: ; A ; Stack: ; 1 ; Call: ; GET_TIMER_CLICKS_L ; GET_TIMER_CLICKS_H ; ******+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GET_TIMER_CLICKS: MOV A,R6 CALL GET_TIMER_CLICKS_L MOV R4,A ; R4 - Low byte of timer count MOV A,R6 ; Retrieve hex digit again to get high byte CALL GET_TIMER_CLICKS_H MOV R5,A ; R7 - High byte of timer count RET ; ------------------------------------------------------------- GET_TIMER_CLICKS_L: ; Read the lower byte of timer count ; Count is returned in A INC A ; Increment the hex digit to get past RET ; instruction MOVC A,@A+PC ; Read ASCII table RET ; The time interval is not exactly as specified, because of ; the xtal frequency. Use 12 MHz xtal for precise timing, ; though at the expence of lower or non-standrad baud rate DB 9 ; Approximately 10 usec interval (9*12/11.0592 MHz) DB 18 ; 20 usec TH = 0 DB 28 ; 30 usec TH = 0 DB 37 ; 40 usec TH = 0 DB 46 ; 50 usec TH = 0 DB 55 ; 60 usec TH = 0 DB 65 ; 70 usec TH = 0 DB 74 ; 80 usec TH = 0 DB 83 ; 90 usec TH = 0 DB 92 ; 100 usec TH = 0 DB 184 ; 200 usec TH = 0 DB 205 ; 500 usec TH = 1 DB 154 ; 1000 usec (1 msec) TH = 3 DB 51 ; 2000 usec (2 msec) TH = 7 DB 0 ; 5000 usec (5 msec) TH = 18 DB 0 ; 10000 usec (10 msec) TH = 36 GET_TIMER_CLICKS_H: ; Read the upper byte of timer count ; Count is returned in A INC A ; Increment the hex digit to get past RET ; instruction MOVC A,@A+PC ; Read ASCII table RET DB 0 ; Approximately 10 usec DB 0 ; 20 usec DB 0 ; 30 usec DB 0 ; 40 usec DB 0 ; 50 usec DB 0 ; 60 usec DB 0 ; 70 usec DB 0 ; 80 usec DB 0 ; 90 usec DB 0 ; 100 usec DB 0 ; 200 usec DB 1 ; 500 usec DB 3 ; 1000 usec (1 msec) DB 7 ; 2000 usec (2 msec) DB 10 ; 5000 usec (5 msec) DB 36 ; 10000 usec (10 msec) ; ---------------------------------------------------------------- ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB SEND_DATA ; ; This subroutine will transmit the recorded ADC scan to PC through ; serial port ; Transmission starts with a header constaining infor on the timer ; duration and # of pages. ; It is followed by 16 ADC scan per line. ; Each scan of 16 bit ADC data is tranmitted as 4 digits (4 ASCII chars) ; Each scan is separated by a blank space ; Each line is terminated by a CR ; It is done to allow viewing the data on a PC setup as a terminal as well ; as to allow a software running on PC to easily accept this info and ; display it in any useful form, such as a table or graph. ; ; Header: ! T Ticks N #_of_Pages ; Data: #### blank #### blank ....... #### ; ....... ....... ...... ; ; Entry: ; R6 = Timer Clicks (0-F) ; R7 = # of pages (512 Byte) of conversion (0-F) ; EXIT: ; R6 = Timer Clicks (0-F) ; R7 = # of pages (256 Byte) of conversion (1-F) ; ; Used: ; A ; R5, R6, R7 ; Call: ; GET_CMD ; ASCII_2_HEX ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SEND_DATA: MOV R3,#00H ; Clear data counter CALL SEND_HEADER ; First initialize the 24 bit address pointers MOV DMAL,#00H ; Set 24 bit DMA pointer to the start MOV DMAH,#00H ; of external memory MOV DMAP,#00H MOV DPL,#00H ; Set Data pointer to the start MOV DPH,#00H ; of external memory SEND_DATA_2: ; Send a page of data MOVX A,@DPTR ; Read upper byte of result INC DPTR ; Bump up pointer ; If there is an overflow from DPH, the ; page pointer DPH will automatically ; be incremented CALL SEND_BYTE ; Transmit as 2 ASCII chars MOVX A,@DPTR ; Read lower byte of result INC DPTR ; Bump up pointer CALL SEND_BYTE ; Transmit as 2 ASCII chars INC R3 ; Increment data counter CJNE R3,#16D,SEND_DATA_3 ; If 16 sets of results sent then do not ; send blank space MOV A,#20H ; Send a blank char CALL SEND_CHAR SEND_DATA_3: CALL SEND_CRLF ; Send a CR & LF MOV A,R7 CJNE A,DPH,SEND_DATA_2 ; If all pages not sent then send another RET ; --------------------------------------------------------------- ; ++++++**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB SIGN_ON ; ; This subroutine will send a sign on message through serial port ; Entry: ; ; Used: ; A,DPH,DPL(DPTR saved) ; Stack: ; 2 ; Call: ; SEND_CHAR ; ******+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SIGN_ON: PUSH DPH PUSH DPL MOV DPTR,#MSG1 ; Set DPTR to point to the start of message CLR A MOVC A,@A+DPTR ; Read a char SIGN_ON_2: CALL SEND_CHAR ; Transmit the char INC DPTR CLR A MOVC A,@A+DPTR ; Read another char CJNE A,#00H,SIGN_ON_2 ; If not terminating char, then repeat POP DPL POP DPH RET MSG1: DB 0DH,0AH,'MC Journal>',0DH,0AH,00H ; --------------------------------------------------------------- ; ++++++**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB SEND_HEADER ; ; This subroutine will send header info through serial port ; Entry: ; A = Byte ; Used: ; A ; Stack: ; 1 ; Call: ; HEX_2_ASCII ; SEND_CHAR ; ******+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SEND_HEADER: MOV A,#'!' CALL SEND_CHAR MOV A,#'T' CALL SEND_CHAR MOV A,R6 ; Get Timer clicks CALL HEX_2_ASCII CALL SEND_CHAR MOV A,#'N' CALL SEND_CHAR MOV A,R7 ; Get # of pages CALL HEX_2_ASCII CALL SEND_CHAR CALL SEND_CRLF ; Transmit CR & LF ; Read data from external memory one byte at a time and transmit ; Initialize data pointers RET ; --------------------------------------------------------------- ; ++++++**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB SEND_CMD_PROMPT ; ; This subroutine will send a command prompt through serial port ; The prompt is displayed on a new line. ; Used: ; A ; Call: ; SEND_CHAR ; ******+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SEND_CMD_PROMPT: MOV A,#0DH ; Send a leading CR & LF CALL SEND_CHAR MOV A,#0AH CALL SEND_CHAR MOV A,#'C' CALL SEND_CHAR MOV A,#'m' CALL SEND_CHAR MOV A,#'d' CALL SEND_CHAR MOV A,#'>' CALL SEND_CHAR RET ; --------------------------------------------------------------- ; ++++++**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB ASCII_2_HEX ; ; This subroutine will accept an ASCII char and convert it into hex digit ; There is no check allowed, if a non-hexadecimal ASCII char is received. ; ; Entry: ; A = ASCII char ; Exit: ; A = Hex digit ; ; Used: ; A ; ******+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ASCII_2_HEX: CLR C ; Clear carry bit SUBB A,#30H ; A = A - 30H ANL A,#0FH ; Mask off MSNibble. ; Leave only a digit ranging from 0 - F RET ; --------------------------------------------------------------- ; ++++++**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB HEX_2_ASCII ; ; This subroutine will accept a hex digit and convert it into ASCII ; through table look up. ; ; Entry: ; A = Hex digit ; Exit: ; A = ASCII of hex digit ; ; Used: ; A ; ******+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ HEX_2_ASCII: INC A ; Increment the hex digit MOVC A,@A+PC ; Read ASCII table RET DB '0' ; 30H DB '1' ; 31H DB '2' ; 32H DB '3' ; 33H DB '4' ; 34H DB '5' ; 35H DB '6' ; 36H DB '7' ; 37H DB '8' ; 38H DB '9' ; 39H DB 'A' ; 41H DB 'B' ; 42H DB 'C' ; 43H DB 'D' ; 44H DB 'E' ; 45H DB 'F' ; 46H ; --------------------------------------------------------------- ; ++++++**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB SEND_CRLF ; ; This subroutine will send a CR & LF through serial port ; Entry: ; A = Byte ; Used: ; A ; Stack: ; 0 ; Call: ; SEND_CHAR ; ******+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SEND_CRLF: MOV A,#0DH ; Send CR CALL SEND_CHAR ; Transmit through serial port MOV A,#0AH ; Send LF CALL SEND_CHAR ; Transmit through serial port RET ; --------------------------------------------------------------- ; ++++++**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB SEND_BYTE ; ; This subroutine will send a byte through serial port ; Entry: ; A = Byte ; Used: ; A ; Stack: ; 1 ; Call: ; HEX_2_ASCII ; SEND_CHAR ; ******+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SEND_BYTE: PUSH ACC ; Save a copy of Byte ANL A,#0F0H ; Mask off LSNibble CALL HEX_2_ASCII ; Convert to ASCII CALL SEND_CHAR ; Transmit through serial port POP ACC ; Retrieve the original byte SWAP A ; Shift lower bits to upper nibble ANL A,#0F0H ; Mask off LSNibble CALL HEX_2_ASCII ; Convert to ASCII CALL SEND_CHAR ; Transmit through serial port RET ; --------------------------------------------------------------- ; ++++++++**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB GET_CHAR ; ; This subroutine will accept a char through serial port ; Entry: ; ; EXIT: ; A = Char ; Used: ; A ; RI Flag (SCON) ; SBUF ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GET_CHAR: JNB RI,GET_CHAR ; Wait for char to arrive CLR RI ; Reset flag MOV A,SBUF ; Read char RET ; --------------------------------------------------------------- ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SUB SEND_CHAR ; ; This subroutine will send a char through serial port ; Entry: ; A = Char ; Used: ; A (unmodified) ; TI Flag (SCON) ; SBUF ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SEND_CHAR: JNB TI,SEND_CHAR ; Wait till transmitter is ready CLR TI ; Reset flag for next time MOV SBUF,A ; Place char in transmitter RET ; --------------------------------------------------------------- END