Other Parts Discussed in Thread: ADS1115,
我在arm-linux下使用libi2c和gpio模拟i2c,尝试读取ADS111x的数据,但是存在台阶形状毛刺,具体如下图所示。使用的设备为Licheepi Nano,所用的芯片为F1C100S。
可以看到,输入位1.5v时,D14因该为1,但是次数没有被上拉,形成了一台台阶状的毛刺;同时低八位也存在两个台阶毛刺。但是Config位却能够被正确读取。代码如下:
#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); }
同时,我使用GPIO模拟I2C,仍然存在上述问题,波形如下图所示:
代码如下,gpio.h:
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); } }
main
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); }
同样的,使用ADS1115进行测试,也存在如上问题。