cancel
Showing results for 
Search instead for 
Did you mean: 

How to add delays between I2C bytes to support TI mct8329a / mct8316

BFox.1
Associate II

The TI motor drivers mct8329a and mct8316 require 100us delay between i2c data bytes. This can't include the acknowledge bit, but requires holding down the clock between transfers for the 100us. it is due to a bug in the TI chips that can't stretch clocks. Not doing this properly (according to TI) causes the chip control to freeze requiring a reset to recover.

I'm using an STM32F429/439 MCU and my firmware is utilizing the STM32F4xx HAL, specifically the stm32f4xx_hal_i2c files. I'm using host mode on the ST for the driver chip slave. I have added blocking delays (using a 1us timer) to achieve the 100us delays to HAL_I2C_Master_Transmit, I2C_MasterRequestWrite(), HAL_I2C_Master_Receive() and I2C_MasterRequestRead() functions. I've had to tweak some of the status register setting, particularly the I2C_CR1_ACK flag.

I've been successful getting the behavior I need for most of the transactions. The transmits all work well, where I'm having difficulty is with the first two bytes of a five byte read. The read transaction just doe the 7 bit address write and the five bytes of read from the slave. (Four bytes to the payroll and a CRC.) I've posted one scope image that captures the full read transaction. Note the first two bytes of read (just after the write of the 7 bit address) is where there is no clock stretching by the master. The is read is the result of a immediately preceding write of a three byte address (7 bit I2C address followed by 16 bit register address.)

I've confirmed that with the single place where I don't have the 100us delay between bytes does indeed freeze the motor driver chip.

I've attached my modified driver file and the original. I've tried a considerable number of ways to get that break between the two bytes, but to no avail. This is going through the last part of HAL_I2C_Master_Receive since it is a five byte read.

2 REPLIES 2
gregstm
Senior III

Not sure if this helps - but I recently implemented a one wire interface to the old Dallas Semi temperature sensors (DS18B20). It required precise microsecond timing. I don't use HAL, but used the following simple/efficient timing functions -


#define zero_usec_counter TIM6->CNT = 0
#define get_usec_counter ( TIM6->CNT )
#define delay_to_usec_count(x) while ( get_usec_counter < x )

eg.

one_wire_line_low;
zero_usec_counter;
delay_to_usec_count ( 960 );
one_wire_line_release;
zero_usec_counter;
delay_to_usec_count ( 70 );
out = one_wire_line_value;
delay_to_usec_count ( 480 );

TDK
Guru

There's no way to do this with the STM32F4 I2C peripheral. There is no delay between bytes 1 and 2 when receiving. EV1 kicks off two bytes of reception.

TDK_0-1747015550539.png

 

I see two possibilities:

  • Bit bang I2C.
  • Act as a slave in the same bus and stretch the clock yourself.
If you feel a post has answered your question, please click "Accept as Solution".