Kinetis I2C and SDK

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

Kinetis I2C and SDK

Jump to solution
174 Views
JBM
Contributor V

I am working on a new project which uses a K22FN512VMP12 and another NXP part (which I can't mention due to NDA) as an I2C slave.  I have used this other NXP part for years and have a lot of experience with it.

I am using MCUXpresso v11.10.0 and SDK updated this week, FreeRTOS and custom hardware.

The other part requires a command shortly after startup to keep it from booting (so that the firmware can be updated).  The general method to do this is to power up the part, deassert the reset and then send the command every five milliseconds or sow until the part responds.  The part only listens for this command for about 70 ms after startup.  It will typically not response to the first 5-10 commands as it has a short (<20 ms) boot time.

Sending this command requires a Start, transmission of I2C address and three data bytes, a restart, address and read of four bytes.

The problem I'm having is trying to get the part talking with the I2C_RTOS_Transfer (and associated functions).  The I2C_RTOS_Transfer function reports no slave Ack.  I can see the correct address on the bus using an oscilloscope.  This leads me to think that the SDA line might not be seeing the Ack - even though it looks OK on the scope.  I have used these commands to talk to other parts no problems (different bus).  The bus has 1.8K pullups on it and I have verified that the SDA and SCL lines are pulled high.  I have also confirmed that the slave is powered up and the reset is deasserted.

In my debugging, I enabled the Open Drain in the Pins Tool and when I do this, I get an assertion in the SDK function I2C_MasterTransferRunStateMachine() which is in fsl_i2c.c.  The exception is in the last part of the function here:

        default:
            /* Add this to fix MISRA C2012 rule 16.4 issue: Empty default. */
            assert(false);
            break;
    }

    return result;
}

When I get the assertion, I look at the handle passed to the I2C_MasterTransferRunStateMachine() function and everything is zero (as if written to using memset).  Maybe it's entering this function on a spurious interrupt?

If I disable the open drain on the I2C pins, I don't get the exception, but it doesn't talk either.  I'm not saying that it's an open drain issue.  I have the open drain enabled on the other bus it works fine.

I have tried using the I2C_RTOS_Transfer function transmitting the three bytes in the sub address.  I have also written a function that uses two I2C_RTOS_Transfer calls like this:

bool i2c0_read_write_buffers(int speed, uint8_t slave_address,
		uint8_t* write_buffer, int write_buffer_size,	uint8_t* read_buffer, int read_buffer_size)
{
	i2c_master_transfer_t master_transfer =
	{
		.slaveAddress   = slave_address,
		.direction      = kI2C_Write,
		.subaddress     = 0x0,
		.subaddressSize = 0x0,
		.data           = write_buffer,
		.dataSize       = write_buffer_size,
		.flags          = kI2C_TransferNoStopFlag,
	};

	status_t status = I2C_RTOS_Transfer(&master_handle, &master_transfer);

	if (kStatus_Success == status)
	{
		master_transfer.slaveAddress 	= slave_address;
		master_transfer.direction 	= kI2C_Read;
		master_transfer.subaddress	= 0x0;
		master_transfer.subaddressSize	= 0x0;
		master_transfer.data 		= read_buffer;
		master_transfer.dataSize	= read_buffer_size;
		master_transfer.flags		= kI2C_TransferRepeatedStartFlag;

		status = I2C_RTOS_Transfer(&master_handle, &master_transfer);

		if (kStatus_Success == status) return true;
	}
	return false;
}

This does the same thing as using a single I2C_RTOS_Transfer() call and the sub addresses.

I was able to port older non-interrupt driven I2C code that does correctly talk to this part and prevent the boot.  This older code does enable the open drain in the SDA and SCL pins.  The code blocks in a couple of places and is considerably longer than the SDK functions as it is entirely register driven and doesn't use interrupts which is why I don't want to use it. It does work to talk to the part though which tells me the hardware works.

I don't know if any of this makes sense.  I'm kind of at a loss.  I've used the FreeRTOS commands for years without these kinds of issues.  I've been looking at this for too long and don't know where to go from here.

0 Kudos
Reply
1 Solution
123 Views
JBM
Contributor V

It looks like the problem was two issues.  One the Pins tool was not setting the open drain on the I2C pins correctly.  Sometimes it updated the code, sometimes it didn't.  I found a couple of old commits where the .mex file said open drain and the pin_mux.c file has open drain disabled.  It worked find on I2C1 for some reason. 

The other problem was in switching between the RTOS versions of I2C and my register driven version was causing the crash.  Apparently the RTOS versions of I2C do not disable the interrupt (by calling DisableIRQ(I2C0_IRQn)).  This left the interrupt enabled and when my register driven I2C version was called, it caused an unexpected interrupt with the handle and transfer zeroed which caused the default case execution and the subsequenct assert.  Disabling the IRQ after right before Deinit fixed the issue.

View solution in original post

0 Kudos
Reply
1 Reply
124 Views
JBM
Contributor V

It looks like the problem was two issues.  One the Pins tool was not setting the open drain on the I2C pins correctly.  Sometimes it updated the code, sometimes it didn't.  I found a couple of old commits where the .mex file said open drain and the pin_mux.c file has open drain disabled.  It worked find on I2C1 for some reason. 

The other problem was in switching between the RTOS versions of I2C and my register driven version was causing the crash.  Apparently the RTOS versions of I2C do not disable the interrupt (by calling DisableIRQ(I2C0_IRQn)).  This left the interrupt enabled and when my register driven I2C version was called, it caused an unexpected interrupt with the handle and transfer zeroed which caused the default case execution and the subsequenct assert.  Disabling the IRQ after right before Deinit fixed the issue.

0 Kudos
Reply