OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3720|回复: 3

自编中断方式读24C02,居然总时间比顺序读要长不少

[复制链接]

21

主题

151

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
423
金钱
423
注册时间
2017-4-1
在线时间
73 小时
发表于 2021-1-8 22:56:53 | 显示全部楼层 |阅读模式
本帖最后由 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)
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

21

主题

151

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
423
金钱
423
注册时间
2017-4-1
在线时间
73 小时
 楼主| 发表于 2021-1-9 13:09:14 | 显示全部楼层
附上顺序读的代码,用时大约650uS
uint8_t test (uint32_t ev)
{
        uint16_t sr1 = I2C1->SR1;
        uint32_t sr = (I2C1->SR2 << 16) | sr1;
        return ((sr & ev) == ev);
}

        I2Cx.devAddr = 0xA0;
        I2Cx.regAddr = 0x10;
        I2Cx.eCnt = 0;
        I2Cx.len = 4;
        while (I2C1->SR2 & I2C_SR2_BUSY);
        I2C1->CR1 |= I2C_CR1_ACK | I2C_CR1_START;
        while (!test (EV5));
        I2C1->DR = I2Cx.devAddr;
        while (!test (EV6t));
        I2C1->DR = I2Cx.regAddr;
        while (!test (EV8));
        I2C1->CR1 |= I2C_CR1_ACK | I2C_CR1_START;
        while (!test (EV5));
        I2C1->DR = I2Cx.devAddr | 0x01;
        while (!test (EV6r));
        while (I2Cx.len)
        {
                while (!test (EV7));
                I2Cx.buff[I2Cx.eCnt++] = I2C1->DR;
                if (I2Cx.len-- == 2)
                {
                        I2C1->CR1 &= ~I2C_CR1_ACK;
                        I2C1->CR1 |= I2C_CR1_STOP;
                }
        }
回复 支持 反对

使用道具 举报

21

主题

151

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
423
金钱
423
注册时间
2017-4-1
在线时间
73 小时
 楼主| 发表于 2021-1-9 18:22:35 | 显示全部楼层
不好意思,昨天的附件传错了,已更正。
今天有个发现,如果开启了缓冲区中断(I2C_CR2_ITBUFEN),则读过程时间对头了,时间缩短为650uS,但是EV8的中断次数却达到160多次。
回复 支持 反对

使用道具 举报

21

主题

151

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
423
金钱
423
注册时间
2017-4-1
在线时间
73 小时
 楼主| 发表于 2021-1-9 19:04:07 | 显示全部楼层
微信截图_20210109185831.png
使用STM32CUBE生成的工程,以中断方式读取同样内容,结果如下
打印的内容:
读取数据总耗时约654微秒
第0中断的事件码= 0x00030001
第1中断的事件码= 0x00070082
第2中断的事件码= 0x00070080
第3中断的事件码= 0x00070080
第4中断的事件码= 0x00070080
第5中断的事件码= 0x00070080
第6中断的事件码= 0x00070080
第7中断的事件码= 0x00070080
第8中断的事件码= 0x00070080
第9中断的事件码= 0x00070080
第10中断的事件码= 0x00070080
第11中断的事件码= 0x00070080
第12中断的事件码= 0x00070080
第13中断的事件码= 0x00070080
第14中断的事件码= 0x00070080
第15中断的事件码= 0x00070080
第16中断的事件码= 0x00070080
第17中断的事件码= 0x00070080
第18中断的事件码= 0x00070080
第19中断的事件码= 0x00070080
第20中断的事件码= 0x00070080
第21中断的事件码= 0x00070080
第22中断的事件码= 0x00070080
第23中断的事件码= 0x00070080
第24中断的事件码= 0x00070080
第25中断的事件码= 0x00070080
第26中断的事件码= 0x00070080
第27中断的事件码= 0x00070080
第28中断的事件码= 0x00070080
第29中断的事件码= 0x00070080
第30中断的事件码= 0x00070080
第31中断的事件码= 0x00070080
第32中断的事件码= 0x00070080
第33中断的事件码= 0x00070080
第34中断的事件码= 0x00070080
第35中断的事件码= 0x00070080
第36中断的事件码= 0x00070080
第37中断的事件码= 0x00070080
第38中断的事件码= 0x00070080
第39中断的事件码= 0x00070080
第40中断的事件码= 0x00070080
第41中断的事件码= 0x00070080
第42中断的事件码= 0x00070080
第43中断的事件码= 0x00070080
第44中断的事件码= 0x00070080
第45中断的事件码= 0x00070080
第46中断的事件码= 0x00070080
第47中断的事件码= 0x00070080
第48中断的事件码= 0x00070080
第49中断的事件码= 0x00070080
第50中断的事件码= 0x00070080
第51中断的事件码= 0x00070080
第52中断的事件码= 0x00070080
第53中断的事件码= 0x00070080
第54中断的事件码= 0x00070080
第55中断的事件码= 0x00070080
第56中断的事件码= 0x00070080
第57中断的事件码= 0x00070080
第58中断的事件码= 0x00070080
第59中断的事件码= 0x00070080
第60中断的事件码= 0x00070080
第61中断的事件码= 0x00070080
第62中断的事件码= 0x00070080
第63中断的事件码= 0x00070080
第64中断的事件码= 0x00070080
第65中断的事件码= 0x00070080
第66中断的事件码= 0x00070080
第67中断的事件码= 0x00070080
第68中断的事件码= 0x00070080
第69中断的事件码= 0x00070080
第70中断的事件码= 0x00070080
第71中断的事件码= 0x00070080
第72中断的事件码= 0x00070080
第73中断的事件码= 0x00070080
第74中断的事件码= 0x00070080
第75中断的事件码= 0x00070080
第76中断的事件码= 0x00070080
第77中断的事件码= 0x00070080
第78中断的事件码= 0x00070080
第79中断的事件码= 0x00070080
第80中断的事件码= 0x00070080
第81中断的事件码= 0x00070080
第82中断的事件码= 0x00070080
第83中断的事件码= 0x00070080
第84中断的事件码= 0x00070080
第85中断的事件码= 0x00070084
第86中断的事件码= 0x00070084
第87中断的事件码= 0x00070084
第88中断的事件码= 0x00070084
第89中断的事件码= 0x00070084
第90中断的事件码= 0x00070084
第91中断的事件码= 0x00070084
第92中断的事件码= 0x00070084
第93中断的事件码= 0x00070084
第94中断的事件码= 0x00070084
第95中断的事件码= 0x00070084
第96中断的事件码= 0x00070084
第97中断的事件码= 0x00070084
第98中断的事件码= 0x00070084
第99中断的事件码= 0x00030001
第100中断的事件码= 0x00030002
第101中断的事件码= 0x00030040
第102中断的事件码= 0x00030044
第103中断的事件码= 0x00030044
程序主要是在它的中断服务程序中嵌入记录中断事件的代码,等待读数据结束后将结果打印出来。从结果来看,CUBE的中断服务也遇到同样的问题,说明3楼的方法应该没问题。出现那么多的0x00070084或0x00070080是STM32固有的问题。这个问题的原因应该是找到了。
F407_I2C_Test.rar (6.44 MB, 下载次数: 0)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-3-1 05:52

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表