Accelerating the advancement of Artificial Intelligence for the advancement of humankind
Introduction To Serial Peripheral Interface (SPI) with the dsPIC33
Suppose we want to send data bytes from one microprocessor to another microprocessor. We can achieve sending data in several ways such as serially or in parallel. In this article, we focus sending data serially and specifically, using a simple protocol known as the Serial Peripheral Interface (SPI). We will only discus the master configuration for this article but the slave configuration should be easy enough to implement once you have the concept.

What you will need
If you want to try out the material from this article, you will need:
  • The PIC33F microstick -
  • MPLABX IDE from Microchip - v2.26 was used for this article
  • An Oscilloscope like the Voltcraft DSO-1052D I use or any of your choosing
  • A breadboard to put the microstick on
  • The datasheets for both the dsPIC33F and the microstick
  • Popcorn - because I think this article is that much fun :) 
Microstick for dsPIC33F
The microstick for the dsPIC33F (see Figure 1)from Microchip is supposed to make debugging and programming PIC24 and PIC33 microcontrollers easier. In many ways, this is true. However, when I got a hold of the TMC246A-PA stepper motor controller, it was a requirement to have an SPI sent to this chip to drive the motor. My initial assumption was that SPI was supposed to be easy. I had done SPI before in my studies as a computer engineer, however, during my education at Mississippi State University, several features of the chip were done via a custom library made by our professors. This made programming easy but coupled us to those libraries - not so good in my opinion. Therefore, in this article, I will use the libraries supplied by Microchip - the manufacturer of the dsPIC33F.

Figure 1. The PIC33F microstick from Microchip
SPI Theory
Before we begin, it is important to understand a bit about SPI and how it works. Of course, feel free to skip this part if you know the theory already.  For simplicity, lets assume the following:
  1. The PIC Microstick is the master and the slave is ignored and unconnected
  2. Our data is clocked out on the rising edge SCK
  3. We transmit the maximum word size for the PIC, which is 16 bits
  4. Chip Selection is ignored
Our set up will resemble Figure 2. 

Figure 2. The PIC33F microstick from Microchip. This is a re-draw of the Microchip's SPI documentation[1]

In Figure 2, we see the rather simple SPI architecture. SCK is a square wave clock pulse SPI uses to synchronize reading and writing of data. How? During the rising edge of SCK, data is shifted out from the shift register and into SDO and similarly, data is shifted into SDI during the falling edge of the clock into the shift register. This means we have full duplex communication between our micro-controller and another peripheral device.

Data Transmission Steps:
  1. Fill the transmit buffer (SSPBUF)
  2. Clear the SPI{1|2}IF in the interrupt

Figure 3. The above timings show when data is clocked in an out. From Robert B. Reese and A. Jones [2]

Project Setup
First off, my apologies for not having the feature of attaching code to this blog post. One of these days I'll get around to putting that feature in so for now, I will explain the details as best I can. If you get stuck, you can always make a post on the comments.

Start up MPLAB IDE X and make sure the microstick is plugged into your computer :
  1. Go to File -> New Project->Microchip Embedded followed by the dsPIC33 C Template
  2. Hit next and choose a name and folder location for your project. Also make sure "Set as main project" is selected. MPLAB will generate a few files for you.
  3. Make sure you have the XC16 compiler tool chain installed. Go to tools -> Plugins->Installed and check to see if "toolchain XC16" has the active green check mark. If not, install the tool chain which you can do in the "Available Plugins" tabs.
If properly setup, your project settings should resemble Figure 3.

Figure 4. Project Settings

Note: On Figure 3, I've made a custom configuration "MyPICMicrostickConfig". You can do the same using the "Manage Configurations" button on this same dialog. Do not forget to choose the proper device for your microstick board. Let me know if I need to go more into detail into setting up a project! For now, this is it.

SPI Code
We will use the spi.h headers to ease our SPI programming. Also, part of the motivation of writing this article was that the libraries were not as straight forward as I thought. This is the minimum set up I found to use SPI with the dsPIC33.

The following is the minimal to run SPI:
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() {
    const int SCK = 0x8;    // 0x8 is the SCK function
    const int SDO = 0x7;    // 0x7 is the SDO function

    // Re-assigning pins are dissabled for the PIC but we must re-assign
    // the pins for SPI so the following is the unlock mechanism; see the
    // PIC manual for more info
    __builtin_write_OSCCONL(OSCCON & ~(1 << 6));
    _IOLOCK = 0;
    // end unlock mechanism

    // Pitfall: DO NOT USE pins RB0 and RB1 on the pic microstick board directly,
    // as they are unconnected! see the PIC microstick board manual
    TRISBbits.TRISB2 = 0; //sck pin 6 as output
    TRISBbits.TRISB3 = 0; //sdo pin 7 as output
    TRISBbits.TRISB4 = 1; //sdi pin 11 as input

    // close SPI if it was enabled before

    // configure pins on RP2 and RP3
    _RP2R = SCK;
    _RP3R = SDO;
    RPINR20bits.SCK1R = 11; //configure sck1 as input on pin 11

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

    /* Configure SPI1 module to transmit 16 bit timer1 value in master mode */

    /* Holds the information about SPI Enable/Disable */
    OpenSPI1(SPICONValue, 0, SPISTATValue);

    OpenSPI2(SPICONValue, SPISTATValue, 1);

    // for the moment, I only care about monitoring data out and the clk in the
    // o-scope
    while (1) {
        //asm("clrwdt"); // clear the wdt if enabled
        WriteSPI1(89);  // send out 1011001
        while (SPI1STATbits.SPITBF);

    unsigned int datard;

    // don't care about the input
    while (!DataRdySPI2());
    datard = ReadSPI2();

    /* Turn off SPI module and clear IF bit */

    __builtin_write_OSCCONL(OSCCON & ~(1 << 6));
    _IOLOCK = 0;

If properly set up, we should be able to see SCK and SDO with the proper equipment (SDI is ignored in this article).

Figure 5. SCK and SDO
In Figure 5, we see SCK and SDO respectively. If you notice, the signal is a bit choppy. That's expected since we have our SCK and SDO next to each other and their signals can interfere when the pins are so close by each other.

Obviously, there is more to SPI but the intention was simply to show how relatively easy it is to set up an MPLab project and start sending data with the PIC33 microstick. On the dsPIC33, we can also have the PIC behave as the slave or even increase the bandwidth of the data by increasing the clock frequency. Let me know what you think!!

Article Owner: RobertoOrellana

Article Creation Date: 9/26/2015 12:00:00 AM

Tags: No server implementation yet

Rating: 9

Rate this article!
comments powered by Disqus