📄 i2c.c
字号:
#include "config.h"
#define I2c_Num (*((volatile uint16 *) (Psram_BaseAddr+0x100)))
#define I2c_Addr (*((volatile uint8 *) (Psram_BaseAddr+0x102)))
#define I2C_end (*((volatile uint8 *) (Psram_BaseAddr+0x103))) //操作结束标志
volatile uint8 *I2c_Buf;
I2C_Param *I2C_Pa;
#define I2C_WRITE_END 1 /* 写完成 */
#define I2C_READ_END 2 /* 读完成 */
#define I2C_NOT_GET_BUS 4 /* 丢失仲裁 */
#define I2C_ACK_ERR 8 /* 接收ACK错误 */
/*********************************************************************************************************
** 函数名称: I2cInit
** 功能描述: 初始化I2c(主模式)
** 输 入: FI2c:I2c总线频率,最大值为400K
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
void I2CInit(uint32 FI2c)
{
VICIntEnClr = 1 << 9; // 禁止能I2c中断
if (FI2c > 400000) FI2c = 400000;
PINSEL0 = (PINSEL0 & 0xfffffc0f) | 0x50; // 选择管脚为I2c
IO0DIR |= EEPROM_WP; // P0相关输出引脚初始化
IO0SET = EEPROM_WP; // 写保护有效,引脚输出高电平
I2CONCLR = 0x6C; // 清除控制寄存器
I2SCLH = (Fpclk / FI2c + 1) / 2; // 设置高电平时间
I2SCLL = (Fpclk / FI2c) / 2; // 设置低电平时间
/* 设置I2C中断允许 */
VICIntSelect = 0x00000000; // 设置所有通道为IRQ中断
VICVectCntl0 = 0x29; // I2C通道分配到IRQ slot 0,即优先级最高
VICVectAddr0 = (int)IRQ_I2C; // 设置I2C中断向量地址
}
/*********************************************************************************************************
** 函数名称: __I2cWrite
** 功能描述: 读I2C,但不发送STOP信号
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
void __I2cWrite(void)
{
I2c_Addr = I2C_Pa->Addr & 0xfe; // 存储地址写
I2c_Num = I2C_Pa->WrLen; // 存储写字节数
I2c_Buf = I2C_Pa->RTBuf; // 存储写的数据的指针
I2C_end=0;
I2CONSET = 0x24; // 设置为主机,并启动总线
while(I2C_end==0);
}
/*********************************************************************************************************
** 函数名称: I2cWrite
** 功能描述: 向I2C从器件写数据
** 输 出:发送的数据字节数
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
uint16 I2cWrite(void)
{
I2C_Pa=(I2C_Param *)I2C_Param_Addr;
I2CONCLR = 0x6C; // 清除控制寄存器I2EN,STA,SI,AA
I2CONSET = 0x40; // 使能I2c,I2EN=1
VICIntEnable = 1 << 9; // 使能I2c中断
__I2cWrite();
if ( I2C_end == I2C_WRITE_END)
{
I2CONSET = 1 << 4; // 发送停止信号
I2CONCLR = 0x28; // 清除标志
}
VICIntEnClr = 1 << 9; /// 禁止能I2c中断
return (I2C_Pa->WrLen - I2c_Num);
}
/*********************************************************************************************************
** 函数名称: I2cRead
** 功能描述: 从I2c从器件读数据
** 输 出:已读取的字节数
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
int16 I2cRead(void)
{
I2C_Pa=(I2C_Param *)I2C_Param_Addr;
I2CONCLR = 0x6C; // 清除控制寄存器
I2CONSET = 0x40; // 使能I2c
VICIntEnable = 1 << 9; // 使能I2c中断
if (I2C_Pa->WrLen > 0)
{
__I2cWrite();
if ( I2C_end != I2C_WRITE_END)
{
return -1;
}
}
I2c_Addr = I2C_Pa->Addr | 0x01; // 存储地址读
I2c_Num = I2C_Pa->RdLen; // 存储读字节数
I2c_Buf = I2C_Pa->RTBuf; // 存储读到的数据
I2CONCLR = 0x28;
I2C_end=0;
I2CONSET = 0x24; // 设置为主机,并启动总线
VICIntEnable = 1 << 9; // 使能I2c中断
while(I2C_end==0);
VICIntEnClr = 1 << 9; // 禁止能I2c中断
return (I2C_Pa->RdLen - I2c_Num);
}
/*********************************************************************************************************
** 函数名称: IRQ_I2C_Exception
** 功能描述: I2c中断服务程序
** 输 入: 无
**
** 输 出: 无
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
void __irq IRQ_I2C(void)
{
switch(I2STAT & 0xf8)
{
case 0x08: // 已发送起始条件,与0x18相同处理
case 0x10: // 已发送重复起始条件
I2DAT = I2c_Addr; // 发送地址
I2CONCLR = 0x28; // 清除标志
break;
case 0x18: // 已发送SLA+W,并已接收应答
I2DAT = *I2c_Buf++;
I2c_Num--;
I2CONCLR = 0x28; // 清除标志
break;
case 0x28: // 已发送I2C数据,并接收到应答
if (I2c_Num > 0)
{
I2DAT = *I2c_Buf++;
I2c_Num--;
I2CONCLR = 0x28; // 清除标志
}
else
{
I2C_end=I2C_WRITE_END;
VICIntEnClr = 1 << 9; // 禁止能I2c中断 */
}
break;
case 0x20: // 已发送SLA+W;已接收非ACK, 与0x48处理相同
case 0x30: // 已发送I2DAT中的数据字节;已接收非ACK, 与0x48处理相同
case 0x48: // 已发送SLA+R;已接收非ACK
I2CONSET = 1 << 4; // 发送停止信号
I2C_end=I2C_ACK_ERR;
I2CONCLR = 0x28; // 清除标志
break;
case 0x38: // 在SLA+R/W或数据字节中丢失仲裁
I2C_end=I2C_NOT_GET_BUS;
I2CONCLR = 0x28; // 清除标志 */
break;
case 0x40: // 已发送SLA+R;已接收ACK
if (I2c_Num <= 1)
{
I2CONCLR = 1 << 2; // AA=0,下次发送非应答信号
}
else
{
I2CONSET= 1 << 2; // AA=1,下次发送应答信号
}
I2CONCLR = 0x28; // 清除标志
break;
case 0x50: // 已接收数据字节;已发送ACK
*I2c_Buf++ = I2DAT; // 接收数据
I2c_Num--;
if (I2c_Num <= 1)
{
I2CONCLR = 1 << 2; // 下次发送非应答信号
}
I2CONCLR = 0x28; // 清除标志
break;
case 0x58: // 已接收数据字节;已返发送ACK
*I2c_Buf = I2DAT; // 接收数据
I2c_Num--;
I2CONSET= 1 << 4; // 结束总线
I2C_end=I2C_READ_END;
I2CONCLR = 0x28; // 清除标志
break;
default:
I2CONSET = 1 << 4; // 发送停止信号
I2C_end=0x10; // 非法状态
I2CONCLR = 0x28; // 清除标志
break;
}
VICVectAddr = 0; // 通知中断控制器中断结束
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -