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