PCA9539 gpio expander I2C driver help

Thread Starter

zazas321

Joined Nov 29, 2015
926
Hello. I am trying to write my own I2C expansion driver. I would like to get some clarifications from someone who have some experience developed some I2C drivers before.

I am refering to this datasheet:
https://www.ti.com/lit/ds/symlink/pca9539.pdf?ts=1634021411392&ref_url=https%3A%2F%2Fwww.google.com%2F


All I am trying to do at this moment is to develop 2 functions:

1. Writing to register
2. Reading from register


My code:

Code:
#include "PCA9539.h"

static const char *TAG = "PCA9539";

#define I2C_MASTER_SCL_IO           22      /*!< GPIO number used for I2C master clock */
#define I2C_MASTER_SDA_IO           21      /*!< GPIO number used for I2C master data  */
//#define I2C_MASTER_SCL_IO           1      /*!< GPIO number used for I2C master clock */
//#define I2C_MASTER_SDA_IO           2      /*!< GPIO number used for I2C master data  */
#define I2C_MASTER_NUM              0                          /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ          400000                     /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE   0                          /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE   0                          /*!< I2C master doesn't need buffer */
#define I2C_MASTER_TIMEOUT_MS       1000   



#define PCA9539_SENSOR_ADDR                 0x74        /*!< Slave address of the PCA9539 sensor A0 A1 BOTH L*/

#define WRITE_BIT 0
#define READ_BIT 1
#define ACK_CHECK_EN 0x1                        /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 
#define ACK_VAL I2C_MASTER_ACK                             /*!< I2C ack value */
#define NACK_VAL I2C_MASTER_NACK                          /*!< I2C nack value */

//B2 B1 B0
#define INPUT_PORT_0 0x00
#define INPUT_PORT_1 0x01

#define OUTPUT_PORT_0 0x02
#define OUTPUT_PORT_1 0x03

#define POLARITY_INVERSIOR_PORT_0 0x04
#define POLARITY_INVERSIOR_PORT_1 0x05

#define CONFIGURATION_PORT_0 0x06
#define CONFIGURATION_PORT_1 0x07


// write bit = 0
// READ bit = 1
static esp_err_t PCA_9539_read_reg(i2c_port_t i2c_num, uint8_t reg, uint8_t* data_rd)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (PCA9539_SENSOR_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN); // first send the address with least significant set to 0
    i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); // then send the command byte


    i2c_master_read_byte(cmd, data_rd, NACK_VAL);


    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}



static esp_err_t PCA9539_write_reg(i2c_port_t i2c_num, uint8_t reg, uint8_t data) {

    ESP_LOGI(TAG,"write reg MCP port %d address %d", i2c_num, PCA9539_SENSOR_ADDR);
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (PCA9539_SENSOR_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN); // send address
    i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); // send register(command byte)
    i2c_master_write_byte(cmd, data, ACK_CHECK_EN); // send data
    i2c_master_stop(cmd);

    esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000/portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    if( ret != ESP_OK ) {
        ESP_LOGE(TAG,"Error writing register %d",reg);
        return ESP_FAIL;
    }
    return ESP_OK;
}



esp_err_t i2c_master_init()
{
    int i2c_master_port = I2C_MASTER_NUM;

    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };

    i2c_param_config(i2c_master_port, &conf);

    return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}


void i2c_setup()
{
    ESP_ERROR_CHECK(i2c_master_init());
    ESP_LOGI(TAG, "I2C initialized successfully");
}

My main concerns and questions:

1.In the PCA9539 datasheet, 8.3.1 section, the last paragraph mentions:

"A master receiver signals an end of data to the slave transmitter by not generating an acknowledge (NACK) after
the last byte has been clocked out of the slave. This is done by the master receiver by holding the SDA line high.
In this event, the transmitter must release the data line to enable the master to generate a Stop condition."

Does that mean that I must end the write/read transaction with the NACK ?
If so, that means I would need to change my write_reg function to the following:



2.I cannot get my head around on how to develop the read_register function correctly. I have read the section 8.3.2.4.2 and It says that I must first start with the address with least significant bit set to logic 0. After that I can send the command byte. Then it says :
"After a restart, the device address is sent again, but this time, the least-significant bit is set to a logic 1. ". I dont understand what it means after restart? Could someone explain to me what is a restart in I2C terms? Surely that is not device restart.

There are read from register examples such as:
Hello. I am trying to write my own I2C expansion driver. I would like to get some clarifications from someone who have some experience developed some I2C drivers before.

I am refering to this datasheet:
https://www.ti.com/lit/ds/symlink/p...11392&ref_url=https%3A%2F%2Fwww.google.com%2F


All I am trying to do at this moment is to develop 2 functions:

1. Writing to register
2. Reading from register


My code:

Code:
#include "PCA9539.h"

static const char *TAG = "PCA9539";

#define I2C_MASTER_SCL_IO           22      /*!< GPIO number used for I2C master clock */
#define I2C_MASTER_SDA_IO           21      /*!< GPIO number used for I2C master data  */
//#define I2C_MASTER_SCL_IO           1      /*!< GPIO number used for I2C master clock */
//#define I2C_MASTER_SDA_IO           2      /*!< GPIO number used for I2C master data  */
#define I2C_MASTER_NUM              0                          /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ          400000                     /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE   0                          /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE   0                          /*!< I2C master doesn't need buffer */
#define I2C_MASTER_TIMEOUT_MS       1000    



#define PCA9539_SENSOR_ADDR                 0x74        /*!< Slave address of the PCA9539 sensor A0 A1 BOTH L*/ 

#define WRITE_BIT 0
#define READ_BIT 1
#define ACK_CHECK_EN 0x1                        /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0  
#define ACK_VAL I2C_MASTER_ACK                             /*!< I2C ack value */
#define NACK_VAL I2C_MASTER_NACK                          /*!< I2C nack value */

//B2 B1 B0
#define INPUT_PORT_0 0x00
#define INPUT_PORT_1 0x01

#define OUTPUT_PORT_0 0x02
#define OUTPUT_PORT_1 0x03

#define POLARITY_INVERSIOR_PORT_0 0x04
#define POLARITY_INVERSIOR_PORT_1 0x05

#define CONFIGURATION_PORT_0 0x06
#define CONFIGURATION_PORT_1 0x07


// write bit = 0
// READ bit = 1
static esp_err_t PCA_9539_read_reg(i2c_port_t i2c_num, uint8_t reg, uint8_t* data_rd)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (PCA9539_SENSOR_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN); // first send the address with least significant set to 0
    i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); // then send the command byte


    i2c_master_read_byte(cmd, data_rd, NACK_VAL);


    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}



static esp_err_t PCA9539_write_reg(i2c_port_t i2c_num, uint8_t reg, uint8_t data) {

    ESP_LOGI(TAG,"write reg MCP port %d address %d", i2c_num, PCA9539_SENSOR_ADDR);
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (PCA9539_SENSOR_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN); // send address
    i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); // send register(command byte)
    i2c_master_write_byte(cmd, data, ACK_CHECK_EN); // send data
    i2c_master_stop(cmd);

    esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000/portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    if( ret != ESP_OK ) {
        ESP_LOGE(TAG,"Error writing register %d",reg);
        return ESP_FAIL;
    }
    return ESP_OK;
}



esp_err_t i2c_master_init()
{
    int i2c_master_port = I2C_MASTER_NUM;

    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };

    i2c_param_config(i2c_master_port, &conf);

    return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}


void i2c_setup()
{
    ESP_ERROR_CHECK(i2c_master_init());
    ESP_LOGI(TAG, "I2C initialized successfully");
}

My main concerns and questions:

1.In the PCA9539 datasheet, 8.3.1 section, the last paragraph mentions:

"A master receiver signals an end of data to the slave transmitter by not generating an acknowledge (NACK) after
the last byte has been clocked out of the slave. This is done by the master receiver by holding the SDA line high.
In this event, the transmitter must release the data line to enable the master to generate a Stop condition."

Does that mean that I must end the write/read transaction with the NACK ?
If so, that means I would need to change my write_reg function to the following:



2.I cannot get my head around on how to develop the read_register function correctly. I have read the section 8.3.2.4.2 and It says that I must first start with the address with least significant bit set to logic 0. After that I can send the command byte. Then it says :
"After a restart, the device address is sent again, but this time, the least-significant bit is set to a logic 1. ". I dont understand what it means after restart? Could someone explain to me what is a restart in I2C terms? Surely that is not device restart.

There are read from register examples such as:
1634031716813.png

But as you can see, something is not right here, because it starts with the address and the least significant bit set to 1. Why is the least significant bit set to 1 if the 8.3.2.4.2 sections says that it must start with 0?

But as you can see, something is not right here, because it starts with the address and the least significant bit set to 1. Why is the least significant bit set to 1 if the 8.3.2.4.2 sections says that it must start with 0?
 
I have seen datasheets that specify not acknowledging data before and have not had any problems ignoring what it says (mainly because the PIC I was using didn't have the ability to specify a NACK condition).

There is a "restart" condition that can be used with I2C that they may be referring to. It is a bit different from a normal stop and start and that may be where the ACK / NACK requirements come in to play.

Generally for a read you would first send the device write address followed by the data address you want to read and stop.
Next you would send the device read address then read how ever many bytes you need and stop.

I would use the following to set up the read...
Code:
static esp_err_t PCA9539_write_reg(i2c_port_t i2c_num, uint8_t reg) {
    ESP_LOGI(TAG,"write reg MCP port %d address %d", i2c_num, PCA9539_SENSOR_ADDR);
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (PCA9539_SENSOR_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN); // send address
    i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); // send register(command byte)
    i2c_master_stop(cmd);

    esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000/portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    if( ret != ESP_OK ) {
        ESP_LOGE(TAG,"Error writing register %d",reg);
        return ESP_FAIL;
    }
    return ESP_OK;
}
Then it should be set to read whatever data address you need.
 
1.In the PCA9539 datasheet, 8.3.1 section, the last paragraph mentions:

"A master receiver signals an end of data to the slave transmitter by not generating an acknowledge (NACK) after
the last byte has been clocked out of the slave. This is done by the master receiver by holding the SDA line high.
In this event, the transmitter must release the data line to enable the master to generate a Stop condition."

Does that mean that I must end the write/read transaction with the NACK ?
If so, that means I would need to change my write_reg function to the following:
I thought about this a bit more and decided to do a quick test. On my ESP12F the NACK was set after reading the last byte automatically. I didn't have to do anything different. According to the I2C specification that is the way it is supposed to happen, but in all reality a stop condition should be enough.

i2c.jpg
 
Top