.include "p24FJ48GA002.inc" config __CONFIG1, JTAGEN_OFF & GCP_OFF & GWRP_OFF & BKBUG_OFF & COE_OFF & ICS_PGx1 & FWDTEN_OFF & WINDIS_OFF & FWPSA_PR32 & WDTPS_PS1 config __CONFIG2, IESO_ON & FNOSC_PRIPLL & FCKSM_CSDCMD & OSCIOFNC_OFF & IOL1WAY_OFF & I2C1SEL_PRI & POSCMOD_XT ;****************************************************************************** .section ramdata,bss ; ,address(0x800) DBUF: .space 2048 ; Channel data U1_TXN: .space 2 ; number of bytes to transmit by UART1 U1_TXPTR: .space 2 ; pointer to next byte to transmit U1_TXSTATE: .space 2 ; transmit status U1_RXN: .space 2 ; number of received bytes U1_RXMAX: .space 2 ; maximum number of bytes to receive U1_RXPTR: .space 2 ; pointer to space to store received data U1_RXSTATE: .space 2 ; receive status U1_RXTERM: .space 2 ; receive terminating character HELP: .space 2 T1_CNT: .space 2 ; incremented by Timer 1 ;****************************************************************************** .section romdata,psv MSG1: .ascii "Hello World!\0" MSG2: .ascii "ABCDEFG\0" MSG3: .ascii "AAA\0" ;****************************************************************************** .section *,code .global __reset __reset: ; takes control at device reset/power-on mov #0x2700,w15 ; initialize stack pointer mov #0x27FE,w0 ; and stack limit register (256 bytes space) mov w0,SPLIM ; btst RCON,#POR ; was this a power-on reset? bra z,Start ; branch if not ; clr FaultCount ; else clear fault counter bclr RCON,#POR Start: ;**** General Initialisation *************************************************************************** bclr OSCCON,#6 ; Unlock Config Protection mov #psvpage(romdata),W0 ; Make romdata section visible in data ram space 0x8000-0xFFFF mov W0,PSVPAG bset CORCON,#PSV ;**** Input_Output Initialisation ********************************************************************** mov #0xF1FC,W0 ; Configure Pins 2,3,24,25,26 as Analog Input mov W0,AD1PCFG mov #0xFFEF,W0 ; Configue Pin 12 as Output mov W0,TRISA mov #0xE0BF,W0 ; Configue Pins 15,17,18,21,22,23 as Output mov W0,TRISB ;**** UART1 Initialisation ***************************************************************************** mov #0x0302,W0 ; Configure Inputs RP2=UART1_RXD, RP3=UART1_CTS mov W0,RPINR18 mov #0x0403,W0 ; Configure Outputs RP4=UART1_TXD, RP5=UART1_RTS mov W0,RPOR2 bset U1MODE,#15 ; UART1 enable bclr U1MODE,#14 ; Don't freeze in debug mode bclr U1MODE,#13 ; Continue operation in Idle Mode bclr U1MODE,#12 ; Disable IrDa bclr U1MODE,#11 ; RTS flow control bclr U1MODE,#10 ; UART1 uses default i/o-pins bset U1MODE,#9 ; RTS and CTS flow control done by hardware bclr U1MODE,#8 bset U1MODE,#7 ; wake up on start bit bclr U1MODE,#6 ; no loopback bclr U1MODE,#5 ; no baud rate measurement bclr U1MODE,#4 ; RxD idle state is 1 bset U1MODE,#3 ; High baud rate select bclr U1MODE,#2 ; 8-bit data, no parity bclr U1MODE,#1 bclr U1MODE,#0 ; 1 stop bit bset U1STA,#15 ; Generate Interrupts when TX-buffer is empty bclr U1STA,#13 bclr U1STA,#14 ; TxD idle state is 1 (?) inconsistent with doc!! bclr U1STA,#11 ; no sync break bset U1STA,#10 ; TxD enabled bclr U1STA,#7 ; Generate Interrupt when a character is received bset U1STA,#6 bclr U1STA,#5 ; no addres mode detect bclr U1STA,#1 ; clr err bset IEC0,#U1RXIE ; enable UART1 rx-interrupts ; mov #0x0003,W0 ; Set UART1 baudrate to 1MBit mov #3332,W0 ; Set UART1 baudrate to 1.2k mov W0,U1BRG bclr IPC2,#U1RXIP2 ; Set UART1 Receive interrupt priority to 3 bset IPC2,#U1RXIP1 bset IPC2,#U1RXIP0 bclr IPC3,#U1TXIP2 ; Set UART1 transmit interrupt priority to 2 bset IPC3,#U1TXIP1 bclr IPC3,#U1TXIP0 bset IEC0,#U1RXIE ; enable UART1 rx-interrupts bclr IFS0,#U1TXIF ; Clear UART1 tx-interrupt flag bclr IFS0,#U1RXIF ; Clear UART1 rx-interrupt flag clr T1_CNT ; init T1 counter bset IEC4,#U1ERIE ; enable UART1 error-interrupts clr U1_TXN ; initialize U1RX/TX global variables clr U1_TXPTR clr U1_TXSTATE clr U1_RXN clr U1_RXMAX clr U1_RXPTR clr U1_RXSTATE mov #0xF00A,W0 ; set as terminating char mov W0,U1_RXTERM ;**** Timer1 Initialisation ***************************************************************************** mov #250,W0 ; Timer 1 period value for 1ms mov W0,PR1 mov #0x8020,W0 ; Timer 1 control mov W0,T1CON bclr IFS0,#T1IF ; Clear Timer 1 interrupt flag bset IEC0,#T1IE ; Enable Timer 1 interrupt ;**** Main ******************************************************************** ;**** Main ******************************************************************** ;**** Main ******************************************************************** mov #2048,W0 ; clear DBUF byte-wise mov #DBUF,W1 mov #0,W2 M1: mov.b W2,[W1++] ; fill-loop dec W0,W0 bra NZ,M1 M10: btst T1_CNT,#10 ; wait 1s bra Z,M10 mov #DBUF,W1 ; init U1 reception mov #7,W0 ; max length of string call U1RX ; start reception ; mov #DBUF,W1 ; init U1 transmission for 4 bytes from near RAM ; mov #4,W0 mov #psvoffset(MSG2),W1 ; init U1 transmission for from PSV-Page constant mov #7,W0 ; length of string call U1TX ; start transmission M2: CP0 U1_RXSTATE ; wait until rx has finished bra NZ,M2 mov #7,W0 ; check correct no. of bytes CP U1_RXN bra nz, M3 bset LATB,#11 ; turn on yellow LED if ok M3: mov #psvoffset(MSG2),W1 ; check if rx-string = tx-string ; mov #psvoffset(MSG3),W2 mov #DBUF,W2 call STRCMP bra NZ,M4 bset LATB,#12 ; turn on green LED if equal M4: goto $ ;****************************************************************************** .global __T1Interrupt __T1Interrupt: push SR bclr IFS0,#T1IF ; Clear Timer 1 interrupt flag ; btg LATB,#10 ; toggle red LED inc T1_CNT ; increment T1-counter pop SR RETFIE ;****************************************************************************** .global __U1TXInterrupt __U1TXInterrupt: push SR push W0 push W1 bclr IFS0,#U1TXIF ; Clear UART1 tx-interrupt flag cp0 U1_TXSTATE ; Do nothing if idle bra Z,U2 U3: mov U1_TXPTR,W0 ; get byte to transmit from buffer mov.b [W0],W1 mov W1,U1TXREG ; write byte to transmitter inc U1_TXPTR ; increment pointer dec U1_TXN ; decrement number of bytes bra Z,U1 ; exit if all transmitted btst U1STA,#UTXBF ; check if UART1 tx-buffer is full bra Z,U3 ; do next byte bra U2 ; else exit for this time U1: clr U1_TXSTATE ; Set U1 Tx-state to idle bclr IEC0,#U1TXIE ; disable UART1 tx-interrupts U2: pop W1 pop W0 pop SR RETFIE ;****************************************************************************** .global __U1RXInterrupt __U1RXInterrupt: push SR push W0 push W1 bclr IFS0,#U1RXIF ; Clear UART1 rx-interrupt flag cp0 U1_RXSTATE ; continue if not idle bra NZ,U9 mov U1RXREG,W0 ; discard dummy byte from rx buffer bset LATB,#10 ; red LED bra U7 U9: mov U1_RXPTR,W1 ; load pointer to buffer in W1 mov U1RXREG,W0 ; get byte from rx buffer cp U1_RXTERM ; check if byte in W0 is terminator (word-compare!) bra NZ,U8 ; jump if not clr W0 ; replace byte by 0x00 clr U1_RXSTATE ; reception end, set U1 state to idle ; bclr IEC0,#U1RXIE ; Disable further UART1 rx-interrupts U8: mov.b W0,[W1] ; write byte to buffer inc U1_RXPTR ; increment pointer inc U1_RXN ; increment number of bytes mov U1_RXMAX,W0 ; check if buffer full cp U1_RXN bra N,U6 ; jump if no overflow clr U1_RXSTATE ; else reception end, set U1 state to idle ; bclr IEC0,#U1RXIE ; Disable further UART1 rx-interrupts U6: cp0 U1_RXSTATE ; reception end? bra Z,U7 ; yes, exit btst U1STA,#URXDA ; check if another rx-char is available bra NZ,U9 ; if yes, do next byte U7: pop W1 pop W0 pop SR RETFIE ;****************************************************************************** .global __U1ErrInterrupt __U1ErrInterrupt: bset LATB,#10 ; red LED RETFIE ;*** U1TX*** ****************************************************************** ; Description: ; Starts a block transmission of bytes with UART1. The UART1 initialisation ; has to be done properly. The transmission is started resp. done by enabling ; the __U1TXInterrupt service routine. ; Following global variables are used: ; U1_TXSTATE: 0=idle,1=busy,2=error ; U1_TXPTR: pointer to next byte of data to transmit ; U1_TXN: number of bytes to transmit ; Input : W1=pointer to data, W0=number of bytes ; Output: W0=0 if started properly, W0=1 if previous job has not yet finished ; Destr.: flags,W0 ; Needs : global variables as described, __U1TXInterrupt ;****************************************************************************** U1TX: cp0 U1_TXSTATE ; check previous transmission state bra Z,U4 ; go further if finished cp0 W0 ; 0 bytes? bra NZ,U4 ; go further if >0 mov #1,W0 return U4: mov W1,U1_TXPTR ; store pointer mov W0,U1_TXN ; store number of bytes inc U1_TXSTATE ; set tx state to busy clr W0 bset IEC0,#U1TXIE ; enable UART1 tx-interrupts bclr IFS0,#U1TXIF ; Initiate transmission of 1st byte bset IFS0,#U1TXIF return ;*** U1RX ********************************************************************* ; Description: ; Starts a block reception of bytes via UART1. The UART1 initialisation has ; to be done properly. The reception is started resp. done by enabling the ; __U1RXInterrupt service routine. The receive sequence ends, if U1_RXTERM ; is received or U1_RXN reaches U1_RXMAX. If the reception should not terminate ; by any character, set the h-byte of U1_RXTERM to value greater than 0x00. ; The terminating character is replaced by 0x00 in the buffer to act as string ; terminator. ; Following global variables are used: ; U1_RXSTATE: 0=idle,1=busy,2=error ; U1_RXPTR: pointer to next byte of data to store ; U1_RXN: number of bytes received ; U1_RXMAX: maximum number of bytes to receive ; U1_RXTERM: l-byte - rx terminating character, h-byte termination select ; Input : W1=pointer to data, W0=max. number of bytes to receive ; Output: W0=0 if started properly, W0=1 if previous job has not yet finished ; Destr.: flags,W0 ; Needs : global variables as described, __U1RXInterrupt ;****************************************************************************** U1RX: cp0 U1_RXSTATE ; check previous reception state bra Z,U5 ; jump if finished mov #1,W0 return U5: mov W1,U1_RXPTR ; store pointer mov W0,U1_RXMAX ; store max. number of bytes clr U1_RXN ; reset byte counter inc U1_RXSTATE ; set rx state to busy ; bclr U1STA,#OERR ; clear and reset errors ; mov U1RXREG,W0 ; read dummy byte from rx buffer ; bset IEC0,#U1RXIE ; enable UART1 rx-interrupts clr W0 return ;*** STRCMP ******************************************************************* ; Description: ; Compares two 0-terminated strings bytewise case sensitive. ; Input : W1=pointer to string1, W2=pinter to string2 ; Output: Z-flag set if equal ; Destr.: flags ; Needs : ;****************************************************************************** STRCMP: push W0 push W1 push W2 push W3 S3: mov.b [W1],W0 ; get byte from string1 mov.b [W2],W3 ; get byte from string2 cp.b W0,W3 ; bytes equal? bra NZ,S1 ; exit if not equal cp0.b W0 ; end of strings reached? bra Z,S1 ; exit if yes, stings are equal inc W1,W1 ; else do next bytes inc W2,W2 bra S3 S1: pop W3 pop W2 pop W1 pop W0 return .end