PSOC6 I2C

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

cross mob
mrsinger
Level 1
Level 1
First solution authored 5 sign-ins First reply posted

I'm just trying to get some I2C comms going on a CY8C6247FDI-D32 as SCB0.   SCL is on P0[2] and SDA is on P0[3].   Ive tried setting  the pin mux for them to be GPIO and I can see the pins toggling so our wiring is OK.

Running the code,  SCL is high and stays that way.  And I get timeout errors on the I2C calls.  I dont see where I'm doing anything other than the examples I stole the code from.

What am I missing?

 

static cy_stc_scb_i2c_context_t i2cContext;
const cy_stc_scb_i2c_config_t i2cConfig =
{
.i2cMode = CY_SCB_I2C_MASTER,
.useRxFifo = false,
.useTxFifo = false,
.slaveAddress = 0U,
.slaveAddressMask = 0U,
.acceptAddrInFifo = false,
.ackGeneralAddr = false,
.enableWakeFromSleep = false,
.enableDigitalFilter = false,
.lowPhaseDutyCycle = 8U,
.highPhaseDutyCycle = 8U,
};


Cy_SCB_I2C_Init(SCB0, &i2cConfig, &i2cContext);

/* Connect SCB0 I2C function to pins */
Cy_GPIO_SetHSIOM(I2C_SCL_PORT, I2C_SCL_NUM, P0_2_SCB0_I2C_SCL);
Cy_GPIO_SetHSIOM(I2C_SDA_PORT, I2C_SDA_NUM, P0_3_SCB0_I2C_SDA);

/* Configure pins for I2C operation */
Cy_GPIO_SetDrivemode(I2C_SCL_PORT, I2C_SCL_NUM, CY_GPIO_DM_OD_DRIVESLOW);
Cy_GPIO_SetDrivemode(I2C_SDA_PORT, I2C_SDA_NUM, CY_GPIO_DM_OD_DRIVESLOW);

Cy_SysClk_PeriphAssignDivider(PCLK_SCB0_CLOCK, CY_SYSCLK_DIV_8_BIT, 1);
Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT, 1, 31);
Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT, 1);

uint32_t inputClockFrequency = Cy_SysClk_PeriphGetFrequency(CY_SYSCLK_DIV_8_BIT, 1);

uint32_t currentDataRate = Cy_SCB_I2C_SetDataRate(SCB0, 100000, inputClockFrequency);
if ((currentDataRate > 100000) || (currentDataRate == 0)) {
CY_ASSERT(0);
}

Cy_SCB_I2C_Enable(SCB0);

Cy_SCB_I2C_MasterSendStart(SCB0, 0x48, CY_SCB_I2C_WRITE_XFER, 1000, &i2cContext);
Cy_SCB_I2C_MasterWriteByte(SCB0, 0xAA, 1000, &i2cContext);
Cy_SCB_I2C_MasterSendStop(SCB0, 1000, &i2cContext);

0 Likes
1 Solution
PandaS
Moderator
Moderator
Moderator
250 replies posted 100 solutions authored 5 likes given

Hi @mrsinger ,

Sorry for the late response. I did try your code on my side for a PSoC 62 device, modified it a bit and it is working. I have attached my code example for your reference.

I suspect the fault to be lying in clock settings for I2C peripheral and data rate configurations, because I was also facing the same issue of I2C lines being high after implementing your code.

The Peripheral clock for I2C to be running at 100khz should be within a range of 1.55 – 3.2 MHz by using a peripheral divider. The code snippet provided in PDL documentation is for a PERI_CLK source of 50Mhz being divided by a factor of 32, thus giving an output of 1.56Mhz. So, for my system the PERI_CLK source was 100Mhz -> 8bit Divider 0 with factor 64 did the job. 

 

#include "cy_pdl.h"
#include "cyhal.h"
#include "cybsp.h"

#define I2C_PORT      (P6_0_PORT)
#define I2C_SCL_NUM   (P6_0_NUM)
#define I2C_SDA_NUM   (P6_1_NUM)

#define I2C_CLK_DIV_TYPE  (CY_SYSCLK_DIV_8_BIT)
#define I2C_CLK_DIV_NUM   (0U)

#define I2C_DESIRED_DATA_RATE_HZ    (100000U)

static cy_stc_scb_i2c_context_t i2cContext;

int main(void)
{
    cy_rslt_t result;

    /* Initialize the device and board peripherals */
    result = cybsp_init() ;
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }



    const cy_stc_scb_i2c_config_t i2cConfig =
    {
    .i2cMode = CY_SCB_I2C_MASTER,
    .useRxFifo = false,
    .useTxFifo = false,
    .slaveAddress = 0U,
    .slaveAddressMask = 0U,
    .acceptAddrInFifo = false,
    .ackGeneralAddr = false,
    .enableWakeFromSleep = false,
    .enableDigitalFilter = false,
    .lowPhaseDutyCycle = 8U,
    .highPhaseDutyCycle = 8U,
    };


    if(CY_SCB_I2C_SUCCESS != Cy_SCB_I2C_Init(SCB3, &i2cConfig, &i2cContext)){
    	while(1);
    }

    /* Connect SCB0 I2C function to pins */
    Cy_GPIO_SetHSIOM(I2C_PORT, I2C_SCL_NUM, P6_0_SCB3_I2C_SCL);
    Cy_GPIO_SetHSIOM(I2C_PORT, I2C_SDA_NUM, P6_1_SCB3_I2C_SDA);

    /* Configure pins for I2C operation */
    Cy_GPIO_SetDrivemode(I2C_PORT, I2C_SCL_NUM, CY_GPIO_DM_OD_DRIVESLOW);
    Cy_GPIO_SetDrivemode(I2C_PORT, I2C_SDA_NUM, CY_GPIO_DM_OD_DRIVESLOW);

    Cy_SysClk_PeriphAssignDivider(PCLK_SCB3_CLOCK, CY_SYSCLK_DIV_8_BIT, I2C_CLK_DIV_NUM);
    Cy_SysClk_PeriphSetDivider   (I2C_CLK_DIV_TYPE, I2C_CLK_DIV_NUM, 63u);
    Cy_SysClk_PeriphEnableDivider(I2C_CLK_DIV_TYPE, I2C_CLK_DIV_NUM);

    uint32_t dataRate;
    dataRate = Cy_SCB_I2C_SetDataRate(SCB3, I2C_DESIRED_DATA_RATE_HZ, Cy_SysClk_PeriphGetFrequency(I2C_CLK_DIV_TYPE, I2C_CLK_DIV_NUM));
    if ((dataRate > I2C_DESIRED_DATA_RATE_HZ) || (dataRate == 0U))
    {
        /* Can not reach desired data rate */
        CY_ASSERT(0U);
    }

    /* Enable I2C to operate */
    Cy_SCB_I2C_Enable(SCB3);

    /* Enable global interrupts */
    __enable_irq();



    for (;;)
    {
    	/* Wait 100 ms until operation completion */
    	uint32_t timeout = 100UL;
    	/* Send Start condition, address and receive ACK/NACK response from slave */
    	uint32_t status = Cy_SCB_I2C_MasterSendStart(SCB3, 0x48U, CY_SCB_I2C_WRITE_XFER, timeout, &i2cContext);

    	if (CY_SCB_I2C_SUCCESS == status)
    	{
    	    /* Write data into the slave */

    	    status = Cy_SCB_I2C_MasterWriteByte(SCB3, 0xAA, 1000, &i2cContext);

    	}
    	/* Check status of transaction */
    	if (status == CY_SCB_I2C_MASTER_MANUAL_ADDR_NAK)
    	{
    	    /* Send Stop condition on the bus */
    	    status = Cy_SCB_I2C_MasterSendStop(SCB3, timeout, &i2cContext);
    	    if (status == CY_SCB_I2C_SUCCESS)
    	    {
    	        /* Data has been written into the slave */
    	    }
    	}
    	else
    	{
    	    /* Other statuses do not require any actions */
    	}
    }
}

/* [] END OF FILE */

 

 

Here is the output of the above code on Logic Analyser.

PandaS_0-1653202318904.png

Here is the Pinout for the Pins used 6_0 and 6_1:

PandaS_1-1653205417343.png

Remark: Please ensure that the Pins and SCB block used in your application are only for I2C purpose and are not overlapping by any other function.

Thanks and Regards

Sobhit

 

View solution in original post

0 Likes
3 Replies
PandaS
Moderator
Moderator
Moderator
250 replies posted 100 solutions authored 5 likes given

Hi @mrsinger ,

Ensure that pull up resistors are provided externally(as it is in Open Drain Mode for I2C).

Follow this KBA for appropriate pull up and series resistors : https://community.infineon.com/t5/Knowledge-Base-Articles/Frequently-Asked-Questions-about-I2C-lines...

 

Thanks

Sobhit

0 Likes
mrsinger
Level 1
Level 1
First solution authored 5 sign-ins First reply posted

Yes, the pullup are external. 

0 Likes
PandaS
Moderator
Moderator
Moderator
250 replies posted 100 solutions authored 5 likes given

Hi @mrsinger ,

Sorry for the late response. I did try your code on my side for a PSoC 62 device, modified it a bit and it is working. I have attached my code example for your reference.

I suspect the fault to be lying in clock settings for I2C peripheral and data rate configurations, because I was also facing the same issue of I2C lines being high after implementing your code.

The Peripheral clock for I2C to be running at 100khz should be within a range of 1.55 – 3.2 MHz by using a peripheral divider. The code snippet provided in PDL documentation is for a PERI_CLK source of 50Mhz being divided by a factor of 32, thus giving an output of 1.56Mhz. So, for my system the PERI_CLK source was 100Mhz -> 8bit Divider 0 with factor 64 did the job. 

 

#include "cy_pdl.h"
#include "cyhal.h"
#include "cybsp.h"

#define I2C_PORT      (P6_0_PORT)
#define I2C_SCL_NUM   (P6_0_NUM)
#define I2C_SDA_NUM   (P6_1_NUM)

#define I2C_CLK_DIV_TYPE  (CY_SYSCLK_DIV_8_BIT)
#define I2C_CLK_DIV_NUM   (0U)

#define I2C_DESIRED_DATA_RATE_HZ    (100000U)

static cy_stc_scb_i2c_context_t i2cContext;

int main(void)
{
    cy_rslt_t result;

    /* Initialize the device and board peripherals */
    result = cybsp_init() ;
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }



    const cy_stc_scb_i2c_config_t i2cConfig =
    {
    .i2cMode = CY_SCB_I2C_MASTER,
    .useRxFifo = false,
    .useTxFifo = false,
    .slaveAddress = 0U,
    .slaveAddressMask = 0U,
    .acceptAddrInFifo = false,
    .ackGeneralAddr = false,
    .enableWakeFromSleep = false,
    .enableDigitalFilter = false,
    .lowPhaseDutyCycle = 8U,
    .highPhaseDutyCycle = 8U,
    };


    if(CY_SCB_I2C_SUCCESS != Cy_SCB_I2C_Init(SCB3, &i2cConfig, &i2cContext)){
    	while(1);
    }

    /* Connect SCB0 I2C function to pins */
    Cy_GPIO_SetHSIOM(I2C_PORT, I2C_SCL_NUM, P6_0_SCB3_I2C_SCL);
    Cy_GPIO_SetHSIOM(I2C_PORT, I2C_SDA_NUM, P6_1_SCB3_I2C_SDA);

    /* Configure pins for I2C operation */
    Cy_GPIO_SetDrivemode(I2C_PORT, I2C_SCL_NUM, CY_GPIO_DM_OD_DRIVESLOW);
    Cy_GPIO_SetDrivemode(I2C_PORT, I2C_SDA_NUM, CY_GPIO_DM_OD_DRIVESLOW);

    Cy_SysClk_PeriphAssignDivider(PCLK_SCB3_CLOCK, CY_SYSCLK_DIV_8_BIT, I2C_CLK_DIV_NUM);
    Cy_SysClk_PeriphSetDivider   (I2C_CLK_DIV_TYPE, I2C_CLK_DIV_NUM, 63u);
    Cy_SysClk_PeriphEnableDivider(I2C_CLK_DIV_TYPE, I2C_CLK_DIV_NUM);

    uint32_t dataRate;
    dataRate = Cy_SCB_I2C_SetDataRate(SCB3, I2C_DESIRED_DATA_RATE_HZ, Cy_SysClk_PeriphGetFrequency(I2C_CLK_DIV_TYPE, I2C_CLK_DIV_NUM));
    if ((dataRate > I2C_DESIRED_DATA_RATE_HZ) || (dataRate == 0U))
    {
        /* Can not reach desired data rate */
        CY_ASSERT(0U);
    }

    /* Enable I2C to operate */
    Cy_SCB_I2C_Enable(SCB3);

    /* Enable global interrupts */
    __enable_irq();



    for (;;)
    {
    	/* Wait 100 ms until operation completion */
    	uint32_t timeout = 100UL;
    	/* Send Start condition, address and receive ACK/NACK response from slave */
    	uint32_t status = Cy_SCB_I2C_MasterSendStart(SCB3, 0x48U, CY_SCB_I2C_WRITE_XFER, timeout, &i2cContext);

    	if (CY_SCB_I2C_SUCCESS == status)
    	{
    	    /* Write data into the slave */

    	    status = Cy_SCB_I2C_MasterWriteByte(SCB3, 0xAA, 1000, &i2cContext);

    	}
    	/* Check status of transaction */
    	if (status == CY_SCB_I2C_MASTER_MANUAL_ADDR_NAK)
    	{
    	    /* Send Stop condition on the bus */
    	    status = Cy_SCB_I2C_MasterSendStop(SCB3, timeout, &i2cContext);
    	    if (status == CY_SCB_I2C_SUCCESS)
    	    {
    	        /* Data has been written into the slave */
    	    }
    	}
    	else
    	{
    	    /* Other statuses do not require any actions */
    	}
    }
}

/* [] END OF FILE */

 

 

Here is the output of the above code on Logic Analyser.

PandaS_0-1653202318904.png

Here is the Pinout for the Pins used 6_0 and 6_1:

PandaS_1-1653205417343.png

Remark: Please ensure that the Pins and SCB block used in your application are only for I2C purpose and are not overlapping by any other function.

Thanks and Regards

Sobhit

 

0 Likes