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/TMS320F28335:写入时的 EEPROM 地址

Guru**** 2040210 points
Other Parts Discussed in Thread: TMS320F28335, CONTROLSUITE
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/741897/ccs-tms320f28335-eeprom-address-over-writing

器件型号:TMS320F28335
Thread 中讨论的其他器件: controlSUITE

工具/软件:Code Composer Studio

 使用 TMS320F28335、我尝试写入 和读取类型为 TM24M01的 EEPROM。  

我刚刚修改 了\ti\controlSUITE\device_support\F2833x\v133\DSP2833x_examples_ccsv4中的一个示例。 写作和阅读效果良好。  我的问题是 尝试写入下一个地址并覆盖当前地址。 对两个地址的读取是相同的。

  我正在尝试仅写入器件的第一页(256个 baytes/页)。   原因可能是什么?  此处随附了我修改后的读数源和屏幕截图。  


#include "DSP28x_Project.h"    //器件头文件和示例 include 文件
#define I2C_SLAVE_ADDR       0x50
#define I2C_NUMBYTES         14.
#define I2C_EEPROM_HIGH_ADDR 0x00
#define I2C_EEPROM_LOW_ADDR  0x0F

void  I2CA_Init (void);
uint16 I2CA_WriteData (struct I2CMSG *msg);
uint16 I2CA_ReadData (struct I2CMSG *msg);
uint16 I2CA_WriteDataConfig (struct I2CMSG *msg);
uint16 I2CA_ReadDataConfig (struct I2CMSG *msg);
中断 void i2c_int1a_isr (void);
中断空 CPU_timer0_ISR (空);
UINT16 EEPROM_Buffer_Init();
uint16 EEPROM_ParaMetersUpdate();
uint16 EEPROM_DataMgt();
uint16 I2CA_PointerOverWrite (struct I2CMSG *msg);

uint16错误;
uint16 tempMsgStatus_OUT、tempMsgStatus_IN、tempSlaveAddress、tempNumOfBytes、
 tempMemoryHighAddr、tempMemoryLowAddr;
  uint32内存 HighLastAddr;
  uint32内存 LowLastAddr;

 uint16 PassCount、WriteCounter、L、I、k;
 uint16 Temparray[256];
#define M_TIME_100ms  3.
uint16mtime;
结构 I2CMSG I2cMsgOut1;
 结构 I2CMSG I2cMsgIn1;
 struct I2CMSG * CurrentMsgPtr;

void main (void)

 // uint16错误;
 // uint16 i;
 // CurrentMsgPtr =&I2cMsgOut1;
 // I2cMsgOut1.MsgBuffer[0]= 0x00;
//步骤1. 初始化系统控制:
// PLL、安全装置、启用外设时钟
//此示例函数位于 DSP2833x_SYSCTRL.c 文件中。
  InitSysCtrl();

//步骤2. 初始化 GPIO:
//此示例函数位于 DSP2833x_GPIO.c 文件和中
//说明了如何将 GPIO 设置为其默认状态。
// InitGpio();
//仅针对 I2C 功能设置 GP I/O
  InitI2CGpio();
//步骤3. 清除所有中断并初始化 PIE 矢量表:
//禁用 CPU 中断
  Dint;
//将 PIE 控制寄存器初始化为默认状态。
//默认状态为禁用所有 PIE 中断和标志
//被清除。
//此函数位于 DSP2833x_PIECTRL.c 文件中。
  InitPieCtrl();
//禁用 CPU 中断并清除所有 CPU 中断标志:
  IER = 0x0000;
  IFR = 0x0000;
//使用指向 shell 中断的指针初始化 PIE 矢量表
//服务例程(ISR)。
//这将填充整个表,即使是中断也是如此
//在本例中未使用。  这对于调试很有用。
//可以在 DSP2833x_DefaultIsr.c 中找到 shell ISR 例程
//此函数可在 DSP2833x_PieVect.c 中找到
  InitPieVectTable();
//此示例中使用的中断被重新映射到
//此文件中的 ISR 函数。
  EALLOW; //这是写入 EALLOW 受保护寄存器所必需的
  PieVectTable.I2CINT1A =&i2c_int1a_ISR;
  PieVectTable.TINT0 =  &CPU_timer0_ISR;
  EDIS;  //这是禁止写入 EALLOW 受保护寄存器所必需的
//步骤4. 初始化所有器件外设:
//此函数位于 DSP2833x_InitPeripherals.c 中
// InitPeripherals ();//此示例不需要
  I2CA_Init();
  InitCpuTimer();
  ConfigCpuTimer (&CpuTimer0、100、1000);
  PieCtrlRegs.PIEIER8.bit.INTx1 = 1;
  PieCtrlRegs.PIEIER1.bit.INTx7=1; //计时器0配置
  IER |= M_INT8|M_INT1;
  StartCpuTimer0();
  EINT;
  EEPROM_Buffer_Init();
  for (;;)
  {
     //////////////////////////////////////////////////////////////////////
 // EEPROM_DataMgt();
   }  //结束 for (;);)
}  // main 结束

中断空 CPU_timer0_ISR (空)
 mtime++;
 if (mtime >= M_TIME_100ms)
 {
  mtime = 0;
  EEPROM_DataMgt();
 }

 PieCtrlRegs.PIEACX.ALL |= PIEACK_Group1;

空 I2CA_Init (空)

  //初始化 I2C
  I2caRegs.I2CSAR = 0x0050;  //从器件地址- EEPROM 控制代码
  #IF (CPU_FRQ_150MHz)            //默认-对于150MHz SYSCLKOUT
       I2caRegs.I2CPSC.all = 14;  //预分频器-模块时需要7-12MHz (150/15=10MHz)
  #endif
  对于            100MHz SYSCLKOUT、#IF (CPU_FRQ_100MHz)//
    I2caRegs.I2CPSC.all = 9;    //预分频器-模块时需要7-12MHz (100/10 = 10MHz)
  #endif
  I2caRegs.I2CCLKL = 10;   //注意:必须为非零
  I2caRegs.I2CCLKH = 5;   //注意:必须为非零
  I2caRegs.I2CIER.ALL = 0x24;  //启用 SCD 和 ARDY 中断
  I2caRegs.I2CMDR.ALL = 0x0020; //使 I2C 退出复位
           //挂起时停止 I2C
  I2caRegs.I2CFFTX.ALL = 0x6000; //启用 FIFO 模式和 TXFIFO
  I2caRegs.I2CFFRX.ALL = 0x2040; //启用 RXFIFO、清除 RXFFINT、
  返回;
UINT16 EEPROM_Buffer_Init()

           PassCount = 0;
        WriteCounter = 0;
        L= 0;
        K = 0;

        //清除传入消息缓冲区
      对于(I = 0;I < I2C_MAX_BUFFER_SIZE;I++)
        {
            I2cMsgIn1.MsgBuffer[i]= 0x0000;
            I2cMsgOut1.MsgBuffer[i]= 0x0000;
        }
    tempsMsgStatus_OUT =    I2C_MSGSTAT_SEND_WITHSTOP;
    tempsMsgStatus_IN =     I2C_MSGSTAT_SEND_NOSTOP;
    tempSlaveAddress =  I2C_SLAVE_ADDR;
    tempNumOfBytes =    I2C_NUMBYTES ;
    tempMemoryHighAddr = I2C_EEPROM_HIGH_ADDR;
    tempMemoryLowAddr  = I2C_EEPROM_LOW_ADDR;
    I2CA_ReadDataConfig (&I2cMsgIn1);
    I2CA_WriteDataConfig (&I2cMsgOut1);
     返回0;

UINT16 EEPROM_DataMgt()
 如果(L<30) //要写30次:15篇著作,15篇以上著作: L 在每次成功写后加1
 {
   if (I2cMsgOut1.MsgStatus = I2C_MSGSTAT_SEND_WITHSTOP)
      {
              if (WriteCounter ==0)//写入下一个地址
                {
                    MemoryHighLastAddr = tempMemoryHighAddr;//存储当前地址
                    MemoryLowLastAddr =  tempMemoryLowAddr;
                         tempMemoryHighAddr = tempMemoryHighAddr;
                      tempMemoryLowAddr =   (tempMemoryLowAddr += 0x10); //计算 要写入的下一个低位地址
                    I2CA_WriteDataConfig (&I2cMsgOut1);// 发送要写入的地址和数据
                  }
              否则、if (WriteCounter ==1)//改写当前地址
                 {
                         tempMemoryHighAddr =  MemoryHighLastAddr;//复位到存储的地址
                   tempMemoryLowAddr =   内存 LowLastAddr;
                     I2CA_PointerOverWrite (&I2cMsgOut1);
                   }
              否则 {/*I2CA_WriteDataConfig (&I2cMsgOut1);*/}
                 错误= I2CA_WriteData (&I2cMsgOut1);
                 如果(错误= I2C_Success)
                 {
                           L++;
                   WriteCounter++;
                       CurrentMsgPtr =&I2cMsgOut1;
                       I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY;
                          if (WriteCounter==2)
                             {
                                   WriteCounter = 0;// 在写入下一个地址并覆盖当前地址后复位
                                 tempMemoryHighAddr =  tempMemoryHighAddr;
                                 tempMemoryLowAddr = (tempMemoryLowAddr += 0x10);//存储写入的地址
                             }
                       }
           }
      } //写入段结束
  else //如果 L>32:完成写入后,开始读取。
     {
         //检查传入消息状态。
    if (I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP)// I2cMsgIn1.MsgStatus 在程序启动时初始化为 I2C_MSGSTAT_SEND_NOSTOP
              {
                  // EEPROM 地址设置部分
                 // I2CA_ReadDataConfig (&I2cMsgIn1);
                    while (I2CA_ReadData (&I2cMsgIn1)!= I2C_Success)
                      {
                           //可以设置一个尝试计数器来打破无限 while
                           //循环。 EEPROM 将在执行时发回一个 NACK
                           //写入操作。 即使是写公报
                           //完成此时,EEPROM 仍可能处于忙状态
                           //对数据进行编程。 因此、会多次尝试
                           //必需。
                      }
                         //更新当前消息指针和消息状态
                    CurrentMsgPtr =&I2cMsgIn1;
                    I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY;

                }
         //一旦消息经过设置内部地址的过程
         //在 EEPROM 中、发送重新启动以从读取数据字节
         // EEPROM。 使用停止位完成通信。 MsgStatus 为
         //在中断服务例程中更新。
           否则、IF (I2cMsgIn1.MsgStatus = I2C_MSGSTAT_RESTART)
              {
                    //读取数据部分
                     while (I2CA_ReadData (&I2cMsgIn1)!= I2C_Success)
                     {
                       //可以设置一个尝试计数器来打破无限 while
                      //循环。
                     }
                     //更新当前消息指针和消息状态
                     CurrentMsgPtr =&I2cMsgIn1;
                     I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY;
               }
       } //读取段结束

           返回0;

uint16 I2CA_WriteDataConfig (struct I2CMSG *msg)
        MSG->MsgStatus     = tempMsgStatus_OUT  ;
   MSG->SlaveAddress  = tempSlaveAddress;
   MSG->NumOfBytes    = tempNumOfBytes;
   MSG->MemoryHighAddr = tempMemoryHighAddr;
   MSG->MemoryLowAddr = tempMemoryLowAddr;
                 MSG->MsgBuffer[0]  =    0x05;
           MSG->MsgBuffer[1]  =    0x06;
           MSG->MsgBuffer[2]  =    0x00;
           MSG->MsgBuffer[3]  =    0xE1;
           MSG->MsgBuffer[4]  =     0x00;
             MSG->MsgBuffer[5]  =     0xE1;
             MSG->MsgBuffer[6]  =     0x00;
             MSG->MsgBuffer[7]  =     0x00;
             MSG->MsgBuffer[8]  =     0x00;
             MSG->MsgBuffer[9]  =     0x00;
             MSG->MsgBuffer[10] =     0x64;
             MSG->MsgBuffer[11] =     0x96;
             MSG->MsgBuffer[12]=0x64      ;
             MSG->MsgBuffer[13] =     0x0A;
                MSG->MsgBuffer[14]=0x00      ;
               MSG->MsgBuffer[15]=0x00      ;
返回0;

UINT16 I2CA_PointerOverWrite (struct I2CMSG *msg)
    MSG->MsgStatus     = tempMsgStatus_OUT  ;
  MSG->SlaveAddress  = tempSlaveAddress;
  MSG->NumOfBytes    = tempNumOfBytes;
  MSG->MemoryHighAddr = tempMemoryHighAddr;
  MSG->MemoryLowAddr = tempMemoryLowAddr ;
                MSG->MsgBuffer[0]  =    0x00;
          MSG->MsgBuffer[1]  =    0x06;
          MSG->MsgBuffer[2]  =    0x01;
          MSG->MsgBuffer[3]  =    0xF4;
          MSG->MsgBuffer[4]  =    0x01;
            MSG->MsgBuffer[5]  =    0xF4;
            MSG->MsgBuffer[6]  =    0x00;
            MSG->MsgBuffer[7]  =    0x00;
            MSG->MsgBuffer[8]  =    0x00;
            MSG->MsgBuffer[9]  =    0x00;
            MSG->MsgBuffer[10] =     0x64;
            MSG->MsgBuffer[11] =     0x96;
            MSG->MsgBuffer[12]=0x64       ;
            MSG->MsgBuffer[13] =     0x00;
               MSG->MsgBuffer[14]=0x00      ;
              MSG->MsgBuffer[15]=0x00      ;

返回0;

uint16 I2CA_ReadDataConfig (struct I2CMSG *msg)
 MSG->MsgStatus     = tempMsgStatus_in  ;
 MSG->SlaveAddress  = tempSlaveAddress;
 MSG->NumOfBytes    = tempNumOfBytes;
 MSG->MemoryHighAddr = tempMemoryHighAddr;
   MSG->MemoryLowAddr = tempMemoryLowAddr ;
 返回0;
uint16 I2CA_WriteData (struct I2CMSG *msg)

  uint16 i;
  //等待直到 STP 位从任何先前的主设备通信中清零。
  //模块清除该位的操作被延迟到 SCD 位之后
  //设置。 如果在启动新消息之前未选中此位
  // I2C 可能会被混淆。
  IF (I2caRegs.I2CMDR.bit.STP==1)
  {
     返回 I2C_STP_NOT _READY_ERROR;
  }
  //设置从地址
  I2caRegs.I2CSAR = msg->SlaveAddress;
  //检查总线是否占线
  IF (I2cRegs.I2CSTR.bit.BB = 1)
  {
     返回 I2C_BUS_BUS_BUSY_ERROR;
  }
  //设置要发送的字节数
  // MsgBuffer +地址
  I2caRegs.I2CCNT = msg->NumOfBytes+2;
  //设置要发送的数据
  I2caRegs.I2CDXR = msg->MemoryHighAddr;
  I2caRegs.I2CDXR = msg->MemoryLowAddr;
//对于(i=0;i NumOfBytes-2;i++)
  对于(i=0;i NumOfBytes;i++)
  {
     I2caRegs.I2CDXR =*(msg->MsgBuffer+I);
  }
  //将 START 作为主发送器发送
  I2caRegs.I2CMDR.ALL = 0x6E20;

  返回 I2C_Success;

uint16 I2CA_ReadData (struct I2CMSG *msg)

  //等待直到 STP 位从任何先前的主设备通信中清零。
  //模块清除该位的操作被延迟到 SCD 位之后
  //设置。 如果在启动新消息之前未选中此位
  // I2C 可能会被混淆。
  IF (I2caRegs.I2CMDR.bit.STP==1)
  {
     返回 I2C_STP_NOT _READY_ERROR;
  }
  I2caRegs.I2CSAR = msg->SlaveAddress;
  if (msg->MsgStatus =I2C_MSGSTAT_SEND_NOSTOP)
  {
     //检查总线是否占线
     IF (I2cRegs.I2CSTR.bit.BB = 1)
     {
        返回 I2C_BUS_BUS_BUSY_ERROR;
     }
     I2caRegs.I2CCNT = 2;
     I2caRegs.I2CDXR =  msg->MemoryHighAddr;
     I2caRegs.I2CDXR =  msg->MemoryLowAddr;
     I2caRegs.I2CMDR.ALL = 0x2620;   //发送数据到设置 EEPROM 地址
  }
  否则 if (msg->MsgStatus =I2C_MSGSTAT_RESTART)
  {
     I2caRegs.I2CCNT = msg->NumOfBytes; //设置预期的字节数
     I2caRegs.I2CMDR.ALL = 0x2C20;   //作为主接收器发送重启
  }
  返回 I2C_Success;
中断 void i2c_int1a_ISR (void)    // I2C-A

  uint16 IntSource、I;
  //读取中断源
  IntSource = I2caRegs.I2CISRC.ALL;
   //中断源=检测到停止条件
  if (IntSource = I2C_SCD_ISRC)
  {
     //如果已完成的消息正在写入数据,则将 msg 重置为非活动状态
     if (CurrentMsgPtr -> MsgStatus = I2C_MSGSTAT_WRITE_BUSY)
        {
        CurrentMsgPtr -> MsgStatus = I2C_MSGSTAT_SEND_WITHSTOP;
         }
     其他
     {
             //如果在的地址设置部分收到 NACK 消息
             // EEPROM 读取、下面的代码进一步包含在寄存器访问就绪中
             //中断源代码将生成停止条件。 停止后
             //条件已接收(此处),将消息状态设置为重试。
             //用户可能希望在生成错误之前限制重试次数。
             if (CurrentMsgPtr -> MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY)
                {
                    CurrentMsgPtr -> MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
                  // PassCount++;
                 }
                   //如果已完成消息正在读取 EEPROM 数据,则将 msg 重置为非活动状态
                   //并从 FIFO 读取数据。
              否则(CurrentMsgPTR->MsgStatus =I2C_MSGSTAT_READ_BUSY)
                  {
                     for (i=0;i < I2C_NUMBYTES;i++)
                            {
                         I2cMsgIn1.MsgBuffer[i]= I2cRegs.I2CDRR;
                            }
                                       if (PassCount< 15)//  在15次读数后停止将数据写入 Temparray。
                                        {
                                             tempMemoryHighAddr = tempMemoryHighAddr;
                                               tempMemoryLowAddr = (tempMemoryLowAddr += 0x10);
                                            for (k = 0;k< CurrentMsgPtr -> NumOfBytes;k++)
                                                Temparray[(14*PassCount)+k]= CurrentMsgPtR->MsgBuffer[k] ;
                                                PassCount++;
                                                I2CA_ReadDataConfig (&I2cMsgIn1);
                                          }

                       }
                  否则{}
         }
  } //检测到停止条件结束
  //中断源=寄存器访问就绪
  //此中断用于确定的 EEPROM 地址设置部分的时间
  //读取数据通信已完成。 由于没有指令停止位、这个标志
  //告诉我们何时发送消息而不是 SCD 标志。 如果 NACK 是
  //接收到,清除 NACK 位并命令停止。 否则、继续读取
  //通信的数据部分。
  否则、IF (IntSource = I2C_ARDY_ISRC)
  {
      if (I2caRegs.I2CSTR.bit.nack = 1)
         {
            I2caRegs.I2CMDR.bit.STP= 1;
            I2caRegs.I2CSTR.All = I2C_CLR_Nack_bit;
         }
       否则(CurrentMsgPtr -> MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY)
         {
           CurrentMsgPtr ->MsgStatus = I2C_MSGSTAT_RESTART;
          }
  } //寄存器访问结束准备就绪
  其他
   {
     //由于中断源无效而产生一些错误
     asm ("  ESTOP0");
   }
  //启用未来的 I2C (PIE 组8)中断
  PieCtrlRegs.PIEACX.ALL = PIEACK_group8;
//============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
//不再需要。
//============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好 Fikadu、

    我建议查看您正在使用的特定 EEPROM 的数据表。 通常情况下、通信的格式应与之匹配、即如何正确读取或写入地址。 该示例可能与开箱即用的所需格式或协议不匹配。

    您使用的是什么 EEPROM? 我无法在线找到 TM24M01。

    此外、您能否提供通信的任何波形?

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

     尊敬的 Kevin:

    非常感谢 你的帮助。

    我很抱歉。 我刚才拼 错了 EEPROM 型号。 它是 AT24CM01。

     我尝试查看数据表、看起来不错。   您会为我检查一下吗?

    在这里、我附加了一个波形的通信。

    再次感谢您

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

    您好 Fikadu、

    好的、没问题、我现在找到了合适的数据表。 该 EEPROM 与本示例所使用的 EEPROM 类似、即读取/写入的寻址部分包含起始条件、从器件地址、第一个字地址、第二个字地址、然后是读取/写入数据。

    您将在 DS 中看到、它显示了写入一个字与写入一个页或读取一个字节与顺序读取的格式。 您需要确保您的通信格式符合以下要求、例如以下 DS:

    在屏幕截图中、您仅显示 SDA 信号。 查看波形时、确保同时探测 SDA 和 SCL、以检查数据格式。

    希望这对您有所帮助、

    Kevin

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

     Kevin、

    我一直在尝试采用上述数据格式、但尚未解决。 我后来得到的是、当第一页被完全写入时、数据写入回滚 、而不是写入下一页。  

      

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

    您好 Fikadu、

    那么、您正在执行页面写入? 我认为这种"翻转"行为是预期行为、并记录在 EEPROM 器件数据表中。 请阅读以下内容:

    希望这对您有所帮助、

    Kevin

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

    尊敬的 Kevin:

    谢谢你。

    是的、我看到过数据表。 我的问题是、为什么第一次停止后它不会转到下一页? 停止第一页的写入并开始下一页后、它会翻转。 什么可能是 原因?

    再次感谢您

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

    您好 Fikadu、

    如何在停止后执行下一页写操作? "第一个/第二个字地址"字节需要与下一页相对应、请确保第二页不使用相同的字节:

    最棒的

    Kevin