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

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

[复制链接]
netlhx 发布时间:2015-11-8 20:18
本帖最后由 netlhx 于 2015-11-8 20:35 编辑
+ h) Z6 [/ [) I6 L
- c" |% E! R- c- [, B( ?NUCLEO-L476RG到手一段时间了,今天来测试一下硬件I2C的操作,听说很多BUG,试一试看如何。
+ D7 I0 \" H/ l. N9 i! ~$ g( w5 m/ O" p) U
准备用I2C来访问AT24C02 EEPROM,将数据写入到EEPROM中,然后再读取出来,验证读写操作的正确性。
* u7 |  R* Y+ Z+ U1 b( ?9 ?. Y& w4 \$ T# ]; }% z+ k( i- M
硬件平台如下0 T( C! J# {3 L/ ^7 B" ~

* E! H0 b/ `3 }; B# B
; ?$ I6 d! a+ O* O6 i' h6 VNUCLEO-L476RG
" q0 d( x0 U: v) b0 c$ g' w; C, o: Y/ F0 q  G# d* m% R0 u- j$ l, L3 h
nucleo-l476.png
& [0 K0 P4 D* `$ e& T5 O3 O* q0 o" e; m
前段时间FSL的KL02Z套装,上面的MINIDOCK扩展板上恰好有AT24C02,所以借过来用一下,FSL不要生气啊) O1 L. Z' e) _# J8 Y: L

9 y; w3 \9 B4 t minidock.png 8 j, e+ K5 v0 O! d0 i5 q4 S

# c" ]& ]5 M+ y5 B) d, ~标准的ARDUINO接口,放到哪都行。合体照。
6 m# c% r( d) {- f# v7 r4 _# e. V- H* b2 ~/ l: @
test.png ! w$ n7 m6 w4 t( g

+ p3 y& g/ o9 I3 [2 {6 Y' R7 |4 _硬件连接及原理图4 [" }4 F5 H/ \9 L
  x# R" e1 b! g$ H5 B
MINI DOCI上的AT24C02连接
4 A) e6 l+ ?5 }/ m) _* B/ W4 r% h3 A; r3 i
QQ截图20151108162714.png
! @- _+ ?! E+ y' \% V5 h: f* }5 Z2 \# I: s$ s! ~
ARDUINO接口:SCL及SDA
8 k% C% W/ D, X# ~) S4 H
5 u! U! h* S* V/ q+ b' k QQ截图20151108162724.png
( z% _  U- D' r4 E1 p! P: G: [' L* j5 [9 O. r( K
NUCLEO-L476RG上对应的接口
; {, k6 V. @! ?6 V: T/ j: l) `- O$ Z7 Z# t1 q9 y) Z" R
nucleo-l476rg-review-16.jpg * F& Q. H8 Q6 u7 O# b9 D
* p! ~. i9 U% z- S, c. V$ b8 I. ]
4 L& o7 ~" l- s  w" b4 X0 S
写程序之前,要了解硬件的基本特性,首先是STM32L476RG上I2C接口支持的特性;其次是AT24C02的特性。
/ d) T& _& m: W- j2 C1 R6 j& Z; {: y2 G
STM32L476RG的I2C功能框图如下
0 P+ e( ^% r0 h6 u& z9 u+ }$ p6 E- j( O$ _
QQ截图20151108154725.png # d; k8 m) @6 d" {% J9 t( @9 {) y
' w' C9 u) U  P3 o5 S/ p  E/ o
值得一提的是,L4的I2C有自己独立的内核时钟,可以在SYSCLK、PCLK及HSI中任选一种做为I2C的内核时钟。另外L4的I2C支持三种不同的通信速率:100KHZ, 400KHZ,1MHZ。由于AT24C02只支持最高400KHZ,所以这里就选择400KHZ做为内核时钟。
3 B9 Y1 a3 Z& W) T. |' W
, _) l4 i$ p# ]) C& q3 l/ q" S创建I2C测试工程,建立过程略。几点要注意的地方。) l4 ~) s& N2 E+ T3 v! _4 W

0 l" ~' _# \8 O5 L2 |首先,本例程中使用的是I2C1,对应的SCL及SDA引脚为PB8及PB9,时钟配置后SYSCLK为80MHZ。; H& s3 b2 C; u/ w4 w( d
1 U; q) M3 X9 c2 `
I2C硬件配置参数如图8 D1 u* s6 U. u  M( }

( t! ~# k, V3 i- i3 \+ N& t, E QQ截图20151108172523.png / ?# B4 r# P3 E

2 L2 v' v( b( z速度有三种可选:标准,快速,快速加。另外针对不同的特定应用,可以选择设置上升和下降沿的时间,以纳秒为单位,范围为0-120纳秒之间。注意这个TIMING参数,是灰色的,CUBEMX自动计算并设置该值,不像以前的F0和F3系列,需要一个专门的工具来设置TIMING的值,够麻烦的。
$ a' w$ Z  O) a6 b; ]
5 D# v* \6 G9 G9 e) u/ w下面是使用HAL库与EEPROM通信的主要代码。
2 t+ k, k# b/ I4 x
0 c4 \7 ~/ g5 c6 B9 ^/ O* N7 f+ V3 |7 S+ J
  1. /* USER CODE BEGIN PV */) X2 M8 i  T+ K1 W- v2 A3 J/ f
  2. /* Private variables ---------------------------------------------------------*/) `3 V- l0 Q0 }& D% o6 @
  3. #define EEPROM_ADDRESS        0xA0
    ! @5 p8 F8 g( |
  4. #define EEPROM_PAGESIZE        0x11
    " B5 e8 b0 i& Z5 }& g
  5. #define EEPROM_TIMEOUT        1000
    8 _: M. s0 h: `; S9 O! }  [
  6. 2 q, j1 M. J, w* ?( G
  7. extern I2C_HandleTypeDef hi2c1;: D" Z/ T( O5 Y# M6 k) `4 r, o$ q
  8. 6 g7 ~& D. `+ {! p! [2 `* e* x: J
  9. char msg[] = "This is a test!\r\n";
    8 Q( i  K8 a/ F% ^+ ]
  10. $ |  \& S. O! o6 r
  11. char buf[40];9 v- u( g& h% U* c8 V

  12. 5 @; T8 U8 t8 h! o8 p
  13. int16_t Remaining_Bytes;
    . Z' Z9 d) t! p  {9 B0 K
  14. uint16_t Memory_Address;
    & N3 \) v+ i# E; T, I

  15. 8 [! [8 {( H4 b- _( y
  16. uint16_t len;
    . l) ?( v. b" f/ T( ?+ L

  17. $ i1 x4 o. S+ v8 \+ k  X  |! s
  18. ......& k5 a& v0 `$ c) R. ?3 {9 w: a
  19. * ^7 b* |& ]2 l5 T- x2 L4 S4 A
  20. //write msg to eeprom
    ' `0 {' W: l* Z2 O
  21. Remaining_Bytes = strlen(msg);
    " T. x3 H2 M" U: C& n/ c( h. E
  22. Memory_Address = 0;
    2 A8 K  z  I/ U
  23.         % B( v. I( u) X
  24. while(Remaining_Bytes > 0); G$ p+ F! |9 d
  25. {
    6 `6 ^) X; r3 A- |& m( H9 R6 \
  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)
    ; e1 ^$ \. y$ F9 [
  27.       {+ n* o2 m; @5 m' e
  28.               Error_Handler();
    4 v* d7 w: Z. X8 R. T
  29.                         ) M0 r: e- g$ D* @! x3 W3 ]: q+ A
  30.        }+ |! r6 t* C& Y3 E" m+ g
  31.                
    1 x+ o6 s  A1 g1 {# l
  32.        while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)% T# ~3 n5 P2 V! [/ E
  33.        {
    8 [" t' j) Z; z: ?' o' P+ v
  34.        }( c( A5 Q' y2 v6 z5 A
  35.                
    ; _# z4 x" U6 s
  36.        while (HAL_I2C_IsDeviceReady(&hi2c1, EEPROM_ADDRESS, 10, 300) == HAL_TIMEOUT);) i# q2 t: k$ U/ Q0 S+ G
  37.                
    # n1 S) T  x/ ]( L% x( F$ V
  38.        while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)' J+ d5 Z9 f: X( `4 v
  39.         {( _8 @% Y" d8 E$ W# X$ l4 o
  40.         }, J. i2 C; h. N5 @
  41.                
    % v) }! y: c4 N: n
  42.          Remaining_Bytes -= EEPROM_PAGESIZE;& ]7 p; S3 i( K* N% C$ d
  43.                 ; X+ \; O' G2 C  ?$ `  P
  44.          Memory_Address += EEPROM_PAGESIZE;
    % V1 ]7 f' x! K% t/ D
  45.         }
    ' L! M5 L' g" K# G( t
  46.         
    # w: s2 c% a5 |; ?, v: t
  47. //read msg to buff2 ]- V" Y( k+ U4 [6 l

  48.   Z5 D* F! U/ i8 x$ T+ s9 H
  49.   if(HAL_I2C_Mem_Read_DMA(&hi2c1 , EEPROM_ADDRESS, 0, I2C_MEMADD_SIZE_8BIT, (uint8_t*)buf, strlen(msg))!= HAL_OK)0 M4 t7 B" O  M- s) Y! d9 B- J
  50.   {
      u7 h4 P: n3 L( L
  51.     /* Reading process Error */
    2 r5 @! b$ |' S5 C2 C: u
  52.     Error_Handler();        
    ' V9 ?4 b: y  `& S6 I
  53.   }
    / D6 U* _0 x+ C, ^
  54.   5 n: D7 |6 F! q% U2 M
  55.   /* Wait for the end of the transfer */  , B! g0 s7 E/ O8 A0 g5 v
  56.   while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
    & P  G3 S# ^9 E
  57.   {+ A# M& ?+ ^6 ^! g
  58.   }
    & B! S' Q, k6 d" C$ e$ F& M
  59.         
复制代码
' o4 m0 h, U+ z% z$ e2 v) M
根据STD库中用户的反馈,I2C出错的原因主要由几方面造成,一是ST设计的I2C接口,通信过程中一些状态变量及标志位的设置非常严格,如果程序逻辑考虑不周全,会导致I2C停止工作,需要软复位后才能继续;另一方面,I2C接口在处理单个,双字节及多字节传输过程中要分开考虑,进一步将问题复杂化了;还有就是结合具体的I2C设备,不同的时序要求,进一步复杂化了通信过程。
1 a) f$ S- `, x' e. c
+ |5 S* A' Z7 R3 C这些问题在HAL库中都得到了很好的解决,为此,HAL库中设计了几种不同类型的API函数供调用。一类是通用的接收和发送函数,这类API函数将I2C接口视为类似于“流对象”,通信时从流对象中接收或发送数据;另一类则是类似于EEPROM之类的特殊存储对象,从这些存储对象中接收或发送数据时,都需要提供一个地址,以便准确定位。使用EEPROM来实验时,我们使用的是第二类API函数。两个主要的API函数原型及参数如下。
' C! a0 W5 u( m) |* ?9 s
/ D3 T: r. V* G+ I
  1. /**/ {: v8 e$ }9 O- U! {* R" ?8 ]
  2.   * @brief  Transmit in master mode an amount of data in non-blocking mode with DMA
    3 N+ Q& F- B" ?8 h3 S
  3.   * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains" L; [( G( j9 w: S4 E  V9 ^
  4.   *                the configuration information for the specified I2C.
    - b/ G! q  O* z  k: B& ^! E! p
  5.   * @param  DevAddress: Target device address7 P  z) s+ p! N' S% s, K6 p+ h& _
  6.   * @param  pData: Pointer to data buffer
    $ s4 e7 a' }3 \4 [8 ~
  7.   * @param  Size: Amount of data to be sent
    5 j/ M" G  w: B2 Z2 I0 H; |( T0 q
  8.   * @retval HAL status
    ) n5 e( K1 O# r3 I
  9.   */' v1 h% f# k6 d0 |% U0 S' H
  10. HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
复制代码
  1. /**  F0 {  B* A% `5 A1 p, `
  2.   * @brief  Reads an amount of data in non-blocking mode with DMA from a specific memory address.& r/ O( M# K8 v! q
  3.   * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains: y9 Z- R1 m7 Q$ W) i
  4.   *                the configuration information for the specified I2C.0 k. ?7 d) S, Z) M, ?, d% R2 ]1 q
  5.   * @param  DevAddress: Target device address
    3 t& n6 P2 E  Z4 J+ P
  6.   * @param  MemAddress: Internal memory address5 Q3 V! k* F0 g  q( k7 J, X
  7.   * @param  MemAddSize: Size of internal memory address
    - y: E. U# ?6 t1 s5 e. j' f8 `
  8.   * @param  pData: Pointer to data buffer1 u. e7 b2 d8 K1 z7 B: t
  9.   * @param  Size: Amount of data to be read
    # z  g2 S! d6 o0 v% q
  10.   * @retval HAL status7 o7 l4 j. N; ?1 D9 e
  11.   */
    * d% D1 C1 y4 V5 K) n% l
  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)
复制代码
* n/ O6 b& w2 R. b' k+ `2 m
关于这两个函数的更详细的调用方法及说明,请参考API文档。/ e( U1 o% y. w5 O

  ?5 M) x( I( A4 U注意在具体操作EEPROM的时候,还要注意,EEPROM分字节读写及页面读写两种类型,对HAL API的调用还要进行适当的修改。
; G. k  i3 ]) Y! o- D
4 W( `/ {9 T9 X* `  v  v由于ST HAL API做了大量的后台工作,上面的代码看起来过于简单了。但实际上API函数在后台做了大量的工作,这不正是我们期待的么!
  Z' F. c- B( f- f. |' _
+ B/ x7 R+ T( X: _最后来看看运行结果。" [1 T  b) W' K
* `# n- j' F7 A6 N; B
UART打印的写入及读取取结果
# e  ^( [% ^/ H. ~$ i) m7 i9 T& r
4 y  o7 U- ]+ Z2 x. v  b5 P QQ截图20151108200641.png
! a- {6 W  l. y( n9 x0 x$ n3 N. Y4 q  K8 ~9 h' k
逻辑分析仪LA! Q3 |2 x/ n) t" n# {

8 j' p# x2 y* P' a5 p. a 无标题.png
* o1 y0 q7 x. M3 i7 W1 c' d  ^4 a
* s1 J! N) A6 j+ Y+ @* h1 g. zI2C通信全程,LA分析结果$ `9 k6 u7 Y. z  I1 n3 {
% u4 m4 Q% ?. ~
QQ截图20151108200233.png
: c! j( y9 U3 X
5 b8 V# _6 a7 @# j5 I. e" }; {% U开始通信,顺序依次是开始信号,地址,EEPROM写入地址,第一个数据字节
: G2 ?8 o& q! R0 \- l: D
8 Y9 W) g  J/ j6 I3 _! @2 w0 l QQ截图20151108200331.png
  c4 K9 {- B4 M! D! B: y8 _+ ]0 k( S7 ?) O
字符0x0D, 0x0A, 结束信号。* }5 r- v: O: x1 [
  X. r+ p+ X3 f! B$ Y
QQ截图20151108200410.png
( j9 B& \# e8 B" B$ M* Z- d, j, r/ I% x2 s8 |6 ]
接收开始,顺序依次是开始信号,地址,EEPROM读取地址,第一个数据字节
- X# `: t9 n% Y4 E4 H7 F. r# R
+ c4 c; G( v/ M5 B+ ] QQ截图20151108200439.png
) L$ c/ I* \9 V* |4 j( l1 g
9 c- H# H2 ^6 w7 E: o4 o读取结束
% i. s% I* s8 r
" B3 \' _0 ?: Q$ x QQ截图20151108200502.png ) Z) ~- N- r/ r  Q: ?: I: S# y. b
" Q) V# W; _, D6 Z" X5 K  M+ ~9 z

6 i) [" n) y+ _  ^% Z. B* E7 c$ ?
2 a9 D  T- Y( b附工程
! A" p/ a  e, u4 N# m$ s5 p- J  p; k$ f# N2 I& h! k
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)
. W/ y  h& c; h7 T6 G2 c: ?                {  S$ P( d! P3 v. r2 C
                        Error_Handler();$ N6 c$ o7 Z& Z6 D
        };程序直接进入Error_Handler()函数,请问是什么原因呢?我检查了很多地方,还是不行,求指教,非常感谢!(测试环境stm32l476rg+at24c02,后来用了at24c16测试还是失败)
Inc_brza 回答时间:2015-11-9 00:43:23
对比过硬件IIC和模拟IIC,硬件的IIC直接被模拟IIC给打爆!
$ H; J3 Z7 o' ]5 G8 B4 x/ u& ^8 j1、移植,直接秒杀不用多说* ]: X6 s. S: T- n5 e6 A+ _; }
2、效率,IIC的硬件通讯过程中用了太多的访问标志位,实际效率不会增加,一样是让CPU在耗,
# r7 r% \" z2 V7 s, W: ]( ~6 s              所以,效率反而没有模拟IIC高,因为GPIO的反转速率轻松满足IIC的通信速率,所以
2 W# V5 |& _# B" d              模拟IIC照样更胜1筹。
$ \( m" B$ |# X1 l3、复杂性,ST的通病,反而模拟IIC更加把协议变得很直观。0 j) ]1 J# h" W6 O' ?/ ~9 q* N
纵上所述,感觉这个硬件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, _; q: E  }* f- z' Z
这个逻辑分析仪是啥牌子的?多少M?那个打标线不错。。。

! m+ @( X6 M* |2 Z5 u- N梦源的牌子吧,100M
12下一页

所属标签

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