I2C Master and multi slave communication problem

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

cross mob
ErNo_1148106
Level 4
Level 4
First solution authored 50 replies posted 25 replies posted

All,

I have a project that has a psoc 4 (CY8C4025LQI-S411) as a I2C master and have the same chip as four slaves all on the same bus with these four addresses: 0x18, 0x28, 0x38, 0x48. The bus is running at 100 khz speed, the pullups are external 4.7k resistors on SCL and SDA lines and its powered with 3.3V. The problem I am having is the master has to switch to the different chips by changing the address to access the different chip and it works ok for a little bit but then stops writing the data correctly which I am thinking it has lost synchronization some how. If I do not change the address the software works fine with 0x18 or the other addresses all day long but when I change to any other address it stops working correctly.

Does the I2C master component need to be stopped to make the address change and then restart the component again? The write buffer is thirty five bytes long and the read buffer is 32 bytes long and all four slave chips have the same firmware aside from the address differences. I checked on my logic analyzer and oscope and the write and read waveforms look good when its working and when it is not the write waveform loses its data and the read appears fine other than the returned data is all 0xff's. It sounds like it is losing synchronization but don't know for sure. I do not know what I am doing wrong and need help to shed some light on this issue. I need to be able to change the address during runtime which in turn connects the host software to another chip on the bus to configure it and then change again etc etc.

Any ideas are greatly appreciated!!

Thanks,

Eric

0 Likes
1 Solution

Hi Motoo,

I have fixed the problem with the I2C issue. I used a exit callback interrupt so the slave can detect the presence of new data. I am now onto the next challenge and believe I have a fix for this new issue now. Thanks for your insight it is greatly appreciated.

Thanks,

Eric

View solution in original post

13 Replies
BragadeeshV
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hi ErNo_1148106​,

Can you please share your psoc creator project and the scope shots of the bus so that we can debug the issue from our side?

Also, please make sure you are completing the current transaction and then write to the next address.

The address of the slave can be simply changed by changing the slave address here. SCB_I2CMasterWriteBuf(uint32 slaveAddress, uint8 * wrData, uint32 cnt, uint32 mode).

Regards,

Bragadeesh

Regards,
Bragadeesh
0 Likes

Hi Bragadeesh,

Unfortunately I can't really share the project easily. It is rather big and would be several psoc files. I can give you snippets though. Here is the master read/write function I am using so far:

void I2C_COMM_Y_Driver_Command_Packet(uint8_t slave_addr)

{

    uint8_t wr_buffer[I2C_COMM_WR_BUFFER_SIZE];

    uint8_t rd_buffer[I2C_COMM_RD_BUFFER_SIZE];

    uint8_t status = 0;

   

    /* I2C COMM is busy */

    I2C_READY_FLAG = 1;

    /* Initialize buffer with packet */  

    wr_buffer[I2C_COMM_PACKET_WR_SOP_POS] = I2C_COMM_PACKET_SOP;

    wr_buffer[I2C_COMM_PACKET_WR_I2A_POS] = I2C_ADDRESS;

    wr_buffer[I2C_COMM_PACKET_WR_DRA_POS] = DRIVER_ACTIVE;

    wr_buffer[I2C_COMM_PACKET_WR_IRU_POS] = IRUN_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_IHO_POS] = IHOLD_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_IHD_POS] = IHOLD_DELAY_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_TPD_POS] = TPOWERDOWN_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_ESC_POS] = EN_SpreadCycle_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_PAS_POS] = PWM_AutoScale_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_PAG_POS] = PWM_AutoGrad_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_PFQ_POS] = PWM_FREQ_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_TOF_POS] = TOFF_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_TBL_POS] = TBL_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_HST_POS] = HSTRT_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_HEN_POS] = HEND_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_TP0_POS] = TPWMTHRS_DATA[0];

    wr_buffer[I2C_COMM_PACKET_WR_TP1_POS] = TPWMTHRS_DATA[1];

    wr_buffer[I2C_COMM_PACKET_WR_TP2_POS] = TPWMTHRS_DATA[2];

    wr_buffer[I2C_COMM_PACKET_WR_TP3_POS] = TPWMTHRS_DATA[3];

    wr_buffer[I2C_COMM_PACKET_WR_PWL_POS] = PWM_LIM_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_PWR_POS] = PWM_REG_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_PWO_POS] = PWM_OFS_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_PWG_POS] = PWM_GRAD_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_MRS_POS] = MRES_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_TC0_POS] = TCOOLTHRS_DATA[0];

    wr_buffer[I2C_COMM_PACKET_WR_TC1_POS] = TCOOLTHRS_DATA[1];

    wr_buffer[I2C_COMM_PACKET_WR_TC2_POS] = TCOOLTHRS_DATA[2];

    wr_buffer[I2C_COMM_PACKET_WR_TC3_POS] = TCOOLTHRS_DATA[3];

    wr_buffer[I2C_COMM_PACKET_WR_SGT_POS] = SGTHRS_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_SEI_POS] = SEIMIN_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_SED_POS] = SEDN_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_SEM_POS] = SEMAX_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_SEU_POS] = SEUP_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_SMN_POS] = SEMIN_DATA;

    wr_buffer[I2C_COMM_PACKET_WR_EPE_POS] = EEPROM_PROG_EN;

    wr_buffer[I2C_COMM_PACKET_WR_RDR_POS] = RD_REQUEST;

    wr_buffer[I2C_COMM_PACKET_WR_BLE_POS] = BOOTLOAD_EN;

    wr_buffer[I2C_COMM_PACKET_WR_EOP_POS] = I2C_COMM_PACKET_EOP;

    /* Start I2C write and check status*/

    if (I2C_COMM_I2C_MSTR_NO_ERROR == I2C_COMM_I2CMasterWriteBuf(slave_addr, wr_buffer, I2C_COMM_WR_PACKET_SIZE,        I2C_COMM_I2C_MODE_COMPLETE_XFER))

    {

        /*If I2C write started without errors, wait until I2C Master completes write transfer */

        while (0u == (I2C_COMM_I2CMasterStatus() & I2C_COMM_I2C_MSTAT_WR_CMPLT))

        {

            /* Wait */

        }

        /* Displays transfer status */   

        if (0u == (I2C_COMM_I2CMasterStatus() & I2C_COMM_I2C_MSTAT_ERR_XFER))

        {

            /* Check if all bytes was written */

            if (I2C_COMM_I2CMasterGetWriteBufSize() == I2C_COMM_WR_PACKET_SIZE)

            {

                I2C_STATUS = I2C_TRANSFER_CMPLT;

            }

           

            else

            {

                I2C_STATUS = I2C_TRANSFER_ERROR;

            }

        }

    }

   

    CyDelay(10u);   /****** Delay 10ms between I2C transactions ******/

   

    (void) I2C_COMM_I2CMasterClearStatus();

   

    if (I2C_COMM_I2C_MSTR_NO_ERROR == I2C_COMM_I2CMasterReadBuf(slave_addr, rd_buffer, I2C_COMM_RD_PACKET_SIZE, I2C_COMM_I2C_MODE_COMPLETE_XFER))

    {

        /* If I2C read started without errors, wait until master complete read transfer */

        while (0u == (I2C_COMM_I2CMasterStatus() & I2C_COMM_I2C_MSTAT_RD_CMPLT))

        {

            /* Wait */

        }

       

        /* Display transfer status */

        if (0u == (I2C_COMM_I2C_MSTAT_ERR_XFER & I2C_COMM_I2CMasterStatus()))

        {           

            /* Check packet structure */

            if ((I2C_COMM_I2CMasterGetReadBufSize() == I2C_COMM_RD_PACKET_SIZE) &&

                (I2C_COMM_PACKET_SOP == rd_buffer[I2C_COMM_PACKET_RD_SOP_POS]) &&

                (I2C_COMM_PACKET_EOP == rd_buffer[I2C_COMM_PACKET_RD_EOP_POS]))

            {               

                /* Check packet status */

                if (I2C_COMM_STS_CMD_DONE == rd_buffer[I2C_COMM_PACKET_RD_STS_POS])

                {

                    Y_TMC2209_DRVSTATUS_REG0_BYTE = rd_buffer[I2C_COMM_PACKET_RD_DS0_POS];

                    Y_TMC2209_DRVSTATUS_REG1_BYTE = rd_buffer[I2C_COMM_PACKET_RD_DS1_POS];

                    Y_TMC2209_DRVSTATUS_REG2_BYTE = rd_buffer[I2C_COMM_PACKET_RD_DS2_POS];

                    Y_TMC2209_DRVSTATUS_REG3_BYTE = rd_buffer[I2C_COMM_PACKET_RD_DS3_POS];

                    Y_TMC_IFCNT0 = rd_buffer[I2C_COMM_PACKET_RD_IF0_POS];

                    Y_TMC_IFCNT1 = rd_buffer[I2C_COMM_PACKET_RD_IF1_POS];

                    Y_TMC_IFCNT2 = rd_buffer[I2C_COMM_PACKET_RD_IF2_POS];

                    Y_TMC_IFCNT3 = rd_buffer[I2C_COMM_PACKET_RD_IF3_POS];

                    Y_TMC_OTP_READ0 = rd_buffer[I2C_COMM_PACKET_RD_OT0_POS];

                    Y_TMC_OTP_READ1 = rd_buffer[I2C_COMM_PACKET_RD_OT1_POS];

                    Y_TMC_OTP_READ2 = rd_buffer[I2C_COMM_PACKET_RD_OT2_POS];

                    Y_TMC_OTP_READ3 = rd_buffer[I2C_COMM_PACKET_RD_OT3_POS];

                    Y_TMC_TSTEP0 = rd_buffer[I2C_COMM_PACKET_RD_TS0_POS];

                    Y_TMC_TSTEP1 = rd_buffer[I2C_COMM_PACKET_RD_TS1_POS];

                    Y_TMC_TSTEP2 = rd_buffer[I2C_COMM_PACKET_RD_TS2_POS];

                    Y_TMC_TSTEP3 = rd_buffer[I2C_COMM_PACKET_RD_TS3_POS];

                    Y_TMC_SG_RESULT0 = rd_buffer[I2C_COMM_PACKET_RD_SG0_POS];

                    Y_TMC_SG_RESULT1 = rd_buffer[I2C_COMM_PACKET_RD_SG1_POS];

                    Y_TMC_SG_RESULT2 = rd_buffer[I2C_COMM_PACKET_RD_SG2_POS];

                    Y_TMC_SG_RESULT3 = rd_buffer[I2C_COMM_PACKET_RD_SG3_POS];

                    Y_TMC_MSCNT0 = rd_buffer[I2C_COMM_PACKET_RD_MC0_POS];

                    Y_TMC_MSCNT1 = rd_buffer[I2C_COMM_PACKET_RD_MC1_POS];

                    Y_TMC_MSCNT2 = rd_buffer[I2C_COMM_PACKET_RD_MC2_POS];

                    Y_TMC_MSCNT3 = rd_buffer[I2C_COMM_PACKET_RD_MC3_POS];

                    Y_TMC_MSCURACT0 = rd_buffer[I2C_COMM_PACKET_RD_MS0_POS];

                    Y_TMC_MSCURACT1 = rd_buffer[I2C_COMM_PACKET_RD_MS1_POS];

                    Y_TMC_MSCURACT2 = rd_buffer[I2C_COMM_PACKET_RD_MS2_POS];

                    Y_TMC_MSCURACT3 = rd_buffer[I2C_COMM_PACKET_RD_MS3_POS];

                    Y_TMC_PWM_SCALE0 = rd_buffer[I2C_COMM_PACKET_RD_PS0_POS];

                    Y_TMC_PWM_SCALE1 = rd_buffer[I2C_COMM_PACKET_RD_PS1_POS];

                    Y_TMC_PWM_SCALE2 = rd_buffer[I2C_COMM_PACKET_RD_PS2_POS];

                    Y_TMC_PWM_SCALE3 = rd_buffer[I2C_COMM_PACKET_RD_PS3_POS];

                    Y_TMC_PWM_AUTO0 = rd_buffer[I2C_COMM_PACKET_RD_PA0_POS];

                    Y_TMC_PWM_AUTO1 = rd_buffer[I2C_COMM_PACKET_RD_PA1_POS];

                    Y_TMC_PWM_AUTO2 = rd_buffer[I2C_COMM_PACKET_RD_PA2_POS];

                    Y_TMC_PWM_AUTO3 = rd_buffer[I2C_COMM_PACKET_RD_PA3_POS];

                    EEPROM_PROG_CMPLT = rd_buffer[I2C_COMM_PACKET_RD_EPC_POS];

                   

                    Y_TMC2209_RD_PWM_SCALE_OUT_BYTE = Y_TMC2209_RD_PWM_SCALE_REG_BYTE;   /* Copy converted register data */

                   

                    I2C_STATUS = status = I2C_TRANSFER_CMPLT;

                   

                    if (I2C_STATUS == 0x00)

                    {

                        I2C_COMM_XFER_CMPLT_LED_Write(LED_ON);

                        CyDelay(5u);    /* Delay 5ms */

                        I2C_COMM_XFER_CMPLT_LED_Write(LED_OFF);

                    }

                }

               

                else

                {

                    I2C_STATUS = status = I2C_TRANSFER_ERROR;

                   

                    if (I2C_STATUS == 0x01)

                    {

                        I2C_COMM_XFER_ERROR_LED_Write(LED_ON);

                        CyDelay(5u);    /* Delay 5ms */

                        I2C_COMM_XFER_ERROR_LED_Write(LED_OFF);

                    }

                }

            }

        }

    }

   

    /* I2C COMM is idle */

    I2C_READY_FLAG = 0;

}

As you can see in the code I change the slave address when I send the request over from the configuration utility. The part I am having a hard time with is knowing when it is OK to switch over to the next slave address to configure the next device without corrupting the data transmission. Is there a status API or sample code you have that can do this?

Here is the code snippet from the slave side:

void Process_I2C_COMM_Packet(void)

{  

    /* Write complete: Parse command packet */  

    if (0u != (I2C_COMM_I2C_SSTAT_WR_CMPLT & I2C_COMM_I2CSlaveStatus()))

    {

        /* Check packet length */       

        if (I2C_COMM_WR_PACKET_SIZE == I2C_COMM_I2CSlaveGetWriteBufSize())

        {

            /* Check start and end of packet markers */          

            if ((I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_SOP_POS] == I2C_COMM_PACKET_SOP) &&

                (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_EOP_POS] == I2C_COMM_PACKET_EOP))

            {

                I2C_ADDRESS = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_I2A_POS]);

                DRIVER_ACTIVE = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_DRA_POS]);

                IRUN_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_IRU_POS]);

                IHOLD_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_IHO_POS]);

                IHOLD_DELAY_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_IHD_POS]);

                TPOWERDOWN_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TPD_POS]);

                EN_SpreadCycle_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_ESC_POS]);

                PWM_AutoScale_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_PAS_POS]);

                PWM_AutoGrad_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_PAG_POS]);

                PWM_FREQ_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_PFQ_POS]);

                TOFF_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TOF_POS]);

                TBL_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TBL_POS]);

                HSTRT_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_HST_POS]);

                HEND_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_HEN_POS]);

                TPWMTHRS_WR_DATA0 = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TP0_POS]);

                TPWMTHRS_WR_DATA1 = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TP1_POS]);

                TPWMTHRS_WR_DATA2 = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TP2_POS]);

                TPWMTHRS_WR_DATA3 = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TP3_POS]);

                PWM_LIM_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_PWL_POS]);

                PWM_REG_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_PWR_POS]);

                PWM_OFS_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_PWO_POS]);

                PWM_GRAD_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_PWG_POS]);

                MRES_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_MRS_POS]);

                TCOOLTHRS_WR_DATA0 = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TC0_POS]);

                TCOOLTHRS_WR_DATA1 = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TC1_POS]);

                TCOOLTHRS_WR_DATA2 = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TC2_POS]);

                TCOOLTHRS_WR_DATA3 = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_TC3_POS]);

                SGTHRS_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_SGT_POS]);

                SEIMIN_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_SEI_POS]);

                SEDN_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_SED_POS]);

                SEMAX_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_SEM_POS]);

                SEUP_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_SEU_POS]);

                SEMIN_DATA = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_SMN_POS]);

                EEPROM_PROG_EN = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_EPE_POS]);

                RD_REQUEST = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_RDR_POS]);

                BOOTLOAD_EN = (I2C_COMM_WRITE_BUFFER[I2C_COMM_PACKET_WR_BLE_POS]);

        

                I2C_COMM_XFER_CMPLT_LED_Write(LED_ON);

                CyDelay(5u);    /* Delay 5ms */

                I2C_COMM_XFER_CMPLT_LED_Write(LED_OFF);

            }

           

            else    /* Bad packet format, set error */

            {                               

                I2C_COMM_XFER_ERROR_LED_Write(LED_ON);

                CyDelay(5u);    /* Delay 5ms */

                I2C_COMM_XFER_ERROR_LED_Write(LED_OFF);

            }

        }

       

        /* Clear the slave write buffer for next write */      

        I2C_COMM_I2CSlaveClearWriteBuf();

        (void) I2C_COMM_I2CSlaveClearWriteStatus();

    }

   

    /* Read complete: Expose buffer to master */   

    if (0u != (I2C_COMM_I2C_SSTAT_RD_CMPLT & I2C_COMM_I2CSlaveStatus()))

    { 

        /* Update read buffer */

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_SOP_POS] = I2C_COMM_PACKET_SOP;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_DS0_POS] = TMC_DRVSTATUS_RD0;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_DS1_POS] = TMC_DRVSTATUS_RD1;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_DS2_POS] = TMC_DRVSTATUS_RD2;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_DS3_POS] = TMC_DRVSTATUS_RD3;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_IF0_POS] = TMC_IFCNT_RD0;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_IF1_POS] = TMC_IFCNT_RD1;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_IF2_POS] = TMC_IFCNT_RD2;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_IF3_POS] = TMC_IFCNT_RD3;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_OT0_POS] = TMC_OTP_READ_RD0;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_OT1_POS] = TMC_OTP_READ_RD1;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_OT2_POS] = TMC_OTP_READ_RD2;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_OT3_POS] = TMC_OTP_READ_RD3;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_TS0_POS] = TMC_TSTEP_RD0;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_TS1_POS] = TMC_TSTEP_RD1;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_TS2_POS] = TMC_TSTEP_RD2;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_TS3_POS] = TMC_TSTEP_RD3;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_SG0_POS] = TMC_SG_RESULT_RD0;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_SG1_POS] = TMC_SG_RESULT_RD1;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_SG2_POS] = TMC_SG_RESULT_RD2;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_SG3_POS] = TMC_SG_RESULT_RD3;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_MC0_POS] = TMC_MSCNT_RD0;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_MC1_POS] = TMC_MSCNT_RD1;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_MC2_POS] = TMC_MSCNT_RD2;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_MC3_POS] = TMC_MSCNT_RD3;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_MS0_POS] = TMC_MSCURACT_RD0;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_MS1_POS] = TMC_MSCURACT_RD1;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_MS2_POS] = TMC_MSCURACT_RD2;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_MS3_POS] = TMC_MSCURACT_RD3;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_PS0_POS] = TMC_PWM_SCALE_RD0;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_PS1_POS] = TMC_PWM_SCALE_RD1;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_PS2_POS] = TMC_PWM_SCALE_RD2;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_PS3_POS] = TMC_PWM_SCALE_RD3;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_PA0_POS] = TMC_PWM_AUTO_RD0;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_PA1_POS] = TMC_PWM_AUTO_RD1;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_PA2_POS] = TMC_PWM_AUTO_RD2;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_PA3_POS] = TMC_PWM_AUTO_RD3;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_EPC_POS] = EEPROM_PROG_CMPLT;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_STS_POS] = I2C_COMM_status;

        I2C_COMM_READ_BUFFER[I2C_COMM_PACKET_RD_EOP_POS] = I2C_COMM_PACKET_EOP;

       

        /* Clear slave read buffer and status */       

        I2C_COMM_I2CSlaveClearReadBuf();

        (void) I2C_COMM_I2CSlaveClearReadStatus();

    }

}

Here is the code in the for loop section:

for(;;)

{

Process_I2C_COMM_Packet();

       

        CyDelay(1u);

               

        Process_WR_Data();

       

        CyDelay(1u);

               

        if (RD_REQUEST == 1)

        {                  

            TMC2209_DRVSTATUS_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_DRVSTATUS, false);   /* Read TMC DRVSTATUS data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_IFCNT_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_IFCNT, false);   /* Read TMC IFCNT data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_OTP_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_OTP_READ, false);   /* Read TMC OTP READ data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_TSTEP_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_TSTEP, false);   /* Read TMC TSTEP data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_SG_RESULT_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_SG_RESULT, false);   /* Read TMC SG RESULT data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_MSCNT_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_MSCNT, false);   /* Read TMC MSCNT data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_MSCURACT_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_MSCURACT, false);   /* Read TMC MSCURACT data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_PWM_SCALE_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_PWMSCALE, false);   /* Read TMC PWM SCALE data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_PWM_AUTO_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_PWM_AUTO, false);   /* Read TMC PWM AUTO data and transfer to I2C bridge */

 

            RD_REQUEST = 0;   /* Set to 0 after TMC read */

        }

}

The above code works great before attempting to switch to another slave device. Please let me know what you can make of this.

Thanks,

Eric

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

Although you may have already known this, we can get the I2C specification from

https://www.nxp.com/docs/en/user-guide/UM10204.pdf

I have written samples/demos accessing 4 or more slave devices using other PSoC 4(s)

without resetting the I2C Master Component.

I have not tried with CY8C4025LQI-S411 though.

The following are off my head check points

(1) Please check the ramp of each signal if it's within the range of the specification(s)

(2) If the ramp of (1) is rather slow, I would try to use 2.2K for pull up.

(3) Make sure to complete an I2C transaction before changing the slave address,

     this includes sending/receiving the expected number of data

     and finish the transaction by sending the Stop Condition.

(4) In case you are reading multi bytes, the last response needs to be "NAK"

    (I often make this mistake)

(5) Make sure the delay that slave requires from receiving the slave address

    to being ready for sending/receiving data is provided.

moto

Hi Motoo Tanaka,

Thank you for your input and yes I have seen the document you mentioned and tried to adhere to as much of what was in there.

Here is the responses to your questions:

The following are off my head check points

(1) Please check the ramp of each signal if it's within the range of the specification(s) The signal looks clean with very little curve at the top almost a square wave.

(2) If the ramp of (1) is rather slow, I would try to use 2.2K for pull up. I tried the 2.2k resistor with very little change to the SDA and SCL signals.

(3) Make sure to complete an I2C transaction before changing the slave address,

     this includes sending/receiving the expected number of data

     and finish the transaction by sending the Stop Condition. Is there status API I need to check for this? I posted code to Bragadeesh's reply. I was trying to use a flag to check if the send packet function is running and if not update the address. I'm sure I am doing something wrong. I have worked with I2C in the past but had four dedicated masters communicating to their respective slaves within a bigger PSOC 4 device. This of course alleviated the issues I am seeing now and wonder if I should scrap this project and go back to something that worked well in the past instead of re-inventing the wheel???

(4) In case you are reading multi bytes, the last response needs to be "NAK" Yes I see NAK's at the end of a write and read

    (I often make this mistake)

(5) Make sure the delay that slave requires from receiving the slave address

    to being ready for sending/receiving data is provided. Im not sure I understand what you mean by a delay?

If you have a small example it would be greatly appreciated to see how you have accomplished this task.

Thanks,

Eric

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Eric-san,

Thank you for your detailed response!

(1), (2), (4) seem to be fine.

About (3), Since you wrote that without changing the address, your program can run "long" time,

I think the chance of having problem here is low.

(5) I'm sorry for my poor English.

I have seen some sensors, which required a certain time after receiving the address

to prepare the device ready to response.

Usually you will see such data in the device's datasheet.

From your description of the symptom, I suspected that the buffer sending may not allow that time for the slave.

If you don't mind can you test the following?

=================

(1) Separate the buffer into 2 part

one for up to DRIVE_ACTIVE

     wr_buffer[I2C_COMM_PACKET_WR_SOP_POS] = I2C_COMM_PACKET_SOP;

    wr_buffer[I2C_COMM_PACKET_WR_I2A_POS] = I2C_ADDRESS;

    wr_buffer[I2C_COMM_PACKET_WR_DRA_POS] = DRIVER_ACTIVE;

the other for the rest.

(2) Then put some delay after the first part, something like

CyDelayUs(10) or CyDelayUs(50)

Then continue sending the rest.

(3)  If I can be even more picky, I'd like to put some delay between

    wr_buffer[I2C_COMM_PACKET_WR_I2A_POS] = I2C_ADDRESS;

and

    wr_buffer[I2C_COMM_PACKET_WR_DRA_POS] = DRIVER_ACTIVE;

=================

Best Regards,

20-Mar-2020

Motoo Tanaka

0 Likes

Hi Motoo,

Here is an o'scope snapshot of the beginning of the write i2c data transaction:

I2C_Capture.JPG

As you can see the quality of the display isn't the greatest but it shows that the I2C signals seem to be OK when it works right.

Please see the responses to your questions:

From your description of the symptom, I suspected that the buffer sending may not allow that time for the slave.

If you don't mind can you test the following?

=================

(1) Separate the buffer into 2 part

one for up to DRIVE_ACTIVE

     wr_buffer[I2C_COMM_PACKET_WR_SOP_POS] = I2C_COMM_PACKET_SOP;

    wr_buffer[I2C_COMM_PACKET_WR_I2A_POS] = I2C_ADDRESS;

    wr_buffer[I2C_COMM_PACKET_WR_DRA_POS] = DRIVER_ACTIVE;

the other for the rest.

(2) Then put some delay after the first part, something like

CyDelayUs(10) or CyDelayUs(50)

Then continue sending the rest.

(3)  If I can be even more picky, I'd like to put some delay between

    wr_buffer[I2C_COMM_PACKET_WR_I2A_POS] = I2C_ADDRESS;

and

    wr_buffer[I2C_COMM_PACKET_WR_DRA_POS] = DRIVER_ACTIVE;

=================

The way I am doing the function is to copy over the data to the buffer and then send it out using the writebuf function. I think by adding the small delay like you are asking will just delay the transfer of the copied data to the large buffer I have set up which is wr_buffer[38].

I think the problem could be from the slave device which is the "middle man". When I send a write and a read request to the slave the slave device might not be fully ready to read and write the data because it is communicating to the driver chip. I have this setup like so just to give you an idea:

for(;;)

    {

        //if (BOOTLOAD_EN == true)

        //{

            /* Schedule the Bootloader application start and execute a software reset */           

            //BOOTLOADABLE_Load();

        //}

       

        /* Check Processor Enable pin. If low, put cpu to sleep. If high, trigger ISR to wakeup the device */

        //if (CyPins_ReadPin(PROCESSOR_EN_0) == 0)

        //{

            //if (CyPins_ReadPin(PROCESSOR_EN_0) != DEEP_SLEEP_ENABLE)

            //{

                //DEEP_SLEEP_ENABLE = CyPins_ReadPin(PROCESSOR_EN_0);

               

                //CySysPmDeepSleep(); /* Put cpu to sleep */

            //}

           

            //DEEP_SLEEP_ENABLE = true;   /* This is never reached if chip goes to sleep. Once the chip wakes up this becomes true

                                           //after initialization */

        //}

       

        /* Wait for EEPROM flag. Once active, load values from EM EEPROM */

        //if (EEPROM_READ_INT == 0)

        //{

            //EM_EEPROM_Read_Data();  /* Send saved data to TMC2209 */

           

            //EEPROM_READ_INT = false;    /* Clear EEPROM flag */

        //}

       

        //if (CyPins_ReadPin(TMC_5V_ACTIVE_0))

        //{

            //TMC_General_Config();

        //}

        CyDelay(1u);

               

        Process_I2C_COMM_Packet();

       

        CyDelay(1u);

               

        Process_WR_Data();

       

        CyDelay(1u);

               

        if (RD_REQUEST == 1)

        {                  

            TMC2209_DRVSTATUS_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_DRVSTATUS, false);   /* Read TMC DRVSTATUS data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_IFCNT_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_IFCNT, false);   /* Read TMC IFCNT data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_OTP_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_OTP_READ, false);   /* Read TMC OTP READ data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_TSTEP_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_TSTEP, false);   /* Read TMC TSTEP data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_SG_RESULT_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_SG_RESULT, false);   /* Read TMC SG RESULT data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_MSCNT_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_MSCNT, false);   /* Read TMC MSCNT data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_MSCURACT_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_MSCURACT, false);   /* Read TMC MSCURACT data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_PWM_SCALE_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_PWMSCALE, false);   /* Read TMC PWM SCALE data and transfer to I2C bridge */

            CyDelay(1u);

            TMC2209_PWM_AUTO_RD_REG_BYTE = TMC2209_Datagram_Read(TMC_SLAVE_ADDR, TMC2209_PWM_AUTO, false);   /* Read TMC PWM AUTO data and transfer to I2C bridge */

 

            RD_REQUEST = 0;   /* Set to 0 after TMC read */

        }

    }

}

The first portion is commented out to try and isolate the issues. If you notice the last part has to be enabled to read the data from the driver. I know this code is working because I have been running the code to one slave only without switching to another slave and it has been running for three hours now and no hiccups yet.

When there is an address change that's when the problems start. When the address changes the write data shows only two bytes transferred which is the address and another byte 0x01. The read transaction looks complete but the full transaction has 0xFF's like its trying to recover from the bus error but cannot. Any ideas? Ill try what you mentioned and let you know what I find.

Thanks,

Eric

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Eric-san,

> I think the problem could be from the slave device which is the "middle man".

Oh, I see.

Then I wonder if there is a slave command which will not affect data but just cause an attention from the slave?

Something like "read state".

If there is such a command.

Can you try

(1) Send a usual data packet to slave A.

(2) Send an attention taking command to slave B.

(3) (May be not necessary) Wait a ms or so.

(4) Send a usual data packet to slave B.

And see if it works.

Best Regards,

20-Mar-2020

Motoo Tanaka

P.S. In case there is no such command,

may be sending only slave address and stopping transaction may also do.

0 Likes

Hi Motoo,

I just thought of a GREAT idea. I could setup the slave as an interrupt driven i2c slave and it will throw an interrupt when the master is sending/requesting information and then process the data and THEN write/read data to the driver chip... BRILLIANT!!! That way everything is synchronized to the master i2c device. This will hopefully solve the address issues as well. Ill post what I have found after I make the changes.

Thanks,

Eric

MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Eric-san,

That sounds promising!

I'm looking forward to hearing your update.

There is one more thing I noticed,

if I remember correct,

if the Master send to address 0

this means a broad-cast (General Call Address)

So we can wake-up (?) all the slaves at once.

Best Regards,

20-Mar-2020

Motoo Tanaka

0 Likes

Hi  Motoo,

I originally wanted a general call but seeing as how my application sends and then receives data it craps out because all four of the slave devices are sending and receiving at the same time.

Thanks,

Eric

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Eric-san,

What I meant was, you may be able to utilize a broadcast before changing the slave.

But your idea of using interrupt sounds more efficient.

The master may need some wait/delay after sending the address

so that the slave can have time to process interrupt.

Best Regards,

20-Mar-2020

Motoo Tanaka

0 Likes

Hi Motoo,

I have fixed the problem with the I2C issue. I used a exit callback interrupt so the slave can detect the presence of new data. I am now onto the next challenge and believe I have a fix for this new issue now. Thanks for your insight it is greatly appreciated.

Thanks,

Eric

MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Eric-san,

Thank you very much for the nice news!

Have a nice day!

Best Regards,

21-Mar-2020

Motoo Tanaka

0 Likes