搜索
bottom↓
回复: 46

STM32_I2C,不稳定,死在I2C_CheckEvent解决办法

[复制链接]

出0入0汤圆

发表于 2011-6-6 07:39:51 | 显示全部楼层 |阅读模式
主设备:STM32F103C8T6
从设备:AT24C02
看见很多人用都出现死在I2C_CheckEvent,或经常不稳定
很多时候是死在AF标志上,在发送完后从设备如果一定时间内不返回ACK,STM32_I2C就置位AF不应答标志
用示波器测了下,带库时偶尔收到ACK,说明通讯有问题
例如
发送器件地址流程是:START->DEVICE_ADDRESS->ACK
因为用了固件库START跟DEVICE_ADDRESS时序会出现偏差,结果从设备偶尔能收到正确数据,偶尔返回ACK造成不稳定
如果ACK一段时间没返回主设备马上AF。。结果经常死在I2C_CheckEvent
解决办法:
一:不要用库,每一段START->ACK尽量写短,写简洁!
二:降低I2C速度!我测试在10KHZ时很稳定,20KHZ非常少,不稳定,50KHZ几乎不稳定

还有一种是中途传输字节,某些原因,主设备复位!结果I2C总线锁死,这种问题另外谈!

带库测试函数:
void I2C_EE_WaitEepromStandbyState(I2C_TypeDef *I2Cx,u8 EEPROM_Addr)
{
  vu16 SR1_Tmp = 0;
  while(1){
          do
          {          
    /* Send START condition */
    //I2C_GenerateSTART(I2Cx, ENABLE);
          
    /* Send EEPROM address for write */
    //I2C_Send7bitAddress(I2Cx, EEPROM_Addr, I2C_Direction_Transmitter);//EEPROM_Addr=0xA0
    }while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件
   }         
  /* Clear AF flag */
  I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
}

不带库测试:
void I2C_EE_WaitEepromStandbyState(I2C_TypeDef *I2Cx,u8 EEPROM_Addr)
{
  vu16 SR1_Tmp = 0;
  while(1){
          do
          {          
     /* Send START condition */
     I2Cx->CR1 |= 0x0100;

     /* Send EEPROM address for write */
     I2Cx->DR = EEPROM_Addr&0xFFFE;);//EEPROM_Addr=0xA0
    }while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件
   }         
  /* Clear AF flag */
  I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
}
下面是带库测试图:
细心看,发送器件地址0xA0,有时不能收到ACK,(长低最后那部分那尖刺就是ACK)

(原文件名:I2C-10KHZ带库.jpg)


(原文件名:I2C-50KHZ带库.jpg)


(原文件名:I2C-60KHZ带库.jpg)


(原文件名:I2C―50KHZ带库1.jpg)


(原文件名:I2C―50KHZ带库.jpg)


(原文件名:I2C―100KHZ带库1.jpg)


(原文件名:I2C―100KHZ带库2.jpg)


(原文件名:I2C―100KHZ带库3.jpg)


(原文件名:I2C―100KHZ带库4.jpg)


(原文件名:I2C―100KHZ带库.jpg)


不带库测试图:

(原文件名:I2C―50KHZ不带库.jpg)


(原文件名:I2C―100KHZ不带库1.jpg)


(原文件名:I2C―100KHZ不带库.jpg)

出0入12汤圆

发表于 2011-6-6 08:06:38 | 显示全部楼层
已改用模拟
官方说法就是DMA解决

出0入0汤圆

 楼主| 发表于 2011-6-6 08:14:04 | 显示全部楼层
又DMA又中断。。。根本不用干什么事了!

出0入12汤圆

发表于 2011-6-6 08:20:39 | 显示全部楼层
降低I2C速度!我测试在10KHZ时很稳定,20KHZ非常少,不稳定,50KHZ几乎不稳定

这个速度太....
最龟速的I2C也要100K吧?

出0入0汤圆

 楼主| 发表于 2011-6-6 08:33:35 | 显示全部楼层
100KHZ那就不要用库。。用库很容易挂。。用库有ns的时序误差!速度越快时丢包率越大
我看别人100KHZ都能用。。我这AT24C02要是用库100KHZ偶尔稳定。完全靠运气,难道我芯片有问题?
其实也不难用,只要保证START->ACK稳定就OK了,这两天调试,大部分是死在ACK无应答
我这EEPROM只是保存一些设置,不频繁,100字节10MS时间,还是能接受的!只要够稳定就行了!
打算不带库写个查询方式,带超时的来!对于AT24C02足够了!

出0入0汤圆

发表于 2011-6-6 12:42:07 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-7 01:22:00 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-13 21:33:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-18 22:57:02 | 显示全部楼层
mark,我以前也遇到这问题

主要就是初始化

出0入0汤圆

发表于 2011-6-19 09:26:49 | 显示全部楼层
这个太好了

出0入0汤圆

发表于 2011-6-19 17:31:05 | 显示全部楼层
目前使用OLED I2C,400K的速度都没问题,但是就是读出现问题。读不出来。

出0入0汤圆

发表于 2011-6-20 11:53:08 | 显示全部楼层
改用时间间隔查询标志位,再加一个读时用DMA的方法可以去到400K,目前产品使用了半年还没有发现问题
switch(step)
{
case 0:
    if(!I2C_GetFlagStatus(I2CC, I2C_FLAG_BUSY))
    {
    step = 1;
   }
else
   {
   err++;//错误次数加1
   }
  break;
case 1:
                  /* Test on EV5 and clear it */
                  if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
                          {
                          /* Send EEPROM address for read */
       
                        addre = WRITE|(addre<<1);
                        I2c_send_7addre(addre);
               
                          }
                  else
                  {
                    err++;
                   }
break:
case 2:
break;
case 3:
break;

}
上面程序是通过例程把while()改成查询,每间隔500US到1.5ms执行一次就行了。
出现总线一直忙时复位接收那个通道的DMA,和I2C总线,就可以了。

出0入0汤圆

 楼主| 发表于 2012-2-23 08:59:54 | 显示全部楼层
整个程序关键是那个SR2,官方的读SR2有些没关中断,我用的时候偶尔会出错,后来在读SR2前加关闭中断,读完再开启,暂时就没发现有问题!
附件有!
void I2C_EE_BufferRead(I2C_TypeDef *I2Cx ,vu8 EEPROM_Addr,vu16 ReadAddr,vu8 *pBuffer,vu16 NumByteToRead )//将EEPROM的数据读入缓冲器
{
        vu32 iErr,nErr;
       
        iErr = EE_TimeOut;
        nErr = EE_Error;
do{
       
//at24c02选择性读时序:START->DEVICE_ADDRESS_WRITE->ACK->BYTE_ADDRESS(n)->ACK----------------------------------------------------------------------------------------------------
        I2C_EE_WaitEepromStandbyState(I2Cx,EEPROM_Addr);//EEPROM设为待命状态
       
        iErr = EE_TimeOut;
        I2Cx->CR1 |= 0x0100;//Send START condition
        while((I2Cx->SR1&0x0001) != 0x0001){
                if(iErr-- == 0)
                goto EE_END;
        }

        iErr = EE_TimeOut;
        I2Cx->DR= EEPROM_Addr&0xFFFE;// Send EEPROM address for write
        /* Wait until ADDR is set: EV6 */
        while((I2Cx->SR1 &0x0002) != 0x0002){//Test on EV6 and clear it        
                if(iErr-- == 0)
                goto EE_END;
        }
        __disable_irq();
        /* Clear ADDR flag by reading SR2 register */
    Readtemp = I2Cx->SR2;        /*读SR2时,必须关闭中断,不关闭示波器看偶尔会发送9个CLK!,或者发送时,卡在EV8上!总之在读SR2时关闭中断读写就正常了!*/  
        /* Re-enable IRQs */
    __enable_irq();

连接原理图

(原文件名:24C64.jpg)
我这要接22PF,不然偶尔会通讯失败!想不明白!
点击此处下载 ourdev_721314E8GQ27.rar(文件大小:7K) (原文件名:EEPROM-I2C驱动.rar)

出0入0汤圆

发表于 2012-2-23 11:25:59 | 显示全部楼层
我用的STM8S105,I2C也用的库,100KHz 不带中断,调试的时候偶然发现有死掉的情况,后来我吧上拉电阻4.7K换成10K,就没有出现死掉的问题了;

出0入0汤圆

发表于 2012-2-23 11:32:47 | 显示全部楼层
呃。。。。我跑L3G4200D的时候用的1.2M的速度,都没问题

出0入0汤圆

发表于 2012-2-23 11:48:54 | 显示全部楼层
学习了,暂时还没用到I2C

出0入0汤圆

发表于 2012-2-23 12:30:37 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-23 15:03:59 | 显示全部楼层
STM32的I2C都成一个月经问题了,其实官网Errata写得很清楚了,就两个解决办法——I2C中断优先级设为最高,用DMA方式。

STM32的I2C单独测试是没有问题的,问题出在放在一个复杂系统里面,很多peripheral同时使用的时候,别的中断会导致I2C总线锁死,这个锁死是无解的,即使是复位也无法解决锁死,只能断电!!!矛盾就出来了,在一个复杂系统里面,不可能把最高中断优先级或DMA分配给I2C这个次要的部件,所以结论就是硬件I2C是不能用的,只能软件模拟!

出0入0汤圆

 楼主| 发表于 2012-2-24 20:53:06 | 显示全部楼层
LS,读SR2寄存器时关一下中断,读完再开,一般应用影响不大吧?

出0入0汤圆

发表于 2012-2-25 02:21:19 | 显示全部楼层
算了吧,你只是把出错概率降低到你无法观察的程度,没解决问题。

出0入0汤圆

发表于 2012-2-25 08:24:58 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-25 09:30:07 | 显示全部楼层
在ST没升级I2C硬件之前,就当它是个废物。

出50入0汤圆

发表于 2012-2-28 15:54:35 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-28 17:06:05 | 显示全部楼层
回复【17楼】i55x
stm32的i2c都成一个月经问题了,其实官网errata写得很清楚了,就两个解决办法——i2c中断优先级设为最高,用dma方式。
stm32的i2c单独测试是没有问题的,问题出在放在一个复杂系统里面,很多peripheral同时使用的时候,别的中断会导致i2c总线锁死,这个锁死是无解的,即使是复位也无法解决锁死,只能断电!!!矛盾就出来了,在一个复杂系统里面,不可能把最高中断优先级或dma分配给i2c这个次要的部件,所以结论就是硬件i2c是不能用的,只能软件模拟!
-----------------------------------------------------------------------

有道理,哈哈!
ST到现在都不解决这个问题。用上DMA和最高优先级中断,还不如直接用IO模拟来的快捷方便。

出0入0汤圆

发表于 2012-2-28 18:57:15 | 显示全部楼层
软件模拟吧

出0入0汤圆

发表于 2012-2-29 13:40:37 | 显示全部楼层
kao,ST这搞法也太烂了,I2C这么常用的东西都搞不定

出0入0汤圆

发表于 2012-4-7 14:03:53 | 显示全部楼层
xiaoxiao2008 发表于 2012-2-23 11:32
呃。。。。我跑L3G4200D的时候用的1.2M的速度,都没问题

这个.....1.2M,能请教一下你是怎么弄的吗

出0入0汤圆

发表于 2012-4-7 14:43:08 来自手机 | 显示全部楼层
mark 现在加减法都负数了呀  2-10=?

出0入0汤圆

发表于 2012-5-24 22:42:53 | 显示全部楼层
将用到STM32,MARK一下,少走弯路。

出0入0汤圆

发表于 2012-5-25 11:24:36 | 显示全部楼层
本帖最后由 xiaobo768015 于 2012-5-25 11:39 编辑

本人亲自试验过,不用ST的库,STM32F103RBT6采用中断方式,以800KHz频率读写AT24C02,屁事没有.(800KHz时,SCL时钟信号高电平290ns,低电平830ns,通信很稳定.当设置到1MHz时就再也读不到AT24C02了,但是通过逻辑分析仪查看得知,通信失败的原因是STM32发出地址信号后得不到AT24C02的应答信号,估计AT24C02实在跟不上了,而此时的SCL时钟信号高电平160ns,低电平590ns,说明STM32的I2C是可以达到甚至高于1MHZ的.只要你外围器件跟得上)

出0入0汤圆

发表于 2012-6-19 19:56:41 | 显示全部楼层
我现在遇到了一个问题,在TIM3中断时,I2C读数据就会死在while循环。BTF位经常莫名其妙被置位,不知道什么原因

出0入0汤圆

发表于 2012-6-19 20:09:03 | 显示全部楼层
dragon_hn 发表于 2012-2-28 17:06
回复【17楼】i55x
stm32的i2c都成一个月经问题了,其实官网errata写得很清楚了,就两个解决办法——i2c中 ...

我现在也遇到了同样的问题,还是希望通过合理调用库函数解决问题

出0入0汤圆

发表于 2012-7-16 15:18:57 | 显示全部楼层
Mark 同样的问题

出0入0汤圆

发表于 2012-7-16 16:29:33 | 显示全部楼层
很好,有图有真相!!

出0入0汤圆

 楼主| 发表于 2012-11-2 16:57:48 | 显示全部楼层
经常死在这吧?我的解决办法是,
__disable_irq();
        /* Clear ADDR flag by reading SR2 register */
    Readtemp = I2Cx->SR2;          
        /* Re-enable IRQs */
    __enable_irq();       

读SR2时,关闭所有中断,读完再开

出0入0汤圆

发表于 2012-11-2 17:31:06 | 显示全部楼层
改写库函数  增加一个超时溢出  然后复位I2C

出0入0汤圆

发表于 2012-11-2 17:33:34 | 显示全部楼层
i55x 发表于 2012-2-23 15:03
STM32的I2C都成一个月经问题了,其实官网Errata写得很清楚了,就两个解决办法——I2C中断优先级设为最高, ...

dma一般用在哪?为何不给i2c用?

出0入0汤圆

发表于 2013-5-22 17:05:49 | 显示全部楼层
遇到同样的问题了。谢谢分享经验。
Mark!

出0入0汤圆

发表于 2013-9-23 10:43:09 | 显示全部楼层
这个不错,取经了

出0入0汤圆

发表于 2013-10-14 15:52:51 | 显示全部楼层
    mark         

出0入0汤圆

发表于 2014-8-17 12:19:48 | 显示全部楼层
我采用的是中断方式。但是ST的库在I2C中断方式也存在一个错误:
库文件stm32f10x_i2c.c里的uint32_t I2C_GetLastEvent(I2C_TypeDef* I2Cx)函数,是同时检测I2C的SR1和SR2的状态,合成一个32BIT的状态返回。
这样的话,当从器件不能及时应答时,就产生一个错误中断(无ACK应答,SR1=0x0400)。而此时SR2必然是0x0003(总线上正在进行数据通讯 + 主模式)。
因此,uint32_t I2C_GetLastEvent(I2C_TypeDef* I2Cx)函数的返回值=0x00030400。
而在文件stm32f10x_i2c.h里,I2C_EVENT_SLAVE_ACK_FAILURE被定义为((uint32_t)0x00000400),是不匹配的。

从ST下载的Accelerometer_Demo例程里是这样的:
I2C错误中断函数:
void I2C1_ErrIntrHandler(void)
{
  if(I2C_EVENT_SLAVE_ACK_FAILURE == I2C_GetLastEvent(I2C1)) //////这里显然不能挑出无ACK应答错误
  {
    // Generate Stop condition (return back to slave mode)
    I2C_GenerateSTOP(I2C1,ENABLE);
  }
  s_Done = TRUE;
  s_Error = TRUE;
}


出0入0汤圆

发表于 2014-11-25 22:48:49 | 显示全部楼层
遇到了同样的问题,感谢分享!

出0入0汤圆

发表于 2014-11-26 09:18:53 | 显示全部楼层
查询不到就死等,然后加看门口复位

出0入0汤圆

发表于 2014-11-26 18:21:07 | 显示全部楼层
建议不要用库,我用STM32F103VET6(主)和PIC16F1824(从)通讯,50KHZ都没什么问题.

出0入0汤圆

发表于 2016-9-27 10:44:25 | 显示全部楼层
谢谢分享。。。

出190入0汤圆

发表于 2016-9-28 10:34:19 | 显示全部楼层
贴上在使用中的I2C代码<从openpilot的i2c代码中提炼出来的>,采用中断(最高优先级)+库,目前没有发现什么问题,欢迎大家测试使用,呵呵。
int bsp_i2c_transfer(i2c_dev_s *i2cx, uint8_t addr, uint8_t reg,
        uint8_t *data, uint8_t len, i2c_txn_direction rw)
{
    int res;

    if(!i2cx)
        return -1;

    sem_lock(i2cx->sem_busy);

    active_i2cx = i2cx;     //use for irq routine

    if(data && len != 0)    //valid data to send
    {
        i2c_txn.active_byte = &data[0];
        i2c_txn.last_byte = &data[len - 1];
        i2c_txn.bytes = len;
    }
    else
    {
        i2c_txn.last_byte = NULL;
        i2c_txn.active_byte = i2c_txn.last_byte + 1;
        i2c_txn.bytes = 0;
    }
    i2c_txn.slave_addr = (addr << 1);
    i2c_txn.sub_addr = reg;
    i2c_txn.rw = rw;

    I2C_GenerateSTART(i2cx->dev, ENABLE);
    I2C_ITConfig(i2cx->dev, I2C_IT_EVT | I2C_IT_ERR, ENABLE);

    res = sem_wait(i2cx->sem_ready, TIMEOUT);
    if(res < 0)
    {
        i2c_reset_bus(i2cx);
//        dbg_log("BUS ERR.\r\n");
    }

    sem_unlock(i2cx->sem_busy);
    return res;
}

static void i2c_ev_handler(void)
{
    uint32_t event = I2C_GetLastEvent(active_i2cx->dev);
    static uint8_t subaddr_send = 0;

#define EVENT_MASK 0x000700FF
    event &= EVENT_MASK;

    switch(event)
    {
    case (I2C_EVENT_MASTER_MODE_SELECT | 0x40):
        (void)active_i2cx->dev->DR; //no break;
    case I2C_EVENT_MASTER_MODE_SELECT: /* EV5 */
//        I2C_AcknowledgeConfig(active_i2cx->dev, ENABLE);
        if((i2c_txn.rw == I2C_TXN_READ) \
                && (subaddr_send || (i2c_txn.sub_addr == SUB_ADDR_NO_USE)))
            I2C_Send7bitAddress(active_i2cx->dev, i2c_txn.slave_addr, I2C_Direction_Receiver);
        else    //direction is Tx, or we have not sent the sub and rep start
            I2C_Send7bitAddress(active_i2cx->dev, i2c_txn.slave_addr, I2C_Direction_Transmitter);
        break;
    case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:/* EV6 */
        I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, ENABLE); // allow us to have an EV8_1
        break;
    case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:   /* EV6 */
        if(i2c_txn.bytes == 1) // EV6_1
        {
            I2C_AcknowledgeConfig(active_i2cx->dev, DISABLE);
            I2C_GenerateSTOP(active_i2cx->dev, ENABLE);
        }
        else if(i2c_txn.bytes >= 2)
        {
            I2C_AcknowledgeConfig(active_i2cx->dev, ENABLE);
        }
        I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, ENABLE);// allow us to have an EV7
        break;
    case I2C_EVENT_MASTER_BYTE_TRANSMITTING: /* EV8 or EV8_1 */
        if(subaddr_send == 0 && i2c_txn.sub_addr != SUB_ADDR_NO_USE)
        {
            subaddr_send = 1;
            active_i2cx->dev->DR = i2c_txn.sub_addr;
            if(i2c_txn.rw == I2C_TXN_READ) // disable TXE to allow the buffer to flush
                I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, DISABLE);
        }
        else if(i2c_txn.rw == I2C_TXN_WRITE)
        {
            if(i2c_txn.active_byte < i2c_txn.last_byte) // write more bytes
                active_i2cx->dev->DR = *i2c_txn.active_byte++;
            else if(i2c_txn.active_byte == i2c_txn.last_byte)
            {   // the last byte
                active_i2cx->dev->DR = *i2c_txn.active_byte++;
                I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, DISABLE);
            }
            else // invalid data, wait for EV8_2
                I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, DISABLE);
        }
        else //subaddress not used for read
            I2C_ITConfig(active_i2cx->dev, I2C_IT_BUF, DISABLE);
        break;
    case I2C_EVENT_MASTER_BYTE_TRANSMITTED: /* EV8_2 */
        if(i2c_txn.rw == I2C_TXN_READ)
            I2C_GenerateSTART(active_i2cx->dev, ENABLE);
        else
        {
            I2C_GenerateSTOP(active_i2cx->dev, ENABLE); // program the Stop
            I2C_ITConfig(active_i2cx->dev, I2C_IT_EVT | I2C_IT_ERR, DISABLE);
            subaddr_send = 0;
            sem_post(active_i2cx->sem_ready);
        }
        break;
    case I2C_EVENT_MASTER_BYTE_RECEIVED: /* EV7 */
        switch(i2c_txn.last_byte - i2c_txn.active_byte + 1)
        {
        case 0:
            (void)active_i2cx->dev->DR;
            I2C_ITConfig(active_i2cx->dev, I2C_IT_EVT | I2C_IT_BUF |I2C_IT_ERR, DISABLE);
            subaddr_send = 0;
            sem_post(active_i2cx->sem_ready);
            break;
        case 1:
            *i2c_txn.active_byte++ = active_i2cx->dev->DR;
            I2C_ITConfig(active_i2cx->dev, I2C_IT_EVT | I2C_IT_BUF |I2C_IT_ERR, DISABLE);
            subaddr_send = 0;
            sem_post(active_i2cx->sem_ready);
            break;
        case 2:
            I2C_AcknowledgeConfig(active_i2cx->dev, DISABLE);
            I2C_GenerateSTOP(active_i2cx->dev, ENABLE);
            *i2c_txn.active_byte++ = active_i2cx->dev->DR;
            break;
        default:
            *i2c_txn.active_byte++ = active_i2cx->dev->DR;
            break;
        }
        break;
    case (I2C_EVENT_MASTER_BYTE_RECEIVED | 0x4): /* EV7 + BTF */
    case 0: /* This triggers an FSM fault sometimes, but not having it stops things working */
    case 0x40: /* RxNE only.  MSL + BUSY have already been cleared by HW. */
    case 0x44: /* RxNE + BTF.  MSL + BUSY have already been cleared by HW. */
    case 0x84: /* TxE + BTF. EV8_2 but TRA + MSL + BUSY have already been cleared by HW. */
        break;
    case 0x80:/* TxE only */
         break;
    case 0x30084: /* Occurs between byte tranmistted and master mode selected */
    case 0x30000: /* Need to throw away this spurious event */
    case 0x30403 & EVENT_MASK: /* Detected this after got a NACK, probably stop bit */
        break;
    default:
        subaddr_send = 0;
        i2c_reset_bus(active_i2cx);
        break;
    }
}

static void i2c_er_handler(void)
{
    uint32_t event = I2C_GetLastEvent(active_i2cx->dev);
    if (event & I2C_FLAG_AF)
    {
        I2C_ClearFlag(active_i2cx->dev, I2C_FLAG_AF);
        I2C_ITConfig(active_i2cx->dev, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
        I2C_AcknowledgeConfig(active_i2cx->dev, DISABLE);
        I2C_GenerateSTOP(active_i2cx->dev, ENABLE);
    }
    else /* mostly bus errors here */
    {
        i2c_reset_bus(active_i2cx);/* Fail hard on any errors for now */
    }
}

出0入0汤圆

发表于 2016-9-29 11:22:45 | 显示全部楼层
make!学习了。一直听别人说ST的I2C不给力。所以从学开始就用模拟。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子论坛 ( 公安交互式论坛备案:44190002001997 粤ICP备09047143号 )

GMT+8, 2022-8-10 16:10

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表