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