This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CCS/TM4C1294NCPDT:具有 FIFO 和 UDMA 的 I2C 示例

Guru**** 2555680 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/874457/ccs-tm4c1294ncpdt-i2c-with-fifo-and-udma-example

器件型号:TM4C1294NCPDT

工具/软件:Code Composer Studio

您好!

我需要使用 FIFO 和 UDMA 实现 I2C 通信。
通过分析文档 SPMA073、我找到了示例"ektm4c129_i2c_master_udma_fifo"、但似乎奇怪的中断"I2C_master_INT_RX_DMA_DONE"和"I2C_master_INT_TX_DMA_DONE"未使用。
是这样吗?
是否有使用它们的示例?
哪种方式会更高效?

谢谢、

Simion。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我认为在本示例中使用 dma_done 中断没有任何好处、因为您在主设备事务处理完成时会收到 I2C 中断。 您可以 提前获取 I2C_MASTER_INT_TX_DMA_DONE、但 I2C FIFO 中仍有要传输的数据。 此时不想将状态更改为 I2C_OP_STOP、因为在传输最后一个字节时仍可能会出现错误或 NAK。 简而言之、在本示例中使用 dma_done 中断没有好处。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的,这是有道理的  

    我还有一些疑问...  

    我的情况稍有不同、在示例中、发送一个16位字来引用 I2C 从设备的注册地址、但我需要一个仅为8位的字、这是 I2C 从设备的数据表所要求的。

    为此、我在 I2C1IntHandler 函数中添加了注释并更改了一些行。

    void I2C1IntHandler (void)
    {
    uint32_t ui32I2CMasterInterruptStatus;
    
    //
    //将 PL4切换为高电平以指示进入 ISR
    //
    ROM_GPIOPinWrite (GPIO_Porte _BASE、GPIO_PIN_4、GPIO_PIN_4);
    
    //
    //获取屏蔽的中断状态并清除标志
    //
    ui32I2CMasterInterruptStatus = ROM_I2CMasterIntStatusEx (I2C1_base、true);
    ROM_I2CMasterIntClearEx (I2C1_base、ui32I2CMasterInterruptStatus);
    
    log[CONT]= ui32I2CMasterInterruptStatus;
    CONT++;
    
    //
    //执行状态机
    //
    开关(g_ui8MasterCurrent 状态){
    I2C_OP_IDLE 情况:
    //
    //从空闲状态移动到发送地址状态
    //
    G_ui8MasterPrevState = g_ui8MasterCurrent 状态;
    // G_ui8MasterCurrent 状态= I2C_OP_TXADDR;
    G_ui8MasterCurrent 状态= I2C_OP_FIFO;
    
    //
    //将页的高位写入从机
    //
    ROM_I2CMasterSlaveAddrSet (I2C1_base、slave_address_EXT、false);
    // I2CMasterDataPut (I2C2_base、(g_ui16SlaveWordAddress >> 8));
    // I2CMasterControl (I2C2_base、I2C_MASTER_CMD_BURST_SEND_START);
    ROM_I2CMasterDataPut (I2C1_base、(g_ui16SlaveWordAddress >> 0);
    ROM_I2CMasterControl (I2C1_base、I2C_MASTER_CMD_BURST_SEND_START);
    中断;
    
    I2C_OP_TXADDR 案例:
    //
    //将当前状态指定为上一状态
    //
    G_ui8MasterPrevState = g_ui8MasterCurrent 状态;
    
    //
    //如果地址已 NAK'ed,则转至停止状态
    //否则进入 FIFO 启动状态
    //
    if (ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK)
    {
    G_ui8MasterCurrent 状态= I2C_OP_STOP;
    }
    其他
    {
    G_ui8MasterCurrent 状态= I2C_OP_FIFO;
    }
    
    //
    //将页的低位写入从机 IF
    //地址已确认
    //
    // ROM_I2CMasterDataPut (I2C1_base、(g_ui16SlaveWordAddress >> 0));
    // ROM_I2CMasterControl (I2C1_base、I2C_MASTER_CMD_BURST_SEND_CONT);
    中断;
    
    I2C_OP_FIFO 案例:
    //
    //如果最后一个数据已 NAK'ed,则转至停止状态
    //
    if (ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK)
    {
    G_ui8MasterCurrent 状态= I2C_OP_STOP;
    }
    //
    //根据方向移动到适当的状态
    //发送或接收。 还发送突发命令
    //用于 FIFO 操作。
    //
    否则 if (!g_bI2CDirection)
    {
    G_ui8MasterCurrent 状态= I2C_OP_TXDATA;
    ROM_I2CMasterControl (I2C1_base、I2C_MASTER_CMD_FIFO_BURST_SEND_FINISH);
    }
    其他
    {
    G_ui8MasterCurrent 状态= I2C_OP_RXDATA;
    ROM_I2CMasterSlaveAddrSet (I2C1_base、slave_address_EXT、true);
    ROM_I2CMasterControl (I2C1_base、I2C_MASTER_CMD_FIFO_SINGLE_Receive);
    }
    中断;
    
    I2C_OP_TXDATA 案例:
    //
    //将当前状态移动到上一状态
    //否则继续传输直到最后一个字节
    //
    G_ui8MasterPrevState = g_ui8MasterCurrent 状态;
    
    //
    //如果地址或数据已经 NAK'ed,则转至停止状态
    //如果由于获得的字节数而出现停止条件
    //完成,然后移动到停止状态
    //
    if (ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK)
    {
    G_ui8MasterCurrent 状态= I2C_OP_STOP;
    }
    否则、IF (ui32I2CMasterInterruptStatus 和 I2C_MASTER_INT_STOP)
    {
    G_ui8MasterCurrent 状态= I2C_OP_STOP;
    }
    否则、IF (ui32I2CMasterInterruptStatus 和 I2C_MASTER_INT_TX_DMA_DONE)
    {
    G_ui8MasterCurrent 状态= I2C_OP_STOP;
    }
    其他
    {
    G_ui8MasterCurrent 状态= I2C_ERR_State;
    }
    中断;
    
    I2C_OP_RXDATA 示例:
    //
    //将当前状态移动到上一状态
    //否则继续传输直到最后一个字节
    //
    G_ui8MasterPrevState = g_ui8MasterCurrent 状态;
    
    //
    //如果地址已 NAK'ed,则转至停止状态
    //如果由于获得的字节数而出现停止条件
    //完成,然后移动到停止状态并读取最后一个数据字节
    //
    if (ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK)
    {
    G_ui8MasterCurrent 状态= I2C_OP_STOP;
    }
    否则、IF (ui32I2CMasterInterruptStatus 和 I2C_MASTER_INT_STOP)
    {
    G_ui8MasterCurrent 状态= I2C_OP_STOP;
    }
    否则、IF (ui32I2CMasterInterruptStatus 和 I2C_MASTER_INT_RX_DMA_DONE)
    {
    G_ui8MasterCurrent 状态= I2C_OP_STOP;
    }
    中断;
    
    案例 I2C_OP_STOP:
    //
    //将当前状态移动到上一状态
    //否则继续传输直到最后一个字节
    //
    G_ui8MasterPrevState = g_ui8MasterCurrent 状态;
    中断;
    
    情况 I2C_ERR_STATE:
    G_ui8MasterCurrent 状态= I2C_ERR_STATE;
    中断;
    
    默认值:
    G_ui8MasterCurrent 状态= I2C_ERR_STATE;
    中断;
    }
    
    //
    //将 PL4切换为低电平以指示退出 ISR
    //
    ROM_GPIOPinWrite (GPIO_Porte _BASE、GPIO_PIN_4、0x0);
    } 

    SDA 和 SCL 线路在发送时表现良好、但我中断了4次、其中两次非常接近。

    绿线显示每个 I2C 中断。

    log 变量存储​​ui32I2CMasterInterruptStatus 的值每次中断时、我得到以下结果:
    log [0]= 0x00;
    日志[1]= I2C_MASTER_INT_DATA;
    日志[2]= I2C_MASTER_INT_TX_DMA_DONE;
    日志[3]= I2C_MASTER_INT_STOP | I2C_MASTER_INT_DATA;

    这两种几乎同时发生的中断是否预计? 是否有更好的方法来实现此目的?

    谢谢、

    Simion

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我明白你的观点。 由于 DMA_DONE 中断会将状态从 I2C_OP_TXDATA 移动到 I2C_OP_STOP、因此最终中断只会将 I2C_OP_STOP 状态复制到之前的状态变量。 您可以在不启用 I2C_MASTER_INT_TX_DMA_DONE 的情况下尝试、查看它是否正常工作、但只需使用一个中断。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    工作正常、但我更喜欢保持原样。

    谢谢、
    Simion