luat_gpio_idf5.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #include "luat_base.h"
  2. #include "luat_gpio.h"
  3. #include "luat_irq.h"
  4. #include "freertos/FreeRTOS.h"
  5. #include "freertos/queue.h"
  6. #include "driver/gpio.h"
  7. #define LUAT_LOG_TAG "gpio"
  8. #include "luat_log.h"
  9. #define GPIO_CHECK(pin) ((pin<0 || pin>=SOC_GPIO_PIN_COUNT) ? -1:0)
  10. #if defined(CONFIG_IDF_TARGET_ESP32C3)
  11. static uint8_t warn_c3_gpio1819 = 0;
  12. #endif
  13. typedef struct gpio_cb_args
  14. {
  15. luat_gpio_irq_cb irq_cb;
  16. void*irq_args;
  17. }gpio_cb_args_t;
  18. static gpio_cb_args_t gpio_isr_cb[SOC_GPIO_PIN_COUNT] = {0};
  19. static uint8_t gpio_isr_sta = 0;
  20. int luat_gpio_irq_default(int pin, void* args);
  21. static void IRAM_ATTR gpio_isr_handler(void *arg) {
  22. uint32_t pin = (uint32_t)arg;
  23. if (gpio_isr_cb[pin].irq_cb)
  24. {
  25. gpio_isr_cb[pin].irq_cb(pin,gpio_isr_cb[pin].irq_args);
  26. }
  27. else
  28. luat_gpio_irq_default(pin, (void*)luat_gpio_get(pin));
  29. }
  30. int luat_gpio_setup(luat_gpio_t *gpio) {
  31. if (GPIO_CHECK(gpio->pin)) {
  32. LLOGW("not such GPIO number %d", gpio->pin);
  33. return -1;
  34. }
  35. int pin = gpio->pin;
  36. #if defined(CONFIG_IDF_TARGET_ESP32C3)
  37. // 如果是GPIO18/19, 这两个2脚也用在USB, 在简约版会导致USB连接中断
  38. if ((18 == pin || 19 == pin) && warn_c3_gpio1819 == 0) {
  39. if (warn_c3_gpio1819 == 0) {
  40. warn_c3_gpio1819 = 1;
  41. LLOGI("GPIO 18/19 is use for USB too");
  42. gpio_reset_pin(18);
  43. gpio_reset_pin(19);
  44. }
  45. }
  46. #elif defined(CONFIG_IDF_TARGET_ESP32S3)
  47. #endif
  48. // 重置管脚的功能为GPIO
  49. gpio_reset_pin(pin);
  50. // 设置输出/输入/中断状态
  51. if (gpio->mode == Luat_GPIO_OUTPUT) {
  52. // 输出模式
  53. gpio_set_direction(pin, GPIO_MODE_OUTPUT);
  54. // 还得设置初始状态
  55. gpio_set_level(pin, gpio->irq); // 输出模式时, gpio-irq兼职输出状态值
  56. }
  57. else if (gpio->mode == Luat_GPIO_INPUT) {
  58. gpio_set_direction(pin, GPIO_MODE_INPUT);
  59. }
  60. else if (gpio->mode == Luat_GPIO_IRQ) {
  61. if (gpio_isr_sta == 0) {
  62. gpio_install_isr_service(0);
  63. gpio_isr_sta = 1;
  64. }
  65. // 中断当然是输入模式了
  66. gpio_set_direction(pin, GPIO_MODE_INPUT);
  67. switch (gpio->irq) {
  68. // 上升沿
  69. case Luat_GPIO_RISING:
  70. gpio_set_intr_type(pin, GPIO_INTR_POSEDGE);
  71. break;
  72. // 下降沿
  73. case Luat_GPIO_FALLING:
  74. gpio_set_intr_type(pin, GPIO_INTR_NEGEDGE);
  75. break;
  76. // 高电平
  77. case Luat_GPIO_HIGH_IRQ:
  78. gpio_set_intr_type(pin, GPIO_INTR_HIGH_LEVEL);
  79. break;
  80. // 低电平
  81. case Luat_GPIO_LOW_IRQ:
  82. gpio_set_intr_type(pin, GPIO_INTR_LOW_LEVEL);
  83. break;
  84. // 双向触发, 上升沿和下降沿都触发
  85. case Luat_GPIO_BOTH:
  86. default:
  87. gpio_set_intr_type(pin, GPIO_INTR_ANYEDGE);
  88. break;
  89. }
  90. if (gpio->irq_cb) {
  91. gpio_isr_cb[pin].irq_cb = gpio->irq_cb;
  92. gpio_isr_cb[pin].irq_args = gpio->irq_args;
  93. }
  94. gpio_isr_handler_add(pin, gpio_isr_handler, (void *)pin);
  95. }
  96. // 上拉/下拉状态
  97. switch (gpio->pull) {
  98. case Luat_GPIO_PULLUP:
  99. gpio_set_pull_mode(pin, GPIO_PULLUP_ONLY);
  100. break;
  101. case Luat_GPIO_PULLDOWN:
  102. gpio_set_pull_mode(pin, GPIO_PULLDOWN_ONLY);
  103. break;
  104. // 默认浮空状态
  105. case Luat_GPIO_DEFAULT:
  106. default:
  107. gpio_set_pull_mode(pin, GPIO_FLOATING);
  108. break;
  109. }
  110. return 0;
  111. }
  112. int luat_gpio_set(int pin, int level) {
  113. if (pin == Luat_GPIO_MAX_ID)
  114. return 0;
  115. if (GPIO_CHECK(pin)) {
  116. return -1;
  117. }
  118. gpio_set_level(pin, level);
  119. return 0; // 总是返回正常, pin正确不可能失败吧
  120. }
  121. int luat_gpio_get(int pin) {
  122. if (pin == Luat_GPIO_MAX_ID)
  123. return 0;
  124. if (GPIO_CHECK(pin)) {
  125. return 0; // 不存在? 总是返回0, 低电平
  126. }
  127. return gpio_get_level(pin);
  128. }
  129. void luat_gpio_close(int pin) {
  130. if (GPIO_CHECK(pin)) {
  131. return;
  132. }
  133. if (gpio_isr_cb[pin].irq_cb)
  134. {
  135. gpio_isr_cb[pin].irq_cb = 0;
  136. gpio_isr_cb[pin].irq_args = 0;
  137. }
  138. gpio_reset_pin(pin);
  139. }
  140. #include "soc/gpio_reg.h"
  141. #define GPIO_OUT_PULSE (*(volatile unsigned int*)(GPIO_OUT_REG))
  142. static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
  143. void IRAM_ATTR luat_gpio_pulse(int pin, uint8_t *level, uint16_t len, uint16_t delay_ns) {
  144. volatile uint32_t tmp = delay_ns > 1024 ? 1024 : delay_ns;
  145. portENTER_CRITICAL_SAFE(&mux);
  146. for(int i=0; i<len; i++) {
  147. if(level[i/8]&(0x80>>(i%8)))
  148. GPIO_OUT_PULSE |= (0x00000001<<pin); // TODO 预先计算会不会更好一些, 也更快
  149. else
  150. GPIO_OUT_PULSE &= ~(0x00000001<<pin);
  151. tmp = delay_ns > 1024 ? 1024 : delay_ns;
  152. while(tmp--); // nop
  153. }
  154. portEXIT_CRITICAL_SAFE(&mux);
  155. }