i2c_slave_reverse_string.c - Slave in pair of files that shows a PIC24 I2C master talking to a PIC24 I2C slaveΒΆ
I2C Example: Demonstrates a PIC24 CPU acting as an I2C slave. The PIC24 slave responds to both write and read transactions.
#include "pic24_all.h"
void reverseString(volatile char *psz_s1, volatile char *psz_s2) {
volatile char *psz_s1end;
if (!(*psz_s1)) {
*psz_s2 = 0; //psz_s1 is empty, return.
return;
}
psz_s1end = psz_s1;
//find end of first string
while (*psz_s1end) psz_s1end++;
psz_s1end--; //backup one to first non-zero byte
//now copy to S2 in reverse order
while (psz_s1end != psz_s1) {
*psz_s2 = *psz_s1end;
psz_s1end--;
psz_s2++;
}
//copy last byte
*psz_s2 = *psz_s1end;
psz_s2++;
//mark end of string
*psz_s2 = 0;
}
#define SLAVE_I2C_ADDR 0x60
typedef enum {
STATE_WAIT_FOR_ADDR,
STATE_WAIT_FOR_WRITE_DATA,
STATE_SEND_READ_DATA,
STATE_SEND_READ_LAST
} STATE;
volatile STATE e_mystate = STATE_WAIT_FOR_ADDR;
#define BUFSIZE 64
volatile char sz_1[BUFSIZE+1];
volatile char sz_2[BUFSIZE+1];
volatile uint16_t u16_index;
void _ISRFAST _SI2C1Interrupt(void) {
uint8_t u8_c;
_SI2C1IF = 0;
switch (e_mystate) {
case STATE_WAIT_FOR_ADDR:
u8_c = I2C1RCV; //clear RBF bit for address
u16_index = 0;
//check the R/W bit and see if read or write transaction
if (I2C1STATbits.R_W) {
I2C1TRN = sz_2[u16_index++]; //get first data byte
I2C1CONbits.SCLREL = 1; //release clock line so MASTER can drive it
e_mystate = STATE_SEND_READ_DATA; //read transaction
} else e_mystate = STATE_WAIT_FOR_WRITE_DATA;
break;
case STATE_WAIT_FOR_WRITE_DATA:
//character arrived, place in buffer
sz_1[u16_index++] = I2C1RCV; //read the byte
if (sz_1[u16_index-1] == 0) {
//have a complete string, reverse it.
reverseString(sz_1,sz_2);
e_mystate = STATE_WAIT_FOR_ADDR; //wait for next transaction
}
break;
case STATE_SEND_READ_DATA:
//just keep placing reversed characters in buffer as MASTER reads our I2C port
I2C1TRN = sz_2[u16_index++];
I2C1CONbits.SCLREL = 1; //release clock line so MASTER can drive it
if (sz_2[u16_index-1] == 0) e_mystate = STATE_SEND_READ_LAST;
//this is the last character, after byte is shifted out, release the clock line again
break;
case STATE_SEND_READ_LAST: //this is interrupt for last character finished shifting out
e_mystate = STATE_WAIT_FOR_ADDR;
break;
default:
e_mystate = STATE_WAIT_FOR_ADDR;
}
}
int main (void) {
configBasic(HELLO_MSG);
configI2C1(400); //configure I2C for 400 KHz
I2C1ADD = SLAVE_I2C_ADDR>>1; //initialize the address register
_SI2C1IF = 0;
#ifdef _SI2C1IP
_SI2C1IP = 1;
#else
#ifdef _SI2C1IP0
_SI2C1IP0 = 1; //header files can be inconsistent in how these are defined for PIC24H versus PIC24F
_SI2C1IP1 = 0;
_SI2C1IP2 = 0;
#endif
#endif
_SI2C1IE = 1; //enable ISR
while (1) doHeartbeat(); //ISR does all work
}