You are here

Psoc and I2C with PCA9685 | Cypress Semiconductor

Psoc and I2C with PCA9685

Summary: 19 Replies, Latest post by Bob Marlowe on 09 Nov 2016 01:40 AM PST
Verified Answers: 0
Last post
Log in to post new comments.
pmartinez_1655886's picture
User
22 posts

I am trying to port the library provided by Adafruit (https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library)  to use it in my project. 

This library is intended to be used with PCA9685 chip, which provides 16 pwm outputs by the use of the I2C protocol. 

I already have a board from adafruit and tested with an arduino and their library, it works fine. I tried to do the same with psoc but I guess I don't ported it well because it is not working (nothing happens when I try to make a servo to work.

I attach you the project so you can check my code and give me some ideas. I am using the first address (6 different modules can be added. The first one is 0x60, it is wrong in my project but result is the same fixing it).

user_1377889's picture
User
10400 posts

At first: set your I2C component to Byte mode or your target gets bad data.

You are omitting the MasterSendStop() API.

Byte I2C interface is quite simple: After setting up the component (no Enable() needed) and starting it you use

    I2C_MasterSendStart(DeviceAddress,I2C_WRITE_XFER_MODE);    // Initialize a transaction for writing
    I2C_MasterWriteByte(Register);                // Indicate which register you want to write to
    I2C_MasterWriteByte(Value);                // Write to register
    I2C_MasterSendStop();                    // End of transaction

When you want to read from a device you use (example for reading two bytes

    I2C_MasterSendStart(DeviceAddress,I2C_WRITE_XFER_MODE);    // Initialize a transaction for writing
    I2C_MasterWrite(Register);                // Indicate which register you want to write to
    I2C_MasterSendRestart(DeviceAddress,I2C_READ_XFER_MODE);
    I2C_MasterReadByte(I2C_ACK_DATA);            // Read from register
    I2C_MasterReadByte(I2C_NAK_DATA);            // Read from register, last byte is NAKed
    I2C_MasterSendStop();                    // End of transaction

Not too difficult. Keep in mind that most of the APIs (except those for reading a byte) return a status byte which, when non-zero indicate an error condition, do not continue when an error occured. Use that status information at least while testing your connection.

 

Bob

pmartinez_1655886's picture
User
22 posts

Thank you, Bob. I will try and post what I find

pmartinez_1655886's picture
User
22 posts

I have made some changes, define the words you use for write/read operations and tested a bit but it seems to hang as soon as the program go into:

PWM_begin()>PWM_reset()>PWM_write8()>MOTOR_I2CMasterWriteByte(d)(HERE PROGRAM STOPS):

 

void PWM_write8(uint8_t reg, uint8_t d) {
  MOTOR_I2CMasterSendStart(_addr, I2C_WRITE_XFER_MODE);
  MOTOR_I2CMasterWriteByte(reg);
  MOTOR_I2CMasterWriteByte(d);   <------ HERE STOPS
  MOTOR_I2CMasterSendStop();
}

 

I don't know if I should activate something else. I also changed to byte mode I2C block.

user_1377889's picture
User
10400 posts

Change your PWM_write8() to

uint8_t PWM_write8(uint8_t reg, uint8_t d)
{uint8_t Result;
    
    if((Result = MOTOR_I2CMasterSendStart(_addr, I2C_WRITE_XFER_MODE))) return Result;
    if((Result = MOTOR_I2CMasterWriteByte(reg))) return Result;
    if((Result = MOTOR_I2CMasterWriteByte(d))) return Result;
    if((Result = MOTOR_I2CMasterSendStop())) return Result;
    return Result;
}

and check the returned result for != 0. There are descriptions in the associated .h file for error reasons.

 

Bob

pmartinez_1655886's picture
User
22 posts

Ok, I tested. It returns at first if. I2CMasterSendStart with 0x02 response code. If I remove Pullup resistors, I get a 0x04 code. I guess: MOTOR_I2C_MSTR_ERR_LB_NAK and MOTOR_I2C_MSTAT_ERR_ARB_LOST

user_1377889's picture
User
10400 posts

Removing of the pullups will not work at all. Try reducing I2C speed to 100kbps. use 2.2k pullups.

First start address NAKed could mean wrong address. Do you set _addr??? Do you call  PWM_ServoDriver() ???

 

Bob

pmartinez_1655886's picture
User
22 posts

Yes, I call PWM_ServoDriver. First thing in my code. I could replicate the 0x02 error. I have just got 0x04 since I post my previous message. 

I modified data rate to 100 and set slew rate to "Slow". I found those parameters in the datasheet. But this IC also supports 400 and fast rate. 

 

I double checked datasheet to see if the address was ok. I think it is. I have all address entries to 0, so it should be 0x40.

user_1377889's picture
User
10400 posts

  

I call PWM_ServoDriver. First thing in my code.   Quite sure? main() reads

    CyGlobalIntEnable; /* Enable global interrupts. */
    PWM_begin();
    PWM_ServoDriver();

And in PWM_begin() you get the device out of sleep mode but using a wrong I2C address.

 

Bob

 

pmartinez_1655886's picture
User
22 posts

Yes, I fixed it. I saw it also when you pointed about the address. I have been reworking the library a bit basing on libraries for python I found on the internet and now I get a first error of 0x02 (NACK?) and then 0x04 always.

I don't have time today to check something else. Tomorrow I will try to test something else and I will post my updates. I willt ry also setting up another pioneer psoc as slave with address 0x40 and see what happens. 

user_1377889's picture
User
10400 posts

Are you using a -042 BLE Pioneer board?

Use P0_4 and P0_5 for I2C and provide your own 2k2 pullup resistors. The ohter pins are connected to FRam with an address 0x42 which will collide with your chip or with an internal UART-USB bridge which will destroy your sda-line data.

 

Bob

Log in to post new comments.