📄 i2c.cpp
字号:
}else
{
OnEndOfCurOperation_InIsr();
}
}else
{
StopOnError(IE_INALID_WRITE_MODE, true);
}
break;
//-----------------------------------------------------------------------
//准备读取第一个字节时进入这个入口,读取下一个字节
//-----------------------------------------------------------------------
case 0x40: //已发送SLA+R,已接收ACK
DP_ISR(putchar('A'));
can_restart = false;
ReadNextByte(); //如果仅仅读取一个字节,那么就不要读取ACK
break;
//-----------------------------------------------------------------------
//读完一个字节后进入这个入口,读取下一个字节
//-----------------------------------------------------------------------
case 0x50: //已接收数据字节,已返回ACK
case 0x58: //已接收数据字节,已返回非应答
can_restart = false;
if(cur_op->mode & I2C_READ)
{
if(! continue_state)
{
DP_ISR(putchar('r'));
if(buf_pos < cur_op->buf_size)
cur_op->buf_ptr[buf_pos++] = I2C0DAT;
}
if(buf_pos >= cur_op->buf_size)
{
OnEndOfCurOperation_InIsr();
}else
{
ReadNextByte(); //如果仅仅读取一个字节,那么就不要读取ACK
}
}else
{
StopOnError(IE_INALID_READ_MODE, true);
}
break;
//-----------------------------------------------------------------------
//不期望的状态值
//-----------------------------------------------------------------------
case 0x00: //
case 0xf8: //无可用信息
case 0x20: //已发送SLA+W,已接收非应答
case 0x30: //已发送I2C1DAT中的数据,已接收非应答
case 0x38: //在SLA+R/W或数据字节中丢失仲裁
case 0x48: //已发送SLA+R,已接收非应答
if(can_restart)
{
DP_ISR(putchar('x'));
ClearFlag(IC_SI);
SetFlag(IC_STOP); //先发送停止条件
SetFlag(IC_SI);
buf_pos = -1; //重新开始发送起始条件
}else
StopOnError(IE_DEVICE_ERROR, true);
can_restart = false;
break;
default:
StopOnError(IE_UNKOWN_ISR_STATE, true);
break;
}
final:
VICVectAddr = 0x00; //中断处理结束
}
//#undef putchar
bool CI2COperation::Init()
{
bool i2c_ok = true;
if(etEndOfOperations == NULL)
etEndOfOperations = CreateEvent(NULL, false , false, NULL);
I2C0SCLH = (Fpclk/FI2C0 + 1) / 2; //I2c速率 400K
I2C0SCLL = (Fpclk/FI2C0 + 1) / 2;
ClearFlag(IC_EN); //先禁止,再使能,使得内部状态复位
ClearFlag(IC_AA | IC_SI | IC_STOP | IC_START);
SetFlag(IC_EN); //再次使能,内部状态机可以被复位
//总线初始化,防止有些设备不正确。先发送起始条件,读空设备,最后发送停止条件
//这是由于总线不支持更好的方式
EnableIsr(ISN_I2C0, false); //禁止中断。如果上次正常结束,则中断自动禁止
//发送起始条件
SetFlag(IC_START);
ClearFlag(IC_SI);
Sleep(2); //等待,而不是检查flag,因为如果总线状态异常则不能被得到中断
if(CheckFlag(IC_SI) == 0)
i2c_ok = false;
//读一个空设备
I2C0DAT = 0XFF; //Device addr:0xfe, read
ClearFlag(IC_START | IC_SI);
Sleep(2);
if(CheckFlag(IC_SI) == 0)
i2c_ok = false;
//发送停止条件
SetFlag(IC_EN | IC_STOP);
ClearFlag(IC_START | IC_SI);
//不要再等待 IC_SI, 因为发送停止条件后不会再触发中断的
can_continue_read = can_continue_write = false;
SetIrq((unsigned long)CI2COperation::I2CIRQSericeEntry, ISN_I2C0, ISR_I2C0_ORDER, false);
if(! i2c_ok)
{
DP_ERR(printk("`9I2C: Init fail\n`0"));
}
return i2c_ok;
}
bool CI2COperation::GetNextOperation()
{
if(op_pos < op_count)
{
cur_op = operations + op_pos;
op_pos ++;
buf_pos = -1;
can_restart = false;
send_start_stop_retry_count = 0;
return true;
}
return false;
}
bool CI2COperation::AddOperation(uint8 mode, uint8 slave_adder, uint8 *buf, int len)
{
if(is_executed)
{
op_count = 0;
is_executed = false;
}
if(op_count < MAX_I2C_OPERATION_COUNT)
{
if((mode & I2C_READ) && (mode & I2C_WRITE))
{
DP_ERR(printk("`9I2C:invalid mode!\n`0"));
return false;
}
operations[op_count].mode = mode;
operations[op_count].slave_addr = slave_adder;
operations[op_count].buf_ptr = buf;
operations[op_count].buf_size = len;
op_count++;
return true;
}else
{
DP_ERR(printk("`9I2C:operation full!\n`0"));
}
return false;
}
bool CI2COperation::AddOp_StartRead(uint8 slave_addr, __packed uint8 *buf, int len, bool append_stop)
{
can_continue_read = ! append_stop;
can_continue_write = false;
return AddOperation(I2C_START | I2C_READ | (append_stop?I2C_APPEND_STOP : 0),
slave_addr,
buf,
len);
}
bool CI2COperation::AddOp_StartWrite(uint8 slave_addr, __packed uint8 *buf, int len, bool append_stop)
{
can_continue_read = false;
can_continue_write = ! append_stop;
return AddOperation(I2C_START | I2C_WRITE | (append_stop?I2C_APPEND_STOP : 0),
slave_addr,
buf,
len);
}
bool CI2COperation::AddOp_ContinueRead(__packed uint8 *buf, int len, bool append_stop)
{
if(! can_continue_read)
{
DP_ERR(printk("`9I2C:START required!\n`0"));
return false;
}
return AddOperation(I2C_READ | (append_stop?I2C_APPEND_STOP : 0),
0,
buf,
len);
}
bool CI2COperation::AddOp_ContinueWrite(__packed uint8 *buf, int len, bool append_stop)
{
if(! can_continue_write)
{
DP_ERR(printk("`9I2C:START required!\n`0"));
return false;
}
return AddOperation(I2C_WRITE | (append_stop?I2C_APPEND_STOP : 0),
0,
buf,
len);
}
bool CI2COperation::AddOp_Stop()
{
return AddOperation(I2C_STOP, 0, NULL, 0);
}
//返回错误代码
TI2CErrorCode CI2COperation::Execute(uint32 time_out_in_ms, bool block)
{
// printk("I2C:Begin ");
EnableIsr(ISN_I2C0, false); //禁止中断。如果上次正常结束,则中断自动禁止
is_executed = true; //再次调用ADD时将重新开始添加
op_pos = 0; //确保 GetNextOperation 函数从第一个操作开始取
start_time = GetTickCount();
error_code = IE_OK;
if(GetNextOperation())
{
ResetEvent(etEndOfOperations);
//ClearFlag(IC_AA | IC_STOP | IC_START | IC_SI);
SetFlag(IC_EN | IC_SI); //设置中断标志
EnableIsr(ISN_I2C0, true); //使能中断
if(block)
{
if(WaitForSingleObject(etEndOfOperations, time_out_in_ms) != WAIT_OBJECT_0)
StopOnError(IE_TIME_OUT, false);
//SetSysLed(0);
}else
return IE_IN_PROGRESS;
}
if(error_code && (dbg_code & 0x80000000) == 0) //keil 仿真状态,不要打印错误信息
{
// "这里仿真不正常,看看实际运行。要把EEPROM去掉"
DP_ERR(printk("\n`9I2C:ErrCode = %d\n`0",error_code));
//DP_ERR(printk("123abcdefghijklmnop4\n"));
}
// printk("I2C end, %d\n",error_code);
if(error_code == IE_CANNOT_SEND_START_STOP)
Init();
return error_code;
}
TI2CErrorCode CI2COperation::GetResult(uint32 time_out_in_ms, bool block)
{
int time_left = time_out_in_ms - ( GetTickCount() - start_time);
if(block )
{
if(time_left < 0 || WaitForSingleObject(etEndOfOperations, time_out_in_ms) != WAIT_OBJECT_0)
StopOnError(IE_TIME_OUT,false);
goto final;
}else if(time_left < 0)
{
StopOnError(IE_TIME_OUT,false);
goto final;
}else
return IE_IN_PROGRESS;
final:
if(error_code == IE_CANNOT_SEND_START_STOP) //总线紊乱,自动初始化
Init();
return error_code;
}
class CAbsI2CBus *GetI2CBus()
{
static class CI2COperation i2c_bus;
return &i2c_bus;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -