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