打印

STM32 I2C 问题

[复制链接]
楼主: shizaigaole
手机看帖
扫描二维码
随时随地手机跟帖
21
shizaigaole|  楼主 | 2010-7-15 15:00 | 只看该作者 回帖奖励 |倒序浏览
按道理,设置停止操作以后,
stm32硬件知道了这个时间,就不应该还继续发生I2C_EVENT_MASTER_BYTE_TRANSMITTED时间,
从而导致反复进中断

使用特权

评论回复
22
shizaigaole|  楼主 | 2010-7-15 15:04 | 只看该作者
哇哇哇!

为什么你6楼的能够正确运行呢。因为:

当代码进入,0x70084(transmitted,i2cEventGroup[10])时,总线上已经被要写的数据全部发送出去了。在这个case里,你的代码执行发送STOP的操作,然后通过你的while(I ...
lut1lut 发表于 2010-7-15 14:13



再次写的时候,
在发启动条件之前,有专门的长时间延时等待,
和此处的中断状态改变等待没有关系

使用特权

评论回复
23
shizaigaole|  楼主 | 2010-7-15 15:13 | 只看该作者
最后调通的中断部分代码如下:

void I2C1_EV_IRQHandler(void)
{   
  i2cEvent = I2C_GetLastEvent(I2C1);
  i2cEventGroup[i2cEventCounter++] = i2cEvent;
  switch (i2cEvent)
  {
    case I2C_EVENT_MASTER_MODE_SELECT:                 /* EV5 */
      
      if(Direction == Transmitter)
      {
        I2C_Send7bitAddress(I2C1, destAddr, I2C_Direction_Transmitter);
      }
      else
      {
        I2C_Send7bitAddress(I2C1, destAddr, I2C_Direction_Receiver);
      }
      
      break;
        
    case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:  
      
      I2C_SendData(I2C1, i2cSendBuf[i2cSendCount++]);
      if(i2cSendLen == 1)
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
        
      break;

  case I2C_EVENT_MASTER_BYTE_TRANSMITTING:  /* Without BTF, EV8 */     
      if(i2cSendCount < i2cSendLen - 1)
      {
        I2C_SendData(I2C1, i2cSendBuf[i2cSendCount++]);
      }
      else
      {
        I2C_SendData(I2C1, i2cSendBuf[i2cSendCount++]);
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
      }        
      break;

    case I2C_EVENT_MASTER_BYTE_TRANSMITTED: /* With BTF EV8-2 */
        if(bSubMenu_Rd == 0)
        {
          I2C_GenerateSTOP(I2C1, ENABLE);
          while(I2C_GetLastEvent(I2C1) == I2C_EVENT_MASTER_BYTE_TRANSMITTED)
            ;
          wrTaskState = 3;
        }
        else
        {
          Direction = Receiver;
          I2C_GenerateSTART(I2C1, ENABLE);
          while(I2C_GetLastEvent(I2C1) == I2C_EVENT_MASTER_BYTE_TRANSMITTED)
            ;
        }
        I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE);
      break;

    /* Master Receiver -------------------------------------------------------*/
    case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:
      if(i2cRevLen == 1)
      {
        I2C_AcknowledgeConfig(I2C1, DISABLE);
        I2C_GenerateSTOP(I2C1, ENABLE);
      }
      break;

   case I2C_EVENT_MASTER_BYTE_RECEIVED:
     i2cRevBuf[i2cRevCount++] = I2C_ReceiveData (I2C1);
     if(i2cRevCount == (i2cRevLen - 1))
     {
       I2C_AcknowledgeConfig(I2C1, DISABLE);
       I2C_GenerateSTOP(I2C1, ENABLE);
     }
     else if(i2cRevCount == i2cRevLen)
     {
       rdTaskState = 3;
     }
     else
       ;
     break;

    default:
      break;
  }

}


大家帮看看为什么不阻止产生多个I2C_EVENT_MASTER_BYTE_TRANSMITTED中断,
会有影响?

使用特权

评论回复
24
lut1lut| | 2010-7-15 15:13 | 只看该作者
LZ,你每次在0x70084(BTF,TXE)的case才发送数据,比在0x70080(TXE)中发送数据,要慢些耶。而且后者就不会有那些多余的0x70084。

你要是实在不想多次进入0x70084,可以在判断发送完毕了,发送STOP后,关闭I2C_IT_BUF中断么,这样BTF标志触发的中断就不回产生了。;P

使用特权

评论回复
25
shizaigaole|  楼主 | 2010-7-15 15:19 | 只看该作者
数据都是在0x70080事件中发送的,
stop是在0x70084中发送的。

使用特权

评论回复
26
shizaigaole|  楼主 | 2010-7-15 15:28 | 只看该作者
按照24楼lut1lut的方法试验了一下,
不加状态改变等待,程序也正常!

但是0x70084还是会发生多个!

奇怪啊,奇怪!

使用特权

评论回复
27
shizaigaole|  楼主 | 2010-7-15 15:31 | 只看该作者
看来按照手册或者库里面的例子写程序,
还是有些问题的!

使用特权

评论回复
28
shizaigaole|  楼主 | 2010-7-15 15:32 | 只看该作者
本帖最后由 shizaigaole 于 2010-7-15 15:34 编辑

按照ut1lut的方法改过的程序中断代码入下:
void I2C1_EV_IRQHandler(void)
{   
  i2cEvent = I2C_GetLastEvent(I2C1);
  i2cEventGroup[i2cEventCounter++] = i2cEvent;
  switch (i2cEvent)
  {
    case I2C_EVENT_MASTER_MODE_SELECT:                 /* EV5 */
      
      if(Direction == Transmitter)
      {
        I2C_Send7bitAddress(I2C1, destAddr, I2C_Direction_Transmitter);
      }
      else
      {
        I2C_Send7bitAddress(I2C1, destAddr, I2C_Direction_Receiver);
      }
      
      break;
        
    case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:  
      
      I2C_SendData(I2C1, i2cSendBuf[i2cSendCount++]);
      if(i2cSendLen == 1)
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
        
      break;

  case I2C_EVENT_MASTER_BYTE_TRANSMITTING:  /* Without BTF, EV8 */     
      if(i2cSendCount < i2cSendLen)
      {
        I2C_SendData(I2C1, i2cSendBuf[i2cSendCount++]);
      }
      else
      {
        I2C_GenerateSTOP(I2C1, ENABLE);
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
      }
        
      break;

    case I2C_EVENT_MASTER_BYTE_TRANSMITTED: /* With BTF EV8-2 */
        if(bSubMenu_Rd == 0)
        {
          wrTaskState = 3;
        }
        else
        {
          Direction = Receiver;
          I2C_GenerateSTART(I2C1, ENABLE);
        }
        I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE);
      break;

    /* Master Receiver -------------------------------------------------------*/
    case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:
      if(i2cRevLen == 1)
      {
        I2C_AcknowledgeConfig(I2C1, DISABLE);
        I2C_GenerateSTOP(I2C1, ENABLE);
      }
      break;

   case I2C_EVENT_MASTER_BYTE_RECEIVED:
     i2cRevBuf[i2cRevCount++] = I2C_ReceiveData (I2C1);
     if(i2cRevCount == (i2cRevLen - 1))
     {
       I2C_AcknowledgeConfig(I2C1, DISABLE);
       I2C_GenerateSTOP(I2C1, ENABLE);
     }
     else if(i2cRevCount == i2cRevLen)
     {
       rdTaskState = 3;
     }
     else
       ;
     break;

    default:
      break;
  }

}

使用特权

评论回复
29
shizaigaole|  楼主 | 2010-7-15 15:34 | 只看该作者
不知其所以然!

使用特权

评论回复
30
lut1lut| | 2010-7-15 15:58 | 只看该作者
不是,我让你在0x70080里面发送数据,并且在判断发送了最后一个数据后发送STOP。

你的这个实现,咋能做到发送完最后一个数据后,不退出该case,接着就发送STOP,并且关闭BUF中断哪。

case I2C_EVENT_MASTER_BYTE_TRANSMITTING:  /* Without BTF, EV8 */     
      if(i2cSendCount < i2cSendLen)
      {
        I2C_SendData(I2C1, i2cSendBuf[i2cSendCount++]);
      }
      else
      {
        I2C_GenerateSTOP(I2C1, ENABLE);
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
      }
        
      break;

使用特权

评论回复
31
shizaigaole|  楼主 | 2010-7-15 16:10 | 只看该作者
你说的是这样吗?

  case I2C_EVENT_MASTER_BYTE_TRANSMITTING:  /* Without BTF, EV8 */     
      if(i2cSendCount < i2cSendLen - 1)
      {
        I2C_SendData(I2C1, i2cSendBuf[i2cSendCount++]);
      }
      else if(i2cSendCount == i2cSendLen - 1)
      {
        I2C_SendData(I2C1, i2cSendBuf[i2cSendCount++]);
        I2C_GenerateSTOP(I2C1, ENABLE);
        I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE);
      }
      else
        ;

这样不行啊,程序运行不下去,
发生不了0x70084中断

使用特权

评论回复
32
lut1lut| | 2010-7-15 16:17 | 只看该作者
哇哇哇,你参考下我那个I2C库中的中断实现里面,各个case的处理,好伐?

使用特权

评论回复
33
shizaigaole|  楼主 | 2010-7-15 16:32 | 只看该作者
你的程序:

      if ((SR1Register &0x0084) == 0x0080)
        {
            /* If there is still data to write */
            if (NumbOfBytes1!=0)
            {
                /* Write the data in DR register */
                I2C1->DR = Buffer_Tx1[Tx_Idx1++];
                /* Decrment the number of data to be written */
                NumbOfBytes1--;
                /* If  no data remains to write, disable the BUF IT in order
                to not have again a TxE interrupt. */
                if (NumbOfBytes1 == 0)
                {
                    /* Disable the BUF IT */
                    I2C1->CR2 &= (uint16_t)~I2C_IT_BUF;
                }
            }
            SR1Register = 0;
            SR2Register = 0;
        }
        /* If BTF and TXE are set (EV8_2), program the STOP */
        if ((SR1Register &0x0084) == 0x0084)
        {

            /* Program the STOP */
            I2C1->CR1 |= CR1_STOP_Set;
            /* Disable EVT IT In order to not have again a BTF IT */
            I2C1->CR2 &= (uint16_t)~I2C_IT_EVT;
            SR1Register = 0;
            SR2Register = 0;
        }

没有0x70080中发stop,
是在0x70084中发stop

使用特权

评论回复
34
shizaigaole|  楼主 | 2010-7-15 16:33 | 只看该作者
本帖最后由 shizaigaole 于 2010-7-15 16:34 编辑

你的程序和库例子处理差不多啊,
不过
case结构改成了平行if结构

使用特权

评论回复
35
luckytoad| | 2010-7-15 16:44 | 只看该作者
强烈建议放弃STM32的I2C,改用模拟的。我测试了各种方式中断 DMA 查询方式,做了无数试验,废了8天时间(我消化整理整个STM32才用了3周,包括编各个模块驱动),总是感觉有问题,而且出现问题,有点束手无策,改用模拟方式,简单、可靠、实用、一切皆可控。实在不是很理解ST,为什么自己把自己搞里面了。通讯里面I2C本来时序是最简单的了。

使用特权

评论回复
36
shizaigaole|  楼主 | 2010-7-15 16:52 | 只看该作者
那道没必要。
硬件模块比模拟高效很多。

我的程序现在也很正常。只是不知其中的原因。
而且我用NXP ARM,PIC,不论主从,从来都不模拟,直接使用模块。

要是用STM32不能使用模块,
我会非常难受。

除非我是在没办法了。

但目前看来还好

使用特权

评论回复
37
lut1lut| | 2010-7-15 16:56 | 只看该作者
哇哇哇,这个才是我的:

void i2c1_evt_isr()
{  
  switch (I2C_GetLastEvent(I2C1))
    {
/************************** Master Invoke**************************************/
          case I2C_EVENT_MASTER_MODE_SELECT:        /* EV5 */
            // MSL SB BUSY 30001
            if(!check_begin)
              i2c_comm_state = COMM_IN_PROCESS;
            
              if (Direction == Receiver)
              {
                if (DeviceOffset != 0xffffffff)
                  I2C_Send7bitAddress(I2C1, SlaveADDR, I2C_Direction_Transmitter);   
                else
                  /* Send slave Address for read */
                  I2C_Send7bitAddress(I2C1, SlaveADDR, I2C_Direction_Receiver);      
              }
              else
              {
                  /* Send slave Address for write */
                  I2C_Send7bitAddress(I2C1, SlaveADDR, I2C_Direction_Transmitter);
              }
              I2C_ITConfig(I2C1, I2C_IT_BUF , ENABLE);//also TxE int allowed
              break;
              
/********************** Master Receiver events ********************************/
          case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:  /* EV6 */
            // MSL BUSY ADDR 0x30002
              if (RxLength == 1)
              {
                  /* Disable I2C1 acknowledgement */
                  I2C_AcknowledgeConfig(I2C1, DISABLE);
                  /* Send I2C1 STOP Condition */
                  I2C_GenerateSTOP(I2C1, ENABLE);
              }
              break;
      
          case I2C_EVENT_MASTER_BYTE_RECEIVED:    /* EV7 */
            // MSL BUSY RXNE 0x30040
              /* Store I2C1 received data */
              *pRxBuffer1++ = I2C_ReceiveData (I2C1);   
              RxLength--;
              /* Disable ACK and send I2C1 STOP condition before receiving the last data */
              if (RxLength == 1)
              {
                  /* Disable I2C1 acknowledgement */
                  I2C_AcknowledgeConfig(I2C1, DISABLE);
                  /* Send I2C1 STOP Condition */
                  I2C_GenerateSTOP(I2C1, ENABLE);     
              }
      
              if (RxLength == 0)
              {                  
                MasterReceptionComplete = 1;      
                i2c_comm_state = COMM_DONE;
                PV_flag_1 = 0;
              }
              break;
      
      
      
/************************* Master Transmitter events **************************/
          case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:     /* EV8 just after EV6 */
            //BUSY, MSL, ADDR, TXE and TRA 0x70082
              if (check_begin)
              {
                check_begin = FALSE;
                WriteComplete = 1;
                i2c_comm_state = COMM_DONE;
                I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF |I2C_IT_ERR, DISABLE);
                I2C_GenerateSTOP(I2C1, ENABLE);
                PV_flag_1 = 0;
                break;
              }
              
              if (DeviceOffset != 0xffffffff)
                I2C_SendData(I2C1, DeviceOffset);
              else
              {
                I2C_SendData(I2C1, *pTxBuffer1++);
                TxLength--;
              }
              break;
              
          case I2C_EVENT_MASTER_BYTE_TRANSMITTING:       /* EV8 */
            //TRA, BUSY, MSL, TXE 0x70080
              if (Direction == Receiver)
              {
                DeviceOffset = 0xffffffff; // enter read-phase 2 (the same as no memory space)
                I2C_ITConfig(I2C1, I2C_IT_BUF , DISABLE);
                while ((I2C1->CR1 & 0x200) == 0x200);
                I2C_GenerateSTART(I2C1, ENABLE);
                break;
              }
              
              if (TxLength >0)
              {
                  I2C_SendData(I2C1, *pTxBuffer1++);      
                  TxLength--;
              }
              /* Disable the I2C_IT_BUF interrupt after sending the last buffer data
              (last EV8) to no allow a new interrupt with TxE and only BTF could generate it */
              else if(TxLength == 0)
              {
                I2C_ITConfig(I2C1,  I2C_IT_BUF, DISABLE);
                I2C_GenerateSTOP(I2C1, ENABLE);              }
              break;
      
          case I2C_EVENT_MASTER_BYTE_TRANSMITTED:       /* EV8-2 */
            //TRA, BUSY, MSL, TXE and BTF 0x70084
            if (Direction == Transmitter)
            {
              MasterTransitionComplete = 1;
              I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE);
              // enable AF and SB and ADDR interrupt
              I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_ERR, ENABLE);
              check_begin = TRUE;
              i2c_comm_state = CHECK_IN_PROCESS;
              //while ((I2C1->CR1 & 0x200) == 0x200);
                if(I2C1->CR1 & 0x200)
                  I2C1->CR1 &= 0xFDFF;
              I2C_GenerateSTART(I2C1, ENABLE);
              break;
            } else
            {
              break;
            }
/********************** Slave Transmitter Events ******************************/
    case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:  /* EV1 */
      //TRA, BUSY, TXE and ADDR 0x60082
      i2c_comm_state = COMM_IN_PROCESS;
      
        I2C_SendData(I2C1, *pTxBuffer1++);
        TxLength--;
        I2C_ITConfig(I2C1, I2C_IT_BUF , ENABLE); // also allow TxE
        break;

    case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:          /* EV3 */
      //TRA, BUSY, TXE and BTF  0x60084
        if (TxLength>0)
        {
            I2C_SendData(I2C1, *pTxBuffer1++);
            TxLength--;
        }
        break;

    case 0x60080:
      // TRA, BUSY,TXE, no BTF
      // if this case added, above case would never be reached
      if (TxLength>0)
        {
            I2C_SendData(I2C1, *pTxBuffer1++);
            TxLength--;
            if (TxLength ==0)
            {
              SlaveTransitionComplete =1;
              i2c_comm_state = COMM_DONE;
              I2C_ITConfig(I2C1, I2C_IT_BUF , DISABLE);//close TxE int
              I2C_ITConfig(I2C1, I2C_IT_ERR , ENABLE);//to handle AF from master receiver
              PV_flag_1 = 0;
            }
        }
      
      break;   
      
/************************ Slave Receiver Events *******************************/
    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:         /* EV1 */
      // BUSY ADDR 0x20002
      i2c_comm_state = COMM_IN_PROCESS;
      
      I2C_ITConfig(I2C1, I2C_IT_BUF , ENABLE); // also allow RxNE
        break;

    case I2C_EVENT_SLAVE_BYTE_RECEIVED:              /* EV2 */
      // BUSY RxNE 0x20040
        *pRxBuffer1++ = I2C_ReceiveData(I2C1);
        RxLength--; // controled by i2c1 sender
        
        if (RxLength == 0)
        {
            SlaveReceptionComplete = 1;
            I2C_ITConfig(I2C1, I2C_IT_BUF , DISABLE); // only EVT(STOPF) int
            I2C_ITConfig(I2C1, I2C_IT_EVT , ENABLE);
        }
        break;


    case I2C_EVENT_SLAVE_STOP_DETECTED:             /* EV4 */
      // STOPF 0x10
        /* Clear I2C2 STOPF flag: read of I2C_SR1 followed by a write in I2C_CR1 */
        (void)(I2C_GetITStatus(I2C1, I2C_IT_STOPF));
        I2C_Cmd(I2C1, ENABLE);
        i2c_comm_state = COMM_DONE;
        PV_flag_1 = 0;
        //I2C_ITConfig(I2C2, I2C_IT_EVT, DISABLE);
        break;
    case 0x20050:
      // used when Rx and Tx handley by one mcu at the same time
      // receive last data and clear stopf
        *pRxBuffer1++ = I2C_ReceiveData(I2C1);
        RxLength--;
        SlaveReceptionComplete = 1;

        (void)(I2C_GetITStatus(I2C1, I2C_IT_STOPF));
        I2C_Cmd(I2C1, ENABLE);
        I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE);
        I2C_ITConfig(I2C1, I2C_IT_BUF , DISABLE);
        break;
        
    case 0x20010:
      // busy+stopf
      // when last data read isr exist, there would be stopf flag
      //which is set during read ISR. and as sender's check begin
      // busy also set
      i2c_comm_state = CHECK_IN_PROCESS;
      (void)(I2C_GetITStatus(I2C1, I2C_IT_STOPF));
        I2C_Cmd(I2C1, ENABLE);
        break;   
        
/******************************* default Events *******************************/
     default:
       break;
      }  
}

void i2c1_err_isr()
{
    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF))
    {
      if (check_begin)
        I2C_GenerateSTART(I2C1, ENABLE);
      else if (I2C1->SR2 &0x01)
      {
        I2C_GenerateSTOP(I2C1, ENABLE);
        i2c_comm_state = COMM_EXIT;
        PV_flag_1 = 0;
      }
      
        I2C_ClearFlag(I2C1, I2C_FLAG_AF);
    }

    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_BERR))
    {
      if (I2C1->SR2 &0x01)
      {
        I2C_GenerateSTOP(I2C1, ENABLE);
        i2c_comm_state = COMM_EXIT;
        PV_flag_1 = 0;
      }
      
      I2C_ClearFlag(I2C1, I2C_FLAG_BERR);
    }
}

使用特权

评论回复
38
shizaigaole|  楼主 | 2010-7-15 16:56 | 只看该作者
本帖最后由 shizaigaole 于 2010-7-15 16:57 编辑

而且,不论哪种芯片,其I2C模块都比IO模拟难用一点。

使用I2C和用C类似,需要一点整体抽象思维。
要是受汇编影响过多的,
一般用不好I2C模块,原因在于他们掌控不了细节,不放心

使用特权

评论回复
39
shizaigaole|  楼主 | 2010-7-15 16:58 | 只看该作者
37# lut1lut

呵呵,以为你是ST的人了

使用特权

评论回复
40
lut1lut| | 2010-7-15 17:01 | 只看该作者
;P;P;P:shutup:

使用特权

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

本版积分规则