SPI on dsPIC33 and PPS problems

picspi

I've been trying to get SPI working on my dsPic33FJ64MC802 for a few days now so I'm desperately needing help because nothing seems to be coming out of SCK1 or SDO according to the o-scope.

This is what I'm trying to achieve:

  • SPI in master mode
  • don't care about sdi
  • should be able to see sck or sdo on the oscope

What I noticed that may be wrong:

  • reconfiguring the pins does not seem to work (I've tried unlocking them with no success)

I never found a full SPI example for the pic33 online, so this is what I have from several examples:

#include "SPIUtils.h"
#include<spi.h>

// this may not be needed, I'm not sure
_FOSC(IOL1WAY_OFF);

unsigned int datard ;
void __attribute__((__interrupt__,auto_psv)) _SPI1Interrupt(void)
{
    IFS0bits.SPI1IF = 0;
}

void __attribute__((__interrupt__,auto_psv)) _SPI2Interrupt(void)
{
     IFS2bits.SPI2IF = 0;
     SPI1STATbits.SPIROV = 0; /* Clear SPI1 receive overflow
     flag if set */
}

// For dsPic33FJ64MC802 on a pic microstick
void SPITransmit() {
    //__builtin_disi(20); // need to disable interupts first?
    // PPS needs to first unlock the pins before re-assignment
   __builtin_write_OSCCONL(0x46); // unlock sequence - step 1
   __builtin_write_OSCCONH(0x57); // unlock sequence - step 2
    _IOLOCK = 0;

    // Pins can now change - though, these don't change in the SFR debugger window... why?
    _RP0R = 8;              // configure sck1 as output on pin 4 /RB0/RP0
    _RP1R = 7;              // configure sdo as output on pin 5 /RB1/RP1
    RPINR20bits.SCK1R = 4;  //configure sck1 as input on pin 4
    RPINR20bits.SDI1R = 6;  // configure SDI for input on pin 6

    // these change as expected in the debugger
    TRISBbits.TRISB0 = 0; //sck pin 4 as output
    TRISBbits.TRISB1 = 0; //sdo pin 5 as output
    TRISBbits.TRISB2 = 1; //sdi pin 6 as input

    /* Holds the information about SPI configuartion */
    unsigned int SPICONValue = 0;
    /* Holds the information about SPI Enable/Disable */
    unsigned int SPISTATValue = 0;

    /* Turn off SPI modules */
    CloseSPI1();
    CloseSPI2();
    TMR1 = 0;

    /* Configure SPI1 interrupt */
    ConfigIntSPI1(SPI_INT_EN & SPI_INT_PRI_6);

    /* Configure SPI1 module to transmit 16 bit timer1 value in master mode */
    SPICONValue = FRAME_ENABLE_OFF & FRAME_SYNC_OUTPUT & ENABLE_SDO_PIN & SPI_MODE16_ON &
            SPI_SMP_OFF & SPI_CKE_OFF & SLAVE_ENABLE_OFF & CLK_POL_ACTIVE_HIGH &
            MASTER_ENABLE_ON & SEC_PRESCAL_7_1 & PRI_PRESCAL_64_1;
    SPISTATValue = SPI_ENABLE & SPI_IDLE_CON & SPI_RX_OVFLOW_CLR;

    // what is this third parameter..? the tools library does not mention it.
    // is this the problem? The two parameter OpenSPI1 is not available
    OpenSPI1(SPICONValue, SPISTATValue, 0);

    SPICONValue = FRAME_ENABLE_OFF & FRAME_SYNC_OUTPUT & ENABLE_SDO_PIN & SPI_MODE16_ON &
            SPI_SMP_OFF & SPI_CKE_OFF & SLAVE_ENABLE_OFF & CLK_POL_ACTIVE_HIGH &
            MASTER_ENABLE_OFF & SEC_PRESCAL_7_1 & PRI_PRESCAL_64_1;
    SPISTATValue = SPI_ENABLE & SPI_IDLE_CON & SPI_RX_OVFLOW_CLR;
    OpenSPI2(SPICONValue, SPISTATValue, 0);

    // for the moment, I only care about monitoring data out and the clk in the
    // o-scope
    while (1) {
        // repeadtedly send out 10101..
        WriteSPI1(0xAAAA);
        while (SPI1STATbits.SPITBF);
    }

    // don't care about the input
//    while (!DataRdySPI2());
//    datard = ReadSPI2();
//    if (datard <= 600) {
//        PORTBbits.RB0 = 1;
//    }

    /* Turn off SPI module and clear IF bit */
    CloseSPI1();
    CloseSPI2();

    __builtin_write_OSCCONL(0x46); // unlock sequence - step 1
    __builtin_write_OSCCONH(0x57); // unlock sequence - step 2
    _IOLOCK = 1; // re-lock the ports
}

and use it like so:

#include <p33FJ64MC802.h>
#include <stdint.h>
#include <xc.h>
#include "main.h"
#include "BlinkLed.h"
#include "SPIUtils.h"
int main()
{
    //BlinkLedOnPortB(2, 8);
    SPITransmit();
    return 0;
}

I can't tell what on earth I'm doing wrong. This is the pic microstick.

Best Answer

You don't need to remap your SPI peripheral inside SPITransmit() this only needs to be done once inside your main() for example. Also you can only use the SPI peripheral once the pin assignment is locked. What you are trying to do is transmit while the pin assignment is unlocked therefore in essence your pins have not been properly remapped.

Try the suggestion below.

#include <p33FJ64MC802.h>
#include <stdint.h>
#include <xc.h>
#include "main.h"
#include "BlinkLed.h"
#include "SPIUtils.h"
int main()
{
    // PPS needs to first unlock the pins before re-assignment
    __builtin_write_OSCCONL(0x46); // unlock sequence - step 1
    __builtin_write_OSCCONH(0x57); // unlock sequence - step 2
    _IOLOCK = 0;

    // Pins can now change - though, these don't change in the SFR debugger window... why?
    _RP0R = 8;              // configure sck1 as output on pin 4 /RB0/RP0
    _RP1R = 7;              // configure sdo as output on pin 5 /RB1/RP1
    RPINR20bits.SCK1R = 4;  //configure sck1 as input on pin 4
    RPINR20bits.SDI1R = 6;  // configure SDI for input on pin 6

    __builtin_write_OSCCONL(0x46); // unlock sequence - step 1
    __builtin_write_OSCCONH(0x57); // unlock sequence - step 2
    _IOLOCK = 1; // re-lock the ports

    //BlinkLedOnPortB(2, 8);
    SPITransmit();
    return 0;
}