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