This is an old revision of the document!
</code c> #include “i2cmem.h” #ifdef EEPROM
———-General I2C functions————————————————————————- volatile u08 I2Cerr; void init_i2c() { TWBR=(u08)1)-8.0); sets the correct clock rate defined as SCL } we dont need to enable the hardware - its done in write void i2cstart() { u16 timeout=1; TWCR = (1«TWINT)|(1«TWSTA)|(1«TWEN); send start
while (!(TWCR & (1<<TWINT)) && timeout); timeout++; //wait for a start to be transmitted if(!timeout) I2Cerr|=16; //timeout out waiting for start error TWCR = (1<<TWEN ); //clear the start condition if (((TWSR & 0xF8) != TW_START)&&((TWSR & 0xF8) != TW_REP_START)) I2Cerr|=1; //error
}
void i2cstop() {
u16 timeout=1; TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); while (!(TWCR & (1<<TWSTO)) && timeout);//wait for stop to be sent timeout++; if(!timeout) I2Cerr|=64; //timeout waiting for stop error
}
void i2cwrite(u08 c) {
u16 timeout=1; TWDR = c; //load the data TWCR = (1<<TWINT)|(1<<TWEN); while (!(TWCR & (1<<TWINT)) && timeout);//wait for it to be sent timeout++; if(!timeout) I2Cerr|=32; //timeout out waiting for write complete error if ( ((TWSR&0xF8)!=TW_MT_SLA_ACK)&&((TWSR&0xF8)!=TW_MR_SLA_ACK)&&((TWSR&0xF8)!=TW_MT_DATA_ACK) ) I2Cerr|=2; //error
}
u08 i2cread(u08 AK) {
u16 timeout=1; TWCR=AK; while ((!(TWCR & (1<<TWINT))) && timeout) timeout++; //wait for it to be recieved if(!timeout) I2Cerr|=8; //timeout out waiting for data response error if(((TWSR & 0xF8) !=TW_MR_DATA_ACK) && ((TWSR & 0xF8) !=TW_MR_DATA_NACK)) I2Cerr|=4; return TWDR;
}
———-EEPROM specific stuff————————————————————————- Designed for 12 byte records atm
void set_address(u32 * address) Sets an address from a pointer - can select the correct physical device but reqires idle bus { i2cstart(); i2cwrite(SLA_W|2); the block
i2cwrite((u08)((*address)>>8)); //address write MSB i2cwrite((u08)(*address)); //address write LSB
}
void write_data(u08 * c, u08 datasize, u32 * address)The address will be incremented as the data is written { u08 n; up to 256 bytes can be written at once
for(n=0;n<datasize;n++,(*address)++) { if(!((u08)*address)) //check the address for overflow for the 8 LSB (Atmel) { i2cstop(); //triggers a page write _delay_loop_2( (u16) ( (float)F_CPU*0.006/4.0 ) );//delay 6 ms for page write set_address(address); //set the new address } i2cwrite(c[n]); //write the data }
}
void read_data(u08 * destination, u08 datasize, u32 * address)Reads a block of data from some address { u08 n; datasize–; i2cstart(); i2cwrite(SLA_R|3); set read to the correct block
for(n=0;n<datasize;n++) { destination[n]=i2cread(_AK_); (*address)++; //increment our pointer /*if(!(u16)(*address)) //we reached the end of the block { i2cstop(); set_address(address); }This isn't needed on the Atmel chips*/ } destination[datasize+1]=i2cread(_NAK_); //send NAK for the last byte recieved i2cstop();
}
u32 findtop() Find the address of record number where we enter painted eeprom { u32 top=12*4); half way through rounded down to nearest 12
u08 n; u08 endcond=TRUE; //used to solve the problem of running with n=0 for(n=16;endcond;) //start by probing half way through { set_address(&top); //the probe address if(n) n--; //need to decr here to get 1 byte resolution else endcond=FALSE; //terminate the loop after completion if(i2cread(_NAK_)==MAGIC_NUMBER) //see if its painted top-=1<<n; //set or clear the nth bit else top+=1<<n; i2cstop(); top = 12*( (u32) (top/12) ); //round down to nearest 12 } return top;
}
void painteeprom() Paints every 12th location with the magic number { u08 magic=MAGIC_NUMBER; magic is our painting value
u32 n; for(n=0;n<131072;n+=12) //this writes every 12th byte { set_address(&n); i2cwrite(magic); //write the data if((u08)n>243) //our next n will be across a page boundary { i2cstop(); _delay_loop_2( (u16) ( (float)F_CPU*0.006/4.0 ) );//delay 6 ms for page write } wdt_reset(); }
} #endif
</code>
I2Cmem.h
#include <util/twi.h> //I2C registers #include <util/delay_basic.h> //wait delay loop for page write #include "avrlibtypes.h" #define SLA_W 0b10100000 //microchip 24LC515 #define SLA_R 0b10100001 #define SCL 100000 #define _AK_ (1<<TWINT)|(1<<TWEN)|(1<<TWEA) //for setting up I2C read with AK and NAK from master #define _NAK_ (1<<TWINT)|(1<<TWEN) #define MAGIC_NUMBER 255 //painting value void init_i2c(); void i2cstart(); void i2cstop(); void i2cwrite(u08 c); u08 i2cread(u08 AK); void set_address(u32* address); void write_data(u08 * c, u08 datasize, u32*address); void read_data(u08 * destination, u08 datasize, u32*address); u32 findtop(); void painteeprom();