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

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

[复制链接]
netlhx 发布时间:2015-11-8 20:18
本帖最后由 netlhx 于 2015-11-8 20:35 编辑 9 R2 \% r4 G1 ]7 x, B' ]" ~

" o) a& _( u2 B+ I/ l( tNUCLEO-L476RG到手一段时间了,今天来测试一下硬件I2C的操作,听说很多BUG,试一试看如何。
9 U  t7 j  f" {; M
+ b6 I8 x' R3 }3 s; {, h准备用I2C来访问AT24C02 EEPROM,将数据写入到EEPROM中,然后再读取出来,验证读写操作的正确性。
* I" |5 h% U+ B4 f& E0 b+ @, S, e$ ]* ?$ X: y) ?7 N" N
硬件平台如下% q2 A& x* @5 y

1 y- D9 w+ |) l1 W+ A/ M, S; ?0 K+ m3 p6 K  a9 _
NUCLEO-L476RG) E" L# i% T6 ~% q2 a5 \

2 y0 \1 i  \, c; U( x# \ nucleo-l476.png ' Q8 s, [. f' }% F- [% P
3 K; i9 m# {" u) l2 @
前段时间FSL的KL02Z套装,上面的MINIDOCK扩展板上恰好有AT24C02,所以借过来用一下,FSL不要生气啊) b# C, `. b6 |2 v

2 M; l8 n; X& o* H9 \8 g% f minidock.png & V$ k( P0 G8 s- [2 S+ M: s  j( P
! q2 p( V" l1 U4 ^& h; l1 x
标准的ARDUINO接口,放到哪都行。合体照。3 i9 O+ \/ z( F' o- z
* A9 }/ P6 H' G) c+ d8 |0 f
test.png
; h& ~( V7 b/ }  f
6 e  d2 _$ n4 J硬件连接及原理图
3 G4 T, z" [" @+ J' H( \, c& H' }3 N7 @, r1 Y# L* }; I
MINI DOCI上的AT24C02连接
( i8 k+ b  Z  ^' G
" g( P" `' O4 X2 e  ^; S5 S& _0 |( R QQ截图20151108162714.png
& |0 e% V! O3 B& V* {+ f3 e$ Q
5 V& n7 x2 E# bARDUINO接口:SCL及SDA
2 b9 D" i4 z9 [% y: L* Z- M$ ~/ |+ a8 L
QQ截图20151108162724.png
7 r  Y$ c' z; `3 S1 d
; Y$ b/ h! p- Q; ~6 Y( wNUCLEO-L476RG上对应的接口
" J  ?9 f; h/ d$ B4 S% O, ?- e
  I* n; H5 k* v nucleo-l476rg-review-16.jpg
+ L! u& o- U' \/ K( O; w2 F
' T4 z- d$ w7 [) Q. ^4 w
" E" g! _  E4 Y% l3 O' z  o) S" ^写程序之前,要了解硬件的基本特性,首先是STM32L476RG上I2C接口支持的特性;其次是AT24C02的特性。& C8 }0 f2 A4 B  `
! l$ ?, J- R7 Y- Y) X5 |
STM32L476RG的I2C功能框图如下8 Z, n. F0 c) c

- B* e, d+ m0 Z9 m6 g" p QQ截图20151108154725.png
& J3 `6 ?7 Z' S. j
: d+ n( \9 y6 ?$ u/ C0 A1 c值得一提的是,L4的I2C有自己独立的内核时钟,可以在SYSCLK、PCLK及HSI中任选一种做为I2C的内核时钟。另外L4的I2C支持三种不同的通信速率:100KHZ, 400KHZ,1MHZ。由于AT24C02只支持最高400KHZ,所以这里就选择400KHZ做为内核时钟。1 Y& `9 y7 Z7 i( X. {4 o
7 L0 `' n: g. J* \( \$ R
创建I2C测试工程,建立过程略。几点要注意的地方。
$ s9 ^8 O; Z+ n2 e
) V" u% V( J. t7 m. s5 J  J( b首先,本例程中使用的是I2C1,对应的SCL及SDA引脚为PB8及PB9,时钟配置后SYSCLK为80MHZ。) `5 G5 e& w0 m
1 \$ W1 \6 C) s  L, k
I2C硬件配置参数如图% C! v2 d" R6 K2 r6 k0 U) q: i
! y1 j! F- @3 r6 `1 x
QQ截图20151108172523.png
& S4 G9 r+ ?1 V. \
& k9 C% L( j+ w7 P9 `" G& N: n速度有三种可选:标准,快速,快速加。另外针对不同的特定应用,可以选择设置上升和下降沿的时间,以纳秒为单位,范围为0-120纳秒之间。注意这个TIMING参数,是灰色的,CUBEMX自动计算并设置该值,不像以前的F0和F3系列,需要一个专门的工具来设置TIMING的值,够麻烦的。
. q! P  L7 |( l$ p$ D5 Y- [5 s- ?; i3 o* A
下面是使用HAL库与EEPROM通信的主要代码。
4 g2 S; C2 e/ T2 ~) H
/ @# V3 y4 O4 K* p0 f! f: h/ u8 O/ d# t- c& V( p
  1. /* USER CODE BEGIN PV */
    3 }3 I. r" V8 E3 @" X9 z
  2. /* Private variables ---------------------------------------------------------*/) B# o, D2 x, j8 Y6 `5 w
  3. #define EEPROM_ADDRESS        0xA0( {1 G: q6 M* S- ^8 ?/ O" g5 |
  4. #define EEPROM_PAGESIZE        0x11* x8 v1 X& Q  l8 r$ \2 z) Q
  5. #define EEPROM_TIMEOUT        1000: Y- y8 m! n7 N$ F

  6. 3 v( o% E; E2 h1 y& k
  7. extern I2C_HandleTypeDef hi2c1;. g9 F" v& F& @; @( |$ t

  8. , m( X7 N: \( d* X( W2 d) i
  9. char msg[] = "This is a test!\r\n";
    * y  k5 M# q1 ?  t
  10. ! ?: B( A$ j0 Q5 E& b  m; `
  11. char buf[40];
    5 G) M- q: D. i- e
  12. & I8 ?% |6 X) R& ^, o
  13. int16_t Remaining_Bytes;
    / C$ S; E' K3 }8 K9 s7 G
  14. uint16_t Memory_Address;
    . }* b& [+ s6 O
  15. 9 O( C$ J- |- `( N0 P
  16. uint16_t len;
    , ^' b0 a9 g1 q) [; H: d+ b

  17. & e) K$ w7 e0 ~8 x% w
  18. ......
    * Q1 ?( R1 o1 }& G/ J
  19. ' w4 e/ Z# F, l: ~
  20. //write msg to eeprom
    * P6 K* m3 q& g8 s) W2 W8 K7 ]
  21. Remaining_Bytes = strlen(msg);
    / \. b$ m# w; T8 D7 m
  22. Memory_Address = 0;
    ; x# @% j. [( ]6 f( D+ L
  23.         
    # [" o' Z6 [8 t" A! P3 u# B) R  M
  24. while(Remaining_Bytes > 0)
    $ z- z# U, m3 a; f
  25. {
    # y& ~4 ?% E5 U* [+ i* _
  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)
    5 n9 C* D. v* b# w) |! w2 C
  27.       {) f7 I7 X* C: o; d& c- t0 o% O1 K+ P/ t
  28.               Error_Handler();
    ' k- ?9 m( _2 ^, w
  29.                         
    / v1 ]; J# a0 T4 s" O) o9 g* X
  30.        }
    4 v# \! R' V8 d# I% D& \
  31.                 # g. f) `: O; ^3 U' l" p
  32.        while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
    1 C* A- u5 N2 u. F. ~" }  n* z+ Y2 I, d
  33.        {
    3 N" u" I6 S7 H
  34.        }; Y/ o+ T: Q8 m- m4 v
  35.                
    2 ?7 R+ y2 I2 N9 I9 k5 H3 |
  36.        while (HAL_I2C_IsDeviceReady(&hi2c1, EEPROM_ADDRESS, 10, 300) == HAL_TIMEOUT);
    ( g0 N3 \  Y. Y9 J9 T  D
  37.                 0 }( ~3 ^5 h4 C  P3 t9 F" v
  38.        while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)( M$ J- d/ [  p0 |- ~5 A
  39.         {" y( {1 K2 O. k8 }
  40.         }
    ! r% X5 w& s* ~$ U! q- _( T
  41.                
    - f) {. `" y1 u7 k; e6 u
  42.          Remaining_Bytes -= EEPROM_PAGESIZE;
    7 A! \9 ]$ _4 U$ X7 P# `
  43.                 & O- J2 V, E8 c
  44.          Memory_Address += EEPROM_PAGESIZE;# z/ ^: R1 _: q+ }: m. ]
  45.         }: t( j* v! j3 Z9 L3 ~
  46.         
    1 ]% c2 i; m& ]3 g: G0 L
  47. //read msg to buff0 _1 z$ {5 s7 ]) @

  48. 8 i5 p' ]' u1 R3 q& ~8 j! j8 s
  49.   if(HAL_I2C_Mem_Read_DMA(&hi2c1 , EEPROM_ADDRESS, 0, I2C_MEMADD_SIZE_8BIT, (uint8_t*)buf, strlen(msg))!= HAL_OK)' b/ x- k; [% q7 z  ]
  50.   {
    5 @4 a6 C6 g6 S# W" c4 l
  51.     /* Reading process Error */
    . }) O! C/ g# Z; v) D
  52.     Error_Handler();        
      V$ y, \! M5 ]0 Z/ r
  53.   }
    : I# Z( A  q. r0 w3 h
  54.   
    4 i4 @. V% M* q" d5 F" y; b( V, ^2 ^
  55.   /* Wait for the end of the transfer */  & V( u) V- z2 ]$ h- o, u3 \: ]- L
  56.   while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)) d7 M# U3 g2 L
  57.   {7 c, i0 p. L$ i) C  [
  58.   }
    2 ]% p  z$ V/ k+ ?  u% V
  59.         
复制代码
2 {  H8 U. Q' ]! Y- x
根据STD库中用户的反馈,I2C出错的原因主要由几方面造成,一是ST设计的I2C接口,通信过程中一些状态变量及标志位的设置非常严格,如果程序逻辑考虑不周全,会导致I2C停止工作,需要软复位后才能继续;另一方面,I2C接口在处理单个,双字节及多字节传输过程中要分开考虑,进一步将问题复杂化了;还有就是结合具体的I2C设备,不同的时序要求,进一步复杂化了通信过程。
7 x, a. l  v) ]0 a' R) Z: Z, H
0 I- F7 {. F) |; H" J7 `5 x这些问题在HAL库中都得到了很好的解决,为此,HAL库中设计了几种不同类型的API函数供调用。一类是通用的接收和发送函数,这类API函数将I2C接口视为类似于“流对象”,通信时从流对象中接收或发送数据;另一类则是类似于EEPROM之类的特殊存储对象,从这些存储对象中接收或发送数据时,都需要提供一个地址,以便准确定位。使用EEPROM来实验时,我们使用的是第二类API函数。两个主要的API函数原型及参数如下。
5 x, X* D) i3 e6 k1 P
% _  E4 d7 @' s& h: F& _4 A
  1. /**! R, S5 q' L, y' O' h4 y' R! t) d6 X
  2.   * @brief  Transmit in master mode an amount of data in non-blocking mode with DMA
    , ?: V7 t1 p' t& Z, \
  3.   * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains
    - u+ l6 E3 A3 x% M' V% y, O
  4.   *                the configuration information for the specified I2C.- _8 g" [; ^; c% Z
  5.   * @param  DevAddress: Target device address
    * I* o7 \1 W* f7 z+ B/ Q# {
  6.   * @param  pData: Pointer to data buffer3 T; A; B+ P" j9 e# r' W. b. v
  7.   * @param  Size: Amount of data to be sent3 D; q- }' z' p4 c. Y
  8.   * @retval HAL status
    9 l6 a% T; Q. v
  9.   */
    " F- L: O. x- m2 `( o, c
  10. HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
复制代码
  1. /**
      U5 x( ]3 B  ]* O( J# z7 v
  2.   * @brief  Reads an amount of data in non-blocking mode with DMA from a specific memory address.3 e! m" s/ Q, A6 C% K
  3.   * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains, E+ u3 P4 Q1 i& S/ q$ J) W* T
  4.   *                the configuration information for the specified I2C." ?+ h# n1 `1 I/ }) n
  5.   * @param  DevAddress: Target device address
    1 w- V  c- x6 X9 C' y6 S) x1 J
  6.   * @param  MemAddress: Internal memory address
    : j0 q! t; f. t, d; D6 E
  7.   * @param  MemAddSize: Size of internal memory address
    + ]! p6 _8 ?9 c6 e
  8.   * @param  pData: Pointer to data buffer
    5 ^* l) b4 L4 u2 C' ]0 _
  9.   * @param  Size: Amount of data to be read
    5 Z& C2 j0 u2 \5 N
  10.   * @retval HAL status2 ^8 W" U2 T+ l
  11.   */
    5 D7 e* }) E' B- u. h
  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)
复制代码
3 `# C. V# t. y; j
关于这两个函数的更详细的调用方法及说明,请参考API文档。
; D0 h7 @& \9 ]0 }0 O# _' Z5 @! k, m
注意在具体操作EEPROM的时候,还要注意,EEPROM分字节读写及页面读写两种类型,对HAL API的调用还要进行适当的修改。
) _) q5 g8 C9 Q4 ?" J  |- ]% o1 u) s* p( d' _$ v" L* F$ V: ~
由于ST HAL API做了大量的后台工作,上面的代码看起来过于简单了。但实际上API函数在后台做了大量的工作,这不正是我们期待的么!
) C/ D9 b  q! i  A6 \  q4 C/ q+ Q: t7 D4 ]+ l3 U
最后来看看运行结果。2 R5 a( p/ [, G3 x3 |

, o+ a3 H' D9 x* q9 j+ J- W+ `UART打印的写入及读取取结果
9 t) c3 V' }* ^/ _" t# g: l
3 w. h5 e6 R6 Q# [3 i( r. ` QQ截图20151108200641.png ) H8 `- m2 }# ^7 X

2 {* Y8 {. j& p2 d+ q逻辑分析仪LA/ H9 I, Q' A( m4 x: u! T) {
" _& A  L5 V; k% B2 B0 c- i
无标题.png % ^/ v- g7 Y/ b' s5 D( d0 ^. G

# L) _; h# h9 rI2C通信全程,LA分析结果: b! \% B9 W2 v* Q( s
2 J$ b0 N& [, Q! e9 _
QQ截图20151108200233.png 4 ]! m6 O, ~; i

, F! r9 m' m  v9 k6 S/ |+ ^* f  c开始通信,顺序依次是开始信号,地址,EEPROM写入地址,第一个数据字节* R& b: B- O7 l6 I" ~* n8 A- w

; Q/ Q/ `7 u2 Z, ]" S* C QQ截图20151108200331.png + R1 ^% N. Q' J; B
- k$ F9 p0 E% h, b$ }4 {3 |
字符0x0D, 0x0A, 结束信号。* a2 L9 }1 N; U$ P/ r) ^

0 }5 S! {& z1 o, T, N QQ截图20151108200410.png $ W; Q* A7 B8 m: l* t# w

  Y( P# Y0 F3 [( K接收开始,顺序依次是开始信号,地址,EEPROM读取地址,第一个数据字节: k. m6 F+ c1 P4 F7 r  S, ?7 n& j7 H

% A8 z: n, c% \ QQ截图20151108200439.png ' Q% F, j* H" t& @" x' F

- [- |1 `# q; p7 Y) Q" K5 \读取结束
  C3 W6 e/ T' }0 w9 \- e- m+ p0 L3 \9 A& {1 S: G
QQ截图20151108200502.png 2 c$ ]2 J7 |  |7 k- p0 @

* s" u1 n& W8 V/ v2 j9 S1 z% t$ f7 _$ R" X8 b2 t) i. L/ u

4 E+ R" I* f9 R& n+ J/ k$ V* N附工程
( h/ U$ O5 ^0 p; }! ~9 S, G! }- }7 }+ k
6 M; C* ~; R2 e7 T/ Y 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)& I, v. Y, h) v) R  S- h6 Q1 E. t
                {
  j9 }2 G" n$ Q# U% N                        Error_Handler();/ M, g# p2 [3 ?7 ~& M/ H7 `/ E0 Y# L
        };程序直接进入Error_Handler()函数,请问是什么原因呢?我检查了很多地方,还是不行,求指教,非常感谢!(测试环境stm32l476rg+at24c02,后来用了at24c16测试还是失败)
Inc_brza 回答时间:2015-11-9 00:43:23
对比过硬件IIC和模拟IIC,硬件的IIC直接被模拟IIC给打爆!
( w( x1 X) W& q4 T* t1、移植,直接秒杀不用多说
8 K9 B1 A& K9 @& N) T* q1 X1 w2、效率,IIC的硬件通讯过程中用了太多的访问标志位,实际效率不会增加,一样是让CPU在耗,
0 k. L' J2 |2 r. U: S              所以,效率反而没有模拟IIC高,因为GPIO的反转速率轻松满足IIC的通信速率,所以0 k3 n9 G" I0 m6 Z/ i. W& p
              模拟IIC照样更胜1筹。
( R! u' o  e; x1 h$ e3、复杂性,ST的通病,反而模拟IIC更加把协议变得很直观。! S5 v$ ?. a1 G. R% e
纵上所述,感觉这个硬件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. x$ ?: _8 b% V+ E$ o" I2 K
这个逻辑分析仪是啥牌子的?多少M?那个打标线不错。。。

% D5 H+ ?/ V- h$ K' C& n梦源的牌子吧,100M
12下一页

所属标签

相似分享

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