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

查看: 12280|回复: 6

解决stm32f10x I2C读写EEPROM芯片死锁问题

[复制链接]

3

主题

28

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2012-10-7 11:43:17 | 显示全部楼层 |阅读模式
首先说下编写这个程序的目的和思路:把AT24C02的驱动代码放一个模块里,只对外提供3个API函数-初始化,指定地址写一个字节,指定地址读一个字节。页写页读什么的都不用,这样方便外部调用. 
参考官方的库和神舟的源代码编写了个简单的读写AT24C02一个字节的程序,调试发现了几个问题:
1. 程序第一次调试没问题,第二次修改写入的数据再调试就陷入了死循环,再也跳不出来了
2. 换成神舟1号(目标板是神舟1号开发板)的源代码,重新编译写入调试,还是同样的问题
3. 把仿真器,目标板全部断电,放一段时间再调试,有时候能够正常跑,有时死锁
4. 打开寄存器查看,发现通常I2C模块一旦初始化,SR1的BUSY位自动置位,等多久都没有
上网搜索,发现碰得这问题的人很多,绝大多数意见都认为是这个BUSY问题,有人说是bug官方推荐模拟I2C,有人说是官方例程有问题,其中一位指出是初始话顺序的问题,应该先配置I2C,再配置GPIO的复用功能,这话很有道理,照做,修改自己写的程序调试,第
一次是没问题,reset再运行,还是死锁,问题依旧。
后来隐约想到,官方文档好像说引脚的初始话应该先置高。修改,在初始化的配置GPIO的复用功能之前,先将GPIO配置为输出,且置
高,而且在每次读操作之后执行初始化一次防止BUSY(写操作实测不需要)。测试再也没有发现令人崩溃的BUSY了。
下面是AT24C02.C的代码,
 
#include"stm32f10x.h"
 
       static AT24C02_Delay(){
//延时2ms, 确保写入成功 ;对外隐藏
        uint32_t   i;
         i=72*200*2;  //72对应系统时钟多少兆,2对应要延时多少毫秒
         while(i--);
      }               
 
  void AT24CO2_Init(uint32_t I2C_speed,uint8_t I2C_selfAddr ){
//I2C_speed     : I2C的SCL的频率,通常配置为100000
//I2C_selfAddr : 自身地址,这里可以为任意
        GPIO_InitTypeDef GPIO_InitStructure;
        I2C_InitTypeDef  I2C_InitStructure;
        //第一步:
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
        I2C_DeInit(I2C1);
        I2C_InitStructure.I2C_ClockSpeed         =  I2C_speed;    
        I2C_InitStructure.I2C_Mode               =  I2C_Mode_I2C;
        I2C_InitStructure.I2C_DutyCycle          =  I2C_DutyCycle_2; 
        I2C_InitStructure.I2C_OwnAddress1        =  I2C_selfAddr;
        I2C_InitStructure.I2C_Ack                =  I2C_Ack_Enable;
        I2C_InitStructure.I2C_AcknowledgedAddress=  I2C_AcknowledgedAddress_7bit; 
        I2C_DeInit(I2C1);
        I2C_Init(I2C1,&I2C_InitStructure);
        //第二步:先将Pins配置为通用输出且置高
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
        GPIO_InitStructure.GPIO_Pin   = (GPIO_Pin_6|GPIO_Pin_7);
        GPIO_InitStructure.GPIO_Mode  =  GPIO_Mode_Out_PP ;
        GPIO_InitStructure.GPIO_Speed =  GPIO_Speed_10MHz;
        GPIO_Init(GPIOB,&GPIO_InitStructure);
        GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);
        //第三步:配置为I2C功能
        GPIO_InitStructure.GPIO_Pin   = (GPIO_Pin_6|GPIO_Pin_7);
        GPIO_InitStructure.GPIO_Mode  =  GPIO_Mode_AF_OD ;
        GPIO_InitStructure.GPIO_Speed =  GPIO_Speed_10MHz;
        GPIO_Init(GPIOB,&GPIO_InitStructure);       
       }
 
 
void AT24C02_WriteByte(uint8_t AT24C02_MemAddr, uint8_t data){
//向指定地址写一个数据,1个字节
//AT24C02_MemAddr: 存储地址,范围为0x00~0xFF
// data                           : 8位数据,范围为0x00~0xFF           
                I2C_GenerateSTART(I2C1,  ENABLE);
                 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
                 I2C_Send7bitAddress(I2C1, 0xA0,I2C_Direction_Transmitter);
                 while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
                 I2C_SendData(I2C1,  AT24C02_MemAddr);
                 while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
                 I2C_SendData(I2C1,data);
                 while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
                 I2C_GenerateSTOP(I2C1,  ENABLE);
                 AT24C02_Delay();   //延时2毫秒,确保写入成功
}
 
 
uint8_t AT24C02_ReadByte(uint8_t AT24C02_MemAddr){
//随机读取一个字节的数据
//从指定地址读出一个字节       
//AT24C02_MemAddr: 存储地址,范围为0x00~0xFF 
                 uint8_t I2cReceiveData;
                 I2C_GenerateSTART(I2C1,  ENABLE);
                 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
                 I2C_Send7bitAddress(I2C1, 0xA0,I2C_Direction_Transmitter);
                 while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
                 I2C_SendData(I2C1, AT24C02_MemAddr );
                 while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));       
                 I2C_GenerateSTART(I2C1,  ENABLE);
                 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
                 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Receiver);
                while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));               
                 while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED));       
                 I2cReceiveData=I2C_ReceiveData(I2C1);
                 I2C_AcknowledgeConfig(I2C1,  DISABLE);
                 I2C_GenerateSTOP(I2C1,  ENABLE);
                 I2C_AcknowledgeConfig(I2C1,  ENABLE);
                 AT24CO2_Init( 100000, 0xDD );  //这里跟main函数中的初始设置保持一致
                 return I2cReceiveData ;
}
 
回复

使用道具 举报

3

主题

28

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
 楼主| 发表于 2012-10-7 11:51:52 | 显示全部楼层

回复:解决stm32f10x I2C读写EEPROM芯片死锁问题

 怎么排版老不对,无解了。欢迎大家拍砖
回复 支持 反对

使用道具 举报

0

主题

3

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2012-12-3 17:37:57 | 显示全部楼层

RE:解决stm32f10x I2C读写EEPROM芯片死锁问题

I2C_InitStructure.I2C_AcknowledgedAddress=  I2C_AcknowledgedAddress_7bit;
I2C_DeInit(I2C1);
回复 支持 反对

使用道具 举报

0

主题

3

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2012-12-4 06:44:10 | 显示全部楼层

回复:解决stm32f10x I2C读写EEPROM芯片死锁问题

检查下这两行里面设了什么
     RCC_APB1PeriphClockCmd(?????
                           , ENABLE );
         RCC_APB2PeriphClockCmd( ????| RCC_APB2Periph_GPIOA  |RCC_APB2Periph_AFIO
                       , ENABLE );     
如有该设的时脉未设到,及不该出现同时启动了的,皆无法正常运行
回复 支持 反对

使用道具 举报

3

主题

28

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
 楼主| 发表于 2012-12-21 22:52:27 | 显示全部楼层

回复:解决stm32f10x I2C读写EEPROM芯片死锁问题

<div style="padding:5px;border:1px dashed #ccc;">
回复第 3 楼 于2012-12-03 17:37:57发表:
I2C_InitStructure.I2C_AcknowledgedAddress=  I2C_AcknowledgedAddress_7bit;
I2C_DeInit(I2C1);
回复 支持 反对

使用道具 举报

0

主题

2

回帖

0

蝴蝶豆

新手上路

最后登录
2017-9-8
发表于 2017-9-8 09:45:59 | 显示全部楼层
楼主,你好!这个问题困扰我很久了,你说“后来隐约想到,官方文档好像说引脚的初始话应该先置高”,请问你这是在哪里看到的,是参考手册吗,我怎么没看到有这个,麻烦指点一二,谢谢!
回复 支持 反对

使用道具 举报

0

主题

1

回帖

0

蝴蝶豆

新手上路

最后登录
2018-4-29
发表于 2018-4-29 22:09:13 | 显示全部楼层
猜测一下,是不是eeprom没有识别到非应答,或mcu给出了应答信号
回复 支持 反对

使用道具 举报

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版