Get Adobe Flash player
FacebookTwitterGoogle+
English Arabic French German Italian Portuguese Russian Spanish

Did you know?

"Sleep" features that power down home office equipment and other electronic devices that are turned on but not in use can save households up to $70 annually
 

Help us stay online:

small donate

spi ebaseThe Serial Peripheral Interface (SPI) module is a synchronous serial interface useful for communicating with other peripheral or microcontroller devices. These peripheral devices may be Serial EEPROMs, shift registers, display drivers, A/D converters, etc.Block diagram of the SPI module is shown on picture. Depending on the variant, the dsPIC30F family offers one or two SPI modules on a single device. SPI1 and SPI2 are functionally identical. The SPI2 module is available in many of the higher pin count packages (64-pin and higher), while the SPI1 module is available on all devices.

The SPI serial port consists of the following Special Function Registers (SFRs):
• SPIxBUF: Address in SFR space that is used to buffer data to be transmitted and data that is received. This address is shared by the SPIxTXB and SPIxRXB registers.
• SPIxCON: A control register that configures the module for various modes of operation.
• SPIxSTAT: A status register that indicates various status conditions.
In addition, there is a 16-bit shift register, SPIxSR, that is not memory mapped. It is used for shifting data in and out of the SPI port.

block diagram spi dspic30f

The memory mapped SFR, SPIxBUF, is the SPI Data Receive/Transmit register. Internally, the SPIxBUF register actually consists of two separate registers - SPIxTXB and SPIxRXB. The Receive Buffer register, SPIxRXB, and the Transmit Buffer register, SPIxTXB, are two unidirectional 16-bit registers. These registers share the SFR address named SPIxBUF. If a user writes data to be transmitted to the SPIxBUF address, internally the data gets written to the SPIxTXB register. Similarly, when the user reads the received data from SPIxBUF, internally the data is read from the SPIxRXB register. This double-buffering of transmit and receive operations allows continuous data transfers in the background. Transmission and reception occur simultaneously.
The SPI serial interface consists of the following four pins:
• SDIx: Serial Data Input
• SDOx: Serial Data Output
• SCKx: Shift Clock Input or Output
• SSx: Active low slave select or frame synchronization I/O pulse

For more information read this SPI guide for dsPIC30F. Now we will show you how to use SPI for dsPIC30F4013. Embbeded C30 compiler library is used. Just include "spi.h" in your project and function such as ConfigIntSPI1, WriteSPI1, ReadSPI1 will be available. You can find "spi.h" file in your Microchip instalation directory:
C:\Program Files\Microchip\MPLAB C30\src\peripheral_30F_24H_33F\include\
Also, you can see realization of these function in:
C:\Program Files\Microchip\MPLAB C30\src\peripheral_30F_24H_33F\src\pmc\spi\
A lot of macros for easy configuration are available. Here is "spi.h" file:

"spi.h"

/********************************************************************/
/*              Header for SPI module library functions             */
/********************************************************************/
#if defined(__dsPIC30F__)
#include <p30fxxxx.h>
#elif defined(__dsPIC33F__)
#include <p33Fxxxx.h>
#elif defined(__PIC24H__)
#include <p24Hxxxx.h>
#endif
#ifndef __SPI_H
#define __SPI_H
/* List of SFRs for SPI */
/* This list contains the SFRs with default (POR) values to be used for configuring SPI */
/* The user can modify this based on the requirement */
#define SPI1STAT_VALUE         0x0000
#define SPI2STAT_VALUE         0x0000
#define SPI1BUF_VALUE          0x0000
#define SPI2BUF_VALUE          0x0000
 
#if defined(__dsPIC33F__) || defined(__PIC24H__) || \
    defined(__dsPIC30F1010__) || defined(__dsPIC30F2020__) || defined(__dsPIC30F2023__)
#define _SPI_V2
#define SPI1CON1_VALUE          0x0000
#define SPI2CON1_VALUE          0x0000
#define SPI1CON2_VALUE          0x0000
#define SPI2CON2_VALUE          0x0000
#elif defined(__dsPIC30F__)
#define _SPI_V1
#define SPI1CON_VALUE          0x0000
#define SPI2CON_VALUE          0x0000
#endif
#if defined(_SPI_V2)
/* SPIXCON1 REGISTER bits differing from 30F devices*/
#define DISABLE_SCK_PIN         0xffff  /* Internal SPI clock is diabled, pin functions as I/O */
#define ENABLE_SCK_PIN          0xefff  /*Internal SPI clock is enabled */
/* SPIXCON2 REGISTER */
#define  FRAME_ENABLE_ON        0xffff  /* Frame SPI support enable        */
#define  FRAME_ENABLE_OFF       0x7fff  /* Frame SPI support Disable       */
#define  FRAME_SYNC_INPUT       0xffff  /* Frame sync pulse Input (slave)  */
#define  FRAME_SYNC_OUTPUT      0xbfff  /* Frame sync pulse Output (master)*/
#define FRAME_POL_ACTIVE_HIGH   0xffff  /* Frame sync pulse is active-high*/
#define FRAME_POL_ACTIVE_LOW    0xdfff  /* Frame sync pulse is active-low */
#define FRAME_SYNC_EDGE_COINCIDE 0xffff  /* Frame sync pulse coincides with first bit clock */
#define FRAME_SYNC_EDGE_PRECEDE  0xfffd  /* Frame sync pulse precedes first bit clock */
#define FIFO_BUFFER_ENABLE      0xffff  /* FIFO buffer enabled */
#define FIFO_BUFFER_DISABLE     0xfffe  /* FIFO buffer enabled */
#elif defined(_SPI_V1)
/* SPIxCON REGISTER bits in 30F (non-SMPS) devices differing from 33F and 24H devices */
#define  FRAME_ENABLE_ON        0xffff  /* Frame SPI support enable        */
#define  FRAME_ENABLE_OFF       0xbfff  /* Frame SPI support Disable       */
#define  FRAME_SYNC_INPUT       0xffff  /* Frame sync pulse Input (slave)  */
#define  FRAME_SYNC_OUTPUT      0xdfff  /* Frame sync pulse Output (master)*/
#endif
#define  DISABLE_SDO_PIN        0xffff  /* SDO pin is not used by module   */
#define  ENABLE_SDO_PIN         0xf7ff  /* SDO pin is  used by module      */
#define  SPI_MODE16_ON          0xffff  /* Communication is word wide      */
#define  SPI_MODE16_OFF         0xfbff  /* Communication is byte wide      */
#define  SPI_SMP_ON             0xffff  /* Input data sampled at end of data output time */
#define  SPI_SMP_OFF            0xfdff  /* Input data sampled at middle of data output time */
#define  SPI_CKE_ON             0xffff  /* Transmit happens from active clock 
                                           state to idle clock state*/
#define  SPI_CKE_OFF            0xfeff  /* Transmit happens on transition from
                                           idle clock state to active clock state */
#define  SLAVE_ENABLE_ON        0xffff  /* Slave Select enbale               */
#define  SLAVE_ENABLE_OFF       0xff7f  /* Slave Select not used by module   */
#define  CLK_POL_ACTIVE_LOW     0xffff  /* Idle state for clock is high, active is low */
#define  CLK_POL_ACTIVE_HIGH    0xffbf  /* Idle state for clock is low, active is high */
#define  MASTER_ENABLE_ON       0xffff  /* Master Mode              */
#define  MASTER_ENABLE_OFF      0xffdf  /* Slave Mode               */
#define  SEC_PRESCAL_1_1        0xffff  /* Secondary Prescale 1:1   */
#define  SEC_PRESCAL_2_1        0xfffb  /* Secondary Prescale 2:1   */
#define  SEC_PRESCAL_3_1        0xfff7  /* Secondary Prescale 3:1   */
#define  SEC_PRESCAL_4_1        0xfff3  /* Secondary Prescale 4:1   */
#define  SEC_PRESCAL_5_1        0xffef  /* Secondary Prescale 5:1   */
#define  SEC_PRESCAL_6_1        0xffeb  /* Secondary Prescale 6:1   */
#define  SEC_PRESCAL_7_1        0xffe7  /* Secondary Prescale 7:1   */
#define  SEC_PRESCAL_8_1        0xffe3  /* Secondary Prescale 8:1   */
#define  PRI_PRESCAL_1_1        0xffff  /* Primary Prescale 1:1     */
#define  PRI_PRESCAL_4_1        0xfffe  /* Primary Prescale 4:1     */
#define  PRI_PRESCAL_16_1       0xfffd  /* Primary Prescale 16:1    */
#define  PRI_PRESCAL_64_1       0xfffc  /* Primary Prescale 64:1    */
/* SPIxSTAT REGISTER */
#define  SPI_ENABLE             0xffff  /* Enable module */
#define  SPI_DISABLE            0x7fff  /* Disable module */
#define  SPI_IDLE_CON           0xdfff  /* Continue module operation in idle mode */
#define  SPI_IDLE_STOP          0xffff  /* Discontinue module operation in idle mode */ 
#define  SPI_RX_OVFLOW_CLR     0xffbf   /* Clear receive overflow bit.*/
/* SPI Interrupt defines */
#define  SPI_INT_EN             0xffff  /* SPI Interrupt Enable     */
#define  SPI_INT_DIS            0xfff7  /* SPI Interrupt Disable    */
#define  SPI_INT_PRI_0          0xfff8  /* SPI Interrupt Prior Level_0 */
#define  SPI_INT_PRI_1          0xfff9  /* SPI Interrupt Prior Level_1 */
#define  SPI_INT_PRI_2          0xfffa  /* SPI Interrupt Prior Level_2 */
#define  SPI_INT_PRI_3          0xfffb  /* SPI Interrupt Prior Level_3 */
#define  SPI_INT_PRI_4          0xfffc  /* SPI Interrupt Prior Level_4 */
#define  SPI_INT_PRI_5          0xfffd  /* SPI Interrupt Prior Level_5 */
#define  SPI_INT_PRI_6          0xfffe  /* SPI Interrupt Prior Level_6 */
#define  SPI_INT_PRI_7          0xffff  /* SPI Interrupt Prior Level_7 */
/* Macros to  Enable/Disable interrupts and set Interrupt priority of SPI1 in 33F*/
#define EnableIntSPI1                    _SPI1IE = 1
#define DisableIntSPI1                   _SPI1IE = 0
#define SetPriorityIntSPI1(priority)     _SPI1IP = priority
/* CloseSPI. Disables SPI module */
void  CloseSPI1() __attribute__ ((section (".libperi")));
/* ConfigINtSPI1. Configure Interrupt enable and priorities */
void ConfigIntSPI1(unsigned int config)  __attribute__ ((section(".libperi")));
/* DataRdySPI */
 
char DataRdySPI1() __attribute__ ((section (".libperi")));
/* getcSPI. Read byte from SPIBUF register */
#define  getcSPI1    ReadSPI1
/* getsSPI.Write string to SPIBUF */
unsigned int getsSPI1(unsigned int length, unsigned int *rdptr, unsigned int spi_data_wait)
__attribute__ ((section (".libperi")));
/* OpenSPI1 */
#if defined(_SPI_V2)
void OpenSPI1(unsigned int config1,unsigned int config2, unsigned int config3 )__attribute__ ((section(".libperi")));
#elif defined(_SPI_V1)
void OpenSPI1(unsigned int config1,unsigned int config2 ) __attribute__ ((section (".libperi")));
#endif
/* putcSPI.Write byte/word to SPIBUF register */
#define  putcSPI1    WriteSPI1
/* putsSPI Read string from SPIBUF */
void putsSPI1(unsigned int length, unsigned int *wrptr)__attribute__ ((section (".libperi")));
/* ReadSPI.Read byte/word from SPIBUF register */
unsigned int ReadSPI1() __attribute__ ((section (".libperi")));
/* WriteSPI. Write byte/word to SPIBUF register */
void WriteSPI1(unsigned int data_out) __attribute__ ((section (".libperi")));
#ifdef _SPI2IF
/* Macros to  Enable/Disable interrupts and set Interrupt priority of SPI2 */
#define EnableIntSPI2                    _SPI2IE = 1
#define DisableIntSPI2                   _SPI2IE = 0
#define SetPriorityIntSPI2(priority)     _SPI2IP = priority
/* CloseSPI2.Disables SPI module */
void  CloseSPI2()  __attribute__ ((section (".libperi")));
/* ConfigINtSPI2. Configures Interrupt enable and priorities */
void ConfigIntSPI2(unsigned int config)  __attribute__ ((section(".libperi")));
/* OpenSPI2 */
#if defined(_SPI_V2)
void OpenSPI2(unsigned int config1,unsigned int config2, unsigned int config3 )__attribute__ ((section(".libperi")));
#elif defined(_SPI_V1)
void OpenSPI2(unsigned int config1,unsigned int config2 ) __attribute__ ((section (".libperi")));
#endif
/* DataRdySPI2. Test if SPIBUF register is full */
char DataRdySPI2()  __attribute__ ((section (".libperi")));
/* getcSPI2.Read byte from SPIBUF register */
#define  getcSPI2    ReadSPI2
/* getsSPI2.Write string to SPIBUF */
unsigned int getsSPI2(unsigned int length, unsigned int *rdptr, unsigned int spi_data_wait)
 __attribute__ ((section(".libperi")));
/* putcSPI2.Write byte/word to SPIBUF register */
#define  putcSPI2    WriteSPI2
/* putsSPI2. Read string from SPIBUF */
void putsSPI2(unsigned int length, unsigned int *wrptr)__attribute__ ((section(".libperi")));
/* ReadSPI2.Read byte/word from SPIBUF register */
unsigned int ReadSPI2() __attribute__ ((section (".libperi")));
/* WriteSPI2. Write byte/word to SPIBUF register */
void WriteSPI2( unsigned int data_out) __attribute__ ((section(".libperi")));
#endif
#endif

For easy usage we make our own SPI functions. These function can be use later for every SPI device. As you can see, we have 4 function: InitSPI(), SPIWrite(data), SPIRead() and SPIClose(). Look for comments in InitSPI() function to understand how we configure SPI registers. You can change this data according to your application. For example you can see in article dsPIC30F4013 and LISY300 Gyroscope - SPI example how we use SPI for gyroscope.

"my_SPI.h"

/* 
 * File:   my_SPI.h
 * Created on November 21, 2013, 4:44 PM
 */
void InitSPI(void);                     // Initialization of SPI
void SPIWrite(unsigned int data);       // dsPIC SPI Write function
unsigned int SPIRead(void);		// dsPIC SPI Read function
void SPIClose (void);                   // close SPI

"my_SPI.c"

#include <spi.h>
#include "my_SPI.h"
void InitSPI (void)
{
    unsigned int SPICONValue;
    unsigned int SPISTATValue;
    TRISFbits.TRISF6 = 0;        //Output RF6/SCK1
    TRISFbits.TRISF2 = 1;        //Input  RF2/SDI1
    TRISFbits.TRISF3 = 0;        //Output RF3/SDO1
    ADPCFGbits.PCFG2=1;          //Pin RB2 analgoni
    TRISBbits.TRISB2 = 0;        //Output RB2 (SDC_CS RB2)
    LATBbits.LATB2 = 1;
    SPICONValue =           FRAME_ENABLE_OFF &     //FRMEN:  0 = Framed SPI support disabled
                            FRAME_SYNC_OUTPUT &    //SPIFSD: 0 = Frame sync pulse output (master) 
                            ENABLE_SDO_PIN &       //DISSDO: 0 = SDOx pin is controlled by the module
                            SPI_MODE16_OFF &       //MODE16: 0 = Communication is byte-wide (8 bits)
                            SPI_SMP_OFF &          //SMP:    0 = Input data sampled at middle of data output time
                            SPI_CKE_OFF &          //CKE:    0 = Serial output data changes on transition from Idle clk state to active clk state
                            SLAVE_ENABLE_OFF  &    //SSEN:   0 = SS pin not used by module. Pin controlled by port function
                            CLK_POL_ACTIVE_HIGH &  //CKP:    0 = SS pin not used by module. Pin controlled by port function
                            MASTER_ENABLE_ON &     //MSTEN:  1 = Master mode
                            SEC_PRESCAL_3_1 &      //SPRE<2:0>: Secondary Prescale 3:1
                            PRI_PRESCAL_1_1;       //PPRE<1:0> Primary Prescale 1:1
    SPISTATValue =          SPI_ENABLE &           //SPIEN:   1 = Enables module and configures SCKx, SDOx, SDIx and SSx as serial port pins
                            SPI_IDLE_CON &         //SPISIDL: 0 = Continue module operation in Idle mode
                            SPI_RX_OVFLOW_CLR;     //SPIROV:  0 = No overflow has occurred. Clear receive overflow bit.
    OpenSPI1(SPICONValue, SPISTATValue);
}
void SPIWrite(unsigned int data)
{
    while(SPI1STATbits.SPITBF);
    WriteSPI1(data);  
}
unsigned int SPIRead()
{
    unsigned int tmp = 0;
    WriteSPI1(0);
    while(!DataRdySPI1());
    tmp = ReadSPI1();
    return tmp;
}
void SPIClose (void)
{
    CloseSPI1();
}

In SPIWrite(unsigned int data) function we wait start of transmision (SPITBF: 0 = Transmit started, SPIxTXB is empty), than we send data via embedded library function. In SPIRead() function we check SPIRBF bit, or we wait until transmision is over (1 = Receive complete, SPIxRXB is full).