目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。
& F' Q. o Q5 ]0 y5 t1 M D
* X* C* G0 `0 D7 W( ~1 {% I3 N目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。 {+ m/ [3 |5 D/ w
# e- ~( ^2 P8 J下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。
5 B9 d- ]7 f. @* J! \6 u; u
: }0 M1 N9 E w& V* A+ I2 d
& G* P0 ^, k; B& z% T' n3 f: v" P! R7 j5 D/ z
9 u p# V4 m# [* b- I. S) E, K
6 b w$ D" X1 \' h& u7 Z, X! z% B1 L
t. e a6 M9 z; ^3 x
* ~; [; U# }& N* ?
下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):
6 R. X0 B: w% u( z5 o: I& v) _1 a1 a8 B4 ]! A7 d2 x3 w2 @7 }* I. Z
[基本的初始化]
z% A5 F! \- W$ G5 ^5 _3 \; r1 O5 y r' D4 \$ H8 _
1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。0 b' U7 d2 a( Y1 n/ R$ e% V
; G; e: @% h! c2 l4 _6 z
2.CR1先赋值为0,复位IIC.
6 a# Y! ^4 D' ~! }( s1 u, j3 x. [# H; D/ r" h3 ~ o) T
3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为09 b) g" x2 O4 t
% Y8 i! \1 k1 H) P7 F5 a4.设置CR1使能IIC。
8 @' w, u8 x4 Z& n1 I: e" j( p3 \
4 I+ q( R. M! S4 k$ l注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。5 ~# g( ^- w0 K; o, o3 Y, s% o
! u0 G; Y( c* ` N
, |3 i0 V* Q: _) ~ J/ D* ~
, n8 ~! A; E) D* `2 m7 b[读取]! j/ M0 x+ l9 u8 S
$ h# z, ~# I, H7 b) A5 o6 b
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
, k5 }) t+ J0 Z% m1 \; i! D' v
+ T- R, @2 W; C9 H6 ~2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。
0 g( r8 D1 T) v" @& N& k! G. g! }, K9 f$ h2 q. z9 \0 V0 X
3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
% G( p- u# ^; d8 @- y) H p& D* \1 f* j& A5 \3 p7 M6 M- ^# [! q
4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。
+ M* Z' M# U( a! U! L4 k! J
$ Y0 b9 d# H/ ]3 b5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。9 n: \$ n$ O# W1 K& S5 A
6 L0 \4 I6 W% }6 L, y' Q' w
6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。
- C$ d4 u5 Y2 T a! E o" @+ D* W' W# v# L
7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。
7 B! B9 M0 z, ]( m& s2 |, Y% m" S
8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。0 e& e9 x" G6 R6 y. N( J# W* `( q
$ k$ v6 E" p! ^2 E9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。4 O$ j% V, D% w& o- u; ~
7 c2 g- O- S# w5 L/ X! f3 @, O3 t3 k) k
7 h) E9 z9 Z* r" }! D5 J, ]; ^2 |
+ X" \% R, d% Q. M: b. l
[写入]
* u" l% M; }1 \+ Y6 @4 F% D/ f7 M- y3 K, x3 b) ^$ d9 V* h% d
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。2 V! v3 \5 P; V
, z! N* x! \3 z+ F- L2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。
' I2 a: k! M Z4 i
5 C* U" L5 P" P2 J" i1 Q: |( ~3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。7 k' Y+ t6 N& @8 Y0 @
7 K! }% a0 e% V9 M9 ~4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。
( ^- |& _' G, l- w
& q% Q0 Q! O' T) B7 w' X5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
8 K# j L+ k) Q( A9 Y/ a+ g* P
5 n/ L0 ?; o3 N) G z3 z+ T6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。
0 P+ ^ o, t* X
4 b1 d* _/ u# q: F7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。
- j4 ]- `( o2 @, m6 y, N5 P: v; L! |" m* x$ u
8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。
/ g* n( f& }1 i$ T# E3 j& o: [
) `# h4 V! m8 C( K9.需要注意的是,所有的操作都要给超时,跟读取一样。
9 Q- ^1 f! F( D" l6 \; G) u: d) B- V( U! t* d& x" Z2 D& q1 [
3 ]: r2 T$ _0 o+ y
* f+ W' j1 d8 G. }, L9 v) x0 O" ?4 A; d注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。9 I. E" m- S; M" t# \) _ z4 A
5 C# X2 x* r$ A
9 m4 v, t3 Z- Z3 X7 m( Y0 f4 G1 L; W/ h! _* L
好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试) s; @+ u7 I. Z, o5 I
, x8 A5 r7 F5 ~" H o- /*************************************************************************************************************
9 a @/ m/ X5 P; z - * 文件名 : stm32f7_iic.c
2 J7 m, G3 r% q( n a! Z2 X7 k - * 功能 : STM32F7 IIC接口驱动2 \( K7 c; r! H* Z& t
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
! B8 f$ c9 `% D3 D9 @ - * 创建时间 : 2020-02-09' T3 S# @6 X6 m; f8 V
- * 最后修改时间 : 2020-02-09! g0 P1 I0 ~4 ?0 c8 q+ s
- * 详细: 只支持主机模式,7bit地址,默认APB1为IIC提供时钟
( I7 W8 i! l% p' o5 ~- T/ f - 涉及到读写1字节的超时时间是us,其余的是ms
9 P' o8 N E; y - 注意:IIC的IO必须初始化为复用开漏输出。/ d1 v3 U1 h! P
- *************************************************************************************************************/
! l' R6 D2 x0 T# |$ A2 H - #include "stm32f7_iic.h"# ?! q- S1 B% Q) y0 L$ y
- #include "system.h"
( n. N2 W- a9 {' @: T* G% X - #include "dma.h" l( g }0 d" m+ u" Z# e
- {( U, W) P7 K7 y1 z% `3 p- #define IIC_FLAG_MASK ((uint32_t)0x0001FFFF) //中断标志掩码; j: |; Q7 O, @
- o7 u% E9 [9 g5 x) V2 |% q
- //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)
- n, `5 J7 |9 \: a - typedef enum
+ \; b0 D. z3 M8 T - {
& {. r. N* w+ L" u, k - IIC_SOFTEND_MODE = 0, //手动结束,并不开启重载
8 r3 z' ^$ l: {8 D0 b4 l - IIC_AUTOEND_MODE = 1, //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯
( R9 N/ O1 V* ~7 k( e7 }8 L- [' m. H1 s - IIC_RELOAD_MODE = 2, //后续还有数据,本次通讯后自动重载,重新设置后继续通讯( @0 u+ C$ t. J$ ]
- }IIC_RELOAD_END_MODE;6 }5 ]! ?. M& P4 I
) {) b1 U+ K( b7 l- //读写与开始模式控制$ X# p7 {4 x4 l9 e, r
- typedef enum
& s& a* i7 `( s1 D& g" ]/ }( E. c - {
1 l9 H* n8 T2 j - IIC_NOSTART_WRITE = 0, //没有开始的写-用于后续数据的写入: |$ l8 l% `- s* N4 @; f
- IIC_NOSTART_READ = 1, //没有开始的读-用于后续数据读取& | q1 X9 j# I1 z! R
- IIC_START_WRITE = 2, //生成开始写-用于通讯开始时,写地址或数据
! \% v" H a# f - IIC_START_READ = 3, //生成开始读-用于读取数据时切换到读取方向,并读取后续数据
& Z' m% _; y5 T8 f - }IIC_START_WR_MODE;& a ]. d" x* ?* J
- 1 b- u$ ^3 |7 _$ @3 b' `! d0 x) y
- //IIC句柄
# d9 G- _( J+ j3 i& x - typedef struct8 b F5 t. [$ s" R& j* t
- {
+ X( d4 }0 f' ]7 ^ - IIC_CH_Type ch; //当前通道. p) v }% o0 h- W7 `
- I2C_TypeDef *I2Cx; //当前通道外设结构体
, H+ m7 O6 ]. Y R; }4 z - u32 TimeOutUs; //操作超时,单位us2 z6 `5 X+ q2 q) r5 \3 O f. \7 ?
- u16 Speed_KHz; //通讯速度,单位KHz
$ g* R) t, h Q& D3 z - bool isMasterMode; //是否为主设备模式-目前只支持主设备模式
# r$ E3 G7 ], T H8 [ - }IIC_HANDLE;: e% P" V, o, Z) k; `; n" G: s
, u3 _( W* \0 r: p, H- //IIC外设结构指针+ b% p9 n& \% \
- static const I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};
! X. B; N( L/ \0 @0 ?3 W3 Z7 _+ W8 l# a/ r - //IIC通道句柄定义; g& Q; _( ]" @$ s0 c# w4 o
- static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];. j4 H: |% o9 D8 H4 E# P7 w
- 4 Z, l+ d5 W- r
- //发送NAK5 t$ ]- \) f/ ^. |( Y! T$ p8 [9 x
- //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}: Z5 ]/ Z3 m# W& O# I' a2 V2 M
- //发送STOP6 q8 l( Q- t! O6 R' I( v) s* q3 j0 x
- static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}
! D4 [3 t; |7 l C2 _ - //发送START
! r! z7 |6 r* s6 a - //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}
+ \0 g# P0 G/ m! O& w9 M - //获取中断状态
. R) ]6 W7 g, P. L* ?3 j1 i: D - static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}2 W5 l' d( t! D( g
- //清除中断状态9 u/ C3 s! s' U9 `
- static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}! Q( h8 [. \% }9 W5 o1 |6 V! K0 o. @
- //复位CR2寄存器
, v! j) e7 N0 d, M+ h9 B - static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}
& I7 `" c; C5 [( T- x - 4 h) @ S$ d6 {9 g( R
- static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)
$ g( X; X4 M3 R2 E - static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算
6 O- g* }: L _1 I' W( m k! z7 G - , i; k* r* q: `! L2 r8 m' L# X$ y/ w
- ! D5 v8 F1 G% s9 g: Y) i
- /*************************************************************************************************************************
. O( U* D8 G' u9 h - * 函数 : bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs), [; T( s- F. Z; `
- * 功能 : 硬件IIC初始化4 i8 ], M7 |7 d5 N( G, Q
- * 参数 : ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)$ L$ X+ ~# D- v5 o+ H" M
- * 返回 : IIC_ERROR
) R; ]( D& }- c - * 依赖 : 底层宏定义
6 X$ L5 z1 G: {5 {5 g0 ` - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
/ ~- c# k" | ^+ Y+ ^: X0 z - * 时间 : 2020-02-151 g9 F4 W. k; z" l( t5 H
- * 最后修改时间 : 2020-02-15
; X0 S7 _0 G( ~. O - * 说明 : 速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,& o2 n( e$ Y- k- `8 J
- 时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性2 f& V6 ?4 x2 i4 f [
- *************************************************************************************************************************/0 h5 e5 _5 G3 `5 K! z* Q: \
- bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)3 X E4 [1 P- B7 } ?# I) X
- {
7 Y3 o' ?- c4 ?# M$ N. i) _/ Q% y7 Y E - SYS_DEV_CLOCK DevClock;- C5 t! [! k# e
- IIC_HANDLE *pHandle;0 W j' o3 Q, v. H% {. A
-
# n5 {. x" S1 ]4 [& [+ ` - switch(ch)
( c9 c5 ]5 H \7 s - {' l8 d$ e4 Y! n5 O
- case IIC_CH1 : //IIC1& {: K _, }0 Y7 j0 u' E" R
- {
$ \4 ~+ k5 ~2 r: d# f" [ - RCC->DCKCFGR2 &= ~(0x3 << 16); //清除设置,使用APB1作为时钟源3 [ ]5 l& [/ h
- DevClock = DEV_I2C1;" g7 H8 u9 ?( O
- //初始化I2C IO
1 @* r6 k8 S+ }" v - #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7) //I2C1 使用PB6/7 G/ n7 T3 @1 Z8 _
- SYS_DeviceClockEnable(DEV_GPIOB, TRUE); //使能GPIOB时钟
1 o8 G; B! J W* {) J: e% ?; o - SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M); //PB6
7 K2 m; h5 n. Q% t' G3 s! { - SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M); //PB76 H6 j# [' | f9 v9 @3 @
- SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1); //AF4 P G/ k6 k# e# x0 I( j
- SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1); //AF4
: s4 U) {8 I, K4 t - #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9) //I2C1 使用PB8/9
' Q9 z2 V+ `& [: V1 n0 w- j - SYS_DeviceClockEnable(DEV_GPIOB, TRUE); //使能GPIOB时钟
; R1 L7 C1 r% |4 q - SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M); //PB8
- |. L( V/ j Q! e; X+ `, j - SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M); //PB9
1 ^; |* r, l8 n4 J6 r - SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1); //AF4! H3 e6 Z" C5 C; r2 [& A
- SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1); //AF49 i8 _7 n* g. J) Z/ y; c
- #else) [1 P4 J3 W7 O# n/ _6 W
- #error("无效的I2C1 IO选择");/ W* G- N% I2 c* q0 n
- #endif //IIC_CH1_IO_SELECT. j1 k( r3 C$ g j! A, W
- }break;2 u, B- T/ b0 }
- case IIC_CH2 : //IIC2$ e! f0 J+ F. r% c: x+ P! {) \- T: C# b
- {9 O, e, H. U7 [
- RCC->DCKCFGR2 &= ~(0x3 << 18); //清除设置,使用APB1作为时钟源# J+ w8 J+ g, x% _9 N5 t" e
- DevClock = DEV_I2C2;
0 r6 v& O( q+ E3 H3 s9 S - //初始化I2C IO8 V3 c' u: z4 j4 v4 _. w- p
- #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11) //使用PB10,PB11
1 y" z& \( W; V/ c: V& d; N - SYS_DeviceClockEnable(DEV_GPIOB, TRUE); //使能GPIOB时钟
* Y6 m' g( e, W" u1 Q+ m - SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M); //PB10 x" I3 D- ~* a/ V
- SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M); //PB11% S: d5 z+ O% ~. G1 F3 e
- SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2); //AF4+ [, q$ M# X2 y, q. i/ s, d
- SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2); //AF4( {* `) W3 R3 r1 M- n) S4 W
- #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1) //PF0,PF15 K2 W. ?' e- ?, q2 [ |, e
- SYS_DeviceClockEnable(DEV_GPIOF, TRUE); //使能GPIOF时钟
' A6 l- ^% v& f& h: q& e1 s - SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M); //PF0
% F/ U _5 E' P7 c, @0 M0 z - SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M); //PF1 }6 ?) s7 J/ [4 i6 A, g
- SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2); //AF4& ~( E W n& H8 H
- SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2); //AF43 n: B4 U5 ~% B
- #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5) //PH4,PH5
, v7 l; l8 O8 r. l4 t! Q4 i" g Y - SYS_DeviceClockEnable(DEV_GPIOH, TRUE); //使能GPIOH时钟
0 ?" P- X+ d& A0 q) E/ d: n - SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M); //PH4
% y+ q0 ]: K+ t - SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M); //PH5
s! [! X8 q8 x8 f6 ~6 U5 N1 t - SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2); //AF4/ ]1 @& n! A3 f) s! @9 P: x- ]
- SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2); //AF4 1 F( s7 z4 j. n: x) i+ W
- #else
3 l q- w. X1 w- m: U - #error("无效的I2C2 IO选择");- I+ R2 j( o6 ~0 g
- #endif //IIC_CH2_IO_SELECT2 d) [1 ~2 F9 }# [2 V( ]# Y
- }break;
# ~9 i+ m. b. t2 i7 ?3 V/ c6 h - case IIC_CH3 : //IIC3
' N D: f# A* w9 E5 `: } - {/ |* k# b+ c n
- RCC->DCKCFGR2 &= ~(0x3 << 20); //清除设置,使用APB1作为时钟源
- n4 B) k1 _* J9 \ l - DevClock = DEV_I2C3;& i1 i1 u4 U/ g
- //初始化I2C IO" q2 z8 v1 y; r
- #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8) //PH7,PH8
+ @- q. q% T8 e7 O; R - SYS_DeviceClockEnable(DEV_GPIOH, TRUE); //使能GPIOH时钟1 A. y+ ~1 D/ M( s1 H6 I8 U
- SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M); //PH7
4 c& }/ V( K# T. m - SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M); //PH8
8 v& M; p9 k' E4 m2 X - SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3); //AF4
/ E" E0 [, i9 D, B) q3 S$ A - SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3); //AF4
: B6 z& A) i$ R- }4 P - #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9) //PA8,PC9" [+ G# M. k; i
- SYS_DeviceClockEnable(DEV_GPIOA, TRUE); //使能GPIOA时钟9 O) r Z% A# q5 o3 D9 f
- SYS_DeviceClockEnable(DEV_GPIOC, TRUE); //使能GPIOC时钟
$ l4 l& F' c0 l; k8 x9 H# g; U - SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M); //PA8
6 r# `2 c$ {% [0 J/ O. |5 Z - SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M); //PC99 ?6 E5 E! L% u/ Y$ C- m
- SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3); //AF4
0 x; S9 ~6 C( M. H# o8 E/ M - SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3); //AF4
# a+ Q- n0 X5 t# E8 v" J - #else
! R* s5 N& t3 g X0 { - #error("无效的I2C3 IO选择");& Z6 t: U* K1 e7 o
- #endif //IIC_CH3_IO_SELECT 0 [+ R0 x4 ~' C3 c5 x+ T
- }break;
: N. y" f {- k3 D% T5 E. b: q - case IIC_CH4 : //IIC4! B6 S# @" l; E% p
- {
- a1 z+ @! h) X/ c - RCC->DCKCFGR2 &= ~(0x3 << 22); //清除设置,使用APB1作为时钟源
. T9 M' J' } }# O5 I3 [$ B - DevClock = DEV_I2C4;: v" y. z& u1 C2 B4 h0 i w V
- //初始化I2C IO9 R# w* Z5 e6 ?7 J% k+ f, P4 ?
- #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13) //PD12,PD13
# I5 i$ ^: Q7 d( W" E - SYS_DeviceClockEnable(DEV_GPIOD, TRUE); //使能GPIOD时钟6 M2 j% X. `" y5 `
- SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M); //PD12
; a6 N0 b7 i7 h: D9 {2 L9 t+ P - SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M); //PD132 h' o0 {6 j9 ?" s5 k* I
- SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4); //AF4! F$ l2 s4 y1 r' N" z7 O+ i
- SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4); //AF46 v7 g. B( r) E
- #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15) //PF14,PF153 R0 R% F* [$ @* `$ ]4 V' k
- SYS_DeviceClockEnable(DEV_GPIOF, TRUE); //使能GPIOF时钟
7 j& y+ h! \8 ?# U" m) F: C. N - SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M); //PF14
- Z% B3 j! Z2 ^& p! w - SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M); //PF15
& z P1 ]. j2 ~1 G - SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4); //AF4
- M; q8 _! T$ X0 e- [' [ - SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4); //AF42 t* W# Q9 n0 B) V9 h0 `
- #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12) //PH11,PH12
, z7 l9 h ], Z) E* C" i - SYS_DeviceClockEnable(DEV_GPIOH, TRUE); //使能GPIOH时钟
$ s2 V" B, K; [, I+ \4 F - SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M); //PH11
0 ?' `( A% `. v' b - SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M); //PH12# ^" t4 `7 E$ m) y
- SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4); //AF4. ]- u; g8 _ W! z
- SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4); //AF4 ) W+ |! Y5 r# a# V' q
- #else
( w& r( G& v9 h* o' H9 }+ z4 y - #error("无效的I2C4 IO选择");. A7 y; T, j4 J( h& S& V
- #endif //IIC_CH4_IO_SELECT
- y0 O* S4 R$ e: T4 S9 }0 z F( _( b - }break;
( a5 H* s" J# S0 F8 O8 k - default:
" [; D m. [5 h1 C( j - {! B( V# Z A- y8 w" c/ c i
- DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);2 G0 U* E" M! m) ] B% v0 e
- return FALSE;
! j0 z2 d6 r$ J/ l, G2 ^; X$ K - }
8 N/ l) u4 e8 _/ r, u* G r - }
+ K' s8 S" W; P( `# K0 m! j2 `5 ] - pHandle = &sg_IIC_Handle[ch]; //获取相关通道的句柄
! d" I2 g4 K; w1 T9 c - if(pHandle == NULL)7 p, S+ K3 U* `* [
- {. O9 y+ J9 ?' w; z# t5 d# a
- DEBUG("初始化IIC失败:无效的IIC句柄\r\n");. M4 K2 L0 f1 ?6 h1 l
- return FALSE;. G3 i- ^9 h9 I3 O& c# p
- }
$ q7 F$ d) e) d+ L# r# c, K -
5 j+ J9 a a) J" b& ?2 i% q4 W/ v - SYS_DeviceClockEnable(DevClock, TRUE); //使能时钟
' P! j, B; g1 g1 k, j* a - SYS_DeviceReset(DevClock); //外设复位
9 V3 A' `3 v$ b7 i3 \ - pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch]; //外设指针
$ a* e5 r, H0 o - pHandle->I2Cx->CR1 = 0;
+ @$ S D$ L/ h- \6 Z - Delay_US(1); ) R/ w: i+ o$ t& ~3 D: a
- pHandle->I2Cx->CR1 |= 2<<8; //设置噪声滤波器,关闭所有中断/ H8 v0 q4 q: k- ]0 S. I! m
- pHandle->I2Cx->CR2 = 0;, y/ [+ n" q( U8 T4 `: |* w
- pHandle->I2Cx->OAR1 = 0;
& q+ {5 M) o& ~% p$ X8 _+ w - pHandle->I2Cx->OAR2 = 0;' o9 J" j5 u6 A2 A0 U" I: p
- if(Speed_KHz > 1000) Speed_KHz = 1000;
$ r o; e+ C p& U# { - if(Speed_KHz < 10) Speed_KHz = 10;4 ?4 D3 F! Y- G* t) q( B
- pHandle->Speed_KHz = Speed_KHz; //记录速度
& z8 S- _ W5 _ - if(TimeOutUs == 0) //需要自动计算超时时间,时钟周期*10*10
6 r& Q; O: I6 r+ d9 e- J9 b6 M - {
. E( D" q* |$ w1 U. _6 w - TimeOutUs = 1000/Speed_KHz; //时钟周期
; E$ f; q8 L, @0 F - TimeOutUs *= 10; //字节周期
2 {- I/ {5 x* r$ }" } - TimeOutUs *= 10; //超时时间为10个字节时间
- q8 a$ G" y8 M' ~: t1 S- F4 d5 b* T& P - }
. c6 j3 Z# W4 a, Y% D - if(TimeOutUs < 3) TimeOutUs = 3;/ \; q& [; H0 T; x# f1 t
- pHandle->TimeOutUs = TimeOutUs; //记录通讯超时时间. _: S; t, p/ C3 f, Z
- uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);
5 w# H6 b) Z& M- r! c! r" ?6 H - pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732; //时序' }2 _% V2 A0 U( X2 s* H
- pHandle->I2Cx->CR1 |= BIT0; //使能IIC* f9 g; D+ w4 f, l4 R$ E$ J
- pHandle->isMasterMode = TRUE; //主设备模式
`5 j* e( M* u& O7 o% s3 z: E - Delay_US(1);8 ~0 o9 G: c7 ~: s9 i
6 \2 o+ N9 e7 Z- return TRUE;1 O Z6 `" a6 X$ j! x6 u+ |. b0 b% W
- }
* a+ y; z8 F! W( U$ [ - . `: U& ?9 ]- A" `' c$ @
d1 n( q' g1 J2 K9 \4 q3 J- /*************************************************************************************************************************1 K7 I" N# [' u
- * 函数 : static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)/ G* {9 P* p- l& H( [
- * 功能 : 检查是否有NACK中断状态,如果有则清除掉
' L; m9 I- U& _0 G - * 参数 : pHandle:句柄;TimeOutUs:超时时间,单位us
6 Z! Z! }3 w& e: t - * 返回 : IIC_ERROR
9 r: |) M% L. R - * 依赖 : 底层宏定义
+ y0 x0 z7 \3 b" u0 y c - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
' a3 A, r; q: V% V# V" { p3 d& H - * 时间 : 2020-02-15/ V# R# `& Z; w2 b( x; M9 S
- * 最后修改时间 : 2020-02-15
( ~, x( B& g% f8 d) F. p - * 说明 : 如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误
1 @, g' `5 I) P% r# m5 G5 d - *************************************************************************************************************************/ 9 L+ |6 s; ?$ i5 G" u s* ?9 X
- static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)) ^$ `8 C% k9 F% @
- {7 ]: h: n8 O: {/ V( P
- IIC_ERROR Error = IIC_OK;" W8 ]' F+ Q( I! a$ T8 k1 K# d4 i
-
. k. l. r- U( o0 h' Y$ P. | - if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF) //接收到否定应答标志
" i5 L' k. g% _2 Y5 S" h - {2 N2 o) m: }: S# F2 b5 p
- uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);& X5 O. V0 D; r" N) ?, n( B
- uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
5 H' d" ?5 ^0 c1 z6 I5 a3 ` - uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
& y8 U1 u; c3 k. O5 t8 j - //主设备下,如果没有开启自动产生停止位,则手动产生停止位4 f" i. |0 d( ^9 B$ K, N
- if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))
8 F2 T% f! t5 A- Y4 f - {
" u" C6 E! p0 {) `+ ] - IIC_SendStop(pHandle); //send stop, ?7 X* S2 d5 Z$ }9 H& ?' y6 o
- }) k, W9 O# V9 _3 k2 n4 }
- //等待STOP标志有效
; p+ J9 _6 p. @: N- ^, y( g; L0 k, f$ K - while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)' x" P c E R
- {
! z0 r9 `6 W6 E' E - if(TimeOutUs == 0) //检查是否超时了( C8 J' ^) i" P
- {
% ]7 C% L- z; R$ c% N% ^) F ~6 ? - break;
( r0 L2 Q/ v( C" l2 }9 U" ]4 D5 x - } ; J% K) i; D& c' p% y' a- F
- TimeOutUs --;& W7 b `+ O; D7 l
- Delay_US(1); //延时
! c2 t6 M, |$ a9 ^: {1 p8 M! r+ C- z5 n - }
: D8 B& I% Y3 R. X6 b - //清除相关的中断标志- e% b p+ d. z. `, ?, N/ U) U
- IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF); //清除NACK,STOP标志( N: i) G/ V! e5 p# L
- pHandle->I2Cx->CR2 = 0; //清除CR2寄存器
9 x( ?4 n9 x9 z% y& P - IIC_SoftReset(pHandle); //执行软复位
% J* B& G R8 U( [! t8 U. j - if(TimeOutUs == 0) //没有超时,就是硬件通讯出错了0 m$ _( c6 y; [; e' t. V: {4 \
- {
2 A! L2 V3 u$ ?- ~' g; u - DEBUG("IIC发送stop超时\r\n");
- j7 a* s, ], \1 h' E1 A7 d* F - Error = IIC_TIMEOUT; //超时
1 a: \7 t& ~1 n/ ], @ - }
/ r) f) `; ^% t2 ^# H3 @7 ~3 n4 f& c. n - else
% Z: d: y. D5 C8 ^' \. w - {# l' ]$ Q4 d6 i- Y8 D) `: h3 x
- Error = IIC_HAL_ERROR; //底层错误( k2 b8 g/ v9 g Z8 C6 ?2 ]
- }' L8 O: K" q- ]
- }
2 N- ?" a } U7 O8 ? -
* `! L) X. S( a) p - return Error;
) X0 [; d8 l# U) C/ g - }
! w$ Z. u' h% C) K& S9 G
2 y/ @8 X; a' R8 ?; e# _5 ^7 p
9 t3 Z% y. R J* A
e9 M3 h; Z. N0 E2 ^6 @) x- q" p- /*************************************************************************************************************************
- I5 K4 g) S; u9 ?' A - * 函数 : static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
! k0 Z& p3 F: B, n% n' X - * 功能 : 等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)( E- b/ m: n. G7 {9 `( i
- * 参数 : pHandle:句柄;TimeOutUs:超时时间,单位us6 D# Y* N; D4 E( h
- * 返回 : IIC_ERROR& }+ ^# a& G6 |- b; ~, u/ e+ f
- * 依赖 : 底层宏定义
% Q5 }7 m& S' {# Q5 H0 I8 g2 x1 E - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
! K. t( \+ h' l v; Z - * 时间 : 2020-02-151 f" m- Y$ y/ q- R# P
- * 最后修改时间 : 2020-02-15
4 `. A- c& v, x% E2 ^( n - * 说明 : 会先检查NACK中断,如果有NACK会直接退出的7 _, R! b. ^% j# k* W6 @
- *************************************************************************************************************************/
7 J5 U* M; m( T: d; I - static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
. A( E$ i. l' W9 O' ^/ s" ? - {
6 p( y! T1 j A- r) f - //等待TXIS中断有效* i# v5 Y/ J9 r9 l3 `1 r Y
- while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)/ l) W' T& L5 I' A+ E- v
- {
" i! {- e; @4 d: p$ h9 o - //有NACK中断,进行处理! r% m4 B ?$ j7 U; S( h
- if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK) ' f" r5 j2 ~6 [ o! Q
- {
4 ?6 h6 t% Y$ U' ~1 ` - DEBUG("检测到NAK错误\r\n");
9 B5 y3 [9 v/ J/ _+ a- |2 v6 U - return IIC_NACK;. X- G) S& ^: a6 i0 J1 ]- ]
- }' E" k; w6 f! i, n3 _( w- B& w6 s) n
-
5 |0 _' `! c/ `3 c D - if(TimeOutUs == 0) //检查是否超时了; |4 G, d; D3 d8 E2 m7 V
- {! z- K, F" r7 z m
- uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);
0 Z: q8 p1 x* S: D5 G/ g- H# a6 N - uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);: l8 G8 \3 t. n3 Z8 j
- uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
4 P( W; i M/ u2 {5 n& b ^" d - # W+ B8 R3 X" @! a. T8 R8 @
- IIC_SoftReset(pHandle); //执行软复位5 F0 t1 X' f2 F8 \+ B
- return IIC_TIMEOUT; //超时 g0 j8 ^5 C( z- D/ W
- } 6 k% A |& R) |1 A+ _4 s- G' E
- TimeOutUs --;
9 E0 g; Z% l1 L$ n5 E& g4 \7 e - Delay_US(1); //延时2 v6 ]3 C: C& O0 n
- }' l6 G. i- c3 B* u
- 4 f1 _6 a1 F/ u, S5 Y" j
- return IIC_OK;
/ Z$ u% I _& s: t - }$ C, I# c9 \) b) V# \2 |3 j0 T" S1 d$ R
$ V' F8 |( q& h% ^ z- & k" W" b) @' B9 F: u. s4 B
- /*************************************************************************************************************************
% E; o0 d- R6 W, k# f2 [ - * 函数 : static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)5 ^+ N9 o* v U5 T5 c0 ?( u; T
- * 功能 : 等待STOP中断有效(等待 发送结束 ); |5 g3 r. M+ d7 h
- * 参数 : pHandle:句柄;TimeOutUs:超时时间,单位us
: ~9 D, ^; z4 U3 l- Q - * 返回 : IIC_ERROR
* U1 { C ^" [$ ]/ Q0 d5 s0 { - * 依赖 : 底层宏定义
. w7 f1 g' ?5 I0 A - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
1 P9 O. u4 ^. g( i9 B - * 时间 : 2020-02-15$ ^7 t) T- d) v% ^ z4 [; t( j
- * 最后修改时间 : 2020-02-150 v! A4 \5 C: ]
- * 说明 : 会先检查NACK中断,如果有NACK会直接退出的
' s0 l% i( N9 O* _ - *************************************************************************************************************************/ * \7 x& @! ?& X5 c2 h F4 ?
- static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)3 |' h' t5 M; m/ A8 H# {0 Y, {
- {, G' h# H. Y+ @! |! D% B' D
- //等待STOPF中断有效6 f" k' o5 W0 f; _+ f2 W/ u; g; R* ]
- while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
2 [/ ] @- \) I% K: Y6 K& `) v/ q - {) ~/ P4 E- z8 M$ d
- //有NACK中断,进行处理
2 B; K9 i3 q U+ R$ U$ A: q - if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)
& G# U0 Y: u4 X1 w" a - {
3 ~, P! E+ v; W5 [' B1 r - return IIC_HAL_ERROR;- e- Y) D3 j0 \& B8 A( R
- }
: N/ v( i% p6 Z& O4 d -
; `) A7 ^! x8 y9 _6 S" C# `# C - if(TimeOutUs == 0) //检查是否超时了7 s. m4 M& u F
- {4 [7 k: g: ]. W5 M
- IIC_SoftReset(pHandle); //执行软复位, k8 P7 d% z' @4 B
- DEBUG("IIC等待结束超时\r\n");
% Z, |+ ]; ^( T" P5 V - return IIC_TIMEOUT; //超时
; r* r& k t7 i' h! U: c; l( Y - }
, c. B y* D! ?' }! X |: Z - TimeOutUs --;
9 D+ c* Q x) q! z - Delay_US(1); //延时6 A+ u) U d3 p: d
- }1 l/ j% g' \! {; {; K3 `: M' j
-
0 k' M* d5 {8 d+ [5 }4 |' a - return IIC_OK;5 n/ [5 A% t0 V- P0 ]
- }2 S5 [$ P0 m- r, p9 `
- 0 }& b, U- C+ _/ W, E' o! o& H
- , q0 u0 G- S6 s5 }1 v+ H/ O. x
- /*************************************************************************************************************************3 ?# U& r( N- O9 c N" Y
- * 函数 : static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
3 F% Q9 y! p" ?9 R - * 功能 : 等待中断有效
. s) X9 z9 e. ? - * 参数 : pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us7 Z2 ^3 k& s- W; Z5 w5 a; y% J
- * 返回 : IIC_ERROR H) |# S3 t0 m7 d! x; \3 U. e. R
- * 依赖 : 底层宏定义
' O$ z$ e# v# z; S% C( p3 Z - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>: ?( `2 F) g. i% L5 @7 G4 I l' W
- * 时间 : 2020-02-154 f+ Y: B2 T7 {
- * 最后修改时间 : 2020-02-15
$ _# e% n/ s2 B1 T/ D* v: j1 ~; H - * 说明 : # M6 V4 v j. ]4 x7 s% d0 z& {2 h& l
- *************************************************************************************************************************/ ' j2 q' {6 \5 _0 D) V5 {( L
- static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
) M" _5 [! Q! D( V4 p/ ]& z - {- X* x+ b$ |7 ]+ U
- if(isWaitFlagSet) //需要等待标志有效
& ]& t8 k9 }/ I( k7 w9 k - {; x+ b) C7 A7 D4 `8 n+ [/ {# }
- while((IIC_GetISR(pHandle) & Flag) == 0)+ z7 ^5 y: t* E" N/ C/ q8 h
- {( \8 `, ~/ X3 f
- if(TimeOutUs == 0) //检查是否超时了
9 c2 A3 ]+ F2 ]5 U4 \' z& t - {
* p) q$ b' p* o% G3 W7 _9 [1 M - return IIC_TIMEOUT; //超时
{5 K( u: n' z7 ?- c+ ~0 g: p" q - }
( d0 Z. l" F W7 y: l" P: i+ R - TimeOutUs --;0 j# \% ]9 \7 Z
- Delay_US(1); //延时6 c8 J4 }; ~& C+ R+ D
- }
+ x! X1 V. b! p3 G - }+ W2 ?3 N' v/ ~& J( h3 S
- else //需要等待标志复位
3 ?) T# B) u6 L3 R - {
8 W/ p* J q2 I* R% ^$ Q - while((IIC_GetISR(pHandle) & Flag) != 0)7 l, v8 O9 Q0 q. `; p0 |3 W
- {
" ~5 ?" t/ `8 s7 A1 Y7 a! m - if(TimeOutUs == 0) //检查是否超时了
) K' q/ o8 B+ x" } - {
4 ?" y, P9 |) ^0 ?9 M1 q# \ - return IIC_TIMEOUT; //超时
7 L9 l1 R' X6 M1 }: V4 f) P6 K0 { - } * y+ O4 V9 o6 U, E) Q
- TimeOutUs --;6 S/ g, f$ M/ D1 w v2 v
- Delay_US(1); //延时
1 k0 N3 ?6 h9 h7 B; I' f - }& X0 l# ^8 ]+ Q1 o8 n
- } u' B5 Y6 h4 U$ ^8 A0 |( H
- 1 I" a7 \9 g6 q% z( f" t
- return IIC_OK;
, I8 }4 \( T% ~3 o' e& c n9 k' _ - }
/ t4 @* U8 w. ~2 a# r. T
7 i# r# t& Z" B4 C+ ?
, m# U7 J9 `- q6 k/ R+ {: L- $ g) M% q) m- K4 b2 {
6 e" E! a* @ ^1 T- /*************************************************************************************************************************. Z8 N" V& I9 v% L* `
- * 函数 : static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)) Z( A5 H6 R5 C; j
- * 功能 : 主设备传输配置(配置CR2寄存器)5 c+ O5 G+ n, r& ?! D8 Z" W" |! L
- * 参数 : pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR
# V. j2 [ i+ ] - * 返回 : 无% W! b4 S% Y2 h0 v
- * 依赖 : 底层宏定义
3 g, M3 d" ~8 Y: P9 |9 c/ j" p - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>1 K$ x' j/ w. T- i! b
- * 时间 : 2020-02-15: W i+ u7 q* Q) b# r2 v) ^
- * 最后修改时间 : 2020-02-16
. o# \6 X5 m- m; N2 L1 { - * 说明 : 在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。2 h9 G0 r9 j! V& {- s
- 当 RELOAD 位置 1 时,AUTOEND 位将不起作用;
- W M; d- X4 J. Z5 v$ o" Y - *************************************************************************************************************************/
& A! X0 b4 O- U! [ - static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)( T9 I' g& q6 D( n& q( D1 H7 I9 p- t
- {
e- n1 L4 B6 a - u32 temp = 0;3 z- ^4 p- s) Z9 F8 N
- 3 b' f8 f; `1 H, g+ s* [+ a9 H% z# L8 c
- //先读取CR2寄存器的值
" B# _4 A9 x2 U+ y, F/ D& s8 F4 I - temp = pHandle->I2Cx->CR2;1 X- @ w1 I3 C$ ?7 _$ |6 c
- //清除掉相关的字节
) _+ q1 H$ X5 q6 I3 c - temp &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND |I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP));6 {4 G! | X$ y& X/ [9 q
- //生成配置数据( S4 l8 I c' l( \* T3 R% N- j
- temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));
+ c# D; C$ V+ x+ A0 Q4 [, b- h - //重载与自动结束只能二选一. C8 W- C2 n ~1 s9 A7 h; N2 |
- if(EndorReload == IIC_AUTOEND_MODE) 5 }1 j& J Q- v' W4 _
- {$ E% Q- N9 F. F9 S7 G+ [# p
- temp |= I2C_CR2_AUTOEND; //自动结束模式
7 w& v* F+ p! Y* e1 K+ U9 N/ b+ |; J - }
9 f3 D/ ]! } a8 M2 L - else if(EndorReload == IIC_RELOAD_MODE)/ f& @! b! g! h! J% T
- {
" E! q' Q" D0 P( e: v( }- V( U - temp |= I2C_CR2_RELOAD; //NBYTES 重载模式
4 |) E+ b2 o1 C - }
/ S( W! `, S5 ]; K5 I5 ^2 f -
% ]- h6 ]8 t4 P1 n: F& M" a) T - switch(StartAndWR)% _8 ?$ J9 A2 V3 X7 l
- {1 q/ v7 ]; H% H7 N) R N/ V
- case IIC_NOSTART_WRITE : break; //没有开始的写-默认就是这样的0 ~. p9 A2 }1 S% `" Z& H
- case IIC_NOSTART_READ : //没有开始的读-用于后续数据读取; M! M. k, j- e, S' b: B2 ^! k
- {
: a4 g& ]: Z" e/ P9 u - temp |= I2C_CR2_RD_WRN; //读取
* @- y+ a% Z- n4 } l n0 m - }break;
9 t( G8 f9 h0 a - case IIC_START_WRITE : //生成开始写; ?- G( t+ z7 `' T [
- {
, {" Q1 c! V+ Q" N9 V4 s3 T, E; u - temp |= I2C_CR2_START; //启动传输
' z1 v) h* K% [+ o+ q9 |9 i" I9 H! P* Q - }break;, w9 y7 N5 q, A* u5 D
- case IIC_START_READ : //生成开始读 . T3 K% Y/ Z0 u6 k7 W
- {
}6 v2 c6 K* r. ] - temp |= I2C_CR2_RD_WRN; //读取( `0 E& L3 O" O5 C4 O0 R" x( f
- temp |= I2C_CR2_START; //启动传输6 J+ \8 e- z8 |& Z
- }break;) H J* M( O( n1 f& n
- default:break;
' e/ i1 K8 ]7 ? - }! S ?1 d5 W; U, w1 @ Z
- 7 L! @+ t* q( O& H* O
- //uart_printf("准备写入CR2=0x%X\t", temp);
$ v- c+ k& K5 k6 f' Q4 I: I1 Z - //更新到寄存器
# o* ~. \! r# |- r3 p" C - pHandle->I2Cx->CR2 = temp; //测试
6 M% \7 @) R% V. S! Q, C! ? - //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);: x( ?# L% T! ~% O6 s Z
- Delay_US(100);* W& V) R2 ?# |+ s& J1 K( i- |
- }3 L; ~/ S7 {2 h8 S& f5 j0 M
. ~( I& M- L/ L7 o7 ?- X" ~- 2 \* y8 ]" I% T$ o
- /*************************************************************************************************************************
3 ~% `1 e6 \7 e8 R( e - * 函数 : static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
. z- C3 P9 u- V0 F- g - * 功能 : IIC发送一字节# R" i0 \" J; _
- * 参数 : pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us% P* S* s4 v9 A+ b; ^: W* [, T
- * 返回 : IIC_ERROR
* e l: L0 O0 {' ?7 s - * 依赖 : 底层宏定义
% o! h# c. a5 x1 K0 ^2 L4 } - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
+ w; b9 z$ m5 B6 ~; H' m - * 时间 : 2020-02-15
7 V/ _! l5 I% O1 B$ N/ ] - * 最后修改时间 : 2020-02-16$ j! z E0 ]) `' S' M
- * 说明 : TXIS有效后才会进行数据发送,不会检查数据发送是否完成。9 `, q% X% ^- g1 k I9 _- l
- 如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断
8 s( ^) p3 a" S6 i5 A, V) H( o - *************************************************************************************************************************/
% e. `0 e. r& E. ?+ @ - static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
1 y' Y: U/ {0 {0 n5 [- o" E - {8 I: Q3 Q) W9 z2 J4 x( j, s
- IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs); //先等待可以发数据# X: {2 \( W5 @' i+ n4 q
- if(Error != IIC_OK) return Error;
) f8 _' ?, y B9 m0 ?8 p$ p - pHandle->I2Cx->TXDR = data; //写数据到发送寄存器-不会等待数据发送完成
+ v- s/ j: Y! n8 t/ c8 e$ K - 2 x# b7 ^ K/ o# m4 O1 w
- return IIC_OK;1 E6 v4 g5 C) N# v
- }% G& a! i7 q2 F/ K
- 1 k7 n! l! b$ C& l3 J1 F
- /*************************************************************************************************************************! z2 u* K- J; J6 c" B/ H5 N
- * 函数 : static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
: J+ |" M! K* T: b' r - bool isRead,u32 TimeOutUs)
' @; C" S" W! N4 L - * 功能 : 主设备请求发送从机地址与目标寄存器地址
4 F% x9 o0 c0 r* W - * 参数 : pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,
5 ^2 W/ i+ `# Q5 [5 z - FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us* l' Q5 Q8 @! f; n" q7 o
- * 返回 : IIC_ERROR
2 `* I' }/ |3 Z( d+ k; s* J+ q4 w5 x - * 依赖 : 底层宏定义
- p: P, S8 @2 y& U, A w8 }7 s - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>9 e! S% A$ h6 f, B
- * 时间 : 2020-02-158 c) `2 [7 C" ?
- * 最后修改时间 : 2020-02-16: o" B+ @* }. V0 t4 n8 z2 H" ]
- * 说明 : " o7 X# ~" a- p% z
- *************************************************************************************************************************/
) r/ k: \5 t6 a. j+ A" B - static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)2 w% S9 z. X, u
- {
9 ~# | q( `% ~/ N: l1 _; |# s - IIC_ERROR Error;
1 z- v H- E; _# Y5 j) Q3 ` N -
1 N7 H( ?- k/ _6 L4 b - //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);8 l7 }, s, ]8 i* l) `4 O9 W
- //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
* E/ k% a/ u( m9 S4 N& n4 t+ r - //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
/ c( R- |& {, ^) v* h* r% G/ e - //传输配置,并启动传输,发送起始序列,开始IIC传输了
- Y6 {- R6 x5 N+ p' \6 ? - //如果是读取则使能软件结束,如果是写则是自动重载4 _3 H' n- R: P8 N% z$ f/ x* R
- IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE); //传输相关配置-写,并启动传输
& V: I6 V3 w; c; X4 Z - ( t+ I/ Z" U7 I3 y( s
- //开始发送寄存器地址7 i: o# {9 x# A1 t+ Q8 a+ h2 G' I
- if(is8bitRegAddr==FALSE) //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调
* T0 G6 Z( _' S: j( T - { F- a; n8 \& B2 Z
- Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs); //先发送MSB-非最后一字节
, I) w; P. \1 p% T - if(Error != IIC_OK)
9 y5 j, Z2 \- \3 q - {
, L' ^" y$ x, ?" H - DEBUG("IIC发送寄存器地址MSB失败\r\n");
7 N. T7 T1 q1 W - return Error;
3 Q5 j! ]! l8 W/ u( }( N0 F( w" Q% M - } ( b% _0 B+ G: q4 T1 A8 i7 t4 ]6 f
- }" m" F) w& R* E% b3 T x
- Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs); //再发送LSB-最后一字节
* r& v5 a. q( ~9 U) i4 v - if(Error != IIC_OK). {2 ], R- f1 `
- {
$ `& b8 d4 Y6 I9 {9 u! E - DEBUG("IIC发送寄存器地址LSB失败\r\n");8 B% B' b9 C+ ~
- return Error;% Q% }3 W5 w$ c0 l
- }# i5 Z6 G: k% M
- //等待全部数据发送完成7 B* Q ~' b F9 ], w4 @
- if(isRead) //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。
2 U7 O0 m. J! b2 f l& V - {
9 f" E0 c0 P9 o( G - if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)/ y& h; Z6 B+ a' W4 C/ r# U, y
- {
% o; B8 X% R5 L" U0 B7 |0 c( q3 s V - return IIC_TIMEOUT;6 ?. W+ B( p8 S( z- F; [5 w
- }
3 [& D/ V8 w& q+ b9 P - } o6 H5 c d) {
- else //写入方向,等待重载
$ g. v+ L8 n4 N7 p& H - {
& ~+ Q0 P$ I5 x7 D+ D - if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)
' |) k* b1 }3 [' h3 i - {3 G; c4 |. d. z' r
- return IIC_TIMEOUT;, P4 J' s. p+ `. h0 U
- }
2 {' [* {) p: L* K6 K, U - }
5 h7 V) D. L ^0 I0 y5 {* ? - : ]. `7 E* s" q: Q( s8 ~4 E
- return Error;' b6 o m, @$ S+ O8 ?/ S
- }& Z# ^# A8 S8 q1 `
- " R; c; K& {$ j. Y
[4 d) Z; ]$ K u/ J. W" `# _& w' Y- /*************************************************************************************************************************; [1 y' Y% ? x% E9 r# U' j. a
- * 函数 : static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
1 a+ J! r' y! f* \( [: a7 B - * 功能 : 等待接收一字节数据, a! \0 b' Y% P/ V% k: `, f: y
- * 参数 : pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms w& ?1 u' d1 C- i
- * 返回 : IIC_ERROR
& Z `$ e5 ?' e5 m$ q T1 h - * 依赖 : 底层宏定义
5 m' t- q4 Z. W4 |$ P! y- k - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
( a8 ~% }& i& ~) m. p/ n - * 时间 : 2020-02-15
% r; u" i4 X+ k2 x9 M% }: | - * 最后修改时间 : 2020-02-156 T- C1 y( c# z4 ~ z& z) W' A& O
- * 说明 : 当RXNE有效后读取一条数据,否则可能会超时( I" d# }8 Y" h! v5 d5 Z
- *************************************************************************************************************************/
5 Q' @- S6 B% L8 _2 B R! i6 x% _ - static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
4 ?2 @3 D' q; n4 u+ o: y& r - {
s7 M# L$ K; ^( I$ I/ J4 R! u" A - while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0) //等待RXNE有效
. R2 Y4 X$ l T, c/ D) F - {6 Z4 o# `9 g1 M' v2 C. \- S
- if(TimeOutUs == 0) //检查是否超时了
* v+ M. s4 C! n4 T4 s0 x7 Z - {
& k4 a$ _4 f2 ]1 T: q - DEBUG("IIC等待接收超时\r\n");
0 \1 y4 n8 t( l7 T2 w1 J c* w, O - return IIC_TIMEOUT; //超时3 H* J$ {6 E3 Z
- }
8 W [; H! x" a" f1 F: I9 C - TimeOutUs --;# ]5 T8 a- G- U0 \8 Y% P4 e
- Delay_US(1); //延时
+ S9 O6 q8 o+ l* [& ~ - }: ~* C/ D+ r$ c- H0 n3 I
- ( P2 G2 Q. e' Y: Q \$ i# {( }9 d
- *pData = pHandle->I2Cx->RXDR; //读取收到的数据7 r* |; v, }& E
- return IIC_OK;
6 Y/ A& @( b+ l3 s7 u; v* ? - }
& w/ b! E: w" Q - 4 ]6 {$ o& g* A3 Q' K
- ! U: E* S' ^: H, z3 d
- /*************************************************************************************************************************
9 l& [3 \9 x) T7 i. w2 f - * 函数 : IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, 1 d' F, W4 N: n7 B: I i0 }
- u8 *pDataBuff, u16 ReadByteNum)+ b7 E7 ], v6 V0 R4 N
- * 功能 : IIC读取寄存器(可以读取1个或者多个寄存器)$ y( Y. K4 g3 w1 @) E% s
- * 参数 : ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;3 z% V/ {, e# S$ d7 [
- pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;
: g4 |( T R. l# p# U% W( r; E& l - * 返回 : IIC_ERROR
; f" X* o+ P8 ]4 z/ p - * 依赖 : 底层宏定义
( j8 I! r/ l3 _5 R; F. @3 r - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
" O0 s/ h; A! ~0 P# @3 c& g - * 时间 : 2020-02-15
5 {* L6 n7 D& \+ a3 N- q - * 最后修改时间 : 2020-02-15) s8 n% `) s. \$ z r; N. w# F9 }' N
- * 说明 : 读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据" C+ N& G R# l& P. m
- 可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
$ C3 T; v. D2 Q( N4 w# y' [ - 增加信号量
% u) X4 v# Y- D# C3 v- l - 通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在# X$ X& h" p+ M
- 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。! I- K& ]3 n/ f& n
- *************************************************************************************************************************/! X: c( d R: s- Y8 T: v
- IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)
7 ~3 \6 f- s' v8 y$ ?8 X - {
: A {9 E0 g& S" D3 u& O$ C - IIC_ERROR Error = IIC_OK;
# N9 ^4 N1 G2 r% }$ T! [- L% e - u16 ReadCount;3 A; i( O+ J' A7 V& ?" C# _
- IIC_HANDLE *pHandle;0 G* i ^! V- J+ U
-
# ~1 I3 @" b. I1 D* t0 V9 _ - if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)7 e Y r0 Q$ O
- {
* r, S V+ i8 I. z - DEBUG("IIC错误:无效的参数\r\n");
8 G; e e% ~# S- G v7 \! W - return IIC_PARAMETER_ERROR;
; T- h- ]; \ X$ l9 I - }; ?( W, }/ q5 m7 l( K6 I; R
- pHandle = &sg_IIC_Handle[ch]; //获取相关通道的句柄# b. B4 K. ]8 F* Z" J: ]
-
5 [& D/ I' w& E" O - if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙8 ]. `5 H- d. {6 |$ b* B( S# O. g
- {. {8 n( ^0 }! U6 H" C, X
- IIC_SoftReset(pHandle);
) U$ b9 S1 u, Y; O9 ~& a - DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");3 N# E8 z* `: K) P! e$ K
- if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙
4 y! v- y \! f$ J2 i1 q, N% h* s9 x - {. m- H5 w% V7 x' S1 T f
- DEBUG("IIC错误:总线忙,复位后未恢复\r\n");6 F3 Z `; x" u; z0 Y, I2 K d
- Error = IIC_BUSY;; C1 {: a/ f$ J" X
- goto end_loop;4 C# B! t! i: Q" E
- }5 T7 E" V1 d: P o0 R3 c! T" s
- }$ C- S% q: a/ i C5 C* B. p6 W
- IIC_ClearISR(pHandle, IIC_GetISR(pHandle)); //复位错误状态) o3 @! z( H; ~5 g& i6 O: J9 w
- IIC_ClearCR2(pHandle); //复位CR2寄存器$ O8 e" C* R+ ]$ z+ h' s: w
- //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
0 k/ P) U, W/ X! a8 J7 U - Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);
. q6 k9 _; I3 X- E4 J - if(Error != IIC_OK)
! p5 f6 r# f6 M: V; R( Y& { - {: H q& _6 N: ?3 Q. X+ ~7 t: A/ L
- goto end_loop;
2 i1 m# o! p5 r - }
+ I$ ~: G. O! `% L - //发送后续数据
' ^7 v& K, ?. G" a; w d7 J - if(ReadByteNum > 255) //如果超过255字节,则需要分多次读取-后续还有数据,需要重载
& X: z T6 ?; m% n4 O3 m - {
6 L8 }6 b% @* W0 E. G+ S - ReadCount = 255; //本次需要读取的数据长度255
% [, P: p' n- z. B/ j% T' u3 e' { - IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ); //传输相关配置-读取,并启动传输
o8 \/ o% M! k+ j - }
6 r2 i$ W l# d0 N; n, i0 j" _ - else
4 n7 `& ^2 Y0 A5 c+ e# Y - {
+ _) f. ? ^3 v, s - ReadCount = ReadByteNum; //记录本次需要读取的数据长度-最后一次通讯后自动结束
4 Y: p0 }( i _) T* ~, f' I - IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ); //传输相关配置-读取,并启动传输% G1 {2 Q0 [. X7 I
- }0 u, ]. x. x: m
-
' F/ ?( j, h- R$ R7 U. H" a7 Z - //循环等待接收数据完成: I2 v3 E. i8 f& L+ a( l! x$ @
- do
9 T2 |0 i( g! e$ a - {! H7 Y# |. o5 ]( I: Q) E6 D3 h! {
- //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);
& S: Y9 z2 _1 [" p7 T+ K8 E - Error = IIC_WaitRxOneByte(pHandle, pDataBuff, pHandle->TimeOutUs); //接收1字节数据' T3 S, v: U: c2 ^
- if(Error != IIC_OK)
2 k6 D# }: n4 M# U$ K6 W7 Y6 ~9 l) } - {( d/ K' [8 W4 F3 J# c( L# a2 j
- goto end_loop;
8 O2 b# i# G3 |* s% R - }/ i3 R j8 I t. M8 L T) d" C0 R1 X
-
7 q" h+ k6 |; D* l/ w - pDataBuff ++;: O: [/ ]: R0 e, u9 [$ y) ^8 t
- ReadCount --;# S8 P; |4 s+ x# @: L
- ReadByteNum --;! p$ w: ?- f/ @6 j) d4 T0 b% u
- if((ReadByteNum > 0) && (ReadCount == 0)) //还有数据要读取
) ]" s* r4 ^, Q* }! m4 R - {1 e0 U ~0 S' l$ r+ g
- if(ReadByteNum > 255) //如果超过255字节,则需要分多次读取6 ^. _: I/ K+ x. D! R8 U' c
- { U$ P/ v: u* k4 w4 ] U
- ReadCount = 255; //本次需要读取的数据长度255-后续还有数据,需要重载4 K% H. G( [+ q
- IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ); //传输相关配置-读取,不启动传输 ) ?) `* u& \; ?4 G
- }) [6 C% {8 h) H- G$ X: S- J: t
- else
8 s q+ [: ]9 F2 u& F* b - {
) R/ h6 d& \- D - ReadCount = ReadByteNum; //记录本次需要读取的数据长度-最后一次通讯,自动结束9 Y9 v8 m7 j# l! C! z
- IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ); //传输相关配置-读取,不启动传输
9 F+ C6 q$ B& d; p: t8 n - }
' N( i# G7 }2 c9 V - }
5 E! B7 Z- O/ T* t- s - }while(ReadByteNum);8 o* f# L, T" }% D) W3 G
- //读取完成了,等待STOP位有效
& W: h. y0 p& R3 d - Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);3 r* ?4 \" K/ @( f& g8 @
- if(Error != IIC_OK)
0 f/ z7 C9 u |& R3 { - {, M1 O' W: X5 W* c, B5 L# q I
- Error = IIC_STOP_ERROR;, }# w# O$ l6 q, O: l# o
- goto end_loop;+ C6 e( @$ w4 T% E3 e! m
- }
( h' z* G/ O# X! Z9 p - IIC_ClearISR(pHandle, IIC_GetISR(pHandle)); //复位错误状态5 c! \7 W! E8 q5 r. P6 v0 j/ H
- ) C' @( O8 a2 l
- end_loop: * i, O# O5 |1 p$ I9 w9 w) Q
- IIC_ClearCR2(pHandle); //复位CR2寄存器
% w- Q+ k3 ?' F6 ? e( H4 _ - if(Error != IIC_OK), v3 ]; ]/ d/ f' D7 A
- {
) D9 o' \$ Y! S$ a% C3 V5 n - IIC_SoftReset(pHandle); //IIC软复位,清除掉错误
1 I* b# b7 m* g8 {+ K* F2 m. D+ J - DEBUG("[IIC R错误]:%d\r\n", Error);6 r+ t9 S; n) V8 ~
- }
, Z5 h. \6 C* h( J - if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的6 R8 j1 d! ^5 z4 [$ m# r* ~
- {
3 L1 g9 u. L, I4 n! D4 ` - IIC_SendStop(pHandle); //总线忙,发送一个STOP,释放掉总线
2 ^' ]3 m. P8 E8 y - DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);
* H) Z2 @$ \" A6 x" n - }7 { s: D. ~( ^. l6 S4 ^
-
" B! p9 u% @9 `( i8 D+ F - return Error;
0 I' }# d9 e% H/ x9 i - }
1 Q9 l, X# c( P1 J* @ T - 2 @7 J( @. \! J3 j0 K; l* K% j
- 7 V3 [5 g/ |3 k
- /*************************************************************************************************************************. H# g' \+ Y! J- M* K( K% O: \
- * 函数 : IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, 6 F: X" @/ s3 P
- u8 *pDataBuff, u16 WriteByteNum)
$ s7 k9 f$ Q( \5 k4 V7 A4 S - * 功能 : IIC写寄存器(可以写1个或者多个寄存器)
$ V& d$ j+ I5 q* D% [$ C& f! C - * 参数 : ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;$ v/ V8 u" v8 R3 l
- pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;: Q J) l5 o! K) `( O' n4 j8 a6 ]
- * 返回 : IIC_ERROR
! P6 B& A6 V' \9 n7 I/ v5 p - * 依赖 : 底层宏定义1 v, j& I& b8 I/ x% v! N2 l) w
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a> M3 n, R5 C: g: }* p
- * 时间 : 2020-02-16
6 Z6 M, [0 `5 [; }7 O$ x, [- { - * 最后修改时间 : 2020-02-16
! D+ C' F1 s: o a - * 说明 : 写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff7 F) V' N6 V# z* X' k ]' S0 E& z4 D
- 可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
. n; D) j, ?- l* ?6 N7 | c# z. T - 增加信号量 f; B5 H! x3 o Y% m$ y, G+ w
- 通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在7 A' F; V/ U) p6 j6 J# @
- 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
; S. q4 ]- G! M! L- \( u$ t - *************************************************************************************************************************/
+ e# X ?) P# _! _ - IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)
( G' w8 y5 ?/ G& ~+ y% X, L& i - { m! t- D; U' ]$ C) a
- IIC_ERROR Error = IIC_OK;
0 z$ j8 U' }) T2 H' Y - u16 ReadCount;4 e2 S! r0 q2 w4 B) Y
- IIC_HANDLE *pHandle;9 L$ \7 ~ H8 V, |
- 5 {3 w, y# D9 ^- }; Y i1 o( ~
- if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)
( Q G8 b- z3 u- F" M5 v - {
% Z- f3 k4 @ `: r1 E8 B, r' Y- ` - DEBUG("IIC错误:无效的参数\r\n");" U) V% \$ j& e% x% X S' h) T, ?
- return IIC_PARAMETER_ERROR;9 X+ T% q$ G8 {9 \' ~6 Z( H' p/ o" U
- }
- ~# j1 P1 C* |& b- \ - pHandle = &sg_IIC_Handle[ch]; //获取相关通道的句柄* C: `1 y- P6 X L' x4 N
-
! _2 x6 G0 v( u4 B$ V5 v) V - if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙
4 L' X# v5 z2 m" P - {
( T: M7 \$ a! C6 W) S; y - DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");0 A' N k7 A! R% F9 n3 A3 p
- IIC_SoftReset(pHandle);
4 M* z3 H1 h' H* b# S - / Q# `# a3 r8 N) S' l0 Y
- if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙
$ ~; |$ m7 O" h: |$ _: F1 l - {4 c& O+ p4 t1 y& C0 P+ f/ T
- DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
" y- n0 @. W) ^1 ]* [% K* |4 |% B - Error = IIC_BUSY;
" x. u$ k# x0 H+ {# U2 ?2 S. p - goto end_loop;$ h1 r6 ?; j8 \3 n% \# H2 M& C
- }
s3 k9 C3 [7 {% o - }
' g+ R8 z2 A+ A2 k% a: F- q - 7 G$ H; {( g. ?8 b
- IIC_ClearISR(pHandle, IIC_GetISR(pHandle)); //复位错误状态
9 H7 ^$ g3 L! n8 ?" w - IIC_ClearCR2(pHandle); //复位CR2寄存器& {6 G$ R* U8 b4 L! F4 w8 y
- //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
- j4 X' f1 ~( A/ Z2 c. K+ d0 B. O - Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE, pHandle->TimeOutUs);) b# P9 i" {+ c0 F
- if(Error != IIC_OK)
& l8 s( T3 \7 r! ] - {1 `+ L& g' M) c' f6 [
- goto end_loop;8 Z" v1 l3 h$ k l4 Z
- }0 C$ E/ k7 N2 m5 i3 C f# o, b% X
- //发送后续数据5 S f$ [* X' @- k- i( q
- if(WriteByteNum > 255) //如果超过255字节,则需要分多次写入-后续还有数据,需要重载& C# T$ }: v5 V- a# v; s8 C+ h
- {! o: Q: k9 ^2 K8 Y' u0 C
- ReadCount = 255; //本次需要写入的数据长度2551 Q Y" a6 \1 V' v. w
- IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE); //传输相关配置-不启动传输的写入 6 N3 {: c" A4 _8 c
- }* K0 p: p: m0 ]3 Z% A" z
- else
( K0 B6 O2 i& t/ A - {
- N4 G9 k( x" s. g - ReadCount = WriteByteNum; //记录本次需要写入的数据长度-最后一次通讯后自动结束
% y, r9 Q5 d' H: c, K+ i - IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE); //传输相关配置-不启动传输的写入+ ]; O6 ~: c1 a% N. J# n: o& V1 M
- }
$ G" Y' C- d+ D& v# o9 A; v8 G2 N - 8 ], p+ C2 [ ~! A% y4 ?+ B3 J! p3 P
- //循环发送数据3 M, ?+ a2 _. Y( r4 c0 M
- do
1 e1 p: v3 L: \/ S - {9 Q) H; p! W6 W, l+ p, P( g
- Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs); //发送一字节
: U4 ?7 D" u% r2 H9 b! ] - if(Error != IIC_OK)
, Z3 M! W" a" ~# b" K& i - {4 J- R. v- j8 g% {: P
- goto end_loop;! n3 T7 Z T4 s/ K) f; g! w8 |
- }
; x8 s: Y) ~! A4 ~- g - ! _) e) g' C1 J m* w& h
- ReadCount --;$ Y) r8 `; k3 o1 X9 A1 o
- WriteByteNum --;
/ r; x# m+ A, a - pDataBuff ++;( ]- z3 i; B; B5 b$ C5 }' o8 l
- 3 G% K& _+ u8 j+ \
- if((WriteByteNum > 0) && (ReadCount == 0)) //还有数据要读取
7 u. D$ j/ W$ E) X3 ]( i2 H - {
/ k6 H; E+ j K- M* k, i( O! a - if(WriteByteNum > 255) //如果超过255字节,则需要分多次读取
B3 _+ }. k, `, l/ f" c - {" g3 I; i2 I4 b) I1 g& g$ W
- ReadCount = 255; //本次需要写入的数据长度255-后续还有数据,需要重载* @" |1 d6 H" P1 N6 k7 w; P
- IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE); //传输相关配置-不启动传输的写入
- D$ ~* U- i6 M) @. T- x% R- I' `) f - }
6 a2 }5 |' h+ i3 U6 ^8 q, v - else5 }3 [9 Y* M0 N$ |9 a
- {8 B. |9 C8 t; J* B( _
- ReadCount = WriteByteNum; //记录本次需要写入的数据长度-最后一次通讯,自动结束
8 D' w* W3 g. h# l& ^! ~: C+ Y# [ - IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE); //传输相关配置-不启动传输的写入
. h; m0 {6 W6 R c9 Z9 i - }
' _) c! }. w# c# ^( K+ V; g1 D - }
% M8 r3 F4 k7 P+ T3 C! X- o9 E - }while(WriteByteNum);
. o8 K" w' M4 d+ v - 4 i9 g5 w% [$ o# S; H
- //写入完成了,等待STOP位有效
( t. {" R1 e% c - Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);2 M% @. d4 K |" p# ~1 p
- if(Error != IIC_OK)
2 L7 m6 o; X2 T" l - { N2 A4 x+ c7 H! R( }# t- i* i
- Error = IIC_STOP_ERROR;# n$ T& ?9 w& t* _( t
- goto end_loop;1 Q% t: J7 R5 x C; |5 {6 r: H
- }
) C Z8 `2 v! E+ w5 }- C1 O. V5 \ - IIC_ClearISR(pHandle, IIC_GetISR(pHandle)); //复位错误状态2 ]( x' I: v# Y$ F
-
& a; b. z) a5 U4 f. ` - end_loop:
q' V6 ^: d5 D% c/ N" }4 Y - IIC_ClearCR2(pHandle); //复位CR2寄存器
& r9 J8 \5 L7 i - if(Error != IIC_OK)
6 k; G/ c, I. e7 g5 t, q, |$ J - {. M2 y1 u+ @0 d' [, L- u
- IIC_SoftReset(pHandle); //IIC软复位,清除掉错误
j3 M* e5 L) L; m9 l0 t; }3 \ - DEBUG("[IIC W错误]:%d\r\n", Error);
_* {/ J4 z; E5 M: E! Q( m" W% T - }. }/ O% Z& T, u4 ]2 }2 ^
-
7 ?( ^" X6 o7 b" h! b# i X- e - if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的3 X/ d; i8 P& \! F& i
- {
( Q2 Q3 F3 e2 @' E" r* T0 F - IIC_SendStop(pHandle); //总线忙,发送一个STOP,释放掉总线9 H; L5 [7 J- J1 B! V( p& H
- DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR); * T! I, D4 P* x+ v+ c& t
- }
3 |! A8 s3 A4 u4 a" g0 X$ ?* N" P - return Error;5 [ K+ \9 [, b
- }5 u0 q- q) R, p0 u, ]+ b1 l/ J" a
- & C$ h1 _1 N2 z5 ]; g8 E
- ) |& m6 U$ r$ @* }$ B2 V3 H" N
- /*************************************************************************************************************************
# ^1 w+ m9 [) k" V - * 函数 : void IIC_SoftReset(IIC_HANDLE *pHandle)
7 ^$ |, K/ ^7 ^! \* o - * 功能 : 硬件IIC软复位(会使能IIC) l; B8 M0 `4 L: l* _/ f! ~
- * 参数 : ch:IIC通道& Y3 ^ D, G) l: v" w
- * 返回 : IIC_ERROR$ Q5 d8 |% P) S( v
- * 依赖 : 底层宏定义& K' W! x+ u; l; P' b, N
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
# n7 R# K" F6 E' R7 r) l - * 时间 : 2020-02-15
! q r0 D B% C! H, t* C. w - * 最后修改时间 : 2020-02-15
* N2 I9 I6 @* {7 d+ E& ? ^# s - * 说明 : IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。$ i$ l* n( ~* r* Q/ _3 G4 x2 P
- *************************************************************************************************************************/
~ ~4 m+ y; s- Q2 r - static void IIC_SoftReset(IIC_HANDLE *pHandle)7 J4 p3 c$ w5 d7 l- O; t0 @
- {3 X. r, v- K. U
- pHandle->I2Cx->CR1 &= ~BIT0; //关闭IIC后执行软复位
4 ^$ y! _+ ?7 o - Delay_US(1); - P# h) z- D. r& P/ {
- if(pHandle->I2Cx->CR1 & BIT0)/ V# d% v9 O5 W9 z
- {4 a) U4 R+ S) ]; ?) B/ t; u
- DEBUG("IIC软复位失败\r\n");9 R% Z9 x' t$ B) ?" G9 @
- }
3 q0 i, {8 G) V4 h T - pHandle->I2Cx->CR1 |= BIT0; //重新启动! j. S" ~# t! ^' I
- Delay_US(1);
) r5 x* y% C, p, Y* { - }3 b7 J+ ]! H) v/ Y+ ~
( s9 V: P; n' R& w f
- e) r }& @3 ~5 \6 ]- I$ p U, Y% T; G- 0 P' h& r0 ^3 j/ |; @8 n- A" \% ^. x
- /*************************************************************************************************************************5 n: f! S% q% I( B4 C
- * 函数 : static u32 IIC_CalculationTiming(u16 Speed_KHz)" v& w4 G A$ E: G! [$ z
- * 功能 : 硬件IIC时序计算
" k s3 b1 W2 \: X5 v: g& Q - * 参数 : ch:IIC通道;Speed_KHz:速度10-1000
" L" i! [: y3 E' I9 A - * 返回 : IIC_ERROR
3 W) D/ z! W# u0 ?' O" i6 h - * 依赖 : 底层宏定义" r6 q9 c! v8 C
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>. g& ` P0 Y; j5 n4 _
- * 时间 : 2020-02-15- s& c* X9 y V4 h
- * 最后修改时间 : 2020-02-15& ~2 p7 x$ D& m7 u5 |+ y6 V
- * 说明 : IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz 7 f/ j0 m( v5 g0 \1 R' U3 }1 E( E
- APB1时钟:最大不能超过45MHz . q/ e8 }4 }1 z$ N7 j5 d3 L
- 如果速度是100,则按照SMBUS时序5 d& I3 y- i8 u4 x
- *************************************************************************************************************************/
5 |; H5 L& r. z1 X8 N% c - static u32 IIC_CalculationTiming(u16 Speed_KHz)
- y Y# M7 ]- k& s7 l - {
. K7 x% g$ I8 J - u32 tTime = 0;- `) J, d! s. a/ w
- u32 temp;. b6 ?* ]6 U. r0 q7 e
- u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000; //先获取APB1时钟速度
! [4 \2 d, G/ a: E* z - u32 Th = 1000/Speed_KHz/2; //计算高电平时间(低电平时间一样),单位ns
( U9 Z4 m6 S J -
2 t4 y4 v0 \% t - if(time_temp < 20) time_temp = 20;
7 n, {, f3 @* I% Z - time_temp = 1*1000 / time_temp; //单位ns# B& y1 t& r& k. v: @% H
- uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);$ i5 h) y( D3 C* a: b
- if(Speed_KHz == 100) //如果是100,则按照SMBUS时序+ N6 m, U1 _9 e! j
- {
~. d) ~* h3 F6 _! {6 b - //主时钟分频系数固定为3
" l" J5 ?& ?/ ] |/ A! {! `+ s - time_temp *= 3; //主时钟周期" A9 s$ b ^" M* U: {0 [
- uart_printf("IIC时钟周期:%dns\t", time_temp);" `; o* M" ~, \1 X: k3 z( n
- tTime |= (3-1) << 28; //PRESC,时钟预分配- C$ w* d. h2 v* M0 u
- //计算数据建立时间,要求最小250ns* c. ~! R1 Y: R% a
- temp = 250 / time_temp;
. W3 c8 |; ]$ e" ~ D! e - if(temp > 15) temp = 15;: |" J" Y5 P* O# ?' N
- if(temp < 1) temp = 1;2 C' k: N7 `2 R w" U j( q
- tTime |= temp << 20;
# [+ B% i: R0 m6 i* J - //计算数据保持时间,要求至少300ns# i* G- E/ b: A
- temp = 300 / time_temp;+ R; G3 x; q, _& \' x" x
- if(temp > 15) temp = 15;
2 x7 W! C: ^! o* S* M5 Z/ k - if(temp < 1) temp = 1;
* n+ L' I) k4 a. }1 s - tTime |= temp << 16;4 k1 P4 \2 @% D4 Y1 o! R8 f( r. w5 x* L
- //计算高电平周期5us; ^9 K7 @0 [' h4 x( Z* R" j
- temp = 5*1000 / time_temp;/ H3 {" ~/ X, U" \, _$ v9 `- S% N
- if(temp > 255) temp = 255;8 k& H; s/ N; p. [- ?+ n7 m
- if(temp < 1) temp = 1;5 w. z1 O& x1 R7 \: }* y8 y
- tTime |= temp << 8;2 R! V% ?+ D' r6 {5 i6 a9 |0 w# U, y
- //计算低电平周期5us
6 H- ?4 ~& P" a% } - temp = 5*1000 / time_temp;: j: K6 D2 N: \; T6 f( I5 D. c7 k
- if(temp > 255) temp = 255;: I3 s4 Y3 {7 b+ @, ^. X
- if(temp < 1) temp = 1;
/ I; g3 m& r! e5 [3 V: ?# ` - tTime |= temp << 0;& c w. ~+ K' @2 Y: i
- }
. l H! t0 e7 Y3 z: K$ d) c2 o( s - else if(Speed_KHz < 100)
& r; Y: C4 @6 `" x/ g% K; q - {+ e n7 G1 I7 f! ?& G; F O& ~
- //主时钟分频系数固定为6
) K( ~4 c% ~" x; H* } - time_temp *= 6; //主时钟周期 C% N, Y$ C/ ~" w( q
- uart_printf("IIC时钟周期:%dns\t", time_temp);
/ m8 V# t! {' v5 W6 d+ A - tTime |= (6-1) << 28; //PRESC,时钟预分配# ]% {& Z5 p. F. K' z( ^3 _+ F
- //计算数据建立时间,要求最小250ns
% D7 H8 R' S- u" b: @6 q - temp = 250 / time_temp;
1 h8 n9 r9 N: ^" U; s# u& c$ L - if(temp > 15) temp = 15;
' h6 l& c6 ^+ Z: p1 m/ Q - tTime |= temp << 20;
& E" }% N4 b: M8 U) u - //计算数据保持时间,要求至少300ns
3 T+ P: M2 j2 R/ f - temp = 300 / time_temp;
7 `5 E3 T. a6 h( D5 ~+ B8 p4 ~ - if(temp > 15) temp = 15;7 O G Q' m$ r" Z2 _
- tTime |= temp << 16;
4 G! {( q/ x1 H - //计算高电平周期Th us! @* Z f; f5 K9 ?
- temp = Th*1000 / time_temp;; z4 k9 Z4 G' A; W3 ]( P5 }
- if(temp > 255) temp = 255;
' A0 c$ b% N, m. ^6 _% r - if(temp < 1) temp = 1;
9 C( V' o$ N' I' l- d" m - tTime |= temp << 8;
8 u7 m& D/ d7 M) {8 u! P - //计算低电平周期 Th us" |3 |3 ^& j: M' \3 X7 O: k* G
- temp = Th*1000 / time_temp;" M: r0 T( ]) B; e Q" C3 F$ n
- if(temp > 255) temp = 255;" N- k1 u5 B4 P# \
- if(temp < 1) temp = 1;/ a( h L% I) U5 b9 b2 f6 [
- tTime |= temp << 0;
+ h! o. ?8 I- P - }
- d( Q" M& ]0 g( Q - else //>1005 _( X" G4 H& i0 T, ^; {: b
- {
- p2 |. n% I( z - //主时钟分频系数固定为2" X8 M2 c/ ?( g, ~1 B! w# H+ t
- time_temp *= 2; //主时钟周期
% ?' }. a1 G+ o) B2 p - uart_printf("IIC时钟周期:%dns\t", time_temp);( @+ ?% z, @0 B7 S# y$ @
- tTime |= (2-1) << 28; //PRESC,时钟预分配
$ X! q5 O" ^; V( P9 ?+ O: n - //计算数据建立时间,随便给100ns. f1 I1 }7 y- u" \7 v6 R1 O
- temp = 100 / time_temp;
3 @( U* O$ m, f/ ]$ Z+ k - if(temp > 15) temp = 15;! x- Z* G. _, z8 M' F
- tTime |= temp << 20;
9 g& F n4 D |* l" _ - //计算数据保持时间,给100ns& S$ |# b% |7 |1 s* ^; C
- temp = 100 / time_temp;9 y7 I; K) u( P& r. f3 X
- if(temp > 15) temp = 15;
/ q; J; @$ ^: [% z& G - tTime |= temp << 16;, q' ^5 {8 i8 ~6 V/ Z- |
- //计算高电平周期Th us* P+ D; P, K2 r2 f; ~) h- p
- temp = Th*1000 / time_temp;
& G2 ~0 v# j" q) f' b - if(temp > 255) temp = 255;
9 Q/ K1 X# r5 a" P/ X - if(temp < 1) temp = 1;$ ]6 v3 g$ c8 E0 w
- tTime |= temp << 8;8 ]. u% Y( A' l& L& C! W
- //计算低电平周期 Th us: c: }: C/ e8 @( t8 |$ l
- temp = Th*1000 / time_temp;5 Q2 S' O% i3 v& T ~" L
- if(temp > 255) temp = 255;
4 @, B1 |& J) K; _1 P - if(temp < 1) temp = 1;0 G1 b- M) q. j" J
- tTime |= temp << 0;
% v P5 Z3 }' g" G6 W - }/ P. z$ T9 F( f" r5 |# L
-
- c; L% C5 ]! R% h2 t& x% a - uart_printf("时序寄存器结果为:0x%X\r\n", tTime);3 j6 [1 I; V- ?7 {; e
- 4 ~; W, C: X5 o9 y0 N. Y7 E9 U
- return tTime;
- }, a- q/ z# B2 H9 x - }
复制代码
% n$ h) [* s1 z' H2 f+ @0 D* q i! N) m* D
- /*************************************************************************************************************
* i8 c2 y- ?# s% _6 b - * 文件名 : stm32f7_iic.h3 U$ x( W0 Y" g* S! f
- * 功能 : STM32F7 IIC接口驱动
8 r( y0 _( h" w* x; V; O0 m8 u - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
# b! {* Z( v' H$ F8 S7 h - * 创建时间 : 2020-02-09
7 J, m" {0 B* D1 P9 _/ Y# m - * 最后修改时间 : 2020-02-09# j% E, j8 ~, J% A# q
- * 详细:
4 V0 @, v6 K" Z% ] - *************************************************************************************************************/ : @- y* p! ^0 g3 Q$ c& p0 a3 N0 m
- #ifndef __STM32F7_IIC_H_: o2 L9 h3 V ~) V/ y
- #define __STM32F7_IIC_H_
% C" ~4 }/ F+ n7 T1 q, q: i& v2 d - #include "system.h"
' T4 f( P; L5 C0 P$ p
, c+ m5 a, a. z- //16位整形数高低对调4 p1 H0 x5 c. O# a( }& o& e
- #ifndef SWAP163 x; W$ o! w: O- u/ d' O9 j
- #define SWAP16(x) (((x & 0xff00) >> 8) | ((x & 0xff) << 8))
* w! o3 C% s/ x& C8 Y9 r. ? - #endif //SWAP16
% H6 Q. a* `+ `# `9 m8 M - * s t# ]/ Z$ i- z
- //硬件IO口选择, ]$ @6 o* a, M+ z2 O
- //I2C1 IO定义与选择( R) t6 p2 }: t' u( O4 f: K
- #define IIC_CH1_PB6_7 0 //PB6,PB72 l2 t8 c. {9 E9 i
- #define IIC_CH1_PB8_9 1 //PB8,PB9
t+ T1 M0 c6 r* S# ^ a0 q4 o - #define IIC_CH1_IO_SELECT IIC_CH1_PB6_7 //选择I2C1 的IO
6 E3 ]. R7 N( ?3 Z. z" G, ~) j - 2 [9 d, d; r4 G- f
- //I2C2 IO定义与选择
# t' o6 F$ p3 x: Y6 g7 R. z - #define IIC_CH2_PB10_11 0 //PB10,PB11
+ W/ G, E5 U8 v - #define IIC_CH2_PF0_1 1 //PF0,PF1& H: ?2 M3 e4 F% b5 e7 j- m" G( t$ f
- #define IIC_CH2_PH4_5 2 //PH4,PH5: z9 u- s( t( E/ E# ]4 l1 s
- #define IIC_CH2_IO_SELECT IIC_CH2_PB10_11 //选择I2C2 的IO) s. @9 T4 f& E2 p7 S8 Q
! R% I7 L) M3 S, M& ?- //I2C3 IO定义与选择
* a0 {7 S; v( g* S: W) ~ - #define IIC_CH3_PH7_8 0 //PH7,PH8! w0 `; N, P5 }$ k7 b: w
- #define IIC_CH3_PA8_PC9 1 //PA8,PC9, k9 a, e; u% k& _
- #define IIC_CH3_IO_SELECT IIC_CH3_PH7_8 //选择I2C3 的IO
5 X1 Q5 B3 f9 y6 V - ( M1 Q/ d! [( j2 s! b4 s
- //I2C4 IO定义与选择
* C& n9 W) f& \! ~9 |) u) r" F, M - #define IIC_CH4_PD12_13 0 //PD12,PD13; x0 ]4 \& A# Z- B
- #define IIC_CH4_PF14_15 1 //PF14,PF15: _$ o, u; g' b, Q
- #define IIC_CH4_PH11_12 2 //PH11,PH12
9 L4 R6 B* ]! z - #define IIC_CH4_IO_SELECT IIC_CH4_PD12_13 //选择I2C4 的IO
7 ~+ Y1 ]$ w& |9 |3 ~9 I1 @5 u
7 w8 T1 I# A) N- //IIC硬件接口选择
5 v e/ @0 ~" u' ~( C - typedef enum
2 ?* Z) Y, B( K% N - {- f7 s; \) ^* I, K
- IIC_CH1 = 0, //IIC1
6 T- b& c w/ ^2 x; B) n3 y: ? - IIC_CH2 = 1, //IIC2
( s" B' q% Y5 A3 T& y8 `7 W/ R8 `/ ^ - IIC_CH3 = 2, //IIC3
- i/ Z4 f& ] _. N( F1 Z - IIC_CH4 = 3, //IIC4
$ Q7 t+ e9 K# \ - }IIC_CH_Type;
. j9 v6 X8 n* w9 F! R6 ` - #define IIC_CH_COUNT 4 //4个IIC# v# o% L9 B% m9 B! O
- I6 b& K' B; n
- 4 u; w8 [/ O- s
- //中断状态1 h! S, j- t1 r* |1 u9 o
- #define IIC_FLAG_TXE BIT0 //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。
" a, o# B" X5 s- g3 N - #define IIC_FLAG_TXIS BIT1 //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。
1 Y# r* \3 T/ g; C0 c6 J% f( D - #define IIC_FLAG_RXNE BIT2 //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。
# b1 K9 ^8 q# t0 T, h - #define IIC_FLAG_ADDR BIT3 //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。
% g# m: p6 z+ |# y - #define IIC_FLAG_NACKF BIT4 //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。5 S) [- j( S" K% d* a6 t
- #define IIC_FLAG_STOPF BIT5 //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1
5 v" H' Q/ U' Y, R0 \) [ - #define IIC_FLAG_TC BIT6 //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。
9 N6 W% o) j9 Z1 P - #define IIC_FLAG_TCR BIT7 //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。7 W5 d4 y4 W4 ?1 L! b8 e
- #define IIC_FLAG_BERR BIT8 //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。
: i' }" r' G2 E4 k, D/ m - #define IIC_FLAG_ARLO BIT9 //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。7 T& W1 ]- j2 O. `+ Y! j9 Y
- #define IIC_FLAG_OVR BIT10 //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。( ?! _6 y; }! i8 ?1 B5 A* Q
- #define IIC_FLAG_PECERR BIT11 //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。
, h# u: W* l ^* |$ q - #define IIC_FLAG_TIMEOUT BIT12 //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。
( H5 _. E, }) @" S; C - #define IIC_FLAG_ALERT BIT13 //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。
; k f% v: l; g% l2 N8 a/ m" ] - #define IIC_FLAG_BUSY BIT15 //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。+ T; g/ V3 N: ~( O
- #define IIC_FLAG_DIR BIT16 //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读
6 D7 J* R' ^, E0 \' j1 {; U - 1 `" L8 f9 @; Q0 ?4 y( K
- //通讯错误状态5 n! I+ M; U2 M* n& a
- typedef enum
9 T+ O2 w7 A7 J2 C! e4 Q3 y - {3 h2 }& U. e3 Z. r1 S2 f
- IIC_OK = 0, //没有错误
: e9 ?$ H: T- o( a - IIC_PARAMETER_ERROR = 1, //参数错误( D t% X2 d# W4 M l1 L W
- IIC_TIMEOUT = 2, //超时错误,也可能是底层错误
& N) }& X: m8 ? - IIC_HAL_ERROR = 3, //底层错误3 S i! A8 D5 o1 W: ^
- IIC_STOP_ERROR = 4, //等待结束错误) d# y7 r, X- H3 x3 D* E
- IIC_BUSY = 5, //硬件忙
' b, ]% f- a8 L {$ g - IIC_NACK = 6, //收到NACK了
3 i9 _" D. W8 U0 m6 B - }IIC_ERROR;& I6 e- t! p# j; O- L# X2 d: l
5 v' s5 J1 _2 i0 }3 z4 O
6 y9 @9 G( [' P, G2 [' ?) w- bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs); //硬件IIC初始化
9 m" w0 G8 p$ ~ b8 Q8 K( W - IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum); //IIC读取寄存器(可以读取1个或者多个寄存器)' a2 Z2 H* }; W' B) B1 m
- IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum); //IIC写寄存器(可以写1个或者多个寄存器)) `+ s# z3 [5 d$ ~7 X0 _
- ) M% i. O2 E& }# M' L; n
/ P9 A5 k+ L- W9 g( C, a; Q- #endif //__STM32F7_IIC_H_
复制代码 " j% G' m3 v* D# X3 _0 _
9 i. l8 [( r. X& [) a8 k//初始化2 H9 B: W, W6 _3 Z3 t+ w0 d* J
" W$ j1 A4 I3 b6 O$ T
- IIC_Init(IIC_CH3, 200, 0); //硬件IIC初始化
复制代码
( ~$ d# `# c- e6 Z
/ S V, ^) G U7 l. q//调用: Y, o! G4 p0 I; K. f" P
; }4 v9 X- L/ a* ?4 f1 J) U4 h- //触摸屏IIC读取寄存器接口* R( N+ B* y$ N7 d& n5 p
- bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
+ A' ?* y' Z% _ - {+ i; b# g" a! E, D+ ]2 s8 [* S
- if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)- v5 ^3 v7 B E+ ^9 `
- {
) e( ^4 T5 D' m8 t. c - return TRUE;
' D9 ^1 d- p: I2 } - }
+ v8 X" [5 F9 q- ]+ k& T& C5 a: I - else; Y0 r( @" o7 s7 I; d( w( N# M. |
- {
( w; _6 B- F( C" E% ] - return FALSE;6 t. X, y7 d; t0 J7 u3 a6 i6 e
- }1 z1 b! ^. q% W/ b0 @6 X
- }
d& U! `" V, _) M0 z. D+ k, W3 k
' L9 W% C o( X0 m- //触摸屏IIC写寄存器接口
3 t: O+ d4 e3 s6 t5 Y - bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)6 ]5 `$ n& N* `8 @
- {/ U J7 p" `) b3 p! Q0 u
- if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK), d" Q/ A5 y1 m1 x2 c2 @
- {* R& c0 c+ a" k6 ]3 v$ _, M/ ~' b
- return TRUE;
; b7 a0 O. b S - }
- r) K3 \& s$ T/ c, r* z - else) K8 `+ h2 {1 i% u# X
- {. }* P3 L8 K. d" z
- return FALSE;
: n' I1 ^! n; m1 g& ]' V$ Q0 M B - }$ U' b( B& E. b( V* e. b
- 1 B/ H7 z% y: K0 ~; x( L v7 b
复制代码
- U* t8 V, [. a5 ?0 D1 A/ [' a
. D, }3 S3 V! T& ~1 F
# k; S7 J3 s' W0 ?1 L* p9 N } |