13 Replies Latest reply on Mar 20, 2020 5:14 PM by MoTa_728816

    I2C Master and multi slave communication problem

    ErNo_1148106

      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

        • 1. Re: I2C Master and multi slave communication problem
          BragadeeshV_41

          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

          • 2. Re: I2C Master and multi slave communication problem
            MoTa_728816

            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

            • 3. Re: I2C Master and multi slave communication problem
              ErNo_1148106

              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

              • 4. Re: I2C Master and multi slave communication problem
                ErNo_1148106

                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

                • 5. Re: I2C Master and multi slave communication problem
                  MoTa_728816

                  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

                  • 6. Re: I2C Master and multi slave communication problem
                    ErNo_1148106

                    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

                    • 7. Re: I2C Master and multi slave communication problem
                      MoTa_728816

                      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.

                      • 8. Re: I2C Master and multi slave communication problem
                        ErNo_1148106

                        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

                        • 9. Re: I2C Master and multi slave communication problem
                          MoTa_728816

                          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

                          • 10. Re: I2C Master and multi slave communication problem
                            ErNo_1148106

                            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

                            • 11. Re: I2C Master and multi slave communication problem
                              MoTa_728816

                              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

                              • 12. Re: I2C Master and multi slave communication problem
                                ErNo_1148106

                                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

                                • 13. Re: I2C Master and multi slave communication problem
                                  MoTa_728816

                                  Dear Eric-san,

                                   

                                  Thank you very much for the nice news!

                                   

                                  Have a nice day!

                                   

                                  Best Regards,

                                  21-Mar-2020

                                  Motoo Tanaka