Skip to main content
RMoli.3
Associate III
March 17, 2023
Solved

How to fix HAL for STM32F767 I2C master not suporting clock streching from a I2C slave?

  • March 17, 2023
  • 4 replies
  • 3039 views

I am currently using a TSC2007 to detect touchs on a screen.

When working in blocking mode this is correctly working as the TSC2007 correctly streches the clock and the HAL correctly waits for the data to be ready

When working with interrupts the HAL fails to wait as a NACK and STOP interrupt is triggered which cancels further transmissions of bytes.

I can avoid the TSC2007 doing the streching by manually waiting a specific amount of time. The probem is that depending on the waiting time the read value is incorrect.

The current solution I am using is calling my TSC2007 driver in blocking mode in a low level priority freertos task

Correct clock streching and read when using HAL_I2C_Master_Receive

0693W00000aJCivQAG.png 

Read cancelled by HAL when using HAL_I2C_Master_Receive_IT

0693W00000aJCj5QAG.pngRead correctly done with HAL_I2C_Master_Receive_IT(but incorrect values reported by device) if I wait for an amount of time that requieres

0693W00000aJCjUQAW.png 

Any idea how to support clock streching in master mode with Interruptions?

This topic has been closed for replies.
Best answer by RMoli.3

After properly understanding the issue, the casuse was incorrect transmision of the message when using the HAL_I2C_Master_Receive_IT/HAL_I2C_Master_Transmit_IT

With blocking mode this was working

void Task_TSC2007Driver(void)
{
 TSC2007_CommandByte driver_command = { 0 };
 
 driver_command.cmd_bits.tc_function = TC_FUNCTION_MEASURE_Y_POSITION;
 driver_command.cmd_bits.power_config = POWER_CONFIG_ADC_ON_IRQ_DISABLED;
 driver_command.cmd_bits.adc_config = ADC_CONFIG_12_BITS_RESOLUTION;
 HAL_I2C_Master_Transmit(tsc2007_i2c_handle, TSC2007_I2C_ADDR, &driver_command.cmd_byte, 1,100);
 HAL_I2C_Master_Receive(tsc2007_i2c_handle, TSC2007_I2C_ADDR, &y_buffer[0], 2,100);
}

Howerver with IT based approach it is necessary to ensure that the pointer were the data is stored remains unmodified during all the transmission as the HAL driver does not make a copy of it.

In my case I have a variable that creates the data to be transmitted (TSC2007_CommandByte driver_command). Ensuring this variable maintains its value after calling HAL_I2C_Master_Transmit_IT ensures the tranmission is correct. Thus this will work erratically:

static void TSC2007_GetX(void)
{
 TSC2007_CommandByte driver_command = { 0 };
 fsm_tsc2007_driver_it = TSC_IT_GET_X;
 driver_command.cmd_bits.tc_function = TC_FUNCTION_MEASURE_X_POSITION;
 driver_command.cmd_bits.power_config = POWER_CONFIG_ADC_ON_IRQ_DISABLED;
 driver_command.cmd_bits.adc_config = ADC_CONFIG_12_BITS_RESOLUTION;
 HAL_I2C_Master_Transmit_IT(tsc2007_i2c_handle, TSC2007_I2C_ADDR, &driver_command.cmd_byte, 1);
}

And this will work properly:

TSC2007_CommandByte driver_command = { 0 };
static void TSC2007_GetX(void)
{
 fsm_tsc2007_driver_it = TSC_IT_GET_X;
 driver_command.cmd_bits.tc_function = TC_FUNCTION_MEASURE_X_POSITION;
 driver_command.cmd_bits.power_config = POWER_CONFIG_ADC_ON_IRQ_DISABLED;
 driver_command.cmd_bits.adc_config = ADC_CONFIG_12_BITS_RESOLUTION;
 HAL_I2C_Master_Transmit_IT(tsc2007_i2c_handle, TSC2007_I2C_ADDR, &driver_command.cmd_byte, 1);
}

4 replies

S.Ma
Principal
March 17, 2023

Where is the SCL clock stretching in the scope captures? SCL clock stretching means the yellow clock pusle should have missing pusles if master doesn't hold on. The "Stop/Start" bit makes a longer clock high period, it's normal. I'm puzzled.

AScha.3
Super User
March 17, 2023

you didnt show any clock stretching , as S.Ma said.

it would be like this : scl kept low by slave

0693W00000aJDqMQAW.png

"If you feel a post has answered your question, please click ""Accept as Solution""."
Tesla DeLorean
Guru
March 17, 2023

And to be honest, this clock-stretching concept where the slave drags on SCL wasn't even a thing when I was with PHILIPS/NXP (mid/late 1980's)

If one needs to deal with really abhorrent divergence from normal behaviour you can always bit-bang the bus, and monitor the SCL attaining the desired state.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Foued_KH
ST Employee
March 17, 2023

Hello @Community member​ ,

Please try to debug and check registers to see the received data .

Check the error flags set in the status register or catch the error via HAL_I2C_GetError.

If you are facing some erratic behavior on STM32F7, do not forget to check Errata sheet of the device. There are few points related to I2C interface. 

Foued

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
RMoli.3
RMoli.3AuthorBest answer
Associate III
March 20, 2023

After properly understanding the issue, the casuse was incorrect transmision of the message when using the HAL_I2C_Master_Receive_IT/HAL_I2C_Master_Transmit_IT

With blocking mode this was working

void Task_TSC2007Driver(void)
{
 TSC2007_CommandByte driver_command = { 0 };
 
 driver_command.cmd_bits.tc_function = TC_FUNCTION_MEASURE_Y_POSITION;
 driver_command.cmd_bits.power_config = POWER_CONFIG_ADC_ON_IRQ_DISABLED;
 driver_command.cmd_bits.adc_config = ADC_CONFIG_12_BITS_RESOLUTION;
 HAL_I2C_Master_Transmit(tsc2007_i2c_handle, TSC2007_I2C_ADDR, &driver_command.cmd_byte, 1,100);
 HAL_I2C_Master_Receive(tsc2007_i2c_handle, TSC2007_I2C_ADDR, &y_buffer[0], 2,100);
}

Howerver with IT based approach it is necessary to ensure that the pointer were the data is stored remains unmodified during all the transmission as the HAL driver does not make a copy of it.

In my case I have a variable that creates the data to be transmitted (TSC2007_CommandByte driver_command). Ensuring this variable maintains its value after calling HAL_I2C_Master_Transmit_IT ensures the tranmission is correct. Thus this will work erratically:

static void TSC2007_GetX(void)
{
 TSC2007_CommandByte driver_command = { 0 };
 fsm_tsc2007_driver_it = TSC_IT_GET_X;
 driver_command.cmd_bits.tc_function = TC_FUNCTION_MEASURE_X_POSITION;
 driver_command.cmd_bits.power_config = POWER_CONFIG_ADC_ON_IRQ_DISABLED;
 driver_command.cmd_bits.adc_config = ADC_CONFIG_12_BITS_RESOLUTION;
 HAL_I2C_Master_Transmit_IT(tsc2007_i2c_handle, TSC2007_I2C_ADDR, &driver_command.cmd_byte, 1);
}

And this will work properly:

TSC2007_CommandByte driver_command = { 0 };
static void TSC2007_GetX(void)
{
 fsm_tsc2007_driver_it = TSC_IT_GET_X;
 driver_command.cmd_bits.tc_function = TC_FUNCTION_MEASURE_X_POSITION;
 driver_command.cmd_bits.power_config = POWER_CONFIG_ADC_ON_IRQ_DISABLED;
 driver_command.cmd_bits.adc_config = ADC_CONFIG_12_BITS_RESOLUTION;
 HAL_I2C_Master_Transmit_IT(tsc2007_i2c_handle, TSC2007_I2C_ADDR, &driver_command.cmd_byte, 1);
}