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