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

【NUCLEO-L476RG开发】硬件I2C 精华  

[复制链接]
netlhx 发布时间:2015-11-8 20:18
本帖最后由 netlhx 于 2015-11-8 20:35 编辑
1 t. q6 H/ Q7 }! p/ l& c9 m9 L* @  E, B1 w. K! Q
NUCLEO-L476RG到手一段时间了,今天来测试一下硬件I2C的操作,听说很多BUG,试一试看如何。$ G$ y8 S  V( d9 I, T. x% ]
# L1 W# E9 r6 }
准备用I2C来访问AT24C02 EEPROM,将数据写入到EEPROM中,然后再读取出来,验证读写操作的正确性。1 Y. x: z) D4 t$ Q0 d) c

$ }7 c. D& E& m# B' {/ Z硬件平台如下1 S3 B- }6 R- Q# Z

# ]  P  k& `( {3 |/ a4 X8 H
% I# M2 ?; l! a7 CNUCLEO-L476RG) `/ g$ y2 G* j. D

- s) k3 Y1 j5 [3 h& F" h3 C nucleo-l476.png
& B9 J8 |; f2 T7 T4 O6 B) s& i3 u! v1 X( d& X, g
前段时间FSL的KL02Z套装,上面的MINIDOCK扩展板上恰好有AT24C02,所以借过来用一下,FSL不要生气啊
# O, M4 n5 q. d- q. f4 X
/ m0 E3 Y) @: x8 s) s7 ] minidock.png * X( I, K0 x% B

- Y4 [  Y, S/ k" `4 U# Z标准的ARDUINO接口,放到哪都行。合体照。
: w/ m% K* c$ g, ^: V) l( H; {& g) }1 F  f( n. r
test.png
0 h$ p: V9 O, a% z* G  _$ N" H
& C) \; \$ l8 {: A硬件连接及原理图
5 H- ?1 N1 V/ W! G$ h- z
/ m- g9 t  p! D9 ?9 r) kMINI DOCI上的AT24C02连接( w# Y" l" f2 Y! V& n. B
( M7 ~' I8 J6 x- E" M2 u
QQ截图20151108162714.png
$ p# o8 v& ^% N, l" X
& r- g( O) `- @+ T& F  \ARDUINO接口:SCL及SDA3 z: K% @( F9 y- G4 y- R9 K
3 S$ a7 S8 U. A6 R7 ^) j9 Z1 T
QQ截图20151108162724.png
5 `4 N  s0 j8 L3 j7 r' M) m* d0 U& r' M
NUCLEO-L476RG上对应的接口
% f2 H- q8 V  `- S8 y# y$ {) @- F. U3 Q- _
nucleo-l476rg-review-16.jpg
2 Q% z, ~; y' p$ W& I. K+ }5 f! K8 R2 L  I
& Y7 r" x4 i, c/ y
写程序之前,要了解硬件的基本特性,首先是STM32L476RG上I2C接口支持的特性;其次是AT24C02的特性。# l9 h6 D8 G& W1 n  n

  m! S' I8 f$ Q1 C( QSTM32L476RG的I2C功能框图如下
3 E$ L8 t) L6 d1 }  w7 A+ N  p' A7 I3 ], Y& K  X3 {
QQ截图20151108154725.png
% l6 |5 Q' x! z" W7 w9 H/ ~, Y; v
值得一提的是,L4的I2C有自己独立的内核时钟,可以在SYSCLK、PCLK及HSI中任选一种做为I2C的内核时钟。另外L4的I2C支持三种不同的通信速率:100KHZ, 400KHZ,1MHZ。由于AT24C02只支持最高400KHZ,所以这里就选择400KHZ做为内核时钟。
# s6 C  x9 d9 s8 |1 m1 V: D0 x
' b8 ^: W0 ]* F# W创建I2C测试工程,建立过程略。几点要注意的地方。' E" E* X; U. G" q$ O; l3 L

5 a* s+ S) J. y; r% a; S9 F首先,本例程中使用的是I2C1,对应的SCL及SDA引脚为PB8及PB9,时钟配置后SYSCLK为80MHZ。/ O. L7 Y' y3 A0 p
6 l7 a0 j: \7 F) r/ F$ e0 I
I2C硬件配置参数如图( R$ e, N; Q9 H& [* t
' F" c# ]6 V* b+ U7 S2 {
QQ截图20151108172523.png ( C6 b" F' P! k

% m6 m0 z' t# M1 N" n* `6 R速度有三种可选:标准,快速,快速加。另外针对不同的特定应用,可以选择设置上升和下降沿的时间,以纳秒为单位,范围为0-120纳秒之间。注意这个TIMING参数,是灰色的,CUBEMX自动计算并设置该值,不像以前的F0和F3系列,需要一个专门的工具来设置TIMING的值,够麻烦的。
' L3 G( q+ t/ {, Y8 @& d: e9 L7 `$ N% V6 k. M( V  `
下面是使用HAL库与EEPROM通信的主要代码。7 j4 v3 c" c( S$ j
9 B5 |4 j4 F7 ]# x$ Z# s
2 w# y* D  n5 w; b& ]
  1. /* USER CODE BEGIN PV */8 }( L' S1 z4 k5 m
  2. /* Private variables ---------------------------------------------------------*/
    # u3 O3 W1 B# ?2 J* H9 z0 T1 M
  3. #define EEPROM_ADDRESS        0xA0
    ) Z' Y% }- J9 ]8 _' {
  4. #define EEPROM_PAGESIZE        0x11; W. L" o4 S8 ]( _. T$ O! K' ^
  5. #define EEPROM_TIMEOUT        10006 T; y! M8 r) d% X1 p
  6. 9 z, i  c4 [+ R+ `
  7. extern I2C_HandleTypeDef hi2c1;7 c( m% S) n* G6 ?1 z
  8. 8 j  p& D: y, j' M1 i) K
  9. char msg[] = "This is a test!\r\n";7 }! Y+ a% G; ?* R# L

  10. ! g! M# K) G3 O9 F% S% n& u% _  Z. x
  11. char buf[40];% D7 v4 G/ O8 ^4 n* k* T

  12. 0 q4 C1 k% K- @4 c8 d. \, x; c
  13. int16_t Remaining_Bytes;
    & Q6 b( [# V) j( r& a' w! s
  14. uint16_t Memory_Address;/ r: o" i* x1 K9 @  S- S6 o7 ^

  15. * L1 o7 L) h& t* s; y, j- G, O
  16. uint16_t len;
    & Q9 M# A8 M* e# r) v5 e! f% n
  17. : ]: Y5 ~5 d3 x& Q8 [% a  P9 ]
  18. ......( Y% n- E. s: R. V/ Q; `

  19. 1 X  |7 g/ a/ |) Z: G+ T6 W
  20. //write msg to eeprom3 B5 M6 k7 ~  I' n
  21. Remaining_Bytes = strlen(msg);
    " s2 ]7 `; m4 f& j# E4 Y
  22. Memory_Address = 0;
    + a7 e: p; C) t, A. h; ]
  23.         
    0 j/ {  p. S! F' G
  24. while(Remaining_Bytes > 0)# S. Y- V" G+ {& |: f
  25. {
    : U" s0 T* _, k! F; o4 S" Y7 C
  26.       if(HAL_I2C_Mem_Write_DMA(&hi2c1, EEPROM_ADDRESS, Memory_Address, I2C_MEMADD_SIZE_8BIT, (uint8_t *)(msg + Memory_Address), EEPROM_PAGESIZE) != HAL_OK). F. h, d5 M5 C& n; N( g
  27.       {$ M5 n3 ^) |) O$ F1 l3 a
  28.               Error_Handler();/ y. M+ V9 F/ c0 H
  29.                         + Y, h8 F, l3 M  R  a
  30.        }; W: b3 M! c* k) M! L
  31.                 3 R' O  g" _7 ], c. u, K& H- o  W
  32.        while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
    9 U4 G- Z4 _3 [# ?7 K! s" g
  33.        {: N0 ?0 G4 P6 e# F
  34.        }
    & q; U7 A, r7 l9 y
  35.                
    + v7 K+ \1 M6 C4 o
  36.        while (HAL_I2C_IsDeviceReady(&hi2c1, EEPROM_ADDRESS, 10, 300) == HAL_TIMEOUT);% t' [# r/ q' q" u
  37.                
    " @; m- X1 s% M4 c  H/ F
  38.        while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)& f$ ?8 V- S% B+ e
  39.         {* `' A/ m, n- s" R( P$ K7 P: H
  40.         }
    ' p6 P, C5 j: N9 e( f
  41.                 4 c/ @$ \9 Z6 L
  42.          Remaining_Bytes -= EEPROM_PAGESIZE;
    % X: ^1 y4 s: t
  43.                
    - |9 F. m' I6 _
  44.          Memory_Address += EEPROM_PAGESIZE;) O2 z2 x' X2 o/ Z* b( B- x
  45.         }" j; a2 a. z5 W+ a; Z+ u" U6 x, N
  46.         
    4 ~. F) V8 [6 ^! l7 c# y9 f) o
  47. //read msg to buff
    3 }1 T/ ~6 v) s+ d8 h

  48. * A) h  E3 [) x( B5 W. I8 ]- q& @3 u
  49.   if(HAL_I2C_Mem_Read_DMA(&hi2c1 , EEPROM_ADDRESS, 0, I2C_MEMADD_SIZE_8BIT, (uint8_t*)buf, strlen(msg))!= HAL_OK)
    : i7 k' h7 g3 f- t
  50.   {# G' p4 R0 a/ L0 k  E9 q, B( j
  51.     /* Reading process Error */' y3 Y+ ~9 a# `! Z% K& w7 o
  52.     Error_Handler();        
    1 f% i$ j% E+ v! [" B4 K9 |
  53.   }; d! g/ \% p' ^7 N  Z5 o5 S4 \
  54.   
    $ `' k; q( @* u8 [' _, g. v
  55.   /* Wait for the end of the transfer */  . W7 Y1 k- g9 j
  56.   while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)+ f2 Z6 F! c: l$ L: M
  57.   {
    1 u7 B4 ]4 ]% [3 C! S) r* J$ j
  58.   }
    $ V, p, Z0 m5 y9 j* ^$ x
  59.         
复制代码

) u/ j2 n7 m) H' U: Y根据STD库中用户的反馈,I2C出错的原因主要由几方面造成,一是ST设计的I2C接口,通信过程中一些状态变量及标志位的设置非常严格,如果程序逻辑考虑不周全,会导致I2C停止工作,需要软复位后才能继续;另一方面,I2C接口在处理单个,双字节及多字节传输过程中要分开考虑,进一步将问题复杂化了;还有就是结合具体的I2C设备,不同的时序要求,进一步复杂化了通信过程。, C1 L& ]- X  M* _1 b

3 M3 b9 [& d* j; y5 ?' V这些问题在HAL库中都得到了很好的解决,为此,HAL库中设计了几种不同类型的API函数供调用。一类是通用的接收和发送函数,这类API函数将I2C接口视为类似于“流对象”,通信时从流对象中接收或发送数据;另一类则是类似于EEPROM之类的特殊存储对象,从这些存储对象中接收或发送数据时,都需要提供一个地址,以便准确定位。使用EEPROM来实验时,我们使用的是第二类API函数。两个主要的API函数原型及参数如下。$ A4 b$ L% i7 N" h& P* \
2 A1 i. H, j3 z7 s, x5 D
  1. /**, w9 f; G( X# u) k# r0 Q: `. W+ k" @
  2.   * @brief  Transmit in master mode an amount of data in non-blocking mode with DMA, ~0 P9 h: C% ]
  3.   * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains
    2 l4 g# k4 P& o  P1 \2 F
  4.   *                the configuration information for the specified I2C.! I. t) i( n  C8 c8 B, a5 p5 w* T  x, w
  5.   * @param  DevAddress: Target device address
    # B7 f( a+ G: f
  6.   * @param  pData: Pointer to data buffer" G4 z& H$ i  L" R  [0 |
  7.   * @param  Size: Amount of data to be sent0 h" D4 _- Y; @2 r- A( ~) S
  8.   * @retval HAL status! Y- y8 _0 w0 ~. C, j
  9.   */7 _9 P+ f8 c9 W# B$ I$ K; t
  10. HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
复制代码
  1. /**
    " ~0 b% i% a4 N% Z
  2.   * @brief  Reads an amount of data in non-blocking mode with DMA from a specific memory address.
    3 l9 g' N9 }/ e' b# {* H( f
  3.   * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains7 y3 \# B  R: g5 {' n! }, @6 n; I
  4.   *                the configuration information for the specified I2C.
    : X7 c. n" t0 }) `' e6 H
  5.   * @param  DevAddress: Target device address
    * e' R5 c, I6 o: f8 L  ~
  6.   * @param  MemAddress: Internal memory address7 f& r1 u3 o! y3 P
  7.   * @param  MemAddSize: Size of internal memory address, e" T; A/ c4 `) B: O
  8.   * @param  pData: Pointer to data buffer
    : L2 V& Z5 Y  b! |0 F! r
  9.   * @param  Size: Amount of data to be read+ x/ q( b: z$ R3 @; M+ q
  10.   * @retval HAL status6 i5 i; U3 R7 z! e6 o
  11.   */% O8 N/ `  v1 j5 w
  12. HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size)
复制代码
: ~6 {2 X' C- s+ U$ b4 F  q
关于这两个函数的更详细的调用方法及说明,请参考API文档。- M5 H/ s1 {: a4 ^4 u! ^; n) W
7 h# x" K# i3 q8 q- X5 w2 b! q9 i
注意在具体操作EEPROM的时候,还要注意,EEPROM分字节读写及页面读写两种类型,对HAL API的调用还要进行适当的修改。
3 ^! a, a1 d0 }( Y- k. b& F- v# F* a. S; s6 v, _
由于ST HAL API做了大量的后台工作,上面的代码看起来过于简单了。但实际上API函数在后台做了大量的工作,这不正是我们期待的么!
9 r" C: F. i& Q4 `, I' }2 p& r$ B7 X0 L! L; v7 m$ V
最后来看看运行结果。
3 `& N: j+ n; R2 _1 C
, g/ |; n+ ?* t, wUART打印的写入及读取取结果
9 |6 Q1 ]  Z+ T  X' D! t$ J+ i0 P# g0 Z  U6 |; t
QQ截图20151108200641.png
' }8 T" L& f) U& m+ y: H' P* F% B7 @7 ^% m* v. S, |: {$ e9 o
逻辑分析仪LA; @; u9 Y, l. l( j5 n
) e0 Y& M7 M1 P9 C; `& N$ e; M6 P
无标题.png
# Z! P) E( N# [6 y8 v. J
( I% |; T! h& k4 [I2C通信全程,LA分析结果) y$ c% Q; w0 ?- \
3 t! ^* _' @6 A3 p1 M# d
QQ截图20151108200233.png
. |/ C& L# P; m* `, n4 B, E9 X0 _1 M% p" u& `/ `, M! u. ^2 N
开始通信,顺序依次是开始信号,地址,EEPROM写入地址,第一个数据字节
; H5 _! ~8 t- G# `4 b0 c7 F3 d( B* \4 W8 B" q
QQ截图20151108200331.png
! B& I' i$ V1 I( h3 ~+ }/ O. |% }
8 j' V, Y) e& Z$ M1 `0 W0 V字符0x0D, 0x0A, 结束信号。7 s6 R; S% r% u. S8 Q4 E
5 g% w5 `, r* Z. P  h) Y
QQ截图20151108200410.png
% {( \1 L0 x0 U5 X2 `8 _; k; I6 B2 u" }- _  t
接收开始,顺序依次是开始信号,地址,EEPROM读取地址,第一个数据字节5 Q: |) R3 }, o7 ?; Q$ T8 t
9 q" D& X3 X( y# W
QQ截图20151108200439.png
6 T, J2 k" ^5 O% ]  ^, f
, m0 K& z2 n/ G) e* I( Q读取结束
# Q$ r+ [, G7 f, y0 X5 j2 W3 E6 V" Q5 t& ?6 R8 ~
QQ截图20151108200502.png
+ F# @6 u+ Y& _  G2 i/ f6 e. l- t5 k  u8 U/ H6 y5 y
; R4 N. h0 x+ t+ V, M8 B6 ~* A

# N/ f9 g1 W' Z+ Z附工程
  p# g- N0 x( b5 T. I: t. u! y1 H+ T
eeprom.zip (3.17 MB, 下载次数: 203)
赞 收藏 5 评论20 发布时间:2015-11-8 20:18

举报

20个回答
lulongqin 回答时间:2016-5-8 23:06:50
楼主,您好,我利用您的代码测试失败,串口只发送了“Write to EEPROM:和This is a test!”,经测试,程序在运行        这部分是发生错误:        if(HAL_I2C_Mem_Write_DMA(&hi2c1, EEPROM_ADDRESS, Memory_Address, I2C_MEMADD_SIZE_8BIT, (uint8_t *)(msg + Memory_Address), EEPROM_PAGESIZE) != HAL_OK)
) X: S3 Z% u3 ]& ~                {
' M6 {8 U6 o8 n: [; R  K                        Error_Handler();
& e' `# m+ D  R1 {4 B% u, }8 u        };程序直接进入Error_Handler()函数,请问是什么原因呢?我检查了很多地方,还是不行,求指教,非常感谢!(测试环境stm32l476rg+at24c02,后来用了at24c16测试还是失败)
Inc_brza 回答时间:2015-11-9 00:43:23
对比过硬件IIC和模拟IIC,硬件的IIC直接被模拟IIC给打爆!( s- v( ?4 N6 g3 R, b
1、移植,直接秒杀不用多说
& ]' k; u' `5 p! W2 ^+ y2、效率,IIC的硬件通讯过程中用了太多的访问标志位,实际效率不会增加,一样是让CPU在耗,
; y6 i1 E9 I1 {9 Y, Z+ W) n. }$ S              所以,效率反而没有模拟IIC高,因为GPIO的反转速率轻松满足IIC的通信速率,所以
/ ~- g7 p3 t4 ?: y( W8 O7 \0 N              模拟IIC照样更胜1筹。
0 o, K( H8 I2 W% n: @3、复杂性,ST的通病,反而模拟IIC更加把协议变得很直观。
0 f4 F5 _& V" A纵上所述,感觉这个硬件IIC就是个鸡肋。
埃斯提爱慕 回答时间:2015-11-9 21:27:00
提示: 作者被禁止或删除 内容自动屏蔽
陈金华 回答时间:2015-11-8 20:26:37
沙发                     
netlhx 回答时间:2015-11-8 20:28:17
地板
qianfan 回答时间:2015-11-8 20:42:46
这个逻辑分析仪是啥牌子的?多少M?那个打标线不错。。。
Paderboy 回答时间:2015-11-8 20:57:26
多谢分享啊。。。。
2958155267 回答时间:2015-11-8 21:06:47
Hal库把底层都写好了,所以硬件i2c还是较简单的
kingsings 回答时间:2015-11-8 22:56:32
楼主好牛,两个板子都有了。而且还有逻辑分析仪
alvin_ 回答时间:2015-11-9 08:41:14
逻辑分析仪自己买的吗大神总是一鸣惊人啊
黄小狼 回答时间:2015-11-9 08:51:37
前来学习观战中。。。
奋斗逼 回答时间:2015-11-9 09:01:57
强大
戏如人生 回答时间:2015-11-9 09:05:51
逻辑分析仪都用上了啊??多少钱啊
watershade 回答时间:2015-11-9 15:24:45
楼主的逻辑分析仪花了多少钱?便宜的话推荐一下吧
aabird 回答时间:2015-11-9 16:52:41
这个厉害,虽然IIC很多人都觉得不好用
netlhx 回答时间:2015-11-9 18:40:19
QianFan 发表于 2015-11-8 20:42
  a( ]5 B9 M9 x这个逻辑分析仪是啥牌子的?多少M?那个打标线不错。。。
- o7 R5 M* R' H& x* m
梦源的牌子吧,100M
12下一页

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版