This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

I²C unexpected behaviour

Hi folks,

I'm trying to read a constant voltage through the MCP3425 ADC connected to a LPC1768 microcontroller, using the i2c 1 port. My code is based in one of the Keil i2c usage examples.
I'm getting a very strange behaviour, I ended up stucked in a point in which I can't get into a conclusion: if I'm getting this issue due to the way I'm reading the channel through the microcontroller or if this behavious is normal to this ADC.

Look at the for loop inside the Firwmare.c file. I start configuring the MCP3425 address, and then I follow to a reading in a loop. The only way I found to get the two bytes of reading is setting the I2CReadLength[PORT_USED] as multiples of 2.

Firmware.c

#include <rtl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include "LPC17xx.h"
#include "type.h"
#include "i2c.h"


#define      WAIT_SI      while (!(LPC_I2C1->I2CONSET & (1<<3)))
#define      CLEAR_SI      LPC_I2C1->I2CONCLR = 1<< 3
#define      ACTION       LPC_GPIO0->FIOSET0 = 1
#define      ACTION_E      LPC_GPIO0->FIOCLR0 = 1
#define      ADDRESS       LPC_GPIO0->FIOSET0 = 2
#define      ADDRESS_E      LPC_GPIO0->FIOCLR0 = 2

#define      WRITE      LPC_GPIO0->FIOSET0 = 1<<4
#define      WRITE_E            LPC_GPIO0->FIOCLR0 = 1<<4
#define      READ       LPC_GPIO0->FIOSET0 = 1<<5
#define      READ_E     LPC_GPIO0->FIOCLR0 = 1<<5


#define PORT_USED               1
extern volatile uint8_t I2CMasterBuffer[I2C_PORT_NUM][BUFSIZE];
extern volatile uint8_t I2CSlaveBuffer[I2C_PORT_NUM][BUFSIZE];
extern volatile uint32_t I2CReadLength[I2C_PORT_NUM];
extern volatile uint32_t I2CWriteLength[I2C_PORT_NUM];

int main(void) {
        uint32_t i;

        SystemInit();

        I2C1Init();

        I2CWriteLength[PORT_USED] = 2;
        I2CReadLength[PORT_USED] = 0;
        I2CMasterBuffer[PORT_USED][0] = 0xD0; //MCP3425 DEVICE CODE ADDRESS FROM DATASHEET
        I2CMasterBuffer[PORT_USED][1] = 0x18;    //continuos conversion

        I2CEngine(PORT_USED);

        DELAY_ms(2000);

        //here i'm reading a voltage in a loop
for(i=0; i < 128;i = i+2){
        I2CWriteLength[PORT_USED] = 1;
        I2CReadLength[PORT_USED] = i+2;
        I2CMasterBuffer[PORT_USED][0] = 0xD1;
        I2CEngine(PORT_USED);

        DELAY_ms(2000);

}

        while (1);

}

  • i2c.c

    
    #include "lpc17xx.h"
    #include "type.h"
    #include "i2c.h"
    
    volatile uint32_t I2CMasterState[I2C_PORT_NUM] = {I2C_IDLE,I2C_IDLE,I2C_IDLE};
    volatile uint32_t timeout[I2C_PORT_NUM] = {0, 0, 0};
    
    volatile uint8_t I2CMasterBuffer[I2C_PORT_NUM][BUFSIZE];
    volatile uint8_t I2CSlaveBuffer[I2C_PORT_NUM][BUFSIZE];
    volatile uint32_t I2CCount[I2C_PORT_NUM] = {0, 0, 0};
    volatile uint32_t I2CReadLength[I2C_PORT_NUM];
    volatile uint32_t I2CWriteLength[I2C_PORT_NUM];
    
    volatile uint32_t RdIndex0 = 0, RdIndex1 = 0, RdIndex2 = 0;
    volatile uint32_t WrIndex0 = 0, WrIndex1 = 0, WrIndex2 = 0;
    
    
    void I2C1_IRQHandler(void)
    {
      uint8_t StatValue;
    
      timeout[1] = 0;
      /* this handler deals with master read and master write only */
      StatValue = LPC_I2C1->I2STAT;
      switch ( StatValue )
      {
            case 0x08:                      /* A Start condition is issued. */
            WrIndex1 = 0;
            LPC_I2C1->I2DAT = I2CMasterBuffer[1][WrIndex1++];
            LPC_I2C1->I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
            break;
    
            case 0x10:                      /* A repeated started is issued */
            RdIndex1 = 0;
            /* Send SLA with R bit set, */
            LPC_I2C1->I2DAT = I2CMasterBuffer[1][WrIndex1++];
            LPC_I2C1->I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
            break;
    
            case 0x18:                      /* Regardless, it's a ACK */
            if ( I2CWriteLength[1] == 1 )
            {
              LPC_I2C1->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
              I2CMasterState[1] = I2C_NO_DATA;
            }
            else
            {
              LPC_I2C1->I2DAT = I2CMasterBuffer[1][WrIndex1++];
            }
            LPC_I2C1->I2CONCLR = I2CONCLR_SIC;
            break;
    
            case 0x28:      /* Data byte has been transmitted, regardless ACK or NACK */
            if ( WrIndex1 < I2CWriteLength[1] )
            {
              LPC_I2C1->I2DAT = I2CMasterBuffer[1][WrIndex1++]; /* this should be the last one */
            }
            else
            {
              if ( I2CReadLength[1] != 0 )
              {
                    LPC_I2C1->I2CONSET = I2CONSET_STA;   /* Set Repeated-start flag */
              }
              else
              {
                    LPC_I2C1->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
                    I2CMasterState[1] = I2C_OK;
              }
            }
            LPC_I2C1->I2CONCLR = I2CONCLR_SIC;
            break;
    
            case 0x30:
            LPC_I2C1->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
            I2CMasterState[1] = I2C_NACK_ON_DATA;
            LPC_I2C1->I2CONCLR = I2CONCLR_SIC;
            break;
    
            case 0x40:      /* Master Receive, SLA_R has been sent */
            if ( (RdIndex1 + 1) < I2CReadLength[1] )
            {
              /* Will go to State 0x50 */
              LPC_I2C1->I2CONSET = I2CONSET_AA;  /* assert ACK after data is received */
            }
            else
            {
              /* Will go to State 0x58 */
              LPC_I2C1->I2CONCLR = I2CONCLR_AAC; /* assert NACK after data is received */
            }
            LPC_I2C1->I2CONCLR = I2CONCLR_SIC;
            break;
    
            case 0x50:      /* Data byte has been received, regardless following ACK or NACK */
            I2CSlaveBuffer[1][RdIndex1++] = LPC_I2C1->I2DAT;
            if ( (RdIndex1 + 1) < I2CReadLength[1] )
            {
              LPC_I2C1->I2CONSET = I2CONSET_AA;  /* assert ACK after data is received */
            }
            else
            {
              LPC_I2C1->I2CONCLR = I2CONCLR_AAC; /* assert NACK on last byte */
            }
            LPC_I2C1->I2CONCLR = I2CONCLR_SIC;
            break;
    
            case 0x58:
            I2CSlaveBuffer[1][RdIndex1++] = LPC_I2C1->I2DAT;
            I2CMasterState[1] = I2C_OK;
            LPC_I2C1->I2CONSET = I2CONSET_STO;   /* Set Stop flag */
            LPC_I2C1->I2CONCLR = I2CONCLR_SIC;   /* Clear SI flag */
            break;
    
            case 0x20:              /* regardless, it's a NACK */
            case 0x48:
            LPC_I2C1->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
            I2CMasterState[1] = I2C_NACK_ON_ADDRESS;
            LPC_I2C1->I2CONCLR = I2CONCLR_SIC;
            break;
    
            case 0x38:              /* Arbitration lost, in this example, we don't
                                            deal with multiple master situation */
            default:
            I2CMasterState[1] = I2C_ARBITRATION_LOST;
            LPC_I2C1->I2CONCLR = I2CONCLR_SIC;
            break;
      }
      return;
    }
    
    uint32_t I2CStart( uint32_t portNum )
    {
      uint32_t retVal = FALSE;
    
      timeout[portNum] = 0;
      /*--- Issue a start condition ---*/
      LPC_I2C[portNum]->I2CONSET = I2CONSET_STA; /* Set Start flag */
    
      /*--- Wait until START transmitted ---*/
      while( 1 )
      {
            if ( I2CMasterState[portNum] == I2C_STARTED )
            {
              retVal = TRUE;
              break;
            }
            if ( timeout[portNum] >= MAX_TIMEOUT )
            {
              retVal = FALSE;
              break;
            }
            timeout[portNum]++;
      }
      return( retVal );
    }
    
    uint32_t I2CStop( uint32_t portNum )
    {
      LPC_I2C[portNum]->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
      LPC_I2C[portNum]->I2CONCLR = I2CONCLR_SIC;  /* Clear SI flag */
    
      /*--- Wait for STOP detected ---*/
      while( LPC_I2C[portNum]->I2CONSET & I2CONSET_STO );
      return TRUE;
    }
    
    void I2C1Init( void )
    {
      LPC_SC->PCONP |= (1 << 19);
    
    #if 0
      /* set PIO0.0 and PIO0.1 to I2C1 SDA and SCL */
      /* function to 11 on both SDA and SCL. */
      LPC_PINCON->PINSEL0 &= ~((0x3<<0)|(0x3<<2));
      LPC_PINCON->PINSEL0 |= ((0x3<<0)|(0x3<<2));
      LPC_PINCON->PINMODE0 &= ~((0x3<<0)|(0x3<<2));
      LPC_PINCON->PINMODE0 |= ((0x2<<0)|(0x2<<2));           /* No pull-up no pull-down */
      LPC_PINCON->PINMODE_OD0 |= ((0x01<<0)|(0x1<<1));       /* Open drain */
    #endif
    #if 1
      /* set PIO0.19 and PIO0.20 to I2C1 SDA and SCL */
      /* function to 11 on both SDA and SCL. */
    
     LPC_PINCON->PINSEL1 = 0;
      LPC_PINCON->PINSEL1 |= 0x3C0;
      LPC_PINCON->PINMODE1 = 0;
      LPC_PINCON->PINMODE1 |= 0x280;     /* No pull-up no pull-down */
      LPC_PINCON->PINMODE_OD0 |= ((0x1<<19)|(0x1<<20));
    
    #endif
    
      /*--- Clear flags ---*/
      LPC_I2C1->I2CONCLR = I2CONCLR_AAC | I2CONCLR_SIC | I2CONCLR_STAC | I2CONCLR_I2ENC;
    
      /*--- Reset registers ---*/
      LPC_I2C1->I2SCLL   = I2SCLL_SCLL;
      LPC_I2C1->I2SCLH   = I2SCLH_SCLH;
    
      /* Install interrupt handler */
      NVIC_EnableIRQ(I2C1_IRQn);
    
      LPC_I2C1->I2CONSET = I2CONSET_I2EN;
      return;
    }
    
    uint32_t I2CEngine( uint32_t portNum )
    {
      /*--- Issue a start condition ---*/
      LPC_I2C[portNum]->I2CONSET = I2CONSET_STA; /* Set Start flag */
    
      I2CMasterState[portNum] = I2C_BUSY;
    
      while ( I2CMasterState[portNum] == I2C_BUSY )
      {
            if ( timeout[portNum] >= MAX_TIMEOUT )
            {
              I2CMasterState[portNum] = I2C_TIME_OUT;
              break;
            }
            timeout[portNum]++;
      }
      LPC_I2C[portNum]->I2CONCLR = I2CONCLR_STAC;
    
      return ( I2CMasterState[portNum] );
    }