AnsweredAssumed Answered

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

Question asked by lgr l on Nov 9, 2016

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

Outcomes