The I2CxCNT register is used to specify the length in bytes of a complete message in an I2C data transaction. The value of the I2CxCNT register will be decremented in hardware every time a byte of data has been transmitted or received by the module, until it has decremented to zero. Once the I2CxCNT register decrements to zero, the Byte Count Interrupt Flag (CNTIF) bit will be set, signifying the end of that message and data transfer will halt until the I2CxCNT register has been written to again. This feature is unique to the stand-alone I2C module and can be used to send variable length messages with minimal software intervention.
The example below demonstrates how the I2C module can be used to transmit ‘N’ bytes of data using the Data Byte Counter (I2CxCNT) register. In this code snippet, the value used for the variable ‘len’ would be written to the I2CxCNT register and will decrement every time data is written to the slave device. The same principal can be applied to read ‘N’ bytes of data as the I2CxCNT register should be used for both receiving and transmitting data on the I2C bus.
void WriteNBytesRegister(uint8_t address, uint8_t reg, void* data, uint8_t len)
{
uint8_t *dataPointer = data;
I2CxADB1 = (uint8_t)(address << 1); // Load address with write = 0
I2CxTXB = reg; // Load beginning slave register address
I2CxCNT = len; // Load with size of array to write
I2CxCON0bits.S = 1; // Set Start to get things going
while(I2CxCNT) // While count is true
{
while(!I2CxSTAT1bits.TXBE); // Wait until buffer is empty before load
I2CxTXB = *dataPointer++; // Load next byte to transmit,
}
// Hardware decrements I2CxCNT
wait4Stop(); // Wait for hardware to issue Stop
}