I2C Get Byte, Print over UART

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

Hello,

   

I seem to be having some trouble setting up I2C, and/or formatting the data to view it over the UART.  I'm hoping someone can please identify my error(s) and help me to correct them.

   

I am using the PSoC4 Pioneer kit.

   

I have connected to the SCL/SDA the corresponding pins of an MCP9808 breakout board (and +5V/GND).
MCP9808 I2C Address: 0x18
MCP9808 Temperature Register: 0x05  (2 Byte data output)

   

​I have confirmed with a different MCU/FW setup that the MCP9808 is working correctly over I2C.

   

The output I2C data out (Address and Register seem to be sending correctly) I see on the scope is not data I would expect - which leads me to believe that my I2C protocol is incorrect.
The scope data is also not what I'm seeing reported in TeraTerm - so I may have data formatting issues too.
I am seeing my UART test reported in TeraTerm, so that seems to be fine.

   

Any guidance would be greatly appreciated!  Thank you.

   
     #include <MCP9808.h>
#include <stdio.h>
   
   
     #define MCP_I2C_ADDRESS 0x18
#define MCP_REGISTER 0x05
uint32 MCP_temp[2];
   
   
     void Get_Temp(void);   
   
     int main()
{   
    /* Initialization of Variables */
        char OutputString[2];
    
    /* Initialization / Startup */
        I2C_Start();
        UART_Start();
   
    /* Enabling the Global Interrupt */ 
        CyGlobalIntEnable;
                      
    /* Application code */
        UART_UartPutString("\r\nGet Temp: CONNECTED \r\n");     //Check UART/Terminal connection
    
    for(;;)
    {
        /* Call the function to get the current temp via I2C */        
        Get_Temp();
        
        /* Store formatted data as string */
        sprintf(OutputString, "%lu", MCP_temp);
        
        /* Print the received temp to Hyperterminal  */ 
        UART_UartPutString(OutputString);  
        UART_UartPutString("\r\n");
        
        CyDelay(1000);
    }
   
} /* END MAIN() */
   
   
     /*******************************************************************************
* Function Name : Get_Temp
********************************************************************************
* Summary:
*   It receives the current temp from the MCP9808 in the Current_temp array. 
*
* Parameters:
*   None
*
* Return Value:
*   None
*******************************************************************************/
   
   
     void Get_Temp(void)
{  
    //Initialize Transaction for Writing
    I2C_I2CMasterSendStart(MCP_I2C_ADDRESS, I2C_I2C_WRITE_XFER_MODE);
    
    //Indicate Register to Write to
    I2C_I2CMasterWriteByte(MCP_REGISTER);
    I2C_I2CMasterSendRestart(MCP_I2C_ADDRESS, I2C_I2C_READ_XFER_MODE);
    
    //Read from Register (2 Bytes, last byte NAKed)
    MCP_temp[0] = I2C_I2CMasterReadByte(I2C_I2C_ACK_DATA);    
    MCP_temp[1] = I2C_I2CMasterReadByte(I2C_I2C_NAK_DATA);
    
    //End Transaction
    I2C_I2CMasterSendStop();
    
} /* END GET_TEMP */    
   
   
     /* END FILE */   
0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Archive is not compilable, lots(!!) of projects and missing .h-files.

   

 

   

uint32 MCP_temp[2]; This makes MCP_temp an array, thus the reference to MCP_temp is the address of that array.

   

        char OutputString[2]; This is a two-byte array. As a string, the last byte needs to carry the string terminator 0x00.

   

        sprintf(OutputString, "%lu", MCP_temp); This will fill OutputString with more than one character(!!!) thus clobbering your stack

   

I2C: set byte mode.

   

See attaced project. Take care not to overwrite your original.

   

 

   

Bob

View solution in original post

0 Likes
11 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Welcome in the forum.

   

At first sight: You are overwriting your OutputString which is only 2 bytes in length when you call sprintf().

   

Next time better post your complete project, so that we all can have a look at all of your settings. To do so, use
Creator->File->Create Workspace Bundle (minimal)
and attach the resulting file.

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi Bob,

   

Thank you for that.  I have attached the bundle as requested.

   

I apologize - I don't think I'm clear on what you mean though regarding the sprintf function.  
My intent was to convert the two-byte read from the sensor (MCP_temp) into characters (OutputString) to output into TeraTerm. I see that it is throwing warnings.  My interpretation was that the format is sprintf(output_buffer, "%format", data_to_convert), is that incorrect?  

   

Thank you for helping me to understand, I appreciate your assistance.  

0 Likes
lock attach
Attachments are accessible only for community members.
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Archive is not compilable, lots(!!) of projects and missing .h-files.

   

 

   

uint32 MCP_temp[2]; This makes MCP_temp an array, thus the reference to MCP_temp is the address of that array.

   

        char OutputString[2]; This is a two-byte array. As a string, the last byte needs to carry the string terminator 0x00.

   

        sprintf(OutputString, "%lu", MCP_temp); This will fill OutputString with more than one character(!!!) thus clobbering your stack

   

I2C: set byte mode.

   

See attaced project. Take care not to overwrite your original.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

Bob,

   

Thank you - I see that's a much more efficient way to get multiple bytes out.

   

Thank you also for your help and comments in the data types for the variables, and the functions.  I did try to use pointers while I was trying to figure this out, piecing together different examples.

   

I'm happy to share that thanks to your help and explanations, I am reporting correct temperatures.  I look forward to expanding the project (and also possibly not putting as many projects into a workspace?)

   

Cheers!

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

You are always welcome!

   

 

   

Bob

0 Likes
Anonymous
Not applicable

okeee, i downloaded the code and copied it and it worked once, after i powered on and off the slave i'm trying to talk to... but once i stop the program (Psoc creator 4) and restart i get strange errors of "master not ready" from the sendstart command; upon trying it again, sometimes get a 1 ("master lost arbitration")... i don't understand how the "master" can not be ready when the only commands are:

   

   I2C_2_Start();    
    CyGlobalIntEnable;

   

errStat = I2C_2_I2CMasterSendStart(0x77,I2C_2_I2C_WRITE_XFER_MODE); // this is where i get a 4 or a 1 for errStat

   

errStat = I2C_2_I2CMasterWriteByte(0xE0);        // register with device ID

   

errStat = I2C_2_I2CMasterSendRestart(0x77,I2C_2_I2C_READ_XFER_MODE);

   

byteRead = I2C_2_I2CMasterReadByte(I2C_2_I2C_ACK_DATA) & 0x00ff;    
byteRead |= (I2C_2_I2CMasterReadByte(I2C_2_I2C_NAK_DATA) <<8) & 0x00ff;    

   

thanks for your posts

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

@mfarkas: Welcome in the forum.

   

Can you please post your complete project, so that we all can have a look at all of your settings. To do so, use
Creator->File->Create Workspace Bundle (minimal)
and attach the resulting file. Additionally a link to the datasheet of the device you want to talk to.

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

wow... fast response...

   

the data sheet has a watermark that reads "confidential", so i reckon i shouldn't attach it... 

   

btb, i re-ran it again, and even after resetting the device i got the "master lost arbitration" (a 1) error when trying to execute the restart

   

thanks for your help

0 Likes
Anonymous
Not applicable

it mentions this to perform a read:

   

1. Write the slave address followed by the Write flag 1’b0
2. Write the register address followed by a Stop instruction
3. Write the slave address followed by the Read flag 1’b1
4. Read as many data bytes while the internal sub-address is auto-incremented

   

i assume 1. is sendstart, 2. is writebyte, sendrestart (have tried a stop as well here) 3. is readbyte

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Set I2C to byte mode.

   

Insert an infinite loop at end of main() to hinder a restart of the project.

   

The error can be caused by bad hardware / pullup resistors / wrong I2C address. Best is to use a logic analyzer to watch the communication.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

thanks very much... i checked byte mode; i'll investigate the hardware... if i reset (unplug and plug) the psoc and power off and on the slave, the thing seems to read from it, but not expected data...

   

thanks again

   

matt

0 Likes