LPC812 i2c freezes

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

LPC812 i2c freezes

5,282 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by elef on Fri May 31 07:47:50 MST 2013
[FONT=Arial][SIZE=2]Hi,

How can i get the i2c not to freeze or hang the controller when nothing is plugged into the i2c port?
For example:
    I2C_MstInit(LPC_I2C, 29, CFG_MSTENA, 0x00);
    I2C_TimeoutInit(LPC_I2C,8);
    I2C_CheckIdle(LPC_I2C);

    while(1){
        I2C_MstSend( LPC_I2C, 0xB4, (uint8_t *)I2CMasterTXBuffer, 1 );
        execution hangs on the line above and never reaches here.
        do_other_stuff(); //never gets called
    }

I want to keep the controller running and doing other stuff until something is plugged into the i2c port.
Does anyone have any suggestions how i can modify lpc8xx_i2c.c that comes with lpcxpresso lib?

I have tried with and without enabling TIMEOUT_ENABLED in the [/SIZE][/FONT][FONT=Arial][SIZE=2][FONT=Arial][SIZE=2]lpc8xx_i2c.h [/SIZE][/FONT]header file.

FYI, you can also check i2ctest.c that comes with lpcxpresso, with nothing connected to the demo board, execution never goes past line 156.

Thanks.

[/SIZE][/FONT]
0 Kudos
Reply
16 Replies

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bob_walker on Tue Jun 09 17:16:21 MST 2015
The ROM implementation misses one important necessity, in my mind. That is the ability to have the send pointer point to a ROM location, e.g. send messages stored in ROM.
Because of the requirement for the Device Address to be the first element of the buffer, you would need to copy the rom data to buffer[1]---buffer[n] with DevAdr in buffer[0]. This is absurd.
There should be a separate "uint16_t device_address" as part of the I2C structure and the buffer should only reference r/w data, either in RAM or ROM.
Furthermore the driver could use a 7/10bit flag in order to know how to deal with the device address (1 or 2 bytes) as well
as a R/W flag to set/clear BIT0.

So my question is, can the driver be coerced into the following procedure:

1) Set a local variable with the device address
2) Issue an i2c_master_write with a size of 1 byte, send_ptr points to the variable (7bit adr) and NO stop bit
....ignoring NAKs for the sake of this example...
3) Issue a 2nd i2c_master_write with a size of the ROM or RAM data, send_ptr points the address in ROM or RAM of the data, and this time, the stop is enabled.

Has anyone tried this with the I2C ROM API?

0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by elef on Fri Jun 07 04:04:47 MST 2013
noahk, thank you, but i would disagree that a "bus failure" is outside "normal i2c operations"
Failures happen in real life and they shouldn't lock up a controller by default (it should be optional extra!)
For me (and i'm guessing most other logical thinking engineers), a function returning an error code makes much more sense instead of locking up the whole MCU.

Anyways, i managed to get the interrupt version of the ROM drivers working without freezing. The catch was to call the i2c_set_timeout() function AFTER the i2c_master_tx_rx_intr() function EVERY time. It wasn't sufficient to just set it once like i was at the beginning of my code! Maybe it's documented somewhere but i couldn't find it?!

I can now connect SCL and/or SDA to GND and it will not freeze the controller

Here is a sample from the modified code from the LPCopen i2c ROM example if anyone is interested:
isTxRxCompleted = false;
LPC_I2CD_API->i2c_master_tx_rx_intr(i2c_handle, &param, &result);
LPC_I2CD_API->i2c_set_timeout(i2c_handle, I2C_TIMEOUT_SETTING); //all i had to do was add this line!!!
while (!isTxRxCompleted) {
}//while
Calling i2c_set_timeout() before the tx_rx_intr() locks up the controller, it must be called AFTER.
So, is this a bug in the ROM or is it a deliberate "feature" hehehehe!
Either way, it's an easy work around, so i'm happy with this for what i need
It even returns the correct error code ERR_I2C_TIMEOUT
Excellent!!!
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by serge on Fri Jun 07 03:56:17 MST 2013
When using a timeout, which will be the best solution for you i think, don't forget that when SCL is tied low it can also mean that a device is using clock stretching. Especialy some slow I2C devices use this clock stretching. So make sure that your timeout is long enough in this case. Or make sure that all I2C devices on your bus are fast enough.
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by noahk on Thu Jun 06 10:59:26 MST 2013
Hi elef,

It seems to me that a prepackaged library for I2C is not going to serve your purposes. You are asking for a very specific type of implementation in a situation that is outside of normal I2C communications.

If you would use the I2C without the library you would find that it is possible to handle all types of I2C failures, including a short of SCL / SDA to ground. For example, the I2C has a timeout mechanism which creates an interrupt. That mechanism can signal your master logic to abort.

Either you can have the master busy poll the STAT register for both MST_PENDING and (SCL_TIMEOUT / EVENT_TIMEOUT), or you can have interrupt mode set up and have the ISR handle MST_PENDING and (SCL_TIMEOUT / EVENT_TIMEOUT). The timeouts handle both an SCL low scenario (also good for SMBUS), and handle communication dead scenarios, like the software controlling the I2C getting stuck.

To use the timeout, you would have to do something like this:
CFG |= TIMEOUTEN;
TIMEOUT = 0xFFFFFF; // (some large number)
while(!(STAT & EVENT_TIMEOUT)); // would busy wait for a timeout, unlikely that you would want this exactly.

If you were waiting for MST_PENDING and EVENT_TIMEOUT you could do this:
while(!(STAT & MST_PENDING) && !(STAT & EVENT_TIMEOUT));
if(STAT & EVENT_TIMEOUT) {
abort();
}

Event Timeout gets set when the bus is busy yet no changes on SDA or SCL have happened for timeout clocks.
SCL Timeout gets set when SCL is low for timeout clocks.

Neither timeout will happen if the bus is idle (a start / scl low until a stop would be considered non-idle and allow for timeouts).

Noah
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by elef on Wed Jun 05 23:50:37 MST 2013

Quote: Serge
Why would you remove any of the pullup resistors on the SDA and SCL lines?
Shorting the SCL line to GND means that another Master on the bus will start sending. Don't forget that I2C is a multimaster bus.
When there is no communication both lines should be at 3.3V.


In some applications it is desireable for the controller to lock up because of a bus error. However, as i mentioned earlier, in this particular application, it is a requirement that under no circumstances is a bus fault or another master on the i2c bus allows to "crash" or "lock up" this controller. For example, if the bus cable is accidentally cut and SCL shorts to GND, we CANNOT have the controller freeze. Currently it freezes. If anyone knows how to prevent this please let me know urgently! If I can't get this sorted in the next week or 2, we might be forced to use another device, which i really don't want to do because the LPC812 is great for this product (other than this i2c problem).
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by serge on Wed Jun 05 23:31:44 MST 2013
Why would you remove any of the pullup resistors on the SDA and SCL lines?
Shorting the SCL line to GND means that another Master on the bus will start sending. Don't forget that I2C is a multimaster bus.
When there is no communication both lines should be at 3.3V.
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by elef on Wed Jun 05 08:22:58 MST 2013
well i got the i2c ROM drivers working, using the LPCopen example as a base.
Much more reliable compared to the default LPCXpresso drivers, i can no longer freeze the controller by remove the SDA pullup resistor :)

However, if i remove the SCL pullup resistor or short SCL to GND, then the controller freezes again, waiting for SCL, until i return it back... I tried this using interrupt and the polled mode, but same thing

I tried setting LPC_I2CD_API->i2c_set_timeout() but it doesn't make any difference. Maybe the ROM drive doesn't use the timeouts (bit silly if you can set them using the ROM driver)? Do i need to check the timeout flags manually? One of the error codes is timeout, but i can't check for this if the send function never returns...
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by elef on Tue Jun 04 04:53:25 MST 2013
noahk, thanks resetting the MSTENA seems to do the trick, it brings the i2c block back to life!
And yes it is the pullup resistors on the SDA and SCL line i was referring to in my previous post, sorry for the confusion.

I was disconnecting then connecting the resistors and also an i2c slave to test different fault scenarios, such as cable/wiring faults that occur in the real world. In this particular application, i cannot have a faulty cable/resistor lockup/restart the microcontroller, so i need to cover all scenarios.

wells, thanks that looks exactly the type of demo code i want for i2c ROM, i'll give it a go when i have some spare time.
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wells on Mon Jun 03 14:16:10 MST 2013

Quote: wongss
Just wander if it is possible for nxp to provide some easy to use basic functions so that we quickly focus on applications be successful quickly.
Not sure if the expectation is reasonable.



There is one other option that may - or may not help. For the LPC8xx, I2C support exists in the ROM with a simpler API that is well-defined.
See http://docs.lpcware.com/lpc800um/RegisterMaps/i2capi/c-Howtoreadthischapter.html

The LPCOpen platform has a different I2C example that shows how to use the ROM API functions. You can look at the LPC812 I2C example to get an idea of how they work.
http://docs.lpcware.com/lpcopen/v1.03/
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by noahk on Sun Jun 02 10:33:24 MST 2013
Hi elef,

Are there pullups on SDA and SCL? The behavior you are seeing might indicate that a pullup is missing. If you don't have those pullups connected, and you still want to reset the master, you should be able to clear the MSTEN bit in CFG. That should put the I2C master in reset. Enabling MSTEN again should allow you to start again.

Noah
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by elef on Sun Jun 02 04:34:16 MST 2013
noahk,

Thanks i tried that, but if one of the resistors is removed, it still locks up and spins forever at:
    while (!(I2Cx->STAT & STAT_MSTPEND));

So i guess all i need to know now is what to put in the timeout function, to reset the i2c once the timeout occurs, so  it is allowed to transmit again. I tried MSTCTL = STOP; but it doesn't  help.

Any ideas?

Thanks.
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by noahk on Sat Jun 01 09:45:02 MST 2013
Hi elef,

I advise you at this point to stop using the library. The library seems to be causing more issues than it solves. I have written pseudo code at the bottom to demonstrate simple I2C writes with nack detection. Here is a quick summary of the I2C master functionality.

To perform any action on the I2C master:
1. Enable the master in the CFG register.
At this point the master is in the IDLE state, you can see this state by reading MSTPEND and then checking for the MSTSTATE which is equal to MSTIDLE.
2. Put an address with RWn bit in the master data register.
This does NOTHING to the I2C state. The data just sits there until you give the master a command
3. Write to the MSTCTRL the command you want to use.
This register should ONLY be written when MSTPENDING in the status is 1.
This register should not be read as it is a write 1 register meant for sending commands, |= and &~ type code would not be used.
To send a start (which is the only correct thing to do from IDLE), write START to MSTCTRL
4. Wait for MSTPENDING
Once MSTPENDING is high you can see the state of the master by reading the MSTSTATE.
MSTNACKADDR means that the address was nacked. You can send a start, or stop from this point. Put a new address in the data register if you want to send a start (the old address is gone by now).
MSTTX means that you sent an RWn bit of 0 and the master is now ready to write data. Put data in the data register and write CONTINUE in the MSTCTL register (or send a start or stop if desired)
MSTRX means that you sent an RWn bit of 1 and that there is data to read. Read the data from the data register and write CONTINUE in the MSTCTL register (or send a start or stop if desired).
MSTNACKTX means that you received a nack on TX data.  You can send a start, or stop from this point. Put a new address in the data register if you want to send a start (the old address is gone by now).
MSTARBLOSS means that you lost arbitration. You can write to CONTINUE to stay off the bus, or write to START to wait to send a new start. It will wait automatically until the bus is idle.
MSTSSERR means that it detected an error on the bus with an invalidly timed start or stop error.

For example, to do what you want to do: (send data and detect nacked address)

CFG = MSTEN;
MSTDATA = (address << 1) | 0; // slave address and RWn bit
MSTCTL = START; // start address cycle
while(!(MSTSTAT & MSTPENDING)); // wait for the master to be pending
if((MSTSTAT & MSTSTATE) == MSTNACKADDR) { // check nack on address
  MSTCTL = STOP;
  return 1; //device still nacking
}
MSTDATA = data_to_send; // writing data
MSTCTL = CONTINUE; // start data cycle
while(!(MSTSTAT & MSTPENDING)); // wait for the master to be pending
MSTCTL = STOP;
return 0;

Here is the same thing with some simple error checking:

CFG = MSTEN;
MSTDATA = (address << 1) | 0; // slave address and RWn bit
MSTCTL = START; // start address cycle
while(!(MSTSTAT & MSTPENDING)); // wait for the master to be pending
if((MSTSTAT & MSTSTATE) == MSTNACKADDR) { // check nack on address
  MSTCTL = STOP;
  return 1; //device still nacking
}
if((MSTSTAT & MSTSTATE) == MSTARBLOSS) { // check arbloss
  return -1; //got an error
}
if((MSTSTAT & MSTSTATE) == MSTSSERR) { // check sserr
  return -2; //got an error
}
if((MSTSTAT & MSTSTATE) != MSTTX) { // check fatal state
  return -3; //got a fatal error since the state is in the wrong place. shouldn't happen
}
MSTDATA = data_to_send; // writing data
MSTCTL = CONTINUE; // start data cycle
while(!(MSTSTAT & MSTPENDING)); // wait for the master to be pending
if((MSTSTAT & MSTSTATE) == MSTNACKTX) // check nack on data
  return 2; //device nacked data
if((MSTSTAT & MSTSTATE) == MSTARBLOSS) { // check arbloss
  return -1; //got an error
}
if((MSTSTAT & MSTSTATE) == MSTSSERR) { // check sserr
  return -2; //got an error
}
if((MSTSTAT & MSTSTATE) != MSTTX) { // check fatal state
  return -3; //got a fatal error since the state is in the wrong place. shouldn't happen
}
MSTCTL = STOP;
return 0;

Noah
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by elef on Fri May 31 23:15:30 MST 2013
wonggs i totally agree with you mate.
I want to focus on my program, not waste my time writing i2c drivers or fixing nxp bugs.
the lpc812 manual mentions i2c ROM drivers, has anyone used them and does anyone know if there are any examples we can look at?
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wongss on Fri May 31 21:45:48 MST 2013
Would like to make some comment here. I put it here as I am also currently struggling with i2c on lpc812:

I find the LPC8xx processor very attractive in price and performance. Unfortunately, I find the examples given very intimidating.
I have been struggling to get the i2c to work properly. It also currently freezes at the I2C_MstSend().

I had been using our own 3 functions (master mode) in our teaching and student projects using 8051 compatible controllers:
void i2cInit(void);
uint8_t i2cSend(uint8_t addr, uint8_t n, uint8_t *buf); // return success or failure
uint8_t i2cReceive(uint8_t addr, uint8_t n, uint8_t *buf); // return success or failure
None of the above would get stuck even if there will be error (e.g. nack).

We also use mbed. The i2c and spi functions are really easy to use and one can focus on the application.
Unfortunately, the nxp mbed boards are rather costly and the environment can be quick different when one moves to own target board.

I recently actively promote the use of Arduino environment on atmega328 MCU on breadboard to student projects.
We encapsulate the given i2c wire.h functions (already considered a bit complex) to the above 3 simple to use functions too.

I intend to use lpc8xx as either host or peripherals. Unfortunately the examples given put me off (sorry to say that).
They are hard to understand to me and there are lots of intimidating registers level access.
Documentation is poor, eg. there are inconsistencies and some of the input and output parameters are not even explained.
Example:
/*****************************************************************************
** Function name:I2C_MstInit
**
** Descriptions:I2C port initialization routine
**
** parameters:None
** Returned value:None
**
*****************************************************************************/
void I2C_MstInit( LPC_I2C_TypeDef *I2Cx, uint32_t div, uint32_t cfg, uint32_t dutycycle )
{
/* For master mode plus, if desired I2C clock is 1MHz (SCL high time + SCL low time).
If CCLK is 36MHz, MasterSclLow and MasterSclHigh are 0s,
SCL high time = (ClkDiv+1) * (MstSclHigh + 2 )
SCL low time = (ClkDiv+1) * (MstSclLow + 2 )
Pre-divider should be 8.
If fast mode, e.g. communicating with a temp sensor, Max I2C clock is set to 400KHz.
Pre-divider should be 11. */

There is no simple example to learn from. The i2ctest.c is hard to understand.

Just wander if it is possible for nxp to provide some easy to use basic functions so that we quickly focus on applications be successful quickly.
Not sure if the expectation is reasonable.
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by elef on Fri May 31 18:27:34 MST 2013
Thanks. It didn't work, because MSTSTATE is 0 (idle).
I can get out of the function by checking the timeout timer, but the problem is next time the I2C_MstSend() is called, it never starts another transmission. It is as if the whole i2c is locked up and can't transmit. Is there a way to reset the i2c without doing a full reset on the peripheral (i don't want to initialise the i2c module again).

For example, if you look in I2C_MstSend(), i want something like this:
        while(!msttxrdy) {
            if ( I2C_CheckError(I2Cx) ) { //i check in here for timeouts also
                //do some kind of i2c reset here, so next time mstsend is called, it will transmit again.
                return;
            }
0 Kudos
Reply

4,574 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by noahk on Fri May 31 12:37:05 MST 2013
From what I can see, the I2C_MstSend function doesn't look for NACKs. It checks for errors and then attempts retransmits, but for NACKs it loops busily, and will never exit. Here's some code that might help you to understand how nacks are detected in the I2C. This can help you to make the modifications you need.

I2Cx->MSTDAT = addr; // setup address
I2Cx->MSTCTL = CTL_MSTSTART; // try to start sending
while(!(I2Cx->STAT & STAT_MSTPEND)); // wait for master pending
if((I2Cx->STAT & MASTER_STATE_MASK) == STAT_MSTNACKADDR) // check for nack on address
return -1; // slave nacked address
// check for errors in stat and make sure stat is equal to STAT_MSTTX
I2Cx->MSTDAT = data; // setup data
I2Cx->MSTCTL = CTL_MSTCONTINUE; // send data
while(!(I2Cx->STAT & STAT_MSTPEND)); // wait for master pending
if((I2Cx->STAT & MASTER_STATE_MASK) == STAT_MSTNACKTX) // check for nack on data
return -1; //error
// check for errors in stat and make sure stat is equal to STAT_MSTTX
I2Cx->MSTCTL = CTL_MSTSTOP; // send stop

This code demonstrates detection of nacks. Hopefully this will help.

Noah
0 Kudos
Reply