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