小弟今天用Licheepi Nano读取ADS1110,当输入数据小于等于1V时,能得到正确的数据,但是当输入大于1v时,得到的数据则是不正确的。代码如下:
#define NUMS 10
char readbuf[NUMS];
int main(int argc, char** argv)
{
int file = open("/dev/i2c-0", O_RDWR);
// addr = 1001 xxx
int addr = 0b1001000;
if (file < 0)
{
printf("openfile error!\n");
exit(1);
}
if (ioctl(file, I2C_SLAVE, addr) < 0)
{
printf("ioctl error!\n");
exit(1);
}
// Debug Gain 1
readbuf[0] = 0x0C;
if (write(file, readbuf, 1) != 1)
{
printf("write error!\n");
exit(1);
}
if (read(file, readbuf, 3) != 3)
{
printf("read error!\n");
exit(1);
}
printf("%x %x %x\n", readbuf[0] & 0xff, readbuf[1] & 0xff, readbuf[2] & 0xff);
close(file);
exit(EXIT_SUCCESS);
}
上述代码中我写入0x0C,使ADS1110以15sps、16bits输出,同时增益为1。当输入为1V时,输出为`3E 00 0C`,即,3E00 / 32767 * 2.048;当输入为1.5V时,输出大约应为`5E 00 0C'左右,但是我得到的数据大约为`1D 00`。使用调试器的时候能正确读取,请问我这里是哪里没写对吗,感谢大佬指出。
离线
可以看到D14的数据本来应该拉高的,但是Nano这边却在将SDA拉低。
但是除了这一位和低八位的数据,接收的其他数据确是正常的。之后我又使用gpiod库来手动模拟了i2c,但是该问题仍然存在:
可以看到,除了config八位的数据是正常的,data的数据均没有被拉起来。这三个字节使用同一段代码读取,不知道是哪里出的问题。下面是我模拟i2c的代码:
struct gpiod_chip* gpiochip0;
struct gpiod_line* line_SCL;
struct gpiod_line* line_SDA;
int PE11Num = (4 * 32) + 11;
int PE12Num = (4 * 32) + 12;
bool i2cInit()
{
gpiochip0 = gpiod_chip_open("/dev/gpiochip0");
line_SCL = gpiod_chip_get_line(gpiochip0, PE11Num);
line_SDA = gpiod_chip_get_line(gpiochip0, PE12Num);
int reqSCL = gpiod_line_request_output(line_SCL, "SCL", 1);
int reqSDA = gpiod_line_request_output(line_SDA, "SDA", 1);
return !(reqSCL | reqSDA);
}
bool i2cSDAConf(bool toOutput)
{
int reqSDA;
gpiod_line_release(line_SDA);
if (toOutput)
{
int reqSDA = gpiod_line_request_output(line_SDA, "SDA", 1);
}
else
{
int reqSDA = gpiod_line_request_input(line_SDA, "SDA");
}
return !reqSDA;
}
void i2cSDALevel(bool toHigh)
{
gpiod_line_set_value(line_SDA, toHigh);
}
void i2cSCLLevel(bool toHigh)
{
gpiod_line_set_value(line_SCL, toHigh);
}
void i2cDelay()
{
for (int i = 0; i < 1000; ++i) { /* do nothing */ }
}
void i2cStart()
{
i2cSDALevel(1);
i2cSCLLevel(1);
i2cDelay();
i2cSDALevel(0);
i2cDelay();
i2cSCLLevel(0);
i2cDelay();
}
void i2cEnd()
{
i2cSDALevel(0);
i2cDelay();
i2cSCLLevel(1);
i2cDelay();
i2cSDALevel(1);
}
void i2cACK()
{
// make sure the SDA is output before send
i2cSDAConf(1);
i2cSDALevel(0);
i2cDelay();
i2cSCLLevel(1);
i2cDelay();
i2cSCLLevel(0);
i2cDelay();
}
void i2cNACK()
{
// make sure the SDA is output before send
i2cSDAConf(1);
i2cSDALevel(1);
i2cDelay();
i2cSCLLevel(1);
i2cDelay();
i2cSCLLevel(0);
i2cDelay();
}
bool i2cSDARelease()
{
// i2cSDALevel(0);
return i2cSDAConf(0);
}
bool i2cWaitAck()
{
return !i2cGetSDA();
}
void i2cSend(u8 data)
{
// make sure the SDA is output before send
i2cSDAConf(1);
for (int i = 0; i < 8; ++i)
{
if (data & 0x80)
i2cSDALevel(1);
else
i2cSDALevel(0);
i2cDelay();
i2cSCLLevel(1);
i2cDelay();
i2cSCLLevel(0);
i2cDelay();
data <<= 1;
}
// 释放SDA
i2cSDARelease();
}
bool i2cGetSDA()
{
i2cSCLLevel(1);
i2cDelay();
bool level = gpiod_line_get_value(line_SDA);
i2cSCLLevel(0);
i2cDelay();
return level;
}
u8 i2cReceive()
{
i2cSDARelease();
u8 data;
for (int i = 0; i < 8; ++i)
{
data <<= 1;
data |= i2cGetSDA();
}
return data;
}
u8 i2cReceiveDebug(u32* biasDebug)
{
i2cSDARelease();
u8 data;
for (int i = 0; i < 8; ++i)
{
data <<= 1;
data |= i2cGetSDA();
*biasDebug <<= 2;
// 查看pull寄存器状态
static int dev_fd;
unsigned char *map_base;
dev_fd = open("/dev/mem", O_RDWR);
map_base = (unsigned char *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, GPIO_PAGE_OFFSET);
*biasDebug |= (*(volatile u32*)(map_base + GPIO_BASE_OFFSET + rPE_PULL0)) >> 24 & 0b11;
munmap(map_base, MAP_SIZE);
}
return data;
}
void i2cRelease()
{
gpiod_chip_close(gpiochip0);
}
void i2cClear()
{
i2cSDARelease();
for (int i = 0; i < 32; ++i)
{
i2cSCLLevel(0);
i2cSCLLevel(1);
}
}
ADS1110读取,在start之前和end之后,我输出了一段scl的时钟,以期对清楚ADS1110的寄存器内容。
void ADS1110_ReadData()
{
if(!i2cInit())
{
printf("I2C init error\n");
i2cRelease();
exit(1);
}
i2cClear();
i2cSDAConf(1);
i2cStart();
u8 addr = 0b10010001;
i2cSend(addr);
if (!i2cWaitAck())
{
printf("none ACK received\n");
printf("%d\n", gpiod_line_direction(line_SDA));
i2cRelease();
exit(1);
}
u8 data[3];
data[0] = i2cReceive();
i2cACK();
data[0] = i2cReceive();
i2cACK();
data[0] = i2cReceive();
i2cNACK();
i2cEnd();
i2cClear();
i2cRelease();
printf("%x %x %x\n", data[0] & 0xFF, data[1] & 0xFF, data[2] & 0xFF);
}
同时,总线上只有ADS1110一个设备:
# i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
离线