0
\$\begingroup\$

Currently I am trying to use a new haven display (product number NHD-C0216CiZ-FN-FBW-3V) with an i2c to usb device. I am using there bit banger code from the documentation, link http://www.newhavendisplay.com/specs/NHD-C0216CiZ-FN-FBW-3V.pdf, but whenever I send a old bit into I2C_Out I get suck into the while loop, because SDA never goes low. And I see that I never get an ack from SDA. If anyone knows how to solve this issue it would be greatly appreciated.

while(SDA==1){   
    SCL=0;   
    SCL=1;   
}

EDIT I thought that the time was two short between setting SCL low then high so I added in a 1 second delay but I am still getting suck into an infinite loop. Also I have already tried to use the given function that the i2c to usb device gives me, but those functions weren't working as well so I decided to just use the bitbanger code. The reason for this is because with the functions given from the device it sends the i2c_start then sends the data then sends the i2c_stop command. But what I need to do is send the start command then a lot of commands then the i2c_stop command. Here is the complete code that I am trying to execute

 void Show(unsigned char *text){  
    int n;  
    I2C_Start();  
    for(n=0;n<1;n++){   
        I2C_out(0x7C);  
        Delay(.05);
        I2C_out(0x40);  
        Delay(.05);
        I2C_out(*text);   
        ++text;   
    }  
    I2C_Stop(); 
}

void I2C_out(unsigned char j) {  
    BYTE value;
    int n, rc;  
    unsigned char d;  
    d=j;  
    for(n=0;n<8;n++){   
        if((d&0x80)==0x80)   
            rc = HidSmbus_WriteLatch(i2cDevice,0xFF,0x40); //SDA = 1   
        else   
            rc = HidSmbus_WriteLatch(i2cDevice,0,0x40); //SDA = 0  
        d=(d<<1);   
        Delay(.001);
        rc = HidSmbus_WriteLatch(i2cDevice,0,0x80); //Clock = 0   
        Delay(.001);
        rc = HidSmbus_WriteLatch(i2cDevice,0xFF,0x80); //Clock = 1  
        Delay(.001);
        rc = HidSmbus_WriteLatch(i2cDevice,0,0x80); //Clock = 0  
        Delay(.001);

    } 
    rc = HidSmbus_WriteLatch(i2cDevice,0xFF,0x80); //Clock = 1
    Delay(.001);
    rc = HidSmbus_ReadLatch(i2cDevice, &value);
    n = 116;
    while(((value &0x20)==0x20) && n--){
        rc = HidSmbus_WriteLatch(i2cDevice,0x00,0x80); //Clock = 0
        Delay(.001);
        rc = HidSmbus_WriteLatch(i2cDevice,0xFF,0x80); //Clock = 1 
        Delay(.001);
        //rc = HidSmbus_WriteLatch(i2cDevice,0x00,0x80); 
        rc = HidSmbus_ReadLatch(i2cDevice, &value);     
    }
    rc = HidSmbus_WriteLatch(i2cDevice,0,0x80); //Clock = 0 
}

void I2C_Stop(void) {  
    int rc;
    rc = HidSmbus_WriteLatch(i2cDevice,0,0x40); //SDA = 0
    rc = HidSmbus_WriteLatch(i2cDevice,0,0x80); //SCL = 0
    rc = HidSmbus_WriteLatch(i2cDevice,0xFF,0x80); //SCL = 1
    rc = HidSmbus_WriteLatch(i2cDevice,0xFF,0x40); //SDA = 1
}

void I2C_Start(void) {  
    int rc;
    rc = HidSmbus_WriteLatch(i2cDevice,0xFF,0x80);//pin 7 is clock  
    rc = HidSmbus_WriteLatch(i2cDevice,0xFF,0x40);//pin 6 is data
    rc = HidSmbus_WriteLatch(i2cDevice,0x00,0x40); //SDA = 0
    rc = HidSmbus_WriteLatch(i2cDevice,0x00,0x80); //SCL = 0
} 

void init_LCD(){ 
    I2C_Start();
    Delay(.05);
    I2C_out(0x7C); 
    Delay(.05);
    I2C_out(0x00); 
    Delay(.05);
    I2C_out(0x38); 
    Delay(0.10); 
    I2C_out(0x39); 
    Delay(0.10); 
    I2C_out(0x14); 
    Delay(.05);
    I2C_out(0x78); 
    Delay(.05);
    I2C_out(0x5E); 
    Delay(.05);
    I2C_out(0x6D); 
    Delay(.05);
    I2C_out(0x0E); 
    Delay(.05);
    I2C_out(0x01); 
    Delay(.05);
    I2C_out(0x06); 
    Delay(0.10); 
    I2C_Stop(); 
}

int BitBanger(){
    unsigned char text[]={"B"};
    int rc;
    BYTE dir, mode, special, clk;
    rc = HidSmbus_GetGpioConfig(i2cDevice, &dir, &mode, &special, &clk); 
    rc=HidSmbus_SetGpioConfig(i2cDevice, dir,0, 0, 0);
     init_LCD();
    Show(text); 

}
\$\endgroup\$
8
  • 1
    \$\begingroup\$ The time between the two lines code is very short. \$\endgroup\$
    – Eugene Sh.
    Commented Aug 14, 2017 at 13:41
  • \$\begingroup\$ @EugeneSh. I thought that was the case so I added in a second delay but there I am still getting stuck into the while loop \$\endgroup\$ Commented Aug 14, 2017 at 13:43
  • \$\begingroup\$ We can't guess what else have you tried. I have pointed to the first obvious issue. If you have some information to add - do it, please. \$\endgroup\$
    – Eugene Sh.
    Commented Aug 14, 2017 at 13:44
  • \$\begingroup\$ Doesn't an I²C to USB interface provide a high level abstraction, so you don't have to implement a bit-bang style I²C? \$\endgroup\$
    – Arsenal
    Commented Aug 14, 2017 at 13:47
  • 2
    \$\begingroup\$ @mohammedsaleh - Please supply an accurate schematic diagram. As explained in a comment to your previous question, you are again causing confusion by mentioning an I2C-to-USB device (which would handle the I2C protocol itself) but then asking about low-level bit-banging of the I2C protocol. These two parts of your question seem to contradict each other. It also doesn't help that you are describing only a small part of your overall system. This is like asking us to diagnose the problem inside a big room, by looking through a small keyhole! :-( \$\endgroup\$
    – SamGibson
    Commented Aug 14, 2017 at 14:01

1 Answer 1

1
\$\begingroup\$

The code you show makes no sense. There is no reason SDA is required to go low after some number of SCL pulses.

It's not clear what you are trying to do, but low level IIC master code should never sit in a infinite loop. If it does, that's really bad programming. Since the master controls the bus, there is really nothing it should have to wait for. The only exception is when any of the slaves can do clock stretching. In that case there should be a timeout. After that, the code should try to clear the bus, then return with error.

Note that if there is no slave out there, you got the address wrong, or the slave didn't properly receive the address byte, it won't ACK. However, whether ACK or not, there is nothing to wait on by the master. The ACK bit is one bit time in length, with SDA either being high (NACK) or low (ACK).

One way or another, you need to use competent low level IIC routines, now what you show.

\$\endgroup\$
7
  • \$\begingroup\$ I was using the code provided in the documentation, do you have another source where I can get an example of this done correctly \$\endgroup\$ Commented Aug 14, 2017 at 15:12
  • 1
    \$\begingroup\$ Most MCU vendors provide I²C example code, which you can use for low level bus communication. The code in the datasheet is clearly meant only for illustrative purposes and does not work in practise. \$\endgroup\$
    – Turbo J
    Commented Aug 14, 2017 at 16:52
  • \$\begingroup\$ @mohammedsaleh - "I was using the code provided in the documentation" - To be clear, you claim you are using the code from the LCD display documentation, but you haven't supplied the schematic diagram I requested earlier, to show where you're trying to run that code. Note that: (a) As Turbo J kindly explained, that code in the LCD display datasheet is incomplete. (b) You still have not explained exactly how you are trying to execute that code which you quote (that code won't work on the CP2112 USB-to-SMBus device, which you said you are using in your other question). \$\endgroup\$
    – SamGibson
    Commented Aug 14, 2017 at 17:17
  • \$\begingroup\$ @mohammedsaleh - You have now added different code, which does use the CP2112 OS API. In other words, you are not running the initial code which you claimed to be using, from the LCD documentation. As I said, that original code you gave (while(SDA==1){ SCL=0; SCL=1; }) won't work on the CP2112. By giving that earlier misleading info, you have lost my trust that it's worth helping further, so I won't spend any more time on this question. I will just say (a) the new code is poor - rc is never checked; (b) a small logic analyser and improving the code may allow you to solve this. Good luck! \$\endgroup\$
    – SamGibson
    Commented Aug 14, 2017 at 18:12
  • \$\begingroup\$ @SamGibson I don't now what your talking about, the code does the same thing as the code that was provided in the documentation, the reason I supplied the code from the documentation and not my code was because my code required an api for the i2c to usb device, and rc is meant for a debugging purpose another reason why I didn't share my code exactly, even though both codes should do the same thing \$\endgroup\$ Commented Aug 14, 2017 at 18:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.