/*********************************************************************! * 技术讨论:QQ群 123763203 * 官网 :www.navota.com * * @file i2c.c * @brief i2c通讯接口函数库 * @author Navota * @date 2017-1-1 ************************************************************************/ #include "common.h" #include "i2c.h" /*! * @brief 存放回调入口 * */ static I2C_CallbackType I2C_Callback[2] = {(I2C_CallbackType)NULL}; void I2C0_Isr( void ); /****************************************************************************** * 定义I2C的接口函数 *******************************************************************************/ /*****************************************************************************//*! * * @brief 初始化I2C模块. * * @param[in] pI2Cx I2C的基址. * @param[in] pI2CConfig 配置I2C的结构体. * * @return none * *****************************************************************************/ void I2C_Init(I2C_Type *pI2Cx,I2C_ConfigPtr pI2CConfig) { uint8_t u8Temp; #if defined(CPU_NV32) SIM->SCGC |= SIM_SCGC_IIC_MASK; #endif I2C_SetBaudRate(pI2Cx,pI2CConfig->u16F); I2C_SetSlaveAddress(pI2Cx,pI2CConfig->u16OwnA1); pI2Cx->FLT = (uint8_t)pI2CConfig->u16Filt; pI2Cx->RA = (uint8_t)pI2CConfig->u16RangeA & 0xfe; I2C_SetSCLLowETMeout(pI2Cx,pI2CConfig->u16Slt); /* 配置控制寄存器C2 */ u8Temp = 0; if( pI2CConfig->sSetting.bGCAEn ) { u8Temp |= I2C_C2_GCAEN_MASK; } if( pI2CConfig->sSetting.bAddressExt ) { u8Temp |= I2C_C2_ADEXT_MASK; } if( pI2CConfig->sSetting.bRangeAddEn ) { u8Temp |= I2C_C2_RMEN_MASK; } pI2Cx->C2 |= u8Temp; /* 配置寄存器SMB */ u8Temp = 0; if( pI2CConfig->sSetting.bFackEn ) { u8Temp |= I2C_SMB_FACK_MASK; } if( pI2CConfig->sSetting.bSMB_AlertEn ) { u8Temp |= I2C_SMB_ALERTEN_MASK; } if( pI2CConfig->sSetting.bSecondAddressEn ) { u8Temp |= I2C_SMB_SIICAEN_MASK; } if( pI2CConfig->sSetting.bSHTF2IntEn ) { u8Temp |= I2C_SMB_SHTF2IE_MASK; } pI2Cx->SMB = u8Temp; /* 配置寄存器C1 */ u8Temp = 0; if( pI2CConfig->sSetting.bIntEn ) { u8Temp |= I2C_C1_IICIE_MASK; if(pI2Cx == I2C0) { NVIC_EnableIRQ(I2C0_IRQn); } else { // } } if( pI2CConfig->sSetting.bWakeUpEn ) { u8Temp |= I2C_C1_WUEN_MASK; } if( pI2CConfig->sSetting.bI2CEn ) { u8Temp |= I2C_C1_IICEN_MASK; } pI2Cx->C1 = u8Temp; } /*****************************************************************************//*! * * @brief 发送I2C起始信号(启动传输). * * @param[in] pI2Cx I2C的基址. * * @return 错误状态 * *****************************************************************************/ uint8_t I2C_Start(I2C_Type *pI2Cx) { uint32_t u32ETMeout; uint8_t u8ErrorStatus; u32ETMeout = 0; u8ErrorStatus = 0x00; I2C_TxEnable(pI2Cx);//将 I2C 配置成 TX 发送模式 pI2Cx->C1 |= I2C_C1_MST_MASK;//将 I2C 配置成主机模式 //持续监测起始位有没有发送成功 while( (!I2C_IsBusy(pI2Cx)) && ( u32ETMeout < I2C_WAIT_STATUS_ETMEOUT)) { u32ETMeout ++; } if( u32ETMeout == I2C_WAIT_STATUS_ETMEOUT ) { u8ErrorStatus |= I2C_ERROR_START_NO_BUSY_FLAG; } return u8ErrorStatus;//返回错误标志,为0x10即起始信号没有发送成功 } /*****************************************************************************//*! * * @brief 发送停止信号. * * @param[in] pI2Cx I2C的基址. * * @return 错误状态 * *****************************************************************************/ uint8_t I2C_Stop(I2C_Type *pI2Cx) { uint32_t u32ETMeout; uint8_t u8ErrorStatus; u32ETMeout = 0; u8ErrorStatus = 0x00; pI2Cx->C1 &= ~I2C_C1_MST_MASK; //持续监测 I2C 停止位是否发送成功 while( (I2C_IsBusy(pI2Cx) ) && ( u32ETMeout < I2C_WAIT_STATUS_ETMEOUT)) { u32ETMeout ++; } if( u32ETMeout == I2C_WAIT_STATUS_ETMEOUT ) { u8ErrorStatus |= I2C_ERROR_STOP_BUSY_FLAG; } return u8ErrorStatus; } /*****************************************************************************//*! * * @brief 发送重复起始位. * * @param[in] pI2Cx I2C的基址. * * @return 错误状态. * *****************************************************************************/ uint8_t I2C_RepeatStart(I2C_Type *pI2Cx) { uint32_t u32ETMeout; uint8_t u8ErrorStatus; u32ETMeout = 0; u8ErrorStatus = 0x00; pI2Cx->C1 |= I2C_C1_RSTA_MASK; //持续监测起始位是否发送成功 while( (!I2C_IsBusy(I2C0) ) && ( u32ETMeout < I2C_WAIT_STATUS_ETMEOUT)) { u32ETMeout ++; } if( u32ETMeout == I2C_WAIT_STATUS_ETMEOUT ) { u8ErrorStatus |= I2C_ERROR_START_NO_BUSY_FLAG; } return u8ErrorStatus; } /*****************************************************************************//*! * * @brief 设置从机地址. * * @param[in] pI2Cx I2C的基址. * @param[in] u16SlaveAddress 从机地址. * * @return none * *****************************************************************************/ void I2C_SetSlaveAddress(I2C_Type *pI2Cx,uint16_t u16SlaveAddress) { /* 写入8位地址 */ pI2Cx->A1 = (uint8_t)u16SlaveAddress; /* 如果支持十位从机地址, 写入高三位地址 */ pI2Cx->C2 &= ~I2C_C2_AD_MASK; pI2Cx->C2 |= (uint8_t)(u16SlaveAddress>>8)&0x03; } /*****************************************************************************//*! * * @brief 禁用I2C中断. * * @param[in] pI2Cx I2C的基址. * * @return none. * *****************************************************************************/ void I2C_IntDisable(I2C_Type *pI2Cx) { pI2Cx->C1 &= ~I2C_C1_IICIE_MASK; if(pI2Cx == I2C0) { NVIC_DisableIRQ(I2C0_IRQn); } else { } } /*****************************************************************************//*! * * @brief 使能I2C中断. * * @param[in] pI2Cx I2C的基址. * * @return none. * *****************************************************************************/ void I2C_IntEnable(I2C_Type *pI2Cx) { pI2Cx->C1 |= I2C_C1_IICIE_MASK; if(pI2Cx == I2C0) { NVIC_EnableIRQ(I2C0_IRQn); } else { } } /*****************************************************************************//*! * * @brief 设置SCL低超时周期. * * @param[in] pI2Cx I2C的基址. * * @return none. * *****************************************************************************/ void I2C_SetSCLLowETMeout(I2C_Type *pI2Cx, uint16_t u16ETMeout) { pI2Cx->SLTL = (uint8_t)u16ETMeout; pI2Cx->SLTH = (uint8_t)(u16ETMeout>>8); } /*****************************************************************************//*! * * @brief 复位I2C模块. * * @param[in] pI2Cx I2C的基址. * * @return none * *****************************************************************************/ void I2C_Deinit(I2C_Type *pI2Cx) { pI2Cx->C1 &= ~I2C_C1_IICEN_MASK; #if defined(CPU_NV32) SIM->SCGC &= ~SIM_SCGC_IIC_MASK; #endif } /*****************************************************************************//*! * * @brief 发送单字节数据. * * @param[in] pI2Cx I2C模块的基址. * @param[in] u8WrBuff 要写的数据缓冲区. * * @return 错误状态 * *****************************************************************************/ uint8_t I2C_WriteOneByte(I2C_Type *pI2Cx, uint8_t u8WrBuff) { uint32_t u32ETMeout; uint8_t u8ErrorStatus; u32ETMeout = 0; u8ErrorStatus = 0x00; while (((I2C_GetStatus(pI2Cx)&I2C_S_TCF_MASK) != I2C_S_TCF_MASK) && (u32ETMeout= I2C_WAIT_STATUS_ETMEOUT) { u8ErrorStatus |= I2C_ERROR_NO_WAIT_TCF_FLAG; return u8ErrorStatus; } I2C_TxEnable(pI2Cx); //将 I2C 配置成 TX 输出模式 I2C_WriteDataReg(pI2Cx,u8WrBuff); //写数据寄存器发送数据 u32ETMeout = 0; while (((I2C_GetStatus(pI2Cx)&I2C_S_IICIF_MASK) != I2C_S_IICIF_MASK) && (u32ETMeout= I2C_WAIT_STATUS_ETMEOUT) { u8ErrorStatus |= I2C_ERROR_NO_WAIT_IICIF_FLAG; return u8ErrorStatus; } /* 清除中断标志位 */ I2C_ClearStatus(pI2Cx,I2C_S_IICIF_MASK); if (I2C_GetStatus(pI2Cx) & I2C_S_RXAK_MASK) { u8ErrorStatus |= I2C_ERROR_NO_GET_ACK; } return u8ErrorStatus; } /*****************************************************************************//*! * * @brief 读取单字节数据. * * @param[in] pI2Cx I2C的基址. * @param[out] pRdBuff 所要从从机读的地址. * @param[out] u8Ack 发送 ack or nack. * * @return 错误状态 * *****************************************************************************/ uint8_t I2C_ReadOneByte(I2C_Type *pI2Cx, uint8_t *pRdBuff, uint8_t u8Ack) { uint32_t u32ETMeout; uint8_t u8ErrorStatus; u32ETMeout = 0; u8ErrorStatus = 0x00; while (((I2C_GetStatus(pI2Cx)&I2C_S_TCF_MASK) != I2C_S_TCF_MASK) && (u32ETMeout= I2C_WAIT_STATUS_ETMEOUT) { u8ErrorStatus |= I2C_ERROR_NO_WAIT_TCF_FLAG; return u8ErrorStatus; } I2C_RxEnable(pI2Cx); //将 I2C 配置为输入模式 if( u8Ack ) { /* 发送 nack */ I2C_SendNack(pI2Cx); } else { /* 发送 ack */ I2C_SendAck(pI2Cx); } *pRdBuff = I2C_ReadDataReg(pI2Cx); //将读到的数据存放到参数里头 u32ETMeout = 0; //持续监测中断标志 while (((I2C_GetStatus(pI2Cx)&I2C_S_IICIF_MASK) != I2C_S_IICIF_MASK) && (u32ETMeout= I2C_WAIT_STATUS_ETMEOUT) { u8ErrorStatus |= I2C_ERROR_NO_WAIT_IICIF_FLAG; return u8ErrorStatus; } /*清除 IIC 中断标志位 */ I2C_ClearStatus(pI2Cx,I2C_S_IICIF_MASK); return u8ErrorStatus; } /*****************************************************************************//*! * * @brief 发送数据到I2C,然后等待数据传送完成. * * @param[in] pI2Cx I2C的基址. * @param[in] u16SlaveAddress 16位从机地址. * @param[in] pWrBuff 需要发送数据的缓冲数组. * @param[in] u32Length 发送字节的数目. * * @return 错误状态 * *****************************************************************************/ uint8_t I2C_MasterSendWait(I2C_Type *pI2Cx,uint16_t u16SlaveAddress,uint8_t *pWrBuff,uint32_t u32Length) { uint32_t i; uint8_t u8ErrorStatus; /* 发送起始信号 */ u8ErrorStatus = I2C_Start(pI2Cx); /* 给从机发送从机地址 */ u8ErrorStatus = I2C_WriteOneByte(pI2Cx,((uint8_t)u16SlaveAddress<<1) | I2C_WRITE); /* 如果没有错误发生, 则继续发送字节*/ if( u8ErrorStatus == I2C_ERROR_NULL ) { for(i=0;i