The Serial Peripheral Interface (SPI) is a high speed, synchronous, serial communication standard. This communication protocol is basically a Master – Slave implementation where the master device controls the clock based on which the slave devices operate. The master communicates with a slave or a number of slaves in a system through the SPI bus.
The SPI bus requires a minimum of three wires including SDO (Serial Data Out), SDI (Serial Data Input) and SCK (Serial Clock). Since it is a master controller system the SDO is also called MOSI (Master Output Slave Input) and the SDI is also called MISO (Master Input Slave Output).
The SPI is a full-duplex high speed communication protocol. The master and slave can transmit and receive data at the same time. The master is the device which generates clock for all these data transmissions.
Read PIC microcontroller tutorial based on PIC18F4550 microcontrollers in which one of the microcontroller acts as a slave transmitter and the other acts as master receiver.
[[wysiwyg_imageupload:8843:]]
In PIC18F4550 microcontroller the hardware implementation for the SPI interface can be viewed as a simple SISO (Serial-In-Serial-Out) Shift register controlled by a Clock.
Fig. 2: Block Diagram of hardware implementation for SPI interface in PIC18F4550 microcontroller
The above diagram is a single buffer implementation of the SPI hardware. The data is shifted into the buffer from the slave device through the SDI (MISO) and the data is shifted out of the buffer to the slave through the SDO (MOSI). The only difference in the hardware configuration of a master and slave device is the direction of the clock. For a master device the clock is always output and for a slave device the clock is always input.
The Clock unit can generate the clock required for the data transmission. In case of a master device the clock is generated by the device and all other devices in the SPI bus send or receive data to the master based on this clock. When the microcontroller is configured as a slave it can only accept the clock from a master device.
On each clock generated or received one bit in the SISO register is shifted from the SDI to SDO. After the eighth clock since the communication starts, one byte of data has been shifted out through the SDO and one byte of data has been shifted in through the SDI. Now the SISO has an entire byte received from the slave while transmitting a byte to the slave.
In PIC18F4550 the Serial Communication registers are not dedicated for the SPI only, but it can be configured for IIC communication also. The entire module is called Master Synchronous Serial Port (MSSP) module. There are a few registers available in the PIC18F4550 which helps to configure the MSSP as an SPI master or slave module. The major registers associated with the SPI communication in the PIC18F4550 are SSPBUF, SSPSTAT and SSPCON1 register.
SSPBUF
The Synchronous Serial Port Buffer (SSPBUF) register is the register which holds the SPI data which needed to be shifted out to the slave or which has been shifted in from the slave. In case of a slave device this register holds the SPI data which needed to be shifted out to the master or which has been shifted in from the master.
SSPSTAT
The Synchronous Serial Port Status (SSPSTAT) register is the register which holds the status of the SPI module. The first two bits and the last bit of this register are only dedicated for the SPI communication.
Fig. 3: Bit Configuration of SSPSTAT Register in SPI Communication
The SMP bit decides when the master should sample the data, the CKE decides when to transmit data based on the clock transition and the value of BF indicates whether the SSPBUF is full or not (reception complete or not).
SSPCON1
The Synchronous Serial Port Control 1(SSPCON1) register is the register which is dedicated register for the control of SPI only. All the bits of these register are significant and should be carefully set them.
Fig. 4: Bit Configuration of SSCON1 Register in SPI Communication using PIC
WCOL bit indicates whether a Write collision has been occurred or not, the SSPOV indicates whether an overflow occurred in SSPBUF or not, SSPEN is the bit which is used to enable or disable the SPI module. The CKP bit is used to decide which are the idle state and the active state of the clock. The bits SSPM3 to SSPM0 is used to set the device as a master or slave with required clock frequency for master and SS enabled or disabled for the slave.
The registers are explained with more details in PIC microcontroller
READ AND WRITE OPERATIONS
Whenever the master or slave needs to transmit data, it can simply write the data to the SSPBUF. When the master writes the data to the SSPBUF the clock will get generated automatically and with each clock the data from the SSPBUF is shifted out through the SDO pin bit by bit. When the slave writes into the SSPBUF the data remains there until the master generates a clock which will shift the data out from the slave’s SSPBUF through its SDO pin.
Apart from simply writing into the SSPBUF for data transmission, the master or slave can also read the received data from the SSPBUF. The master and slave should write or read from the SSPBUF in a particular manner only. Read PIC microcontroller tutorial to know more.
TIPS FOR CODING:
The SPI protocol is implemented in different devices in different manner and hence when it comes to the coding one should carefully study all the hardware details regarding the SPI implementation in the device for which the coding should be done. Care should be taken especially on the clock frequency, SPI pin’s multiplexed arrangement, clock polarity settings, use of SS pin and code performance etc. To have clear understanding of code writing visit PIC Microcontroller tutorial.
CODE DETAILS
The code includes a few functions for initializing the SPI module, sending and receiving the SPI data etc. The details of the functions are given below;
Voidspi master_init ( void )
This function is used to initialize the SPI module as a master with the required clock frequency. It also set the clock polarity and when to sample input data and to transmit output data regarding the clock transition states. It also sets the SPI pins as input or output as required by the master. It can also disable all other modules multiplexed into the SPI pins.
Voidspi slave_init ( void )
This function is used to initialize the SPI module as a slave with SS pin enabled. It also set the clock polarity and when to sample input data and to transmit output data regarding the clock transition states. It also sets the SPI pins as input or output as required by the slave. It can also disable all other modules multiplexed into the SPI pins.
unsigned char spi data ( unsigned char tx_data )
This function can send a data byte which it takes as the argument and return the received data byte. The master first write the data and then wait for the data to complete transmission and then read the received data while the slave first wait till all the data bits has been received, and then reads the data followed by a data write.
The functions are explained with more details in PIC microcontroller tutorial.
MASTER AND SLAVE AS TRANSMITTER AND RECEIVER
The arrangement below shows how the master transmits some meaningful data to the slave which the slave can receive. The data which the master transmits is displayed in the first line of the 16×2 LCD. The slave then transmits the same data which it has received back to the master which is then displayed in the second line of LCD. In this way the master is doing transmission and reception and the slave is also performing transmission and reception. Since the PIC18F4550 is used as master and slave the capabilities of the SPI module of the PIC18F4550 is exploited to the maximum in this project. The following figure can make the arrangement details more clear;
Fig. 5: Block Diagram of PIC Microcontroller as Mater and Slave in SPI communication
A 16*2 LCD screen is used to observe the data flowing through the SDO and SDI lines of the SPI bus in the system. The data which is transmitted from the master is displayed in the first line of the LCD and the data which is received from the slave is displayed in the second line of the LCD.
Fig. 6: Block Diagram of data transfer with PIC18F4550 microcontrollers and 16*2 LCD screen
The project is implemented using two PIC18F4550 microcontrollers and a 16*2 LCD screen. One of the microcontroller acts like the master while the other microcontroller act as the slave. The LCD screen is connected to the master microcontroller only.
Since the SPI is a full-duplex serial communication with the data transmission and reception as far as a device is concerned occurs through two separate channels called SDO and SDI, both the master and slave can transmit and receive data at the same time. The master communicates with the slave and all the data that the master transmits to the slave as well as receives from the slave is displayed on the LCD screen.
The arrangement in which the master and slave transmit data at the same time is shown in the following figure;
Fig. 7: Block Diagram Of Master & Slave Transmitting Data simultaneously in SPI communication
The circuit needs 5V regulated power supply. No external crystal is connected with the circuit since the microcontrollers are running with internal oscillator enabled.
Fig. 8: PIC18F4550 microcontroller and LCD screen Circuit on breadborad
The slave transmit the data back to the master in response to each data byte received from the transmitter, however the first byte transmitted from the slave will be a demo data. The demo data could be any meaningless byte which the master has to transmit in order to generate a SPI clock and the slave will transmit in response to the first byte from the master. The slave put its data on the master’s SDI pin on this clock transitions. The master then reads the data arriving from the slave and displays it on the LCD.
Once the master finishes transmitting its data to the slave and still wish to receive from the slave it can start sending demo data. In this particular project the master send some data, the slave receives the data and sends the same data back to the receiver.
The data flow occurs at the SDO and SDI pins when both the master and slave acts as transmitter and receiver are shown in the following figure;
Fig. 9: Data flow at SDO and SDI pins when both the master and slave acts as transmitter and receiver
Fig. 10: Complete Circuit Setup of SPI Implementation using PIC
Fig. 11: Demo Data from Master and Slave displayed on LCD screen in SPI using PIC
Project Source Code
###
//####################### For Master ####################// #include <p18f4550.h> //======================= chip config ===================// #pragma config PLLDIV = 1 #pragma config CPUDIV = OSC4_PLL6 #pragma config FOSC = INTOSC_HS #pragma config USBDIV = 1 #pragma config IESO = OFF #pragma config PWRT = OFF #pragma config BOR = OFF #pragma config VREGEN = OFF #pragma config WDT = OFF #pragma config WDTPS = 32768 #pragma config CCP2MX = ON #pragma config PBADEN = OFF #pragma config LPT1OSC = OFF #pragma config MCLRE = ON #pragma config STVREN = ON #pragma config LVP = OFF #pragma config ICPRT = OFF #pragma config XINST = OFF #pragma config DEBUG = OFF #pragma config WRTD = OFF //======================= chip config ===================// //LCD Control pins #define rs PORTBbits.RB4 #define rw PORTBbits.RB3 #define en PORTBbits.RB2 //LCD Data pins #define lcdport PORTD #define lcd_port_dir TRISD void lcd_clear ( void ); void lcd_2nd_line ( void ); void lcd_1st_line ( void ); void lcd_ini ( void ); void dis_cmd ( unsigned char cmd_value ); void dis_data ( unsigned char data_value ); void lcdcmd ( unsigned char cmdout ); void lcddata ( unsigned char dataout ); void delay_ms ( int delay ); void spi_master_init ( void ); unsigned char spi_data ( unsigned char tx_data ); unsigned char spi_read_data; void main() { unsigned int i = 0, a = 3, b = 3; unsigned char data1 [] = "EngineersGarage"; unsigned char data2 [] = " SPI demo "; unsigned char data3 [] = "EG LABS"; OSCCON = 0x72; // set CPU Frequency as 8 MHz lcd_ini (); // LCD initialization //========================= start up display on LCD ================================// while ( data1 [i] != '