- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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);
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Here is the Pinout for the Pins used 6_0 and 6_1:
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, the pullup are external.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Here is the Pinout for the Pins used 6_0 and 6_1:
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