assemblyembeddeduartpic18

PIC18f46k42 UART not receiving


The TL;DR first: UART1 receiver isn't receiving; please tell me what I'm doing wrong.

More detailed version:

I'm currently working on a project that uses UART to send status reports between two PIC18f46k42 chips. Previous tests on a prototype board using a f8722 chip worked fine, but after switching to the f46k42, I've only been able to get the transmitter to work; the receive buffer does not fill at all.

I've checked and rechecked the setup described in the documentation (page 480 of the datasheet has a basic checklist), so I've concluded that this is either a simple mistake that I'm blind to, or there is some other setting I've neglected.

Some details and things I've checked while debugging:

Here's some test code using a single chip (wanted to make sure my other chip wasn't bad / oscillator significantly different) and without all the bells and whistles in order to focus on the UART problem. It's not very pretty (contains unnecessary artifacts from other tests), so my apologies in advance. This code never reaches the receive subroutine, there is never anything in the receive buffer (0x00, should be 0x87), the receive FIFO never overflows. Interestingly, the RXIDL bit is clear when running this test, even though it never actually receives anything.

;UART TEST

    #include <p18F46k42.inc> 
    CONFIG  WDTE = OFF
    CONFIG  LVP = OFF
    CONFIG  FEXTOSC = HS          ; External Oscillator Selection (HS (crystal oscillator) above 8 MHz; PFM set to high power)
    CONFIG  RSTOSC = HFINTOSC_1MHZ




PROCR   EQU 0x02    ;Temp register for receiving 
PROCT   EQU 0x03    ;Temp register for transmitting 

    ORG 0x00
    GOTO    START
    ORG 0x100
START:
    BCF TRISD,0
    BCF PORTD,0
    BANKSEL ANSELC
    BCF     ANSELC,7
    BCF     ANSELC,6
    BSF    TRISC,7
    BCF     TRISC,6

UART1_INIT:
    BANKSEL U1BRGL
    MOVLW   d'207' ;particularly slow baud rate for testing purposes
    MOVWF   U1BRGL
    CLRF    U1BRGH
    BANKSEL U1CON0
    MOVLW   b'00110000'  ;enable tx and rx for UART1; 8-bit, no parity
    MOVWF   U1CON0
    MOVLW   b'10000000'  ;enable UART1 module
    MOVWF   U1CON1
    MOVLW   b'00000000'  ;normal polarity (high idle)
    MOVWF   U1CON2

    BANKSEL PIE0
    MOVLW   b'01001000';Turn on UART1, and Receive interrupts
    MOVWF   PIE3


    BANKSEL INTCON0
    BSF INTCON0,GIEH

    BANKSEL U1RXPPS
    MOVLW   b'00010111' ;PORTC,7 for U1 receive pin
    MOVWF   U1RXPPS
    BANKSEL RC6PPS
    MOVLW   b'00010011' ;PORTC,6 for U1 tx pin
    MOVWF   RC6PPS

MAIN:
    MOVLW   0x87
    MOVWF   PROCT
    CALL    TRANSMT
M2:
    BANKSEL PIR3
    BTFSS   PIR3,3  ;check for full receive buffer
    BRA MAIN
    CALL    RECEIVE
    BRA MAIN


TRANSMT: 
    BANKSEL U1FIFO
    BTFSS   U1FIFO,5    ;Check if transmit register is empty
    BRA     TRANSMT     ;If not, wait until it is empty
    MOVF    PROCT,W
    BANKSEL U1TXB
    MOVWF   U1TXB       ;Send data
    RETURN

RECEIVE:
    BANKSEL PIR0
    BCF     PIR3,U1RXIF   ;Clear interrupt flag
    BANKSEL U1RXB
    MOVF    U1RXB,W
    MOVWF   PORTD
    RETURN

    END

Any help is appreciated; this problem is the only thing hampering my progress at the moment and the only thing I haven't been able to figure out on my own.


Solution

  • Finally figured it out (after a significant break to refresh my eyes).

    So, this answer is twofold, applying both to the question here and the problem I created this test program to solve.

    This Question

    This program will work after fixing the interrupt enable. U1RXIE (PIE3,4) should not be set. This was an embarrassing oversight on my part. I'm still not sure why the flag was cleared without the receive buffer being read, though. The following is the working version of the incorrect setup above:

    UART1_INIT:
        BANKSEL U1BRGL
        MOVLW   d'207'
        MOVWF   U1BRGL
        CLRF    U1BRGH
        BANKSEL U1CON0
        MOVLW   b'00110000'
        MOVWF   U1CON0
        MOVLW   b'10000000'
        MOVWF   U1CON1
        MOVLW   b'00000000'
        MOVWF   U1CON2
    
        BANKSEL PIE0
        MOVLW   b'01000000';Turn on UART1 interrupts
        MOVWF   PIE3
    
    
        BANKSEL INTCON0
        BSF INTCON0,GIEH
    
        BANKSEL U1RXPPS
        MOVLW   b'00010111' ;PORTC,7 for U1 recieve pin
        MOVWF   U1RXPPS
        BANKSEL RC6PPS
        MOVLW   b'00010011' ;PORTC,6 for U1 tx pin
        MOVWF   RC6PPS
    

    The overall problem

    In case it helps anyone reading this: my actual code is supposed to interrupt on reception of a data byte. When debugging, it wasn't making it to the ISR, I never saw anything in the receive buffer, and I never saw the interrupt flag set. So I started trying to root out what was wrong using the code above; once I fixed it, I went back to the other test (using interrupts). Since it still didn't work, I knew it had to do with the interrupt.

    Turns out, I messed up when pointing to the IVT, so the address of my ISR was placed in the wrong portion of the table... Addition, of all the things to screw up...

    Well, on the bright side, both were things I messed up on instead of being something I knew nothing about. Thanks to anyone that looked at this question!