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