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

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

[复制链接]
netlhx 发布时间:2015-11-8 20:18
本帖最后由 netlhx 于 2015-11-8 20:35 编辑 1 L8 u# }5 }) N! S! q) h; R- l

8 ~5 u+ u. M, h( B( U& R) F& {NUCLEO-L476RG到手一段时间了,今天来测试一下硬件I2C的操作,听说很多BUG,试一试看如何。
' `( |" m3 _% ]( Z& n- A
: {: m+ v' O- q0 E% q准备用I2C来访问AT24C02 EEPROM,将数据写入到EEPROM中,然后再读取出来,验证读写操作的正确性。
) e3 Z$ X7 i( s' h  }# P$ D7 c% B2 _. R, e2 H
硬件平台如下% l" w( P) @" i; b* w" A0 P
! j/ q( s5 T9 @' A9 g5 E- g3 n: q

9 q' D8 o( k( w" H+ e$ Y/ m9 @NUCLEO-L476RG
5 ~; V+ Q4 I5 C$ t9 x8 l! P
8 T' S' G" P) D; h7 ^ nucleo-l476.png # \0 l- [8 V9 h) A5 j5 g
) D. l/ C" t# p: K( w
前段时间FSL的KL02Z套装,上面的MINIDOCK扩展板上恰好有AT24C02,所以借过来用一下,FSL不要生气啊
$ f6 T1 V, c$ y4 O8 ?2 N, P! C1 D3 X8 Y0 d1 N& S
minidock.png
! O" a, x+ e" j# s9 n6 R' e
+ k6 f- m. w9 d! @4 d标准的ARDUINO接口,放到哪都行。合体照。6 a: x1 ]1 ^2 s/ y; J) ^

  r; ]: N5 i8 [ test.png * A0 F8 g& Q( K0 A1 K1 u- p  I& M
3 R3 D! B1 z% |6 b$ }* j- x4 l
硬件连接及原理图1 k% D: ]" M6 `/ z

( N# H% N" B0 N' RMINI DOCI上的AT24C02连接
. V) v. r& C# ]- i( x& ?  Z
# T& x9 ]: {' K# D$ [ QQ截图20151108162714.png
* T& U& h& M' N0 V, d
. v. P3 b! h- R" T4 ~% b# E8 ^ARDUINO接口:SCL及SDA
" B. I' |+ d3 m; p) V. `0 {* x$ N8 u" X/ p  d
QQ截图20151108162724.png
6 O8 U1 g* V% c) v
# i/ j# H) V, x/ i) k$ cNUCLEO-L476RG上对应的接口$ ]% L4 |1 E7 T6 P5 _
9 s, G% j" j3 D; [
nucleo-l476rg-review-16.jpg $ [% }* H2 i, z1 U* ]/ i3 I
6 R- p) [7 V, U* Q) c
; s. p) \+ k) G, s
写程序之前,要了解硬件的基本特性,首先是STM32L476RG上I2C接口支持的特性;其次是AT24C02的特性。, l: d, Q- Z7 i) ]

7 V. ^2 C; c* ~. E, [" U4 kSTM32L476RG的I2C功能框图如下/ _! n3 V& u  |/ a5 f6 z

  E" l) E5 G; g' ? QQ截图20151108154725.png ( p. r, K- v/ S

7 V# |& {3 l% _2 a, R% }; c8 Z) o值得一提的是,L4的I2C有自己独立的内核时钟,可以在SYSCLK、PCLK及HSI中任选一种做为I2C的内核时钟。另外L4的I2C支持三种不同的通信速率:100KHZ, 400KHZ,1MHZ。由于AT24C02只支持最高400KHZ,所以这里就选择400KHZ做为内核时钟。( R  P% d- ~7 B2 P1 R! Z: j

+ [# y! `3 d- x! C6 }创建I2C测试工程,建立过程略。几点要注意的地方。
. E' y8 J% L, r4 e% D, c* F7 {2 |& G, Z0 u! Z' f
首先,本例程中使用的是I2C1,对应的SCL及SDA引脚为PB8及PB9,时钟配置后SYSCLK为80MHZ。
" U. S% U' _9 u' R2 c$ Q( |$ C) v/ ^3 q; K+ ^3 f, w, u8 K
I2C硬件配置参数如图" p+ p/ G- J% M3 t8 ]# f- ?
, ~0 @3 L0 g, P4 |2 A, p$ H* V  }
QQ截图20151108172523.png
  S* n+ U! ]; y5 o9 @0 A# }& u8 f4 T& P. }8 D+ w) \
速度有三种可选:标准,快速,快速加。另外针对不同的特定应用,可以选择设置上升和下降沿的时间,以纳秒为单位,范围为0-120纳秒之间。注意这个TIMING参数,是灰色的,CUBEMX自动计算并设置该值,不像以前的F0和F3系列,需要一个专门的工具来设置TIMING的值,够麻烦的。- C( ?+ E( r6 _$ F5 Z4 z
! |8 v' N' _7 ]" K, `
下面是使用HAL库与EEPROM通信的主要代码。
7 T0 x  j+ `+ U8 ~: o* Y2 g1 j4 g% ?

% R$ J) l' F4 b+ i; \5 @  Q1 K% q: C
  1. /* USER CODE BEGIN PV */
    # P0 ~( E1 n, Y6 T/ {
  2. /* Private variables ---------------------------------------------------------*/! \1 Q6 ~6 r. P8 P  A  T& V
  3. #define EEPROM_ADDRESS        0xA0- ]* y, H, F" }+ ?) [" E8 H6 C
  4. #define EEPROM_PAGESIZE        0x11
    ! A, S; i5 c; ?) P, ~1 j
  5. #define EEPROM_TIMEOUT        1000
    ' L: w8 O, y) c" N, _) p2 X8 w' e; v) j

  6. & s' p6 Z- W7 e; W3 |
  7. extern I2C_HandleTypeDef hi2c1;6 A) }5 e( [# \6 f7 o+ V+ C3 j
  8. 1 m- v0 b' d$ y* V; J/ B4 A
  9. char msg[] = "This is a test!\r\n";
    " _, G6 A+ J2 K7 k+ c: v( a
  10. * Y; j$ W2 B, i- ~3 C9 @+ T6 T
  11. char buf[40];
    1 B; |" |' g; `
  12. . V0 C% v: O3 ]; h
  13. int16_t Remaining_Bytes;
    4 P: R8 Q1 D9 a5 G& B3 {+ j0 x
  14. uint16_t Memory_Address;6 U& k( W- o% h( ^

  15. ' R  P: \& l! R# A
  16. uint16_t len;: {9 m5 z; m: `& q4 I2 P

  17. * \5 U0 ^! b' k
  18. ......
    ) C, ]0 V, I+ l3 H! k( D- U

  19. : l5 X4 V/ u3 m+ m: v
  20. //write msg to eeprom
    " |  M/ `) ~! E6 ^8 f
  21. Remaining_Bytes = strlen(msg);
    " |! L9 _* ]1 h
  22. Memory_Address = 0;
    6 k7 R' ~5 w/ f
  23.         
    5 D, y* x) j- O: h1 x
  24. while(Remaining_Bytes > 0)
    5 S" U% G( g  h1 M
  25. {
    9 ]! u6 t7 ?+ U
  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)- W# s! P6 k$ s
  27.       {' ?+ b3 r3 J; R0 z3 t8 a. k
  28.               Error_Handler();+ X- [$ r; o' }5 i8 S; X7 U8 L
  29.                         6 K9 Y# A$ u' v/ w6 U6 m
  30.        }
    : w) x* X+ B( I  _
  31.                
    3 J: C: I, Z$ z" D* s' Y4 W
  32.        while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY); Z+ G2 g' W" ?+ ^( ~8 Z
  33.        {9 ]" c; J! B% w% o
  34.        }" n. k; V6 ~% X
  35.                
    * H  z; H4 t, ~7 v
  36.        while (HAL_I2C_IsDeviceReady(&hi2c1, EEPROM_ADDRESS, 10, 300) == HAL_TIMEOUT);
    . C  s3 n/ U; f' n; }# q  J
  37.                 " Y. W4 |8 @% i% ?
  38.        while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
    7 q! C4 n1 J5 l2 m7 C. ~0 W  M0 `
  39.         {
    ) z" X! }) Z: F  v3 b$ X, v) j
  40.         }
    1 s, ?: u2 ]7 L
  41.                 ; S% ]" A2 H9 q, C2 R
  42.          Remaining_Bytes -= EEPROM_PAGESIZE;
    : Y" v3 o& x. z& s% M( b
  43.                
    ) L6 \3 a' V  ^6 e, V4 x
  44.          Memory_Address += EEPROM_PAGESIZE;
    4 x1 a. N1 X% p+ f: L4 o# l, a. J
  45.         }2 Y& s  g# i7 \) ~3 i- X
  46.           ]3 p& `" p. u  i1 \
  47. //read msg to buff  Z5 @7 S$ v1 Y' W
  48. 6 {& r4 K4 D  ]# w% Q8 G
  49.   if(HAL_I2C_Mem_Read_DMA(&hi2c1 , EEPROM_ADDRESS, 0, I2C_MEMADD_SIZE_8BIT, (uint8_t*)buf, strlen(msg))!= HAL_OK)4 p; k- H  k  p* S9 I  Z. o6 U9 d; [& b
  50.   {6 I# q2 i, Q2 O# H
  51.     /* Reading process Error */4 @0 Q7 R) T4 H! P
  52.     Error_Handler();        
    * z( \) F4 R% U
  53.   }- p. a9 V# ~7 A* Z8 v) g
  54.   
    2 v+ C/ v2 O! a+ Y: d- d
  55.   /* Wait for the end of the transfer */  
    8 `5 l# `" f6 R9 W, L6 l
  56.   while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
    + U! f1 j- |( h- v5 `/ w7 e7 I
  57.   {- M9 s1 {' g5 N' ~9 t, I2 Z
  58.   }
    2 T8 f8 e' [/ p$ x$ n1 S8 g
  59.         
复制代码

4 c6 t+ K1 Z! c根据STD库中用户的反馈,I2C出错的原因主要由几方面造成,一是ST设计的I2C接口,通信过程中一些状态变量及标志位的设置非常严格,如果程序逻辑考虑不周全,会导致I2C停止工作,需要软复位后才能继续;另一方面,I2C接口在处理单个,双字节及多字节传输过程中要分开考虑,进一步将问题复杂化了;还有就是结合具体的I2C设备,不同的时序要求,进一步复杂化了通信过程。9 a8 z. T8 Q; W2 o& ^+ i7 z

0 i3 o5 h+ H- Z4 ]. d8 d! u这些问题在HAL库中都得到了很好的解决,为此,HAL库中设计了几种不同类型的API函数供调用。一类是通用的接收和发送函数,这类API函数将I2C接口视为类似于“流对象”,通信时从流对象中接收或发送数据;另一类则是类似于EEPROM之类的特殊存储对象,从这些存储对象中接收或发送数据时,都需要提供一个地址,以便准确定位。使用EEPROM来实验时,我们使用的是第二类API函数。两个主要的API函数原型及参数如下。
5 c$ B8 c& ?; X- j  O2 H
* m; R5 v, x) w* i/ [2 X8 c
  1. /**; x8 E  |' L: Q" g; Y$ G9 W" o9 V
  2.   * @brief  Transmit in master mode an amount of data in non-blocking mode with DMA* T9 \' H3 Q3 v8 `: j
  3.   * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains
    3 B* j) I0 V8 _2 }' i: V
  4.   *                the configuration information for the specified I2C.
    % H9 ~  P; C+ F% _
  5.   * @param  DevAddress: Target device address
    ' i- {2 n. v: D! a% W
  6.   * @param  pData: Pointer to data buffer
    $ v' u# T' _2 w$ |# ?( W
  7.   * @param  Size: Amount of data to be sent3 f+ x( u2 r9 x6 s& P% H
  8.   * @retval HAL status; L- v) V: ?' a) o9 m6 Y* f+ ?
  9.   */8 P/ U; v/ g- \7 c' P1 {
  10. HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
复制代码
  1. /**' [% m8 b: ~5 {2 f+ H
  2.   * @brief  Reads an amount of data in non-blocking mode with DMA from a specific memory address.
    3 f4 L1 O* @/ \  r) l( `
  3.   * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains& ^$ H+ h7 x! H5 d! T
  4.   *                the configuration information for the specified I2C.
    3 P+ u$ J: N$ w; J; {
  5.   * @param  DevAddress: Target device address
    8 y  S9 m3 ?0 z: R# {) |7 f
  6.   * @param  MemAddress: Internal memory address
    8 p: p: y- i4 O( Y
  7.   * @param  MemAddSize: Size of internal memory address) z, O' q2 L1 i# H3 g& C
  8.   * @param  pData: Pointer to data buffer; ^& ]/ X3 v2 ]. N' O* O
  9.   * @param  Size: Amount of data to be read+ x- @0 b( p6 h, X! v# k
  10.   * @retval HAL status
    : z, @* i: x' D( A6 Z6 m# o
  11.   */0 I. K$ }. d( y! l$ u$ |1 k
  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)
复制代码
* }% L% `1 ]- S8 _, ^4 I/ n
关于这两个函数的更详细的调用方法及说明,请参考API文档。0 P! s* @" ^5 i. [* R4 ^. q5 V

* [# h; Y' B' A* {4 z注意在具体操作EEPROM的时候,还要注意,EEPROM分字节读写及页面读写两种类型,对HAL API的调用还要进行适当的修改。+ N4 k) W! c$ K  V& d
0 A: u5 a# T2 ^8 v9 F
由于ST HAL API做了大量的后台工作,上面的代码看起来过于简单了。但实际上API函数在后台做了大量的工作,这不正是我们期待的么!
& B7 n: x8 Z7 v9 P: x  V- N
( i+ b+ r7 ]  \+ T最后来看看运行结果。& F  |) W. Q% E* z# X  V% n! ^4 r
# Y( \  o# E- _! T8 q
UART打印的写入及读取取结果- P1 T- K' `; @: q

* u% s; a4 u' l4 A& G& ~2 S QQ截图20151108200641.png
# S  q( u- T# M8 f0 m
/ f5 @/ Q3 Y/ L5 m' ~2 u$ V, I3 s逻辑分析仪LA: \. I/ `: s) w

8 x0 u4 D# O# L 无标题.png 9 N( b1 f9 l% N
, ]4 o" b# i  w( x
I2C通信全程,LA分析结果. v1 \$ [3 g2 m: }

% b! Y1 b! Q) S QQ截图20151108200233.png
9 F. v( y% S+ `9 V( w0 B/ M
0 e; u1 T% b; d) f" \: ?( X) G# H开始通信,顺序依次是开始信号,地址,EEPROM写入地址,第一个数据字节
  m1 M0 J( u( q% Z) J& }/ x' H' K& D  I, V
QQ截图20151108200331.png 4 w8 K+ @0 u) ?6 A) c! g
2 S- {7 i# ~) n. f4 t
字符0x0D, 0x0A, 结束信号。
3 P, U( ?# X7 t2 n. k/ t+ s
6 l2 J& {* E: z& y( }' X) e QQ截图20151108200410.png ) S* k, f5 F' i9 w9 W
3 D; ?6 }+ @( |# v# W5 p
接收开始,顺序依次是开始信号,地址,EEPROM读取地址,第一个数据字节
# A" J* \9 F0 n* _7 g# u9 B/ F. F
* s$ L2 s6 k( m QQ截图20151108200439.png 6 Z/ B$ v  U. @( l
; {) \# s- e1 S* W9 R
读取结束
# a$ u$ C  h2 S& x' X3 y2 e9 q  M) z* y3 }' o# c2 {
QQ截图20151108200502.png 5 w) p( ^# p2 X$ C

; J! A+ r' c5 Q  l" k; Z
/ q. i! }) L% h% i$ X4 |/ S% t) N& v# @3 b" k7 O9 B7 _
附工程! P# z0 a* _; H+ @0 F

* x- h# E  L# c. g; P# |) b eeprom.zip (3.17 MB, 下载次数: 201)
收藏 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)% D% b# i1 f0 Z
                {
" S$ G% A6 d- G; N% s$ s7 }                        Error_Handler();
7 o; u. q' `# A( r! I3 d/ h        };程序直接进入Error_Handler()函数,请问是什么原因呢?我检查了很多地方,还是不行,求指教,非常感谢!(测试环境stm32l476rg+at24c02,后来用了at24c16测试还是失败)
Inc_brza 回答时间:2015-11-9 00:43:23
对比过硬件IIC和模拟IIC,硬件的IIC直接被模拟IIC给打爆!/ X9 N  ~! Y3 D
1、移植,直接秒杀不用多说
7 X! L" M8 X* C  M* g; n2、效率,IIC的硬件通讯过程中用了太多的访问标志位,实际效率不会增加,一样是让CPU在耗,
" A8 S4 A/ K& P4 m1 u2 x: o              所以,效率反而没有模拟IIC高,因为GPIO的反转速率轻松满足IIC的通信速率,所以
# F/ x% R! V- l              模拟IIC照样更胜1筹。9 ?) H' K1 e  T5 s# f/ {& r
3、复杂性,ST的通病,反而模拟IIC更加把协议变得很直观。
7 {- V2 Z0 ]1 k' D9 \* U纵上所述,感觉这个硬件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
  @  W5 n) Y: L4 g* M这个逻辑分析仪是啥牌子的?多少M?那个打标线不错。。。
  V  P4 s/ y' F) \: h$ B
梦源的牌子吧,100M
12下一页

所属标签

相似分享

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