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.
工具与软件:
你(们)好
我使用 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 函数、我们没有计划在源代码中提供这些特定函数、我们希望客户根据需要手动实现。