打印

STM32 I2C 封装库(查询方式+29楼中断方式+32楼DMA方式)

[复制链接]
楼主: lut1lut
手机看帖
扫描二维码
随时随地手机跟帖
21
lut1lut|  楼主 | 2009-1-5 15:19 | 只看该作者 回帖奖励 |倒序浏览

嗯,目前还在收集意见阶段

在8楼提出了一个对systick的变通使用手法。hjiongh看看如何

就是说最终i2c的超时还是用systick来做,因为如果“能有一个其它超时的来给i2c1”,那么这样一个定时器Timer1~8都有可能在用户的其他应用中冲突。

使用特权

评论回复
22
香水城| | 2009-1-5 15:21 | 只看该作者

例程中使用Systick实现超时控制,你可以根据实际情况稍加修

I2C操作需要某个内部的硬件机制实现超时控制,作为例程不管使用什么机制都有可能与用户使用的资源冲突,现在例程中使用了Systick,你完全可以根据原理自己根据实际情况稍加修改。


比如你使用Systick作为ms级的定时,那么你只需要引入一个全局变量,假定这个全局变量为I2C_Timestamp,每次进入你的Systick中断程序时对这个全局变量加一,然后在楼主的例程中所有用到Systick的地方,用对这个全局变量的判断代替即可。

例如例程中需要一个2ms的超时处理时,可以用下列代码代替:

  vu32 I2C_Time;

  I2C_Time = I2C_Timestamp + 2;
  while (I2C_Time > I2C_Timestamp);

请注意:我这个例子没有处理变量溢出的情况。

使用特权

评论回复
23
hjiongh| | 2009-1-5 16:05 | 只看该作者

这样理解对不对?

香主的这两句话没看太明白,请指教以下:
例如例程中需要一个2ms的超时处理时,可以用下列代码代替:

  vu32 I2C_Time;

  I2C_Time = I2C_Timestamp + 2;
  while (I2C_Time > I2C_Timestamp);

请注意:我这个例子没有处理变量溢出的情况。


====================================================
实际的例子代码:
I2C_Result  I2C_Comm_MasterWrite(I2C_TypeDef* I2Cx, u16 slave_addr, u32 offset, u8* pBuffer, u32 length)
{
vu32 check_time = 0;

    /*wait bus free*/
//SysTick_SetReload(BUS_BUSY_TIMEOUT);
*(u32 *)0xe000e014 = BUS_BUSY_TIMEOUT;
//SysTick_CounterCmd(SysTick_Counter_Clear);
*(u32 *)0xe000e018 = 0;
//SysTick_CounterCmd(SysTick_Counter_Enable);
*(u32 *)0xe000e010 |= 1;
    while((I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY))&&(!I2C_OT));
//SysTick_CounterCmd(SysTick_Counter_Disable);
*(u32 *)0xe000e010 &= 0xfffffffe;
    if (I2C_OT)
    {
      /*i2c bus is busy.  some other i2c communication is ongoing*/
      I2C_OT = FALSE;
      return BUS_BUSY;
    } 

 

我现在如果设一个全局变量 I2C_Timestamp ; 每进入一次SysTicker就自动加1
我的想法: 因为我现在SysTicker基准设置的是20ms。 因此这个全局变量是20ms加1。

那我如何修改呢?




使用特权

评论回复
24
香水城| | 2009-1-5 16:16 | 只看该作者

如果你的Systick基准为20ms,最好自己找一个空闲的TIMx控制超

楼主的例程中的超时都是us级的,显然离你的20ms基准差的太远,所以最好按照例程的超时时间,自己找一个空闲的TIMx控制超时。

使用特权

评论回复
25
hjiongh| | 2009-1-5 16:27 | 只看该作者

晕,我用101的片子,3个TIM都用完了

使用特权

评论回复
26
hjiongh| | 2009-1-5 16:34 | 只看该作者

原来的例子库um0427的有问题吗?

那样的话,看来我要用um0427 的例子库了, V2.0.3版本的。 这个是不用SysTick的。不过好像大家都说有问题。

使用特权

评论回复
27
hjiongh| | 2009-1-5 16:46 | 只看该作者

我用2.0.3版本的可以了。这个版本的只有方便

2.0.3版本的只有方便嘛。 楼主给的太麻烦了。 

使用特权

评论回复
28
lut1lut|  楼主 | 2009-1-5 17:16 | 只看该作者

hjiongh肯定没有看压缩包中的文档

文档一来就说了为什么要做这个封装库~~~

而且在“c)    基于I2C-E2PROM例子的修改”段落中有分析2.0.3中会出现的错误~~~

使用特权

评论回复
29
lut1lut|  楼主 | 2009-1-5 17:17 | 只看该作者

占位给中断方式的封装库

中断方式
/*************** 请参看文档 ******************/
1.与查询方式的接口区别在于读写函数的返回参数都只是void
2.Master 读/写函数:初始化通信参数,然后发送start开始通信,于是返回。
  Slave读写函数:初始化通信参数,然后返回
函数返回了,就可以做自己的其他事情,剩下的I2C通信过程由中断来完成。MCU可以随时检查相应标志,根据标志情况来采取对I2C的其他行动
3.文档中有主/从设备进行读/写操作,四个情况下的中断响应流程图,供参考。

/*************** 项目例程 ******************/
4.两个项目共有源文件,只是各自的main不同,分别跑在两块STM32板子上,一个是作为主设备的I2C1,一个是作为从设备的I2C2.

5.主设备的板子上还有个一个永远是从设备的e2prom

6.主设备的<main.c>,两个测试Test A & Test B,分别用[#if1 #endif]。主设备先对另一个块板子上的从设备STM32的I2C2进行读/写;在对自己板子上的e2prom进行读/写。

7.从设备的<main.c>,就一个测试Test A,对应主设备的读/写操作

8.例程中虽然在读写操作函数调用后即返回,随后仍然以while的形式等待读/写操作真正完成。实际上,用户完全可以函数调用返回后,作自己的事情,比如其他数据的处理。让处理完成后,check状态,再继续。

9.上传的项目中没有带第三方驱动,打开项目是,弹出项目初始化错误提示框,请大家自己指定路径即可。

链接文档如下

I2C主设备例程项目文件

I2C从设备例程项目文件

使用特权

评论回复
30
eddia2000| | 2009-1-5 19:23 | 只看该作者

中断方式的封装库在那下?

[占位给中断方式的封装库]在那下哦。

使用特权

评论回复
31
汽车电子| | 2009-1-5 21:57 | 只看该作者

STM32这么好的资源,DMA怎么不用呢?

   在设计新产品,我准备所有的驱动都用DMA

使用特权

评论回复
32
lut1lut|  楼主 | 2009-1-6 09:10 | 只看该作者

占位给DMA方式的封装库

使用特权

评论回复
33
hjiongh| | 2009-1-6 11:10 | 只看该作者

果然,我用2.0.3版本的出错了,在内部while里面

使用特权

评论回复
34
hjiongh| | 2009-1-6 17:31 | 只看该作者

看来我只能模拟了

我SysTick,3个TIM都用掉了。我用的是101RC的片子。

所以我只能GPIO模拟了。无法享受硬件I2C的乐趣了。

使用特权

评论回复
35
香水城| | 2009-1-6 17:53 | 只看该作者

所有定时器通道都占用了也照样可以使用定时器的定时功能

STM32中所有的定时器都是使用一个计数器循环计数实现定时功能,对于楼主的I2C函数,所有的超时控制都是us级的,可以说这个时间基准大大小于你的任何一个定时器的基准,因此你可以通过读出任一定时器的计数器数值,并通过比较,得到I2C函数中要求的us级超时检测。


以使用Systick实现这个功能为例:Systick是使用AHB时钟或AHB时钟除以8作为计数器时钟,假定你使用了72MHz的AHB时钟作为Systick的时钟,则Systick的计数器每递减一次表示13.9ns的时间;如果需要控制一个2us的超时时间,则需要判断Systick的计数器是否递减超过了144次。

示范程序:
  vu32 I2C_Timestamp;

  I2C_Timestamp = SysTick->VAL - 144;
  while (I2C_Timestamp < SysTick->VAL); // 等待2us超时

请注意:我这个示范没有处理Systick计数器减到0再Reload的情况。

使用特权

评论回复
36
LPcfANS| | 2009-1-8 14:11 | 只看该作者

mark...谢谢...

使用特权

评论回复
37
LPcfANS| | 2009-1-13 11:51 | 只看该作者

在初始化函数I2C_Comm_Init,运行不下去.

如果设置SysTick_CounterCmd(SysTick_Counter_Clear);后运行不下去.但设置成SysTick_CounterCmd(SysTick_Counter_Enable);可以运行,但读出来的
re1=2
re2=3,
re3=3,
re4=3;

使用特权

评论回复
38
lut1lut|  楼主 | 2009-1-13 16:45 | 只看该作者

从返回参数来看

re1=2  --〉bus busy
re2=3, --> start send err
re3=3, --> start send err
re4=3; --> start send err

第一次通信时,I2C总线应该不是都为高电平的idle状态,所以Busy位一直被置位,函数返回re1=2 (bus busy)

余下的三次通信,按理如果总线不变的话,应该还是返回bus busy啊,但是实际是start send err。即MSL/SB/BUSY没有都被置位。看看此时寄存器的值,并且看看start condition的波形到底出来没有。

一般来说,如果start condtion发不出去的话,都是因为总线还是busy状态,但是你说没有返回bus busy,倒是有些奇怪。

使用特权

评论回复
39
LPcfANS| | 2009-1-14 09:27 | 只看该作者

用万利199板子,返回的都是2..BUS BUSY..

使用特权

评论回复
40
LPcfANS| | 2009-1-14 11:08 | 只看该作者

终于搞定了.在开始I2C前,把I2C设置成数据IO,然后拉低.

使用特权

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

本版积分规则