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?

  • \$\begingroup\$ Check SPI chip select is pulled up to logic 1, and is asserted to 0 correctly during comms. \$\endgroup\$
    – Oliver
    Dec 21, 2014 at 19:42
  • \$\begingroup\$ @Oliver If you mean Slave Select, I have disabled it by specifying SPI1CON1bits.SSEN=0; (which is default), but it still does not solve the problem. \$\endgroup\$
    – Harsha
    Dec 22, 2014 at 14:50
  • 1
    \$\begingroup\$ Can anybody mail me an example SPI code that achieves communication between 2 PIC24 microcontrollers? There seems to be no reference for me to refer. hp07@india.com \$\endgroup\$
    – Harsha
    Dec 24, 2014 at 13:54
  • 1
    \$\begingroup\$ @Harsha: I recommend putting debug code between the statements while and LATA as follows: -display message ("read data, press tab to continue") -wait (for tab press). \$\endgroup\$
    – Guill
    Dec 28, 2014 at 22:21
  • 1
    \$\begingroup\$ If you are not going to use a slave select line, you you need incorporate either a time- or data- based method of detecting the start of a new transmission in order to achieve synchronization. Otherwise you system will depend on startup order, and once mis-synchronized will have no way to correct for that. \$\endgroup\$ Jul 3, 2015 at 16:02

1 Answer 1


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 -> https://github.com/felis/cdb/blob/master/fw/minimal/bsp.c#L185

  • \$\begingroup\$ If that was the problem then there would be no transmission at all but there are changes that occur in the output and also the first transmission happens successfully. \$\endgroup\$
    – Harsha
    Jan 13, 2015 at 8:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.