gpio.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. /******************************************************************************
  2. 版权所有:
  3. 文件名称: gpio.c
  4. 文件版本: 01.01
  5. 创建作者: zhaoyang
  6. 创建日期: 2023-12-14
  7. 功能说明: gpio驱动程序。
  8. 其它说明:
  9. 修改记录:
  10. [new]-->applay
  11. B_DO_ADJ --> GPIOD_17 --> gpio113 预置返校
  12. B_DO_0 --> GPIOD_03 --> gpio99 预置
  13. B_DO_1 --> GPIOD_19 --> gpio115
  14. B_DO_2 --> GPIOD_02 --> gpio98
  15. B_DO_3 --> GPIOD_09 --> gpio105
  16. B_DO_4 --> GPIOD_18 --> gpio114
  17. B_DO_5 --> GPIOD_16 --> gpio112
  18. B_DO_6 --> GPIOD_07 --> gpio103
  19. B_DO_7 --> GPIOD_08 --> gpio104
  20. B_DO_8 --> GPIOD_06 --> gpio102
  21. T536 start ↓↓↓↓↓↓
  22. RUN_LED --> PB7 --> gpio39
  23. ERR_LED --> PF4 --> gpio164
  24. ESAM_PWR --> PL7 --> gpio159
  25. LINE_LOSS_SET --> PM5 --> gpio389
  26. T536 end ↑↑↑↑↑↑
  27. */
  28. /*------------------------------- 头文件 --------------------------------------
  29. */
  30. #include "bspconfig.h"
  31. #include "gpio.h"
  32. #include "head.h"
  33. #include <rtdm/gpio.h>
  34. /*------------------------------- 宏定义 --------------------------------------
  35. */
  36. #if CFG_BSP_DEBUG
  37. #define _GPIO_DEBUG
  38. #endif
  39. /*------------------------------ 全局变量 -------------------------------------
  40. */
  41. typedef enum
  42. {
  43. SYS_GPIO = 0,
  44. RTDM_GPIO = 1,
  45. } GPIO_TYPE;
  46. unsigned short kc_pwm0_stu;
  47. unsigned short kc_pwm1_stu;
  48. unsigned short kc_kout0_stu;
  49. unsigned short kc_kout1_stu;
  50. extern uint32_t g_yx_buf[2]; // 预留64个遥信
  51. /*------------------------------ 函数声明 -------------------------------------
  52. */
  53. extern unsigned int change_di_ch(unsigned int di);
  54. int gpio_val_fd[DO_NUM];
  55. int gpio_dev_type[DO_NUM] = {
  56. SYS_GPIO,
  57. }; // 0:系统GPIO, 1:RTDM GPIO
  58. /* 开出gpio */
  59. const int gpio_val[DO_NUM] = {115, 98, 105, 114, 112, 103, 104, 102, 99, 113};
  60. // static int gpio_watchdog_val = 0;
  61. static int gpio_run_led_val = 0;
  62. /*------------------------------ 外部函数 -------------------------------------
  63. */
  64. int sysfs_gpio_unexport(int gpio)
  65. {
  66. char path[64];
  67. int fd;
  68. snprintf(path, sizeof(path), "/sys/class/gpio/unexport");
  69. fd = open(path, O_WRONLY);
  70. if (fd < 0)
  71. {
  72. perror("Failed to open unexport");
  73. return -1;
  74. }
  75. char buf[16];
  76. snprintf(buf, sizeof(buf), "%d", gpio);
  77. if (write(fd, buf, strlen(buf)) < 0)
  78. {
  79. perror("Failed to set GPIO");
  80. close(fd);
  81. return -1;
  82. }
  83. close(fd);
  84. return 0;
  85. }
  86. int sysfs_gpio_export(int gpio)
  87. {
  88. char path[64];
  89. int fd;
  90. // 检查是否已导出
  91. snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d", gpio);
  92. if (access(path, F_OK) == 0)
  93. {
  94. sysfs_gpio_unexport(gpio); // bugfix: 避免重复导出
  95. msleep(50); // 短暂等待让内核处理
  96. }
  97. snprintf(path, sizeof(path), "/sys/class/gpio/export");
  98. fd = open(path, O_WRONLY);
  99. if (fd < 0)
  100. {
  101. perror("Failed to open export");
  102. return -1;
  103. }
  104. char buf[16];
  105. snprintf(buf, sizeof(buf), "%d", gpio);
  106. if (write(fd, buf, strlen(buf)) < 0)
  107. {
  108. perror("Failed to export GPIO");
  109. close(fd);
  110. return -2;
  111. }
  112. close(fd);
  113. return 0;
  114. }
  115. int sysfs_gpio_set_direction(int gpio, int is_output)
  116. {
  117. char path[64];
  118. int fd;
  119. snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", gpio);
  120. fd = open(path, O_WRONLY);
  121. if (fd < 0)
  122. {
  123. perror("Failed to open direction");
  124. return -1;
  125. }
  126. if (write(fd, is_output ? "out" : "in", is_output ? 3 : 2) < 0)
  127. {
  128. perror("Failed to set direction");
  129. close(fd);
  130. return -1;
  131. }
  132. close(fd);
  133. return 0;
  134. }
  135. int sysfs_gpio_set_edge_detect(int gpio, int edge)
  136. {
  137. char path[64];
  138. int fd;
  139. snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", gpio);
  140. fd = open(path, O_WRONLY);
  141. if (fd < 0)
  142. {
  143. perror("Failed to open edge");
  144. close(fd);
  145. return -1;
  146. }
  147. if (write(fd, edge, strlen(edge)) < 0)
  148. {
  149. perror("Failed to set edge");
  150. close(fd);
  151. return -1;
  152. }
  153. close(fd);
  154. return 0;
  155. }
  156. int sysfs_gpio_set_value(int gpio, int value)
  157. {
  158. char path[64];
  159. int fd = -1;
  160. snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", gpio);
  161. fd = open(path, O_WRONLY);
  162. if (fd < 0)
  163. {
  164. perror("Failed to open value");
  165. return -1;
  166. }
  167. if (write(fd, value ? "1" : "0", 1) < 0)
  168. {
  169. perror("Failed to set value");
  170. close(fd);
  171. return -1;
  172. }
  173. return fd;
  174. }
  175. int sysfs_gpio_init(int gpio, int direction)
  176. {
  177. #define GPIO_LOW 0
  178. int ret;
  179. ret = sysfs_gpio_export(gpio);
  180. if (ret < 0)
  181. {
  182. dp_err_n_c("sysfs_gpio_export error ret = %d!", ret);
  183. return -1;
  184. }
  185. ret = sysfs_gpio_set_direction(gpio, direction);
  186. if (ret < 0)
  187. {
  188. dp_err_n_c("sysfs_gpio_set_direction error");
  189. }
  190. return sysfs_gpio_set_value(gpio, GPIO_LOW); // 初始化IO为低电平
  191. }
  192. int is_rtdm_device(int fd)
  193. {
  194. if (gpio_dev_type[fd] > SYS_GPIO)
  195. return 1;
  196. else if (gpio_dev_type[fd] == SYS_GPIO)
  197. return 0;
  198. else
  199. return -1;
  200. }
  201. int rt_write(int fd, char *buf, int len)
  202. {
  203. int value;
  204. if (len <= 0 || buf == NULL)
  205. {
  206. return -1;
  207. }
  208. if (is_rtdm_device(fd) == 1)
  209. {
  210. // Xenomai RTDM设备:需要转换为二进制值
  211. value = atoi(buf);
  212. if (value != 0 && value != 1)
  213. {
  214. dp_err_n_c("value :%d ERR, Please enter '0' or '1'", value);
  215. return -1;
  216. }
  217. return write(fd, &value, sizeof(value));
  218. }
  219. else
  220. {
  221. // 常规系统设备:直接传递字符串
  222. return write(fd, buf, len);
  223. }
  224. }
  225. int rtdm_gpio_init(int gpio, int direction)
  226. {
  227. #define GPIO_LOW 0
  228. char path[64];
  229. int fd = -1, ret;
  230. int value = 1;
  231. snprintf(path, sizeof(path), "/dev/rtdm/3604000.pinctrl/gpio%d", gpio);
  232. fd = open(path, O_RDWR);
  233. if (fd < 0)
  234. {
  235. perror("open");
  236. return -1;
  237. }
  238. if (113 == gpio) /* 预置继电器是开入 */
  239. {
  240. ret = ioctl(fd, GPIO_RTIOC_DIR_IN, &value);
  241. }
  242. else
  243. {
  244. ret = ioctl(fd, GPIO_RTIOC_DIR_OUT, &value);
  245. }
  246. if (ret < 0)
  247. {
  248. perror("ioctl DIR_OUT");
  249. close(fd);
  250. return -1;
  251. }
  252. rt_write(gpio_val_fd[DO_OUT0], "0", 2); // 初始化IO为低电平
  253. return fd;
  254. }
  255. int gpio_init(void)
  256. {
  257. #define GPIO_OUTPUT 1
  258. int i;
  259. for (i = 0; i < DO_NUM; i++)
  260. {
  261. gpio_val_fd[i] = rtdm_gpio_init(gpio_val[i], GPIO_OUTPUT);
  262. if (gpio_val_fd[i] < 0)
  263. {
  264. gpio_val_fd[i] = sysfs_gpio_init(gpio_val[i], GPIO_OUTPUT);
  265. if (gpio_val_fd[i] < 0)
  266. {
  267. dp_err_n_c("gpio_val_fd[%d] error", i);
  268. gpio_val_fd[i] = -1;
  269. gpio_dev_type[i] = -1;
  270. return -1;
  271. }
  272. }
  273. else
  274. {
  275. gpio_dev_type[i] = gpio_val_fd[i]; // 保存RTDM设备类型句柄,这里有风险,fd句柄可能为0
  276. }
  277. }
  278. msleep(10); // 延时10ms
  279. kc_pwm0_stu = 0;
  280. kc_pwm1_stu = 0;
  281. kc_kout0_stu = 0;
  282. kc_kout1_stu = 0;
  283. for (i = DO_OUT1; i < DO_NUM; i++)
  284. {
  285. write(gpio_val_fd[i], "1", 2);
  286. }
  287. return 0;
  288. }
  289. int gpio_exit(void)
  290. {
  291. int i;
  292. for (i = 0; i < DO_NUM; i++)
  293. {
  294. if (gpio_val_fd[i] >= 0)
  295. {
  296. close(gpio_val_fd[i]);
  297. gpio_val_fd[i] = -1;
  298. }
  299. sysfs_gpio_unexport(gpio_val[i]);
  300. }
  301. return 0;
  302. }
  303. /******************************************************************************
  304. 函数名称: gpio_get_kin
  305. 函数版本: 01.01
  306. 创建作者: sunxi
  307. 创建日期: 2008-09-16
  308. 函数说明: 得到开入的状态。
  309. 参数说明: 无
  310. 返回值: 返回开入的状态,每个bit代表一个开入量。
  311. 修改记录:
  312. */
  313. unsigned int gpio_get_kin(unsigned int addr)
  314. {
  315. register unsigned int dw;
  316. unsigned int value[3];
  317. value[0] = *(volatile unsigned int *)addr;
  318. value[1] = *(volatile unsigned int *)addr;
  319. value[2] = *(volatile unsigned int *)addr;
  320. dw = (value[0] & value[1]) | (value[0] & value[2]) | (value[1] & value[2]);
  321. return dw;
  322. }
  323. /******************************************************************************
  324. 函数名称: gpio_get_di
  325. 函数版本: 01.01
  326. 创建作者:
  327. 创建日期: 2014-11-28
  328. 函数说明: 得到开入的状态
  329. 参数说明: 无
  330. 返回值: 返回开入的状态,每个bit代表一个开入量。
  331. 修改记录:
  332. */
  333. unsigned int gpio_get_di(void)
  334. {
  335. unsigned int dw = 0;
  336. dw = g_yx_buf[0]; // 这里保存的是共享内存的yx值,156us更新一次
  337. return change_di_ch(~dw); // 取反---因为没有短接时,值为1. 所以要取反为0才行
  338. }
  339. /******************************************************************************
  340. 函数名称: gpio_di_fj
  341. 函数版本: 01.01
  342. 创建作者:
  343. 创建日期: 2014-11-28
  344. 函数说明: 读取开出返校遥信值,控制板遥信为YX17~YX18
  345. YX17:选择, YX18:执行
  346. 参数说明: 无
  347. 返回值: 返回遥信值
  348. 修改记录:
  349. */
  350. #ifdef DO_KOUT_CHECK
  351. unsigned short gpio_di_fj(unsigned char index) //(void)
  352. #else
  353. unsigned short gpio_di_fj(void)
  354. #endif
  355. {
  356. unsigned int di = 0;
  357. unsigned short ret = 0;
  358. di = gpio_get_di();
  359. #ifdef DO_KOUT_CHECK
  360. // V4-20;
  361. // ret = (unsigned short)((di >>19) & 0x0001);
  362. ret = (unsigned short)((di >> index) & 0x0001);
  363. #else
  364. ret = (unsigned short)((di >> 23) & 0x0001); // dtu
  365. #endif
  366. return ret;
  367. }
  368. static void gpio_kouten_do(int on, unsigned int kouten)
  369. {
  370. #if !defined CPU_FUXI
  371. if (kouten > KOUT_EN1)
  372. return;
  373. if(on)
  374. {
  375. }
  376. else
  377. {
  378. }
  379. #endif
  380. }
  381. /******************************************************************************
  382. 函数名称: gpio_kout_do
  383. 函数版本: 01.01
  384. 创建作者:
  385. 创建日期: 2014-11-28
  386. 函数说明: 开出
  387. 参数说明: on: 1开出, 0回收
  388. kout: 那一路
  389. 返回值: 无
  390. 修改记录:
  391. */
  392. void gpio_kout_do(int on, unsigned int kout)
  393. {
  394. // if (kout > (DO_NUM-DO_OUT0))
  395. // return;
  396. if (on)
  397. {
  398. if ((kout == 6) || (kout == 7))
  399. {
  400. // gpio_kouten_do(1,KOUT_EN1);
  401. kc_kout1_stu |= (1 << kout);
  402. }
  403. else
  404. {
  405. // gpio_kouten_do(1,KOUT_EN0);
  406. kc_kout0_stu |= (1 << kout);
  407. }
  408. write(gpio_val_fd[kout + DO_OUT0], "0", 2);
  409. }
  410. else
  411. {
  412. write(gpio_val_fd[kout + DO_OUT0], "1", 2);
  413. if ((kout == 6) || (kout == 7))
  414. {
  415. kc_kout1_stu &= ~(1 << kout);
  416. }
  417. else
  418. {
  419. kc_kout0_stu &= ~(1 << kout);
  420. }
  421. if ((kc_pwm1_stu == 0) && (kc_kout1_stu == 0))
  422. {
  423. // gpio_kouten_do(0,KOUT_EN1);
  424. }
  425. if ((kc_kout0_stu == 0) && (kc_pwm0_stu == 0))
  426. {
  427. // gpio_kouten_do(0,KOUT_EN0);
  428. }
  429. }
  430. }
  431. /******************************************************************************
  432. 函数名称: gpio_pwm_do
  433. 函数版本: 01.01
  434. 创建作者:
  435. 创建日期: 2014-11-28
  436. 函数说明: pwm开出,由于存在kc_pwm_stu,只允许在同一控制路径中开出(例如同一中断或同一线程).
  437. 参数说明: on: 1开出, 0回收
  438. 返回值: 无
  439. 修改记录:
  440. */
  441. void gpio_pwm_do(int on, unsigned int kout)
  442. {
  443. // if (kout >= DO_NUM)
  444. // return;
  445. if (on)
  446. {
  447. if ((kout == 0) || (kout == 1))
  448. {
  449. // gpio_kouten_do(1,KOUT_EN1);
  450. kc_pwm1_stu |= (1 << kout);
  451. }
  452. else
  453. {
  454. // gpio_kouten_do(1,KOUT_EN0);
  455. kc_pwm0_stu |= (1 << kout);
  456. }
  457. write(gpio_val_fd[kout], "0", 2);
  458. }
  459. else
  460. {
  461. write(gpio_val_fd[kout], "1", 2);
  462. if ((kout == 0) || (kout == 1))
  463. {
  464. kc_pwm1_stu &= ~(1 << kout);
  465. }
  466. else
  467. {
  468. kc_pwm0_stu &= ~(1 << kout);
  469. }
  470. if ((kc_pwm1_stu == 0) && (kc_kout1_stu == 0))
  471. {
  472. // gpio_kouten_do(0,KOUT_EN1);
  473. }
  474. if ((kc_kout0_stu == 0) && (kc_pwm0_stu == 0))
  475. {
  476. // gpio_kouten_do(0,KOUT_EN0);
  477. }
  478. }
  479. }
  480. /******************************************************************************
  481. 函数名称: gpio_get_wirelessin
  482. 函数版本: 01.01
  483. 创建作者: sunxi
  484. 创建日期: 2008-09-16
  485. 函数说明: 得到无线遥控的状态。
  486. 参数说明: 无
  487. 返回值: 返回开入的状态,每个bit代表一个开入量。
  488. 修改记录:
  489. */
  490. unsigned int gpio_get_wirelessin(void)
  491. {
  492. register unsigned int dw = 0;
  493. return dw;
  494. }
  495. unsigned int gpio_get_version(void)
  496. {
  497. register unsigned int dw = 0;
  498. return dw;
  499. }
  500. unsigned int gpio_get_addr(void)
  501. {
  502. register unsigned int dw = 0;
  503. return dw;
  504. }
  505. void _led_run_err(void)
  506. {
  507. // 上电就亮错误灯,有错误就继续亮没有就熄灭
  508. static uint8 err_led = 2;
  509. if (rt_err_count())
  510. {
  511. // 错误指示灯常亮且运行熄灭
  512. if (!(err_led & 0x01))
  513. {
  514. err_led |= 1;
  515. // write(gpio_val_fd_other[ERR_LED], "0", 2);
  516. // write(gpio_val_fd_other[RUN_LED], "1", 2);
  517. }
  518. return;
  519. }
  520. if (err_led)
  521. {
  522. err_led = 0;
  523. // write(gpio_val_fd_other[ERR_LED], "1", 2);
  524. }
  525. // 运行指示灯,每隔1s改变状态一次
  526. if (!gpio_run_led_val)
  527. {
  528. gpio_run_led_val = 1;
  529. // write(gpio_val_fd_other[RUN_LED], "0", 2);
  530. }
  531. else
  532. {
  533. gpio_run_led_val = 0;
  534. // write(gpio_val_fd_other[RUN_LED], "1", 2);
  535. }
  536. }
  537. void esam_power_ctrl(int on)
  538. {
  539. // if (on)
  540. // write(gpio_val_fd_other[ESAM_PWR], "1", 2);
  541. // else
  542. // write(gpio_val_fd_other[ESAM_PWR], "0", 2);
  543. }
  544. /*------------------------------ 内部函数 -------------------------------------
  545. */
  546. /*------------------------------ 测试函数 -------------------------------------
  547. */
  548. #ifdef _GPIO_DEBUG
  549. #include "ustimer.h"
  550. #include "rt.h"
  551. int gpio_test(void)
  552. {
  553. int ret = 0;
  554. // unsigned int i;
  555. // gpio_kouten_do(1,KOUT_EN1);
  556. #if 1
  557. while (1)
  558. {
  559. sleep(5);
  560. gpio_kout_do(1, DO_OUT2 - DO_OUT0);
  561. // gpio_kout_do(1,DO_OUT3-DO_OUT0);
  562. // gpio_pwm_do(1,DO_PWM1);
  563. sleep(5);
  564. gpio_kout_do(0, DO_OUT2 - DO_OUT0);
  565. // gpio_kout_do(0,DO_OUT3-DO_OUT0);
  566. // gpio_pwm_do(0,DO_PWM1);
  567. /*
  568. for(i=DO_OUT0; i<DO_NUM; i++)
  569. {
  570. rt_printf("kout number = %d!\r", i);
  571. //msleep();
  572. sleep(1);
  573. gpio_kout_do(1,i-DO_OUT0);
  574. sleep(1);
  575. gpio_kout_do(0,i-DO_OUT0);
  576. }
  577. */
  578. }
  579. #endif
  580. return ret;
  581. }
  582. int test_kc_function(void)
  583. {
  584. write(gpio_val_fd[DO_OUT_PRESET], "0", 2); // 预置动作
  585. char gpio_state[2];
  586. int ret;
  587. // 读取GPIO状态
  588. ret = read(gpio_val_fd[DO_IN_PRESET], gpio_state, sizeof(gpio_state));
  589. printf("ret: %d\n", ret);
  590. if (ret > 0)
  591. {
  592. gpio_state[ret] = '\0'; // 添加字符串结束符
  593. printf("PRESET: %s\n", gpio_state); // 应该是"0"或"1"
  594. }
  595. write(gpio_val_fd[DO_OUT0], "0", 2);
  596. sleep(1);
  597. write(gpio_val_fd[DO_OUT0], "1", 2);
  598. write(gpio_val_fd[DO_OUT1], "0", 2);
  599. sleep(1);
  600. write(gpio_val_fd[DO_OUT1], "1", 2);
  601. write(gpio_val_fd[DO_OUT2], "0", 2);
  602. sleep(1);
  603. write(gpio_val_fd[DO_OUT2], "1", 2);
  604. write(gpio_val_fd[DO_OUT3], "0", 2);
  605. sleep(1);
  606. write(gpio_val_fd[DO_OUT3], "1", 2);
  607. write(gpio_val_fd[DO_OUT_PRESET], "1", 2); // 预置动作
  608. // 读取GPIO状态
  609. ret = read(gpio_val_fd[DO_IN_PRESET], gpio_state, sizeof(gpio_state));
  610. printf("ret: %d\n", ret);
  611. if (ret > 0)
  612. {
  613. gpio_state[ret] = '\0'; // 添加字符串结束符
  614. printf("PRESET: %s\n", gpio_state); // 应该是"0"或"1"
  615. }
  616. write(gpio_val_fd[DO_OUT4], "0", 2);
  617. sleep(1);
  618. write(gpio_val_fd[DO_OUT4], "1", 2);
  619. write(gpio_val_fd[DO_OUT5], "0", 2);
  620. sleep(1);
  621. write(gpio_val_fd[DO_OUT5], "1", 2);
  622. write(gpio_val_fd[DO_OUT6], "0", 2);
  623. sleep(1);
  624. write(gpio_val_fd[DO_OUT6], "1", 2);
  625. write(gpio_val_fd[DO_OUT7], "0", 2);
  626. sleep(1);
  627. write(gpio_val_fd[DO_OUT7], "1", 2);
  628. }
  629. #endif