Announcement

Collapse
No announcement yet.

I2C Communications Error with DAC

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • I2C Communications Error with DAC

    Hey guys I'm having some difficulties with I2C. I'm using a uLCD-43DT and a Microchip TC1321 10-bit DAC. Now I've been scouring the forums and google for answers but have come up naught so here I am.

    A few things about hardware: I am using 1k pullups on both data and clock lines. As far as I can tell I have the device hooked up correctly and it's being powered by a 5Vdc regulator. I also have a trimmer POT connected to Vref of the TC1321 set at 3.44Vdc.

    There are two issues:
    1. My error handling variable keeps saying that I2C1_Stop() was Unsuccessful, while debugging the previous commands yielded Successes, no failures. It's like the device was talking fine but then it couldn't stop for some reason.
    2. The voltage out of the TC1321 is 0.0008 when powered up, so nothing is changing.

    Since I'm starting VoltsOut at 500, I should see at least a volt and a half or something, but I see nothing. Any help is appreciated!!!

    Code:
    /* The function of this code is to continually increase the variable VoltsOut from 0 to 1023 (10 bits),
    while sending the data to a DAC with each incrementation, thus slowly increasing the voltage out
    from 0 to 3.44Vdc.
    */
    
    #platform "uLCD-43DT"
    
    #inherit "4DGL_16bitColours.fnc"
    
    func main()
        gfx_ScreenMode(LANDSCAPE) ; // change manually if orientation change
        var Address := 144; //Address = 1001000, plus and extra '0' as the LSB for 'Write'
        var VoltsOut;
        var ErHd; //Error handling variable
        VoltsOut := 500;
    
        print("\nBegin!\n");
        I2C1_Open(I2C_SLOW, 3, 2);
    
        repeat
        if(VoltsOut<1023)
            ++VoltsOut;
        else
            VoltsOut := 0;
        endif
        //Create Start condition---------------------------------------------------------
        while(I2C1_Idle()==0)
            print("Waiting for Idle\n");   //This statement never prints. Line is always idle I guess.
            pause(1000);
        wend
        I2C1_Start();
        pause(100);
        //Write address to I2C bus------------------------------------------------------------
        I2C1_Write(LObyte(Address)); //Address Byte. I think the LSB is Read/Write. 0 is Write.
        //Select CONFIG register-------------------------------------------------------------
        I2C1_Write(0); //Selects the DATA register
        //Write Data to I2C bus for DAC---------------------------------------------------------
        I2C1_Write(HIbyte(VoltsOut)); //Data Byte
        I2C1_Write(LObyte(VoltsOut)); //Data Byte
        //Stop I2C--------------------------------------------------------------------------
        ErHd := I2C1_Stop();
                if(ErHd==0)
                    print("\nStop Unsuccessful\n"); //    <---------This is the current problem
                endif
                if(ErHd==1)
                    print("\nStop Successful\n");
                endif
        pause(100); //This is set so long to show that the first pass is what's failing
        forever
    
    endfunc
    - Cody

  • #2
    Hi Cody,

    This is a function I used for an I2C write

    var DAC := 0x90;

    func writebytes(var register, var value1, var value2)
    I2C1_Start(); // Generate Start condition
    I2C1_Write(DAC); // send slave address
    I2C1_Write(register); // select the register
    I2C1_Write(value1); // save the value in selected register
    I2C1_Write(value2);
    I2C1_Stop(); // finished with bus
    endfunc

    Usage writebytes(0, HIbyte(VoltsOut), LObyte(VoltsOut));

    Which appears to be the same as yours, You could try I2C_MED as most I2c devices run at that speed.

    regards

    Paul

    Comment


    • #3
      Thank you for the reply but the TC1321 tops out at 100kHz. I tried slower speeds also to no avail. Yeah my code is pretty much the same as yours. What's confusing me is that it's only failing to Stop. When debugging I found that Start and all the Write commands receive an ACK signal back, so it's like it is working just not at the end for some reason.

      Comment


      • #4
        Hi Cody,

        Looking at the datasheet, the TC1321 doesn't send an ACK after a STOP. The next ACK would come from a START on the next write. If you look at page 11 on the datasheet http://ww1.microchip.com/downloads/e...Doc/21387C.pdf Value1 should be VoltsOut >> 2 and Value2 should be (VoltsOut << 6) & 0xC0.

        var value1;
        var value2;

        value1 := VoltsOut >> 2;
        value2 := (VoltsOut << 6) & 0xC0;

        I2C1_Write(LObyte(value1));
        I2C1_Write(LObyte(value2));

        I am not sure if the LObyte is necessary as we have spilt the VoltsOut into 2 bytes already.

        I hope this helps

        Paul

        Comment


        • #5
          Thanks for the help, Paul! I didn't notice that the bytes needed to be that way. So I made the changes you have here and it still wasn't working. Now I eliminated the error handling like you suggested, but my output voltage is still non existent. I changed up the code a bit and based on my print statements it looks like value1 and value2 contain the correct data. I've worked on it for a couple of hours now so I'm back on the forums. Here's the new code:
          Code:
          /* The function of this code is to continually increase the variable VoltsOut from 0 to 1023 (10 bits),
          while sending the data to a DAC with each incrementation, thus slowly increasing the voltage out
          from 0 to 3.44Vdc.
          */
          
          #platform "uLCD-43DT"
          
          #inherit "4DGL_16bitColours.fnc"
          
          func main()
              gfx_ScreenMode(LANDSCAPE) ; // change manually if orientation change
              var Address := 144; //Address = 1001000, plus and extra '0' as the LSB for 'Write'
              var VoltsOut;
              var value1;
              var value2;
              var ErHd; //Error handling variable
              VoltsOut := 500;
              print("\n", [BIN16Z]VoltsOut);
              print("\nBegin!\n");
              I2C1_Open(I2C_10KHZ, 3, 2);
          
              repeat
              if(VoltsOut<1023)
                  ++VoltsOut;
                  value1 := VoltsOut;
                  value1 >> 2;
                  value1 := LObyte(value1);
                  value2 := VoltsOut;
                  value2 := (value2 << 6) & 0xC0; //Anding: 1100 0000
                  value2 := LObyte(value2);
                  print("\n", "Binary Values: ", [BIN16Z]VoltsOut, " ", [BIN8Z]value1, " ", [BIN8Z]value2);
              else
                  VoltsOut := 0;
              endif
              //Create Start condition---------------------------------------------------------
              while(I2C1_Idle()==0)
                  print("Waiting for Idle\n");   //This statement never prints. Line is always idle I guess.
                  pause(1000);
              wend
              I2C1_Start();
              pause(100);
              //Write address to I2C bus------------------------------------------------------------
              I2C1_Write(LObyte(Address)); //Address Byte. I think the LSB is Read/Write. 0 is Write.
              //Select CONFIG register-------------------------------------------------------------
              I2C1_Write(0); //Selects the DATA register
              //Write Data to I2C bus for DAC---------------------------------------------------------
              I2C1_Write(value1); //Data Byte
              I2C1_Write(value2); //Data Byte
              //Stop I2C--------------------------------------------------------------------------
              I2C1_Stop();
              forever
          
          endfunc

          Comment


          • #6
            Cody-DCI,

            In your code I2C1_Open(I2C_10KHZ,3,2);

            Please try to use PA3 and PA2 and not pin numbers.
            PA3 corresponds to GPIO1 and PA2 corresponds to GPIO2
            So it should be:

            I2C1_Open(I2C_10KHZ,PA3,PA2);

            Best regards,

            Comment


            • #7
              Oh my god. Thank you, Noel. While I had several other issues that Paul helped me solve, your comment showed me the one thing I missed hardcore: I had put the pin numbers of the DAC in my code instead of the uLCD pin numbers. It wasn't 3 and 2, it was PA7 and PA8. Wow I feel stupid. I've been over this code so many times...

              Thank you guys so much for the help! The DAC is working and slowing increasing the voltage. I'm very grateful!!!!

              Comment


              • #8
                Hey guys I hate to bother you again but I've run into another snag. I'm trying to read out of the Data register and for some reason am not getting any data. When I comment out the entire READ section, the voltage runs from about 0V to about 3.3V, then back to zero. With the READ section, the voltage increases, but then jumps up in some cases over a volt very briefly, as though the DATA register is being rewritten after I set the data.

                Now, the datasheet says that I should send the normal slave address set to Write mode, followed by the register byte, then followed by the address again, this time with the Read bit at the end. I've tried it several other ways and it always fails. The ultimate issue is that the ReadData variable always contains all zeroes, and temp1/temp2 never change either. I've been working on this for a few hours now and could really use some help! Thanks guys.

                Code:
                /* The function of this code is to continually increase the variable VoltsOut from 0 to 1023 (10 bits),
                while sending the data to a DAC with each incrementation, thus slowly increasing the voltage out
                from 0 to 3.44Vdc.
                */
                
                #CONST
                ADDRESS := 144; //Address = 1001000, plus and extra '0' as the LSB for 'Write'
                READADDRESS := 145; //Read Address
                CONFIGREG := 1;
                DATAREG:= 0;
                #END
                
                func main()
                    gfx_ScreenMode(LANDSCAPE) ; // change manually if orientation change
                    var VoltsOut;
                    var value1;
                    var value2;
                    var ReadData;
                    var temp1;
                    var temp2;
                    var ErHd; //Error handling variable
                    VoltsOut := 0;
                
                    I2C1_Open(I2C_10KHZ, PA7, PA8);
                
                    repeat
                    if(VoltsOut<1000)
                        ++VoltsOut;
                        value1 := VoltsOut;
                        value1 := value1 >> 2;
                        value2 := VoltsOut;
                        value2 := (value2 << 6) & 0xC0; //Anding: 1100 0000
                        gfx_Cls();
                        print("\n", "Binary Values: ", "\n", [BIN16Z]VoltsOut, "\n", [BIN8Z]value1, "\n", [BIN8Z]value2, "\n", [BIN16Z]ReadData);
                    else
                        VoltsOut := 0;
                    endif
                    //WRITE DATA----------------------------------------------------------------
                    I2C1_Start();
                    I2C1_Write(LObyte(ADDRESS)); //Address Byte. I think the LSB is Read/Write. 0 is Write.
                    I2C1_Write(LObyte(DATAREG)); //Selects the DATA register
                    I2C1_Write(LObyte(value1)); //Data Byte
                    I2C1_Write(LObyte(value2)); //Data Byte
                    I2C1_Stop();
                    pause(1000);
                    //READ DATA------------------------------------------------------------------
                
                    I2C1_Start();
                    I2C1_Write(LObyte(ADDRESS));
                    I2C1_Write(LObyte(DATAREG));
                    I2C1_Write(LObyte(READADDRESS));
                    temp1 := I2C1_Read();
                    I2C1_AckStatus();
                    temp2 := I2C1_Read();
                    I2C1_AckStatus();
                    I2C1_Stop();
                    ReadData := 0;
                        gfx_Cls();
                        print("\n",[DEC]temp1," ",[DEC]temp2); //Always shows: 255, 127
                        pause(1000);
                    (temp1 << 8) & ReadData; //Make the first byte read the upper 8 bits of ReadData
                    temp2 & ReadData; //Make the second byte read the lower 8 bits of ReadData
                
                    forever
                
                endfunc

                Comment


                • #9
                  Hi Cody,

                  Can you try this code for read

                  I2C1_Start(); // Generate Start condition
                  I2C1_Write(LObyte(ADDRESS)); // send slave address
                  I2C1_Write(LObyte(DATAREG)); // Send register address
                  I2C1_Restart(); // Generate Restart
                  I2C1_Write(LObyte(READADDRESS)); // send control byte for Read
                  temp1 := I2C1_Read(); // read the byte
                  I2C1_Nack(); // finished reading, send Not Ack
                  temp2 := I2C1_Read();
                  I2C1_Nack();
                  I2C1_Stop();

                  or

                  I2C1_Start(); // Generate Start condition
                  I2C1_Write(LObyte(ADDRESS)); // send slave address
                  I2C1_Write(LObyte(DATAREG)); // Send register address
                  I2C1_Restart(); // Generate Restart
                  I2C1_Write(LObyte(READADDRESS)); // send control byte for Read
                  temp1 := I2C1_Read(); // read the byte
                  I2C1_Nack();
                  I2C1_Stop();

                  I2C1_Start(); // Generate Start condition
                  I2C1_Write(LObyte(ADDRESS)); // send slave address
                  I2C1_Write(LObyte(DATAREG + 1)); // Send register address
                  I2C1_Restart(); // Generate Restart
                  I2C1_Write(LObyte(READADDRESS)); // send control byte for Read
                  temp2 := I2C1_Read(); // read the byte
                  I2C1_Nack();
                  I2C1_Stop();

                  Best regards

                  Paul

                  Comment


                  • #10
                    Thanks Paul that worked! I missed that I needed to send a restart command. This is what worked:

                    Code:
                    I2C1_Start();
                        I2C1_Write(LObyte(ADDRESS));
                        I2C1_Write(LObyte(DATAREG));
                        I2C1_Restart();
                        I2C1_Write(LObyte(READADDRESS));
                        temp1 := I2C1_Read();
                        I2C1_Ack();
                        temp2 := I2C1_Read();
                        I2C1_Nack();
                        I2C1_Stop();

                    Comment


                    • #11
                      Hi cody,

                      I put a Nack instead of an Ack, sorry for the typo.

                      Best regards

                      Paul

                      Comment

                      Working...
                      X