/* I2C lib R. Reese MSU July 2003 Delay routines are from samples provided with PICC subroutines */ #include #include "i2cmsu.h" #define bitset(var,bitno) ((var) |= (1 << (bitno))) #define bitclr(var,bitno) ((var) &= ~(1 << (bitno))) #define bittst(var,bitno) (var & (1 << (bitno))) void DelayMs(unsigned char cnt) { #if XTAL_FREQ <= 2MHZ do { DelayUs(996); } while(--cnt); #endif #if XTAL_FREQ > 2MHZ unsigned char i; do { i = 4; do { DelayUs(250); } while(--i); } while(--cnt); #endif } /* wait for idle condition */ i2c_idle() { unsigned char byte1; unsigned char byte2; do { byte1 = SSPSTAT & 0x04; // gte R/W bit. byte2 = SSPCON2 & 0x1F; }while (byte1 | byte2); return; } i2c_Start(){ i2c_idle(); bitset(SSPCON2,0); /* initiate start, SEN=1 */ /* wait until start finished */ while (bittst(SSPCON2,0)); } i2c_Stop() { i2c_idle(); bitset(SSPCON2,2); /* initiate stop, PEN=1 */ /* wait until stop finished */ while (bittst(SSPCON2,2)); } i2c_WriteTo(unsigned char addr) { /* first, send start */ i2c_Start(); SSPBUF = addr; /* write data */ while(bittst(SSPSTAT,2)); /* wait until finished */ /* wait for acknowledge */ while(bittst(SSPCON2,6)); /* wait until ack */ } i2c_PutByte(unsigned char byte) { i2c_idle(); SSPBUF = byte; /* write data */ while(bittst(SSPSTAT,2)); /* wait until finished */ /* wait for acknowledge */ while(bittst(SSPCON2,6)); /* wait until ack */ } i2c_FastPutByte(unsigned char byte) { SSPBUF = byte; /* write data */ while(bittst(SSPSTAT,2)); /* wait until finished */ /* wait for acknowledge */ while(bittst(SSPCON2,6)); /* wait until ack */ } i2c_doAck(){ /* send acknowledge */ bitclr(SSPCON2,5); //set ACKBIT = 0 bitset(SSPCON2,4); //initiate acknowlege cycle while(bittst(SSPCON2,4)); // wait unti acknowledge cycle finished } i2c_doNak(){ /* send acknowledge */ bitset(SSPCON2,5); //set ACKBIT = 1 bitset(SSPCON2,4); //initiate acknowlege cycle while(bittst(SSPCON2,4)); // wait unti acknowledge cycle finished } unsigned char i2c_GetByte() { unsigned char byte; i2c_idle(); bitset(SSPCON2,3); /* initiate read event */ while(bittst(SSPCON2,3)); /* wait until finished */ while (!(bittst(SSPSTAT,0))); byte = SSPBUF; /* read data */ return(byte); } void mem_write(unsigned char cmd,unsigned char val, int addr) { unsigned char hbyte; unsigned char lbyte; if (addr & 0x8000) { // if MSB set , set block select bit cmd = cmd | 0x08; } hbyte = (addr >> 8) & 0x7F; // high address byte lbyte = (addr) & 0xFF; // low address byte i2c_WriteTo(cmd); // send write cmd i2c_PutByte(hbyte); // send high address byte i2c_PutByte(lbyte); // send low address byte i2c_PutByte(val); // send data i2c_Stop(); DelayMs(5); } /* this routine does not wait for write to finish! Need to be careful to only call every 5 ms or do end-of-write checking yourself */ void block_mem_write(unsigned char cmd,int addr, char *buf) { unsigned char hbyte; unsigned char lbyte; unsigned char k; if (addr & 0x8000) { // if MSB set , set block select bit cmd = cmd | 0x08; } hbyte = (addr >> 8) & 0x7F; // high address byte lbyte = (addr) & 0xFF; // low address byte i2c_WriteTo(cmd); // send write cmd i2c_PutByte(hbyte); // send high address byte i2c_PutByte(lbyte); // send low address byte for (k=0;k<64;k++) { //i2c_PutByte(buf[k]); // send data i2c_FastPutByte(buf[k]); // send data } i2c_Stop(); //DelayMs(5); // no need to delay, will not be back here for 5 ms } /* random read */ unsigned char mem_read(unsigned char cmd,int addr) { unsigned char hbyte; unsigned char lbyte; unsigned char val; if (addr & 0x8000) { // if MSB set , set block select bit cmd = cmd | 0x08; } hbyte = (addr >> 8) & 0x7F; // high address byte lbyte = (addr) & 0xFF; // low address byte i2c_WriteTo(cmd); // send write cmd, do this to set address counter i2c_PutByte(hbyte); // send high address byte i2c_PutByte(lbyte); // send low address byte i2c_Stop(); // send stop cmd = cmd | 0x1; // set read bit i2c_WriteTo(cmd); // send read cmd, address set by previous cmd val = i2c_GetByte(); // read data i2c_Stop(); // send stop return(val); } /* block read */ void block_mem_read(unsigned char cmd,int addr,char *buf) { unsigned char hbyte; unsigned char lbyte; unsigned char k; if (addr & 0x8000) { // if MSB set , set block select bit cmd = cmd | 0x08; } hbyte = (addr >> 8) & 0x7F; // high address byte lbyte = (addr) & 0xFF; // low address byte i2c_WriteTo(cmd); // send write cmd, do this to set address counter i2c_PutByte(hbyte); // send high address byte i2c_PutByte(lbyte); // send low address byte i2c_Stop(); // send stop cmd = cmd | 0x1; // set read bit i2c_WriteTo(cmd); for (k=0;k<64;k++){ buf[k] = i2c_GetByte(); // read data if (k== 63) i2c_Stop(); else i2c_doAck(); } }