|
调试情况1 现象:主I2C发送数据而没有收到应答,则下一次不能正常发送数据
9 i ^7 y3 S$ Q% j \7 d0 y: F! k9 b$ F: u% R$ i
( c+ y4 g' k" j- e' [2 C* F背景:主I2C每次应该都能正常发送数据 硬件:野火STM32-MINI,1主0从,SCL和SDA直接上拉 软件:按键触发中断,主I2C发送一次数据,中断优先级,按键最低,I2C最高,且主I2C中有TIMEOUT计时 - void PB_K2_IRQ_HANDLER(void)" ~6 q- U) k! R" b
- {- y0 a ?1 B0 R2 o
- if(EXTI_GetITStatus(PB_K2_EXTILINE) != RESET)+ n" V: Z2 c" c& b
- {0 g7 `3 y& |6 o
- EXTI_ClearITPendingBit(PB_K2_EXTILINE);+ X* s& f, N: A5 F: c
-
( L$ C) M+ `/ Z4 e% [5 f) x - mini_i2c_write(0x22, 0x47);$ o. f8 c( ~" h4 d& o! g- M3 w% ~
- LED_D5_TOGGLE;
, G6 P P5 b7 L* ^. G7 Y - // printf("Push button K2 clicked!\r\n"); n7 a" }# D( |+ k
- }; I9 W# x) C, G5 S
- }
复制代码- #define PB_PREPRIO 3
2 _4 z8 Y" e; z - #define PB_SUBPRIO 3
复制代码- #define SLAVER_I2C_PRIPRIO 0% q( b3 C8 b2 ]. t) g: Y
- #define SLAVER_I2C_SUBPRIO 0
复制代码优先级分组均为2 - void mini_uart_config(void)8 G4 u$ E5 o; D0 N2 O1 i9 B
- {( j g& r7 o! V/ Y9 `/ M
- // structure define, Z; q9 g: w& O. |6 H; z: I3 ~* x* {
- USART_InitTypeDef usart_struct;& X) a( m7 x; K! U+ i
- GPIO_InitTypeDef gpio_struct;
0 ]; i, V" ~ [8 c$ _) z - NVIC_InitTypeDef nvic_struct;
( |9 Y7 R0 d& \# p& z -
+ H) O$ T* q, |0 B& [ - // clock enable
( J, v$ f! j' `2 D/ C; N9 _% \ - DEBUG_UART_RCC_CMD(DEBUG_UART_RCC, ENABLE);
2 h% B, i& F. c& O - GPIO_RCC_CMD(DEBUG_UART_GPIO_RCC, ENABLE);0 y: r: m7 \& A' z
- 2 _5 {5 E. |6 H/ z" q
- // GPIO initialization. z2 k! j) y8 d8 [6 N& E
- gpio_struct.GPIO_Mode = GPIO_Mode_AF_PP;
4 i+ Z3 y. Q3 D5 Q- j" K - gpio_struct.GPIO_Speed = GPIO_Speed_50MHz;! [( |: r: P1 n5 D
- gpio_struct.GPIO_Pin = DEBUG_UART_TX;5 B4 R9 @" `9 ~( P( r
- GPIO_Init(DEBUG_UART_GPIO, &gpio_struct);- _7 p6 _( v# z3 e+ j
- 1 @9 d* [4 D8 _! `% C% h" ?
- gpio_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
5 t) v. }* o1 F% D' D5 f% m - gpio_struct.GPIO_Pin = DEBUG_UART_RX;/ \* m! R0 A, r8 V$ U
- GPIO_Init(DEBUG_UART_GPIO, &gpio_struct);, ]6 T4 B% l6 V2 U0 B3 j: k
-
! q8 |6 U7 z2 |3 A) Y% q - // NVIC initialization
N3 P# b. p' \8 j- v' G2 _ - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
8 U$ p, E5 X3 B( k H0 e - nvic_struct.NVIC_IRQChannel = DEBUG_UART_IRQ;
/ a y( ~5 ~6 |4 m - nvic_struct.NVIC_IRQChannelPreemptionPriority = DEBUG_UART_PRIPRIO;" _8 Q7 o* ] i. c5 r
- nvic_struct.NVIC_IRQChannelSubPriority = DEBUG_UART_SUBPRIO;8 Y- i3 R( E8 ]. H
- nvic_struct.NVIC_IRQChannelCmd = ENABLE;* v4 S, ^1 m* E
- NVIC_Init(&nvic_struct);
- e, O* i* [7 x6 }! p2 W3 l( t - 0 m/ Q* s2 Q* F6 ]
- // USART initialization6 A( i3 Q) s. I( g' {1 v2 u8 S/ d, c
- usart_struct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
* q3 c* X( w' w9 m0 ~8 v( F - usart_struct.USART_Parity = USART_Parity_No;
8 {) B0 V- c `' O. G v9 U# Y. V - usart_struct.USART_StopBits = USART_StopBits_1;
7 d* a$ X5 B# n3 ~, l3 _ - usart_struct.USART_WordLength = USART_WordLength_8b;' b; D- k# @2 V/ v) \( T( T
- usart_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;8 Y5 m/ C7 X% C: \8 a
- usart_struct.USART_BaudRate = DEBUG_UART_BAUDRATE;4 e: W- b0 Z5 S( I9 Q) G
- USART_Init(DEBUG_UART, &usart_struct);
4 y: L7 p/ q% ~4 z7 F9 c - + n, Y- l4 M% } b; G1 c
- USART_Cmd(DEBUG_UART, ENABLE);
; ]7 C4 z/ \3 ]& U: { - ) t) c+ R2 i8 M& |
- USART_ITConfig(DEBUG_UART, USART_IT_RXNE, ENABLE);" {( |1 ]' w& K* w4 _) K
- }
复制代码- void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)4 S" j* y- n& J
- {: X6 |+ L& m9 Z9 _- }3 t
- uint32_t timeout;# {2 Q* q7 f, L6 e, B) o* b- Y9 R
-
" n+ q" M' t- L$ A* C! { - I2C_GenerateSTART(MASTER_I2C, ENABLE);
: F6 u% G# y) h& O8 W" ]) t! b7 T - timeout = I2C_TIMEOUT;
6 D f0 c: l* s1 u - while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET)5 ]; m! [4 E+ _4 v/ a5 d6 l
- {
3 n7 c- C3 F( R4 o7 p - if(timeout-- == 0)
2 u* d* N3 p( z! o6 q4 J0 l - {- z& Y8 |# p' g6 N
- I2C_GenerateSTOP(MASTER_I2C, ENABLE);* {* `' d& O* ^% ]7 e \" z7 I
- break;
4 c- [( `7 ?9 E, I" `! i - }8 f# o' U0 g; D& S# d5 a& ~8 [; a
- }. m$ b* i" V$ e A& O+ f- W
-
: h" q. f/ I9 d- y - // device address
9 A5 f" X2 v. G/ Y. L/ J, k& N - I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);
4 r3 `- }# @* U/ J& p3 p- ~9 b( R - timeout = I2C_TIMEOUT;, ^6 j7 a. M% j- a
- while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)+ I/ u# z8 [; M, j; O9 W0 L- V
- {
- }# f7 Y9 F2 I - if(timeout-- == 0), y! N8 v/ \" s. M7 z! K' }
- {
! _1 w6 w2 k& Q - I2C_GenerateSTOP(MASTER_I2C, ENABLE);% d' P4 z+ p( x4 G2 g
- break;
! L; c9 r. {6 l! u1 \' Y1 K0 E' I - }% e. ?2 i& A6 C- `2 A$ d, T+ _
- }/ ^$ z- x# P) P
-
" t/ G8 D8 |( _+ j+ I - I2C_SendData(MASTER_I2C, reg_addr);; ?1 P. D3 O- C0 L, ^* L
- timeout = I2C_TIMEOUT;
2 t. w9 i# b4 Y7 g - while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET)
4 J. f* ^: d, m - {
5 O! k4 A* V0 Q/ @( Z - if(timeout-- == 0)6 B/ J. B3 K$ g$ d# ]
- {; _2 K. D% o# a5 w# i4 n
- I2C_GenerateSTOP(MASTER_I2C, ENABLE);' y: y# T( D5 o, N4 O1 C/ ` T, o6 _
- break;" {4 U# h+ f# }* r/ e6 C% n: z
- }
/ t$ |! _" B6 H$ e, [ - }
( V8 ^+ B) Y8 { - ! p9 K1 _- H; S: B% V8 y
- I2C_SendData(MASTER_I2C, wdata);8 G3 m$ \* u! j* j% k1 a
- timeout = I2C_TIMEOUT;
2 }. F2 M0 v0 `% r4 m7 @ - while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET) ~$ i' N) g6 x
- {
0 f% s- `6 z' p. o: R - if(timeout-- == 0)) j; q1 p+ t. u2 i4 {
- {
9 U3 m7 j! E+ ?2 I" s - I2C_GenerateSTOP(MASTER_I2C, ENABLE);( K3 H6 V8 l# L9 d) ?4 P2 ~
- break;
: `; c! x [' W X - }
4 @' z; e( w' m& [2 p* T - }; C( @3 o8 w% `+ M$ z, t
- ) A) N7 V# x6 n$ r
- I2C_GenerateSTOP(MASTER_I2C, ENABLE);+ ^% d% N4 g& B% v1 I/ b& z
- }
复制代码
- e! b. y& A/ G$ e1 g. f问题所在:主I2C在未收到ACK应答,会产生应答错误,SR1的AF位置1,在TIMEOUT时间后,上面的用户代码会调用I2C_GenerateSTOP(MASTER_I2C, ENABLE)函数,CR1的STOP为会被置位,导致出错 调试代码,用串口打印状态寄存器及控制寄存器的值 - void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)
: b4 K5 T0 q" O) p, _$ o - {
1 H. O, u' b. C* Y/ f - if((MASTER_I2C->SR1 != 0) || (MASTER_I2C->SR2 != 0))
& k" ]5 }9 c4 Z, L, t x - {$ ~+ C7 S V: A' i- H
- 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
- 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 _
- // mini_i2c_config();
5 X. x0 Q/ g5 R% Q# H - MASTER_I2C->CR1 ^= 0x0200;; z R) C' T$ q) N7 O0 K/ W
- printf("Master I2C SR1 is %x and SR2 is %x\r\n", MASTER_I2C->SR1, MASTER_I2C->SR2);' [; f; l8 X7 J3 y& s; ]
- 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
- }0 I% H& g- F/ f
-
3 _4 r/ G8 {/ H m - uint32_t timeout;
" S1 L S2 Z4 ]; ` - % x* c2 m8 v8 O0 z% s0 o! _
- I2C_GenerateSTART(MASTER_I2C, ENABLE);7 f+ ^4 ? G+ x0 e- c J% ~
- timeout = I2C_TIMEOUT;- e9 C$ |) B6 @- x- u9 W# ^
- while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET)
. q9 N( |& ?: j# O g8 t - {
& S* {0 O7 S- i - if(timeout-- == 0)1 z6 @* n$ L/ u3 G1 v' u/ d, X
- {1 c( ^+ y4 A9 T$ Q$ O5 i
- I2C_GenerateSTOP(MASTER_I2C, ENABLE);6 Y7 j* j8 H+ l% x
- break;
9 b! E7 F7 Z0 J" m; n5 T$ u) g - }# j% T7 ]& g# X, N) a7 x
- }
0 U) {# Z( i G0 O1 N4 ? - 9 o. m$ F) S0 v. S; A2 G! N" r
- // device address
* f4 F' n9 y* P @5 u2 `* O - I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);
1 i9 t( W+ D8 y( t - timeout = I2C_TIMEOUT;5 w) G2 e* A8 w5 {" v* m( c# s
- while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)
2 C$ @0 B7 p& C, f. R. ?* x - {' C$ J7 X: I7 e& c& L7 n
- if(timeout-- == 0)
/ R# o% [* ?6 i% ^5 N# L1 ]) Y - {
5 E+ `2 i7 t3 q/ z: T( B - I2C_GenerateSTOP(MASTER_I2C, ENABLE);
- V( d# H% ~. r s9 b - break;7 a' ^$ c# j2 z* G# J M
- }
" r2 _: j! h! s4 a - }
复制代码
& M5 Z7 m( ]- j7 \5 a经验证,重新初始化I2C或复位CR1的STOP可以排除对下次发送数据的干扰,串口打印消息如下 - // Using mini_i2c_config()Program started!
2 }: e+ l5 X$ c6 e# V% S) U - Master I2C SR1 is 400 and SR2 is 0$ h- Y) F2 w0 n/ v" y: i, ?
- Master I2C CR1 is 601 and CR2 is 24
k5 c# ^3 x! C H# K! S7 T1 s - Master I2C SR1 is 0 and SR2 is 08 r% E. A9 v( x" }
- Master I2C CR1 is 401 and CR2 is 24// Using MASTER_I2C->CR1 ^= 0x0200
. q& n5 u1 I! J& M8 M, Y% H5 I - Program started!; k* u/ c# k4 M% I: E) h
- Master I2C SR1 is 400 and SR2 is 0
|( R) V v( Z: c - Master I2C CR1 is 601 and CR2 is 24
5 w: `! I$ L) ?+ X3 x - Master I2C SR1 is 400 and SR2 is 0
0 W5 l& @6 |; z& z9 i( k - Master I2C CR1 is 401 and CR2 is 24
复制代码
" ]2 W8 E8 w' r- p6 ^ {+ N解决方案:使能主I2C错误中断,在中断中重新初始化I2C,并设置一个变量使主I2C发送函数提前终止 - nvic_struct.NVIC_IRQChannel = MASTER_I2C_ER_IRQ;
[ P" J" t; R. ]# @+ S5 C+ o3 t3 | - NVIC_Init(&nvic_struct);
复制代码- I2C_ITConfig(MASTER_I2C, I2C_IT_ERR, ENABLE);
复制代码- void MASTER_I2C_ER_IRQ_HANDLER(void)9 l. i8 l5 ~: B
- {$ f: G6 T4 q5 b1 o. {. Q) n1 [
- if(I2C_GetITStatus(MASTER_I2C, I2C_IT_AF) != RESET)5 ?' ^" U* S& X: r1 r) M7 T
- {
& W) F# L& {: p7 R0 K# C i - I2C_ClearITPendingBit(MASTER_I2C, I2C_IT_AF);& Z' s/ Z# }( G7 p$ Y
-
! U s4 u( d1 u4 c1 g# V - mini_i2c_config();
% ]8 L8 r% v6 U2 h - master_i2c_af = 1;' j: x8 i, S+ d2 R g: h( T9 X8 G, M
- }3 q! m \, D9 R9 k$ ]3 \" F
- }
复制代码- void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)/ u) b3 R& A" w0 Z, R, T+ \ j( \) V
- {1 c3 X) P/ F, O* U7 [" t2 n$ ^
- master_i2c_af = 0;# o: Z; w$ h- i
-
/ Z- [+ X0 U8 |- ^' M. y5 U8 \ - I2C_GenerateSTART(MASTER_I2C, ENABLE);. h1 y4 Q3 h2 a& b8 d8 o
- while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET);5 N, T% u$ M& }- k" O, _
-
. z9 U: L+ s- ~. O% a2 r - // device address) H9 i' k8 a4 b$ [
- I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);- P# h/ B6 K, d) Z9 N/ J- W* v
- while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)
: g( h" }+ P* D5 a - {
$ `0 G* L1 {7 y1 ^$ q4 p' |" J - if(master_i2c_af)5 W' ~, i# ^$ \& q1 p4 j
- {0 w0 Z' ^3 D; `* D$ N& n
- master_i2c_af = 0;/ ~; `+ B6 G" @) e, U
- return; // maybe there is a solution here7 y W j8 Z' w4 {1 E9 K. Z" G
- }
0 W9 P# S! s. x( i2 @ - }: V) n0 `4 U! \" d
-
5 c8 } x: E# F) e4 S: o - I2C_SendData(MASTER_I2C, reg_addr);
+ d. a- Y# I6 q! h - while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET);
. X$ ]- E$ v% v9 H, Y - . b6 o$ }! b$ ]% o( X0 ?
- I2C_SendData(MASTER_I2C, wdata);
n2 C O U: O1 s+ p6 Y - while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET);7 G: A- z/ f3 I& i1 {/ w5 u3 P
- 2 @. M2 T$ M6 k5 g( ]4 Z4 ^" M' R
- I2C_GenerateSTOP(MASTER_I2C, ENABLE);
$ G+ w) v2 }' r5 m' V( x - }
复制代码
! 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 |