PCAL9714 sample code review

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

PCAL9714 sample code review

Jump to solution
50 Views
ahmedd
Contributor II

Hi everyone,

I am trying to write to the register and read it back but it didnt give the same value. I would appreciate if someone would look into my code and correct me. I am using arduino Uno

This is the ino file

#include <Arduino.h>
#include <SPI.h>
#include <stdint.h>
#include "pcal9714.h"

void setup() {
    Serial.begin(9600);
    uint8_t debounce_pins_port0 = 0xFF; // to enable debounce on all pins of port 0
    uint8_t debounce_pins_port1 = 0xFF; // to enable debounce on all pins of port 1
    uint16_t debounce_counter_value = 10;        // debounce time of 10 microseconds
    
    pcal9714_configure_debounce(debounce_pins_port0, debounce_pins_port1, debounce_counter_value);

    // Set all pins you want to monitor as inputs with internal pull-up
    for (uint8_t pin = 0; pin < 8; pin++) {
      pcal9714_set_mode(pin, INPUT_PULLUP);

    }

    // Write a test value to a register
    uint8_t testValue = 0xAA; // Example test value (170 in decimal)
    pcal9714_write(PCAL_CONF_PORT0, testValue);

    // Read the value back
    uint8_t readBackValue = pcal9714_read(PCAL_CONF_PORT0);

    // Print the read back value to the serial monitor
    Serial.print("Wrote: 0x");
    Serial.print(testValue, HEX);
    Serial.print(", Read back: 0x");
    Serial.println(readBackValue, HEX);


        // Set GPIOEXP_LIMIT_SWITCH_HOME_Y_V10 as an output
    pcal9714_set_mode(GPIOEXP_LIMIT_SWITCH_HOME_Y_V10, OUTPUT); // Set the pin as output

    // Set the pin high
    pcal9714_set_pin(GPIOEXP_LIMIT_SWITCH_HOME_Y_V10, HIGH); // Drive the pin high

    // Add a short delay to observe the pin voltage with a multimeter
    delay(1000); // Wait for 1 second

    // Set the pin low
    pcal9714_set_pin(GPIOEXP_LIMIT_SWITCH_HOME_Y_V10, LOW); // Drive the pin low

    // Add another short delay to observe the pin voltage with a multimeter
    delay(1000); // Wait for 1 second


    Serial.println("Direct pin test setup complete.");

}

void loop() {
    // Read the state of a pin (for example, P0_2) and print it to the serial monitor
  int limitSwitchValue = pcal9714_read_pin(GPIOEXP_LIMIT_SWITCH_HOME_Y_V10);
  
  // Print the state to the serial monitor
  Serial.print("Limit Switch State: ");
  Serial.println(limitSwitchValue);

  // Add a delay to prevent flooding the serial monitor
  delay(500);

  static bool pinState = LOW;
  pcal9714_set_pin(GPIOEXP_LIMIT_SWITCH_HOME_Y_V10, pinState);
  pinState = !pinState; // Toggle the state
  delay(1000); // 1 second delay

       
}

 

cpp file

#include <Arduino.h>
#include "pcal9714.h"
#include <SPI.h>


/**
********************************************************************************
* @file pcal9714.cpp
* @author ahmed
* @date 2024-04-22
* @brief Implementation of the pcal9714 driver.
********************************************************************************
*/

/// @brief Configure the pcal9714 device.
void pcal9714_init(void)
{

pinMode(PCAL9714_SPI_CS_PIN, OUTPUT);
digitalWrite(PCAL9714_SPI_CS_PIN, HIGH); // Deselect the device
SPI.begin(); // Initialize SPI communication

}

/// @brief Set the value of a pin on the pcal9714 device.
///  channel Channel number.
///  value 1 for high, 0 for low.
void pcal9714_set_pin(uint8_t channel, uint8_t value)
{
uint8_t port = channel / 8; // Determine port (0 or 1)
uint8_t pin = channel % 8; // Determine pin within the port

uint8_t portValue = pcal9714_read_port(port); // Read current port value

if (value) {
portValue |= (1 << pin); // Set the pin to HIGH
} else {
portValue &= ~(1 << pin); // Set the pin to LOW
}

pcal9714_write(PCAL_OUT_PORT0 + port, portValue); // Write to the output port

}

/// @brief Read the value of a pin on the pcal9714 device.
///  channel Channel number.
/// @return The value of the pin.
uint8_t pcal9714_read_pin(uint8_t channel)
{
uint8_t port = channel / 8;
uint8_t pin = channel % 8;

uint8_t portValue = pcal9714_read_port(port);
return (portValue >> pin) & 0x01;
}

/// @brief Set the mode of a pin on the pcal9714 device.
///  channel Channel number.
///  value 1 for high impedence input, 0 for output.
void pcal9714_set_mode(uint8_t channel, uint8_t mode) {
uint8_t port = channel / 8;
uint8_t pin = channel % 8;

// Setting the overall port configuration for push-pull if we're setting the pin as an output
if (mode == OUTPUT) {
uint8_t out_conf = pcal9714_read(PCAL_OUT_CONF_REG);
out_conf |= 0x03; // Set the ports to push-pull mode
pcal9714_write(PCAL_OUT_CONF_REG, out_conf);

// Set the individual pin configuration for pull-up if required
uint8_t out_conf_reg = (port == 0) ? PCAL_OUT_CONF_REG0 : PCAL_OUT_CONF_REG1;
uint8_t out_conf_value = pcal9714_read(out_conf_reg);
out_conf_value |= (1 << pin); // Enable pull-up for the pin
pcal9714_write(out_conf_reg, out_conf_value);
}

// Then set the pin direction (input/output)
uint8_t config_reg = (port == 0) ? PCAL_CONF_PORT0 : PCAL_CONF_PORT1;
uint8_t current_config = pcal9714_read(config_reg);

if (mode == OUTPUT) {
current_config &= ~(1 << pin); // Clear the bit to set it as output
} else {
current_config |= (1 << pin); // Set the bit to set it as input
}

pcal9714_write(config_reg, current_config);
}


void pcal9714_configure_debounce(uint8_t debounce_pins_port0, uint8_t debounce_pins_port1, uint8_t debounce_counter_value) {
// Initialize SPI communication
pcal9714_init();

// Set up the switch debounce enable registers for port 0 and port 1
pcal9714_write(PCAL_DEBOUNCE_EN_REG0, debounce_pins_port0);
pcal9714_write(PCAL_DEBOUNCE_EN_REG1, debounce_pins_port1);

// Write the debounce counter value to the debounce count register
pcal9714_write(PCAL_DEBOUNCE_COUNT, debounce_counter_value);
}


/// @brief Write a value to a register on the pcal9714 device.
///  addr Address of the register.
///  value Value to write.
void pcal9714_write(uint8_t addr, uint8_t value)
{
digitalWrite(PCAL9714_SPI_CS_PIN, LOW); // Select the device
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

SPI.transfer(addr); // Send the address
SPI.transfer(value); // Send the value

SPI.endTransaction();
digitalWrite(PCAL9714_SPI_CS_PIN, HIGH); // Deselect the device

}

/// @brief Read a value from a port on the pcal9714 device.
///  port port addr
/// @return value of the port
uint8_t pcal9714_read_port(uint8_t port)
{
uint8_t regAddr = (port == 0) ? PCAL_INP_PORT0 : PCAL_INP_PORT1;
return pcal9714_read(regAddr);
}

/// @brief Read a value from a register on the pcal9714 device.
///  addr Address of the register.
/// @return Value read from the register.
uint8_t pcal9714_read(uint8_t addr)
{
uint8_t read_value = 0;

digitalWrite(PCAL9714_SPI_CS_PIN, LOW); // Select the device
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

SPI.transfer(addr | 0x80); // Send the address ORed with the read command
read_value = SPI.transfer(0xFF); // Send dummy data to read the value

SPI.endTransaction();
digitalWrite(PCAL9714_SPI_CS_PIN, HIGH); // Deselect the device

return read_value;


}

 

 

the header file

#ifndef _PCAL9714_H_
#define _PCAL9714_H_

#include <stdint.h>
#include <stdbool.h>


/**
********************************************************************************
* @file pcal9714.h
* @author ahmed
* @date 2024-04-22
* @brief Header file for the pcal9714 driver.
********************************************************************************
*/


typedef enum gpio_expander_channels_v10_t {
GPIOEXP_NONE0_V10,
GPIOEXP_NONE1_V10,
GPIOEXP_LIMIT_SWITCH_HOME_Y_V10,
GPIOEXP_SEL_WG_CD_V10,
GPIOEXP_SEL_FIBER_V10,
GPIOEXP_SEL_WG_AB_V10,
GPIOEXP_NONE2_V10,
GPIOEXP_NONE3_V10,
GPIOEXP_LIMIT_SWITCH_HOME_X_V10,
GPIOEXP_LIMIT_SWITCH_END_X_V10,
GPIOEXP_LIMIT_SWITCH_END_Y_V10,
GPIOEXP_CCB_DETECT_V10,
GPIOEXP_CC_DETECT_V10,
GPIOEXP_MOTOR_ENABLE_V10,
NUMBER_OF_GPIOEXP_PINS_V10
}gpio_expander_channels_v10_t;

#define PCAL_INP_PORT0 0x00
#define PCAL_INP_PORT1 0x01
#define PCAL_OUT_PORT0 0x02
#define PCAL_OUT_PORT1 0x03
#define PCAL_POL_INV_PORT0 0x04
#define PCAL_POL_INV_PORT1 0x05
#define PCAL_CONF_PORT0 0x06
#define PCAL_CONF_PORT1 0x07
#define PCAL_OUT_STR_PORT0A 0x40
#define PCAL_OUT_STR_PORT0B 0x41
#define PCAL_OUT_STR_PORT1A 0x42
#define PCAL_OUT_STR_PORT1B 0x43
#define PCAL_INP_LATCH_REG0 0x44
#define PCAL_INP_LATCH_REG1 0x45
#define PCAL_PULL_EN_PORT0 0x46
#define PCAL_PULL_EN_PORT1 0x47
#define PCAL_PULL_SEL_PORT0 0x48
#define PCAL_PULL_SEL_PORT1 0x49
#define PCAL_INT_MASK_PORT0 0x4A
#define PCAL_INT_MASK_PORT1 0x4B
#define PCAL_INT_STAT_PORT0 0x4C
#define PCAL_INT_STAT_PORT1 0x4D
#define PCAL_OUT_CONF_REG 0x4F
#define PCAL_INT_EDGE_REG0A 0x50
#define PCAL_INT_EDGE_REG0B 0x51
#define PCAL_INT_EDGE_REG1A 0x52
#define PCAL_INT_EDGE_REG1B 0x53
#define PCAL_INT_CLR_REG0 0x54
#define PCAL_INT_CLR_REG1 0x55
#define PCAL_INP_PORT_READ_WO_INT_CLR0 0x56
#define PCAL_INP_PORT_READ_WO_INT_CLR1 0x57
#define PCAL_OUT_CONF_REG0 0x58
#define PCAL_OUT_CONF_REG1 0x59
#define PCAL_DEBOUNCE_EN_REG0 0x5A
#define PCAL_DEBOUNCE_EN_REG1 0x5B
#define PCAL_DEBOUNCE_COUNT 0x5C


// Define the SPI CS pin
#define PCAL9714_SPI_CS_PIN 9 // CS pin for the PCAL9714 is connected to Arduino pin 9


void pcal9714_init(void);
void pcal9714_set_pin(uint8_t channel, uint8_t value);
uint8_t pcal9714_read_pin(uint8_t channel);
void pcal9714_set_mode(uint8_t channel, uint8_t value);
void pcal9714_write(uint8_t addr, uint8_t value);
uint8_t pcal9714_read_port(uint8_t port);
uint8_t pcal9714_read(uint8_t addr);
void pcal9714_configure_debounce(uint8_t debounce_pins_port0, uint8_t debounce_pins_port1, uint8_t debounce_counter_value);




#endif /* _PCAL9714_H_ */

 

 

Please guide me through how to read/write or test the limit switches on the PCAL9714

Best,

Ahmed

0 Kudos
1 Solution
12 Views
ahmedd
Contributor II

Hi David,

sorry for the late response, but I had solved it, here is the corrected code for anyone who needs it

cpp file

#include <Arduino.h>
#include "pcal9714.h"
#include <SPI.h>


/**
 ********************************************************************************
 * @file    pcal9714.cpp
 * @author  ahmed
 * @date    2024-04-22
 * @brief   Implementation of the pcal9714 driver.
 ********************************************************************************
 */

/// @brief Configure the pcal9714 device.
void pcal9714_init(void)
{
    
    pinMode(PCAL9714_SPI_CS_PIN, OUTPUT);
    digitalWrite(PCAL9714_SPI_CS_PIN, HIGH); // Deselect the device
    SPI.begin();  // Initialize SPI communication

}

/// @brief Set the value of a pin on the pcal9714 device.
/// @Param channel Channel number.
/// @Param value 1 for high, 0 for low.
void pcal9714_set_pin(uint8_t channel, uint8_t value)
{
    uint8_t port = channel / 8;  // Determine port (0 or 1)
    uint8_t pin = channel % 8;   // Determine pin within the port

    uint8_t portValue = pcal9714_read_port(port); // Read current port value

    if (value) {
        portValue |= (1 << pin); // Set the pin to HIGH
    } else {
        portValue &= ~(1 << pin); // Set the pin to LOW
    }

    pcal9714_write(PCAL_OUT_PORT0 + port, portValue); // Write to the output port

}

/// @brief Read the value of a pin on the pcal9714 device.
/// @Param channel Channel number.
/// @return The value of the pin.
uint8_t pcal9714_read_pin(uint8_t channel)
{
    uint8_t port = channel / 8;
    uint8_t pin = channel % 8;

    uint8_t portValue = pcal9714_read_port(port);
    return (portValue >> pin) & 0x01; 
}

/// @brief Set the mode of a pin on the pcal9714 device.
/// @Param channel Channel number.
/// @Param value 1 for high impedence input, 0 for output.
void pcal9714_set_mode(uint8_t channel, uint8_t mode) {
    uint8_t port = channel / 8;
    uint8_t pin = channel % 8;

    // Setting the overall port configuration for push-pull if we're setting the pin as an output
    if (mode == OUTPUT) {
        uint8_t out_conf = pcal9714_read(PCAL_OUT_CONF_REG);
        out_conf |= 0x03; // Set the ports to push-pull mode
        pcal9714_write(PCAL_OUT_CONF_REG, out_conf);

        // Set the individual pin configuration for pull-up if required
        uint8_t out_conf_reg = (port == 0) ? PCAL_OUT_CONF_REG0 : PCAL_OUT_CONF_REG1;
        uint8_t out_conf_value = pcal9714_read(out_conf_reg);
        out_conf_value |= (1 << pin); // Enable pull-up for the pin
        pcal9714_write(out_conf_reg, out_conf_value);
    }

    // Then set the pin direction (input/output)
    uint8_t config_reg = (port == 0) ? PCAL_CONF_PORT0 : PCAL_CONF_PORT1;
    uint8_t current_config = pcal9714_read(config_reg);

    if (mode == OUTPUT) {
        current_config &= ~(1 << pin); // Clear the bit to set it as output
    } else {
        current_config |= (1 << pin); // Set the bit to set it as input
    }

    pcal9714_write(config_reg, current_config);
}

/// @brief Configure the debounce on the pcal9714 device.
/// @Param  debounce_pins_port0 This parameter specifies which pins on port 0 of the PCAL9714 device should have debounce enabled. Each bit in this parameter represents a pin on port 0, where a value of 1 enables debounce for that pin, and a value of 0 disables debounce.
/// @Param debounce_pins_port1 Similar to debounce_pins_port0, this parameter specifies debounce settings for pins on port 1 of the device.
/// @Param debounce_counter_value This parameter determines the debounce counter value, which influences the debounce delay. A higher counter value results in a longer debounce delay.

void pcal9714_configure_debounce(uint8_t debounce_pins_port0, uint8_t debounce_pins_port1, uint8_t debounce_counter_value) {
    // Initialize SPI communication
    pcal9714_init();

    // Set up the switch debounce enable registers for port 0 and port 1
    pcal9714_write(PCAL_DEBOUNCE_EN_REG0, debounce_pins_port0);
    
    pcal9714_write(PCAL_DEBOUNCE_EN_REG1, debounce_pins_port1);

    // Write the debounce counter value to the debounce count register
    pcal9714_write(PCAL_DEBOUNCE_COUNT, debounce_counter_value);
}


/// @brief Write a value to a register on the pcal9714 device.
/// @Param addr Address of the register.
/// @Param value Value to write.
void pcal9714_write(uint8_t addr, uint8_t value) {
  // Build the frame according to datasheet. First byte is slave address with R/W bit set to 0 for write.
  uint8_t slaveAddressByte = 0x40; // Adjust as needed.
  uint8_t dataFrame[3] = {slaveAddressByte, addr, value};

  digitalWrite(PCAL9714_SPI_CS_PIN, LOW); // Select the device
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

  for (int i = 0; i < 3; i++) {
    SPI.transfer(dataFrame[i]); // Transfer each byte
  }

  SPI.endTransaction();
  digitalWrite(PCAL9714_SPI_CS_PIN, HIGH); // Deselect the device
}

/// @brief Read a value from a port on the pcal9714 device.
/// @Param port port addr
/// @return value of the port
uint8_t pcal9714_read_port(uint8_t port)
{
    uint8_t regAddr = (port == 0) ? PCAL_INP_PORT0 : PCAL_INP_PORT1; 
    return pcal9714_read(regAddr);
}

/// @brief Read a value from a register on the pcal9714 device.
/// @Param addr Address of the register.
/// @return Value read from the register.

uint8_t pcal9714_read(uint8_t addr) {
  // Build the frame according to datasheet. First byte is slave address with R/W bit set to 1 for read.
  uint8_t slaveAddressByte = (0x41); // OR with 0x01 to indicate read operation
  uint8_t dataOut[3] = {slaveAddressByte, addr, 0x00}; // Third byte doesn't matter, it's dummy for clocking out the data
  uint8_t dataIn[3] = {0, 0, 0};

  digitalWrite(PCAL9714_SPI_CS_PIN, LOW); // Select the device
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

  for (int i = 0; i < 3; i++) {
    dataIn[i] = SPI.transfer(dataOut[i]); // Transfer each byte
    //Serial.println(dataIn[i], HEX);
  }

  SPI.endTransaction();
  digitalWrite(PCAL9714_SPI_CS_PIN, HIGH); // Deselect the device

  return dataIn[2]; // The data read from the device will be in the third byte
}


header file

#ifndef _PCAL9714_H_
#define _PCAL9714_H_

#include <stdint.h>
#include <stdbool.h>


/**
 ********************************************************************************
 * @file    pcal9714.h
 * @author  ahmed
 * @date    2024-04-22
 * @brief   Header file for the pcal9714 driver.
 ********************************************************************************
 */


typedef enum gpio_expander_channels_v10_t {
    GPIOEXP_NONE0_V10,//input P0_0
    GPIOEXP_NONE1_V10,//input P0_2
    GPIOEXP_LIMIT_SWITCH_HOME_Y_V10,
    GPIOEXP_SEL_WG_CD_V10,
    GPIOEXP_SEL_FIBER_V10,
    GPIOEXP_SEL_WG_AB_V10,
    GPIOEXP_NONE2_V10,
    GPIOEXP_NONE3_V10,
    GPIOEXP_LIMIT_SWITCH_HOME_X_V10,
    GPIOEXP_LIMIT_SWITCH_END_X_V10,
    GPIOEXP_LIMIT_SWITCH_END_Y_V10,
    GPIOEXP_CCB_DETECT_V10,
    GPIOEXP_CC_DETECT_V10,
    GPIOEXP_MOTOR_ENABLE_V10,
    NUMBER_OF_GPIOEXP_PINS_V10
}gpio_expander_channels_v10_t;

#define PCAL_INP_PORT0 0x00
#define PCAL_INP_PORT1 0x01
#define PCAL_OUT_PORT0 0x02
#define PCAL_OUT_PORT1 0x03
#define PCAL_POL_INV_PORT0 0x04
#define PCAL_POL_INV_PORT1 0x05
#define PCAL_CONF_PORT0 0x06
#define PCAL_CONF_PORT1 0x07
#define PCAL_OUT_STR_PORT0A 0x40
#define PCAL_OUT_STR_PORT0B 0x41
#define PCAL_OUT_STR_PORT1A 0x42
#define PCAL_OUT_STR_PORT1B 0x43
#define PCAL_INP_LATCH_REG0 0x44
#define PCAL_INP_LATCH_REG1 0x45
#define PCAL_PULL_EN_PORT0 0x46
#define PCAL_PULL_EN_PORT1 0x47
#define PCAL_PULL_SEL_PORT0 0x48
#define PCAL_PULL_SEL_PORT1 0x49
#define PCAL_INT_MASK_PORT0 0x4A
#define PCAL_INT_MASK_PORT1 0x4B
#define PCAL_INT_STAT_PORT0 0x4C
#define PCAL_INT_STAT_PORT1 0x4D
#define PCAL_OUT_CONF_REG 0x4F
#define PCAL_INT_EDGE_REG0A 0x50
#define PCAL_INT_EDGE_REG0B 0x51
#define PCAL_INT_EDGE_REG1A 0x52
#define PCAL_INT_EDGE_REG1B 0x53
#define PCAL_INT_CLR_REG0 0x54
#define PCAL_INT_CLR_REG1 0x55
#define PCAL_INP_PORT_READ_WO_INT_CLR0 0x56
#define PCAL_INP_PORT_READ_WO_INT_CLR1 0x57
#define PCAL_OUT_CONF_REG0 0x58
#define PCAL_OUT_CONF_REG1 0x59
#define PCAL_DEBOUNCE_EN_REG0 0x5A
#define PCAL_DEBOUNCE_EN_REG1 0x5B
#define PCAL_DEBOUNCE_COUNT 0x5C


// Define the SPI CS pin
#define PCAL9714_SPI_CS_PIN   9  // CS pin for the PCAL9714 is connected to Arduino pin 9

// Slave address based on your specific hardware setup
#define PCAL9714_SLAVE_ADDRESS 0x20 // Example slave address



void pcal9714_init(void);
void pcal9714_set_pin(uint8_t channel, uint8_t value);
uint8_t pcal9714_read_pin(uint8_t channel);
void pcal9714_set_mode(uint8_t channel, uint8_t value);
void pcal9714_write(uint8_t addr, uint8_t value);
uint8_t pcal9714_read_port(uint8_t port);
uint8_t pcal9714_read(uint8_t addr);
void pcal9714_configure_debounce(uint8_t debounce_pins_port0, uint8_t debounce_pins_port1, uint8_t debounce_counter_value);




#endif /* _PCAL9714_H_ */







View solution in original post

0 Kudos
2 Replies
13 Views
ahmedd
Contributor II

Hi David,

sorry for the late response, but I had solved it, here is the corrected code for anyone who needs it

cpp file

#include <Arduino.h>
#include "pcal9714.h"
#include <SPI.h>


/**
 ********************************************************************************
 * @file    pcal9714.cpp
 * @author  ahmed
 * @date    2024-04-22
 * @brief   Implementation of the pcal9714 driver.
 ********************************************************************************
 */

/// @brief Configure the pcal9714 device.
void pcal9714_init(void)
{
    
    pinMode(PCAL9714_SPI_CS_PIN, OUTPUT);
    digitalWrite(PCAL9714_SPI_CS_PIN, HIGH); // Deselect the device
    SPI.begin();  // Initialize SPI communication

}

/// @brief Set the value of a pin on the pcal9714 device.
/// @Param channel Channel number.
/// @Param value 1 for high, 0 for low.
void pcal9714_set_pin(uint8_t channel, uint8_t value)
{
    uint8_t port = channel / 8;  // Determine port (0 or 1)
    uint8_t pin = channel % 8;   // Determine pin within the port

    uint8_t portValue = pcal9714_read_port(port); // Read current port value

    if (value) {
        portValue |= (1 << pin); // Set the pin to HIGH
    } else {
        portValue &= ~(1 << pin); // Set the pin to LOW
    }

    pcal9714_write(PCAL_OUT_PORT0 + port, portValue); // Write to the output port

}

/// @brief Read the value of a pin on the pcal9714 device.
/// @Param channel Channel number.
/// @return The value of the pin.
uint8_t pcal9714_read_pin(uint8_t channel)
{
    uint8_t port = channel / 8;
    uint8_t pin = channel % 8;

    uint8_t portValue = pcal9714_read_port(port);
    return (portValue >> pin) & 0x01; 
}

/// @brief Set the mode of a pin on the pcal9714 device.
/// @Param channel Channel number.
/// @Param value 1 for high impedence input, 0 for output.
void pcal9714_set_mode(uint8_t channel, uint8_t mode) {
    uint8_t port = channel / 8;
    uint8_t pin = channel % 8;

    // Setting the overall port configuration for push-pull if we're setting the pin as an output
    if (mode == OUTPUT) {
        uint8_t out_conf = pcal9714_read(PCAL_OUT_CONF_REG);
        out_conf |= 0x03; // Set the ports to push-pull mode
        pcal9714_write(PCAL_OUT_CONF_REG, out_conf);

        // Set the individual pin configuration for pull-up if required
        uint8_t out_conf_reg = (port == 0) ? PCAL_OUT_CONF_REG0 : PCAL_OUT_CONF_REG1;
        uint8_t out_conf_value = pcal9714_read(out_conf_reg);
        out_conf_value |= (1 << pin); // Enable pull-up for the pin
        pcal9714_write(out_conf_reg, out_conf_value);
    }

    // Then set the pin direction (input/output)
    uint8_t config_reg = (port == 0) ? PCAL_CONF_PORT0 : PCAL_CONF_PORT1;
    uint8_t current_config = pcal9714_read(config_reg);

    if (mode == OUTPUT) {
        current_config &= ~(1 << pin); // Clear the bit to set it as output
    } else {
        current_config |= (1 << pin); // Set the bit to set it as input
    }

    pcal9714_write(config_reg, current_config);
}

/// @brief Configure the debounce on the pcal9714 device.
/// @Param  debounce_pins_port0 This parameter specifies which pins on port 0 of the PCAL9714 device should have debounce enabled. Each bit in this parameter represents a pin on port 0, where a value of 1 enables debounce for that pin, and a value of 0 disables debounce.
/// @Param debounce_pins_port1 Similar to debounce_pins_port0, this parameter specifies debounce settings for pins on port 1 of the device.
/// @Param debounce_counter_value This parameter determines the debounce counter value, which influences the debounce delay. A higher counter value results in a longer debounce delay.

void pcal9714_configure_debounce(uint8_t debounce_pins_port0, uint8_t debounce_pins_port1, uint8_t debounce_counter_value) {
    // Initialize SPI communication
    pcal9714_init();

    // Set up the switch debounce enable registers for port 0 and port 1
    pcal9714_write(PCAL_DEBOUNCE_EN_REG0, debounce_pins_port0);
    
    pcal9714_write(PCAL_DEBOUNCE_EN_REG1, debounce_pins_port1);

    // Write the debounce counter value to the debounce count register
    pcal9714_write(PCAL_DEBOUNCE_COUNT, debounce_counter_value);
}


/// @brief Write a value to a register on the pcal9714 device.
/// @Param addr Address of the register.
/// @Param value Value to write.
void pcal9714_write(uint8_t addr, uint8_t value) {
  // Build the frame according to datasheet. First byte is slave address with R/W bit set to 0 for write.
  uint8_t slaveAddressByte = 0x40; // Adjust as needed.
  uint8_t dataFrame[3] = {slaveAddressByte, addr, value};

  digitalWrite(PCAL9714_SPI_CS_PIN, LOW); // Select the device
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

  for (int i = 0; i < 3; i++) {
    SPI.transfer(dataFrame[i]); // Transfer each byte
  }

  SPI.endTransaction();
  digitalWrite(PCAL9714_SPI_CS_PIN, HIGH); // Deselect the device
}

/// @brief Read a value from a port on the pcal9714 device.
/// @Param port port addr
/// @return value of the port
uint8_t pcal9714_read_port(uint8_t port)
{
    uint8_t regAddr = (port == 0) ? PCAL_INP_PORT0 : PCAL_INP_PORT1; 
    return pcal9714_read(regAddr);
}

/// @brief Read a value from a register on the pcal9714 device.
/// @Param addr Address of the register.
/// @return Value read from the register.

uint8_t pcal9714_read(uint8_t addr) {
  // Build the frame according to datasheet. First byte is slave address with R/W bit set to 1 for read.
  uint8_t slaveAddressByte = (0x41); // OR with 0x01 to indicate read operation
  uint8_t dataOut[3] = {slaveAddressByte, addr, 0x00}; // Third byte doesn't matter, it's dummy for clocking out the data
  uint8_t dataIn[3] = {0, 0, 0};

  digitalWrite(PCAL9714_SPI_CS_PIN, LOW); // Select the device
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

  for (int i = 0; i < 3; i++) {
    dataIn[i] = SPI.transfer(dataOut[i]); // Transfer each byte
    //Serial.println(dataIn[i], HEX);
  }

  SPI.endTransaction();
  digitalWrite(PCAL9714_SPI_CS_PIN, HIGH); // Deselect the device

  return dataIn[2]; // The data read from the device will be in the third byte
}


header file

#ifndef _PCAL9714_H_
#define _PCAL9714_H_

#include <stdint.h>
#include <stdbool.h>


/**
 ********************************************************************************
 * @file    pcal9714.h
 * @author  ahmed
 * @date    2024-04-22
 * @brief   Header file for the pcal9714 driver.
 ********************************************************************************
 */


typedef enum gpio_expander_channels_v10_t {
    GPIOEXP_NONE0_V10,//input P0_0
    GPIOEXP_NONE1_V10,//input P0_2
    GPIOEXP_LIMIT_SWITCH_HOME_Y_V10,
    GPIOEXP_SEL_WG_CD_V10,
    GPIOEXP_SEL_FIBER_V10,
    GPIOEXP_SEL_WG_AB_V10,
    GPIOEXP_NONE2_V10,
    GPIOEXP_NONE3_V10,
    GPIOEXP_LIMIT_SWITCH_HOME_X_V10,
    GPIOEXP_LIMIT_SWITCH_END_X_V10,
    GPIOEXP_LIMIT_SWITCH_END_Y_V10,
    GPIOEXP_CCB_DETECT_V10,
    GPIOEXP_CC_DETECT_V10,
    GPIOEXP_MOTOR_ENABLE_V10,
    NUMBER_OF_GPIOEXP_PINS_V10
}gpio_expander_channels_v10_t;

#define PCAL_INP_PORT0 0x00
#define PCAL_INP_PORT1 0x01
#define PCAL_OUT_PORT0 0x02
#define PCAL_OUT_PORT1 0x03
#define PCAL_POL_INV_PORT0 0x04
#define PCAL_POL_INV_PORT1 0x05
#define PCAL_CONF_PORT0 0x06
#define PCAL_CONF_PORT1 0x07
#define PCAL_OUT_STR_PORT0A 0x40
#define PCAL_OUT_STR_PORT0B 0x41
#define PCAL_OUT_STR_PORT1A 0x42
#define PCAL_OUT_STR_PORT1B 0x43
#define PCAL_INP_LATCH_REG0 0x44
#define PCAL_INP_LATCH_REG1 0x45
#define PCAL_PULL_EN_PORT0 0x46
#define PCAL_PULL_EN_PORT1 0x47
#define PCAL_PULL_SEL_PORT0 0x48
#define PCAL_PULL_SEL_PORT1 0x49
#define PCAL_INT_MASK_PORT0 0x4A
#define PCAL_INT_MASK_PORT1 0x4B
#define PCAL_INT_STAT_PORT0 0x4C
#define PCAL_INT_STAT_PORT1 0x4D
#define PCAL_OUT_CONF_REG 0x4F
#define PCAL_INT_EDGE_REG0A 0x50
#define PCAL_INT_EDGE_REG0B 0x51
#define PCAL_INT_EDGE_REG1A 0x52
#define PCAL_INT_EDGE_REG1B 0x53
#define PCAL_INT_CLR_REG0 0x54
#define PCAL_INT_CLR_REG1 0x55
#define PCAL_INP_PORT_READ_WO_INT_CLR0 0x56
#define PCAL_INP_PORT_READ_WO_INT_CLR1 0x57
#define PCAL_OUT_CONF_REG0 0x58
#define PCAL_OUT_CONF_REG1 0x59
#define PCAL_DEBOUNCE_EN_REG0 0x5A
#define PCAL_DEBOUNCE_EN_REG1 0x5B
#define PCAL_DEBOUNCE_COUNT 0x5C


// Define the SPI CS pin
#define PCAL9714_SPI_CS_PIN   9  // CS pin for the PCAL9714 is connected to Arduino pin 9

// Slave address based on your specific hardware setup
#define PCAL9714_SLAVE_ADDRESS 0x20 // Example slave address



void pcal9714_init(void);
void pcal9714_set_pin(uint8_t channel, uint8_t value);
uint8_t pcal9714_read_pin(uint8_t channel);
void pcal9714_set_mode(uint8_t channel, uint8_t value);
void pcal9714_write(uint8_t addr, uint8_t value);
uint8_t pcal9714_read_port(uint8_t port);
uint8_t pcal9714_read(uint8_t addr);
void pcal9714_configure_debounce(uint8_t debounce_pins_port0, uint8_t debounce_pins_port1, uint8_t debounce_counter_value);




#endif /* _PCAL9714_H_ */







0 Kudos
23 Views
diazmarin09
NXP TechSupport
NXP TechSupport

Hello ahmedd,

As mentioned in another post, I would like to focus on your pcal9714_write and pcal9714_read functions.

The bus master must send the target slave address followed by a read or write operation. The slave address of the PCAL9714 is shown below:

diazmarin09_1-1714503244036.png

 

Are you considering such an address before trying to write or read an internal register?

Following the first byte of the slave address, the bus master sends a command byte, which is write-only and stored in the pointer register in the PCAL9714. Finally, the data.

In total, 24 bits of data are transferred before deserting CS.

diazmarin09_0-1714503238811.png

 

Could you please share an oscilloscope of your data transfer?

Regards,

David

0 Kudos