置顶提供的I2C查询读写方式好象有问题。请香版看看。
我用的万利的板子来测试I2C读写eeprom的程序。程序是版面置顶提供的。用的是查询读写方式。
因为我想用在手持设备上,尽量缩小体积和省电。用尽可能低的频率。
当用外置晶振HSE,并且72Mhz做为时钟源没问题,能够正常读写。但是我改为用内置HSI做为时钟源的话,PLL disable,并且HCLK=SYSCLK/2,只用4Mhz为内核时钟,I2C就读写不了。老是返回6错误(TIME OUT). 但是我程序的UART,和定时器都能够正常工作。不管是HSE还是HSI。
不知道是哪里错误了。我尝试调整了好几种one_us_unit ,i2c_10clk_us的值了。还是不能正常工作。
程序上只改动了RCC_Configuration()部份,其他没动。
void RCC_Configuration(void)
{
/* RCC system reset(for debug purpose) */
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_OFF);
if(1)
{
/* Enable Prefetch Buffer */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* Flash 0 wait state */
FLASH_SetLatency(FLASH_Latency_0);
/*HCLK = SYSCLK/2 */
RCC_HCLKConfig(RCC_SYSCLK_Div2);
/* ADCCLK = PCLK2/6 */
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/* PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK */
RCC_PCLK1Config(RCC_HCLK_Div1);
/* Disable PLL */
RCC_PLLCmd(DISABLE);
/* Select HSI as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
}
}
非常感谢e_hui0000
楼主的问题,我这里已经确定了。
这确实是代码的问题!
问题在于:本来代码在做任何I2C操作(比如,发送start,发送addr,发送/接收数据)之前,要先设置一个XXX_TIMEOUT。而这个TIMEOUT在<i2c_comm.c>中用#define定义的。
本来我是根据一个大概的时间限制,比如发送一个地址/字节,我就定义最大时间限制XXX_TIMEOUT为10个I2C总线上时钟所需要的时间。因为每个字节/地址,在总线上传输只需要9个时钟脉冲的时间(8个时钟+ 1个应答时钟)。
但是我忽略了一个问题,就是当HCLK也很低的时候,CPU执行速度很慢的时候,从启动定时器开始“*(u32 *)0xe000e010 |= 1;”,到执行while()中检查状态寄存器的操作,这段执行还没有完成,已经超时到了~~~,虽然此时I2C的通信仍然正常,寄存器状态也正确,但是由于OT标志已经被置位,因此从while出来后,看到OT置位了,就以为超时了。
因此,修改办法:把所有XXX_TIMEOUT的定义设置很大,比如:
#define BUS_BUSY_TIMEOUT (i2c_10clk_us*one_us_unit)*100
#define SEND_START_TIMEOUT (i2c_10clk_us*one_us_unit)*100
#define SEND_ADDR7_TIMEOUT (i2c_10clk_us*one_us_unit)*100
#define SEND_ADDR_HEADER_TIMEOUT (i2c_10clk_us*one_us_unit)*100
#define SEND_DATA_TIMEOUT (i2c_10clk_us*one_us_unit)*100
#define RECEIVE_DATA_TIMEOUT (i2c_10clk_us*one_us_unit)*100
另外,除了以上的宏定义常数对定时器超时赋值外,即“*(u32 *)0xe000e014 = BUS_BUSY_TIMEOUT;”
还有如下的地方,对超时赋值,
/*wait 5us max for bus free time limitation for later transaction */
*(u32 *)0xe000e014 = one_us_unit*;
现在扩大成
*(u32 *)0xe000e014 = one_us_unit*500;即可。
随后我将修改后的重新上传。
再次感谢e_hui0000 !!!
照着改了,还是有些问题。
照着改了,还是有些问题。
如果把 I2C_Comm_Init(I2C1, 400000, 0x0);
改为: I2C_Comm_Init(I2C1, 90000, 0x0);
就可以正常工作了。即使改为 I2C_Comm_Init(I2C1, 100000, 0x0); 都不行。
为什么I2C速度400K和100K都不行。只能够90K? 很奇怪哦。
而且我把内核频率改为8M的话,400K和100K都是正常的。4M的话I2C只能小于100K?
感谢e_hui0000的关注
确实如此~~~
当采用较低的CPU频率时,比如4MHZ,而I2C时钟还是比较快,比如400KHz,300Khz,以及楼主说的100KHz。 在STM32作为主设备读取数据的时候,会有一个问题,就是软件发送stop和disable ACK的操作,由于CPU的速度慢,使得,执行这些操作时,最后一个数据已经在总线上传输完毕了。这样就会造成,最后一个数据没有得到应该的NAK,并且由此,总线上还会出现一个extra data。
正如楼主所说,CPU改到8MHz,CPU执行比较快了,以上操作可以在最后一个数据出现之前完成,所以通信正确。
这个确实是一个存在的问题。
针对这个问题,一般克服的方法是DMA,如果仍然使用查询方式时,对于 master receive 一个或者两个数据,需要用另外稍微特别一点的代码处理流程。
马上等我整理出来,上传,谢谢!!!!!
谢谢lut1lut.另外再提个问题 :)
另外再提个问题. 我测试中断方式程序的时候,我用的都是读写一个字节。因为这样不用考虑页的问题。
for(addr=10,num=0;num < 12;addr++,num++,p++){
i = I2C_Comm_MasterWrite(I2C1, 0xa0,addr,p,1);
while(i2c_comm_state !=0);
}
好象不能正常操作。
要改为:
for(addr=10,num=0;num < 12;addr++,num++,p++){
i = I2C_Comm_MasterWrite(I2C1, 0xa0,addr,p,1);
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
}
可能在写的时候,i2c_comm_state在完全写完之前就返回了?谢谢。
请e_hui0000检验
查询方式操作下,在master receive时,对于接收一个或者两个数据时,处理流程比较特殊。
在接收多于两个数据时,为了克服由e_hui0000同学提出的当CPU比较慢,I2C速度比较快时通信问题,接收三个及以上数据的办法也有修改了。
我这里试过不同数据长度,不同CPU速度,通信正常。
更新后的项目在置顶帖子的第二楼那个压缩包。谢谢!!
还有问题。程序还要改改。
我用了新下载的查询方式读写的程序一样是4Mhz频率。
当我初始化90K的时候正常。但当我改成400K时程序一直停在
I2C_Comm_MasterWrite里的while里。在:
I2C_GenerateSTART(I2Cx, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
如果重新reset一下,重新再运行一下同样的程序,又能正常了。再reset一下,再运行又不行了。这次运行正常了。reset一下,再次运行一次就会停在那个while里面。
程序可能还要再改改。因为还是会有当机的危险。
谢谢lut1lut
8楼为什么要频繁改动I2C的频率呢?
要知道很难做到使用一组参数满足所有频率的需要,你这样频繁改动I2C的频率有什么具体意义吗?
至少能确定程序要足够健壮。
而且现在的情况是400K这次能运行。reset重新运行就不行了。再reset一下重新运行就可以。跟90K没有关系了。
MasterWrite的时序可能还有些小问题。而且那个while里应该要加timeout吧。
你说得现象这次我没有重现
我按照你的4MCPU的速度,先配置I2C总线时钟为90KHz,运行正常;又改成400KHz,也是运行正常的。
你能不能出问题时候的波形给我看看。谢谢。
我旁边没有示波器。不好意思。
400Khz时reset一下行,再一次不行,这种情况比较少。但有时还是会出现。
(这里的reset我指按一下IAR的reset button,不是指整个板的reset).
但是当我从90K运行一次,改成400K后编绎再运行,通常这次就不行了。reset一下后就可以正常。
想起一个手册中说到的限制
若要I2C总线速度400KHz,APB1时钟要是10MHz的整倍数。
Note: 1 FPCLK1 is the multiple of 10 MHz required to generate the Fast clock at 400 kHz.
请e_hui0000CPU=4MHz的情况下,不要跑400KHz的I2C速度看看。
其实就是STM32的I2C有BUG!
一开始就看不顺STM32的I2C.
于STM32 I2C不合理的看法:
相关链接:
http://blog.ednchina.com/netjob/151567/message.aspx
说不上是芯片问题吧。
只是做得比较复杂而已。当时他们可能考虑了太多的灵活性。现在的人都喜欢傻瓜化的东东。包括我。
哈哈,看起来Netjob对Bug的定义和我的定义不同
我对Bug的定义是:芯片的功能不能实现对芯片的设计要求。
而从Netjob的博客中,我所看到的是,“ST公司确实是把简单的问题复杂化了”,这就是你所说的Bug吗?这就是你对Bug的定义吗? 我不敢苟同。
呵呵,广义BUG 和 狭义BUG 的区别
是不是可以这么理解
狭义BUG——出了问题,才是BUG
广义BUG——潜在问题,也是BUG
更广义的BUG——简单问题复杂化,导致出问题的概率上升。也是BUG。