Want to add something to your remappable pin woes.
If you look at chip diagram at the begin of the datasheet, almost every pin will have RP added with a number. You can route most peripheral functions through to any peripheral pin on this PIC24.
For a given remappable output you need to select what peripheral output source you want to use, in this case UART TX pin (source 3).
For a peripheral input source you need to choose which remappable input to listen to.
Regarding uart TX/RX interrupt:
1) Hmm, yeah, similar.. but not quite. Interrupts are generated by hardware and tied to the interrupt controller of the CPU. If a hardware interrupt fires, the CPU will look in the interrupt vector table which interrupt handler to execute. That function will be called (similar to an event), regardless of what your main application is doing (one exception: you disabled interrupts in software). The functions called through the main tree are paused.
Interrupts are high priority pieces of code and need to be short. A conventional technique is not to call any functions in an interrupt or have any long polling actions taken place. This makes sure that the interrupt is a short piece of code, thus quick. Remember; it "steals" CPU time from the main() code that can happen at any time. There are some caveats you may need to look out for, like the proper use of "volatile" and atomic read/write. These are necessary because the C compiler is not perfect, and may not be able to see any modifiers to a variable and thus assume it's constant.
2) No strictly not. Remember that most microcontroller peripherals are pretty dumb simple and rely on the software driver to tie them together. Also, some peripherals have some limitations. UART is a good example of that; you can receive a new character at any time, and waiting for a second character to be received or transmitted can take centuries in MCU land. E.g. at 9600Baud a single character will almost take 1ms to transmit. In addition, the UART can only hold a few characters at a time. In your microcontroller, there is a FIFO that hold up to 4 characters. If the FIFO overflows bytes are lost, so you need to read the data in time. A 4-byte FIFO is already quite luxurious; most 8-bit MCU's (and even some ARM micro's) don't have a FIFO and can only hold 1 character at a time.
Because of this you will see most people at least putting RX in an interrupt. That way you can have your main() code do whatever it needs to do, and once in a while come back to a buffer (that's filled by the RX interrupt) and serve the characters.
However, a scenario may happen that you need to transmit lots of TX data as well; and each byte will take 1ms to transmit. If you that messes with other main() code, you could serve interrupts for TX as well.
From what I can see your interrupt bits are correct.
3) Yes, that's correct. I'm sorry but I don't have any working code right at hand now, but an interrupt may look something like tihs:
circularbuffer uart_receive_buffer;
circularbuffer uart_transmit_buffer;
void U1_interrupt_handler(void) // this is not the actual ISR function name
{
if (IFS0bits.U1RXIF) { // RX-not-empty interrupt fired
uint8_t data = U1RXREG; // read register
CircularBufferWrite data into uart_receive_buffer ; // store data in circular buffer; the main() code can read bytes from this buffer
IFS0bits.U1RXIF = 0;
}
if (IFS0bits.U1TXIF) { // TX-empty interrupt fired
if (CircularBufferEmpty uart_transmit_buffer)
{
U1STA = disable TX;
}
else
{
U1TXREG = CircularBufferRead from uart_transmit_buffer;
}
IFS0bits.U1TXIF = 0;
}
}
For persistent storage I would look at using the internal microcontroller FLASH (although you can't erase & write FLASH 1 byte at a time); or an external EEPROM chip connected via I2C or SPI.