346675655 发表于 2008-8-19 11:13:20

STM32——I2C——EEPROM 通讯老问题 有波形图 请教大家

EK-stm32的实验板,问题依旧是EEPROM例程无法通过
以下分别
 http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_383464.jpg
(原文件名:原实验板波形图.jpg)

http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_383465.jpg
(原文件名:上拉改为4.7k后波形图.jpg)

http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_383466.jpg
(原文件名:i2c.jpg)  



I2C总线的波形上升沿不够陡,想先把硬件的问题解决掉再考虑程序的问题
怎样能改善这种情况   请教 大家 谢谢

346675655 发表于 2008-8-19 16:42:00

刷贴太快 基本没人看到就沉了
顶一下吧

bluelucky 发表于 2008-8-19 17:05:02

先把总线速度降到很低,以使波形足够标准,看看软件是否正确再试着慢慢提高总线速度

makesoft 发表于 2008-8-19 17:46:09

上拉电阻小了,换成1K的试试吧

346675655 发表于 2008-8-20 08:46:25

to 【2楼】 bluelucky
速度2m的时候 波形规则了许多   按照21ic上给出的驱动函数 可以实现读写,可如果中间出错一次
复位都不行 必须断电才可以下次通过 不知道这个是为什么。
另:固件库都是while()语句,如果死在这里 岂不复位??

hkap 发表于 2008-8-20 10:18:05

一般都是时序不严格造成的无法读写

teltium 发表于 2008-9-1 18:11:54

400K比较安全

xue110592 发表于 2008-11-25 11:22:27

2楼问题解决没有,我现在也碰到这样的问题,是芯片本身问题吧,用51单片即读就没有这个问题

xue110592 发表于 2008-11-25 11:25:14

抱歉:是1楼问题解决没有,我现在也碰到这样的问题,是芯片本身问题吧,用51单片机读就没有这个问题,好象用STM32软件

仿真的就可以正常使用,难道是寄存器有问题 

__STM32__ 发表于 2008-11-26 22:20:23

1) 建议先把速率降下来把程序调通,然后再提高速率。

2) 建议把上拉电阻放到2.2K或3K,一般保持1~2mA的上拉电流比较好。

3) 波形图中看不到通讯过程,不好说其它有什么问题。

kugel 发表于 2008-11-26 23:45:38

上拉太大了,你看下I2C规范,时钟上升时间都是有要求的。

xue110592 发表于 2008-11-27 09:51:12

回复9楼,前期通讯能够建立,并且能够正常读写一次IIC外设,接着就挂了,而且复位都不行,必须断电。



IIC频率40KHZ

__STM32__ 发表于 2008-11-27 10:03:50

11楼的问题可能是第一次正常读写后的结束位不对,请对照示波器仔细检查。

ningmeng7294 发表于 2009-7-4 01:18:18

到底有没有问题呀,这个IIC搞死人了,确认一下,各位搞定了没?

346675655 发表于 2009-7-4 09:02:28

我没有搞定拖半年了已经项目没有E2不行
请香主 帮忙给一个“连续读写超过512字节的” 没有问题的例子
代表坛子里所有的搞不定stm32 I2C的人先谢谢香主

另:正在切换 模拟I2C的方案

huike 发表于 2009-9-20 17:18:00

我手上有的STM32板子在上电之后读EEPROM就死循环了(不是每次都会,复位一下又好了)。

有的板都不会。程序问题?硬件问题?

STM32的IIC真叫人难受呀!!!看来要改模拟接口了。

jijuxie321 发表于 2009-9-20 17:59:52

看下24C02的数据手册。是不是本身速度就不够。。

kebaojun305 发表于 2009-9-20 20:01:18

楼主如果要存的参数不事太多的话,用内部flash模拟的也不错啊。

lvyi913 发表于 2009-9-20 21:37:12

这个问题不是速度的问题,我目前用的就是400K的,问题在于STm32的I2C的设计问题,这个大家可以去国外的网站上找一下,并且STM32最新的勘误表也指出了这个错误。特别是在I2C读EEP的时候,明显存在问题。

    关于I2C读写EEP三种选择:

1、 软件模拟方式,推荐指数2;
2、I2C中断方式,由于STm32的I2C设计问题,导致中断方式几乎不能用(当然可以下载他们最新的历程,好像是可以的,我没有测试过),推荐指数:1或者0;不推荐使用;
3、DMA+I2C的方式,效率最高,而且工作起来也最正常,推荐指数:3;

我在这个问题上也是搞了好久,所以如果用STM32的I2C读写EEP,千万别用中断方式,推荐DMA方式,实在不行就软件模拟方式。

lvyi913 发表于 2009-9-20 21:40:05

下面是我的用法,大家可以参考一下,没有怎么整理思路,只是把整个I2C相关的代码拷贝了过来,欢迎高手拍砖,呵呵!
//
//use DMA1 channel7 for I2C receive:RRP read
//

static void I2C_RcvDMAConfig(void)
{
    DMA_InitTypeDef    DMA_InitStructure;
   
// Deinit the DMA1 Channel7 for I2C revieve
    DMA1_Channel7->CCR &= CCR_ENABLE_Reset;
    /* Reset DMAy Channelx control register */
    DMA1_Channel7->CCR= 0;
    /* Reset DMAy Channelx remaining bytes register */
    DMA1_Channel7->CNDTR = 0;
    /* Reset DMAy Channelx peripheral address register */
    DMA1_Channel7->CPAR= 0;
    /* Reset DMAy Channelx memory address register */
    DMA1_Channel7->CMAR = 0;
    /* Reset interrupt pending bits for DMA1 Channel6 */
    DMA1->IFCR |= DMA1_Channel7_IT_Mask;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)EEP.ReadBuf;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = 255;        /* Just for initialization */
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel7, &DMA_InitStructure);

}

//
//use DMA1 channel6 for I2C send:RRP write
//
static void I2C_SendDMAConfig(void)
{
    DMA_InitTypeDef    DMA_InitStructure;
   
// Deinit the DMA1 Channel7 for I2C revieve
    DMA1_Channel6->CCR &= CCR_ENABLE_Reset;
    /* Reset DMAy Channelx control register */
    DMA1_Channel6->CCR= 0;
    /* Reset DMAy Channelx remaining bytes register */
    DMA1_Channel6->CNDTR = 0;
    /* Reset DMAy Channelx peripheral address register */
    DMA1_Channel6->CPAR= 0;
    /* Reset DMAy Channelx memory address register */
    DMA1_Channel6->CMAR = 0;
    /* Reset interrupt pending bits for DMA1 Channel6 */
    DMA1->IFCR |= DMA1_Channel6_IT_Mask;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)EEP.WriteBuf;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = 255;        /* Just for initialization */
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority =DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel6, &DMA_InitStructure);

}


/**
* @briefConfigures I2C1
* @paramNone
* @retval : None
*/

static void I2C_MasterConfig(void)
{
    I2C_InitTypeDefI2C_InitStructure;
    I2C_DeInit(I2C1);
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x30;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
    I2C_Init(I2C1, &I2C_InitStructure);
    I2C_ITConfig(I2C1, I2C_IT_ERR|I2C_IT_EVT, ENABLE);
}

static void I2C_GPIOInit(void)
{
    GPIO_InitTypeDefGPIO_InitStructure;
    /* Configure I2C1 pins: SCL and SDA */
    GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

   
            /* Configure P2.01 asEEPROM write protect pin                                                               
           GPIO2->PC0 |=EEP_WP;                                                                                                               
       GPIO2->PC1 &= ~EEP_WP;
       GPIO2->PC2 |=EEP_WP;*/
          
        ENABLE_EEPWP;
}

//
//config the I2C using the DMA mode fpr send and receive
//
void I2C_Config(void)
{
    I2C_MasterConfig();
    I2C_RcvDMAConfig();
    I2C_SendDMAConfig();
    I2C_GPIOInit();
}



//
//EEP read DMA interrupt :I2C rcv
//
void DMA1_Channel7_IRQHandler(void)
{
    DMA1_Channel7->CCR &= CCR_ENABLE_Reset;   //disable the DMA channel7
    DMA1->IFCR = DMA1_FLAG_TC7;                        //clear the channel6 transfer complete interrupt flag
   
    I2C1->CR1 |= CR1_STOP_Set;                        //generate stop condition, release the bus
    I2C1->CR2 &= (uint16_t)~I2C_IT_EVT;             // In order to not have again a BTF event IT

    EEP.State = Idle;
}

/**
* EEP read DMA interrupt : I2C send
*/
void DMA1_Channel6_IRQHandler(void)
{
    DMA1_Channel6->CCR &= CCR_ENABLE_Reset;   //disable the DMA channel6
    DMA1->IFCR = DMA1_FLAG_TC6;                        //clear the channel6 transfer complete interrupt flag
}

/**
* @briefThis function handles I2C1 Event interrupt request.
* @paramNone
* @retval : None
*/
void I2C1_EV_IRQHandler(void)
{
    switch (I2C_GetLastEvent(I2C1))
    {
      case I2C_EVENT_MASTER_MODE_SELECT:               /* EV5 */
            
            if(EEP.DMAState == DMARecv)
            {
                //I2C_Send7bitAddress(I2C1, SLAVE_ADDRESS, I2C_Direction_Receiver);
               I2C1->DR = EEP.ChipAddr | 0x01;
            }else{
               //I2C_Send7bitAddress(I2C1, SLAVE_ADDRESS, I2C_Direction_Transmitter);
                I2C1->DR = EEP.ChipAddr & 0xFE;
            }
      break;

      /* Master Transmitter --------------------------------------------------*/
    case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:
      if(EEP.State == EEPWrite)
      {
             //DMA_Cmd(DMA1_Channel6, ENABLE);
             DMA1_Channel6->CCR |= CCR_ENABLE_Set;
      }else{
            I2C1->DR = EEP.ReadAddr;      
      }
      break;

    case I2C_EVENT_MASTER_BYTE_TRANSMITTED:
      if(EEP.State == EEPWrite)
      {
                I2C1->CR1 |= 0x200;
                //I2C_ITConfig(I2C1, I2C_IT_EVT, DISABLE); /* In order to not have again a BTF event IT */
                I2C1->CR2 &= (uint16_t)~I2C_IT_EVT;
                EEP.State = Idle;

      }else{
            EEP.DMAState = DMARecv;
            I2C1->CR1 |= 0x100;       
      }
      break;

      /* Master Receiver -------------------------------------------------------*/
    case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:
//      DMA_Cmd(DMA1_Channel7, ENABLE);
      DMA1_Channel7->CCR |= CCR_ENABLE_Set;
      break;

    default:
      break;
    }
}

lvyi913 发表于 2009-9-20 21:42:12

这是EEP的读写函数,当然我用的是铁电,没有EEP中的页的概念,所以如果要换到EEP中,要考虑页的概念,还有EEP的写入时间。

void EEP_BufWriteT(U16 Addr, U8* pBuf, U16 NumToWrite)
{
    U32 i;
    if((NumToWrite > I2CTxBufLen)||(0 == NumToWrite)) return;
   
    EEP.ChipAddr =EEPADDR;
    if(Addr>0xFF) EEP.ChipAddr =EEPADDR|0x02;

    EEP.State = EEPWrite;
    EEP.DMAState = DMASend;
    EEP.WriteBuf = (U8)Addr;
    for(i=0; i<NumToWrite; i++)
    {
      EEP.WriteBuf = *(pBuf+i);
    }
   
    DMA1_Channel6->CNDTR = NumToWrite+1;//set the DMA length
    DMA1_Channel6->CCR |= DMA_IT_TC;             // Enable the DMA channel7 transfer complete IT

    I2C1->CR2 |= CR2_DMAEN_Set;   //Enable DMA
    I2C1->CR2 |= I2C_IT_EVT;            //Enable the EV interrupt   
    I2C1->CR1 |= (1<<8);                   //generate start condition
   
}

void EEP_Init(void)
{
    I2C_Config();
    EEP.State = Idle;
    EEP.ChipAddr = EEPADDR;
    EEP.DMAState = Idle;
}

void EEP_BufReadT(U16 Addr , uint16_t NumToRead)
{
    if((NumToRead > I2CRxBufLen)||(0 == NumToRead)) return;
    if(1 == NumToRead) NumToRead++;

    EEP.ChipAddr =EEPADDR;
    if(Addr>255) EEP.ChipAddr =EEPADDR|0x02;
       
    EEP.ReadAddr = Addr;
    EEP.State = EEPRead;
    EEP.DMAState = DMASend;

    DMA1_Channel7->CNDTR = NumToRead;//set the DMA length
    DMA1_Channel7->CCR |= DMA_IT_TC;             // Enable the DMA channel7 transfer complete IT
   
    I2C1->CR2 |= CR2_LAST_Set;      //for the last byte,NACK
    I2C1->CR2 |= CR2_DMAEN_Set;   //Enable DMA
    I2C1->CR2 |= I2C_IT_EVT;            //Enable the EV interrupt   
    I2C1->CR1 |= (1<<8);                   //generate start condition
}

lvyi913 发表于 2009-9-20 21:46:47

OK了,就这么多了,希望对大家有帮助,我们的产品已经进入最后测试阶段,这个代码可用。当然如果有问题,希望大家一起交流。

lvyi913 发表于 2009-9-20 22:01:34

11楼的问题我也遇到过,只有断电才能够再次读写,你可以测一下SDA和SCL,那是SDA和SCL不再都为高电平了,就是没有发出停止条件导致的,所以是无法再进行读写的,也是中断方式惹得祸!

richey07 发表于 2009-11-12 21:49:28

mark

tkxlll 发表于 2010-8-19 16:23:16

看到这个帖子真是兴奋呀,该死的I2C,我都不知道该咋办了!!!

我用的是查询方式(未加DMA),EEPROM为:24C16,读写异常。

偶尔能够写,但是读一直都不行,而且,死掉后,复位没用,还得断电停一会,再上电,才又可以,极不稳定。调试起来太吃力了。

是不是硬件设计上也存在问题呢:硬件如下:

tkxlll 发表于 2010-8-19 16:24:14

http://cache.amobbs.com/bbs_upload782111/files_32/ourdev_576147.JPG
图中芯片型号实际为:24c16 (原文件名:I2C.JPG)

tkxlll 发表于 2010-8-19 16:32:23

还是,程序有问题?程序基本参考列程,部分如下:

I2C初始化如下:
void I2C_Configuration(void)
{
        I2C_InitTypeDef I2C_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
       
    // Enable I2C1 Clock
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);

        // Enable GPIOBclocks
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

        // Configure I2C1 I2C1-SCL(PB.06(58 port)) and I2C1-SDA(PB.07(59 port)) as output open-drain
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        I2C_InitStructure.I2C_ClockSpeed =I2C_CLKSpeed;
        I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
        I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
        I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7;
        I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
        I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

        // enable I2C1
        I2C_Cmd(I2C1, ENABLE);
        //init I2C1
        I2C_Init(I2C1, &I2C_InitStructure);
        //I2C_Cmd(I2C1, ENABLE);
                       
}

写单个字节:
void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
{
/* Send STRAT condition */
I2C_GenerateSTART(I2C1, ENABLE);

/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);

/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
      
/* Send the EEPROM's internal address to write to */
I2C_SendData(I2C1, WriteAddr);

/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

/* Send the byte to be written */
I2C_SendData(I2C1, *pBuffer);
   
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

/* Send STOP condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}

还有: 那个模拟I2C,是什么,能否共享出来参考呀。

june4th 发表于 2010-8-19 16:39:11

这都是老月经了。
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3881417

tkxlll 发表于 2010-8-20 14:46:30

好消息!先谢谢各位指教。

用库2.0,调试通过了。可是换成v3.3.0的,就不行了,只是库的不同,怎么就不行呢?

谁能帮忙解释一下呀,找出原因,谢谢拉

zxc2769 发表于 2010-12-14 11:56:11

怎么看I2C 通讯是否正常吗?

luozhongliang 发表于 2012-5-24 22:19:04

MARK一下,备用

蜂巢 发表于 2012-5-24 22:27:22

这样的波形太差了,就算能通讯你也不放心呀?

prudent 发表于 2012-5-24 23:04:37

楼主不会买到水货24C02了吧,曾经切身体会过换5、6片才有一片良品的飘过

dragonwww 发表于 2012-5-25 09:20:47

官网推荐用CPAL来解决I2C问题,但还未试验。

yo_yo 发表于 2012-7-8 23:25:51

yoyo mark

357853730 发表于 2012-7-9 19:13:43

{:dizzy:}我也遇到这个问题

sdyaojingwen 发表于 2012-7-9 22:15:45

你的速率太高了吧2m ,上拉电阻直接1K试试!你不能只看stm32的能搞定的频率,你还得看看24C02能否搞定啊!你把24C02的sda 和scl断开波形可能就ok了!!!你换个400K试试!我记得24c02手册说的是最大400K!

nust_奔跑 发表于 2012-7-9 23:57:46

STM32的IIC有问题~~~?好像很多人都用模拟的方式~

YimeiCan 发表于 2012-7-17 21:01:38

{:time:}{:time:}{:time:}{:time:}{:time:}{:time:}

johnny_zi 发表于 2012-7-19 23:26:43

STM32的IIC真的就用库有问题吗?好像很多人都用模拟的方式。有没有解决的,用新的库呢??

hzb0624 发表于 2012-10-7 17:33:33

tkxlll 发表于 2010-8-19 16:32 static/image/common/back.gif
还是,程序有问题?程序基本参考列程,部分如下:

I2C初始化如下:


我想问一下27楼,你的这段代码后来调通了吗?我碰到了跟你一样的问题

shanhu1234 发表于 2013-3-4 14:30:45

lvyi913 发表于 2009-9-20 21:37 static/image/common/back.gif
这个问题不是速度的问题,我目前用的就是400K的,问题在于STm32的I2C的设计问题,这个大家可以去国外的网站 ...

我用硬件IIC非中断方式成功测试读写EEPROM。
但是在DMA+中断方式测试则出现不能读一个字节的问题。可以读写多个字节!

xiefy21 发表于 2013-8-12 20:06:57

mark……
顶一个…
页: [1]
查看完整版本: STM32——I2C——EEPROM 通讯老问题 有波形图 请教大家