...
The initialization of I2C on the dspic33fj256710a is very simple. There are only a few necessary choices to make:
Code Block | ||
---|---|---|
| ||
I2C2CONbits.A10M = 0; //7 bit address mode I2C2CONbits.DISSLW = 1; //Slew Rate control disabled for 100KHz I2C2CONbits.SMEN = 0; //Do NOT use SMBus voltage configuration ///I2C1BRG - BAUD RATE GENERATOR ///MPL3115A2 requires Max 4MHz I2C2BRG = 19; //~118KHz clock rate; FCY = 4MHz //Enable the I2C module I2C2CONbits.I2CEN = 1; |
...
At this point reading and writing can take place. The function to do so is called sendMessage():
Code Block | ||
---|---|---|
| ||
char sendMessage(char devAddress, char address, char\* data, char length, char rw) { char rData = 0; I2CIdle(); I2C2CONbits.SEN = 1; //Send Start condition I2CIdle(); //SET Slave Address & write (Address shifted one bit left and then the write(0) bit is added) I2C2TRN = devAddress << 1; //If reading, the read process is specified after the dummy bytes. if (rw == READ) //If in reading mode { rData = readMessage(devAddress, address); } else //Otherwise go into writing mode { writeMessage(address,data, length); } I2CIdle(); I2C2CONbits.PEN = 1; //Send Stop condition I2CIdle(); return rData; } |
In the above code, the I2CIdle(); command is a while loop, which waits until the module is ready to transmit:
Code Block | ||
---|---|---|
| ||
while((I2C2CON & 0x1F ) || I2C2STATbits.TRSTAT == 1);
|
In the code, it is evident that the start condition is asserted (using control register 2), followed by loading the device address and the write bit into the I2C2TRN transmit buffer. At this point the read or write functions are executed, depending on the request, before finally sending the stop condition.
The write command is extremely simple. It simply loops through the data, waiting for an acknowledgment after each one.
Code Block | ||
---|---|---|
| ||
void writeMessage(char address, char\* data, char length) { I2CIdle(); I2C2TRN = address; //Then after it is free, write the address. //Write each byte of data int i = 0; for(i = 0; i < length; i++) { I2CIdle();//Check until transmition was completed I2C2TRN = (char)data[i]; } } |
...
On the contrary the read message is a bit more complicated:
Code Block | ||
---|---|---|
| ||
char readMessage(char devAddress, char address) { I2CIdle(); I2C2TRN = address; //Then after it is free, write the local address. I2CIdle(); //Wait until acknowledge is sent from the slave I2C2CONbits.RSEN = 1; //Resend the start condition I2CIdle(); //Wait until acknowledge is sent from the slave I2C2TRN = (devAddress << 1) + 1; //Shift and add the read bit(1) - Prep for restart I2CIdle(); //Wait until acknowledge is sent from the slave ///THE MESSAGE FROM THE SLAVE IS SENT HERE I2C2CONbits.RCEN = 1; //Enable receive mode I2CIdle(); //Wait until all 8 bits have been acquired while (I2C2STATbits.RBF != 1); char data = I2C2RCV; //Send back a NACK I2C2CONbits.ACKDT = 1; //Send NACK I2C2CONbits.ACKEN = 1; //Start the acknowledge sequence I2CIdle(); //Wait until done return data; } |
...