Difference between revisions of "PIC32MX: I2C Communication between PIC32s"
From Mech
Jump to navigationJump to search (→Code: Added code) |
|||
Line 17: | Line 17: | ||
== Code == |
== Code == |
||
(code description here) |
|||
Where possible, make it a single piece of well-commented cut-and-pastable code, or at least make each function that way, so others can easily copy it. Most comments should be in the code itself; outside the code (on the wiki) should only be explanatory comments that are too cumbersome to include in the code. |
|||
===Master Code=== |
|||
/******************************************************* |
|||
* I2C_Master.c: Master code for I2C communication. * |
|||
* Both PICS use I2C1 module to send/ recieve data.* |
|||
* The master sends different values to a slave, * |
|||
* which uses an interrupt to respond accordingly. * |
|||
* * |
|||
* Hardware: 2 PIC32MX460F512L PICs on NU32 boards * |
|||
******************************************************* |
|||
* Thomas Peterson, James Rein, Eric West * |
|||
* ME333 Winter 2010 * |
|||
* File Created: ??-FEB-2010 * |
|||
* Last Modified: 10-FEB-2010 * |
|||
*******************************************************/ |
|||
#include "HardwareProfile.h" |
|||
#include <plib.h> |
|||
#define SYSCLK (80000000) |
|||
#define PBCLK (SYSCLK) |
|||
#pragma config FPBDIV = DIV_1 //Sets PBCLK to SYSCLK |
|||
#define Fsck 50000 //Frequency of (I2C) serial clock |
|||
#define BRG_VAL ((PBCLK/2/Fsck)-2) //Baud rate value for I2C setup later |
|||
#define Nop() asm( "nop" ) //No-operation; asm stands for assembly, using an assembly command in C. Cool! |
|||
#define DESIRED_BAUDRATE (9600) //The desired BaudRate for RS232 |
|||
#define INPUT_A9 PORTAbits.RA9 |
|||
#define INPUT_A10 PORTAbits.RA10 |
|||
//function declaration for sending data and selecting slave address |
|||
void SendData(int,unsigned int); |
|||
void Delayms( unsigned t); |
|||
/* |
|||
This function is a delay function, causing the program to wait for approximately 4 * cnt cycles |
|||
1 cycle is 1/SYSCLK seconds. |
|||
*/ |
|||
void i2c_wait(unsigned int cnt) |
|||
{ |
|||
while(--cnt) |
|||
{ |
|||
Nop(); |
|||
Nop(); |
|||
} |
|||
} |
|||
/* Main function */ |
|||
int main(void) |
|||
{ |
|||
// 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; |
|||
//Setup TRIS bits for switches and I2C pins |
|||
TRISAbits.TRISA9=1; |
|||
TRISAbits.TRISA10=1; |
|||
TRISAbits.TRISA14=0; |
|||
TRISAbits.TRISA15=0; |
|||
//Initialize all of the LED pins |
|||
mInitAllLEDs(); |
|||
//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 I2C\r\n"); |
|||
unsigned char SlaveAddress; //Slave address variable to tell the master where to send the data. Will be re-assigned for multiple slaves. |
|||
//Enable I2C channel and set the baud rate to BRG_VAL) |
|||
OpenI2C1( I2C_EN, BRG_VAL ); |
|||
int rcv; //For received data |
|||
char string[30]; //For UART use |
|||
//While loop to test LED functionality |
|||
while(1) { |
|||
if (INPUT_A9 == 0) { //First button pressed |
|||
while(INPUT_A9 == 0) { Nop(); } //Wait for release |
|||
mLED_2_Toggle(); //Toggle LED2 |
|||
SendData(0xAA,0x40); //Sends hex data 0xAA to slave address 0x40 |
|||
rcv = RcvData(0x40); //Receives data from address 0x40 |
|||
sprintf(string,"Recieved back [%x]\r\n\0",rcv); putsUART2(string); |
|||
Delayms(100); |
|||
} |
|||
if (INPUT_A10 == 0) { //Second button pressed |
|||
while(INPUT_A10 == 0) { Nop(); } |
|||
mLED_1_Toggle(); //Toggle LED1 |
|||
SendData(0x23,0x40); //Sends hex data 0xAA to slave address 0x40 |
|||
rcv = RcvData(0x40); //Receives data from address 0x40 |
|||
sprintf(string,"Recieved back [%x]\r\n\0",rcv); putsUART2(string); |
|||
Delayms(100); |
|||
} |
|||
}//while loop ending |
|||
return 0; |
|||
} //ending main |
|||
/**************************************************** |
|||
* RcvData(unsigned int address) * |
|||
* * |
|||
* Gets a byte of data from I2C slave device at * |
|||
* ADDRESS. * |
|||
* * |
|||
* Returns: Received data * |
|||
****************************************************/ |
|||
int RcvData(unsigned int address) { |
|||
StartI2C1(); //Send line start condition |
|||
IdleI2C1(); //Wait to complete |
|||
MasterWriteI2C1((address << 1) | 1); //Write out slave address OR 1 (read command) |
|||
IdleI2C1(); //Wait to complete |
|||
int rcv = MasterReadI2C1(); //Read in a value |
|||
StopI2C1(); //Send line stop condition |
|||
IdleI2C1(); //Wait co complete |
|||
return rcv; //Return read value |
|||
} |
|||
/*************************************************** |
|||
* SendData(int data, unsigned int address) * |
|||
* * |
|||
* Sends a byte of data (DATA) over the I2C line * |
|||
* to I2C address ADDRESS * |
|||
* * |
|||
* Returns: nothing * |
|||
***************************************************/ |
|||
void SendData (int data, unsigned int address){ |
|||
StartI2C1(); //Send the Start Bit |
|||
IdleI2C1(); //Wait to complete |
|||
MasterWriteI2C1((address << 1) | 0); //Sends the slave address over the I2C line. This must happen first so the proper slave is selected to receive data. |
|||
IdleI2C1(); //Wait to complete |
|||
MasterWriteI2C1(data); //Sends data byte over I2C line |
|||
IdleI2C1(); //Wait to complete |
|||
StopI2C1(); //Send the Stop condition |
|||
IdleI2C1(); //Wait to complete |
|||
} //end function |
|||
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=== |
|||
/*********************************************************************** |
|||
* PIC32 I2C Slave Code |
|||
***********************************************************************/ |
|||
#include "GenericTypeDefs.h" |
|||
#include "Compiler.h" |
|||
#include "HardwareProfile.h" |
|||
#include <plib.h> |
|||
#define SYSCLK (80000000) |
|||
#define PBCLK (SYSCLK) |
|||
#define Fsck 50000 |
|||
#define BRG_VAL ((PBCLK/2/Fsck)-2) |
|||
// this is the modules Slave Address |
|||
#define SLAVE_ADDRESS 0x40 |
|||
// volatile variables to hold the switch and led states |
|||
volatile unsigned char dataRead = 0; |
|||
/////////////////////////////////////////////////////////////////// |
|||
// |
|||
// InitI2C |
|||
// |
|||
// Perform initialisation of the I2C module to operate as a slave |
|||
// |
|||
/////////////////////////////////////////////////////////////////// |
|||
void InitI2C(void) |
|||
{ |
|||
unsigned char temp; |
|||
// Enable the I2C module with clock stretching enabled |
|||
OpenI2C1(I2C_ON | I2C_7BIT_ADD | I2C_STR_EN, BRG_VAL); |
|||
// set the address of the slave module, address matching is with bits |
|||
// 7:1 of the message compared with bits 6:0 of the ADD SFR so we |
|||
// need to shift the desired address 1 bit. |
|||
I2C1ADD = SLAVE_ADDRESS; // >> 1; |
|||
I2C1MSK = 0; |
|||
// configure the interrupt priority for the I2C peripheral |
|||
mI2C1SetIntPriority(I2C_INT_PRI_3 | I2C_INT_SLAVE); |
|||
// clear pending interrupts and enable I2C interrupts |
|||
mI2C1SClearIntFlag(); |
|||
EnableIntSI2C1; |
|||
} |
|||
/////////////////////////////////////////////////////////////////// |
|||
// |
|||
// main routine |
|||
// |
|||
// This code example demonstrates using the PIC32 as an I2C slave |
|||
// |
|||
// |
|||
/////////////////////////////////////////////////////////////////// |
|||
int main (void) |
|||
{ |
|||
// set for 80MHz operation |
|||
SYSTEMConfigPerformance(SYSCLK); |
|||
// set the Pbus to be 40000000 |
|||
mOSCSetPBDIV(OSC_PB_DIV_2); |
|||
// disable the JTAG port |
|||
mJTAGPortEnable(0); |
|||
// enable interrupts |
|||
INTEnableSystemMultiVectoredInt(); |
|||
InitI2C(); |
|||
mInitAllLEDs(); |
|||
// main loop |
|||
while (1) { |
|||
/* If global variable "dataRead" is set high during interrupt, turn on all LEDs */ |
|||
if (dataRead == 0xAA) |
|||
{ |
|||
mLED_0_On(); |
|||
mLED_1_On(); |
|||
mLED_2_On(); |
|||
mLED_3_On(); |
|||
} |
|||
} |
|||
} |
|||
/////////////////////////////////////////////////////////////////// |
|||
// |
|||
// Slave I2C interrupt handler |
|||
// This handler is called when a qualifying I2C events occurs |
|||
// this means that as well as Slave events |
|||
// Master and Bus Collision events will also trigger this handler. |
|||
// |
|||
/////////////////////////////////////////////////////////////////// |
|||
void __ISR(_I2C_1_VECTOR, ipl3) _SlaveI2CHandler(void) |
|||
{ |
|||
mLED_1_On(); |
|||
unsigned char temp; |
|||
static unsigned int dIndex; |
|||
// check for MASTER and Bus events and respond accordingly |
|||
if (IFS0bits.I2C1MIF == 1) { |
|||
mI2C1MClearIntFlag(); |
|||
return; |
|||
} |
|||
if (IFS0bits.I2C1BIF == 1) { |
|||
mI2C1BClearIntFlag(); |
|||
return; |
|||
} |
|||
mLED_1_Off(); |
|||
mLED_2_On(); |
|||
// handle the incoming message |
|||
if ((I2C1STATbits.R_W == 0) && (I2C1STATbits.D_A == 0)) { |
|||
// R/W bit = 0 --> indicates data transfer is input to slave |
|||
// D/A bit = 0 --> indicates last byte was address |
|||
// reset any state variables needed by a message sequence |
|||
// perform a dummy read of the address |
|||
temp = SlaveReadI2C1(); |
|||
mLED_3_On(); |
|||
mLED_2_Off(); |
|||
// release the clock to restart I2C |
|||
I2C1CONbits.SCLREL = 1; // release the clock |
|||
} else if ((I2C1STATbits.R_W == 0) && (I2C1STATbits.D_A == 1)) { |
|||
// R/W bit = 0 --> indicates data transfer is input to slave |
|||
// D/A bit = 1 --> indicates last byte was data |
|||
mLED_3_On(); |
|||
mLED_2_On(); |
|||
// writing data to our module, just store it in adcSample |
|||
dataRead = SlaveReadI2C1(); |
|||
// release the clock to restart I2C |
|||
I2C1CONbits.SCLREL = 1; // release clock stretch bit |
|||
} else if ((I2C1STATbits.R_W == 1) && (I2C1STATbits.D_A == 0)) { |
|||
// R/W bit = 1 --> indicates data transfer is output from slave |
|||
// D/A bit = 1 --> indicates last byte was address |
|||
mLED_0_On(); |
|||
mLED_2_Off(); |
|||
// read of the slave device, read the address |
|||
temp = SlaveReadI2C1(); |
|||
dIndex = 0; |
|||
SlaveWriteI2C1(dataRead); |
|||
} else if ((I2C1STATbits.R_W == 1) && (I2C1STATbits.D_A == 1)) { |
|||
// R/W bit = 1 --> indicates data transfer is input to slave |
|||
// D/A bit = 1 --> indicates last byte was data |
|||
mLED_0_On(); |
|||
mLED_2_On(); |
|||
// output the data until the MASTER terminates the |
|||
// transfer with a NACK, continuing reads return 0 |
|||
if (dIndex == 0) { |
|||
SlaveWriteI2C1(dataRead); |
|||
dIndex++; |
|||
} else |
|||
SlaveWriteI2C1(0); |
|||
} |
|||
// finally clear the slave interrupt flag |
|||
mI2C1SClearIntFlag(); |
|||
} |
Revision as of 17:59, 10 February 2010
Original Assignment
Do not erase this section!
Your assignment is to create code that allows two PIC32s to communicate via I2C.
Overview
Summarize briefly what the page is about.
Circuit
Include a schematic and give any part numbers. A photo of your circuit is OK, but not as a replacement for a schematic.
Code
(code description here)
Master Code
/******************************************************* * I2C_Master.c: Master code for I2C communication. * * Both PICS use I2C1 module to send/ recieve data.* * The master sends different values to a slave, * * which uses an interrupt to respond accordingly. * * * * Hardware: 2 PIC32MX460F512L PICs on NU32 boards * ******************************************************* * Thomas Peterson, James Rein, Eric West * * ME333 Winter 2010 * * File Created: ??-FEB-2010 * * Last Modified: 10-FEB-2010 * *******************************************************/ #include "HardwareProfile.h" #include <plib.h> #define SYSCLK (80000000) #define PBCLK (SYSCLK) #pragma config FPBDIV = DIV_1 //Sets PBCLK to SYSCLK #define Fsck 50000 //Frequency of (I2C) serial clock #define BRG_VAL ((PBCLK/2/Fsck)-2) //Baud rate value for I2C setup later #define Nop() asm( "nop" ) //No-operation; asm stands for assembly, using an assembly command in C. Cool! #define DESIRED_BAUDRATE (9600) //The desired BaudRate for RS232 #define INPUT_A9 PORTAbits.RA9 #define INPUT_A10 PORTAbits.RA10 //function declaration for sending data and selecting slave address void SendData(int,unsigned int); void Delayms( unsigned t); /* This function is a delay function, causing the program to wait for approximately 4 * cnt cycles 1 cycle is 1/SYSCLK seconds. */ void i2c_wait(unsigned int cnt) { while(--cnt) { Nop(); Nop(); } } /* Main function */ int main(void) { // 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; //Setup TRIS bits for switches and I2C pins TRISAbits.TRISA9=1; TRISAbits.TRISA10=1; TRISAbits.TRISA14=0; TRISAbits.TRISA15=0; //Initialize all of the LED pins mInitAllLEDs(); //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 I2C\r\n"); unsigned char SlaveAddress; //Slave address variable to tell the master where to send the data. Will be re-assigned for multiple slaves. //Enable I2C channel and set the baud rate to BRG_VAL) OpenI2C1( I2C_EN, BRG_VAL ); int rcv; //For received data char string[30]; //For UART use //While loop to test LED functionality while(1) { if (INPUT_A9 == 0) { //First button pressed while(INPUT_A9 == 0) { Nop(); } //Wait for release mLED_2_Toggle(); //Toggle LED2 SendData(0xAA,0x40); //Sends hex data 0xAA to slave address 0x40 rcv = RcvData(0x40); //Receives data from address 0x40 sprintf(string,"Recieved back [%x]\r\n\0",rcv); putsUART2(string); Delayms(100); } if (INPUT_A10 == 0) { //Second button pressed while(INPUT_A10 == 0) { Nop(); } mLED_1_Toggle(); //Toggle LED1 SendData(0x23,0x40); //Sends hex data 0xAA to slave address 0x40 rcv = RcvData(0x40); //Receives data from address 0x40 sprintf(string,"Recieved back [%x]\r\n\0",rcv); putsUART2(string); Delayms(100); } }//while loop ending return 0; } //ending main /**************************************************** * RcvData(unsigned int address) * * * * Gets a byte of data from I2C slave device at * * ADDRESS. * * * * Returns: Received data * ****************************************************/ int RcvData(unsigned int address) { StartI2C1(); //Send line start condition IdleI2C1(); //Wait to complete MasterWriteI2C1((address << 1) | 1); //Write out slave address OR 1 (read command) IdleI2C1(); //Wait to complete int rcv = MasterReadI2C1(); //Read in a value StopI2C1(); //Send line stop condition IdleI2C1(); //Wait co complete return rcv; //Return read value } /*************************************************** * SendData(int data, unsigned int address) * * * * Sends a byte of data (DATA) over the I2C line * * to I2C address ADDRESS * * * * Returns: nothing * ***************************************************/ void SendData (int data, unsigned int address){ StartI2C1(); //Send the Start Bit IdleI2C1(); //Wait to complete MasterWriteI2C1((address << 1) | 0); //Sends the slave address over the I2C line. This must happen first so the proper slave is selected to receive data. IdleI2C1(); //Wait to complete MasterWriteI2C1(data); //Sends data byte over I2C line IdleI2C1(); //Wait to complete StopI2C1(); //Send the Stop condition IdleI2C1(); //Wait to complete } //end function 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
/*********************************************************************** * PIC32 I2C Slave Code ***********************************************************************/ #include "GenericTypeDefs.h" #include "Compiler.h" #include "HardwareProfile.h" #include <plib.h> #define SYSCLK (80000000) #define PBCLK (SYSCLK) #define Fsck 50000 #define BRG_VAL ((PBCLK/2/Fsck)-2) // this is the modules Slave Address #define SLAVE_ADDRESS 0x40 // volatile variables to hold the switch and led states volatile unsigned char dataRead = 0; /////////////////////////////////////////////////////////////////// // // InitI2C // // Perform initialisation of the I2C module to operate as a slave // /////////////////////////////////////////////////////////////////// void InitI2C(void) { unsigned char temp; // Enable the I2C module with clock stretching enabled OpenI2C1(I2C_ON | I2C_7BIT_ADD | I2C_STR_EN, BRG_VAL); // set the address of the slave module, address matching is with bits // 7:1 of the message compared with bits 6:0 of the ADD SFR so we // need to shift the desired address 1 bit. I2C1ADD = SLAVE_ADDRESS; // >> 1; I2C1MSK = 0; // configure the interrupt priority for the I2C peripheral mI2C1SetIntPriority(I2C_INT_PRI_3 | I2C_INT_SLAVE); // clear pending interrupts and enable I2C interrupts mI2C1SClearIntFlag(); EnableIntSI2C1; } /////////////////////////////////////////////////////////////////// // // main routine // // This code example demonstrates using the PIC32 as an I2C slave // // /////////////////////////////////////////////////////////////////// int main (void) { // set for 80MHz operation SYSTEMConfigPerformance(SYSCLK); // set the Pbus to be 40000000 mOSCSetPBDIV(OSC_PB_DIV_2); // disable the JTAG port mJTAGPortEnable(0); // enable interrupts INTEnableSystemMultiVectoredInt(); InitI2C(); mInitAllLEDs(); // main loop while (1) { /* If global variable "dataRead" is set high during interrupt, turn on all LEDs */ if (dataRead == 0xAA) { mLED_0_On(); mLED_1_On(); mLED_2_On(); mLED_3_On(); } } } /////////////////////////////////////////////////////////////////// // // Slave I2C interrupt handler // This handler is called when a qualifying I2C events occurs // this means that as well as Slave events // Master and Bus Collision events will also trigger this handler. // /////////////////////////////////////////////////////////////////// void __ISR(_I2C_1_VECTOR, ipl3) _SlaveI2CHandler(void) { mLED_1_On(); unsigned char temp; static unsigned int dIndex; // check for MASTER and Bus events and respond accordingly if (IFS0bits.I2C1MIF == 1) { mI2C1MClearIntFlag(); return; } if (IFS0bits.I2C1BIF == 1) { mI2C1BClearIntFlag(); return; } mLED_1_Off(); mLED_2_On(); // handle the incoming message if ((I2C1STATbits.R_W == 0) && (I2C1STATbits.D_A == 0)) { // R/W bit = 0 --> indicates data transfer is input to slave // D/A bit = 0 --> indicates last byte was address // reset any state variables needed by a message sequence // perform a dummy read of the address temp = SlaveReadI2C1(); mLED_3_On(); mLED_2_Off(); // release the clock to restart I2C I2C1CONbits.SCLREL = 1; // release the clock } else if ((I2C1STATbits.R_W == 0) && (I2C1STATbits.D_A == 1)) { // R/W bit = 0 --> indicates data transfer is input to slave // D/A bit = 1 --> indicates last byte was data mLED_3_On(); mLED_2_On(); // writing data to our module, just store it in adcSample dataRead = SlaveReadI2C1(); // release the clock to restart I2C I2C1CONbits.SCLREL = 1; // release clock stretch bit } else if ((I2C1STATbits.R_W == 1) && (I2C1STATbits.D_A == 0)) { // R/W bit = 1 --> indicates data transfer is output from slave // D/A bit = 1 --> indicates last byte was address mLED_0_On(); mLED_2_Off(); // read of the slave device, read the address temp = SlaveReadI2C1(); dIndex = 0; SlaveWriteI2C1(dataRead); } else if ((I2C1STATbits.R_W == 1) && (I2C1STATbits.D_A == 1)) { // R/W bit = 1 --> indicates data transfer is input to slave // D/A bit = 1 --> indicates last byte was data mLED_0_On(); mLED_2_On(); // output the data until the MASTER terminates the // transfer with a NACK, continuing reads return 0 if (dIndex == 0) { SlaveWriteI2C1(dataRead); dIndex++; } else SlaveWriteI2C1(0); } // finally clear the slave interrupt flag mI2C1SClearIntFlag(); }