;********************************************************************** ; * ; Filename: USB_Code_test.asm * ; Date: 15th April 2006 * ; File Version: 1.0 * ; * ; Author: Ian Stedman * ; Company: * ; * ; * ;********************************************************************** ; * ; Files required: * ; * ; * ; * ;********************************************************************** ; * ; Notes: * ; A simple program to test the PIC16F877 to FTDI USB interface. * ; It sends 'walking bit codes that are used to verify that there * ; Are no stuck bits or solder shorts between pins. ; * ; * ;********************************************************************** list p=16f877 ; list directive to define processor #include ; processor specific variable definitions __CONFIG _LVP_OFF & _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_OFF & _HS_OSC & _WRT_ENABLE_ON & _DEBUG_OFF & _CPD_OFF ; '__CONFIG' directive is used to embed configuration data within .asm file. ; The lables following the directive are located in the respective .inc file. ; See respective data sheet for additional information on configuration word. ;***** VARIABLE DEFINITIONS w_temp EQU 0x40 ; variable used for context saving status_temp EQU 0x42 ; variable used for context saving adcresult EQU 0x44 ; ADC conversion result usbdatarx EQU 0x46 ; Byte received from USB port usbdatatx EQU 0x48 ; Byte to send via USB count EQU 0x50 temp EQU 0x52 time EQU 0x54 READBIT EQU 0 ; PORT C Read bit to USB WRITEBIT EQU 1 ; PORT C Write bit to USB TXFULL EQU 2 ; PORT C TX Full input from USB RXFULL EQU 3 ; PORT C RX Full input from USB INPORT EQU 255 ; Sets an I/O port as all inputs OUTPORT EQU 0 ; Seta an I/O port as all outputs ;********************************************************************** ORG 0x000 ; processor reset vector clrf PCLATH ; ensure page bits are cleared goto main ; go to beginning of program ORG 0x004 ; interrupt vector location movwf w_temp ; save off current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save off contents of STATUS register ; isr code can go here or be located as a call subroutine elsewhere movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt main call picinit mainloop call usbrecv call display movlw 20 movwf time call delay ; Start of the test code. The idea is to turn on each data bit individually, giving 32 codes for the 8 bit interface movlw h'00' movwf usbdatatx call usbsend movlw h'01' movwf usbdatatx call usbsend movlw h'02' movwf usbdatatx call usbsend movlw h'03' movwf usbdatatx call usbsend movlw h'04' movwf usbdatatx call usbsend movlw h'05' movwf usbdatatx call usbsend movlw h'06' movwf usbdatatx call usbsend movlw h'07' movwf usbdatatx call usbsend movlw h'08' movwf usbdatatx call usbsend movlw h'09' movwf usbdatatx call usbsend movlw h'0A' movwf usbdatatx call usbsend movlw h'0B' movwf usbdatatx call usbsend movlw h'0C' movwf usbdatatx call usbsend movlw h'0D' movwf usbdatatx call usbsend movlw h'0E' movwf usbdatatx call usbsend movlw h'0F' movwf usbdatatx call usbsend movlw h'10' movwf usbdatatx call usbsend movlw h'20' movwf usbdatatx call usbsend movlw h'30' movwf usbdatatx call usbsend movlw h'40' movwf usbdatatx call usbsend movlw h'50' movwf usbdatatx call usbsend movlw h'60' movwf usbdatatx call usbsend movlw h'70' movwf usbdatatx call usbsend movlw h'80' movwf usbdatatx call usbsend movlw h'90' movwf usbdatatx call usbsend movlw h'A0' movwf usbdatatx call usbsend movlw h'B0' movwf usbdatatx call usbsend movlw h'C0' movwf usbdatatx call usbsend movlw h'D0' movwf usbdatatx call usbsend movlw h'E0' movwf usbdatatx call usbsend movlw h'F0' movwf usbdatatx call usbsend movlw h'00' movwf usbdatatx call usbsend goto mainloop ; remaining code goes here picinit banksel OPTION_REG movlw H'07' movwf OPTION_REG ; Set TMR0 to divide internal clock by 256 banksel TRISB movlw OUTPORT movwf TRISB ;portb [7-0] outputs movwf TRISA ;porta [7-0] outputs movlw H'0C' ;setup portc [2-3] inputs [0-1,4-7] outputs movwf TRISC movlw INPORT ;setup portd as inputs for now (USB port) movwf TRISD clrf ADCON1 ;left justified, all inputs a/d bcf STATUS,RP0 ;bank 0 movlw H'FF' movwf PORTC ; Ensure Ouputs are 1 (no read/write) clrf PORTB ; All LEDs off. clrf PORTA movlw B'01000001' ;Fosc/8 [7-6], A/D ch0 [5-3], a/d on [0] movwf ADCON0 bsf PORTC,6 ; Debug return ; At the moment a simple function to output the received USB value to the 8 LEDs on Port B display movf usbdatarx,W ; Recall received data bcf PORTC,7 movf usbdatarx,W movwf PORTB ; Output it, job done! bsf PORTC,7 bsf PORTC,6 bsf PORTC,5 return ; A function to check for data received from the USB interface and if present, read it. ; USB is on port D, RC0=READ, RC3=RX_Flag usbrecv btfsc PORTC,RXFULL ; See if RX_flag = 0 which indicates there is data in the FIFO retlw 0 ; return 0 for no data ;If we got here there is data to read. Set PORT D = Input, READ=High, wait, READ=Low then read port D banksel TRISD movlw INPORT movwf TRISD ; PORT D now input, safe to start the read access. banksel PORTD bsf PORTC,READBIT nop nop bcf PORTC,READBIT ; READ now active LOW so READ port D nop nop movf PORTD,W movwf usbdatarx bsf PORTC,READBIT ; Set RD = hig return ; A function to send a byte of information via the USB interface. Checks the TXF flag prior to sending. ; USB is on port D, RC1=Write, RC2=TX_Flag ; The data to send will be in usbdatatx usbsend movf PORTC,W ; Read in PORT C for debug btfsc PORTC,TXFULL ; See if TX_Flag = 0 which indicates OK to transmit. retlw 0 ; Return with 0 if full how???? ;If we get here we can transmit. Set PORT D = output, WRITE=High, Wait, WRITE=Low then Write Data, Write=High banksel TRISD movlw OUTPORT movwf TRISD ; PORT D now output banksel PORTD bsf PORTC,WRITEBIT ; Make sure WR is high before data output. movf usbdatatx,W movwf PORTD nop bcf PORTC,WRITEBIT ; Write now active nop bsf PORTC,WRITEBIT ; All done, WR = high. ; Now tristate the databus, set PORT D to input. banksel TRISD movlw INPORT movwf TRISD ; PORT D now input banksel PORTD ; Return to page 0 nop return ;******************************************************************* ; DELAY Subroutine. This routine provides a 1 second delay. Call for ; as long as you want by storing your desired delay in 'time' before ; calling. ; EXAMPLE ; movlw 10 ; The value here determines the time delay in seconds. ; movwf time ; Store the value. ; call delay ; call the delay routine. ; delay call delay1 ; these lines make sure that the 1 second loop executes n times. decfsz time goto delay return ; When time is up, return from subroutine. delay1 ; The code here initialise the RTCC. bsf STATUS,RP0 movlw 0x07 ; For use by RTCC, prescaler was /256 or 0x07 movwf OPTION_REG ; ditto bcf STATUS,RP0 clrf TMR0 movlw 0x0e ; Delay time value for 1 second movwf count ; store the value movwf temp sloop ; What follows is the actual delay loop for 1 second. btfsc TMR0,5 ; Reset the RTCC, wait for TMR0 bit 5 to go hich goto jmp1 goto sloop jmp1 clrf TMR0 ; RTCC is cleared so decrement the count & repeat. decfsz count goto sloop wlooplo decfsz temp,F goto wlooplo return END ; directive 'end of program'