arduino_midi_player/Midi/music-box-nv32-master/nv32lib/drivers/iic/i2c.c
2025-03-24 14:30:56 +08:00

578 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*********************************************************************!
* 技术讨论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))
{
u32ETMeout ++;
}
if (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))
{
u32ETMeout ++;
}
if (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))
{
u32ETMeout ++;
}
if (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))
{
u32ETMeout ++;
}
if (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<u32Length;i++)
{
u8ErrorStatus = I2C_WriteOneByte(pI2Cx,pWrBuff[i]);
if( u8ErrorStatus != I2C_ERROR_NULL )
{
return u8ErrorStatus;
}
}
}
/*发送 I2C 停止位 */
u8ErrorStatus = I2C_Stop(pI2Cx);
return u8ErrorStatus;
}
/*****************************************************************************//*!
*
* @brief 读取多个字节并等待完成.
*
* @param[in] pI2Cx I2C的基址.
* @param[in] u16SlaveAddress 从机地址.
* @param[in] pRdBuff 用于接收数据的缓冲区.
* @param[in] u32Length 接收数据的字节数.
*
* @return 错误状态
*
*****************************************************************************/
uint8_t I2C_MasterReadWait(I2C_Type *pI2Cx,uint16_t u16SlaveAddress,uint8_t *pRdBuff,uint32_t u32Length)
{
uint32_t i;
uint8_t u8ErrorStatus;
/* 发送起始信号到总线 */
u8ErrorStatus = I2C_Start(pI2Cx);
/* 给从机发送器件地址 */
u8ErrorStatus = I2C_WriteOneByte(pI2Cx,((uint8_t)u16SlaveAddress<<1) | I2C_READ);
/* 如果没有错误发生, 则继续接收字节*/
I2C_ReadOneByte(pI2Cx,&pRdBuff[0],I2C_SEND_ACK);
if( u8ErrorStatus == I2C_ERROR_NULL )
{
for(i=0;i<u32Length-1;i++)
{
u8ErrorStatus = I2C_ReadOneByte(pI2Cx,&pRdBuff[i],I2C_SEND_ACK);
if( u8ErrorStatus != I2C_ERROR_NULL )
{
return u8ErrorStatus;
}
}
u8ErrorStatus = I2C_ReadOneByte(pI2Cx,&pRdBuff[i],I2C_SEND_NACK);
}
/*发送停止信号 */
u8ErrorStatus = I2C_Stop(pI2Cx);
return u8ErrorStatus;
}
/*****************************************************************************//*!
*
* @brief 设置I2C模块的中断回调函数
*
* @param[in] pfnCallback 回调函数的地址
*
* @return none
*
*****************************************************************************/
void I2C1_SetCallBack( I2C_CallbackType pCallBack )
{
I2C_Callback[1] = pCallBack;
}
/*****************************************************************************//*!
*
* @brief 设置RTC模块的中断回调函数
*
* @param[in] pfnCallback 回调函数的地址
*
* @return none
*
*****************************************************************************/
void I2C0_SetCallBack( I2C_CallbackType pCallBack )
{
I2C_Callback[0] = pCallBack;
}
/*! @} */
/*****************************************************************************//*!
*
* @brief I2C0 中断服务函数.
*
* @param
*
* @return none
*
*****************************************************************************/
void I2C0_Isr( void )
{
if( I2C_Callback[0] )
{
I2C_Callback[0]();
}
}
/*****************************************************************************//*!
*
* @brief I2C1 中断服务函数.
*
* @param
*
* @return none
*
*****************************************************************************/
void I2C1_Isr( void )
{
if( I2C_Callback[1] )
{
I2C_Callback[1]();
}
}