你好,
我试着用i2c从加速计读取30个字节。大多数情况下它是有效的,但有时,主程序(DA14580)会发出一个STOP,把随后的数据弄乱。我在用i2c eeprom模块的代码来进行脉冲读取。
有什么明显的东西需要我注意吗?
谢谢,马可
嗨marcodg,
你的描述很通用,所以你能否提供更多的信息,为什么你的代码意外停止工作,以便指导你?您是否尝试在调试模式下运行代码并热连接调试器?你能解释一下你的代码是在哪里崩溃的吗?是NMI处理器还是WDOG攻击了?或者你的代码在你试图从加速计读取字节时在其他地方崩溃了?
谢谢,PM_Dialog
问题似乎在于读取数据的原子性。在i2c_eeprom.c中,我看到如下内容
//------------------------------------------------------------------------------------------/ /关键部分GLOBAL_INT_DISABLE ();//获取接收到的数据For (j = 0;j <大小;j + +){WAIT_FOR_RECEIVED_BYTE ();//等待收到的数据**p =(0xFF & GetWord16(I2C_DATA_CMD_REG));//获取接收的字节(* p) + +;}//临界区结束GLOBAL_INT_RESTORE ();//------------------------------------------------------------------------------------------
我有读取加速度计的代码。问题是,我必须将地址和所有读命令的写入放入同一个临界区,才能让它工作。是这样的:
//------------------------------------------------------------------------------------------/ /关键部分GLOBAL_INT_DISABLE ();i2c_send_address(地址);For (j = 0;j <大小;j + +){WAIT_WHILE_I2C_FIFO_IS_FULL ();//如果Tx FIFO已满,则等待SEND_I2C_COMMAND (0 x0100);//设置读访问次数}//获取接收到的数据For (j = 0;j <大小;j + +){WAIT_FOR_RECEIVED_BYTE ();//等待收到的数据**p =(0xFF & GetWord16(I2C_DATA_CMD_REG));//获取接收的字节(* p) + +;}//临界区结束GLOBAL_INT_RESTORE ();//------------------------------------------------------------------------------------------
我不确定为什么关键部分是必要的,因为似乎一旦i2c状态机运行,它就会自己运行,而不受程序的干预。但是,很明显,如果我不这样做,就会偶尔产生一个错误的STOP,弄乱数据传输。也许这只是我们使用的加速度计(MMA845IQ)的问题。拥有如此大的临界区还会导致其他问题。
当数据的实际接收发生时,我们禁用/恢复中断。这是一种保护的类型,以确保没有中断将发生时,你把数据放入FIFO。请注意,当FIFO为空且没有其他数据时,您将获得一个STOP。因此,如果你不保护这个接收过程和中断是造成的,你将停止把数据放入FIFO, FIFO将是空的,你将得到一个停止。关键部分是当你把数据放入FIFO,而不是当FIFO推入数据。因此,在接收数据时,请不要删除禁用/恢复中断。
嗨marcodg,
你的描述很通用,所以你能否提供更多的信息,为什么你的代码意外停止工作,以便指导你?您是否尝试在调试模式下运行代码并热连接调试器?你能解释一下你的代码是在哪里崩溃的吗?是NMI处理器还是WDOG攻击了?或者你的代码在你试图从加速计读取字节时在其他地方崩溃了?
谢谢,PM_Dialog
问题似乎在于读取数据的原子性。在i2c_eeprom.c中,我看到如下内容
//------------------------------------------------------------------------------------------
/ /关键部分
GLOBAL_INT_DISABLE ();
//获取接收到的数据
For (j = 0;j <大小;j + +)
{
WAIT_FOR_RECEIVED_BYTE ();//等待收到的数据
**p =(0xFF & GetWord16(I2C_DATA_CMD_REG));//获取接收的字节
(* p) + +;
}
//临界区结束
GLOBAL_INT_RESTORE ();
//------------------------------------------------------------------------------------------
我有读取加速度计的代码。问题是,我必须将地址和所有读命令的写入放入同一个临界区,才能让它工作。是这样的:
//------------------------------------------------------------------------------------------
/ /关键部分
GLOBAL_INT_DISABLE ();
i2c_send_address(地址);
For (j = 0;j <大小;j + +)
{
WAIT_WHILE_I2C_FIFO_IS_FULL ();//如果Tx FIFO已满,则等待
SEND_I2C_COMMAND (0 x0100);//设置读访问次数
}
//获取接收到的数据
For (j = 0;j <大小;j + +)
{
WAIT_FOR_RECEIVED_BYTE ();//等待收到的数据
**p =(0xFF & GetWord16(I2C_DATA_CMD_REG));//获取接收的字节
(* p) + +;
}
//临界区结束
GLOBAL_INT_RESTORE ();
//------------------------------------------------------------------------------------------
我不确定为什么关键部分是必要的,因为似乎一旦i2c状态机运行,它就会自己运行,而不受程序的干预。但是,很明显,如果我不这样做,就会偶尔产生一个错误的STOP,弄乱数据传输。也许这只是我们使用的加速度计(MMA845IQ)的问题。拥有如此大的临界区还会导致其他问题。
嗨marcodg,
当数据的实际接收发生时,我们禁用/恢复中断。这是一种保护的类型,以确保没有中断将发生时,你把数据放入FIFO。请注意,当FIFO为空且没有其他数据时,您将获得一个STOP。因此,如果你不保护这个接收过程和中断是造成的,你将停止把数据放入FIFO, FIFO将是空的,你将得到一个停止。关键部分是当你把数据放入FIFO,而不是当FIFO推入数据。因此,在接收数据时,请不要删除禁用/恢复中断。
谢谢,PM_Dialog