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
Solved! Go to Solution.
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_ */
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_ */
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:
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.
Could you please share an oscilloscope of your data transfer?
Regards,
David