I2C works on Teensy 4.0, but not on same chip's EVB. SCL differs.

Status
Not open for further replies.

kingforger

Active member
Let me know if I should be on NXP's forum rather than Teensy's...

I can use the Teensy 4.0 to talk with my Si514 and it'll acknowledge (ACK) back. Furthermore, I can control it perfectly. However, the evaluation board (EVB) for the same chip does not result in ACK when using the EVB's I2C drivers.

Successful ACK from the Si514 being driven by the Teensy 4.0. Slave address 0x55.
Teensy successful ACK PNG.png

No ACK from the Si514 being driven by the EVB's included drivers. It looks identical except for no ACK and the SCL line is not high as long. In other words, the SCL's duty cycle is shorter. It's about 37%. It seems to *start later*, not end earlier. I assume we want 50% duty cycle like in the teensy 4.0. This may be the problem? If it is I have no idea how to change/fix it. Does anyone?
RT1020EVB NACK PNG.png

If you overlay the two pictures, it's obvious that the only difference is the SCL clock width while high (duty cycle), and of course the ACK bit difference on the end. Could the SCL duty cycle cause this problem? Does anyone know how to change this in the included EVB driver? I've been through a lot of settings in it but can't seem to find a way to modify the clock itself.

Why would NXP's driver put out an asymmetrical SCL???? That seems so strange!

There is this struct in the EVB driver, but none seem to affect SCL's duty cycle. I've played with various values of many of these to no avail.

typedef struct _lpi2c_master_config
{
bool enableMaster; /*!< Whether to enable master mode. */
bool enableDoze; /*!< Whether master is enabled in doze mode. */
bool debugEnable; /*!< Enable transfers to continue when halted in debug mode. */
bool ignoreAck; /*!< Whether to ignore ACK/NACK. */
lpi2c_master_pin_config_t pinConfig; /*!< The pin configuration option. */
uint32_t baudRate_Hz; /*!< Desired baud rate in Hertz. */
uint32_t busIdleTimeout_ns; /*!< Bus idle timeout in nanoseconds. Set to 0 to disable. */
uint32_t pinLowTimeout_ns; /*!< Pin low timeout in nanoseconds. Set to 0 to disable. */
uint8_t sdaGlitchFilterWidth_ns; /*!< Width in nanoseconds of glitch filter on SDA pin. Set to 0 to disable. */
uint8_t sclGlitchFilterWidth_ns; /*!< Width in nanoseconds of glitch filter on SCL pin. Set to 0 to disable. */
struct
{
bool enable; /*!< Enable host request. */
lpi2c_host_request_source_t source; /*!< Host request source. */
lpi2c_host_request_polarity_t polarity; /*!< Host request pin polarity. */
} hostRequest; /*!< Host request options. */
} lpi2c_master_config_t;

This struct and two other parameters are passed to a function to start the transfer by sending out the address (0x55 in this case).

My eyes were also drawn to these two functions that set up clocks, but I can't find any way to modify SCL's duty cycle inside them.

/*Clock setting for LPI2C*/
CLOCK_SetMux(kCLOCK_Lpi2cMux, LPI2C_CLOCK_SOURCE_SELECT);
CLOCK_SetDiv(kCLOCK_Lpi2cDiv, LPI2C_CLOCK_SOURCE_DIVIDER);
 
Last edited:
.... I have no idea how to change/fix it. Does anyone?

The info you seek is in section 46.4.1.13 of the reference manual (Rev 1, 12/2018) starting on page 2902.


Why would NXP's driver put out an asymmetrical SCL????

Whoever wrote their driver probably didn't put much effort into the timing details, as I did for many hours of trial & error with my oscilloscope when I wrote Teensy 4.0's Wire lib.
 
If anyone's wondering how to change SCL duty cycle in the EVB drivers, I've got a way thanks to Paul's clue. In fsl_lpi2c.c:

Change
value |= LPI2C_MCCR0_CLKLO(2 * bestClkHi) | LPI2C_MCCR0_SETHOLD(bestClkHi) | LPI2C_MCCR0_DATAVD(bestClkHi / 2);
to
value |= LPI2C_MCCR0_CLKLO(1 * bestClkHi) | LPI2C_MCCR0_SETHOLD(bestClkHi) | LPI2C_MCCR0_DATAVD(bestClkHi / 2);

Add
bestClkHi = bestClkHi * 3 / 2;
just above the line
value = LPI2C_MCCR0_CLKHI(bestClkHi);

They purposefully set the low period to be twice the length of the high period! Their comment was "Assume CLKLO = 2*CLKHI". I'm still not sure why they do that, but they did it on purpose. Perhaps it's to allow more time slack for certain slaves to respond? I'm not sure.

The second thing I did isn't strictly good code, ideally I'd change the function that sets bestClkHi. I also don't know if this works for anything but standard 100kHz speed or not, though I think it will. But I get about 50.5% duty cycle now! You can see in the picture below.

RT1020EVB duty cycle fix.png

I'm still not getting a ACK at the end from my slave device despite the fact that my pulse train looks practically identical now... I'll have to continue thinking. I have pull-up resistors on both. I cut the SCL/SDA traces to the other I2C device that shares the lines on the EVB... I might have to investigate SETHOLD or DATAVD.
 
Last edited:
Status
Not open for further replies.
Back
Top