你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F1 I2C中断方式一次写多页数据问题

[复制链接]
wdshuang09 提问时间:2019-4-26 22:25 /

用STMF103 I2C2中断读写24C32,读指定长度数据没有问题,
但写超过多余一页的数据,多余一页的数据有时能写进去,有时只写了一页数据后面的数据没有写进去。
如:I2C_EE_IRQ_Writ(buf, 0, 255);只能写到32字节(24C32 page为32Bbyte),后面的数据都没有写进去,
仿真时每写完一页数据都能进EV8-2事件中,进行写总数据减、地址增加等直到255字节的数据写完,但读出来发现,只有前面32个字节数据写进去了。
现在没有想到问题出在哪里?
下面是各个子函数:
//EEPROM写数据函数
void I2C_EE_IRQ_Write(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite)
{
  u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
  Addr = WriteAddr % I2C_PageSize;
  count = I2C_PageSize - Addr;
  NumOfPage =  NumByteToWrite / I2C_PageSize;
  NumOfSingle = NumByteToWrite % I2C_PageSize;
  I2C2Buf.NumByteWritingNow=0;
  if(Addr == 0)   /* If WriteAddr is I2C_PageSize aligned  */
  {
    if(NumOfPage == 0)  /* If NumByteToWrite < I2C_PageSize */
    {
      I2C_EE_IRQ_PageWrite(pBuffer, WriteAddr, NumOfSingle);
     I2C2Buf.NumByteWritingNow=NumOfSingle;
    }
    else  /* If NumByteToWrite > I2C_PageSize */
    {
        I2C_EE_IRQ_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
        I2C2Buf.NumByteWritingNow=I2C_PageSize;
    }
  }
  else   /* If WriteAddr is not I2C_PageSize aligned  */
  {
    if(NumOfPage== 0)     /* If NumByteToWrite < I2C_PageSize */
    {
      I2C_EE_IRQ_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      I2C2Buf.NumByteWritingNow=NumOfSingle;
    }
    else/* If NumByteToWrite > I2C_PageSize */
    {
        if(count != 0)
       {  
          I2C_EE_IRQ_PageWrite(pBuffer, WriteAddr, count);
          I2C2Buf.NumByteWritingNow=count;
       }
    }
  }  
}

//EEPROM页写入函数
void I2C_EE_IRQ_PageWrite(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite)
{
        I2C2Buf.MasterDirection= Transmitter;
        I2C2Buf.MasterWComplete=0;
        I2C2Buf.Wdatalen=NumByteToWrite;
        I2C2Buf.SlaveADDR= EEPROM_ADDRESS;
        I2C2Buf.Device_AddrOffset= WriteAddr;
        I2C2Buf.Device_Addr_OffsetDone=0;
        I2C_AcknowledgeConfig(I2C2, ENABLE);
        I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE);
        /* Send START condition */
        if(I2C2->CR1 & 0x200)I2C2->CR1 &= 0xFDFF;
        I2C_GenerateSTART(I2C2, ENABLE);
}

//进入下面中断事件处理
void i2c2_evt_isr(void)
{  
        uint32_t lastevent=  I2C_GetLastEvent(I2C2);
        switch (lastevent)
        {
                /************************** Master Invoke**************************************/
                case I2C_EVENT_MASTER_MODE_SELECT: // 0x00030001. 发送启动条件时产生的事件: EV5      
                {/* EV5 */
                        if (I2C2Buf.MasterDirection == Receiver)//I2C主模式接收
                        {
                                if (!I2C2Buf.Device_Addr_OffsetDone)
                                {
                                        I2C_Send7bitAddress(I2C2,I2C2Buf.SlaveADDR,I2C_Direction_Transmitter);
                                }
                                else
                                {
                                        /* Send slave Address for read */
                                        I2C_Send7bitAddress(I2C2,I2C2Buf.SlaveADDR,I2C_Direction_Receiver);
                                        I2C2Buf.Device_Addr_OffsetDone=0;                                       
                                }
                        }
                        else//I2C主模式发送
                        {
                               I2C_Send7bitAddress(I2C2, I2C2Buf.SlaveADDR, I2C_Direction_Transmitter);
                        }
                        I2C_ITConfig(I2C2, I2C_IT_BUF , ENABLE);
                        break;
                }
                /********************** Master Receiver events ********************************/
                case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: // 0x00030002. 发出读指定I2C从设备时产生的事件:EV6
                {/* EV6 */
                        break;
                }
                case I2C_EVENT_MASTER_BYTE_RECEIVED: //0x00030040主收到一个字节时产生的事件:EV7
                {/* EV7 */
                        I2C2Buf.RBuf[I2C2Buf.RCount++] = I2C_ReceiveData (I2C2);//I2C2中断读取数据
                        if(I2C2Buf.RCount == (I2C2Buf.Rdatalen - 1))//判断是否为倒数第2个数据
                        {
                                I2C_AcknowledgeConfig(I2C2, DISABLE);
                                I2C_GenerateSTOP(I2C2, ENABLE);
                        }
                        if(I2C2Buf.RCount == I2C2Buf.Rdatalen)//读到最后一个数据       
                        {
                                I2C_EE_ReadClearStatus();
                                I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_ERR , DISABLE);
                        }
                        break;
                }
                /************************* Master Transmitter events **************************/
                case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:  // 0x00070082. 发出写指定I2C从设备时产生的事件:EV8 just after EV6   
                {/* EV8 just after EV6 */
                        #if (EE_ADDRESS_NUM>1)//EEPROM内部地址是16位
                                I2C2Buf.Addr_Count++;       
                                if (I2C2Buf.Addr_Count < (EE_ADDRESS_NUM))
                                {
                                        I2C_SendData(I2C2, I2C2Buf.Device_AddrOffset>>8);
                                }
                        #else//EEPROM内部地址是8位
                                I2C_SendData(I2C2, I2C2Buf.Device_AddrOffset);
                                I2C2Buf.RegAddr_OffsetDone=1;//EEPROM内部地址写完
                        #endif
                        break;
                }
                case I2C_EVENT_MASTER_BYTE_TRANSMITTING: // 0x00070080. 正在发送数据中......
                { /* EV8 */
                        #if (EE_ADDRESS_NUM>1)
                        if (!I2C2Buf.Device_Addr_OffsetDone)
                        {
                                if (I2C2Buf.Addr_Count < (EE_ADDRESS_NUM))
                                {
                                        I2C_SendData(I2C2, I2C2Buf.Device_AddrOffset);
                                        I2C2Buf.Addr_Count++;
                                }
                                else
                                {
                                        I2C2Buf.Addr_Count=0;
                                        I2C2Buf.Device_Addr_OffsetDone=1;       
                                }
                                break;
                        }
                        #endif
                        if (I2C2Buf.MasterDirection == Receiver)
                        {
                                I2C_ITConfig(I2C2, I2C_IT_BUF , DISABLE);
                                I2C_GenerateSTART(I2C2, ENABLE);//I2C总线重启
                                break;
                        }
                        else
                        {
                                if(I2C2Buf.WCount < I2C2Buf.Wdatalen)
                                {
                                        I2C_SendData(I2C2, buf[I2C2Buf.WCount++]);
                                }
                                else //小于或等于一页的数据写完成
                                {      
                                        I2C_ITConfig(I2C2,I2C_IT_BUF, DISABLE);
                                }
                                break;
                        }
                }
                case I2C_EVENT_MASTER_BYTE_TRANSMITTED:   // 0x00070084. 一个字节数据发送完成.           
                {/* EV8-2 */
                        if (I2C2Buf.MasterDirection == Receiver)
                        {
                                break;
                        }
                        else
                        {
                                I2C_GenerateSTOP(I2C2, ENABLE);
                                I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_BUF |I2C_IT_ERR, DISABLE);
                                while(I2C_GetFlagStatus(I2C2 , I2C_FLAG_BUSY));//等待页写完
                                I2C2Buf.WBuf+= I2C2Buf.NumByteWritingNow;//写地址偏移上次写完数据的个数
                                I2C2Buf.WriteAddr+= I2C2Buf.NumByteWritingNow;//写地址偏移上次写的数据的个数
                                I2C2Buf.NumByteToWrite-= I2C2Buf.NumByteWritingNow;//写总的数据减去当前写的数据个数
                                if(I2C2Buf.NumByteToWrite>0)//判断数据是否写完
                                {
                                        delay_ms(10);
                                        I2C_EE_IRQ_Write(I2C2Buf.WBuf,I2C2Buf.WriteAddr,I2C2Buf.NumByteToWrite);//再次调入写数据函数
                                }
                                else
                                {
                                        WriteComplete = 1;
                                        I2C_EE_WriteClearStatus();
                                }
                        }
                        break;
                }
        }
}

收藏 评论12 发布时间:2019-4-26 22:25

举报

12个回答
七哥 回答时间:2019-4-27 00:32:59
本帖最后由 toofree 于 2019-4-27 00:34 编辑

24xx EEPROM芯片有一个间隔时间(有可能叫写周期,具体查下手册),前一次停止位到下一次的起始位之间需要延时,最大5ms。
在个器件手册中都有这个参数。
页写完后,必然会有一次停止位。那么在下次页写前,需要加个延时。根据实际测试情况,这个延时有可能比5ms小,最短的可能延时1ms都够用。如果加5ms延时,那么对于各厂家的24xx系列EEPROM都适用。

评分

参与人数 1蝴蝶豆 +3 收起 理由
STMCU + 3

查看全部评分

废鱼 回答时间:2019-4-27 08:59:04
楼主,多页写入时,每次只能写入一页,需要多次写入。

评分

参与人数 1蝴蝶豆 +2 收起 理由
STMCU + 2

查看全部评分

STM1024 回答时间:2019-4-27 10:21:12
你在写之前有没有做check Busy呢?或者调试一下,看看EV的值,在翻页的时候是否会有变化?

评分

参与人数 1蝴蝶豆 +2 收起 理由
STMCU + 2

查看全部评分

wdshuang09 回答时间:2019-4-27 20:43:07
toofree 发表于 2019-4-27 00:32
24xx EEPROM芯片有一个间隔时间(有可能叫写周期,具体查下手册),前一次停止位到下一次的起始位之间需要 ...

每写完一页都有延时10ms,
wdshuang09 回答时间:2019-4-27 20:57:20
stm1024 发表于 2019-4-27 10:21
你在写之前有没有做check Busy呢?或者调试一下,看看EV的值,在翻页的时候是否会有变化? ...

有检测I2C总结的忙标识
DavidTan 回答时间:2019-4-28 11:11:05
你在写超过32个字节的数据时要把数据拆分开,不仅仅是每次只能写入32字节,而且写入地址也要跟着变,因为24C32一次只能写入32字节

评分

参与人数 1蝴蝶豆 +2 收起 理由
STMCU + 2

查看全部评分

wdshuang09 回答时间:2019-4-28 16:20:07
tgw860910 发表于 2019-4-28 11:11
你在写超过32个字节的数据时要把数据拆分开,不仅仅是每次只能写入32字节,而且写入地址也要跟着变,因为24 ...

这些都知道,问题不是出在这,
1.jpg
废鱼 回答时间:2019-4-28 21:38:28
楼主,我们使用过程中,都是每一页进行一次写入操作。要重新开始,保证E2重新收到了新的页地址。
wdshuang09 回答时间:2019-4-29 08:02:43
安 发表于 2019-4-28 21:38
楼主,我们使用过程中,都是每一页进行一次写入操作。要重新开始,保证E2重新收到了新的页地址。 ...

把你的程序发出来看看,我都折腾了好多天了, 怀疑是我写完一页后中断事件处理有点问题,
废鱼 回答时间:2019-4-29 08:47:50
wdshuang09 发表于 2019-4-29 08:02
把你的程序发出来看看,我都折腾了好多天了, 怀疑是我写完一页后中断事件处理有点问题, ...

楼主你好,我只能提供思路,解决方法。代码肯定不能共享的。网上有很多例程,你可以随便参考。
wdshuang09 回答时间:2019-4-29 13:59:12
安 发表于 2019-4-29 08:47
楼主你好,我只能提供思路,解决方法。代码肯定不能共享的。网上有很多例程,你可以随便参考。 ...

"保证E2重新收到了新的页地址",
这个E2是指?就这一小部分程序是怎么实现的,中断里是检测什么EV事件
废鱼 回答时间:2019-4-29 17:48:19
每次只写一页,写完以后,重新开始写入操作。

评分

参与人数 1蝴蝶豆 +1 收起 理由
STMCU + 1

查看全部评分

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版