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.

[参考译文] MSPM0G3507:I2C 示例源代码问题

Guru**** 2533870 points
Other Parts Discussed in Thread: LP-MSPM0G3507, MSPM0G3507, MSP430F5529

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1456495/mspm0g3507-i2c-example-source-code-issue

器件型号:MSPM0G3507
主题中讨论的其他器件:MSP430F5529

工具与软件:

你(们)好

我使用 LP-MSPM0G3507与  EEPROM (24C02)连接、 我尝试使用 i2c_target_rw_multibyte_fifo_interrupts_LP_MSPM0G3507_nortos_ticlang 示例代码

从器件 ID 更改为0x50、不使用47k Ω 上拉电阻。 I2C SDA 和 SCL 线路始终为高电平、这表示未正确建立通信

我曾将 MSP430F5529 Launchpad 与相同的 EEPROM 配合使用、它可以进行所有操作。

提前感谢。

此致、

Yogesh

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

    i2c_target_XXX 示例设计为作为 I2C 目标(从器件)运行、但要与 EEPROM 一起使用、MSPM0需要作为控制器(主器件)运行。 特别是、目标不会(无法)启动事务。

    此处有一个类似的示例"i2c_controller_rw_multibyte_fifo_interrupts":

    https://dev.ti.com/tirex/explore/node?node=A__ACr6MhbD3KdyU.V6hxHG7A__MSPM0-SDK__a3PaaoK__LATEST

    快速浏览代码后、我认为您只需填写 gTxPacket[]并调整长度即可。

    写回和回读之间的 delay_cycles ()只有(1000个)时钟,比 twr=5ms 要短很多,所以你应该把它扩展到类似的东西(5*32000)才能得到5ms。

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

    Bruce、您好!

    感谢您提供的信息。 也会进行测试和更新

    此致、

    Yogesh

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

    Bruce、您好!

    我已经调整了时序 、现在我能够写入 EEPROM。 但需要进一步澄清。  

    gRxPacket 始终显示0xFF、这表示从 EEPROM 读取操作不起作用?

    此致、

    Yogesh  

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

    新的 EEPROM 通常(尽管并非总是)填充0xFF、因此这 表明您正在从尚未写入的区域读取数据。

    执行写入操作后、EEPROM 的内部地址指针指向刚刚写入的数据之后。 要读回您写入的内容、您需要发出仅包含所需 EEPROM 地址的"短"写入命令。 这将设置内部指针、因此您的下一次读取将从该位置读取。 这显示在数据表(doc0180)图11中。 (图11显示了重复开始、即单次交易、但如果更简单、您可以将其作为两次交易进行。)

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

    Bruce、您好!

    我无法在逻辑分析仪上看到 Rx 事务(附加的波形)

    如果对 Tx 相关代码进行了注释、我能够仅查看 Rx 事务

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

    我假设(?) 第一条跟踪来自(失败) Rx 事务。 没有太多的细节,但我的第一个猜测是你遇到了一个 NACK。

    写入(带数据)后、EEPROM 在写入存储器时会停止长达 TWR=5ms。 在此期间、它将否定确认任何请求。 如果 delay_cycles ()太短,这将是您会看到的症状。 我猜 MCU 在32MHz 下运行(如果你不这么说、我想这就是你会得到的)、因此5ms 将是(5*32000)个时钟周期。 您可以尝试提高速度;因为最大速度为80MHz、您可以尝试(5*80000)。

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

    Bruce、您好!

    感谢您的支持。 我使用的代码与您提供的代码相同。  

    /*
     * Copyright (c) 2021, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include "ti_msp_dl_config.h"
    
    /* Maximum size of TX packet */
    #define I2C_TX_MAX_PACKET_SIZE (3)
    
    /* Number of bytes to send to target device */
    #define I2C_TX_PACKET_SIZE (3)
    
    /* Maximum size of RX packet */
    #define I2C_RX_MAX_PACKET_SIZE (3)
    
    /* Number of bytes to received from target */
    #define I2C_RX_PACKET_SIZE (3)
    
    /* I2C Target address */
    #define I2C_TARGET_ADDRESS (0x50)
    
    /* Data sent to the Target */
    uint8_t gTxPacket[I2C_TX_MAX_PACKET_SIZE] = {0x00, 0x00, 0x02};
      // 0x03, 0x04,
       // 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
    /* Counters for TX length and bytes sent */
    uint32_t gTxLen, gTxCount;
    
    /* Data received from Target */
    uint8_t gRxPacket[I2C_RX_MAX_PACKET_SIZE];
    /* Counters for TX length and bytes sent */
    uint32_t gRxLen, gRxCount;
    /* Indicates status of I2C */
    enum I2cControllerStatus {
        I2C_STATUS_IDLE = 0,
        I2C_STATUS_TX_STARTED,
        I2C_STATUS_TX_INPROGRESS,
        I2C_STATUS_TX_COMPLETE,
        I2C_STATUS_RX_STARTED,
        I2C_STATUS_RX_INPROGRESS,
        I2C_STATUS_RX_COMPLETE,
        I2C_STATUS_ERROR,
    } gI2cControllerStatus;
    
    int main(void)
    {
        SYSCFG_DL_init();
    
        /* Set LED to indicate start of transfer */
        DL_GPIO_setPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);
    
        NVIC_EnableIRQ(I2C_INST_INT_IRQN);
        DL_SYSCTL_disableSleepOnExit();
    
        gI2cControllerStatus = I2C_STATUS_IDLE;
    
        gTxLen = I2C_TX_PACKET_SIZE;
        gTxCount = DL_I2C_fillControllerTXFIFO(I2C_INST, &gTxPacket[0], gTxLen);
        if (gTxCount < gTxLen) {
            DL_I2C_enableInterrupt(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
        } else {
            DL_I2C_disableInterrupt(I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
        }
        gI2cControllerStatus = I2C_STATUS_TX_STARTED;
        while (!(DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));
        DL_I2C_startControllerTransfer(I2C_INST, I2C_TARGET_ADDRESS, DL_I2C_CONTROLLER_DIRECTION_TX, gTxLen);
    
        while ((gI2cControllerStatus != I2C_STATUS_TX_COMPLETE) && (gI2cControllerStatus != I2C_STATUS_ERROR)) {
            __WFE();
        }
        while (DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
        /* Trap if there was an error */
        if (DL_I2C_getControllerStatus(I2C_INST) &  DL_I2C_CONTROLLER_STATUS_ERROR) {
            /* LED will remain high if there is an error */
            __BKPT(0);
        }
        while (!(DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));
    
        /* Add delay between transfers */
        delay_cycles(300000);
    
        /* Send a read request to Target */
        gRxLen               = I2C_RX_PACKET_SIZE;
        gRxCount             = 0;
        gI2cControllerStatus = I2C_STATUS_RX_STARTED;
        DL_I2C_startControllerTransfer(I2C_INST, I2C_TARGET_ADDRESS, DL_I2C_CONTROLLER_DIRECTION_RX, gRxLen);
        //************I2C read register **********************
        while (gI2cControllerStatus != I2C_STATUS_RX_COMPLETE) {
            __WFE();
        }
    
        while (DL_I2C_getControllerStatus(I2C_INST) &  DL_I2C_CONTROLLER_STATUS_BUSY_BUS) ;
    
        /* If write and read were successful, toggle LED */
        while (1) {
            DL_GPIO_togglePins(GPIO_LEDS_PORT,
                GPIO_LEDS_USER_LED_1_PIN | GPIO_LEDS_USER_TEST_PIN);
            delay_cycles(16000000);
        }
    }
    
    void I2C_INST_IRQHandler(void)
    {
        switch (DL_I2C_getPendingInterrupt(I2C_INST)) {
            case DL_I2C_IIDX_CONTROLLER_RX_DONE:
                gI2cControllerStatus = I2C_STATUS_RX_COMPLETE;
                break;
            case DL_I2C_IIDX_CONTROLLER_TX_DONE:
                DL_I2C_disableInterrupt(
                    I2C_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
                gI2cControllerStatus = I2C_STATUS_TX_COMPLETE;
                break;
            case DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER:
                gI2cControllerStatus = I2C_STATUS_RX_INPROGRESS;
                /* Receive all bytes from target */
                while (DL_I2C_isControllerRXFIFOEmpty(I2C_INST) != true) {
                    if (gRxCount < gRxLen) {
                        gRxPacket[gRxCount++] =
                            DL_I2C_receiveControllerData(I2C_INST);
                    } else {
                        /* Ignore and remove from FIFO if the buffer is full */
                        DL_I2C_receiveControllerData(I2C_INST);
                    }
                }
                break;
            case DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER:
                gI2cControllerStatus = I2C_STATUS_TX_INPROGRESS;
                /* Fill TX FIFO with next bytes to send */
                if (gTxCount < gTxLen) {
                    gTxCount += DL_I2C_fillControllerTXFIFO(
                        I2C_INST, &gTxPacket[gTxCount], gTxLen - gTxCount);
                }
                break;
                /* Not used for this example */
            case DL_I2C_IIDX_CONTROLLER_ARBITRATION_LOST:
            case DL_I2C_IIDX_CONTROLLER_NACK:
                if ((gI2cControllerStatus == I2C_STATUS_RX_STARTED) ||
                    (gI2cControllerStatus == I2C_STATUS_TX_STARTED)) {
                    /* NACK interrupt if I2C Target is disconnected */
                    gI2cControllerStatus = I2C_STATUS_ERROR;
                }
            case DL_I2C_IIDX_CONTROLLER_RXFIFO_FULL:
            case DL_I2C_IIDX_CONTROLLER_TXFIFO_EMPTY:
            case DL_I2C_IIDX_CONTROLLER_START:
            case DL_I2C_IIDX_CONTROLLER_STOP:
            case DL_I2C_IIDX_CONTROLLER_EVENT1_DMA_DONE:
            case DL_I2C_IIDX_CONTROLLER_EVENT2_DMA_DONE:
            default:
                break;
        }
    }

    我正在尝试使用0x02写入0x0000存储器位置。 同时、我正在尝试读取 EEPROM 的0x0000地址。  

    提前感谢。

    此致、

    Yogesh

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

    第二条迹线似乎是正常读取、结果不是0xFF、因此进度不长。  

    Tx 从 EEPROM 地址0x00开始写入{0x00、0x02}。 然后、Rx 从 EEPROM 地址0x02开始读取数据(在写入的数据之后)。 我想您之前的一些实验在那里写入了0x00。

    这是一个快速(我认为)实验:将 I2C_TX_PACKET_SIZE 更改为1 (不需要将 I2C_TX_MAX_PACKET_SIZE 更改为1)。 然后、查看您从 Rx 事务中得到的内容。 此版本不会写入任何新数据、但 Tx 操作会将 EEPROM 的内部地址指针设置回0x00 (=gTxPacket[0])。 然后、Rx 将从存储器的开头开始进行读取。

    作为额外的实验、您可以将 I2C_RX_MAX_PACKET_SIZE 和 I2C_RX_PACKET_SIZE 更改为更大的值(可能为8或16)、以查看这些0x00-s 是否显示在地址0x02处。

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

    Bruce、您好!

    感谢您的热情支持。  

    我已将  I2C_TX_PACKET_SIZE 修改为1、然后可以看到先前对这些存储器位置的写入

    MSPM0实现存在多种疑问。 一些函数、比如  

    EEPROM_ByteWrite (0x0005、0x89);
    __delay_cycles (3000);
    EEPROM_AckPolling ();
    __delay_cycles (3000);
    unsigned char Read_val = EEPROM_RandomRead (0x0005);//从地址0x0000读取
    __delay_cycles (3000);

     上述功能非常有用、用户友好。 我们是否有类似的函数来读取或写入特定的存储器位置。  

    此致、

    Yogesh

      

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

    我没有看到 TI 针对 MSPM0系列的(I2C) EEPROM 示例。 他们可能有朝一日会为 MSPM0更新 SLAA208、但我不会知道。 可能在 Github 上有一些东西。

    话虽如此、

    (a)您当前的代码有效地实现了 EEPROM_RandomRead [写入地址、然后读取]

    (b)您之前代码的前半部分(Tx 侧)有效地实现了 EEPROM_ByteWrite [写入地址后跟数据]

    因此您可以将它们重新打包为功能。 [您可能会发现从"_pol"(而不是"_interrupt")变体开始要容易一些、但这是你的调用。]

    (c)我建议暂时将 EEPROM_AckPolling 放置、并仅使用延迟 TWR=5ms。  执行 ACK 轮询需要将 NACK 处理为一个"正常"结果、这并不容易适合该结构的其余部分。  它也是一个相对较小的优化。

    [编辑:不要忘记 EEPROM 的写入页面机制。 DOC0180显示24C02的页面大小为8字节(第9页上的"页面写入")。]

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

    您好、Yogesh、您好、Bruce、

    很高兴您能在这里找到有效的解决方案。 为了注释 eeprom_write 和 eeprom_ackPolling 函数、我们没有计划在源代码中提供这些特定函数、我们希望客户根据需要手动实现。