Skip to content

Commit

Permalink
Pca gpio expander (#127)
Browse files Browse the repository at this point in the history
* init pca9539

* get rid of super bad enums lol

* make it way simpler and no bools

* get rid of extra shifts

* misc fixes

* fix buf

* misc fixes needed

* reverse the bits

* no reverse bits

---------

Co-authored-by: Scott A <[email protected]>
  • Loading branch information
jr1221 and Sabramz authored Jun 1, 2024
1 parent 271bf36 commit 86f61de
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 0 deletions.
61 changes: 61 additions & 0 deletions general/include/pca9539.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#ifndef PCA9539_H
#define PCA9539_H

#include "stm32f4xx_hal.h"
#include <stdint.h>

/*
PCA 9539 16 bit GPIO expander. Datasheet: https://www.ti.com/lit/ds/symlink/pca9539.pdf?ts=1716785085909
*/

/// Possible I2C addresses, see comment below
/// A0 A1
/// PCA_I2C_ADDR_0 0x74, L L
/// PCA_I2C_ADDR_1 0x75, L H
/// PCA_I2C_ADDR_2 0x76, H L
/// PCA_I2C_ADDR_3 0x77, H H
#define PCA_I2C_ADDR_0 0x74
#define PCA_I2C_ADDR_1 0x75
#define PCA_I2C_ADDR_2 0x76
#define PCA_I2C_ADDR_3 0x77

/// What to write/read to/from
/// 0 is for pins 0X, 1 is for pins 1X
/// INPUT: The incoming logic level (read only) Result: 1=H 0=L
/// OUTPUT: The outgoing logic level (write only) Set: 1=H 0=L
/// POLARITY: Inversion state, 1=Inverted 0=Uninverted
/// DIRECTION: Input/Output selection 1=Input 0=Output

#define PCA_INPUT_0_REG 0x00
#define PCA_INPUT_1_REG 0x01
#define PCA_OUTPUT_0_REG 0x02
#define PCA_OUTPUT_1_REG 0x03
#define PCA_POLARITY_0_REG 0x04
#define PCA_POLARITY_1_REG 0x05
#define PCA_DIRECTION_0_REG 0x06
#define PCA_DIRECTION_1_REG 0x07

typedef struct
{
I2C_HandleTypeDef *i2c_handle;
uint16_t dev_addr;
} pca9539_t;

/// Init PCA9539, a 16 bit I2C GPIO expander
void pca9539_init(pca9539_t *pca, I2C_HandleTypeDef *i2c_handle, uint8_t dev_addr);

/// @brief Read all pins on a bus, for example using reg_type input to get incoming logic level
HAL_StatusTypeDef pca9539_read_reg(pca9539_t *pca, uint8_t reg_type,
uint8_t *buf);
/// @brief Read a specific pin on a bus, do not iterate over this, use read_pins instead
HAL_StatusTypeDef pca9539_read_pin(pca9539_t *pca, uint8_t reg_type,
uint8_t pin, uint8_t *buf);

/// @brief Write all pins on a bus, for example using reg_type OUTPUT to set logic level or DIRECTION to set as
/// output
HAL_StatusTypeDef pca9539_write_reg(pca9539_t *pca, uint8_t reg_type, uint8_t buf);
/// @brief Write a specific pin on a bus, do not iterate over this, use write_pins instead
HAL_StatusTypeDef pca9539_write_pin(pca9539_t *pca, uint8_t reg_type, uint8_t pin,
uint8_t buf);

#endif
71 changes: 71 additions & 0 deletions general/src/pca9539.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include "pca9539.h"

#include "../../middleware/include/c_utils.h"

#define REG_SIZE_BITS 8

HAL_StatusTypeDef pca_write_reg(pca9539_t* pca, uint16_t address, uint8_t* data)
{
// ensure shifting left one, HAL adds the write bit
return HAL_I2C_Mem_Write(pca->i2c_handle, pca->dev_addr, address, I2C_MEMADD_SIZE_8BIT, data, 1,
HAL_MAX_DELAY);
}

HAL_StatusTypeDef pca_read_reg(pca9539_t* pca, uint16_t address, uint8_t* data)
{

return HAL_I2C_Mem_Read(pca->i2c_handle, pca->dev_addr, address, I2C_MEMADD_SIZE_8BIT, data, 1,
HAL_MAX_DELAY);
}

void pca9539_init(pca9539_t* pca, I2C_HandleTypeDef* i2c_handle, uint8_t dev_addr)
{
pca->i2c_handle = i2c_handle;
pca->dev_addr = dev_addr << 1u; /* shifted one to the left cuz STM says so */
}

HAL_StatusTypeDef pca9539_read_reg(pca9539_t* pca, uint8_t reg_type, uint8_t* buf)
{

HAL_StatusTypeDef status = pca_read_reg(pca, reg_type, buf);
if (status) {
return status;
}

return status;
}

HAL_StatusTypeDef pca9539_read_pin(pca9539_t* pca, uint8_t reg_type, uint8_t pin, uint8_t* buf)
{
uint8_t data;
HAL_StatusTypeDef status = pca_read_reg(pca, reg_type, &data);
if (status) {
return status;
}

*buf = (data & (1 << pin)) > 0;

return status;
}

HAL_StatusTypeDef pca9539_write_reg(pca9539_t* pca, uint8_t reg_type, uint8_t buf)
{

return pca_write_reg(pca, reg_type, &buf);
}

HAL_StatusTypeDef pca9539_write_pin(pca9539_t* pca, uint8_t reg_type, uint8_t pin, uint8_t buf)
{

uint8_t data;
uint8_t data_new;

HAL_StatusTypeDef status = pca_read_reg(pca, reg_type, &data);
if (status) {
return status;
}

data_new = (data & ~(1u << pin)) | (buf << pin);

return pca_write_reg(pca, reg_type, &data_new);
}

0 comments on commit 86f61de

Please sign in to comment.