中级会员
 
- 积分
- 423
- 金钱
- 423
- 注册时间
- 2017-4-1
- 在线时间
- 73 小时
|
本帖最后由 bucker 于 2021-1-9 18:17 编辑
最近琢磨这学点I2C编程,体验了几种方法。HAL方式在主模式下使用比较方便,但在从模式下却显得有些不足,主要是它的发送或接收只能定长度,而按照I2C的要求作为从机应该是读写长度由主机控制。由于是初学,拿着网上的顺序读代码做了实验,从24C02读4个字节总耗时约为655uS,而自己改编为中断服务方式之后,总的读写过程居然耗时740uS。根据调试发现主要是在第一次发送寄存器地址后,出现EV8_2事件中断,在相应次中断发送起始信号之后,EV8_2的事件总是重复发生,大约延迟月90uS。按照参考手册介绍,EV8_2信号应该在出现起始、停止或PE=0时会被清除,而实际上这个事件保持了近一个收发字节的时间才消除。不知各位大侠是如何处理这个问题的,望各位不灵赐教 。
中断服务程序比较简单,就是按照参考手册的信号链条加以处理
void I2C1_EV_IRQHandler (void)
{
uint16_t sr1 = I2C1->SR1;
uint16_t sr2 = I2C1->SR2;
uint32_t sr = (sr2 << 16) | sr1;
static uint8_t* p;
if (__TestSR (sr, EV5)) // EV5事件
{
if (!I2Cx.eCnt) I2C1->DR = I2Cx.devAddr & 0xFE;
else I2C1->DR = I2Cx.devAddr | 0x01;
}
else if (__TestSR (sr, EV6t)) I2C1->DR = I2Cx.regAddr; // EV6t事件,发送写地址时产生的事件
else if (__TestSR (sr, EV6r)) p = I2Cx.buff; // EV6r事件,发送读地址时产生的事件
else if (__TestSR (sr, EV8)) I2C1->CR1 |= I2C_CR1_START; // EV8事件,问题主要出在这里,就是这个事件总是在主机发出起始信号之后未被清除
else if (__TestSR (sr, EV7)) // EV7事件
{
if (I2Cx.len)
{
*p++ = I2C1->DR;
if (I2Cx.len-- == 1)
{
I2C1->CR1 &= ~I2C_CR1_ACK;
I2C1->CR1 |= I2C_CR1_STOP;
}
}
else I2C1->CR1 &= ~I2C_CR1_PE;
} I2Cx.eCnt++;
}
附件为全部代码
F407_I2C.rar
(4.27 MB, 下载次数: 0)
|
|