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