//////////////////////////////////////////////////////////////////////////////////////////// // File: i2cmsu.c // This code is provided by Dr. Robert Reese. // We thank him for the use of it. // // //////////////////////////////////////////////////////////////////////////////////////////// #include #include "i2cmsu.h" #include "delay.h" #define bitset(var,bitno) ((var) |= (1 << (bitno))) #define bitclr(var,bitno) ((var) &= ~(1 << (bitno))) #define bittst(var,bitno) (var & (1 << (bitno))) #define I2C_IDLE_ERR 1 #define I2C_START_ERR 2 #define I2C_RSTART_ERR 3 #define I2C_STOP_ERR 4 #define I2C_GET_ERR 5 #define I2C_PUT_ERR 6 #define I2C_MISSACK_ERR 7 #define I2C_ACK_ERR 8 #define I2C_NAK_ERR 9 // error variable for acknowledge persistent char i2c_errstat; i2c_init(char bitrate){ // enable I2C Master Mode SSPM3 = 1; SSPM2 = 0;SSPM1 = 0; SSPM0 = 0; SSPADD = bitrate; // set bus clk SSPEN = 1; bitset(TRISC,3); bitset(TRISC,4); // SDA, SCL pins are inputs SSPIF = 0; // clear SPIF bit i2c_errstat = 0; // clear error status } i2c_idle(){ // wait for idle condition unsigned char byte1; unsigned char byte2; asm("clrwdt"); i2c_errstat = I2C_IDLE_ERR; do { // byte1 has R/W bit. byte1 = SSPSTAT & 0x04; byte2 = SSPCON2 & 0x1F; }while (byte1 | byte2); asm("clrwdt"); i2c_errstat = 0; return; } i2c_start(){ //i2c_idle(); //i2c_errstat = I2C_START_ERR; SEN = 1; // initiate start // wait until start finished while (SEN); asm("clrwdt"); //i2c_errstat = 0; } i2c_rstart(){// repeated start i2c_idle(); i2c_errstat = I2C_RSTART_ERR; RSEN = 1; // initiate start // wait until start finished while (RSEN); asm("clrwdt"); i2c_errstat = 0; } i2c_stop() { //i2c_idle(); //i2c_errstat = I2C_STOP_ERR; PEN=1; // initiate stop, PEN=1 //wait until stop finished while (PEN); asm("clrwdt"); i2c_errstat = 0; } unsigned char i2c_put(unsigned char byte ) { //i2c_errstat = I2C_PUT_ERR; SSPIF = 0; //clear interrupt flag SSPBUF = byte; // write byte while(!SSPIF); // wait for finish an ack //i2c_errstat = 0; asm("clrwdt"); if (ACKSTAT) { //no acknowledge returned, so reset i2c_errstat = I2C_MISSACK_ERR; asm("reset"); } return(0); } unsigned char i2c_put_noerr(unsigned char byte ) { i2c_errstat = I2C_PUT_ERR; SSPIF = 0; //clear interrupt flag SSPBUF = byte; // write byte while(!SSPIF); // wait for finish an ack i2c_errstat = 0; asm("clrwdt"); if (ACKSTAT) return(1); return(0); } unsigned char i2c_putbyte(unsigned char byte) { i2c_idle(); return(i2c_put(byte)); } i2c_ack(unsigned char ackbit){ // send acknowledge asm("clrwdt"); ACKDT = ackbit; if (ackbit) i2c_errstat = I2C_NAK_ERR; else i2c_errstat = I2C_ACK_ERR; //initiate acknowlege cycle ACKEN = 1; // wait until acknowledge cycle finished while(ACKEN); asm("clrwdt"); i2c_errstat = 0; } unsigned char i2c_get(unsigned char ackbit) { unsigned char byte; i2c_errstat = I2C_GET_ERR; RCEN = 1; //initiate read event while(RCEN); // wait until finished asm("clrwdt"); while (!BF); //also check buffer full asm("clrwdt"); byte = SSPBUF; // read data i2c_errstat = 0; i2c_ack(ackbit); return(byte); } unsigned char i2c_getbyte(unsigned char ackbit) { i2c_idle(); return(i2c_get(ackbit)); } void i2c_print_err(){ pcrlf(); printf("I2C bus error is "); switch (i2c_errstat) { case 0: printf("None");break; case I2C_IDLE_ERR : printf("Idle");break; case I2C_START_ERR : printf("Start");break; case I2C_STOP_ERR : printf("Stop");break; case I2C_GET_ERR : printf("Get");break; case I2C_PUT_ERR : printf("Put");break; case I2C_MISSACK_ERR : printf("Missing Ack");break; case I2C_ACK_ERR : printf("Ack");break; case I2C_NAK_ERR : printf("Nak");break; default: printf("Unknown"); } pcrlf(); }