PSoC Freezes during I2C Transmit with no Slave

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
xahuc_3536641
Level 2
Level 2

Hi All,

I have seen a lot of posts about I2C transmission issues, but none that seem to help point me in the right direction.

I have an issue where every time I try to send a message to a slave that doesn't exist on the bus, the whole PSoC freezes up! I can trigger it at will and using the debugger I have found it gets stuck in the while loop on line 29 of the following chunk of generated code:

uint8 I2C_Master_MasterSendStart(uint8 slaveAddress, uint8 R_nW)
     
{
    uint8 errStatus;

    errStatus = I2C_Master_MSTR_NOT_READY;

    /* If IDLE, check if bus is free */
    if(I2C_Master_SM_IDLE == I2C_Master_state)
    {
        /* If bus is free, generate Start condition */
        if(I2C_Master_CHECK_BUS_FREE(I2C_Master_MCSR_REG))
        {
            /* Disable interrupt for manual master operation */
            I2C_Master_DisableInt();

            /* Set address and read/write flag */
            slaveAddress = (uint8) (slaveAddress << I2C_Master_SLAVE_ADDR_SHIFT);
            if(0u != R_nW)
            {
                slaveAddress |= I2C_Master_READ_FLAG;
                I2C_Master_state = I2C_Master_SM_MSTR_RD_ADDR;
            }
            else
            {
                I2C_Master_state = I2C_Master_SM_MSTR_WR_ADDR;
            }

            /* Hardware actions: write address and generate Start */
            I2C_Master_DATA_REG = slaveAddress;
            I2C_Master_GENERATE_START_MANUAL;

            /* Wait until address is transferred */
            while(I2C_Master_WAIT_BYTE_COMPLETE(I2C_Master_CSR_REG))
            {
            }

        #if(I2C_Master_MODE_MULTI_MASTER_SLAVE_ENABLED)
            if(I2C_Master_CHECK_START_GEN(I2C_Master_MCSR_REG))
            {
                I2C_Master_CLEAR_START_GEN;

                /* Start condition was not generated: reset FSM to IDLE */
                I2C_Master_state = I2C_Master_SM_IDLE;
                errStatus = I2C_Master_MSTR_ERR_ABORT_START_GEN;
            }
            else
        #endif /* (I2C_Master_MODE_MULTI_MASTER_SLAVE_ENABLED) */

        #if(I2C_Master_MODE_MULTI_MASTER_ENABLED)
            if(I2C_Master_CHECK_LOST_ARB(I2C_Master_CSR_REG))
            {
                I2C_Master_BUS_RELEASE_MANUAL;

                /* Master lost arbitrage: reset FSM to IDLE */
                I2C_Master_state = I2C_Master_SM_IDLE;
                errStatus = I2C_Master_MSTR_ERR_ARB_LOST;
            }
            else
        #endif /* (I2C_Master_MODE_MULTI_MASTER_ENABLED) */

            if(I2C_Master_CHECK_ADDR_NAK(I2C_Master_CSR_REG))
            {
                /* Address has been NACKed: reset FSM to IDLE */
                I2C_Master_state = I2C_Master_SM_IDLE;
                errStatus = I2C_Master_MSTR_ERR_LB_NAK;
            }
            else
            {
                /* Start was sent without errors */
                errStatus = I2C_Master_MSTR_NO_ERROR;
            }
        }
        else
        {
            errStatus = I2C_Master_MSTR_BUS_BUSY;
        }
    }

    return(errStatus);
}

Now I know for sure that if the I2C master tries to communicate with a slave that isn't present, it shouldn't cause the bus to fail. I have NO idea why it is and it's causing me serious problems because of the intended application.

Below is a copy of my I2C code:

#include "project.h"
#include "I2C.h"

void I2C_Delay();
void I2C_Reset();

uint8 I2C_Start()
{
    I2C_Master_Start();
    return I2C_SUCCESS;
}

void Clear_Read_Buff(uint8* data, uint8 data_length)
{
    for(uint8 i = 0; i < data_length; i++)
    {
        data = 0;
    }
}

uint8 I2C_Master_Write_Data(uint8 slave_address, uint8* data, uint8 data_length)
{
    uint8 status = 0;
   
    status = I2C_Master_MasterSendStart(slave_address, I2C_Master_WRITE_XFER_MODE);
    if(status == I2C_Master_MSTR_NO_ERROR)
    {
        for(uint8 i = 0; i < data_length; i++)
        {
            status = I2C_Master_MasterWriteByte(data);
            if(status != I2C_Master_MSTR_NO_ERROR)
            {
                I2C_Master_MasterSendStop();
                I2C_Delay();
                I2C_Reset();
                return I2C_FAILURE;
            }
        }
    }
    else
    {               
        I2C_Master_MasterSendStop();
        I2C_Delay();
        I2C_Reset();
        return I2C_FAILURE;
    }
    I2C_Master_MasterSendStop();
    I2C_Delay();
    return I2C_SUCCESS;
}

uint8 I2C_Master_Read_Data(uint8 slave_address, uint8 mem_loc, uint8* data_buf, uint8 data_length)
{   
    uint8 status = 0;
   
    status = I2C_Master_MasterSendStart(slave_address, I2C_Master_WRITE_XFER_MODE);
    if(status == I2C_Master_MSTR_NO_ERROR)
    {
        status = I2C_Master_MasterWriteByte(mem_loc);
        if (status != I2C_Master_MSTR_NO_ERROR)
        {
            I2C_Master_MasterSendStop();
            I2C_Delay();
            I2C_Reset();
            return I2C_FAILURE;
        }
    }
    else
    {
        I2C_Master_MasterSendStop();
        I2C_Delay();
        I2C_Reset();
        return I2C_FAILURE;
    }
   
    status = I2C_Master_MasterSendRestart(slave_address, I2C_Master_READ_XFER_MODE);
    if(status == I2C_Master_MSTR_NO_ERROR)
    {
        for(uint8 i = 0; i < data_length - 1; i++)
        {
            data_buf = I2C_Master_MasterReadByte(I2C_Master_ACK_DATA);
        }
        data_buf[data_length - 1] = I2C_Master_MasterReadByte(I2C_Master_NAK_DATA);
    }
    else
    {
        I2C_Master_MasterSendStop();
        I2C_Delay();
        I2C_Reset();
        return I2C_FAILURE;
    }
    I2C_Master_MasterSendStop();
    I2C_Delay();
    return I2C_SUCCESS;
}

/* I2C Read with a 16 Byte Memory Location */
uint8 I2C_Master_Read_Data16(uint8 slave_address, uint16 mem_loc, uint8* data_buf, uint8 data_length)
{   
    uint8 status = 0;
    uint8 mem_loc_h = (mem_loc & 0xFF00) >> 8;
    uint8 mem_loc_l = (mem_loc & 0x00FF);
   
    status = I2C_Master_MasterSendStart(slave_address, I2C_Master_WRITE_XFER_MODE);
    if(status == I2C_Master_MSTR_NO_ERROR)
    {
        status = I2C_Master_MasterWriteByte(mem_loc_h);
        if(status == I2C_Master_MSTR_NO_ERROR)
        {
            status = I2C_Master_MasterWriteByte(mem_loc_l);
            if (status != I2C_Master_MSTR_NO_ERROR)
            {
                I2C_Master_MasterSendStop();
                I2C_Delay();
                I2C_Reset();
                return I2C_FAILURE;
            }
        }
    }
    else
    {
        I2C_Master_MasterSendStop();
        I2C_Delay();
        I2C_Reset();
        return I2C_FAILURE;
    }
   
    status = I2C_Master_MasterSendRestart(slave_address, I2C_Master_READ_XFER_MODE);
    if(status == I2C_Master_MSTR_NO_ERROR)
    {
        for(uint8 i = 0; i < data_length - 1; i++)
        {
            data_buf = I2C_Master_MasterReadByte(I2C_Master_ACK_DATA);
        }
        data_buf[data_length - 1] = I2C_Master_MasterReadByte(I2C_Master_NAK_DATA);
    }
    else
    {
        I2C_Master_MasterSendStop();
        I2C_Delay();
        I2C_Reset();
        return I2C_FAILURE;
    }
    I2C_Master_MasterSendStop();
    I2C_Delay();
    return I2C_SUCCESS;
}

uint8 I2C_Master_Read_Byte(uint8 slave_address, uint8* result)
{
    uint8 status = 0;

    status = I2C_Master_MasterSendStart(slave_address, I2C_Master_READ_XFER_MODE);
    if(status == I2C_Master_MSTR_NO_ERROR)
    {
        *result = I2C_Master_MasterReadByte(I2C_Master_ACK_DATA);
    }
    else
    {
        I2C_Master_MasterSendStop();
        I2C_Delay();
        I2C_Reset();
        return I2C_FAILURE;
    }
   
    I2C_Master_MasterSendStop();
    I2C_Delay();
    return I2C_SUCCESS;
}

void I2C_Delay()
{
    CyDelay(I2C_DELAY_MS);
}

void I2C_Reset()
{
    I2C_Reset_Reg_Write(0b1);
    I2C_Master_Stop();
    I2C_Master_Start();
   
//    Indicator_LED_OUT_Write(0x00);
//    CyDelay(50);
//    Indicator_LED_OUT_Write(0x01);
//    CyDelay(50);
//    Indicator_LED_OUT_Write(0x00);
//    CyDelay(50);
//    Indicator_LED_OUT_Write(0x01);
//    CyDelay(50);
//    Indicator_LED_OUT_Write(0x00);
}

Any and all help is appreciated! I have no idea what I am doing wrong.

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.

Hi xavier.hubbard_3536641​,

Thanks for the update. From the images you have sent, it is like the master is trying to send a start condition but something is pulling the line high. There could be timing issues in the communication due to parasitic capacitance and selection of pull up resistors. But if that is the case, this issue should have occurred under normal conditions also.

But if the issue is with the PSoC firmware, then this issue should have occurred even with the slave present. Anyhow since it is a low level API, it has many blocking while loops without any timeout features. I have attached a sample code wherein I have created a custom API CustomMasterSendStart() that has a timeout feature using SysTick timer in it. Please find the attached sample project and let me know if it resolves your issue.

Under ideal conditions, the PSoC master should just receive a NACK if there is no slave (that is addressed by master) in the bus.

Under no circumstance I could replicate your issue. The one and only time it occurred was when the I2C bus was disturbed. (Disconnected master from bus)

Now since I couldn't replicate your issue, I want you to try a very simple I2C Low level API sample code with anyone of your slave device. If you still face the issue, there is problem with the PSoC device. If not, there is something else wrong in your hardware/ other part of your firmware.

Could you please try the following also?

1.Try using high level APIs and see if you still face the issue.

2. Before checking for the  while(I2C_Master_WAIT_BYTE_COMPLETE(I2C_Master_CSR_REG)) , check if the start condition generation is complete by checking the start_gen bit of  I2C_MCSR register. Check if it has become 0. It becomes 0 when start condition generation is complete. I hope this will always be 1 in your case.  Since no start condition was generated, byte_complete bit of I2C_CSR register will never be set to 1. (Data have been transmitted and an ACK or NACK has been received.) This is what we are checking in the while loop.

Also what is the data rate and the pull up resistors value you are using. Can you check the following?

1. Decrease data rate and report the no of times this failure occurs

2. Increase data rate and report the no of times the failure occurs.

Regards,

Bragadeesh

Regards,
Bragadeesh

View solution in original post

0 Likes
23 Replies