打印

奇怪! 请教香版I2C的时钟问题

[复制链接]
3649|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
myfaith|  楼主 | 2010-6-28 16:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
使用I2C遇到问题,使用8M晶,SYSTEM CLOCK=72M , PCLK1=36M,
当使用I2C在400K时工作不正常,通信读写几次就死掉了,追逐发现是I2C_ADDR_MATCH_ERR,也就是发出地址后器件ACK超时.
仔细查阅手册,发现手册言:
FPCLK1 is the multiple of 10 MHz required to generate the Fast clock at 400 kHz.

我做了以下测试:
I2C设置为100K,长时间读写测试正常,110K也正常,150K正常,180K出错,200K出错.250K出错,350K出错,

请问香板,
1) I2C工作在400K的频率时才需要PCLK是10M的整数倍,还是工作在fast模式时也有此要求?
2) 为什么要求PCLK是10M的整数倍?不是10M的PCLK也完全可以通过通过I2C_CRR寄存器设置分频系数产生400K的SCK啊! 而且即使不能分频产生400K整SCK,I2C作为同步通信有工作在任意频率应该都没关系啊.
3) 按照我现在的时钟配置,I2C能正常工作的最大速度有没有计算方**
谢谢!
沙发
香水城| | 2010-6-28 18:58 | 只看该作者
速度慢时,程序中的延迟不会影响通信;但速度快时,就需要仔细考虑好程序中的延迟问题。

使用特权

评论回复
板凳
myfaith|  楼主 | 2010-6-29 09:48 | 只看该作者
速度慢时,程序中的延迟不会影响通信;但速度快时,就需要仔细考虑好程序中的延迟问题。
香水城 发表于 2010-6-28 18:58

采用查询的方式,等待EVT事件超时时间设置固定为100个SCK时钟,所以应该与程序快慢(主频)无关.

使用特权

评论回复
地板
ST_ARM| | 2010-6-29 21:02 | 只看该作者
请将你的代码贴出来,我发现很多客户在用STM32写程序时,有一些不合理的地方。

使用特权

评论回复
5
myfaith|  楼主 | 2010-6-30 00:55 | 只看该作者
请将你的代码贴出来,我发现很多客户在用STM32写程序时,有一些不合理的地方。
ST_ARM 发表于 2010-6-29 21:02

根据官方EEPROM例程修改而来,如发送程序:
   /*wait 5us min for bus free time limitation for later transaction*/
   SetDelayTime_us(5);
   while(!TOFlag);
    StopDelayCount();          //SysTick_CounterCmd(SysTick_Counter_Disable);
    TOFlag = FALSE;   

    /*wait bus free*/
   SetDelayTime_us(BUS_BUSY_TIMEOUT);
    while((I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY))&&(!TOFlag));
    StopDelayCount();          //SysTick_CounterCmd(SysTick_Counter_Disable);
    if (TOFlag)
    {
      TOFlag = FALSE;
      return I2C_BUS_BUSY;
    }
    /*send start and wait*/
    I2C_GenerateSTART(I2Cx, ENABLE);
   
   SetDelayTime_us(SEND_START_TIMEOUT);
    while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT) || TOFlag));   //wait BUSY,MSL,SB to be set
    StopDelayCount();            //SysTick_CounterCmd(SysTick_Counter_Disable);
    if (TOFlag)
    {
      TOFlag = FALSE;
      return I2C_SEND_START_ERR;
    }  
    /* send 7-bit slave address and wait */
    I2C_Send7bitAddress(I2Cx, (u8)(slaveaddr & 0xFF), I2C_Direction_Transmitter);

   SetDelayTime_us(SEND_ADDR7_TIMEOUT);
    while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) || TOFlag));  //Wait BUSY/MSL/ADDR/TxE/TRA to be set
    StopDelayCount();            //SysTick_CounterCmd(SysTick_Counter_Disable);
    if (TOFlag)
    {
      TOFlag = FALSE;
      I2C_GenerateSTOP(I2Cx, ENABLE);
      while ((I2Cx->CR1 & 0x200) == 0x200);   //wait while STOP bit not cleared
      if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
        I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
      return I2C_ADDR_MATCH_ERR;
I2C_SendData(I2Cx, *pBuffer++);
    length--;
    while (length--)
    {
        SetDelayTime_us(SEND_DATA_TIMEOUT);     
        while (((I2C_GetLastEvent(I2Cx) & 0x04) != 0x04)&&(!TOFlag));  //Wait BTF to be set
     // while (((I2C_GetLastEvent(I2Cx) & 0x80) != 0x80));//&&(!TOFlag));
        StopDelayCount();     
        if (TOFlag)
        {
          TOFlag = FALSE;
          I2C_GenerateSTOP(I2Cx, ENABLE);
          while ((I2Cx->CR1 & 0x200) == 0x200);
          if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
            I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
          return I2C_DATA_TIMEOUT;
        }
        I2C_SendData(I2Cx, *pBuffer++);
    }
      SetDelayTime_us(SEND_DATA_TIMEOUT);
    while (!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) || TOFlag));
   StopDelayCount();   
    if (TOFlag)
    {
      TOFlag = FALSE;
      I2C_GenerateSTOP(I2Cx, ENABLE);
      while ((I2Cx->CR1 & 0x200) == 0x200);
      if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
        I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
      return I2C_DATA_TIMEOUT;
    }
    /* send stop to close communication */
    I2C_GenerateSTOP(I2Cx, ENABLE);
能不能回答一下我1楼提出的那三个问题?
还有感觉I2C设计的怪怪的,接收时不能在从DR寄存器读取字节后立即产生NAK或STOP,而是必须再接收至少三个字节,也就是手册上所说的读n字节时序:
(n-2)BTF后发NAK -> 读(n-2) -> 发STOP -> 读(n-1) -> 等待RxNE -> 读n),
这对于已知要读取的长度的数据好处理,可以在结束前三个字节时开始处理NAK,STOP,而对于需要根据接收的数据来判断是否继续接收,假如根据一定的协议从DR读出接收到的字节指明接收结束,则后续发出NAK和STOP就会必须多读3个字节才结束.这在某些时候会导致问题,比如本来后面的数据要下次读的而你本次为了发出NAK和STOP就多读了3个,那下次读可能就丢失了3个数据.

    }

使用特权

评论回复
6
ST_ARM| | 2010-6-30 14:48 | 只看该作者
if (TOFlag)
    {
      TOFlag = FALSE;
      I2C_GenerateSTOP(I2Cx, ENABLE);
      while ((I2Cx->CR1 & 0x200) == 0x200);   //wait while STOP bit not cleared
      if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
        I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
      return I2C_ADDR_MATCH_ERR;
^^^^^^^^^^^^^^^^^^^^^^^^^这里好像漏了一个“}”

I2C_SendData(I2Cx, *pBuffer++);
    length--;
    while (length--)
    {

使用特权

评论回复
7
myfaith|  楼主 | 2010-6-30 16:53 | 只看该作者
if (TOFlag)
    {
      TOFlag = FALSE;
      I2C_GenerateSTOP(I2Cx, ENABLE);
      while ((I2Cx->CR1 & 0x200) == 0x200);   //wait while STOP bit not cleared
      if(I2C_GetFlagStatus(I2Cx, I2C_FLAG ...
ST_ARM 发表于 2010-6-30 14:48

因为我分两次粘贴的所以后面的{被弄丢了.
语法问题不是问题所在,先帮我解答一下我在以上各楼的问题吧

使用特权

评论回复
8
myfaith|  楼主 | 2010-7-1 13:00 | 只看该作者
没回应了........我的问题这么难....>

使用特权

评论回复
9
香水城| | 2010-7-1 13:07 | 只看该作者
没回应了........我的问题这么难....>
myfaith 发表于 2010-7-1 13:00


确实很难,因为我们不知道STM32在与哪个设备通信? 也无法知道为什么发出地址后器件ACK超时?你是否看过这个器件的手册,它是否支持这么高的速度?

使用特权

评论回复
10
ST_ARM| | 2010-7-1 13:09 | 只看该作者
仔细看了一下你的代码,流程上好像不对,不知道是不是由于漏了“}”造成的。如果"}"没有漏,你测试时,“I2C设置为100K,长时间读写测试正常,110K也正常,150K正常,180K出错,200K出错.250K出错,350K出错”是什么原因导致的,就很难说了。
关于你的三个问题:
1) I2C工作在400K整的频率时才需要PCLK是10M的整数倍,还是工作在fast模式时也有此要求?
答: I2C工作在400K整的频率,就是FAST模式了。需要PCLK是10M的整数倍。

2) 为什么要求PCLK是10M的整数倍?不是10M的PCLK也完全可以通过通过I2C_CRR寄存器设
置分频系数产生400K的SCK啊! 而且即使不能分频产生400K整SCK,I2C作为同步通信有工作在
任意频率应该都没关系啊.
答:手册上要求你这样设置,自然有其道理,你就按照要求操作就是了。

3) 按照我现在的时钟配置,I2C能正常工作的最大速度有没有计算方方法?
答:按照你现在的时钟配置,你将FCLK设为395KHz试一试。只要不是10的整数倍。

使用特权

评论回复
11
myfaith|  楼主 | 2010-7-1 18:17 | 只看该作者
感谢回复~

回9楼香版,与STM32通信的器件是支持400K的.不是一开始就出错,而是来回几个回合后出错.

回10楼ST_ARM,{号是真没漏.漏了岂不编译都通不过了?
你回答的第1个问题还是没有答案,我知道400K属于快速模式,我想知道的是10M整数倍的时钟要求是对包括400K在内的整个快速模式适用还是只对400K整适用而快速模式下其它速度不适用?我这么说应该表达的很清晰了吧

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

68

主题

468

帖子

0

粉丝