AnsweredAssumed Answered

I2C slave read issue with ADuC7023

Question asked by nsolanki on Feb 25, 2014
Latest reply on Mar 3, 2014 by nsolanki

Setup:

 

  • ADuC7023 Interrupt based ADI I2C slave sample code running on the ADuC7023 custom prototype board
  • Bit-bang I2C master code running on the ADuC7021 Eval Kit
  • Hardware is tested. Ground on the both board tied. I2C cables are short. Waveform looks nice. Pulls ups are 4.7 K

 

Codes:

 

ADI sample I2C slave code for the ADuC7023

#include <aduc7023.h>

// Bit Definitions

#define BIT0  0x01

#define BIT1  0x02

#define BIT2  0x04

#define BIT3  0x08

#define BIT4  0x10

#define BIT5  0x20

#define BIT6  0x40

#define BIT7  0x80

#define BIT8  0x100

#define BIT9  0x200

#define BIT10 0x400

#define BIT11 0x800

#define BIT12 0x1000

#define BIT13 0x2000

#define BIT14 0x4000

#define BIT15 0x8000

#define BIT16 0x10000

 

 

unsigned char szStoreData[] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55};    // Array to send to Slave

unsigned char ucStoreCount = 0;          // Array index variable for szStoreData[]

unsigned int uiTest = 0;

int main(void)

{

    POWKEY1 = 0x01;                        // Configure CPU Clock for 41.78MHz, CD=0

     POWCON = 0x00;

     POWKEY2 = 0xF4;   

 

    POWKEY3 = 0x76;                         // Enable PWM, SPI, I2C0, I2C1 Peripherals with 41.78MHz clock

    POWCON1 = 0x924;                   

    POWKEY4 = 0xB1;

    // Configure P0.4 and P0.5 for I2C mode

    GP0CON |= 0x00110000;                // Only write to bits 4/5

    I2C0SCON = BIT0                       // Enable I2C Slave + Enable Rx interrupt +

            + BIT9 + BIT10              // Enable Rx interrupt + Enable Tx interrupt +

            + BIT8;                        // Enable "Stop-after-Start-Detected" IRQ.

    I2C0ID0  = 0xA0;                    // Configure Slave's I2C network address

    I2C0FSTA = BIT8;                    // Flush Slave Tx FIFO

    I2C0FSTA &= ~BIT8;

 

    uiTest = I2C0SCON;

    IRQEN = BIT9;                         // Enable I2C0 Slave interrupts

 

    ucStoreCount = 0;

    while (1)

    {

    }

           

}

void IRQ_Handler(void) __irq

{

    unsigned long IRQSTATUS = 0;

    unsigned int I2CSSTATUS = 0;

 

    IRQSTATUS = IRQSTA;                       // Read off IRQSTA register

 

    if ((IRQSTATUS & BIT9) == BIT9)        //If I2C Slave interrupt source

    {

       I2CSSTATUS = I2C0SSTA;

       if ((I2CSSTATUS & BIT2) == BIT2) // If I2C Master Tx IRQ

       {

            if (ucStoreCount < 6)        // Have max 6 bytes been sent?

                I2C0STX = szStoreData[ucStoreCount++];     // Load Tx buffer

       }

       if ((I2CSSTATUS & BIT3) == BIT3) // If I2C Master Rx IRQ

       {

            if (ucStoreCount < 6)        // Have max 6 bytes been received?

            {

                szStoreData[ucStoreCount] = I2C0SRX;  // Read Rx buffer

                ucStoreCount++;

            }

       }

       if ((I2CSSTATUS & BIT10) == BIT10)// If I2C Stop after Start condition detected IRQ

       {

            ucStoreCount = 0;            // Reset counter Array pointer.

            I2C0FSTA = BIT8;            // Flush Slave Tx FIFO

            I2C0FSTA &= ~BIT8;

       }

       if ((I2CSSTATUS & BIT13) == BIT13) // If I2C Repeated Start detected IRQ

       {

            ucStoreCount = 0;            // Reset counter Array pointer.

            I2C0FSTA = BIT8;            // Flush Slave Tx FIFO

            I2C0FSTA &= ~BIT8;

       }

    }

}

 

 

Bit-Bang I2C code for ADuc7021:

 

 

//P1.1 is configured for SDA

#define SDA0_enable(state)  GP1DAT|=0x02000000;GP1DAT&=0xFFFDFFFF;              //dir-out op-low

#define SDA0_set(state)     ((state?(GP1DAT&=0xFDFFFFFF):(GP1DAT|=0x02000000)))

#define SDA0_get()          ((GP1DAT&0x02)?1:0)

 

//P1.0 is configured for SCL

#define SCL0_enable(state)  GP1DAT|=0x01000000;GP1DAT&=0xFFFEFFFF;              //dir-out op-low

#define SCL0_set(state)     ((state?(GP1DAT&=0xFEFFFFFF):(GP1DAT|=0x01000000)))

 

void i2c_delay(void)

{

   u_int_8 i;

   for (i = 5; i; i--);  

}

 

void i2c_enable (u_int_8 port, u_int_8 enable)

{

   switch (port) {

   case 0:

       // port 0

       SDA0_enable(enable);

       SDA0_set(1);

       SCL0_enable(enable);

       SCL0_set(1);

       break;

   default:

       // unknown port

       break;

   }

   i2c_stop(port);

}

 

void i2c_start (u_int_8 port)

{

/*

*  assumes SDA, SCL = 1

*

*  leaves SDA, SCL = 0

*/

   switch (port) {

   case 0:

       // set SDA and SCL high just in case

       SDA0_set(1);

       i2c_delay();

       SCL0_set(1);

       i2c_delay();

 

       // start conditions are a falling edge on SDA while SCL is high

       SDA0_set(0);

       i2c_delay();

       SCL0_set(0);

       i2c_delay();

       break;

   default:

       // unknown port

       break;

   }

}

 

void i2c_stop (u_int_8 port)

{

/*

*  assumes SDA = 1, SCL = 0

*

*  leaves SDA, SCL = 1

*/

   switch (port) {

   case 0:

       // set SCL low just in case

       SCL0_set(0);

       i2c_delay();

 

       // stop conditions are a rising edge on SDA while SCL is high

       SDA0_set(0);

       i2c_delay();

       SCL0_set(1);

       i2c_delay();

       SDA0_set(1);

       i2c_delay();

       break;

   default:

       // unknown port

       break;

   }

}

 

u_int_8 i2c_putbyte (u_int_8 port, u_int_8 data)

{

/*

*  assumes SDA = 1, SCL = 0

*

*  leaves SDA = 1, SCL = 0

*/

   u_int_8 i;

 

   switch (port) {

   case 0:

       // clock out bits

       for (i = 8; i>0; i--) {

           // put data on the line

           SDA0_set(data&0x80);

           data<<=1;

           i2c_delay();

 

           // clock

           SCL0_set(1);

           i2c_delay();

           SCL0_set(0);

           i2c_delay();

           // release the line

           SDA0_set(1);

           i2c_delay();

       }

       // get ack/nack

       SCL0_set(1);

       i2c_delay();

       i = SDA0_get();

       SCL0_set(0);

       i2c_delay();

       return i;

   default:

       break;

   }

   return 0;

}

 

u_int_8 i2c_getbyte (u_int_8 port, u_int_8 ack)

{

/*

*  assumes SDA = 1, SCL = 0

*

*  leaves SDA = 1, SCL = 0

*/

   u_int_8 i;

   u_int_8 data = 0;

   switch (port) {

   case 0:

       // clock out bits

       for (i = 8; i>0; i--) {

           // unconditionally release SDA, just in case

           SDA0_set(1);

           i2c_delay();

           SCL0_set(1);

           i2c_delay();

           data<<=1;

           data |= SDA0_get();

           SCL0_set(0);

           i2c_delay();

       }

       // set ack/nack

       if (ack)

           SDA0_set(0); // ack

       else

           SDA0_set(1); // nack

       i2c_delay();

       SCL0_set(1);

       i2c_delay();

       SCL0_set(0);

       i2c_delay();

       // release SDA

       SDA0_set(1);

       i2c_delay();

       // return received byte

       return data;

   default:

       break;

   }

   return 0;

}

 

 

int main (void){

     //This sets the clock for the ARM

     SystemClockSetup(F_41_78_MHZ,MODE_ACTIVE);

     //i2c Write works

     i2c_start(0);

     i2c_putbyte(0, 0xA0);

     i2c_putbyte(0, 0xB1);   

     i2c_putbyte(0, 0xC1);   

     i2c_putbyte(0, 0xD1);

     i2c_putbyte(0, 0xD1);

     i2c_stop(0);

 

     while(1){     //This doesn't work I2C slave read

         i2c_start(0);
         i2c_putbyte(0,0xA1);
         rx_byte[0] = i2c_getbyte(0,1);
         rx_byte[1] = i2c_getbyte(0,1);
         rx_byte[2] = i2c_getbyte(0,1);
         rx_byte[3] = i2c_getbyte(0,1);
         i2c_stop(0);

          i2c_delay(0);

          i2c_delay(0);     //break point is here.

      }

}

 

Issues:

 

When I ran the above code in the ADuC7021, it doesn't read reliably from the slave i2c of ADuC7023. Its reading alternate between correct values and 0xff. e.g. first time array output rx_byte = [0xB1, 0XC1, 0xD1, 0xE1], second time rx_byte = [0xFF, 0XFF, 0xFF, 0xFF], third time array output rx_byte = [0xB1, 0XC1, 0xD1, 0xE1], forth time rx_byte = [0xFF, 0XFF, 0xFF, 0xFF] ........repeats

 

So no reliable read.

 

 

Observation:

 

  • When I look on the scope waveform looks fines and waveform corresponds to the data above.

 


Is there any solution or way around this one? I checked the Errata for ADuc7023 i2c slave but nothing.

Any help is appreciated.

 

Regards,

nsolanki

Outcomes