I'm using an external I2C based eeprom on my MCF52233 board.
Now the code to initialise is as below. No matter what I do, I'm unable to get past the I2SR_IBB_BITMASK check. Can any one help me please?
void i2c_init(void)
{
if (I2SR | I2SR_IBB_BITMASK)
{
/* I2SR's IBB flag will be set on power up.
The sequenc below is done to reset this bit. */
I2CR = 0;
I2CR = 0xA0;
I2DR;
I2SR = 0;
I2CR = 0;
I2CR = 0x80;
}
/* The above set up is called again */
/* I2CR: IEN=0,IIEN=0,MSTA=0,MTX=1,TXAK=0,RSTA=0,??=0,??=0 */
I2CR = 0x10;
/* I2FDR: ??=0,??=0,IC=0x3B */
I2FDR = 0x3B;
/* I2ADR: ADR=0,??=0 */
I2ADR = 0x00;
/* I2SR: ICF=1,IAAS=0,IBB=0,IAL=0,??=0,SRW=0,IIF=0,RXAK=1 */
I2SR = 0x81;
/* I2CR: IEN=1 */
I2CR |= 0x80;
/* Check Bus Busy. */
while (I2SR | I2SR_IBB_BITMASK)
;
}
Solved! Go to Solution.
It's been a while since I did this, but I do have a serial EEPROM up and running on my MCF52233 board. Here is the init code:
/********************************************************************
// I2C port Init
//
// Configure the I2C port so we can talk to the external EEPROM
//
/********************************************************************/
void mcf5223x_i2c_init(void)
{
uint8 temp;
MCF_I2C_I2FDR = 0x38; // divide CPU clock by 640 to 100KHz ?
MCF_I2C_I2CR = MCF_I2C_I2CR_IEN; // Turn on the I2C port
/* if bit busy set, send a stop condition to slave module */
if( MCF_I2C_I2SR & MCF_I2C_I2SR_IBB)
{
MCF_I2C_I2CR = 0; /* clear control register */
MCF_I2C_I2CR = MCF_I2C_I2CR_IEN | /* enable module */
MCF_I2C_I2CR_MSTA; /* send a START conditionn */
temp = MCF_I2C_I2DR; /* dummy read */
MCF_I2C_I2SR = 0; /* clear status register */
MCF_I2C_I2CR = 0; /* clear control register */
MCF_I2C_I2CR = 0 | MCF_I2C_I2CR_IEN; /* enable the module again */
}
}
The Read and Write Routines
/***********************************************************************/
// Read an EEPROM Location
//
// Returns: EEPROM byte value
//
// Device is an Atmel or Microchip 24LC08 with all the external
// address pins grounded...
//
//
/***********************************************************************/
#define EEPROM_CTRL_WR 0xA0
#define EEPROM_CTRL_RD 0xA1
uint8 read_ee(int address)
{
uint8 data = 0;
int i=0;
// wait if the bus is busy or a transfer is in progress
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_ICF || // Wait here while either xfer is not done..
MCF_I2C_I2SR & MCF_I2C_I2SR_IBB ){}; // or the bus is busy
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the interrupt flag if on
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; // enable the ACK
MCF_I2C_I2CR |= MCF_I2C_I2CR_MTX; // Set the Transmit Mode
MCF_I2C_I2CR |= MCF_I2C_I2CR_MSTA; // Generate the START condition
MCF_I2C_I2DR = EEPROM_CTRL_WR | ((address>>7) & 0x0e); // Send the Control byte to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for the control byte done
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2DR = address & 0xff; // Send the word Address to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for address to go out
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2CR |= MCF_I2C_I2CR_RSTA; // Generate a REPEAT START condition
MCF_I2C_I2DR = EEPROM_CTRL_RD | ((address>>7) & 0x0e); // Send the Read control byte to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for control byte to go out
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MTX; // setup for the last xfer
MCF_I2C_I2CR |= MCF_I2C_I2CR_TXAK; // no ack....
data = MCF_I2C_I2DR; // Dummy xfer to trigger the read
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for read data
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA; // Send the stop condition
data = MCF_I2C_I2DR & 0xFF; // Grab it.
return(data);
}
/***********************************************************************/
// Write an EEPROM Location
//
// Returns: nothing
//
//
/***********************************************************************/
void write_ee(short int address, unsigned char data)
{
int i;
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; // enable the ACK
MCF_I2C_I2CR |= MCF_I2C_I2CR_MTX; // Set the Transmit Mode
MCF_I2C_I2CR |= MCF_I2C_I2CR_MSTA; // Generate the START condition
MCF_I2C_I2DR = EEPROM_CTRL_WR | ((address>>7) & 0x0e); // Send the Control byte to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for the control byte done
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2DR = address & 0xff; // Send the word Address to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for address to go out
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2DR = data; // write the data to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for data to go out
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA; // Send the stop condition
}
I recollected that I had not done anything with port assignment registers, so I added code for it, bit it still won't work.
void i2c_init(void)
{
PASPAR |= PASPAR_PASPAR00_BITMASK | PASPAR_PASPAR10_BITMASK;
if (I2SR | I2SR_IBB_BITMASK)
{
/* I2SR's IBB flag will be set on power up.
The sequenc below is done to reset this bit. */
I2CR = 0;
I2CR = 0xA0;
I2DR;
I2SR = 0;
I2CR = 0;
I2CR = 0x80;
}
/* The above set up is called again */
/* I2CR: IEN=0,IIEN=0,MSTA=0,MTX=1,TXAK=0,RSTA=0,??=0,??=0 */
I2CR = 0x10;
/* I2FDR: ??=0,??=0,IC=0x3B */
I2FDR = 0x3B;
/* I2ADR: ADR=0,??=0 */
I2ADR = 0x00;
/* I2SR: ICF=1,IAAS=0,IBB=0,IAL=0,??=0,SRW=0,IIF=0,RXAK=1 */
I2SR = 0x81;
/* I2CR: IEN=1 */
I2CR |= 0x80;
while (I2SR | I2SR_IBB_BITMASK)
;
}
Use of | instead of &. Embarrased, a silly mistake that was.
The check for the IBB should have been as below:-
while (I2SR & I2SR_IBB_BITMASK)
;
But I'm still trying. May be a few other with crop up.
It's been a while since I did this, but I do have a serial EEPROM up and running on my MCF52233 board. Here is the init code:
/********************************************************************
// I2C port Init
//
// Configure the I2C port so we can talk to the external EEPROM
//
/********************************************************************/
void mcf5223x_i2c_init(void)
{
uint8 temp;
MCF_I2C_I2FDR = 0x38; // divide CPU clock by 640 to 100KHz ?
MCF_I2C_I2CR = MCF_I2C_I2CR_IEN; // Turn on the I2C port
/* if bit busy set, send a stop condition to slave module */
if( MCF_I2C_I2SR & MCF_I2C_I2SR_IBB)
{
MCF_I2C_I2CR = 0; /* clear control register */
MCF_I2C_I2CR = MCF_I2C_I2CR_IEN | /* enable module */
MCF_I2C_I2CR_MSTA; /* send a START conditionn */
temp = MCF_I2C_I2DR; /* dummy read */
MCF_I2C_I2SR = 0; /* clear status register */
MCF_I2C_I2CR = 0; /* clear control register */
MCF_I2C_I2CR = 0 | MCF_I2C_I2CR_IEN; /* enable the module again */
}
}
The Read and Write Routines
/***********************************************************************/
// Read an EEPROM Location
//
// Returns: EEPROM byte value
//
// Device is an Atmel or Microchip 24LC08 with all the external
// address pins grounded...
//
//
/***********************************************************************/
#define EEPROM_CTRL_WR 0xA0
#define EEPROM_CTRL_RD 0xA1
uint8 read_ee(int address)
{
uint8 data = 0;
int i=0;
// wait if the bus is busy or a transfer is in progress
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_ICF || // Wait here while either xfer is not done..
MCF_I2C_I2SR & MCF_I2C_I2SR_IBB ){}; // or the bus is busy
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the interrupt flag if on
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; // enable the ACK
MCF_I2C_I2CR |= MCF_I2C_I2CR_MTX; // Set the Transmit Mode
MCF_I2C_I2CR |= MCF_I2C_I2CR_MSTA; // Generate the START condition
MCF_I2C_I2DR = EEPROM_CTRL_WR | ((address>>7) & 0x0e); // Send the Control byte to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for the control byte done
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2DR = address & 0xff; // Send the word Address to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for address to go out
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2CR |= MCF_I2C_I2CR_RSTA; // Generate a REPEAT START condition
MCF_I2C_I2DR = EEPROM_CTRL_RD | ((address>>7) & 0x0e); // Send the Read control byte to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for control byte to go out
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MTX; // setup for the last xfer
MCF_I2C_I2CR |= MCF_I2C_I2CR_TXAK; // no ack....
data = MCF_I2C_I2DR; // Dummy xfer to trigger the read
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for read data
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA; // Send the stop condition
data = MCF_I2C_I2DR & 0xFF; // Grab it.
return(data);
}
/***********************************************************************/
// Write an EEPROM Location
//
// Returns: nothing
//
//
/***********************************************************************/
void write_ee(short int address, unsigned char data)
{
int i;
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK; // enable the ACK
MCF_I2C_I2CR |= MCF_I2C_I2CR_MTX; // Set the Transmit Mode
MCF_I2C_I2CR |= MCF_I2C_I2CR_MSTA; // Generate the START condition
MCF_I2C_I2DR = EEPROM_CTRL_WR | ((address>>7) & 0x0e); // Send the Control byte to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for the control byte done
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2DR = address & 0xff; // Send the word Address to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for address to go out
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2DR = data; // write the data to the EEPROM
while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}; // then wait for data to go out
MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF; // clear the flag
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA; // Send the stop condition
}
Thanks for code, just perfect, I works without much effort.
I just modified the code a little bit to provide for ACKs. The only noticable change is the last section of the i2c_read() where IIF flag is rechecked. If I don't do this, I'm unable to do a read operation again??. For simplicity sake I've removed the arguments to these functions, read and writes are always done to address 0xaa55 (32K Bytes eeprom). The write forces a write 35 always.
void i2c_write(void)
{
I2CR &= ~I2CR_TXAK_BITMASK; // enable the ACK
I2CR |= I2CR_MTX_BITMASK; // Set the Transmit Mode
I2CR |= I2CR_MSTA_BITMASK; // Generate the START condition
I2DR = 0xa0; // Send the Control byte to the EEPROM
while(~I2SR & I2SR_IIF_BITMASK){}; // then wait for the control byte done
I2SR &= ~I2SR_IIF_BITMASK; // clear the flag
if (I2SR & I2SR_RXAK_BITMASK) // Check for ack bit.
{
I2CR &= ~I2CR_MSTA_BITMASK; // Send the stop condition
return;
}
I2DR = 0xaa; // Send the word Address high byte to the EEPROM
while(~I2SR & I2SR_IIF_BITMASK){}; // then wait for the control byte done
I2SR &= ~I2SR_IIF_BITMASK; // clear the flag
if (I2SR & I2SR_RXAK_BITMASK) // Check for ack bit.
{
I2CR &= ~I2CR_MSTA_BITMASK; // Send the stop condition
return;
}
I2DR = 0x55; // Send the word Address Low byte to the EEPROM
while(~I2SR & I2SR_IIF_BITMASK){}; // then wait for the control byte done
I2SR &= ~I2SR_IIF_BITMASK; // clear the flag
if (I2SR & I2SR_RXAK_BITMASK) // Check for ack bit.
{
I2CR &= ~I2CR_MSTA_BITMASK; // Send the stop condition
return;
}
I2DR = 35; // Write Data
while(~I2SR & I2SR_IIF_BITMASK){}; // then wait for the control byte done
I2SR &= ~I2SR_IIF_BITMASK; // clear the flag
if (I2SR & I2SR_RXAK_BITMASK) // Check for ack bit.
{
I2CR &= ~I2CR_MSTA_BITMASK; // Send the stop condition
return;
}
I2CR &= ~I2CR_MSTA_BITMASK; // Send the stop condition
}
void i2c_read(void)
{
UINT8 data=0;
/* Check Bus Busy. */
if(!st_exp_cent_timer(ST_I2C_CENT_TIMER))
return;
st_arm_cent_timer(ST_I2C_CENT_TIMER, 2);
I2CR &= ~I2CR_TXAK_BITMASK; // enable the ACK
I2CR |= I2CR_MTX_BITMASK; // Set the Transmit Mode
I2CR |= I2CR_MSTA_BITMASK; // Generate the START condition
I2DR = 0xa0; // Send the Control byte to the EEPROM
while(~I2SR & I2SR_IIF_BITMASK){}; // then wait for the control byte done
I2SR &= ~I2SR_IIF_BITMASK; // clear the flag
if (I2SR & I2SR_RXAK_BITMASK) // Check for ack bit.
{
I2CR &= ~I2CR_MSTA_BITMASK; // Send the stop condition
mtac_obj_tbl[0].r_phase.vtg = data;
return;
}
I2DR = 0xaa; // Send the word Address high byte to the EEPROM
while(~I2SR & I2SR_IIF_BITMASK){}; // then wait for the control byte done
I2SR &= ~I2SR_IIF_BITMASK; // clear the flag
if (I2SR & I2SR_RXAK_BITMASK) // Check for ack bit.
{
I2CR &= ~I2CR_MSTA_BITMASK; // Send the stop condition
mtac_obj_tbl[0].r_phase.vtg = data;
return;
}
I2DR = 0x55; // Send the word Address Low byte to the EEPROM
while(~I2SR & I2SR_IIF_BITMASK){}; // then wait for the control byte done
I2SR &= ~I2SR_IIF_BITMASK; // clear the flag
if (I2SR & I2SR_RXAK_BITMASK) // Check for ack bit.
{
I2CR &= ~I2CR_MSTA_BITMASK; // Send the stop condition
mtac_obj_tbl[0].r_phase.vtg = data;
return;
}
I2CR |= I2CR_RSTA_BITMASK; // Send a re-start condition.
I2DR = 0xa1; // Send the control byte to EEPROM
while(~I2SR & I2SR_IIF_BITMASK){}; // then wait for the control byte done
I2SR &= ~I2SR_IIF_BITMASK; // clear the flag
if (I2SR & I2SR_RXAK_BITMASK) // Check for ack bit.
{
I2CR &= ~I2CR_MSTA_BITMASK; // Send the stop condition
mtac_obj_tbl[0].r_phase.vtg = data;
return;
}
I2CR |= I2CR_TXAK_BITMASK; // Disable the TACK
I2CR &= ~I2CR_MTX_BITMASK; // Change the direction to receive.
I2DR; // Dummy Read to trigger receive.
while(~I2SR & I2SR_IIF_BITMASK){}; // then wait for the control byte done
I2SR &= ~I2SR_IIF_BITMASK; // clear the flag
data = I2DR;
while(~I2SR & I2SR_IIF_BITMASK){}; // Wait for one byte transfer is done.
I2SR &= ~I2SR_IIF_BITMASK; // clear the flag
I2CR &= ~I2CR_MSTA_BITMASK; // Send the stop condition
mtac_obj_tbl[0].r_phase.vtg = data;
}
I don understand wat purpose this serves,its at the beginning of the transmitter & receiver,
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK;
I think it shud be MCF_I2C_I2CR &= MCF_I2C_I2CR_TXAK; for transmitter & when it changes to receiver mode it is
MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK;
Please let me kno if ur code is working
Thank you,
Chethu
Hi Chethu
When the I2C master is receiving data it should set MCF_I2C_I2CR_TXAK to '1' only on the last byte that it reads. It should be '0' for all others.
This causes an ACK to be sent to the slave on each byte reception but excluding the final one so that the slave device knows that the read has now completed.
Regards
Mark