I have this function defined for writing a byte to either the LCD 1602 (using the PCF8574 I/O expander), or the SHT21 humidity sensor. In both cases, it seems like after I write the slave address, I should start transmitting data. The only issue is, is that the microcontroller gets stuck in an infinite loop, as the interrupt flag IICIF does not set.
Below is my code, using the KL25Z controller from Freescale:
int i2c_write_byte(unsigned char addr, unsigned char data) { int retry = 1000; while (I2C1->S & 0x20) { // Wait until bus is not busy (busy: D5 = 1) if (-retry <= 0) { return ERR_BUS_BUSY; } delayUs(100); } // Send start I2C1->C1 |= 0x10; // Set TX (D4) to 1 (transmit) I2C1->C1 |= 0x20; // Set MST (D5) to 1 (master mode) // Send slave address and write flag I2C1->D = addr; // Bit shift leaves R/W = 0, so master will write next byte while(!(I2C1->S & 0x02)); // Wait for TX to complete (i.e. till IICIF = 0) I2C1->S |= 0x02; // clear IICIF if (I2C1->S & 0x10) { // If arbitration is lost (i.e. D4, ARBL = 1) I2C1->S |= 0x10; // clear IICIF return ERR_ARB_LOST; } if (I2C1->S & 0x01) { // Slave NACK'ed (i.e. D0, RXAK = 1) return ERR_NO_ACK; } // Send data I2C1->D = data; while(!(I2C1->S & 0x02)); // Wait for TX to complete (i.e. till IICIF = 0) I2C1->S |= 0x02; // clear IICIF if (I2C1->S & 0x01) { // Slave NACK'ed (i.e. D0, RXAK = 1) return ERR_NO_ACK; } // Stop I2C1->C1 &= ~0x30; // Unset MST (D5) and TX (D4) return ERR_NONE; }
It gets stuck at
while(!(I2C1->S & 0x02)); // Wait for TX to complete (i.e. till IICIF = 0)
And I can't understand why. From the KL25Z datasheet, IICIF sets when there is a one-byte transfer, match of slave address, arbitration lost, etc. How would I be able to tell that my data isn't being transmitted to the slave (despite previously ACK'ing the slave address)?
For the slave devices, I concluded this from their datasheets:
https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf (page 8)
https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT21_Datasheet.pdf (page 8).
As an example, i2c_write_byte(I2C_ADR_W, 0xFE) for soft-resetting the SHT21 gets stuck at that line. I am using pins C10 and C11 on FRDM KL25Z (clock enabled using SCGC5, PCR = ALT2 | PS | PE)
I would be grateful for any help that you can offer me.
Thank you.
This has nothing to do with Keil or ARM - you need to ask NXP about the operational details of their I2C implementation!
https://community.arm.com/developer/tools-software/tools/f/keil-forum/43684/lpc2148-timer0-not-working-as-expected/158950#158950