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:
I'm using mpasm to program, MPLABX, and PICKIT3
U1RXB does not fill with anything, not even garbage data
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.
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!