Simple Two wire SPI communication between two PIC24s


I am trying to achieve a simple SPI communication of 16-bit data from a PIC24FJ64GA002 to another of the same microcontroller.
By following the data sheet to the word, I wrote the transmitter and receiver code as below,


unsigned int i = 0;

void main()
    RPOR2bits.RP4R = 7;  // Data out through Peripheral Pin 4
    RPOR2bits.RP5R = 8;  // Clock out  through Peripheral Pin 5
    SPI1CON1bits.MODE16 = 1; //16 bit mode 
    SPI1CON1bits.MSTEN = 1;  // Master enable
    SPI1CON1bits.SSEN = 0; //No slave selection
    SPI1STATbits.SPIROV = 0; //Receiver Overflow cleared as told in datasheet
    SPI1STATbits.SPIEN = 1; //SPI is enabled
    while (1)
        while (SPI1STATbits.SPITBF); //Waiting for any transmission to complete
        SPI1BUF = i; // Data is written


unsigned int i;

void main()
    RPINR20bits.SDI1R = 0; //Data in through Peripheral pin 0
    RPINR20bits.SCK1R = 2; //Clock in through Peripheral pin 2
    AD1PCFG = 0xFFFF;
    TRISA = 0x0000;
    SPI1CON1bits.MODE16 = 1;
    SPI1CON1bits.MSTEN = 0; // Slave mode
    SPI1CON1bits.SSEN = 0;
    SPI1CON1bits.SMP = 0; //Must be cleared in slave mode as told in datasheet
    SPI1CON1bits.DISSDO = 1; //Receiver only receives data
    SPI1STATbits.SPIROV = 0;
    SPI1STATbits.SPIEN = 1;

    while (1)
        while (!SPI1STATbits.SPIRBF); //waiting for receive to complete
        LATA = SPI1BUF; // pushing Received data onto A

The transmitter seems to be transmitting the data (clock and data lines show expected cycles), but for some reason the receiver does not receive the data and push it onto A terminals.

The configuration settings for both microcontrollers are:

Primary Oscillator Select: Primary Oscillator Disabled 
I2c1 Pin Location Select: Use default SCL 1/SDA 1 pins 
IOLOCK Protection: Disabled 
OSCO Pin Configuration: OSCO functions as port I/O 
Clock Switching and Monitor: Clock switching is enabled, Fail-safe Clock Monitor is enabled 
Oscillator Select: Fast RC Oscillator (FRC) 
Sec Oscillator Select: Default Secondary Oscillator (SOSC) 
Wake-up timer Select: Legacy Wake-up Timer 
Internal External Switch Over Mode: Disabled
External Watchdog Timer Postscaler: 1:32,768
WDT Prescalar: Prescaler ratio of 1:128 
Watchdog Timer Window: Disabled 
Watchdog Timer Enable: Disabled 
Comm Channel Select: Emulator EMUC1/EMUD1 pins are shared with PGC1/PGD1 
Background Debug: Disabled 
General Code Segment Write Protect: Disabled 
General Code Segment Code Protect: Disabled 
JTAG Port Enable: Disabled

The only two connections are the Clock and data lines from the respective peripheral pins. What is the problem here and how to receive the data?

It seems impossible that this actually works, has anybody ever achieved this?

Best Answer

You are assigning pins to peripherals incorrectly. Simply setting the bit is not enough, you must follow an unlock sequence at least once, and it is recommended to lock the register after you're done with assignment. The useful macros are contained in 'pps.h', the code will look like that (for UART2):

PPSOutput( PPS_RP21, PPS_U2TX );
PPSInput( PPS_U2RX, PPS_RP26 );

The whole C file can be seen here ->