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

【经验分享】STM32硬件I2C调试

[复制链接]
STMCU小助手 发布时间:2022-1-27 22:49
调试情况1
现象:主I2C发送数据而没有收到应答,则下一次不能正常发送数据

9 i  ^7 y3 S$ Q% j  \
637417-20181110164400145-1024558856.png
7 d0 y: F! k9 b$ F: u% R$ i
637417-20181110164410368-577421352.png

( c+ y4 g' k" j- e' [2 C* F
背景:主I2C每次应该都能正常发送数据
硬件:野火STM32-MINI,1主0从,SCL和SDA直接上拉
软件:按键触发中断,主I2C发送一次数据,中断优先级,按键最低,I2C最高,且主I2C中有TIMEOUT计时
  1. void PB_K2_IRQ_HANDLER(void)" ~6 q- U) k! R" b
  2. {- y0 a  ?1 B0 R2 o
  3.     if(EXTI_GetITStatus(PB_K2_EXTILINE) != RESET)+ n" V: Z2 c" c& b
  4.     {0 g7 `3 y& |6 o
  5.         EXTI_ClearITPendingBit(PB_K2_EXTILINE);+ X* s& f, N: A5 F: c
  6.         
    ( L$ C) M+ `/ Z4 e% [5 f) x
  7.         mini_i2c_write(0x22, 0x47);$ o. f8 c( ~" h4 d& o! g- M3 w% ~
  8.         LED_D5_TOGGLE;
    , G6 P  P5 b7 L* ^. G7 Y
  9. //        printf("Push button K2 clicked!\r\n");  n7 a" }# D( |+ k
  10.     }; I9 W# x) C, G5 S
  11. }
复制代码
  1. #define PB_PREPRIO                        3
    2 _4 z8 Y" e; z
  2. #define PB_SUBPRIO                        3
复制代码
  1. #define SLAVER_I2C_PRIPRIO                0% q( b3 C8 b2 ]. t) g: Y
  2. #define SLAVER_I2C_SUBPRIO                0
复制代码
优先级分组均为2
  1. void mini_uart_config(void)8 G4 u$ E5 o; D0 N2 O1 i9 B
  2. {( j  g& r7 o! V/ Y9 `/ M
  3.     // structure define, Z; q9 g: w& O. |6 H; z: I3 ~* x* {
  4.     USART_InitTypeDef usart_struct;& X) a( m7 x; K! U+ i
  5.     GPIO_InitTypeDef gpio_struct;
    0 ]; i, V" ~  [8 c$ _) z
  6.     NVIC_InitTypeDef nvic_struct;
    ( |9 Y7 R0 d& \# p& z
  7.    
    + H) O$ T* q, |0 B& [
  8.     // clock enable
    ( J, v$ f! j' `2 D/ C; N9 _% \
  9.     DEBUG_UART_RCC_CMD(DEBUG_UART_RCC, ENABLE);
    2 h% B, i& F. c& O
  10.     GPIO_RCC_CMD(DEBUG_UART_GPIO_RCC, ENABLE);0 y: r: m7 \& A' z
  11.     2 _5 {5 E. |6 H/ z" q
  12.     // GPIO initialization. z2 k! j) y8 d8 [6 N& E
  13.     gpio_struct.GPIO_Mode = GPIO_Mode_AF_PP;
    4 i+ Z3 y. Q3 D5 Q- j" K
  14.     gpio_struct.GPIO_Speed = GPIO_Speed_50MHz;! [( |: r: P1 n5 D
  15.     gpio_struct.GPIO_Pin = DEBUG_UART_TX;5 B4 R9 @" `9 ~( P( r
  16.     GPIO_Init(DEBUG_UART_GPIO, &gpio_struct);- _7 p6 _( v# z3 e+ j
  17.     1 @9 d* [4 D8 _! `% C% h" ?
  18.     gpio_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    5 t) v. }* o1 F% D' D5 f% m
  19.     gpio_struct.GPIO_Pin = DEBUG_UART_RX;/ \* m! R0 A, r8 V$ U
  20.     GPIO_Init(DEBUG_UART_GPIO, &gpio_struct);, ]6 T4 B% l6 V2 U0 B3 j: k
  21.    
    ! q8 |6 U7 z2 |3 A) Y% q
  22.     // NVIC    initialization
      N3 P# b. p' \8 j- v' G2 _
  23.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    8 U$ p, E5 X3 B( k  H0 e
  24.     nvic_struct.NVIC_IRQChannel = DEBUG_UART_IRQ;
    / a  y( ~5 ~6 |4 m
  25.     nvic_struct.NVIC_IRQChannelPreemptionPriority = DEBUG_UART_PRIPRIO;" _8 Q7 o* ]  i. c5 r
  26.     nvic_struct.NVIC_IRQChannelSubPriority = DEBUG_UART_SUBPRIO;8 Y- i3 R( E8 ]. H
  27.     nvic_struct.NVIC_IRQChannelCmd = ENABLE;* v4 S, ^1 m* E
  28.     NVIC_Init(&nvic_struct);
    - e, O* i* [7 x6 }! p2 W3 l( t
  29.     0 m/ Q* s2 Q* F6 ]
  30.     // USART initialization6 A( i3 Q) s. I( g' {1 v2 u8 S/ d, c
  31.     usart_struct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    * q3 c* X( w' w9 m0 ~8 v( F
  32.     usart_struct.USART_Parity = USART_Parity_No;
    8 {) B0 V- c  `' O. G  v9 U# Y. V
  33.     usart_struct.USART_StopBits = USART_StopBits_1;
    7 d* a$ X5 B# n3 ~, l3 _
  34.     usart_struct.USART_WordLength = USART_WordLength_8b;' b; D- k# @2 V/ v) \( T( T
  35.     usart_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;8 Y5 m/ C7 X% C: \8 a
  36.     usart_struct.USART_BaudRate = DEBUG_UART_BAUDRATE;4 e: W- b0 Z5 S( I9 Q) G
  37.     USART_Init(DEBUG_UART, &usart_struct);
    4 y: L7 p/ q% ~4 z7 F9 c
  38.     + n, Y- l4 M% }  b; G1 c
  39.     USART_Cmd(DEBUG_UART, ENABLE);
    ; ]7 C4 z/ \3 ]& U: {
  40.     ) t) c+ R2 i8 M& |
  41.     USART_ITConfig(DEBUG_UART, USART_IT_RXNE, ENABLE);" {( |1 ]' w& K* w4 _) K
  42. }
复制代码
  1. void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)4 S" j* y- n& J
  2. {: X6 |+ L& m9 Z9 _- }3 t
  3.     uint32_t timeout;# {2 Q* q7 f, L6 e, B) o* b- Y9 R
  4.    
    " n+ q" M' t- L$ A* C! {
  5.     I2C_GenerateSTART(MASTER_I2C, ENABLE);
    : F6 u% G# y) h& O8 W" ]) t! b7 T
  6.     timeout = I2C_TIMEOUT;
    6 D  f0 c: l* s1 u
  7.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET)5 ]; m! [4 E+ _4 v/ a5 d6 l
  8.     {
    3 n7 c- C3 F( R4 o7 p
  9.         if(timeout-- == 0)
    2 u* d* N3 p( z! o6 q4 J0 l
  10.         {- z& Y8 |# p' g6 N
  11.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);* {* `' d& O* ^% ]7 e  \" z7 I
  12.             break;
    4 c- [( `7 ?9 E, I" `! i
  13.         }8 f# o' U0 g; D& S# d5 a& ~8 [; a
  14.     }. m$ b* i" V$ e  A& O+ f- W
  15.    
    : h" q. f/ I9 d- y
  16.     // device address
    9 A5 f" X2 v. G/ Y. L/ J, k& N
  17.     I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);
    4 r3 `- }# @* U/ J& p3 p- ~9 b( R
  18.     timeout = I2C_TIMEOUT;, ^6 j7 a. M% j- a
  19.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)+ I/ u# z8 [; M, j; O9 W0 L- V
  20.     {
    - }# f7 Y9 F2 I
  21.         if(timeout-- == 0), y! N8 v/ \" s. M7 z! K' }
  22.         {
    ! _1 w6 w2 k& Q
  23.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);% d' P4 z+ p( x4 G2 g
  24.             break;
    ! L; c9 r. {6 l! u1 \' Y1 K0 E' I
  25.         }% e. ?2 i& A6 C- `2 A$ d, T+ _
  26.     }/ ^$ z- x# P) P
  27.    
    " t/ G8 D8 |( _+ j+ I
  28.     I2C_SendData(MASTER_I2C, reg_addr);; ?1 P. D3 O- C0 L, ^* L
  29.     timeout = I2C_TIMEOUT;
    2 t. w9 i# b4 Y7 g
  30.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET)
    4 J. f* ^: d, m
  31.     {
    5 O! k4 A* V0 Q/ @( Z
  32.         if(timeout-- == 0)6 B/ J. B3 K$ g$ d# ]
  33.         {; _2 K. D% o# a5 w# i4 n
  34.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);' y: y# T( D5 o, N4 O1 C/ `  T, o6 _
  35.             break;" {4 U# h+ f# }* r/ e6 C% n: z
  36.         }
    / t$ |! _" B6 H$ e, [
  37.     }
    ( V8 ^+ B) Y8 {
  38.     ! p9 K1 _- H; S: B% V8 y
  39.     I2C_SendData(MASTER_I2C, wdata);8 G3 m$ \* u! j* j% k1 a
  40.     timeout = I2C_TIMEOUT;
    2 }. F2 M0 v0 `% r4 m7 @
  41.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET)  ~$ i' N) g6 x
  42.     {
    0 f% s- `6 z' p. o: R
  43.         if(timeout-- == 0)) j; q1 p+ t. u2 i4 {
  44.         {
    9 U3 m7 j! E+ ?2 I" s
  45.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);( K3 H6 V8 l# L9 d) ?4 P2 ~
  46.             break;
    : `; c! x  [' W  X
  47.         }
    4 @' z; e( w' m& [2 p* T
  48.     }; C( @3 o8 w% `+ M$ z, t
  49.     ) A) N7 V# x6 n$ r
  50.     I2C_GenerateSTOP(MASTER_I2C, ENABLE);+ ^% d% N4 g& B% v1 I/ b& z
  51. }
复制代码

- e! b. y& A/ G$ e1 g. f
问题所在:主I2C在未收到ACK应答,会产生应答错误,SR1的AF位置1,在TIMEOUT时间后,上面的用户代码会调用I2C_GenerateSTOP(MASTER_I2C, ENABLE)函数,CR1的STOP为会被置位,导致出错
调试代码,用串口打印状态寄存器及控制寄存器的值
  1. void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)
    : b4 K5 T0 q" O) p, _$ o
  2. {
    1 H. O, u' b. C* Y/ f
  3.     if((MASTER_I2C->SR1 != 0) || (MASTER_I2C->SR2 != 0))
    & k" ]5 }9 c4 Z, L, t  x
  4.     {$ ~+ C7 S  V: A' i- H
  5.         printf("Master I2C SR1 is %x and SR2 is %x\r\n", MASTER_I2C->SR1, MASTER_I2C->SR2);4 n8 b8 s; h, X) q
  6.         printf("Master I2C CR1 is %x and CR2 is %x\r\n", MASTER_I2C->CR1, MASTER_I2C->CR2);1 L& y$ X1 J! L0 w8 N4 z. x9 _
  7. //        mini_i2c_config();
    5 X. x0 Q/ g5 R% Q# H
  8.         MASTER_I2C->CR1 ^= 0x0200;; z  R) C' T$ q) N7 O0 K/ W
  9.         printf("Master I2C SR1 is %x and SR2 is %x\r\n", MASTER_I2C->SR1, MASTER_I2C->SR2);' [; f; l8 X7 J3 y& s; ]
  10.         printf("Master I2C CR1 is %x and CR2 is %x\r\n", MASTER_I2C->CR1, MASTER_I2C->CR2);  ^& ~, c! R& _% s( P0 @5 s" p
  11.     }0 I% H& g- F/ f
  12.    
    3 _4 r/ G8 {/ H  m
  13.     uint32_t timeout;
    " S1 L  S2 Z4 ]; `
  14.     % x* c2 m8 v8 O0 z% s0 o! _
  15.     I2C_GenerateSTART(MASTER_I2C, ENABLE);7 f+ ^4 ?  G+ x0 e- c  J% ~
  16.     timeout = I2C_TIMEOUT;- e9 C$ |) B6 @- x- u9 W# ^
  17.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET)
    . q9 N( |& ?: j# O  g8 t
  18.     {
    & S* {0 O7 S- i
  19.         if(timeout-- == 0)1 z6 @* n$ L/ u3 G1 v' u/ d, X
  20.         {1 c( ^+ y4 A9 T$ Q$ O5 i
  21.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);6 Y7 j* j8 H+ l% x
  22.             break;
    9 b! E7 F7 Z0 J" m; n5 T$ u) g
  23.         }# j% T7 ]& g# X, N) a7 x
  24.     }
    0 U) {# Z( i  G0 O1 N4 ?
  25.     9 o. m$ F) S0 v. S; A2 G! N" r
  26.     // device address
    * f4 F' n9 y* P  @5 u2 `* O
  27.     I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);
    1 i9 t( W+ D8 y( t
  28.     timeout = I2C_TIMEOUT;5 w) G2 e* A8 w5 {" v* m( c# s
  29.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)
    2 C$ @0 B7 p& C, f. R. ?* x
  30.     {' C$ J7 X: I7 e& c& L7 n
  31.         if(timeout-- == 0)
    / R# o% [* ?6 i% ^5 N# L1 ]) Y
  32.         {
    5 E+ `2 i7 t3 q/ z: T( B
  33.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);
    - V( d# H% ~. r  s9 b
  34.             break;7 a' ^$ c# j2 z* G# J  M
  35.         }
    " r2 _: j! h! s4 a
  36.     }
复制代码

& M5 Z7 m( ]- j7 \5 a
经验证,重新初始化I2C或复位CR1的STOP可以排除对下次发送数据的干扰,串口打印消息如下
  1. // Using mini_i2c_config()Program started!
    2 }: e+ l5 X$ c6 e# V% S) U
  2. Master I2C SR1 is 400 and SR2 is 0$ h- Y) F2 w0 n/ v" y: i, ?
  3. Master I2C CR1 is 601 and CR2 is 24
      k5 c# ^3 x! C  H# K! S7 T1 s
  4. Master I2C SR1 is 0 and SR2 is 08 r% E. A9 v( x" }
  5. Master I2C CR1 is 401 and CR2 is 24// Using MASTER_I2C->CR1 ^= 0x0200
    . q& n5 u1 I! J& M8 M, Y% H5 I
  6. Program started!; k* u/ c# k4 M% I: E) h
  7. Master I2C SR1 is 400 and SR2 is 0
      |( R) V  v( Z: c
  8. Master I2C CR1 is 601 and CR2 is 24
    5 w: `! I$ L) ?+ X3 x
  9. Master I2C SR1 is 400 and SR2 is 0
    0 W5 l& @6 |; z& z9 i( k
  10. Master I2C CR1 is 401 and CR2 is 24
复制代码

" ]2 W8 E8 w' r- p6 ^  {+ N
解决方案:使能主I2C错误中断,在中断中重新初始化I2C,并设置一个变量使主I2C发送函数提前终止
  
  1.     nvic_struct.NVIC_IRQChannel = MASTER_I2C_ER_IRQ;
      [  P" J" t; R. ]# @+ S5 C+ o3 t3 |
  2.     NVIC_Init(&nvic_struct);
复制代码
  1.     I2C_ITConfig(MASTER_I2C, I2C_IT_ERR, ENABLE);
复制代码
  1. void MASTER_I2C_ER_IRQ_HANDLER(void)9 l. i8 l5 ~: B
  2. {$ f: G6 T4 q5 b1 o. {. Q) n1 [
  3.     if(I2C_GetITStatus(MASTER_I2C, I2C_IT_AF) != RESET)5 ?' ^" U* S& X: r1 r) M7 T
  4.     {
    & W) F# L& {: p7 R0 K# C  i
  5.         I2C_ClearITPendingBit(MASTER_I2C, I2C_IT_AF);& Z' s/ Z# }( G7 p$ Y
  6.         
    ! U  s4 u( d1 u4 c1 g# V
  7.         mini_i2c_config();
    % ]8 L8 r% v6 U2 h
  8.         master_i2c_af = 1;' j: x8 i, S+ d2 R  g: h( T9 X8 G, M
  9.     }3 q! m  \, D9 R9 k$ ]3 \" F
  10. }
复制代码
  1. void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)/ u) b3 R& A" w0 Z, R, T+ \  j( \) V
  2. {1 c3 X) P/ F, O* U7 [" t2 n$ ^
  3.     master_i2c_af = 0;# o: Z; w$ h- i
  4.    
    / Z- [+ X0 U8 |- ^' M. y5 U8 \
  5.     I2C_GenerateSTART(MASTER_I2C, ENABLE);. h1 y4 Q3 h2 a& b8 d8 o
  6.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET);5 N, T% u$ M& }- k" O, _
  7.    
    . z9 U: L+ s- ~. O% a2 r
  8.     // device address) H9 i' k8 a4 b$ [
  9.     I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);- P# h/ B6 K, d) Z9 N/ J- W* v
  10.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)
    : g( h" }+ P* D5 a
  11.     {
    $ `0 G* L1 {7 y1 ^$ q4 p' |" J
  12.         if(master_i2c_af)5 W' ~, i# ^$ \& q1 p4 j
  13.         {0 w0 Z' ^3 D; `* D$ N& n
  14.             master_i2c_af = 0;/ ~; `+ B6 G" @) e, U
  15.             return;    // maybe there is a solution here7 y  W  j8 Z' w4 {1 E9 K. Z" G
  16.         }
    0 W9 P# S! s. x( i2 @
  17.     }: V) n0 `4 U! \" d
  18.    
    5 c8 }  x: E# F) e4 S: o
  19.     I2C_SendData(MASTER_I2C, reg_addr);
    + d. a- Y# I6 q! h
  20.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET);
    . X$ ]- E$ v% v9 H, Y
  21.     . b6 o$ }! b$ ]% o( X0 ?
  22.     I2C_SendData(MASTER_I2C, wdata);
      n2 C  O  U: O1 s+ p6 Y
  23.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET);7 G: A- z/ f3 I& i1 {/ w5 u3 P
  24.     2 @. M2 T$ M6 k5 g( ]4 Z4 ^" M' R
  25.     I2C_GenerateSTOP(MASTER_I2C, ENABLE);
    $ G+ w) v2 }' r5 m' V( x
  26. }
复制代码

! x" R/ n5 `# I+ P+ b7 n$ n* l/ }

. o& Q, w' {! y# D  N* X- F+ G1 u' Q* s9 _

4 W( g% E; D; X" x1 I5 f
赞 收藏 评论0 发布时间:2022-1-27 22:49

举报

0个回答

所属标签

相似技术帖

官网相关资源

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