luat_gpio_idf5.c 4.9 KB

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