10 Replies Latest reply on Jul 29, 2016 11:09 AM by juliehardin55_1647776

    I2C API problem

    juliehardin55_1647776

      I am working with a Pioneer board and a CYBLE-012011 eval board. I've instantiated an I2C interface that I've connected to an external MCP4725 DAC, powered by the Pioneer board. I trigger writes to the DAC using a counter with an interrupt on terminal count. My interrupt service routine just sets a flag that my main program checks.

         


      When I attempt to write three bytes to the DAC using the non-blocking, interrupt driven API function SCB_I2CMasterWriteBuf, the output of the I2C has the first byte (the address) correct, but the three bytes of data are all 0's. If, however, I put in a delay after the SCB_I2CMasterWriteBuf function call (either a printf or a CyDelay(1u)), it works correctly. I am able to watch the I2C bus on an oscilloscope. However, this severely limits the bandwidth of I2C writes I can perform - I'm limited by the 1 millisecond delay.

         


      I then changed my code to use the separate functions SCB_I2CMasterSendStart, SCB_I2CMasterWriteByte, and SCB_I2CMasterSendStop. These also work, and I can do I2C bus transactions at approximately 12 KHz, but since they're blocking, I'm unable to do anything else while my data is being written out on the I2C, which won't work for the project I'm designing.

         


      Do you know why the SCB_I2CMasterWriteBuf API function behaves in this fashion and is there a way to do faster, non-blocking I2C transactions? I'm attaching my project bundle.

         

      On a side note, I've only gotten the UART and I2C to work by leveraging off a 100days project (HRM_datalogger). If I start from scratch, copying my code into the new project, neither the UART or the I2C work.

         

      Thanks.

         


       

        • 1. Re: I2C API problem
          user_1377889

          Welcome in the forum, Juliea.

             

          When you uncomment the line containing I2C_M_I2CMasterWriteBuf you get a warning. Take that literally!!!

             

          I2C_M_I2CMasterWriteBuf is expecting an array of uint8 and you pass an array of uint32. Thus, the first 3 bytes transferred are 0x00.

             

          Change your write_buff to an uint8 array. Then the required initial 0x40 for the DAC will be transferred and it should run as expected.

             

          FYI: The parameter type uint32 was taken instead of the more obvious uint8, because no conversion would be needed as masking off unneeded bits etc. The smallest amount of data that can be pushed onto the stack is a 32-bit register, so handling bytes could result in some unneeded overhead.

             

           

             

          Bob

          • 2. Re: I2C API problem
            juliehardin55_1647776

            Please note that when I uncomment the line containing I2C_M_I2CMasterWriteBuf, I also uncomment the declaration above it for the uint8 write_buf. I used the uint8 array with I2C_M_I2CMasterWriteBuf, and the uint32 write_buf array with the SCB_I2CMasterWriteByte function, which requires a uint32 array. So the write_buf parameter type matches the API type I use, and it does not run as expected.

            • 3. Re: I2C API problem
              juliehardin55_1647776

              That would also not explain why inserting a delay (the commented out printf or the commented out CyDelay) would fix the problem.

              • 4. Re: I2C API problem
                user_242978793

                Is this your  Mpc 4725 circuit or are you using a module designed by some one else? if it is your design did you follow the  layout recommendations. Also I would slow the clock down in the configuration for the I2C component to see if that helps. 

                   

                   

                • 5. Re: I2C API problem
                  juliehardin55_1647776

                  I'm still prototyping before doing my board design, so I'm using a Sparkfun board for the MCP4725 DAC. I had used 100 kbps previously for the I2C, but changed the design back to 100 kbps to take the attached screen captures. The first, labeled "Using blocking function calls" uses the SCB_I2CMasterSendStart, SCB_I2CMasterWriteByte, and SCB_I2CMasterSendStop API calls and a uint32 data buffer. You can see the I2C address and 3 bytes of non-zero data. The second, labeled "Single function call" uses the SCB_I2CMasterWriteBuf API and a uint8 data buffer. You can see the I2C address but all of the 3 data bytes are 0's. The third screen capture still uses the SCB_I2CMasterWriteBuf API with uint8 data buffer, but has a CyDelay(1) call immediately after the SCB_I2CMasterWriteBuf function call. Again, the I2C address and the 3 bytes of non-zero data are visible. Changing the API calls (and the corresponding data buffer data types) was the only difference between the screen captures. So there is something about the SCB_I2CMasterWriteBuf API call that doesn't seem to work unless some sort of long delay is involved. Note that I have sent those three bytes every 100ms with the same results (I can send I2C data every 91us with the blocking API calls), so it doesn't seem like I could be taxing the speed of the I2C interface.

                  • 6. Re: I2C API problem
                    user_242978793

                    100khz clock is the max normal clock frequency.  If you want to run at high speed you need to send a command to the part for that mode and I don't see that in your code.

                       

                    • 7. Re: I2C API problem
                      user_242978793

                      This issue looks like a timing issue and that is why I said drop the clock speed. Also looking at your scope pictures why is the clock signal having missing transitions in it . The bottom two pictures show this and they shouldn't have any issues with the clock. Also just a question you are using pull up resistors on the I2C lines.

                      • 8. Re: I2C API problem
                        juliehardin55_1647776

                        Yes, I've dropped the clock speed but it doesn't change the problem. The Sparkfun board does have 4.7k pullup resistors on the I2C lines.  https://cdn.sparkfun.com/datasheets/BreakoutBoards/MCP4725_Breakout_v14.pdf  

                           

                        The only difference between the bottom 2 pictures and the first is that I used SCB_I2CMasterWriteBuf on the bottom two rather than SCB_I2CMasterSendStart, SCB_I2CMasterWriteByte, and SCB_I2CMasterSendStop on the top one.  The first works for higher clock speeds without sending a special command.  SCB_I2CMasterWriteBuf doesn't work without a CyDelay regardless of clock speed, the frequency of write commands, or sending a special command.

                        • 9. Re: I2C API problem
                          juliehardin55_1647776

                          So the question comes down to the difference between using SCB_I2CMasterWriteBuf (non-blocking, interrupt driven, but not working) and using SCB_I2CMasterSendStart, SCB_I2CMasterWriteByte, and SCB_I2CMasterSendStop (which works but since they are blocking they totally blow my timing budget). Having to use the blocking API calls makes the CYBLE-012011 a non-starter for me.

                          • 10. Re: I2C API problem
                            juliehardin55_1647776

                            I'm still not sure if the CYBLE-012011 will run fast enough, but I found the solution to my issue in another 100days code sample. After the SCB_12CMasterWriteBuf call, I needed to do the following, to wait until the write was complete. Now I can write much faster without needing long delays.

                               


                            while(0u == (SCB_I2CMasterStatus() & SCB_I2C_MSTAT_WR_CMPLT))
                             {
                                 /* Wait until master complete write */
                             }
                                if (0u == (SCB_I2C_MSTAT_ERR_XFER & SCB_I2CMasterStatus()))
                                {
                                    status = CYRET_SUCCESS;
                                }
                             /* Clear I2C master status */
                             (void) SCB_I2CMasterClearStatus();