使用LPC55S28 I2C从机功能,接收不定长的数据(通过字节数或者STOP条件判断)

电子说

1.2w人已加入

描述

    使用LPC55S28的I2C从机接口,比如实现 24LC系列的从机EEPROM 。可以提供以下操作,如字节写入、页面写入、当前地址读取、随机读取和顺序读取。接下来,使用Byte Write和Random Read作为示例来说明。首先明确需要判断的状态,包括以下内容:数据和地址-- 用于确定接收到的地址或数据。起始位-- 用于判断是否接收到起始位。读写-- 用于判断是写状态还是读状态。 

随机读取

如果从设备生成kI2C_SlaveAddressMatchEvent,则表示从设备检测到主设备发送的启动或重复启动。可以在程序中设置一个变量,记录它是启动还是重复启动,并根据传输情况合理设置该变量的值。假设从设备检测到启动,那么根据接受容量字节大小,接收到两个字节或三个字节,那么第一个字节是包含读写操作的设备的地址,第二个和第三个字(如果存在)是要操作的数据的地址。接下来,LPC5528将再次检测启动,即再次接收具有读取操作的设备地址。LPC5528从相应的数据地址读取数据并将其返回给主机。 

状态机

字节写

如果从设备生成kI2C_SlaveAddressMatchEvent,则表示从设备检测到主设备发送的启动或重复启动。可以在程序中设置一个变量,记录它是启动还是重复启动,并根据传输情况合理设置该变量的值。假设从设备检测到启动,那么根据接收容量大小,接收到两个字节或三个字节,那么第一个字节是包含读写操作的设备的地址,第二个和第三个字(如果存在)是要操作的数据的地址。紧随其后的字节是数据。将此数据字节保存到上一步骤中获得的地址中。

状态机

当主机设置STOP条件停止传输的时候,从机端需要获得一个提醒。可以参考例程"i2c_interrupt_b2b_transfer_slave.c" 实现基于I2C从机的例子。

状态机

状态机

I2C驱动的状态机设置xfer->rxSize 和xfer->txSize 变量。

static void i2c_slave_callback(I2C_Type *base, volatile i2c_slave_transfer_t *xfer, void *userData)
{
    switch (xfer->event)
    {
        /*  Address match event */
        case kI2C_SlaveAddressMatchEvent:
            xfer->rxData = NULL;
            xfer->rxSize = 0;
            break;
        /*  Transmit request */
        case kI2C_SlaveTransmitEvent:
            /*  Update information for transmit process */
            xfer->txData = &g_slave_buff[2];
            xfer->txSize = g_slave_buff[1];
            break;

        /* Setup the slave receive buffer */
        case kI2C_SlaveReceiveEvent:
            /*  Update information for received process */
            xfer->rxData = g_slave_buff;
            xfer->rxSize = I2C_DATA_LENGTH;
            break;

        /* The master has sent a stop transition on the bus */
        case kI2C_SlaveCompletionEvent:
            g_SlaveCompletionFlag = true;
            break;

        default:
            g_SlaveCompletionFlag = false;
            break;
    }

}

    如果主机发送一定数据后,判断分支case kI2C_SlaveCompletionEvent 将会执行,同时 g_SlaveCompletionFlag 标志将会设置为 true。在SDK中,使用I2C_SlaveTransferNonBlocking 函数,有判断字节传输完成的动作。

/* Start accepting I2C transfers on the I2C slave peripheral */
reVal = I2C_SlaveTransferNonBlocking(EXAMPLE_I2C_SLAVE, &g_s_handle,
kI2C_SlaveAddressMatchEvent | kI2C_SlaveCompletionEvent);
if (reVal != kStatus_Success)
{
return -1;
}

/* Wait for transfer completed. */
while (!g_SlaveCompletionFlag)
{
}
g_SlaveCompletionFlag = false;

    case k2IC_SlaveCompletionEvent 这个分支的进入不是根据主机发送的stop条件进入的,而是根据字节数进入的,譬如:如果主机发送256字节,接收字节数定义为16,当第16个数据接收完成后,就会进入该分支。但是 I2C 从机端事先并不知道 I2C 主机发送的字节数,所以无法判定停止。有什么办法能判断停止呢?

    “API需要编写代码判断在I2C STOP停止时达到完成状态,而不是通过rxData计数到0。”参考示例代码只显示raData计数减到了0。如果要在停止时达到完成状态,在 i2c 从机回调函数i2c_slave_callback中,需要添加case kI2C_SlaveDeselectedEvent。

static void i2c_slave_callback(I2C_Type*base, volatile i2c_slave_transfer_t *xfer, void *userData)
{
switch (xfer->event)
    {

...

  casekI2C_SlaveDeselectedEvent:
                  g_SlaveCompletionFlag = true;
        //        用户代码
                  break;

...

}
}

    在传输函数中,需要添加 kI2C_SlaveDeselectedEvent:

/* 在 I2C 从机外设中, 启动接收 I2C传输 */
    reVal = I2C_SlaveTransferNonBlocking(EXAMPLE_I2C_SLAVE,&g_s_handle, kI2C_SlaveAddressMatchEvent | kI2C_SlaveCompletionEvent|kI2C_SlaveDeselectedEvent);

    当 I2C主机发送 STOP,从机的STAT标志将会设置为1,函数 I2C_SlaveTransferHandleIRQ将会触发 kI2C_SlaveDeselectedEvent。查看驱动代码如下 :

void I2C_SlaveTransferHandleIRQ(I2C_Type *base,i2c_slave_handle_t *handle)
{
uint32_t i2cStatus = base->STAT;

if (i2cStatus &I2C_STAT_SLVDESEL_MASK)
    {
        I2C_SlaveInvokeEvent(base, handle,kI2C_SlaveDeselectedEvent);
        I2C_SlaveClearStatusFlags(base,I2C_STAT_SLVDESEL_MASK);
    }

...

}

    在 LPC55 参考手册第 637页面有相关描述。

状态机

  审核编辑:汤梓红。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分