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

cross mob

PSoC™ 6: I2C slave clock stretching - KBA237815

PSoC™ 6: I2C slave clock stretching - KBA237815

Infineon_Team
Employee
Employee
50 replies posted 25 likes received 25 replies posted

1 Introduction


When a slave device is not yet ready to process data, it may drive a ‘0’ on the SCL line to hold it down. Due to the implementation of the I/O signal interface, the SCL line value will be ‘0’, independent of the values that any other master or slave may be driving on the SCL line. This is known as clock stretching, and it is the only situation where a slave drives the SCL line.

Infineon_Team_0-1692772718020.pngInfineon_Team_1-1692772728647.png

Figure 1 Clock stretching

The master device monitors and detects the SCL line when it cannot generate a positive clock pulse (‘1’) on the SCL line. It then reacts by delaying the generation of a positive edge on the SCL line, effectively synchronizing with the slave device that is stretching the clock. The I2C clock stretching feature is available in the PSoC™ 6 Serial Communication Block (SCB).

By default, PSoC™ 6 I2C slave clock stretching doesn't occur on data bytes (except when the internal FIFO is full), only between the w/r bit and the ACK of "address+r/w" bytes, and there is no config parameter to turn OFF in GUI.

FIFO mode: In this mode, the RX data is stored in the RX FIFO, and the TX data is loaded from the TX FIFO. Depending on the S_NOT_READY_DATA_NACK configuration, clock stretching or NACK occurs when the RX FIFO is full.

S_NOT_READ_ADDR_NACK and S_NOT_READY_DATA_NACK are two register bits used to disable clock stretching when the RX FIFO is full. For more details, refer to the S_NOT_READY_DATA_NACK and S_NOT_READY_ADDR_NACK registers (see Figure 2) in PSoC_62_Register_Technical_Reference_Manual.

Infineon_Team_2-1692772791732.png

Figure 2 S_NOT_READY_DATA_NACK and S_NOT_READY_ADDR_NACK registers

1.1 Avoiding clock stretching in a project


To avoid clock stretching in the project, set the register value to '1’.

  1. First, run the project in debug mode and set a breakpoint at (init) initialization.
  2. Click on the Window option in the toolbar and navigate to the Show view > Peripherals option.
  3. In the Peripherals window, select the SCB that you are using in the project.

The registers are visible in the memory section as shown in Figure 3.

Infineon_Team_3-1692772836105.png

Figure 3 Registers

By default, the S_NOT_READY_ADDR_NACK register is set to ‘1’, but after the step over from the breakpoint (initializing the I2C macro), the register value is set to ‘0’, as shown in Figure 4. This may cause clock stretching in the project.

In a few cases, this clock stretching delay is not acceptable by design. In such an issue, use the following code to turn OFF clock stretching between the w/r bit and the ACK of "address+r/w" bytes.

Cy_SCB_I2C_Init(CYBSP_I2C_HW, &CYBSP_I2C_config, &CYBSP_I2C_context);
/* When '1', a received (matching) slave address is immediately ACK'd when the receiver FIFO is not full” */
SCB_I2C_CTRL(CYBSP_I2C_HW) |= _VAL2FLD(SCB_I2C_CTRL_S_READY_ADDR_ACK, 1UL);
Cy_SCB_I2C_Enable(CYBSP_I2C_HW);

Infineon_Team_4-1692772904268.png

Figure 4 Register value: set to 0

Add the following code after initializing and enabling the I2C slave component to set S_NOT_READY_DATA_NACK and S_NOT_READY_ADDR_NACK registers to ‘1’.

SCB_I2C_CTRL(sI2C_HW)|=(SCB_I2C_CTRL_S_NOT_READY_ADDR_NACK_Msk | SCB_I2C_CTRL_S_NOT_READY_DATA_NACK_Msk);


Note: A long delay introduced in the ISR will create a clock stretch scenario, but this clock stretch cannot be handled by the driver as the ISR is interrupt-driven.

Do the following to avoid the clock stretching in all cases:

  1. Set the I2C interrupt priority to the highest.
  2. Disable the I2C block every time you go to a critical section (interrupts are disabled).

Set the register bits as mentioned earlier.

1.2 Options to disable clock stretching


Option 1
:

In a firmware, identify the critical sections, disable the I2C, and later enable it. For example:

Cy_SCB_I2C_Disable()
// Disable the interrupts
// CRITICAL SECTION
// Enable the interrupts
Cy_SCB_I2C_SlaveConfigReadBuf()
Cy_SCB_I2C_SlaveConfigWriteBuf()
Cy_SCB_I2C_Enable()

 

Option 2:

When the I2C block is disabled, it does the following:

  • The slave will NACK, instead of stretching the clock
  • On read frames, it will drive HIGH, instead of stretching the clock

The block behaves as described earlier if you disable the I2C block during an I2C transaction.

Infineon provides a few wrappers to enter the critical section; for example, search for:

Cy_SysLib_EnterCriticalSection()

If you use FreeRTOS, it is called:

taskENTER_CRITICAL()

taskENTER_CRITICAL_FROM_ISR()

Note that you can have your own implementation of critical sections where you can manually disable the interrupts.

References:

0 Likes
167 Views