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