Strange I2C Problem LPC1200

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

Strange I2C Problem LPC1200

588 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by jab on Wed Feb 29 15:19:18 MST 2012
I have a custom LPC1200 board which is being used in a project to read input from some I2C I/O Expanders, process the input and then write it out over i2c to some LED drivers.

I have an LPClink debug board and have been debugging the code. Writing values over I2c works perfectly but I am having trouble reading values.

When I run the code and step through it line by line it works fine, I2C reads complete and then the value is taken in.

When the code is allowed to just run (in debugger) and is stopped at breakpoints the code doesnt work.

When the code is just run, it doesnt work.

I dont understand the problem, I can only assume the compiler is optimising something out?

I have posted the relevant bits of code. I havent included ALL the code simply because some of it works totally fine and is independent of these bits.

Main.c
volatile uint32_t msTicks=0; // counter for 1ms SysTicks
volatile unsigned char LED[5] = {0, 0, 0, 0, 0};
volatile unsigned char BUTTONS[8];

int main(void)
{
    unsigned char IOCONF[5] = {0, 0, 0, 0, 0};
    unsigned char Temp[2] = { 0xff, 0xff};

    SetupI2CBlock();
    PCA9545_SetCh(0, 0, 0, 0, 1);
    PCA9505_Write(0, PCA9505_CMD_AI|PCA9505_CMD_IOC0, 5, (unsigned char*)IOCONF);

    PCA9545_SetCh(0, 1, 0, 0, 0);

    PCA8575_Write(0, (unsigned char*) Temp);

    /* Systick rate is 1ms for timekeeping */
    SysTick_Config(SystemCoreClock / 1000);

    /* Blink for 5 seconds, then enter ISP */
    while(1)
    {
        if (msTicks%100==0)
        {
            // Function
            unsigned char TempButtons[2];
            PCA9545_SetCh(0, 1, 0, 0, 0);

            /******************************************/
            // Problems begin here
            // PCA8575_READ never overwrites Tempbuttons unless stepping through code manually in debugger
            PCA8575_Read(0, (unsigned char*) TempButtons);

            LED[0] = TempButtons[0];
            LED[1] = TempButtons[1];
            LED[2] = 0;
            LED[3] = 0;
            LED[4] = 0;

            PCA9545_SetCh(0, 0, 0, 0, 1);
            PCA9505_Write(0, PCA9505_CMD_AI|PCA9505_CMD_OP0, 5, (unsigned char*)LED);

        }
        __WFI();
    }
    return 0;
}
// ****************
//  SysTick_Handler - just increment SysTick counter
void SysTick_Handler(void)
{
    msTicks++;
}


PCA8575.c
void PCA8575_Read(unsigned char AddressOffset, unsigned char *Data)
{
    unsigned char Address = PCA8575_Base_Addr + AddressOffset;

    ReceiveI2C(Address, 2, Data);
}


i2c.c
void ReceiveI2C(unsigned char Address, unsigned char NumBytes, unsigned char* Data)
{
    unsigned char I2CAddress = (Address << 1) + 1;

    // Clear SI Bit
    i2c_clr_intrpt_flag();
    // Set the I2C Enable Bit
    i2c_enable();
    // Load the address
    LPC_I2C->DAT = I2CAddress;
    // Set the STA bit
    i2c_start_tx();
    // Wait until the SI bit is set
    while ((LPC_I2C->CONSET & 0x08) == 0);
    // Check the Status Register
    if (LPC_I2C->STAT != 0x08)
    {
        i2c_stop_tx();
        return;
    }

    // Clear SI & Start Flag
    i2c_no_start();
    i2c_ack();
    i2c_clr_intrpt_flag();

    // Wait until the SI bit is set again
    while ((LPC_I2C->CONSET & 0x08) == 0);

    if (LPC_I2C->STAT != 0x40)
    {
        i2c_nack();
        i2c_clr_intrpt_flag();
        i2c_stop_tx();
        return;
    }

    if (NumBytes <= 1)
    {
        i2c_nack();
        i2c_clr_intrpt_flag();
    }
    else
    {
        i2c_ack();
        i2c_clr_intrpt_flag();

        unsigned i;

        for(i = 0; i < NumBytes; i++)
        {
            while((LPC_I2C->CONSET & 0x08) == 0);

            if (LPC_I2C->STAT == 0x50)
            {
                if (i > (NumBytes - 2))//-If more then two receive another byte
                {
                   Data = LPC_I2C->DAT;   //-Load data buffer.
                }
                else//-Get ready to stop receiving
                {//-Part 1 of 2 of the stop sequence
                    i2c_nack();                //-Send nAck so next interrupt goes to case 58H
                    Data = LPC_I2C->DAT;   //-Load data buffer - second to last byte to receive
                }
                // Clear SI Flag
                i2c_clr_intrpt_flag();
            }
            else if (LPC_I2C->STAT == 0x58)
            {
                ReadData = LPC_I2C->DAT;
                i2c_stop_tx();
                i2c_ack();                  //-Re-enable reception
                // Clear SI Flag
                i2c_clr_intrpt_flag();
            }
            else
            {
                i2c_stop_tx();
                // Clear SI Flag
                i2c_clr_intrpt_flag();
                return;
            }

            // Clear SI Flag
            i2c_clr_intrpt_flag();
        }
    }
}


Basically, Main calls PCA8575_Read, PCA8575_Read calls I2C_Read.

If i step through the code the data gets back, otherwise it seems to ignore that data was ever read from the I2C_DAT register.

I think that's is

oh using  LPCXpresso v4.1.0
0 Kudos
Reply
2 Replies

565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by jab on Wed Feb 29 16:50:35 MST 2012
Already There.....

In i2c.c at the start of the data loop:

while ((LPC_I2C->CONSET & 0x08 == 0);


0x08 is the SI bit so this waits until it becomes set
0 Kudos
Reply

565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rob65 on Wed Feb 29 15:56:25 MST 2012
This is not a problem with code being optimized away by the compiler.

If single stepping works but normal flow not then you are just missing something. In this case it seems you are not waiting for the data in the I2C_DAT register to become valid.

You might want to add a loop to wait for data to become available before reading I2C_DAT:
while (!(LPC_I2C->CONSET & I2C_I2CONSET_SI));


Rob
0 Kudos
Reply