interrupt based i2c transfer not working in i2c_17xx_40xx.c

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

interrupt based i2c transfer not working in i2c_17xx_40xx.c

1,735 次查看
misisp
Contributor I

/* Chip event handler interrupt based */
void Chip_I2C_EventHandler(I2C_ID_T id, I2C_EVENT_T event)
{
    struct i2c_interface *iic = &i2c[id];
    volatile I2C_STATUS_T *stat;

    /* Only WAIT event needs to be handled */
    if (event != I2C_EVENT_WAIT) {
        return;
    }

    stat = &iic->mXfer->status;
    /* Wait for the status to change */
    while (*stat == I2C_STATUS_BUSY) {}
}

I need help with the i2c routine's from the lpc_chip_175x_6x. The transfer's are sucessfull but the program wait's in the routine till the transfer is done... The means not interrupt based i think.

When I comment out the while loop it becomes a hard fault.

标记 (3)
4 回复数

1,347 次查看
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Micha and Daniel,

   I have tested the lpcopen_2_10_keil_iar_nxp_lpcxpresso_1769 periph_i2c project on my LPCXpresso LPC1769 today, at beginning, I also meet the same problem as Micha,

   But now, please check the following code modification, I also use the interrupt mode, I can enter I2C1_IRQHandler and it works OK, the code won't stop at Chip_I2C_EventHandler. 

 1. Most important area, board.c, Board_I2C_Init

void Board_I2C_Init(I2C_ID_T id)
{
     switch (id) {
     case I2C0:
          Chip_IOCON_PinMux(LPC_IOCON, 0, 27, IOCON_MODE_INACT, IOCON_FUNC1);
          Chip_IOCON_PinMux(LPC_IOCON, 0, 28, IOCON_MODE_INACT, IOCON_FUNC1);
          Chip_IOCON_SetI2CPad(LPC_IOCON, I2CPADCFG_STD_MODE);
          break;

     case I2C1:
          //Chip_IOCON_PinMux(LPC_IOCON, 0, 19, IOCON_MODE_INACT, IOCON_FUNC2);
          //Chip_IOCON_PinMux(LPC_IOCON, 0, 20, IOCON_MODE_INACT, IOCON_FUNC2);
          Chip_IOCON_PinMux(LPC_IOCON, 0, 19, IOCON_MODE_INACT, IOCON_FUNC3);
          Chip_IOCON_PinMux(LPC_IOCON, 0, 20, IOCON_MODE_INACT, IOCON_FUNC3);                
          Chip_IOCON_EnableOD(LPC_IOCON, 0, 19);
          Chip_IOCON_EnableOD(LPC_IOCON, 0, 20);
          break;

     case I2C2:
          Chip_IOCON_PinMux(LPC_IOCON, 0, 10, IOCON_MODE_INACT, IOCON_FUNC2);
          Chip_IOCON_PinMux(LPC_IOCON, 0, 11, IOCON_MODE_INACT, IOCON_FUNC2);
          Chip_IOCON_EnableOD(LPC_IOCON, 0, 10);
          Chip_IOCON_EnableOD(LPC_IOCON, 0, 11);
          break;
     }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Please note, I2C1 pin p0.19 and p0.20 FUNC3 is the I2C function, not FUCN2.

pastedImage_5.png

    So, if you choose the FUNC2, the I2C data won't be sent out, the code will stop at the loop.

2. For easy testing, I modify the main code like the following code.

  The hardware connection:

- LPCXpresso 1769 (using UART3)
- P0.19(SDA1) connected to P0.27(SDA0)
- P0.20(SCL1) connected to P0.28(SCL0)

int main(void)
{
     int tmp;
     int xflag = 0;
     static I2C_XFER_T xfer;

     SystemCoreClockUpdate();
     Board_Init();
     i2c_app_init(I2C0, SPEED_100KHZ);
     i2c_app_init(I2C1, SPEED_100KHZ);

     /* Simulate an EEPROM slave in I2C0 */
     i2c_eeprom_init(I2C_EEPROM_BUS);

     /* Simuldate an IO Expansion slave in I2C0 */
     i2c_iox_init(I2C_IOX_BUS);
        
//=============================kerry data==================================
        //step 1
       i2c_set_mode(I2C1, 0);//I2C1 as interrupt
       i2cDev = I2C1;
       //step2
      // i2c_rw_input(&xfer, 2);
            xfer.slaveAddr = 0X5B;
     xfer.rxBuff = 0;
     xfer.txBuff = 0;
     xfer.txSz = 0;
     xfer.rxSz = 0;
        buffer[0][0] = 6;
        xfer.txSz = 1;
     xfer.txBuff = buffer[0];
       tmp = Chip_I2C_MasterSend(i2cDev, xfer.slaveAddr, xfer.txBuff, xfer.txSz);
       DEBUGOUT("Written %d bytes of data to slave 0x%02X.\r\n", tmp, xfer.slaveAddr);
        

        

        
        while(1)
        {}
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Now, give you the test result and the I2C bus wave:

pastedImage_6.png

I send 7 bit ADDR=0X5B, so the first byte is 0X0x5b<<1=0xB6, correct, the second byte is 0X6, correct.

Micha said the code can't enter the interrupt, please check my following debug information.

pastedImage_7.png

pastedImage_8.png

You can find my I2C1 handler can be entered, and at last, the code stay in the main while(1) after I send all the I2C data.

So, all the function works.

I also attach my modified file, just for your reference.

Besides, about the document of the lpcopen I2C, please refer to this online document:

LPCOpen Platform: LPC17xx/40xx I2C example 

Wish it helps you!


Have a great day,
Kerry

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

1,347 次查看
danielholala
Senior Contributor II

misisp wrote:

  /* Chip event handler interrupt based */
void Chip_I2C_EventHandler(I2C_ID_T id, I2C_EVENT_T event)
{
    struct i2c_interface *iic = &i2c[id];
    volatile I2C_STATUS_T *stat;

 

    /* Only WAIT event needs to be handled */
    if (event != I2C_EVENT_WAIT) {
        return;
    }

 

    stat = &iic->mXfer->status;
    /* Wait for the status to change */
    while (*stat == I2C_STATUS_BUSY) {}
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

I need help with the i2c routine's from the lpc_chip_175x_6x. The transfer's are sucessfull but the program wait's in the routine till the transfer is done... The means not interrupt based i think. When I comment out the while loop it becomes a hard fault.

Hi Micha,

I suggest you do not remove the while loop.

You bumped into a dreadful piece of code here:  the event handler Chip_I2C_EventHandler()  which is both called from task and from interrupt context. So at first I also thought the while loop would defeat the purpose of using the i2c functions (i.e. Chip_I2C_MasterStateHandler()) in an interrupt driven way. With some debugging I found out that the event handler function is called from interrupt context with event = I2C_EVENT_DONE only and thus at least during interrupt the while loop is not executed.

Still I think this piece of code is low quality as:

a) it's not well documented (why do I need this event handler, what does it do, what do the different event states  I2C_EVENT_T mean and what are important considerations when reimplementing the handler)

b) the handler is both called from ISR and from the task running the i2c application and the handler code does not explicitly know in which context (ISR or task) it is executed

c) busy wait burns CPU cycles and is incommensurate with the use of an RTOS, e.g., FreeRTOS.

d) busy wait does not implement a timeout. If a bus obstruction occurs, your application hangs as long as the obstruction exists.

I don't mind that LPCOpen has no separate documentation as I'm happy with the inlined (doxygen) documentation but it needs to be more elaborate with attention to important details.

Best regards,

Daniel

0 项奖励
回复

1,347 次查看
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Micha,

   Please refer to this LPC17XX driver:

https://community.nxp.com/servlet/JiveServlet/download/941033-1-409324/lpc175x_6x_cmsis_driver_libra... 

There contains the I2C master and slave interrupt example .

Wish it helps you!

If you still have question about it, please kindly let me know!


Have a great day,
Kerry

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

0 项奖励
回复

1,347 次查看
danielholala
Senior Contributor II

Hi Kerry,

I don't think it's helpful to just point to another set of examples. First, these driver library examples are dated (last update 2012 according to release notes). Second, we would need to come to grips with this driver library code and more importantly, the driver library code is not based on the LPCOpen middleware (i.e., i2c_17xx_40xx.c) but on an older framework (i.e., lpc17xx_i2c.h) with a different API.

Back to LPCOpen, I'd appreciate if you could shed more light on the relevance of the master event handler, which is the Chip_I2C_EventHandler(), according to the example.

Thanks a lot!

Best regards,

Daniel

0 项奖励
回复