cancel
Showing results for 
Search instead for 
Did you mean: 

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

RMoli.3
Associate III

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?

1 ACCEPTED SOLUTION

Accepted Solutions
RMoli.3
Associate III

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);
}

View solution in original post

6 REPLIES 6
S.Ma
Principal

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
Chief III

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".
Foued_KH
ST Employee

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.

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
Up vote any posts that you find helpful, it shows what's working..

@AScha.3​  Thank you for the clarification. I was misinterpreting the stop+start as the clock stretching. This means that what I am probably seing is the TX of a message that for some reason i failing and then a second message is started to be TX. I will further troubleshoot this issue

RMoli.3
Associate III

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);
}