I²C malfunction/freezing of lpc824 I²C communication 

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

I²C malfunction/freezing of lpc824 I²C communication 

2,499 Views
lgr
Contributor I

Using I2C1 of LPC824,SCL pins for PIO0_12,SDA pin for PIO0_13. And the Slave device is FMC24C02, i2c bus rate is 400KHz, pull-up resistor is 10k.

 The I2C bus is stuck after reset and start this works fine for a while (some times 57 seconds, other times up to 5 minutes or even longer).
Logic analyzer shows that SCL timing will go wrong before the bus is stuck. It lost a SCL clock .It should send 9 SCL clock, however, it sends 8 SCL clock.Because one of the clock-low-states was longer than the others, obviously twice as long.
At this time I find that I2C Status register MSTPENDING BIT is 0 always or  MSTSTATE is  NACK Address/NACK Data  when debugging.Thus I2C1 controller can't operate the bus no longer.

 I think that Pull up resistance is too large at first, then I change the resistance to 4.7K, however the issue is the same as before. At the same time, I find that when enter debug mode in keil,it is easier to appear problem.

Here are my  soure code of test demo.


#include "LPC8xx.h"
//#include <cr_section_macros.h>
//#include <stdio.h>

#include "lpc8xx_i2c.h"
#include "lpc8xx_swm.h"
#include "lpc8xx_syscon.h"
#include "utilities.h"

/*******************************************************************************
NOTE:The official demo about I2C1 clock control bit can make a mistake,
I2C1 clock control bit should be 21st in SYSAHBCLKCTRL register,
but it is the 20th in official source code .Please fix the bug.
*******************************************************************************/

/*******************************************************************************
macro definition
*******************************************************************************/
#define I2C_M_7BIT 0x00u /* 7-bits device addr */
#define I2C_M_WR 0x00u /* write operation */
#define I2C_M_RD 0x02u /* read operation */
#define I2C_M_NOSTART 0x10u /* Don't need to restar */

#define I2C_MASTER LPC_I2C1
#define EEPROM_ADDR 0x50 /* EEPROM device addr */
#define TEST_LEN 0x08 /* EEPROM page size */

#define NULL ((void *)0) /* Null pointer */

#define WaitForUART0txRdy while(((LPC_USART0->STAT) & (1<<2)) == 0)

/*******************************************************************************
Global variable definition
*******************************************************************************/
const unsigned char the_prompt[] = "i2c1 operation eeprom\n\r";


/*******************************************************************************
Function declaration in advance
*******************************************************************************/
void setup_debug_uart(void);


/**
* \brief I2C transmission structure definition, it is mainly used for I2C polling mode.
*/
typedef struct i2c_transfer {
/** \brief I2C device addr */
volatile uint16_t addr;
/** \brief I2C device feature */
volatile uint16_t flags;
/** \brief I2C transmit data buffer pointer */
volatile void *p_buf;
/** \brief I2C data buffer length */
volatile uint16_t length;
} i2c_transfer_t;

/** \brief I2C transmission structure */
i2c_transfer_t g_i2c1_transfer;

/**
* \brief I2C transmission structure parameter setting function
* \retval 0 : Structure is set up correctly;
*/
static int __i2c_mktrans (i2c_transfer_t *p_trans,
uint16_t addr,
uint16_t flags,
void *p_buf,
uint16_t length)
{
if(p_trans == NULL) {
return -1;
}

p_trans->addr = addr;
p_trans->flags = flags;
p_trans->p_buf = p_buf;
p_trans->length = length;

return 0;
}

/**
* \brief The I2C MASTER Start
*/
static void __i2c_mst_start (LPC_I2C_TypeDef *p_hw_i2c,
i2c_transfer_t *p_trans)
{
uint16_t dev_addr = (p_trans->addr) << 1;

if(!(p_trans->flags & I2C_M_NOSTART)) {

if (p_trans->flags & I2C_M_RD) {
dev_addr |= 0x1; /* bit0 is 1,read */
} else {
dev_addr |= 0x0; /* bit0 is 0,write */
}

p_hw_i2c->MSTDAT = dev_addr; /* Sending device addr */
p_hw_i2c->MSTCTL = CTL_MSTSTART; /* Sending start signal */
}
}

/**
* \brief The I2C MASTER sending address/data
*
* \retval 0 : Send complete
*/
static int __i2c_mst_send (LPC_I2C_TypeDef *p_hw_i2c,
i2c_transfer_t *p_trans)

{
uint8_t i;

for (i = 0;i < p_trans->length; i++) {

while (!(p_hw_i2c->STAT & STAT_MSTPEND));
while ((p_hw_i2c->STAT & MASTER_STATE_MASK) != STAT_MSTTX);

p_hw_i2c->MSTDAT = ((uint8_t *)(p_trans->p_buf))[i];
p_hw_i2c->MSTCTL = CTL_MSTCONTINUE;
}

while (!(p_hw_i2c->STAT & STAT_MSTPEND));
while ((p_hw_i2c->STAT & MASTER_STATE_MASK) != STAT_MSTTX);

return 0;
}

/**
* \brief The I2C MASTER recv data
*
* \retval 0 : recv complete
*/
static int __i2c_mst_recv (LPC_I2C_TypeDef *p_hw_i2c,
i2c_transfer_t *p_trans)
{
uint8_t i;

for (i = 0; i < p_trans->length; i++) {

while (!(p_hw_i2c->STAT & STAT_MSTPEND));
while ((p_hw_i2c->STAT & MASTER_STATE_MASK) != STAT_MSTRX);

/* recv data */
((uint8_t *)(p_trans->p_buf))[i] = p_hw_i2c->MSTDAT;

/* recv complete */
if (i != (p_trans->length - 1)) {
p_hw_i2c->MSTCTL = CTL_MSTCONTINUE;
}
}

return 0;
}

/*****************************************************************************
*****************************************************************************/
int main(void) {

i2c_transfer_t *p_trans = &g_i2c1_transfer;
uint8_t eeprom_buf[TEST_LEN] = {0};
uint8_t test_addr[2] = {0x00};


// Configure the debug uart (see Serial.c)
setup_debug_uart();

PutTerminalString(LPC_USART0, (uint8_t *)the_prompt);// See utilities_lib

// Enable clocks to I2C1, SWM (see lpc8xx_syscon.h)
LPC_SYSCON->SYSAHBCLKCTRL |= (I2C1 | SWM);

// SWM settings for I2C0:
// P0.10 = I2C0_SCK
// P0.11 = I2C0_SDA
// P0.12 = I2C1_SCK
// P0.13 = I2C1_SDA

// Configure the SWM (see utilities_lib and lpc8xx_swm.h)
// On the LPC824, I2C0_SDA and I2C0_SCL are fixed pin functions which are enabled / disabled in the pinenable0 register
// On the LPC812, I2C0_SDA and I2C0_SCL are movable functions which are assigned using the pin assign registers

// LPC_SWM->PINENABLE0 &= ~(I2C0_SCL|I2C0_SDA); // Use for LPC824

LPC_IOCON->PIO0_12 |= (1 << 10);
LPC_IOCON->PIO0_13 |= (1 << 10);

ConfigSWM(I2C1_SDA, P0_13);
ConfigSWM(I2C1_SCL, P0_12);

// Give I2C1 a reset (see lpc8xx_syscon.h)
LPC_SYSCON->PRESETCTRL &= (I2C1_RST_N);
LPC_SYSCON->PRESETCTRL |= ~(I2C1_RST_N);

// Configure the I2C0 clock divider
// Desired bit rate = Fscl = 100,000 Hz (1/Fscl = 10 us, 5 us low and 5 us high)
// Use default clock high and clock low times (= 2 clocks each)
// So 4 I2C_PCLKs = 100,000/second, or 1 I2C_PCLK = 400,000/second
// I2C_PCLK = SystemClock = 30,000,000/second, so we divide by 30/.4 = 75
// Remember, value written to DIV divides by value+1

// 400K SCL
LPC_I2C1->CLKDIV = 0x0012;
LPC_I2C1->MSTTIME = 0x0000;

// Configure the I2C0 CFG register:
// Master enable = true
// Slave enable = true
// Monitor enable = false
// Time-out enable = false
// Monitor function clock stretching = false
//
LPC_I2C1->CFG = CFG_MSTENA ;

while(1) {

WaitI2CMasterState(LPC_I2C1, I2C_STAT_MSTST_IDLE); // Wait the master state to be idle

/* set transfer struct param,write device addr */
__i2c_mktrans(p_trans,
EEPROM_ADDR,
(I2C_M_7BIT | I2C_M_WR),
(uint8_t *)test_addr,
1);

__i2c_mst_start(I2C_MASTER, p_trans);
__i2c_mst_send (I2C_MASTER, p_trans);

__i2c_mktrans(p_trans,
EEPROM_ADDR,
(I2C_M_7BIT | I2C_M_RD),
(uint8_t *)eeprom_buf,
TEST_LEN);

__i2c_mst_start(I2C_MASTER, p_trans);
__i2c_mst_recv(I2C_MASTER, p_trans);

/* stop */
LPC_I2C1->MSTCTL = CTL_MSTSTOP;

PutTerminalString(LPC_USART0, (uint8_t *)"run\r\n");
}

}

 

 

 Please See the attachment for more information. Attachment has test demo project and Logic analyzer pictures.

What could be my problem ? can someone help me ? Thanks a lot!

Original Attachment has been moved to: LPC824_Example_Code_Bundle_Keil_r1.0.zip

Original Attachment has been moved to: Example_I2C_MasterSlave_main.c.zip

Labels (1)
0 Kudos
Reply
1 Reply

1,826 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Igr l,

 

       Thank you for your interest in NXP LPC product, I would like to provide service for you.

      About this question, we already have talked a lot in your external eefocus forum post:

http://www.nxpic.org/module/forum/thread-606742-1-1.html

    Now, in conclusion, just as I have said, two points need to take care:

1. change the external I2C pull up resistor in the normal GPIO pin to 1.2K , don't use 4.7K or 10K

2. Please modify your code, and refer to UM10800.pdf, Chapter 34: LPC82x Code examples

  When you check the (LPC_I2C->STAT & I2C_STAT_MSTSTATE), please  refer to the user maual code, use if instead of the while to wait.

 Take an example:

LPC_I2C->CFG = I2C_CFG_MSTEN;
while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));
if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_IDLE) abort();
LPC_I2C->MSTDAT = (0x23 << 1) | 0; // address and 0 for RWn bit in order to write
// subaddress
LPC_I2C->MSTCTL = I2C_MSTCTL_MSTSTART; // send start
while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));
if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTSTX) abort();
LPC_I2C->MSTDAT = 0xaa; // send subaddress
LPC_I2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE; // continue transaction
while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));
if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTSTX) abort();
LPC_I2C->MSTDAT = (0x23 << 1) | 1; // address and 1 for RWn bit in order to write
// subaddress
LPC_I2C->MSTCTL = I2C_MSTCTL_MSTSTART; // send repeated start
while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));
if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_RX) abort();
data = LPC_I2C->MSTDAT; // read data
if(data != 0xdd) abort();
LPC_I2C->MSTCTL = I2C_MSTCTL_MSTSTOP; // send stop
while(!(LPC_I2C->STAT & I2C_STAT_MSTPENDING));
if((LPC_I2C->STAT & I2C_STAT_MSTSTATE) != I2C_STAT_MSTST_IDLE) abort();

 

When the state is not what you want, just abort, don't wait any more, after abort, then stop the I2C and restart it again.

Because in practical usage, there maybe have some abnormal state happens(eg. external can't give the correct ack), if you use the while, it will block your code.

 

Wish it helps you!

If you still have problem after use my suggestions, welcome to discuss it no matter in community or eefocus external community.

 

Have a great day,
Kerry

 

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply