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