Blocking I2C driver

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Blocking I2C driver

Jump to solution
2,164 Views
martindusek
Contributor V

Hi,

is there a simple blocking I2C driver example for Kinetis K22? I need simple functions:

void IicInit( void) // init i2c baud rate

void IicStart( void) // generate start condition, wait for bus busy

void IicWrite(byte Data) // write data byte, wait for transfer complete

void IicStop( void) // generate stop condition, wait for bus idle

Thanks

Martin

Labels (1)
0 Kudos
1 Solution
1,599 Views
danielchen
NXP TechSupport
NXP TechSupport

Hi Martin:

There is an example shows how to use i2c driver as master to do board to board transfer.

    I2C_MasterGetDefaultConfig(&masterConfig);
    masterConfig.baudRate_Bps = I2C_BAUDRATE;

    sourceClock = I2C_MASTER_CLK_FREQ;

    I2C_MasterInit(EXAMPLE_I2C_MASTER_BASEADDR, &masterConfig, sourceClock);

    memset(&masterXfer, 0, sizeof(masterXfer));

    /* subAddress = 0x01, data = g_master_txBuff - write to slave.
      start + slaveaddress(w) + subAddress + length of data buffer + data buffer + stop*/
    uint8_t deviceAddress = 0x01U;
    masterXfer.slaveAddress = I2C_MASTER_SLAVE_ADDR_7BIT;
    masterXfer.direction = kI2C_Write;
    masterXfer.subaddress = (uint32_t)deviceAddress;
    masterXfer.subaddressSize = 1;
    masterXfer.data = g_master_txBuff;
    masterXfer.dataSize = I2C_DATA_LENGTH;
    masterXfer.flags = kI2C_TransferDefaultFlag;

    I2C_MasterTransferBlocking(EXAMPLE_I2C_MASTER_BASEADDR, &masterXfer);

Please refer to the below demo for more details

SDK_2.4.0_FRDM-K22F\boards\frdmk22f\driver_examples\i2c\polling_b2b_transfer

Regards

Daniel

View solution in original post

5 Replies
1,600 Views
danielchen
NXP TechSupport
NXP TechSupport

Hi Martin:

There is an example shows how to use i2c driver as master to do board to board transfer.

    I2C_MasterGetDefaultConfig(&masterConfig);
    masterConfig.baudRate_Bps = I2C_BAUDRATE;

    sourceClock = I2C_MASTER_CLK_FREQ;

    I2C_MasterInit(EXAMPLE_I2C_MASTER_BASEADDR, &masterConfig, sourceClock);

    memset(&masterXfer, 0, sizeof(masterXfer));

    /* subAddress = 0x01, data = g_master_txBuff - write to slave.
      start + slaveaddress(w) + subAddress + length of data buffer + data buffer + stop*/
    uint8_t deviceAddress = 0x01U;
    masterXfer.slaveAddress = I2C_MASTER_SLAVE_ADDR_7BIT;
    masterXfer.direction = kI2C_Write;
    masterXfer.subaddress = (uint32_t)deviceAddress;
    masterXfer.subaddressSize = 1;
    masterXfer.data = g_master_txBuff;
    masterXfer.dataSize = I2C_DATA_LENGTH;
    masterXfer.flags = kI2C_TransferDefaultFlag;

    I2C_MasterTransferBlocking(EXAMPLE_I2C_MASTER_BASEADDR, &masterXfer);

Please refer to the below demo for more details

SDK_2.4.0_FRDM-K22F\boards\frdmk22f\driver_examples\i2c\polling_b2b_transfer

Regards

Daniel

1,599 Views
martindusek
Contributor V

I tried these functions, but my app freezes on some while always:

void IicInit( void)
{
IicPinInit(); // initialize mux and enable pullups on SDA and SCL
CLOCK_EnableClock(kCLOCK_I2c0);
I2C0->F = ((IIC_MULT << I2C_F_MULT_SHIFT) | IIC_ICR);
}

void IicStart( void)
{

I2C0->C1 |= (I2C_C1_IICEN_MASK | I2C_C1_MST_MASK | I2C_C1_TX_MASK);
while(!(I2C0->S & I2C_S_BUSY_MASK));
}

int IicWrite(byte Data)
{
I2C0->D = Data;
while(!(I2C0->S & I2C_S_TCF_MASK));
}

void IicStop( void)
{
I2C0->C1 = 0;
while(I2C0->S & I2C_S_BUSY_MASK);
}

Please help me fix thhese functions.

0 Kudos
1,599 Views
mjbcswitzerland
Specialist V

Hi Martin

- Make sure that the status registers being used are correctly defined as "volatile" registers.
- See Appendix A of the following document for some information of the I2C state during transmission/reception: http://www.utasker.com/docs/uTasker/uTasker_I2C.pdf The I2C controller in the KL25 (shown there) is the same as in the K22.
- You can set the start condition and write the address "at the same time" (rather than waiting)
- The I2C interrupt flag (even when not using interrupts) is also useful for monitoring the state (it needs to be cleared by writing '1' to it though)
- It is best to check the busy state "before" sending the start condition
- You note that the pins have pull-ups defined but make sure that you have also set them to "open-drain" mode to otherwise it will not be able to work
- Blocking mode is low performance, high CPU overhead for initial tests so interrupt and DMA driven methods are recommended for real product developments
- It is useful to log the status register values 'seen' by the code as it works through the procedure to get to know the I2C operation (which is not necessarily documented in adequate detail in the user's manual). This tends to be better than monitoring the status register with the debugger since reads can sometimes clear flags (of Fifos)

Regards

Mark


uTasker developer and supporter (+5'000 hours experience on +60 Kinetis derivatives in +80 product developments)
Kinetis: http://www.utasker.com/kinetis.html

0 Kudos
1,599 Views
martindusek
Contributor V

Hi Mark,

thanks for the points. I can confirm, that I have open drain enable for SDA and SCL pin. I use standard MK22 header file from Kinetis SDK, I hope they declare all registers volatile (they are decorated with __IO).

I monitor I2C status register and I can see busy bit set although bus is idle (3V3 measured on both SDA and SCL) or I can see SRW bit set although I don't use slave mode at all.

I'm trying to replace my old software I2C driver (I was manually driving/reading SDA and SCL using GPIO module) which worked well. Implementing simple blocking I2 driver using peripheral is really pain...

I know blocking peripheral driver is not the best solution, but I can live with that. I don't transfer a lot of data on I2C frequently.

0 Kudos
1,599 Views
mjbcswitzerland
Specialist V

Martin

I have attached the low level I2C driver from the uTasker project which may give you some ideas. It has been used on > 60 different Kinetis parts (usable as master/slave on single and double-buffered parts) since 2012 so ensures full part compatibility and reliability. Note that it also includes dead-lock recovery (when the I2C slave is holding the bus at reset).

In your case you may however find it easier to simply bit-bang the GPIOs as you have done in the past as long as you are sure you don't need improved performance in the future.

Regards

Mark

http://www.utasker.com/docs/uTasker/uTasker_I2C.pdf

uTasker - for more performance and faster, cheaper product development

0 Kudos