打印
[MCU]

软件i2c读多字节只能读出第一个字节

[复制链接]
2224|26
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1. 我用的是cypress芯片,用IO模拟软件i2c,读取单个字节没有问题,读取多个字节时,只有第一个字节是对的,后面的字节都是0
2. 波形图中左边是电脑端读i2c的波形,是没有问题的,排除硬件问题
3. 波形图中右边是单片机io模拟读i2c的波形,第一个字节对,第二个字节是0,看波形图,ACK(0)之前SDA被拉高(红色箭头处),可能slave误以为发了ACK(1)所以结束了
4. 请问那个SDA被拉高是什么原因?

SDA配置.png (25.86 KB )

SDA配置.png

部分代码.jpg (165.89 KB )

部分代码.jpg

波形对比.jpg (365.81 KB )

波形对比.jpg

使用特权

评论回复

相关帖子

沙发
ayb_ice| | 2020-6-10 16:32 | 只看该作者
多半是应答错了

使用特权

评论回复
板凳
qinchxiong|  楼主 | 2020-6-10 16:43 | 只看该作者
ayb_ice 发表于 2020-6-10 16:32
多半是应答错了

能不能具体说一下,看波形,我的应答ack(0)在那个高电平产生之后发送的,但那个高电平不是我的代码操作的

使用特权

评论回复
地板
ayb_ice| | 2020-6-10 16:46 | 只看该作者
qinchxiong 发表于 2020-6-10 16:43
能不能具体说一下,看波形,我的应答ack(0)在那个高电平产生之后发送的,但那个高电平不是我的代码操作的 ...

你应答时,要先切换GPIO模式

使用特权

评论回复
5
qinchxiong|  楼主 | 2020-6-10 16:57 | 只看该作者
ayb_ice 发表于 2020-6-10 16:46
你应答时,要先切换GPIO模式

我了解你的意思,切换SDA为输出模式,这个我想到过,cypress平台配置sda为bidirectional,双向模式,用psoc生成的代码,但没看到它的代码里设置模式的接口,所以我推测调用pin write和pin read的时候它自动切换的

使用特权

评论回复
6
ayb_ice| | 2020-6-11 08:24 | 只看该作者
本帖最后由 ayb_ice 于 2020-6-11 08:39 编辑
qinchxiong 发表于 2020-6-10 16:57
我了解你的意思,切换SDA为输出模式,这个我想到过,cypress平台配置sda为bidirectional,双向模式,用ps ...

自己测试下GPIO,这种情况下直接输出0,或1,正确吗

使用特权

评论回复
7
William1994| | 2020-6-11 08:48 | 只看该作者
每个receive byte都都必须ack(0),除了最后一个字节。
你只有N个字节后ack了一下。
你应该知道I2C的一个byte frame是9个bit,前8个是一方发送,第9个是另外一方发送的。

使用特权

评论回复
8
qinchxiong|  楼主 | 2020-6-11 09:15 | 只看该作者
William1994 发表于 2020-6-11 08:48
每个receive byte都都必须ack(0),除了最后一个字节。
你只有N个字节后ack了一下。
你应该知道I2C的一个byt ...

整理代码图片前不小心把ack(0)删掉了,原本代码是:
......
......
......
for (i = 0; i < len - 1; i++)
{   
         *buffer = recv_byte();
                          
          ack_i2c(0);

          buffer++;
}

        *buffer = recv_byte();               
        ack_i2c(1);
        stop_i2c();   

使用特权

评论回复
9
qinchxiong|  楼主 | 2020-6-11 09:36 | 只看该作者
ayb_ice 发表于 2020-6-11 08:24
自己测试下GPIO,这种情况下直接输出0,或1,正确吗

我测试了一下,这种情况下输出0,1正常,另外我的接收代码是(昨天整理代码图片时删了一句ack_i2c(0)):
for (i = 0; i < len - 1; i++)
{   
         *buffer = recv_byte();                        
          ack_i2c(0);
          buffer++;
}
        *buffer = recv_byte();               
        ack_i2c(1);
        stop_i2c();
根本问题还是:那个红色箭头处的SDA拉高不知道是哪里给出的,不是我的代码发出的

使用特权

评论回复
10
ayb_ice| | 2020-6-11 09:36 | 只看该作者
qinchxiong 发表于 2020-6-11 09:36
我测试了一下,这种情况下输出0,1正常,另外我的接收代码是(昨天整理代码图片时删了一句ack_i2c(0)):
fo ...

是不是其它地方也在控制,时序没有问题,方便的话发下完整的代码

使用特权

评论回复
11
ayb_ice| | 2020-6-11 09:41 | 只看该作者
qinchxiong 发表于 2020-6-11 09:36
我测试了一下,这种情况下输出0,1正常,另外我的接收代码是(昨天整理代码图片时删了一句ack_i2c(0)):
fo ...

那个高其实是没问题的,因为SCL低时,SDA可以 变化,只要在SCL上升沿前电平是对的就可以 了

使用特权

评论回复
12
qinchxiong|  楼主 | 2020-6-11 10:07 | 只看该作者
ayb_ice 发表于 2020-6-11 09:36
是不是其它地方也在控制,时序没有问题,方便的话发下完整的代码

附件是操作代码,你说的在非clk周期内sda是高电平没有影响,我也是这么想的,但我看电脑操作的波形是没有的,读取也没有问题。

i2c_master.rar

1.6 KB

使用特权

评论回复
13
ayb_ice| | 2020-6-11 10:40 | 只看该作者
qinchxiong 发表于 2020-6-11 10:07
附件是操作代码,你说的在非clk周期内sda是高电平没有影响,我也是这么想的,但我看电脑操作的波形是没有 ...

read_ack只能发送一次时钟,不可以发送多次,
其它的地方暂时没看

使用特权

评论回复
14
qinchxiong|  楼主 | 2020-6-11 11:48 | 只看该作者
ayb_ice 发表于 2020-6-11 10:40
read_ack只能发送一次时钟,不可以发送多次,
其它的地方暂时没看

static uint8_t wait_read_ack(void)
{
       uint8_t ack = 1;
       int32_t i;
       uint8_t max_count = 10;

        SDA_H;
        SCL_H;
        for(i = 0; i < max_count; i++)
        {
                ack = I2C_SDA_READ;
                if(ack == 0)
                        break;
        
                if(i == max_count - 1)
                        return 1;
        }
        SCL_L;       
        return 0;
}
我确认了一下,跟read_ack里的多次发送时钟无关,我改成上面的代码,仍然只能读一个字节,波形是一样的

使用特权

评论回复
15
ayb_ice| | 2020-6-11 12:57 | 只看该作者
qinchxiong 发表于 2020-6-11 11:48
static uint8_t wait_read_ack(void)
{
       uint8_t ack = 1;

这是协议的问题,你连协议都没搞清楚,

读应答之前要将GPIO设为输入状态,没看到哪里有切换,

就是标准的51也要置个1才能读,

使用特权

评论回复
16
ayb_ice| | 2020-6-11 13:09 | 只看该作者
qinchxiong 发表于 2020-6-11 11:48
static uint8_t wait_read_ack(void)
{
       uint8_t ack = 1;

你这个代码有延时吗,这样肯定不行

使用特权

评论回复
17
qinchxiong|  楼主 | 2020-6-11 13:51 | 只看该作者
ayb_ice 发表于 2020-6-11 12:57
这是协议的问题,你连协议都没搞清楚,

读应答之前要将GPIO设为输入状态,没看到哪里有切换,

我知道你的意思,我最开始的时候想到过这个问题,用cypress的 pSoC4配置和生成的代码,没看到IO方向切换接口,我推测配置为bidretcional和open drive + low模式生成的代码,SDA pin write和read时我不确定是不是自动切换io方向,因为read单个字节,是没有问题的。

SDA配置.png (25.86 KB )

SDA配置.png

使用特权

评论回复
18
qinchxiong|  楼主 | 2020-6-11 14:01 | 只看该作者
ayb_ice 发表于 2020-6-11 13:09
你这个代码有延时吗,这样肯定不行

试过了,这里的延时没有影响

使用特权

评论回复
19
ayb_ice| | 2020-6-11 14:11 | 只看该作者
qinchxiong 发表于 2020-6-11 13:51
我知道你的意思,我最开始的时候想到过这个问题,用cypress的 pSoC4配置和生成的代码,没看到IO方向切换 ...

可以忽略这个应答的结果,直接往下读试试

使用特权

评论回复
20
ayb_ice| | 2020-6-11 14:14 | 只看该作者
qinchxiong 发表于 2020-6-11 13:51
我知道你的意思,我最开始的时候想到过这个问题,用cypress的 pSoC4配置和生成的代码,没看到IO方向切换 ...

你这就是类似51的准双向口,读GPIO之前先输出1

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

41

帖子

0

粉丝