UKHAS Wiki

UK High Altitude Society

User Tools

Site Tools


code:i2c_eeprom

I2Cmem.c

#include "i2cmem.h"
#ifdef EEPROM
 
//----------General I2C functions-------------------------------------------------------------------------
 
volatile u08 I2Cerr;
 
void init_i2c()
{
	TWBR=(u08)(((float)F_CPU/(2.0*(float)SCL))-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|(((*address)>>15)&0x02));	//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|((u08)((*address)>>15)&0x02));	//set read to the correct block
	for(n=0;n<datasize;n++)						//the eeproms address pointer should have been setup already
	{
		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]=i2cread(_NAK_);		//send NAK for the last byte recieved
	i2cstop();
	(*address)++;
}
 
 
u32 findtop()									//Find the address of record number where we enter painted eeprom
{
	u32 top=12*((u32)1<<13);					//half way through rounded down to 12
	u08 n,endcond=TRUE;
	u16 place=1<<13;
	for(n=14;endcond;)							//start by probing half way through - place is in records
	{
		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									//need to decr here to get 1 byte resolution
		i2cstart();								//read the slave
		i2cwrite(SLA_R);
		if(i2cread(_NAK_)==MAGIC_NUMBER)		//see if its painted
			place&=~(1<<n);						//clear the nth bit in the place holder
		if(n)
			place|=(1<<(n-1));					//set the next bit
		i2cstop();
		if(place>10922)
			place=10922;
		top = 12*( (u32)place );				//place is in units of 12
	}
	set_address(&top);
	i2cstart();
	i2cwrite(SLA_R);
	if(i2cread(_NAK_)!=MAGIC_NUMBER)			//check the location to make sure its blank
		place++;
	top = 12*( (u32)place );
	return top;
}
 
void painteeprom()								//Paints every 12th location with the magic number
{
	u08 magic=MAGIC_NUMBER;						//magic is our painting value
	u32 n=0;
	for(;n<131072;n++/*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
		}*/
		if(!((u08)n))							//this code is for writing every byte
		{
			i2cstop();
			_delay_loop_2( (u16) ( (float)F_CPU*0.006/4.0 ) );//delay 6 ms for page write
			set_address(&n);
		}
		i2cwrite(magic);
		wdt_reset();
	}
	i2cstop();
}
#endif

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();
code/i2c_eeprom.txt ยท Last modified: 2009/03/20 04:50 by laurenceb