I2C Master On MCF52233

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

I2C Master On MCF52233

Jump to solution
4,010 Views
ahoysala
Contributor I

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)
        ;

 

}

Labels (1)
0 Kudos
Reply
1 Solution
1,167 Views
Dave_at_Mot
Contributor III

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
   
}


 

View solution in original post

0 Kudos
Reply
6 Replies
1,167 Views
ahoysala
Contributor I

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)
        ;

 

 

}

0 Kudos
Reply
1,167 Views
ahoysala
Contributor I

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.

 

0 Kudos
Reply
1,168 Views
Dave_at_Mot
Contributor III

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
   
}


 

0 Kudos
Reply
1,167 Views
ahoysala
Contributor I

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;
}

0 Kudos
Reply
1,167 Views
Chethu
Contributor I

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

Message Edited by Chethu on 2010-01-07 02:50 PM
0 Kudos
Reply
1,167 Views
mjbcswitzerland
Specialist V

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

 

 

 

0 Kudos
Reply