Difference between revisions of "PIC32MX: SPI Communication between PIC32s"
Line 68: | Line 68: | ||
The data bytes are 0xAA and 0x23. Slave-LED0 toggles when 0xAA is received from the master, and slave-LED1 toggles when anything else (for example, 0x23) is received from the master. |
The data bytes are 0xAA and 0x23. Slave-LED0 toggles when 0xAA is received from the master, and slave-LED1 toggles when anything else (for example, 0x23) is received from the master. |
||
===Master Code=== |
|||
/**************************************************** |
|||
* SPI_master_btwnPIC32s.c: Master code for Master- * |
|||
* Slave SPI communication. Both PICs are set to * |
|||
* use the SPI1 module and no SS line. A SS line * |
|||
* would be used if there were more than two PICs.* |
|||
* * |
|||
* Hardware: 2 PIC32MX460F512L PICs on NU32 boards * |
|||
**************************************************** |
|||
* Thomas Peterson, James Rein, Eric West * |
|||
* ME333 Winter 2010 * |
|||
* File Created: 05-FEB-2010 * |
|||
* Last Modified: 10-FEB-2010 * |
|||
****************************************************/ |
|||
#include "HardwareProfile.h" |
|||
#include <plib.h> |
|||
//No-operation; asm stands for assembly, using an assembly command in C. Cool! |
|||
#define Nop() asm( "nop" ) |
|||
#define INPUT_A9 PORTAbits.RA9 |
|||
#define INPUT_A10 PORTAbits.RA10 |
|||
#define DESIRED_BAUDRATE (9600) //The desired BaudRate for RS232 |
|||
#pragma config FPBDIV = DIV_1 //Sets PBCLK to SYSCLK |
|||
//function definitions |
|||
void SendData(int); //Sends data |
|||
void Delayms( unsigned t); //Delay fcn |
|||
/* Main Function */ |
|||
int main(void) |
|||
{ |
|||
char tmpstr[30]; //For RS232 debugging |
|||
// Configure the proper PB frequency and the number of wait states. Need this in, like, everything for our board |
|||
int pbClk = SYSTEMConfigPerformance(SYS_FREQ); |
|||
// Set all analog pins to be digital I/O |
|||
AD1PCFG = 0xFFFF; |
|||
//Initialize all of the LED pins |
|||
mInitAllLEDs(); |
|||
// Set A9-A10 as a digital inputs for push buttons |
|||
TRISAbits.TRISA9=1; |
|||
TRISAbits.TRISA10=1; |
|||
//SPI setup |
|||
int rData = SPI1BUF; //Clears receive buffer |
|||
IFS0CLR = 0x03800000; //Clears any existing event (rx / tx/ fault interrupt) |
|||
SPI1STATCLR = 0x40; //Clears overflow |
|||
//Enables the SPI channel (channel, master mode enable | use 8 bit mode | turn on, clock divider) |
|||
SpiChnOpen(1, SPI_CON_MSTEN | SPI_CON_MODE8 | SPI_CON_ON, 1024); // divide fpb by 1024, configure the I/O ports. |
|||
//UART setup |
|||
#define config1 UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN |
|||
#define config2 UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR |
|||
// Open UART2 with config1 and config2 |
|||
OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1); |
|||
putsUART2("Init Done Master\r\n"); |
|||
/* Main while loop: Waits for button press to send/ receive data */ |
|||
while(1) |
|||
{ |
|||
if (INPUT_A9 == 0) //If button 1 depressed |
|||
{ |
|||
while(INPUT_A9 == 0) { Nop(); } //Wait for release |
|||
mLED_2_Toggle(); //Toggle LED |
|||
putcSPI1(0xAA); //Sends hex data 0xAA to slave |
|||
Delayms(50); //Wait for slave |
|||
SpiChnClrIntFlags(1); //Clear interrupt flags (Tx / Rx buffers empty) |
|||
int receive = SPI1BUF; //Read SP1BUF (dummy read) |
|||
SPI1BUF = 0x0; //Write SP1BUF- sets Tx flag, if not done read will not clock |
|||
receive = getcSPI1(); //Generates clock and reads SDO |
|||
sprintf(tmpstr,"Received [%x]\r\n\0", receive); |
|||
putsUART2(tmpstr); |
|||
Delayms(100); |
|||
}//if loop ending |
|||
if (INPUT_A10 == 0) |
|||
{ |
|||
while(INPUT_A10 == 0) { Nop(); } |
|||
mLED_1_Toggle();//Toggle LED |
|||
putcSPI1(0x23); //Sends hex data 0x23 to slave |
|||
Delayms(50); //Wait for slave |
|||
SpiChnClrIntFlags(1); //Clear interrupt flags (Tx / Rx buffers empty) |
|||
int receive = SPI1BUF; //Read SP1BUF (dummy read) |
|||
SPI1BUF = 0x0; //Write SP1BUF- sets Tx flag, if not done read will not clock |
|||
receive = getcSPI1(); //Generates clock and reads SDO |
|||
sprintf(tmpstr,"Received [%x]\r\n\0", receive); |
|||
putsUART2(tmpstr); |
|||
Delayms(100); |
|||
}//if loop ending |
|||
}//while loop ending |
|||
return 0; |
|||
} //ending main |
|||
void Delayms( unsigned t) |
|||
// This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ |
|||
{ |
|||
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF); |
|||
while (t--) |
|||
{ // t x 1ms loop |
|||
WriteTimer1(0); |
|||
while (ReadTimer1() < SYS_FREQ/256/1000); |
|||
} |
|||
CloseTimer1(); |
|||
} // Delayms |
|||
===Slave Code=== |
|||
/**************************************************** |
|||
* SPI_slave_btwnPIC32s.c: Slave code for Master- * |
|||
* Slave SPI communication. Both PICs are set to * |
|||
* use the SPI1 module and no SS line. A SS line * |
|||
* would be used if there were more than two PICs.* |
|||
* * |
|||
* Hardware: 2 PIC32MX460F512L PICs on NU32 boards * |
|||
**************************************************** |
|||
* Thomas Peterson, James Rein, Eric West * |
|||
* ME333 Winter 2010 * |
|||
* File Created: 05-FEB-2010 * |
|||
* Last Modified: 10-FEB-2010 * |
|||
****************************************************/ |
|||
#include "HardwareProfile.h" |
|||
#include <plib.h> |
|||
#define Nop() asm( "nop" ) //No-operation; asm stands for assembly, using an assembly command in C. Cool! |
|||
#define DESIRED_BAUDRATE (9600) // The desired BaudRate |
|||
//Function definition for Delay function |
|||
void Delayms( unsigned t); |
|||
/* Main function */ |
|||
int main(void) |
|||
char tmpstr[30]; |
|||
int pbClk; |
|||
// Configure the proper PB frequency and the number of wait states. Need this in, like, everything for our board |
|||
pbClk = SYSTEMConfigPerformance(SYS_FREQ); |
|||
// Set all analog pins to be digital I/O |
|||
AD1PCFG = 0xFFFF; |
|||
/* Set TRIS bits for SPI lines (this may not be necessary */ |
|||
TRISDbits.TRISD10=1; |
|||
TRISDbits.TRISD0=0; |
|||
TRISCbits.TRISC4=1; |
|||
//Initialize all of the LED pins |
|||
mInitAllLEDs(); |
|||
mLED_3_Off(); |
|||
//Setup UART2 |
|||
#define config1 UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN |
|||
#define config2 UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR |
|||
// Open UART2 with config1 and config2 |
|||
OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1); // calculate actual BAUD generate value. |
|||
//SPI setup |
|||
SPI1CON = 0; //Clears config register |
|||
int rData = SPI1BUF; //Clears receive buffer |
|||
IFS0CLR = 0x03800000; //Clears any existing event (rx / tx/ fault interrupt) |
|||
SPI1STATCLR = 0x40; //Clears overflow |
|||
//Enables the SPI channel (channel, master mode enable | use 8 bit mode | turn on, clock divider) |
|||
SpiChnOpen(1, SPI_CON_SLVEN | SPI_CON_MODE8 | SPI_CON_ON, 1024); // divide fpb by 1024, configure the I/O ports. |
|||
putsUART2("Init Done \r\n"); |
|||
//While loop to test LED functionality |
|||
while(1) |
|||
{ |
|||
rData = SpiChnGetC(1); //Wait and read character when aviliable |
|||
if (rData == 0xAA){mLED_0_Toggle();} //Toggle LED0 if 0xAA |
|||
else {mLED_1_Toggle();} //Toggle LED1 if not |
|||
putcSPI1(rData); //Send character back (when clock arrives) |
|||
rData = SPI1BUF; //Clear recieve buffer (brevents overflow) |
|||
Delayms(5); |
|||
}//while loop ending |
|||
return 0; |
|||
} //ending main |
|||
void Delayms( unsigned t) |
|||
// This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ |
|||
{ |
|||
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF); |
|||
while (t--) |
|||
{ // t x 1ms loop |
|||
WriteTimer1(0); |
|||
while (ReadTimer1() < SYS_FREQ/256/1000); |
|||
} |
|||
CloseTimer1(); |
|||
} // Delayms |
Revision as of 19:04, 10 February 2010
Original Assignment
Do not erase this section!
Your assignment is to create code that allows two PIC32 boards to communicate with each other via SPI.
Overview
SPI or Serial Peripheral Interface is a communication method that was once used to connect devices such as printers, cameras, scanners, etc. to a desktop computer. This function has largely been taken over by USB, but SPI can still be a useful communication tool for some applications. SPI runs using a master/slave set-up and can run in full duplex mode, meaning that signals can be transmitted between the master and the slave simultaneously. There is no standard communication protocol for SPI.
SPI is still used to control some peripheral devices and has some advantages over I2CCHANGE THIS TO OUR I2C PAGE!! (another type of serial data communication). SPI can communicate at much higher data rates than I2C. Furthermore, when multiple slaves are present, SPI requires no addressing to differentiate between these slaves. Compared to parallel buses, SPI has the additional benefit of requiring only simple wiring. However, one disadvantage when compared to I2C is that each slave must have a dedicated slave line. A slave line is not necessary when only one slave is present.
Peripheral devices that still use SPI:
• Converters (ADC and DAC)
• Memories (EEPROM and FLASH)
• Real Time Clocks (RTC)
• Sensors (temperature, pressure, etc.)
• Others (signal mixer, potentiometer, LCD controller, UART, CAN controller, USB controller, amplifier)
Basic Operation
SPI requires three lines, and the optional slave select, and is therefore often termed the “four wire” serial bus. These four lines are described in the table below.
Line | Name | Description |
---|---|---|
SCK1 | Serial Clock | Output from master |
SDO1 | Master Output, Slave Input | Output from master |
SDI1 | Master Input, Slave Output | Output from slave |
SS1 | Slave Select | Output from master (active low) |
The master, as its name suggests, controls all communication. By controlling the clock, the master decides when data is sent and received. Within each clock cycle a full duplex communication is carried out; each side sends and receives one bit of information. Because there is no standard communication protocol, the master can either send data or both send and receive data, depending on the needs of the application. Likewise, the slave can either receive data or both receive and send data back to the master.
Using the “Slave Select” line, the master chooses which slave with which to communicate. Note that more than one slave may be selected, simply by applying a logic low to the desired SS lines, as illustrated in the schematic diagram shown above. If a given slave is not selected (its SS is high) it disregards signals sent by the master.
References
SPI Background(www.totalphase.com)
SPI Wikipedia Article (www.wikipedia.org)
More Information (www.mct.net)
Circuit
Code
This code, coupled with the circuit diagram above, sends one of two bytes of data from the master to the slave, and back, so the master can output which byte is sent via RS232 communication protocol.
The data bytes are 0xAA and 0x23. Slave-LED0 toggles when 0xAA is received from the master, and slave-LED1 toggles when anything else (for example, 0x23) is received from the master.
Master Code
/**************************************************** * SPI_master_btwnPIC32s.c: Master code for Master- * * Slave SPI communication. Both PICs are set to * * use the SPI1 module and no SS line. A SS line * * would be used if there were more than two PICs.* * * * Hardware: 2 PIC32MX460F512L PICs on NU32 boards * **************************************************** * Thomas Peterson, James Rein, Eric West * * ME333 Winter 2010 * * File Created: 05-FEB-2010 * * Last Modified: 10-FEB-2010 * ****************************************************/ #include "HardwareProfile.h" #include <plib.h> //No-operation; asm stands for assembly, using an assembly command in C. Cool! #define Nop() asm( "nop" ) #define INPUT_A9 PORTAbits.RA9 #define INPUT_A10 PORTAbits.RA10 #define DESIRED_BAUDRATE (9600) //The desired BaudRate for RS232 #pragma config FPBDIV = DIV_1 //Sets PBCLK to SYSCLK //function definitions void SendData(int); //Sends data void Delayms( unsigned t); //Delay fcn /* Main Function */ int main(void) { char tmpstr[30]; //For RS232 debugging // Configure the proper PB frequency and the number of wait states. Need this in, like, everything for our board int pbClk = SYSTEMConfigPerformance(SYS_FREQ); // Set all analog pins to be digital I/O AD1PCFG = 0xFFFF; //Initialize all of the LED pins mInitAllLEDs(); // Set A9-A10 as a digital inputs for push buttons TRISAbits.TRISA9=1; TRISAbits.TRISA10=1; //SPI setup int rData = SPI1BUF; //Clears receive buffer IFS0CLR = 0x03800000; //Clears any existing event (rx / tx/ fault interrupt) SPI1STATCLR = 0x40; //Clears overflow //Enables the SPI channel (channel, master mode enable | use 8 bit mode | turn on, clock divider) SpiChnOpen(1, SPI_CON_MSTEN | SPI_CON_MODE8 | SPI_CON_ON, 1024); // divide fpb by 1024, configure the I/O ports. //UART setup #define config1 UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN #define config2 UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR // Open UART2 with config1 and config2 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1); putsUART2("Init Done Master\r\n"); /* Main while loop: Waits for button press to send/ receive data */ while(1) { if (INPUT_A9 == 0) //If button 1 depressed { while(INPUT_A9 == 0) { Nop(); } //Wait for release mLED_2_Toggle(); //Toggle LED putcSPI1(0xAA); //Sends hex data 0xAA to slave Delayms(50); //Wait for slave SpiChnClrIntFlags(1); //Clear interrupt flags (Tx / Rx buffers empty) int receive = SPI1BUF; //Read SP1BUF (dummy read) SPI1BUF = 0x0; //Write SP1BUF- sets Tx flag, if not done read will not clock receive = getcSPI1(); //Generates clock and reads SDO sprintf(tmpstr,"Received [%x]\r\n\0", receive); putsUART2(tmpstr); Delayms(100); }//if loop ending if (INPUT_A10 == 0) { while(INPUT_A10 == 0) { Nop(); } mLED_1_Toggle();//Toggle LED putcSPI1(0x23); //Sends hex data 0x23 to slave Delayms(50); //Wait for slave SpiChnClrIntFlags(1); //Clear interrupt flags (Tx / Rx buffers empty) int receive = SPI1BUF; //Read SP1BUF (dummy read) SPI1BUF = 0x0; //Write SP1BUF- sets Tx flag, if not done read will not clock receive = getcSPI1(); //Generates clock and reads SDO sprintf(tmpstr,"Received [%x]\r\n\0", receive); putsUART2(tmpstr); Delayms(100); }//if loop ending }//while loop ending return 0; } //ending main void Delayms( unsigned t) // This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ { OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF); while (t--) { // t x 1ms loop WriteTimer1(0); while (ReadTimer1() < SYS_FREQ/256/1000); } CloseTimer1(); } // Delayms
Slave Code
/**************************************************** * SPI_slave_btwnPIC32s.c: Slave code for Master- * * Slave SPI communication. Both PICs are set to * * use the SPI1 module and no SS line. A SS line * * would be used if there were more than two PICs.* * * * Hardware: 2 PIC32MX460F512L PICs on NU32 boards * **************************************************** * Thomas Peterson, James Rein, Eric West * * ME333 Winter 2010 * * File Created: 05-FEB-2010 * * Last Modified: 10-FEB-2010 * ****************************************************/
#include "HardwareProfile.h" #include <plib.h> #define Nop() asm( "nop" ) //No-operation; asm stands for assembly, using an assembly command in C. Cool! #define DESIRED_BAUDRATE (9600) // The desired BaudRate //Function definition for Delay function void Delayms( unsigned t); /* Main function */ int main(void) char tmpstr[30]; int pbClk; // Configure the proper PB frequency and the number of wait states. Need this in, like, everything for our board pbClk = SYSTEMConfigPerformance(SYS_FREQ); // Set all analog pins to be digital I/O AD1PCFG = 0xFFFF; /* Set TRIS bits for SPI lines (this may not be necessary */ TRISDbits.TRISD10=1; TRISDbits.TRISD0=0; TRISCbits.TRISC4=1; //Initialize all of the LED pins mInitAllLEDs(); mLED_3_Off(); //Setup UART2 #define config1 UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN #define config2 UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR // Open UART2 with config1 and config2 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1); // calculate actual BAUD generate value. //SPI setup SPI1CON = 0; //Clears config register int rData = SPI1BUF; //Clears receive buffer IFS0CLR = 0x03800000; //Clears any existing event (rx / tx/ fault interrupt) SPI1STATCLR = 0x40; //Clears overflow //Enables the SPI channel (channel, master mode enable | use 8 bit mode | turn on, clock divider) SpiChnOpen(1, SPI_CON_SLVEN | SPI_CON_MODE8 | SPI_CON_ON, 1024); // divide fpb by 1024, configure the I/O ports. putsUART2("Init Done \r\n"); //While loop to test LED functionality while(1) { rData = SpiChnGetC(1); //Wait and read character when aviliable if (rData == 0xAA){mLED_0_Toggle();} //Toggle LED0 if 0xAA else {mLED_1_Toggle();} //Toggle LED1 if not putcSPI1(rData); //Send character back (when clock arrives) rData = SPI1BUF; //Clear recieve buffer (brevents overflow) Delayms(5); }//while loop ending return 0; } //ending main void Delayms( unsigned t) // This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ { OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF); while (t--) { // t x 1ms loop WriteTimer1(0); while (ReadTimer1() < SYS_FREQ/256/1000); } CloseTimer1(); } // Delayms