cancel
Showing results for 
Search instead for 
Did you mean: 

PSoC 5, 3 & 1

joli_601446
Contributor

Hello, I trying to develop a simple I2C program using two PSoC5 CY8CKIT-059's. I have one kit acting as the Master and the other kit as a Slave. The idea is to have the slave PWM control the onboard blue LED. The Slave expects to receive two bytes, byte 1 will turn on the LED and byte 2 will control the PWM frequency. I got it working using the Bridge Control Panel. I was so happy. Here is my code:

int main(void)

{

    uint8 i2cbuff[2];

    CyGlobalIntEnable; /* Enable global interrupts. */

    I2C_Start();

    I2C_SetBuffer1(2,2, i2cbuff);

    i2cbuff[0] = 0;

    PWM_1_WriteCompare1(1);

   

    for(;;)

   {

        if(i2cbuff[0] == 0)     // Byte 0 is the on/off control, if equal to 0 stops the PWM

            PWM_1_Stop();

        else if(i2cbuff[0] == 1)  // Byte 0 is 1 start PWM module

        {

            PWM_1_Start();

            PWM_1_WriteCompare1(255);

        }

    }

}

The Slave was very easy because there was a great PSoC 101 video on the topic and I used EZI2C module.

The problem I now have is getting the Master I2C to work. The Master should send out two bytes to Slave. I have connected together the SCL on both kits and also connected together the SDA pins. Here is my Master Code:

int main()

{

     LED_ON;  //   define macro to turn on blue led

    CyGlobalIntEnable;

    I2CM_Start();

    LED_ON;

    WriteCommandPacket();   // call function to transmit to slave

   return 0;   

}

/*******************************************************************************

* WriteCommandPacket(): Writes command packet to I2C slave

*******************************************************************************/

uint32 WriteCommandPacket(void)

{

    uint8  buffer[2];

    uint32 status = TRANSFER_ERROR;

    uint8 read = 0;

    /* Initialize buffer with packet */

    buffer[0] = 1;

    buffer[1] = 255;

   

    I2CM_MasterClearStatus();

    I2CM_MasterWriteBuf(0x8, (uint8 *) buffer, 2, I2CM_MODE_COMPLETE_XFER);

    read = I2CM_MasterStatus();

    read = I2CM_MasterStatus(); 

   

    while (0u == (I2CM_MasterStatus() & I2CM_MSTAT_WR_CMPLT))

    {

        /* Waits until master completes write transfer */

            LED_OFF;

            CyDelay(1200u);

            LED_ON;

            CyDelay(1200u);

            LED_OFF;

            CyDelay(300u);

            LED_ON;

            CyDelay(300u);

          

    }

   

    LED_OFF;

    I2CM_MasterClearStatus();

    return (status);

}

The MasterStatus return 0x004 which is means the transfer in progress.

I have the Master power using a MiniProg3 and the Slave plugs into my laptop. I measured the voltage on the Master and it is 3.3V and the voltage on the Slave is 5.

Could that be the problem?

Thanks,

Joe

0 Likes
1 Solution
Bob_Marlowe
Expert II

Just had the time to setup test environment.

Try attached project, care for external resistors and connections.

Bob

View solution in original post

0 Likes
29 Replies
joli_601446
Contributor

I found another PSoc5 Kit and snapped off the KitProg so know I have two Kits powered using two MiniProg3 programmers. One laptop has the Master and another laptop has a Slave. Hope this helps.

0 Likes
joli_601446
Contributor

Seems like the Master stays in the "Transfer in Progress" state and the transfer never completes. Any ideas?

Thanks,

Joe

0 Likes
Bob_Marlowe
Expert II

A few changes:

At first set both (master and slave) to the same speed (i.e. 100kbs) using internal clock.

For Master p12_0 and P12_1 is ok. For the slave use a different set as P12[5:4] to avoid doubly pull-up resistors.

EZI2C protocol is: First byte address, second(and following bytes) data

So when you send "1,255" you will receive in your slave buffer[1] the value 255. You never test for that.

You issue multiple starts and stops to your PWM even when the I2C data did not change. Could be done better when you wait for a successful transfer, then check the data and act accordingly.

And at last a hint: To make life(and debugging) easier you may create I2C Master and Slave un the same device with external connections.

Happy coding

Bob

0 Likes
joli_601446
Contributor

Thanks Bob! I'll try your suggestions and let you know if I have any problems.

Thanks again!

0 Likes
joli_601446
Contributor

Bob,

HI, I've made a project with a Master and Slave module. Two quick questions for you. Do I need to use pull-up resistors on the SCL and SDA external pins? Last, what drive mode should I use for the SDA and SCL for Master pins and the Slave pins?

Thanks,

Joe

0 Likes
Bob_Marlowe
Expert II

The CY8CKIT-059 prototyping kit has got pullups at pins P12_0 and P12_1 already. Connect those to the I2C master. Of course you may use different pins, but then you need to provide your own pullup resistrors.

AllI2C pins should be "Open Drain drives low". This ensures that the pullup resistors care for the "High" state and that any device can pull a signal low.Needed for slave clock stretching.

Bob

0 Likes
joli_601446
Contributor

Bob,

Hello, I have removed the external pull-ups and changed the pin mode to Open Drain drives Low.  Here is my code:

#include "project.h"

#include "header.h"

int main()

{

    uint8 i2cbuff[1];

    uint8 compare = 0;

    i2cbuff[0]=3;  

    I2C_SetBuffer1(1,1, i2cbuff);  

    I2CM_Start();  // start master

    I2C_Start();  // start slave

    CyGlobalIntEnable;

    WriteCommandPacket();  

    PWM_1_Start();

    PWM_1_WriteCompare1(1);

  

    for(;;)

    {

        if(compare != i2cbuff[0])

        {

            PWM_1_WriteCompare1(i2cbuff[0]);

            compare = i2cbuff[0];

        }

  }

  return 0;  

}

/*******************************************************************************

* WriteCommandPacket(): Writes command packet to I2C slave

*******************************************************************************/

uint32 WriteCommandPacket(void)

{

    uint8  buffer[1];

    uint32 status = TRANSFER_ERROR;

    uint8 read = 0;

    uint32 i2cmWriteSize = 0;

    /* Initialize buffer with packet */

    buffer[0] = 255;

  

    I2CM_MasterClearStatus();

    I2CM_MasterWriteBuf(0x8,  buffer, sizeof(buffer), I2CM_MODE_COMPLETE_XFER);

    read = I2CM_MasterStatus();

    read = I2CM_MasterStatus();

  

    /* Waits until master completes write transfer */

    while(0u == (I2CM_MasterStatus() & I2CM_MSTAT_WR_CMPLT));

  

    i2cmWriteSize = I2CM_MasterGetWriteBufSize();

    I2CM_MasterClearStatus();

    return (status);

}

When I step through the code it never finishes the command:

while(0u == (I2CM_MasterStatus() & I2CM_MSTAT_WR_CMPLT));

I have have 12[5] SDA connected to 12[1]. I have 12[4] SCL connected to 12[0]. If you could quickly look over what I have attached perhaps you may see what I'm doing wrong. I did attach an o-scope to the SCL and I only saw three low going saw tooth pulses, but that was with the wrong Pin mode settings. I'll try again.

Thank you very much,

Joe

0 Likes
joli_601446
Contributor

I decided to try a different kit. The one that I was using I snapped off the KitProg. I decided to try a brand new kit with the KitProg still attached. I was able to get past the line:

while(0u == (I2CM_MasterStatus() & I2CM_MSTAT_WR_CMPLT));

and the line

  i2cmWriteSize = I2CM_MasterGetWriteBufSize();

showed that i2cmWriteSize was 1 which is what I expect, 1 Byte was sent.

However, the receive buffer uint8 i2cbuff[1] did not show the value of 255 which the Master sent. Maybe I'm getting closer. Any ideas?

thanks,

Joe

0 Likes
Bob_Marlowe
Expert II

Look for changes I made.

Bob

0 Likes
joli_601446
Contributor

Bob,

Thank you very much for those additions to the code. I did run the code on a complete PSoC CYCKit-059 and it did get past the line Wait() function, but there was nothing in the receiver buffer, only 0's. If I run the code only on a PSoc 5LP (Target only) the code never gets past the Wait() function. I have wires connecting the SDA lines and the SCL lines together and not using any external pull-up resistors. Can you think of anything outside of the code that could be cause this problem. I did connect connect an oscope on the SCL lines but did not see a clock. Do I need to run the Kit at 5V instead of 3.3V?

Thank you,

Joe

0 Likes
joli_601446
Contributor

Bob,

Hi, it appears when using the Target and the KitProg the value returned by the line:

read = I2CM_MasterStatus();

is 0x92 which on page 21/61 of the I2C Master doc means the following bits were set:

I2C_MSTAT_WR_CMPLT

I2C_MSTAT_ERR_SHORT_XFER: write xfer completed before all bytes were transfered

I2C_MSTAT_ERR_XFER

I don't see any transitions on the SDA or SCL pins on the o-scope.

If I run with only the Target (KitProg broken off) then the it never gets past the Wait() call. Could this be a MiniProg configuration?

I'll look over the EZI2C doc and maybe I'll find something.

Joe

0 Likes
joli_601446
Contributor

I ran the code with the Target only and if you wait long enough it will get past the Wait() call and the call read = I2CM_MasterStatus(); return 0x92. Maybe that will help find what the problem is. Joe

0 Likes
joli_601446
Contributor

I was reading page 4/24 of the EZI2C Slave ver 2.0 and under Pin connections I decided to choose I2C1 option which set SCL to 12.0 and SDA to 12.1. I was already using these two pins for those functions but decided to try something. After running the code on the Target only it did get past the Wait() and it returned 0xA2 from the I2C_MasterStatus() call. The error 0xA2 says the Slave is not acking back. I'll keep working on it.

0 Likes
joli_601446
Contributor

Hello, well I've made some progress. Below is a screen shot of one Master write:

scope_0.bmp

I have not used the Serial Decode on the scope before but I believe the first word it the address, the next word is the Address within the EZI2C Buffer, and the last is the data that is transmitted (decimal  201). So, it looks like I'm transmitting okay. I did change some pins to the following:

Master:

SDA: P12[3]

SCL: P0[1]

Slave:

SDA: P12[1]

SCL: P12[0]

I am using the PSoc5 Kit with the ProgKit and the Target connected together.

Now, here's my problem the EZI2C Slave buffer is not getting filled with the data. The line I2CM_MasterStatus() returns the hex value of 0x92 which I think means the Slave did not acknowledge the address. I'll start looking into this problem next.

Joe

0 Likes
joli_601446
Contributor

Hello, just letting everyone know that I got the code working with only the Target PSoc5 device. I was not using pull-up resistors on SDA/SCL. However, I'm still not getting anything on the EZI2C Slave Buffer. I've attached my lastest code version.

Thanks,

Joe

0 Likes
joli_601446
Contributor

Now I broke it, I got the bits swapped in the address so now I'm transmitting 0x10 instead of 0x08, not sure what I did in the code. However, the data is still correct and the EZI2C address with in the buffer is still correct.

0 Likes
joli_601446
Contributor

I found another post (Re: I'm using an I2C Master component (tried both fixed and UDB) when I2C_1_GENERATE_START_MANUAL is... ) where it stated, "When you address a slave at 0x7f the master will send a 0xf7 or 0xff. Last bit is for read and write (0,1)."

In my case the Slave address is 0x08, so I should see 0x80.

scope_1.bmp

0 Likes
joli_601446
Contributor

I did my homework and studied how I2C works and now I understand why 0x10 is being sent first.

Slave Address is 0x8:

0000 1000

Take the upper 7 bits

0001 000x

because I'm doing a write, we place a 0 in the the bit[0] place

0001 0000

Therefore we we have 0x10

Now that I understand how the address is sent I'm back to trying to get the Slave Receive buffer to be written to.

0 Likes
ScWi_1017771
New Contributor II

Just to check the basics:

1. You mentioned connecting SDA and SCL. Is there a good ground

connection as well? Preferably direct and short, not e.g. through wall-bug

cables and a power strip.

2. How long will the connections be in the final application? I2C was

originally designed to be a low-cost, on-board inter-IC bus (when logic

gates were far more expensive). It is high impedance (several-kOhm

pullups), has low noise immunity, little tolerance for common-mode ground

differences (a few hundred millivolts), etc.

3. You mentioned different supply voltages. Pullups should be to the

lower supply voltage.

4. Sorry, any chance that the SDA and SCL connections are swapped?

0 Likes
joli_601446
Contributor

Hello, here is a picture of my setup. I'm only using a PSOC5 Kit with only the Target device. If I swap my connections, I don't see any decoding on the scope, so I believe my pins are connected problem. I have to the o-scope set to Trigger on a Frame (Start, Addr7, Write, Ack, Data) and seems to be triggering every time I do a MasterWriteBuf.

IMG_4162.JPG

I will upload my recent software, perhaps my setup is not correct?

Thanks,

Joe

0 Likes
joli_601446
Contributor

If I understanding the o-scope output correctly I get an ACK after the Slave Address, I get an ACK after the Register Address, but I get a NACK after the Data Byte.

0 Likes
Bob_Marlowe
Expert II

This is correct. The last byte sent must be NAKed by the master.

​Bob

0 Likes
joli_601446
Contributor

Great! Thanks Bob!

Any ideas why the SlaveBuffer is empty after the Master transmits?

0 Likes
joli_601446
Contributor

Bob, does the Master NACK at the end of the bytes he is sending, or NACKS back af the end of the data the Slave is sending? I ask because was reading the document SLVA704.pdf  "Understanding The I2C Bus" from TI

http://www.ti.com/lit/an/slva704/slva704.pdf

On page 6 it give some reasons for a NACK at the end of a transfer. I'm not an expert with I2C, in fact this is my first experience with I2C.

I'll keep trying to figure things out.

Thanks Bob!

0 Likes
joli_601446
Contributor

Bob,

Hello, because I'm getting the ACK from the Slave after the Address and the Register Address could you say that at least we know the connections between the Master and Slave are good? So, the problem must be in the code, do you agree?

Thanks,

Joe

0 Likes
joli_601446
Contributor

The original post was connecting two PSoc5 kits together but I'm not doing that now, I'm trying to get a Master and Slave working on a single kit. So I won't be posting anything until I get that one working.  Thanks everyone for your inputs.

Joe

0 Likes
Bob_Marlowe
Expert II

Just had the time to setup test environment.

Try attached project, care for external resistors and connections.

Bob

View solution in original post

0 Likes
joli_601446
Contributor

Bob,

Hello, thank you for the example. I did get the things working using the EZI2C Slave, turns out that I needed to call the Slave Start before setting up the Slave Buffer1 function. I notice that you did not use the EZI2C module, that is good because now I have a great example to follow for future I2C comms.

Now I was going to spend a little time trying to have one PSOC Target as Master and another PSOC Target has Slave and connect them together. I'm using two MicroProg3's for each Target. I first run the Slave board in Debug mode and then run the Master board in debug mode, then I have the Master send data, when I pause the Slave board the code is in a forever while loop in the Start() function. Now sure why this is. I am using external pull-up and have both boards using the same ground, I connected the grounds together. If you have any ideas, please let me know.

0 Likes
joli_601446
Contributor

I got it running! I think it was my cheap breadboard the pull-up resistors weren't making a good connection when I was testing with two PSoc Targets and the I had to run the Slave Start before initializing the SlaveBuff1.

I thank everyone that helped me get this going, especially Bob.

Thanks everyone!!

0 Likes