I can use the Teensy 4.0 (RT1062) to talk with my Si514 and it'll acknowledge (ACK) back. Furthermore, I can control it perfectly. However, NXP's RT1020 evaluation board (EVB) 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.
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?
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. */
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. */
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*/
But then why does SCL stay low forever? On my first picture where it is working, SCL is released and goes back up high. Why does the RT1020 default driver, after sending the address bit, not release SCL?
Basically, I can never get the demo driver to send anything after the address bit. I can only ever get it to send the address bit. I'd love to figure out how to just write any more data.
The SCL keeping low is because the SDA keeping high. The I2C stop condition is SDA rising edge when SCL high. In the first photo, SDA jump low after ack bit. Comparing with RT1060, is there any difference in master status register?
So I found info in section 184.108.40.206 of the reference manual (Rev 1, 12/2018) starting on page 2902. Here's what I did to change the SCL duty cycle.
value |= LPI2C_MCCR0_CLKLO(2 * bestClkHi) | LPI2C_MCCR0_SETHOLD(bestClkHi) | LPI2C_MCCR0_DATAVD(bestClkHi / 2);
value |= LPI2C_MCCR0_CLKLO(1 * bestClkHi) | LPI2C_MCCR0_SETHOLD(bestClkHi) | LPI2C_MCCR0_DATAVD(bestClkHi / 2);
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.
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 between this and the Teensy board... 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... anyone have any clues?