目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。
目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。
下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。
正在上传…重新上传取消
下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):
[基本的初始化]
1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。
2.CR1先赋值为0,复位IIC.
3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为0
4.设置CR1使能IIC。
注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。
[读取]
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。
3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。
5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。
7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。
8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。
9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。
[写入]
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。
3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。
5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。
7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。
8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。
9.需要注意的是,所有的操作都要给超时,跟读取一样。
注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。
好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)
/*************************************************************************************************************
- 文件名 : stm32f7_iic.c
- 功能 : STM32F7 IIC接口驱动
- 作者 : cp1300@139.com
- 创建时间 : 2020-02-09
- 最后修改时间 : 2020-02-09
- 详细: 只支持主机模式,7bit地址,默认APB1为IIC提供时钟
涉及到读写1字节的超时时间是us,其余的是ms
注意:IIC的IO必须初始化为复用开漏输出。
*************************************************************************************************************/
#include “stm32f7_iic.h”
#include “system.h”
#include “dma.h”
#define IIC_FLAG_MASK ((uint32_t)0x0001FFFF) //中断标志掩码
//自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)
typedef enum
{
IIC_SOFTEND_MODE = 0, //手动结束,并不开启重载
IIC_AUTOEND_MODE = 1, //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯
IIC_RELOAD_MODE = 2, //后续还有数据,本次通讯后自动重载,重新设置后继续通讯
}IIC_RELOAD_END_MODE;
//读写与开始模式控制
typedef enum
{
IIC_NOSTART_WRITE = 0, //没有开始的写-用于后续数据的写入
IIC_NOSTART_READ = 1, //没有开始的读-用于后续数据读取
IIC_START_WRITE = 2, //生成开始写-用于通讯开始时,写地址或数据
IIC_START_READ = 3, //生成开始读-用于读取数据时切换到读取方向,并读取后续数据
}IIC_START_WR_MODE;
//IIC句柄
typedef struct
{
IIC_CH_Type ch; //当前通道
I2C_TypeDef *I2Cx; //当前通道外设结构体
u32 TimeOutUs; //操作超时,单位us
u16 Speed_KHz; //通讯速度,单位KHz
bool isMasterMode; //是否为主设备模式-目前只支持主设备模式
}IIC_HANDLE;
//IIC外设结构指针
static const I2C_TypeDef * const I2C_TYPE_BUFF[4] = {I2C1,I2C2,I2C3,I2C4};
//IIC通道句柄定义
static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];
//发送NAK
static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}
//发送STOP
static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}
//发送START
static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}
//获取中断状态
static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}
//清除中断状态
static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}
//复位CR2寄存器
static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}
static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)
static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算
/*************************************************************************************************************************
-
函数 : bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)
-
功能 : 硬件IIC初始化
-
参数 : ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)
-
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-15
-
说明 : 速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,
时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性
*************************************************************************************************************************/
bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)
{
SYS_DEV_CLOCK DevCloce;
IIC_HANDLE *pHandle;switch(ch)
{
case IIC_CH1 : //IIC1
{
RCC->DCKCFGR2 &= ~(0x3 << 16); //清除设置,使用APB1作为时钟源
DevCloce = DEV_I2C1;
}break;
case IIC_CH2 : //IIC2
{
RCC->DCKCFGR2 &= ~(0x3 << 18); //清除设置,使用APB1作为时钟源
DevCloce = DEV_I2C2;
}break;
case IIC_CH3 : //IIC3
{
RCC->DCKCFGR2 &= ~(0x3 << 20); //清除设置,使用APB1作为时钟源
DevCloce = DEV_I2C3;
//初始化IO口
SYS_DeviceClockEnable(DEV_GPIOH, TRUE); //使能GPIOH时钟
SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M); //PH7
SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M); //PH8
SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3); //AF4
SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3); //AF4
}break;
case IIC_CH4 : //IIC4
{
RCC->DCKCFGR2 &= ~(0x3 << 22); //清除设置,使用APB1作为时钟源
DevCloce = DEV_I2C4;
}break;
default:
{
DEBUG(“初始化IIC失败:无效的IIC通道%d\r\n”, ch);
return FALSE;
}
}
pHandle = &sg_IIC_Handle[ch]; //获取相关通道的句柄
if(pHandle == NULL)
{
DEBUG(“初始化IIC失败:无效的IIC句柄\r\n”);
return FALSE;
}SYS_DeviceClockEnable(DevCloce, TRUE); //使能时钟
SYS_DeviceReset(DevCloce); //外设复位
pHandle->I2Cx = (I2C_TypeDef )I2C_TYPE_BUFF[ch]; //外设指针
pHandle->I2Cx->CR1 = 0;
Delay_US(1);
pHandle->I2Cx->CR1 |= 2<<8; //设置噪声滤波器,关闭所有中断
pHandle->I2Cx->CR2 = 0;
pHandle->I2Cx->OAR1 = 0;
pHandle->I2Cx->OAR2 = 0;
if(Speed_KHz > 1000) Speed_KHz = 1000;
if(Speed_KHz < 10) Speed_KHz = 10;
pHandle->Speed_KHz = Speed_KHz; //记录速度
if(TimeOutUs == 0) //需要自动计算超时时间,时钟周期10*10
{
TimeOutUs = 1000/Speed_KHz; //时钟周期
TimeOutUs *= 10; //字节周期
TimeOutUs *= 10; //超时时间为10个字节时间
}
if(TimeOutUs < 3) TimeOutUs = 3;
pHandle->TimeOutUs = TimeOutUs; //记录通讯超时时间
uart_printf(“IIC超时时间:%dus\r\n”, pHandle->TimeOutUs);
pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732; //时序
pHandle->I2Cx->CR1 |= BIT0; //使能IIC
pHandle->isMasterMode = TRUE; //主设备模式
Delay_US(1);return TRUE;
}
/*************************************************************************************************************************
-
函数 : static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)
-
功能 : 检查是否有NACK中断状态,如果有则清除掉
-
参数 : pHandle:句柄;TimeOutUs:超时时间,单位us
-
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-15
-
说明 : 如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误
*************************************************************************************************************************/
static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)
{
IIC_ERROR Error = IIC_OK;if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF) //接收到否定应答标志
{
uart_printf(“NACK : IIC_isWaitTXIS:CR1=0x%X\t”, pHandle->I2Cx->CR1);
uart_printf(“CR2=0x%X\t”, pHandle->I2Cx->CR2);
uart_printf(“ISR=0x%X\r\n”, IIC_GetISR(pHandle));
//主设备下,如果没有开启自动产生停止位,则手动产生停止位
if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))
{
IIC_SendStop(pHandle); //send stop
}
//等待STOP标志有效
while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
{
if(TimeOutUs == 0) //检查是否超时了
{
break;
}
TimeOutUs --;
Delay_US(1); //延时
}
//清除相关的中断标志
IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF); //清除NACK,STOP标志
pHandle->I2Cx->CR2 = 0; //清除CR2寄存器
IIC_SoftReset(pHandle); //执行软复位
if(TimeOutUs == 0) //没有超时,就是硬件通讯出错了
{
DEBUG(“IIC发送stop超时\r\n”);
Error = IIC_TIMEOUT; //超时
}
else
{
Error = IIC_HAL_ERROR; //底层错误
}
}return Error;
}
/*************************************************************************************************************************
-
函数 : static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
-
功能 : 等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)
-
参数 : pHandle:句柄;TimeOutUs:超时时间,单位us
-
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-15
-
说明 : 会先检查NACK中断,如果有NACK会直接退出的
*************************************************************************************************************************/
static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
{
//等待TXIS中断有效
while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)
{
//有NACK中断,进行处理
if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)
{
DEBUG(“检测到NAK错误\r\n”);
return IIC_NACK;
}if(TimeOutUs == 0) //检查是否超时了 { uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1); uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2); uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle)); IIC_SoftReset(pHandle); //执行软复位 return IIC_TIMEOUT; //超时 } TimeOutUs --; Delay_US(1); //延时
}
return IIC_OK;
}
/*************************************************************************************************************************
-
函数 : static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)
-
功能 : 等待STOP中断有效(等待 发送结束 )
-
参数 : pHandle:句柄;TimeOutUs:超时时间,单位us
-
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-15
-
说明 : 会先检查NACK中断,如果有NACK会直接退出的
*************************************************************************************************************************/
static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)
{
//等待STOPF中断有效
while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
{
//有NACK中断,进行处理
if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)
{
return IIC_HAL_ERROR;
}if(TimeOutUs == 0) //检查是否超时了 { IIC_SoftReset(pHandle); //执行软复位 DEBUG("IIC等待结束超时\r\n"); return IIC_TIMEOUT; //超时 } TimeOutUs --; Delay_US(1); //延时
}
return IIC_OK;
}
/*************************************************************************************************************************
-
函数 : static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
-
功能 : 等待中断有效
-
参数 : pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us
-
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-15
-
说明 :
*************************************************************************************************************************/
static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
{
if(isWaitFlagSet) //需要等待标志有效
{
while((IIC_GetISR(pHandle) & Flag) == 0)
{
if(TimeOutUs == 0) //检查是否超时了
{
return IIC_TIMEOUT; //超时
}
TimeOutUs --;
Delay_US(1); //延时
}
}
else //需要等待标志复位
{
while((IIC_GetISR(pHandle) & Flag) != 0)
{
if(TimeOutUs == 0) //检查是否超时了
{
return IIC_TIMEOUT; //超时
}
TimeOutUs --;
Delay_US(1); //延时
}
}return IIC_OK;
}
/*************************************************************************************************************************
-
函数 : static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)
-
功能 : 主设备传输配置(配置CR2寄存器)
-
参数 : pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR
-
返回 : 无
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-16
-
说明 : 在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。
当 RELOAD 位置 1 时,AUTOEND 位将不起作用;
*************************************************************************************************************************/
static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)
{
u32 temp = 0;//先读取CR2寄存器的值
temp = pHandle->I2Cx->CR2;
//清除掉相关的字节
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));
//生成配置数据
temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));
//重载与自动结束只能二选一
if(EndorReload == IIC_AUTOEND_MODE)
{
temp |= I2C_CR2_AUTOEND; //自动结束模式
}
else if(EndorReload == IIC_RELOAD_MODE)
{
temp |= I2C_CR2_RELOAD; //NBYTES 重载模式
}switch(StartAndWR)
{
case IIC_NOSTART_WRITE : break; //没有开始的写-默认就是这样的
case IIC_NOSTART_READ : //没有开始的读-用于后续数据读取
{
temp |= I2C_CR2_RD_WRN; //读取
}break;
case IIC_START_WRITE : //生成开始写
{
temp |= I2C_CR2_START; //启动传输
}break;
case IIC_START_READ : //生成开始读
{
temp |= I2C_CR2_RD_WRN; //读取
temp |= I2C_CR2_START; //启动传输
}break;
default:break;
}//uart_printf(“准备写入CR2=0x%X\t”, temp);
//更新到寄存器
pHandle->I2Cx->CR2 = temp; //测试
//uart_printf(“ISR=0x%X\r\n”, pHandle->I2Cx->ISR);
Delay_US(100);
}
/*************************************************************************************************************************
-
函数 : static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
-
功能 : IIC发送一字节
-
参数 : pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us
-
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-16
-
说明 : TXIS有效后才会进行数据发送,不会检查数据发送是否完成。
如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断
*************************************************************************************************************************/
static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
{
IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs); //先等待可以发数据
if(Error != IIC_OK) return Error;
pHandle->I2Cx->TXDR = data; //写数据到发送寄存器-不会等待数据发送完成return IIC_OK;
}
/*************************************************************************************************************************
-
函数 : static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
bool isRead,u32 TimeOutUs) -
功能 : 主设备请求发送从机地址与目标寄存器地址
-
参数 : pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,
FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us -
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-16
-
说明 :
*************************************************************************************************************************/
static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)
{
IIC_ERROR Error;//uart_printf(“WriteAddr1:CR1=0x%X\t”, pHandle->I2Cx->CR1);
//uart_printf(“CR2=0x%X\t”, pHandle->I2Cx->CR2);
//uart_printf(“ISR=0x%X\r\n”, pHandle->I2Cx->ISR);
//传输配置,并启动传输,发送起始序列,开始IIC传输了
//如果是读取则使能软件结束,如果是写则是自动重载
IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE); //传输相关配置-写,并启动传输//开始发送寄存器地址
if(is8bitRegAddr==FALSE) //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调
{
Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs); //先发送MSB-非最后一字节
if(Error != IIC_OK)
{
DEBUG(“IIC发送寄存器地址MSB失败\r\n”);
return Error;
}
}
Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs); //再发送LSB-最后一字节
if(Error != IIC_OK)
{
DEBUG(“IIC发送寄存器地址LSB失败\r\n”);
return Error;
}
//等待全部数据发送完成
if(isRead) //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。
{
if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)
{
return IIC_TIMEOUT;
}
}
else //写入方向,等待重载
{
if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)
{
return IIC_TIMEOUT;
}
}return Error;
}
/*************************************************************************************************************************
-
函数 : static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
-
功能 : 等待接收一字节数据
-
参数 : pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms
-
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-15
-
说明 : 当RXNE有效后读取一条数据,否则可能会超时
*************************************************************************************************************************/
static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
{
while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0) //等待RXNE有效
{
if(TimeOutUs == 0) //检查是否超时了
{
DEBUG(“IIC等待接收超时\r\n”);
return IIC_TIMEOUT; //超时
}
TimeOutUs --;
Delay_US(1); //延时
}*pData = pHandle->I2Cx->RXDR; //读取收到的数据
return IIC_OK;
}
/*************************************************************************************************************************
-
函数 : IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
u8 *pDataBuff, u16 ReadByteNum) -
功能 : IIC读取寄存器(可以读取1个或者多个寄存器)
-
参数 : ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量; -
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-15
-
说明 : 读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据
可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
增加信号量
通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在
操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
*************************************************************************************************************************/
IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)
{
IIC_ERROR Error = IIC_OK;
u16 ReadCount;
IIC_HANDLE *pHandle;if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)
{
DEBUG(“IIC错误:无效的参数\r\n”);
return IIC_PARAMETER_ERROR;
}
pHandle = &sg_IIC_Handle[ch]; //获取相关通道的句柄if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙
{
IIC_SoftReset(pHandle);
DEBUG(“IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n”);
if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙
{
DEBUG(“IIC错误:总线忙,复位后未恢复\r\n”);
Error = IIC_BUSY;
goto end_loop;
}
}
IIC_ClearISR(pHandle, IIC_GetISR(pHandle)); //复位错误状态
IIC_ClearCR2(pHandle); //复位CR2寄存器
//主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);
if(Error != IIC_OK)
{
goto end_loop;
}
//发送后续数据
if(ReadByteNum > 255) //如果超过255字节,则需要分多次读取-后续还有数据,需要重载
{
ReadCount = 255; //本次需要读取的数据长度255
IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ); //传输相关配置-读取,并启动传输
}
else
{
ReadCount = ReadByteNum; //记录本次需要读取的数据长度-最后一次通讯后自动结束
IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ); //传输相关配置-读取,并启动传输
}//循环等待接收数据完成
do
{
//uart_printf(“读ISR=0x%X\r\n”, pHandle->I2Cx->ISR);
Error = IIC_WaitRxOneByte(pHandle, pDataBuff, pHandle->TimeOutUs); //接收1字节数据
if(Error != IIC_OK)
{
goto end_loop;
}pDataBuff ++; ReadCount --; ReadByteNum --; if((ReadByteNum > 0) && (ReadCount == 0)) //还有数据要读取 { if(ReadByteNum > 255) //如果超过255字节,则需要分多次读取 { ReadCount = 255; //本次需要读取的数据长度255-后续还有数据,需要重载 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ); //传输相关配置-读取,不启动传输 } else { ReadCount = ReadByteNum; //记录本次需要读取的数据长度-最后一次通讯,自动结束 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ); //传输相关配置-读取,不启动传输 } }
}while(ReadByteNum);
//读取完成了,等待STOP位有效
Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
if(Error != IIC_OK)
{
Error = IIC_STOP_ERROR;
goto end_loop;
}
IIC_ClearISR(pHandle, IIC_GetISR(pHandle)); //复位错误状态
end_loop:
IIC_ClearCR2(pHandle); //复位CR2寄存器
if(Error != IIC_OK)
{
IIC_SoftReset(pHandle); //IIC软复位,清除掉错误
DEBUG("[IIC R错误]:%d\r\n", Error);
}
if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
{
IIC_SendStop(pHandle); //总线忙,发送一个STOP,释放掉总线
DEBUG(“IIC R结束:总线忙 ISR=0x%X\r\n”, pHandle->I2Cx->ISR);
}
return Error;
}
/*************************************************************************************************************************
-
函数 : IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
u8 *pDataBuff, u16 WriteByteNum) -
功能 : IIC写寄存器(可以写1个或者多个寄存器)
-
参数 : ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量; -
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-16
-
最后修改时间 : 2020-02-16
-
说明 : 写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff
可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
增加信号量
通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在
操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
*************************************************************************************************************************/
IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)
{
IIC_ERROR Error = IIC_OK;
u16 ReadCount;
IIC_HANDLE *pHandle;if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)
{
DEBUG(“IIC错误:无效的参数\r\n”);
return IIC_PARAMETER_ERROR;
}
pHandle = &sg_IIC_Handle[ch]; //获取相关通道的句柄if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙
{
DEBUG(“IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n”);
IIC_SoftReset(pHandle);if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙 { DEBUG("IIC错误:总线忙,复位后未恢复\r\n"); Error = IIC_BUSY; goto end_loop; }
}
IIC_ClearISR(pHandle, IIC_GetISR(pHandle)); //复位错误状态
IIC_ClearCR2(pHandle); //复位CR2寄存器
//主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE, pHandle->TimeOutUs);
if(Error != IIC_OK)
{
goto end_loop;
}
//发送后续数据
if(WriteByteNum > 255) //如果超过255字节,则需要分多次写入-后续还有数据,需要重载
{
ReadCount = 255; //本次需要写入的数据长度255
IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE); //传输相关配置-不启动传输的写入
}
else
{
ReadCount = WriteByteNum; //记录本次需要写入的数据长度-最后一次通讯后自动结束
IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE); //传输相关配置-不启动传输的写入
}//循环发送数据
do
{
Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs); //发送一字节
if(Error != IIC_OK)
{
goto end_loop;
}ReadCount --; WriteByteNum --; pDataBuff ++; if((WriteByteNum > 0) && (ReadCount == 0)) //还有数据要读取 { if(WriteByteNum > 255) //如果超过255字节,则需要分多次读取 { ReadCount = 255; //本次需要写入的数据长度255-后续还有数据,需要重载 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE); //传输相关配置-不启动传输的写入 } else { ReadCount = WriteByteNum; //记录本次需要写入的数据长度-最后一次通讯,自动结束 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE); //传输相关配置-不启动传输的写入 } }
}while(WriteByteNum);
//写入完成了,等待STOP位有效
Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
if(Error != IIC_OK)
{
Error = IIC_STOP_ERROR;
goto end_loop;
}
IIC_ClearISR(pHandle, IIC_GetISR(pHandle)); //复位错误状态
end_loop:
IIC_ClearCR2(pHandle); //复位CR2寄存器
if(Error != IIC_OK)
{
IIC_SoftReset(pHandle); //IIC软复位,清除掉错误
DEBUG("[IIC W错误]:%d\r\n", Error);
}
if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY) //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
{
IIC_SendStop(pHandle); //总线忙,发送一个STOP,释放掉总线
DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);
}
return Error;
}
/*************************************************************************************************************************
- 函数 : void IIC_SoftReset(IIC_HANDLE *pHandle)
- 功能 : 硬件IIC软复位(会使能IIC)
- 参数 : ch:IIC通道
- 返回 : IIC_ERROR
- 依赖 : 底层宏定义
- 作者 : cp1300@139.com
- 时间 : 2020-02-15
- 最后修改时间 : 2020-02-15
- 说明 : IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。
*************************************************************************************************************************/
static void IIC_SoftReset(IIC_HANDLE *pHandle)
{
pHandle->I2Cx->CR1 &= ~BIT0; //关闭IIC后执行软复位
Delay_US(1);
if(pHandle->I2Cx->CR1 & BIT0)
{
DEBUG(“IIC软复位失败\r\n”);
}
pHandle->I2Cx->CR1 |= BIT0; //重新启动
Delay_US(1);
}
/*************************************************************************************************************************
-
函数 : static u32 IIC_CalculationTiming(u16 Speed_KHz)
-
功能 : 硬件IIC时序计算
-
参数 : ch:IIC通道;Speed_KHz:速度10-1000
-
返回 : IIC_ERROR
-
依赖 : 底层宏定义
-
作者 : cp1300@139.com
-
时间 : 2020-02-15
-
最后修改时间 : 2020-02-15
-
说明 : IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz
APB1时钟:最大不能超过45MHz
如果速度是100,则按照SMBUS时序
*************************************************************************************************************************/
static u32 IIC_CalculationTiming(u16 Speed_KHz)
{
u32 tTime = 0;
u32 temp;
u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000; //先获取APB1时钟速度
u32 Th = 1000/Speed_KHz/2; //计算高电平时间(低电平时间一样),单位nsif(time_temp < 20) time_temp = 20;
time_temp = 11000 / time_temp; //单位ns
uart_printf(“IIC时钟计算->APB1周期:%dns\t”, time_temp);
if(Speed_KHz == 100) //如果是100,则按照SMBUS时序
{
//主时钟分频系数固定为3
time_temp = 3; //主时钟周期
uart_printf(“IIC时钟周期:%dns\t”, time_temp);
tTime |= (3-1) << 28; //PRESC,时钟预分配
//计算数据建立时间,要求最小250ns
temp = 250 / time_temp;
if(temp > 15) temp = 15;
if(temp < 1) temp = 1;
tTime |= temp << 20;
//计算数据保持时间,要求至少300ns
temp = 300 / time_temp;
if(temp > 15) temp = 15;
if(temp < 1) temp = 1;
tTime |= temp << 16;
//计算高电平周期5us
temp = 51000 / time_temp;
if(temp > 255) temp = 255;
if(temp < 1) temp = 1;
tTime |= temp << 8;
//计算低电平周期5us
temp = 51000 / time_temp;
if(temp > 255) temp = 255;
if(temp < 1) temp = 1;
tTime |= temp << 0;
}
else if(Speed_KHz < 100)
{
//主时钟分频系数固定为6
time_temp = 6; //主时钟周期
uart_printf(“IIC时钟周期:%dns\t”, time_temp);
tTime |= (6-1) << 28; //PRESC,时钟预分配
//计算数据建立时间,要求最小250ns
temp = 250 / time_temp;
if(temp > 15) temp = 15;
tTime |= temp << 20;
//计算数据保持时间,要求至少300ns
temp = 300 / time_temp;
if(temp > 15) temp = 15;
tTime |= temp << 16;
//计算高电平周期Th us
temp = Th1000 / time_temp;
if(temp > 255) temp = 255;
if(temp < 1) temp = 1;
tTime |= temp << 8;
//计算低电平周期 Th us
temp = Th1000 / time_temp;
if(temp > 255) temp = 255;
if(temp < 1) temp = 1;
tTime |= temp << 0;
}
else //>100
{
//主时钟分频系数固定为2
time_temp = 2; //主时钟周期
uart_printf(“IIC时钟周期:%dns\t”, time_temp);
tTime |= (2-1) << 28; //PRESC,时钟预分配
//计算数据建立时间,随便给100ns
temp = 100 / time_temp;
if(temp > 15) temp = 15;
tTime |= temp << 20;
//计算数据保持时间,给100ns
temp = 100 / time_temp;
if(temp > 15) temp = 15;
tTime |= temp << 16;
//计算高电平周期Th us
temp = Th1000 / time_temp;
if(temp > 255) temp = 255;
if(temp < 1) temp = 1;
tTime |= temp << 8;
//计算低电平周期 Th us
temp = Th1000 / time_temp;
if(temp > 255) temp = 255;
if(temp < 1) temp = 1;
tTime |= temp << 0;
}uart_printf(“时序寄存器结果为:0x%X\r\n”, tTime);
return tTime;
}
/*************************************************************************************************************
- 文件名 : stm32f7_iic.h
- 功能 : STM32F7 IIC接口驱动
- 作者 : cp1300@139.com
- 创建时间 : 2020-02-09
- 最后修改时间 : 2020-02-09
- 详细:
*************************************************************************************************************/
#ifndef _STM32F7_IIC_H
#define _STM32F7_IIC_H
#include “system.h”
//IIC硬件接口选择
typedef enum
{
IIC_CH1 = 0, //IIC1
IIC_CH2 = 1, //IIC2
IIC_CH3 = 2, //IIC3
IIC_CH4 = 3, //IIC4
}IIC_CH_Type;
#define IIC_CH_COUNT 4 //4个IIC
//中断状态
#define IIC_FLAG_TXE BIT0 //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。
#define IIC_FLAG_TXIS BIT1 //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。
#define IIC_FLAG_RXNE BIT2 //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。
#define IIC_FLAG_ADDR BIT3 //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。
#define IIC_FLAG_NACKF BIT4 //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。
#define IIC_FLAG_STOPF BIT5 //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1
#define IIC_FLAG_TC BIT6 //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。
#define IIC_FLAG_TCR BIT7 //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。
#define IIC_FLAG_BERR BIT8 //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。
#define IIC_FLAG_ARLO BIT9 //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。
#define IIC_FLAG_OVR BIT10 //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。
#define IIC_FLAG_PECERR BIT11 //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。
#define IIC_FLAG_TIMEOUT BIT12 //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。
#define IIC_FLAG_ALERT BIT13 //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。
#define IIC_FLAG_BUSY BIT15 //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。
#define IIC_FLAG_DIR BIT16 //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读
//通讯错误状态
typedef enum
{
IIC_OK = 0, //没有错误
IIC_PARAMETER_ERROR = 1, //参数错误
IIC_TIMEOUT = 2, //超时错误,也可能是底层错误
IIC_HAL_ERROR = 3, //底层错误
IIC_STOP_ERROR = 4, //等待结束错误
IIC_BUSY = 5, //硬件忙
IIC_NACK = 6, //收到NACK了
}IIC_ERROR;
bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs); //硬件IIC初始化
IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum); //IIC读取寄存器(可以读取1个或者多个寄存器)
IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum); //IIC写寄存器(可以写1个或者多个寄存器)
#endif //_STM32F7_IIC_H
//初始化
IIC_Init(IIC_CH3, 200, 0); //硬件IIC初始化
//调用
//触摸屏IIC读取寄存器接口
bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
{
if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
{
return TRUE;
}
else
{
return FALSE;
}
}
//触摸屏IIC写寄存器接口
bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
{
if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
{
return TRUE;
}
else
{
return FALSE;
}
}
————————————————
版权声明:本文为CSDN博主「cp1300」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cp1300/article/details/104347417
来源:CSDN
作者:D19116092669
链接:https://blog.csdn.net/D19116092669/article/details/104360252