Hi!
I'm developing a portable I2C library which should rely on common flags that can be found on devices from G2553 to I2041: I chose only TX, RX and NACK flags by now.
However, this question aims to gain a better understanding of the I2C operations regardless the chosen MCU. I read three or four user guides looking at the I2C registers and the master operations flow chart, but it's still not clear how and when should i poll-reset the flag.
This is the reference scheme (eUSCI I2C Mode, from SLAU335):
According to this scheme, I drew the following conclusions and wrote a test code. Please tell me if i'm wrong.
- When I set UCTR, the start sequence (along with the slave address) is transmitted. UCTXIFG becomes 1, meaning I can write data in UCBxTXBUF (tx flag polling)
- The slave can ACK/NACK the address byte if and only if something is written in UCBxTXBUF, so after writing my data I have to clear UCTXIFG, check UCNACKIFG, and eventually give a STOP or a START condition. Thus, an ACK/NACK requires something to be written in TXBUF immediately after the start condition.
- After the TXBUF writing, the UCTXIFG will be set ONLY when I'm supposed to decide if sending another byte or if issuing a START/STOP condition.
- The ACK/NACK after a data byte comes only if i do another TXBUF write or a START/STOP condition.
So, for sending multiple bytes i wrote this code, but works only with one data byte:
char I2C_Send(unsigned char Slave_Address, unsigned char ByteNum, unsigned char * TxArrayAddr ) { unsigned int txBuf_index=0; UCB0I2CSA = Slave_Address; // Address Assignment UCB0IFG &=~ (UCTXIFG + UCNACKIFG); // Flag Clear UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition //UCB0IFG &=~ UCTXIFG; // Azzero UCTXIFG (si alza solo dopo l'ack) while(!(UCB0IFG & UCTXIFG)); // While TXIFG = 0 while(txBuf_index < (ByteNum - 1)) { UCB0IFG &=~ UCTXIFG; // BO UCB0TXBUF = TxArrayAddr[txBuf_index++]; // Fill TxBuffer (slave can ACK/NACK) while(!(UCB0IFG & UCTXIFG)) // Mentre UCTXIFG è zero, { if(UCB0IFG & UCNACKIFG) // Se ricevo un NACK, esco. { UCB0CTL1 |= UCTXSTP; // Issue stop return 1; } } if(UCB0IFG & UCNACKIFG) // Se ricevo un NACK, esco. { UCB0CTL1 |= UCTXSTP; // Issue stop return 1; } // Se è uno (posso trasmettere anche il secondo byte) //UCB0IFG &=~ UCTXIFG; // Flag Clear } UCB0IFG &=~ UCTXIFG; // BO UCB0TXBUF = TxArrayAddr[txBuf_index++]; while(!(UCB0IFG & UCTXIFG)) // Mentre UCTXIFG è zero, { if(UCB0IFG & UCNACKIFG) // Se ricevo un NACK, esco. { UCB0CTL1 |= UCTXSTP; // Issue stop return 1; } } UCB0CTL1 |= UCTXSTP; return 0; }
What i'm missing? is something obviously wrong and i don't catch it? After two bytes i receive a nack but it ignores it.
Thank you in advance!