-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpca9555.c
157 lines (136 loc) · 5.57 KB
/
pca9555.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include "pca9555.h"
#include <driver/gpio.h>
#include <esp_err.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <freertos/task.h>
#include <sdkconfig.h>
#include <stdbool.h>
#include "managed_i2c.h"
static const char* TAG = "pca9555";
/* I2C access */
static inline esp_err_t read_reg(PCA9555* device, uint8_t reg, uint8_t* data, size_t data_len) {
if (device->i2c_semaphore != NULL) xSemaphoreTake(device->i2c_semaphore, portMAX_DELAY);
esp_err_t res = i2c_read_reg(device->i2c_bus, device->i2c_addr, reg, data, data_len);
if (device->i2c_semaphore != NULL) xSemaphoreGive(device->i2c_semaphore);
if (res != ESP_OK) {
ESP_LOGE(TAG, "read reg error %d", res);
}
return res;
}
static inline esp_err_t write_reg(PCA9555* device, uint8_t reg, uint8_t* data, size_t data_len) {
if (device->i2c_semaphore != NULL) xSemaphoreTake(device->i2c_semaphore, portMAX_DELAY);
esp_err_t res = i2c_write_reg_n(device->i2c_bus, device->i2c_addr, reg, data, data_len);
if (device->i2c_semaphore != NULL) xSemaphoreGive(device->i2c_semaphore);
if (res != ESP_OK) {
ESP_LOGE(TAG, "write reg error %d", res);
}
return res;
}
/* Public functions */
esp_err_t pca9555_init(PCA9555* device) {
ESP_LOGD(TAG, "init called");
esp_err_t res;
// Configure pins
device->reg_config[0] = 0xFF; // By default, set all pins to input
device->reg_config[1] = 0xFF;
res = write_reg(device, REG_CONFIG_0, device->reg_config, 2); // Writes port mode to both config 0 and config 1 registers
if (res != ESP_OK) return res;
// Set all ports to active-low
device->reg_polarity[0] = 0xFF;
device->reg_polarity[1] = 0xFF;
res = write_reg(device, REG_POLARITY_0, device->reg_polarity, 2); // Writes port polarity to both port 0 and port 1 registers
if (res != ESP_OK) return res;
device->reg_output[0] = 0x00;
device->reg_output[1] = 0x00;
device->previous_state = 0;
ESP_LOGD(TAG, "init done");
return ESP_OK;
}
esp_err_t pca9555_set_gpio_direction(PCA9555* device, int pin, bool direction) {
if ((pin < 0) || (pin > 15)) return ESP_FAIL; // Out of range
uint8_t port = (pin >= 8) ? 1 : 0;
uint8_t bit = pin % 8;
bool current_state = (device->reg_config[port] >> bit) & 1;
printf("curr = %d, direction = %d\n", current_state, direction);
if (direction != current_state) {
if (direction == PCA_OUTPUT) {
device->reg_config[port] &= ~(1 << bit); // Set the pin to output
} else {
device->reg_config[port] |= (1 << bit); // Set the pin to input
}
}
return write_reg(device, REG_CONFIG_0, device->reg_config, 2);
}
int pca9555_get_gpio_direction(PCA9555* device, int pin) {
if ((pin < 0) || (pin > 15)) return -1; // Out of range
uint8_t port = (pin >= 8) ? 1 : 0;
uint8_t bit = pin % 8;
return (device->reg_config[port] >> bit) & 1; // Return 1 when the pin is an input and 0 when the pin is output
}
esp_err_t pca9555_set_gpio_polarity(PCA9555* device, int pin, bool polarity) {
if ((pin < 0) || (pin > 15)) return ESP_FAIL; // Out of range
uint8_t port = (pin >= 8) ? 1 : 0;
uint8_t bit = pin % 8;
bool current_state = (device->reg_polarity[port] >> bit) & 1;
if (polarity != current_state) {
if (polarity == PCA_NORMAL) {
device->reg_polarity[port] &= ~(1 << bit); // Set pin to normal mode
} else {
device->reg_polarity[port] |= (1 << bit); // Set pin to inverted mode
}
}
return write_reg(device, REG_POLARITY_0, device->reg_polarity, 2);
}
int pca9555_get_gpio_polarity(PCA9555* device, int pin) {
if ((pin < 0) || (pin > 15)) return -1; // Out of range
uint8_t port = (pin >= 8) ? 1 : 0;
uint8_t bit = pin % 8;
return (device->reg_polarity[port] >> bit) & 1; // Return 0 when the pin is in normal mode and 1 when the pin is in inverted mode
}
esp_err_t pca9555_set_gpio_value(PCA9555* device, int pin, bool value) {
if ((pin < 0) || (pin > 15)) return ESP_FAIL; // Out of range
uint8_t port = (pin >= 8) ? 1 : 0;
uint8_t bit = pin % 8;
if (pca9555_get_gpio_direction(device, pin) == PCA_INPUT) {
ESP_LOGE(TAG, "Tried to set level of an input pin P%d.%d", port, bit);
return ESP_FAIL; // Pin is an input
}
if (value) {
device->reg_output[port] |= (1 << bit);
} else {
device->reg_output[port] &= ~(1 << bit);
}
for (int i = 0; i < 8; i++) {
printf("%d", (device->reg_output[port] >> i) & 0x01);
}
printf("\n");
uint8_t reg = port ? REG_OUTPUT_1 : REG_OUTPUT_0;
return write_reg(device, reg, &device->reg_output[port], 1);
}
int pca9555_get_gpio_value(PCA9555* device, int pin) {
if ((pin < 0) || (pin > 15)) return -1; // Out of range
uint8_t port = (pin >= 8) ? 1 : 0;
uint8_t bit = pin % 8;
uint8_t reg;
if (pca9555_get_gpio_direction(device, pin)) {
reg = port ? REG_OUTPUT_1 : REG_OUTPUT_0;
} else {
reg = port ? REG_INPUT_1 : REG_INPUT_0;
}
uint8_t reg_value;
esp_err_t res = read_reg(device, reg, ®_value, 1);
if (res != ESP_OK) return -1;
return (reg_value >> bit) & 1;
}
int pca9555_get_gpio_values(PCA9555* device, uint16_t* output) {
uint8_t data[] = {0, 0};
esp_err_t res = read_reg(device, REG_INPUT_0, data, 2);
if (res != ESP_OK) {
ESP_LOGE(TAG, "failed to read input state of device %d", device->i2c_addr);
return ESP_FAIL;
}
*output = data[0] + (data[1] << 8);
return ESP_OK;
}