gpio_exp.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /* GDS Example
  2. This example code is in the Public Domain (or CC0 licensed, at your option.)
  3. Unless required by applicable law or agreed to in writing, this
  4. software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied.
  6. */
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include "freertos/FreeRTOS.h"
  10. #include "freertos/task.h"
  11. #include "esp_log.h"
  12. #include "driver/gpio.h"
  13. #include "driver/i2c.h"
  14. #include "gpio_exp.h"
  15. static const char TAG[] = "gpio expander";
  16. static void IRAM_ATTR intr_isr_handler(void* arg);
  17. static struct gpio_exp_s* find_expander(struct gpio_exp_s *expander, int *gpio);
  18. static void pca9535_set_direction(union gpio_exp_phy_u*, uint32_t, uint32_t);
  19. static int pca9535_read(union gpio_exp_phy_u*);
  20. static void pca9535_write(union gpio_exp_phy_u*, uint32_t, uint32_t);
  21. static void pca85xx_set_direction(union gpio_exp_phy_u*, uint32_t, uint32_t);
  22. static int pca85xx_read(union gpio_exp_phy_u*);
  23. static void pca85xx_write(union gpio_exp_phy_u*, uint32_t, uint32_t);
  24. static esp_err_t i2c_write_byte(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, uint8_t val);
  25. static uint8_t i2c_read_byte(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg);
  26. static uint16_t i2c_read_word(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg);
  27. static esp_err_t i2c_write_word(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, uint16_t data);
  28. static const struct gpio_exp_model_s {
  29. char *model;
  30. gpio_int_type_t trigger;
  31. void (*init)(union gpio_exp_phy_u*);
  32. int (*read)(union gpio_exp_phy_u*);
  33. void (*write)(union gpio_exp_phy_u*, uint32_t r_mask, uint32_t shadow);
  34. void (*set_direction)(union gpio_exp_phy_u*, uint32_t r_mask, uint32_t w_mask);
  35. void (*set_pull_mode)(int, gpio_pull_mode_t);
  36. } registered[] = {
  37. { .model = "pca9535",
  38. .trigger = GPIO_INTR_NEGEDGE,
  39. .set_direction = pca9535_set_direction,
  40. .read = pca9535_read,
  41. .write = pca9535_write, },
  42. { .model = "pca85xx",
  43. .trigger = GPIO_INTR_NEGEDGE,
  44. .set_direction = pca85xx_set_direction,
  45. .read = pca85xx_read,
  46. .write = pca85xx_write, }
  47. };
  48. static uint8_t n_expanders;
  49. static EXT_RAM_ATTR struct gpio_exp_s {
  50. uint32_t first, last;
  51. union gpio_exp_phy_u phy;
  52. uint32_t shadow;
  53. TickType_t age;
  54. uint32_t r_mask, w_mask;
  55. struct {
  56. gpio_exp_isr handler;
  57. void *arg;
  58. } isr[4];
  59. struct gpio_exp_model_s const *model;
  60. } expanders[4];
  61. /******************************************************************************
  62. * Retrieve base from an expander reference
  63. */
  64. uint32_t gpio_exp_base(struct gpio_exp_s *expander) {
  65. return expander->first;
  66. }
  67. /******************************************************************************
  68. * Retrieve reference from a GPIO
  69. */
  70. struct gpio_exp_s *gpio_exp_expander(int gpio) {
  71. int _gpio = gpio;
  72. return find_expander(NULL, &_gpio);
  73. }
  74. /******************************************************************************
  75. * Create an I2C expander
  76. */
  77. struct gpio_exp_s* gpio_exp_create(const gpio_exp_config_t *config) {
  78. struct gpio_exp_s *expander = expanders + n_expanders;
  79. if (config->base < GPIO_EXP_BASE_MIN || n_expanders == sizeof(expanders)/sizeof(struct gpio_exp_s)) {
  80. ESP_LOGE(TAG, "Base %d GPIO must be > %d for %s or too many expanders %d", config->base, GPIO_EXP_BASE_MIN, config->model, n_expanders);
  81. return NULL;
  82. }
  83. // See if we know that model (expanders is zero-initialized)
  84. for (int i = 0; !expander->model && i < sizeof(registered)/sizeof(struct gpio_exp_model_s); i++) {
  85. if (strcasestr(config->model, registered[i].model)) expander->model = registered + i;
  86. }
  87. // well... try again
  88. if (!expander->model) {
  89. ESP_LOGE(TAG,"Unknown GPIO expansion chip %s", config->model);
  90. return NULL;
  91. }
  92. n_expanders++;
  93. expander->first = config->base;
  94. expander->last = config->base + config->count - 1;
  95. memcpy(&expander->phy, &config->phy, sizeof(union gpio_exp_phy_u));
  96. if (expander->model->init) expander->model->init(&expander->phy);
  97. // set interrupt if possible
  98. if (config->intr > 0) {
  99. gpio_pad_select_gpio(config->intr);
  100. gpio_set_direction(config->intr, GPIO_MODE_INPUT);
  101. switch (expander->model->trigger) {
  102. case GPIO_INTR_NEGEDGE:
  103. case GPIO_INTR_LOW_LEVEL:
  104. gpio_set_pull_mode(config->intr, GPIO_PULLUP_ONLY);
  105. break;
  106. case GPIO_INTR_POSEDGE:
  107. case GPIO_INTR_HIGH_LEVEL:
  108. gpio_set_pull_mode(config->intr, GPIO_PULLDOWN_ONLY);
  109. break;
  110. default:
  111. gpio_set_pull_mode(config->intr, GPIO_PULLUP_PULLDOWN);
  112. break;
  113. }
  114. gpio_set_intr_type(config->intr, expander->model->trigger);
  115. gpio_isr_handler_add(config->intr, intr_isr_handler, expander);
  116. gpio_intr_enable(config->intr);
  117. }
  118. ESP_LOGI(TAG, "Create GPIO expander at base %u with INT %u at @%x", config->base, config->intr, config->phy.addr);
  119. return expander;
  120. }
  121. /******************************************************************************
  122. * Add ISR handler
  123. */
  124. bool gpio_exp_add_isr(gpio_exp_isr isr, void *arg, struct gpio_exp_s *expander) {
  125. for (int i = 0; i < sizeof(expander->isr)/sizeof(*expander->isr); i++) {
  126. if (!expander->isr[i].handler) {
  127. expander->isr[i].handler = isr;
  128. expander->isr[i].arg = arg;
  129. ESP_LOGI(TAG, "Added new ISR for expander base %d", expander->first);
  130. return true;
  131. }
  132. }
  133. ESP_LOGE(TAG, "No room left to add new ISR");
  134. return false;
  135. }
  136. /******************************************************************************
  137. * Set GPIO direction
  138. */
  139. struct gpio_exp_s* gpio_exp_set_direction(int gpio, gpio_mode_t mode, struct gpio_exp_s *expander) {
  140. if ((expander = find_expander(expander, &gpio)) == NULL) return NULL;
  141. if (mode == GPIO_MODE_INPUT) {
  142. expander->r_mask |= 1 << gpio;
  143. expander->age = ~xTaskGetTickCount();
  144. } else {
  145. expander->w_mask |= 1 << gpio;
  146. }
  147. if (expander->r_mask & expander->w_mask) {
  148. ESP_LOGE(TAG, "GPIO %d on expander base %u can't be r/w", gpio, expander->first);
  149. return false;
  150. }
  151. // most expanders want unconfigured GPIO to be set to output
  152. if (expander->model->set_direction) expander->model->set_direction(&expander->phy, expander->r_mask, expander->w_mask);
  153. return expander;
  154. }
  155. /******************************************************************************
  156. * Get GPIO level with cache
  157. */
  158. int gpio_exp_get_level(int gpio, uint32_t age, struct gpio_exp_s *expander) {
  159. if ((expander = find_expander(expander, &gpio)) == NULL) return -1;
  160. uint32_t now = xTaskGetTickCount();
  161. if (now - expander->age >= pdMS_TO_TICKS(age)) {
  162. expander->shadow = expander->model->read(&expander->phy);
  163. expander->age = now;
  164. }
  165. ESP_LOGD(TAG, "Get level for GPIO %u => read %x", expander->first + gpio, expander->shadow);
  166. return (expander->shadow >> gpio) & 0x01;
  167. }
  168. /******************************************************************************
  169. * Set GPIO level with cache
  170. */
  171. void gpio_exp_set_level(int gpio, int level, struct gpio_exp_s *expander) {
  172. if ((expander = find_expander(expander, &gpio)) == NULL) return;
  173. uint32_t mask = 1 << gpio;
  174. if ((expander->w_mask & mask) == 0) {
  175. ESP_LOGW(TAG, "GPIO %d is not set for output", expander->first + gpio);
  176. return;
  177. }
  178. level = level ? mask : 0;
  179. mask &= expander->shadow;
  180. // only write if shadow not up to date
  181. if ((mask ^ level) && expander->model->write) {
  182. expander->shadow = (expander->shadow & ~(mask | level)) | level;
  183. expander->model->write(&expander->phy, expander->r_mask, expander->shadow);
  184. }
  185. ESP_LOGD(TAG, "Set level %x for GPIO %u => wrote %x", level, expander->first + gpio, expander->shadow);
  186. }
  187. /******************************************************************************
  188. * Set GPIO pullmode
  189. */
  190. void gpio_exp_set_pull_mode(int gpio, gpio_pull_mode_t mode, struct gpio_exp_s *expander) {
  191. if ((expander = find_expander(expander, &gpio)) != NULL && expander->model->set_pull_mode) {
  192. expander->model->set_pull_mode(gpio, mode);
  193. }
  194. }
  195. /******************************************************************************
  196. * Enumerate modified GPIO
  197. */
  198. void gpio_exp_enumerate(gpio_exp_enumerator enumerator, struct gpio_exp_s *expander) {
  199. uint32_t value = expander->model->read(&expander->phy) ^ expander->shadow;
  200. uint8_t clz;
  201. // memorize newly read value and just update if requested
  202. expander->shadow ^= value;
  203. if (!enumerator) return;
  204. // now we have a bitmap of all modified GPIO sinnce last call
  205. for (int gpio = 0; value; value <<= (clz + 1)) {
  206. clz = __builtin_clz(value);
  207. gpio += clz;
  208. enumerator(expander->first + 31 - gpio, (expander->shadow >> (31 - gpio)) & 0x01, expander);
  209. }
  210. }
  211. /****************************************************************************************
  212. * Find the expander related to base
  213. */
  214. static struct gpio_exp_s* find_expander(struct gpio_exp_s *expander, int *gpio) {
  215. for (int i = 0; !expander && i < n_expanders; i++) {
  216. if (*gpio >= expanders[i].first && *gpio <= expanders[i].last) expander = expanders + i;
  217. }
  218. // normalize GPIO number
  219. if (expander && *gpio >= expanders->first) *gpio -= expanders->first;
  220. return expander;
  221. }
  222. /****************************************************************************************
  223. * PCA9535 family : direction, read and write
  224. */
  225. static void pca9535_set_direction(union gpio_exp_phy_u *phy, uint32_t r_mask, uint32_t w_mask) {
  226. i2c_write_word(phy->port, phy->addr, 0x06, r_mask);
  227. }
  228. static int pca9535_read(union gpio_exp_phy_u *phy) {
  229. return i2c_read_word(phy->port, phy->addr, 0x00);
  230. }
  231. static void pca9535_write(union gpio_exp_phy_u *phy, uint32_t r_mask, uint32_t shadow) {
  232. i2c_write_word(phy->port, phy->addr, 0x02, shadow);
  233. }
  234. /****************************************************************************************
  235. * PCA85xx family : read and write
  236. */
  237. static void pca85xx_set_direction(union gpio_exp_phy_u *phy, uint32_t r_mask, uint32_t w_mask) {
  238. // all inputs must be set to 1 (open drain) and output are left open as well
  239. i2c_write_word(phy->port, phy->addr, 0x255, r_mask | w_mask);
  240. }
  241. static int pca85xx_read(union gpio_exp_phy_u *phy) {
  242. return i2c_read_word(phy->port, phy->addr, 0xff);
  243. }
  244. static void pca85xx_write(union gpio_exp_phy_u *phy, uint32_t r_mask, uint32_t shadow) {
  245. // all input must be set to 1 (open drain)
  246. i2c_write_word(phy->port, phy->addr, 0xff, shadow | r_mask);
  247. }
  248. /****************************************************************************************
  249. * INTR low-level handler
  250. */
  251. static void IRAM_ATTR intr_isr_handler(void* arg)
  252. {
  253. struct gpio_exp_s *expander = (struct gpio_exp_s*) arg;
  254. BaseType_t woken = pdFALSE;
  255. for (int i = 0; i < sizeof(expander->isr)/sizeof(*expander->isr); i++) {
  256. if (expander->isr[i].handler) woken |= expander->isr[i].handler(expander->isr[i].arg);
  257. }
  258. if (woken) portYIELD_FROM_ISR();
  259. ESP_EARLY_LOGD(TAG, "INTR for expander %u", expander->first);
  260. }
  261. /****************************************************************************************
  262. *
  263. */
  264. static esp_err_t i2c_write_byte(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, uint8_t val) {
  265. i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  266. i2c_master_start(cmd);
  267. i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
  268. i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
  269. i2c_master_write_byte(cmd, val, I2C_MASTER_NACK);
  270. i2c_master_stop(cmd);
  271. esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
  272. i2c_cmd_link_delete(cmd);
  273. if (ret != ESP_OK) {
  274. ESP_LOGW(TAG, "I2C write failed");
  275. }
  276. return ret;
  277. }
  278. /****************************************************************************************
  279. * I2C read one byte
  280. */
  281. static uint8_t i2c_read_byte(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg) {
  282. uint8_t data = 0xff;
  283. i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  284. i2c_master_start(cmd);
  285. i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
  286. i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
  287. i2c_master_start(cmd);
  288. i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK);
  289. i2c_master_read_byte(cmd, &data, I2C_MASTER_NACK);
  290. i2c_master_stop(cmd);
  291. esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
  292. i2c_cmd_link_delete(cmd);
  293. if (ret != ESP_OK) {
  294. ESP_LOGW(TAG, "I2C read failed");
  295. }
  296. return data;
  297. }
  298. /****************************************************************************************
  299. * I2C read 16 bits word
  300. */
  301. static uint16_t i2c_read_word(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg) {
  302. uint16_t data = 0xffff;
  303. i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  304. i2c_master_start(cmd);
  305. i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
  306. // when using a register, write it's value then the device address again
  307. if (reg != 0xff) {
  308. i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
  309. i2c_master_start(cmd);
  310. i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK);
  311. }
  312. i2c_master_read(cmd, (uint8_t*) &data, 2, I2C_MASTER_NACK);
  313. i2c_master_stop(cmd);
  314. esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
  315. i2c_cmd_link_delete(cmd);
  316. if (ret != ESP_OK) {
  317. ESP_LOGW(TAG, "I2C read failed");
  318. }
  319. return data;
  320. }
  321. /****************************************************************************************
  322. * I2C write 16 bits word
  323. */
  324. static esp_err_t i2c_write_word(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, uint16_t data) {
  325. i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  326. i2c_master_start(cmd);
  327. i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK);
  328. if (reg != 0xff) i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
  329. i2c_master_write(cmd, (uint8_t*) &data, 2, I2C_MASTER_NACK);
  330. i2c_master_stop(cmd);
  331. esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS);
  332. i2c_cmd_link_delete(cmd);
  333. if (ret != ESP_OK) {
  334. ESP_LOGW(TAG, "I2C write failed");
  335. }
  336. return ret;
  337. }