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