driver_gpio.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. * @File name : driver_gpio.c
  3. * @Author : Bluetrum IOT Team
  4. * @Date : 2023-02-13
  5. * @Description : This file provides functions to manage the most functionalities
  6. * of the GPIO peripheral.
  7. *
  8. * Copyright (c) by Bluetrum, All Rights Reserved.
  9. */
  10. #include "driver_gpio.h"
  11. const gpio_edge_cap_typedef separate_wakeup_io[WAKEUP_IDX_MAX] = {
  12. /*edge is useless from PA7 to PB4 */
  13. [WAKEUP_IDX_PA7] = {GPIO_EDGE_RISING, GPIOA_REG, GPIO_PIN_7},
  14. [WAKEUP_IDX_PB1] = {GPIO_EDGE_RISING, GPIOB_REG, GPIO_PIN_1},
  15. [WAKEUP_IDX_PB2] = {GPIO_EDGE_RISING, GPIOB_REG, GPIO_PIN_2},
  16. [WAKEUP_IDX_PB3] = {GPIO_EDGE_RISING, GPIOB_REG, GPIO_PIN_3},
  17. [WAKEUP_IDX_PB4] = {GPIO_EDGE_RISING, GPIOB_REG, GPIO_PIN_4},
  18. /*WK0 no used in this array*/
  19. [WAKEUP_IDX_WK0] = {GPIO_EDGE_RISING, NULL, 0},
  20. [WAKEUP_IDX_PORT_FALL] = {GPIO_EDGE_FALLING, NULL, 0},
  21. [WAKEUP_IDX_PORT_RISE] = {GPIO_EDGE_RISING, NULL, 0},
  22. };
  23. /**
  24. * @brief Initializes the gpiox peripheral according to the specified
  25. * parameters in the gpio_init_struct.
  26. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  27. * @param gpio_init_struct: pointer to a gpio_init_typedef structure that
  28. * contains the configuration information for the specified GPIO peripheral.
  29. * @retval None
  30. */
  31. void gpio_init(gpio_typedef* gpiox, gpio_init_typedef* gpio_init_struct)
  32. {
  33. u32 reg;
  34. uint32_t pin_idx = 0, pin_bit_offset = 0x00;
  35. uint8_t i = 0x00;
  36. /*--- Configure the port pins ---*/
  37. for (pin_idx = 0; pin_idx < 16; pin_idx++) {
  38. pin_bit_offset = ((uint32_t)0x01) << pin_idx;
  39. if (gpio_init_struct->gpio_pin & pin_bit_offset) {
  40. /*--- Input or Output Configuration ---*/
  41. reg = gpiox->dir;
  42. reg &= ~pin_bit_offset;
  43. reg |= ((uint32_t)(gpio_init_struct->gpio_dir) << pin_idx);
  44. gpiox->dir = reg;
  45. /*--- Digital or Analog Configuration ---*/
  46. reg = gpiox->de;
  47. reg &= ~pin_bit_offset;
  48. reg |= ((uint32_t)(gpio_init_struct->gpio_mode) << pin_idx);
  49. gpiox->de = reg;
  50. /*--- Function Mapping Enable Configuration ---*/
  51. reg = gpiox->fen;
  52. reg &= ~pin_bit_offset;
  53. reg |= ((uint32_t)(gpio_init_struct->gpio_fen) << pin_idx);
  54. gpiox->fen = reg;
  55. /*--- GPIO Direction Select Configguratiopn ---*/
  56. reg = gpiox->fdir;
  57. reg &= ~pin_bit_offset;
  58. reg |= ((uint32_t)(gpio_init_struct->gpio_fdir) << pin_idx);
  59. gpiox->fdir = reg;
  60. /*--- Pull Up or Pull Down Configuration and clear driving cfg ---*/
  61. if (gpio_init_struct->gpio_dir == GPIO_DIR_INPUT) {
  62. gpiox->drv &= ~pin_bit_offset;
  63. for (i = 0; i < 6; i++) {
  64. reg = gpiox->pupd[i];
  65. reg &= ~pin_bit_offset;
  66. if ((i + 1) == gpio_init_struct->gpio_pupd) {
  67. reg |= pin_bit_offset;
  68. }
  69. gpiox->pupd[i] = reg;
  70. }
  71. /*--- Output driving Configuration and clear pupu cfg ---*/
  72. } else if (gpio_init_struct->gpio_dir == GPIO_DIR_OUTPUT) {
  73. for (i = 0; i < 6; i++) {
  74. gpiox->pupd[i] &= ~pin_bit_offset;
  75. }
  76. if (gpio_init_struct->gpio_mode == GPIO_MODE_DIGITAL) {
  77. if (GPIO_SUPPORT_STRONG_CURRENT(gpio_init_struct->gpio_drv, gpiox, pin_idx)) {
  78. reg = gpiox->drv;
  79. reg |= ((uint32_t)(gpio_init_struct->gpio_drv));
  80. gpiox->drv = reg;
  81. } else {
  82. reg = gpiox->drv;
  83. reg &= ~pin_bit_offset;
  84. reg |= ((uint32_t)(gpio_init_struct->gpio_drv) << pin_idx);
  85. gpiox->drv = reg;
  86. }
  87. }
  88. }
  89. }
  90. }
  91. }
  92. /**
  93. * @brief De-initialize the specified GPIO peripheral.
  94. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  95. * @param gpio_pin: specifies the port bits to be written. This parameter
  96. * can be any combination of GPIO_PIN_x where x can be (0..15).
  97. * @retval None
  98. */
  99. uint32_t gpio_deinit(gpio_typedef *gpiox, uint16_t gpio_pin)
  100. {
  101. u32 reg_original_sta;
  102. if (gpiox == GPIOB_REG) {
  103. gpio_pin &= 0x3ff;
  104. }
  105. reg_original_sta = gpiox->de;
  106. gpiox->de &= ~gpio_pin;
  107. return reg_original_sta;
  108. }
  109. /**
  110. * @brief Sets the selected data port bits.
  111. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  112. * @param gpio_pin: specifies the port bits to be written. This parameter
  113. * can be any combination of GPIO_PIN_x where x can be (0..15).
  114. * @retval None
  115. */
  116. AT(.com_periph.gpio.set)
  117. void gpio_set_bits(gpio_typedef* gpiox, uint16_t gpio_pin)
  118. {
  119. gpiox->io_set = gpio_pin;
  120. }
  121. /**
  122. * @brief Clears the selected data port bits.
  123. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  124. * @param gpio_pin: specifies the port bits to be written.
  125. * This parameter can be any combination of GPIO_PIN_x where x can be (0..15).
  126. * @retval None
  127. */
  128. AT(.com_periph.gpio.reset)
  129. void gpio_reset_bits(gpio_typedef* gpiox, uint16_t gpio_pin)
  130. {
  131. gpiox->io_clr = gpio_pin;
  132. }
  133. /**
  134. * @brief Writes the specified GPIO output data port.
  135. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  136. * @param port_val: specifies the port bits to be written. This parameter
  137. * can be any combination of GPIO_PIN_x where x can be (0..15).
  138. * @retval None
  139. */
  140. AT(.com_periph.gpio.write)
  141. void gpio_write_data(gpio_typedef *gpiox, uint16_t port_val)
  142. {
  143. gpiox->data = port_val;
  144. }
  145. /**
  146. * @brief Toggles the selected output data port bits.
  147. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  148. * @param gpio_pin: specifies the port bits to be written. This parameter
  149. * can be any combination of GPIO_PIN_x where x can be (0..15).
  150. * @retval None
  151. */
  152. AT(.com_periph.gpio.toggle)
  153. void gpio_toggle_bits(gpio_typedef *gpiox, uint16_t gpio_pin)
  154. {
  155. gpiox->data ^= gpio_pin;
  156. }
  157. /**
  158. * @brief Reads the specified GPIO input data port.
  159. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  160. * @retval GPIO output data port value.
  161. */
  162. AT(.com_periph.gpio.read_data)
  163. uint16_t gpio_read_data(gpio_typedef* gpiox)
  164. {
  165. return ((uint16_t)(gpiox->data));
  166. }
  167. /**
  168. * @brief Reads the specified input port pin.
  169. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  170. * @param gpio_pin: specifies the port bit to read.
  171. * This parameter can be gpio_pin where x can be (0..15).
  172. * @retval The input port pin value.
  173. */
  174. AT(.com_periph.gpio.read_bit)
  175. uint8_t gpio_read_bit(gpio_typedef* gpiox, uint16_t gpio_pin)
  176. {
  177. uint8_t bit_status;
  178. if ((gpiox->data & gpio_pin) != BIT_RESET) {
  179. bit_status = (uint8_t)SET;
  180. } else {
  181. bit_status = (uint8_t)RESET;
  182. }
  183. return bit_status;
  184. }
  185. AT(.com_periph.gpio.set_input)
  186. void gpio_set_input(gpio_typedef* gpiox, uint16_t gpio_pin)
  187. {
  188. gpiox->dir |= gpio_pin;
  189. }
  190. AT(.com_periph.gpio.set_out)
  191. void gpio_set_out(gpio_typedef* gpiox, uint16_t gpio_pin)
  192. {
  193. gpiox->dir &= ~gpio_pin;
  194. }
  195. /**
  196. * @brief Configure GPIO function mapping.
  197. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  198. * @param gpio_pin: specifies the port bit to read.
  199. * This parameter can be gpio_pin where x can be (0..15).
  200. * @param func_idx: Peripheral index that need to config mapping. The value of this param
  201. * see enumeration "GPIO_CROSSBAR_PERIPHERAL_DEF" in the file "driver_gpio.h".
  202. * @retval None
  203. */
  204. void gpio_func_mapping_config(gpio_typedef* gpiox, uint16_t gpio_pin, GPIO_CROSSBAR_PERIPHERAL_DEF func_idx)
  205. {
  206. u8 i;
  207. u8 pin_idx;
  208. uint8_t register_idx, register_offset;
  209. u8 gpio_crossbar_idx_PA0 = 1;
  210. u8 gpio_crossbar_idx_PB0 = 17;
  211. /*--- Calculate the pin_dix for function mapping ---*/
  212. for (i = 0; i < 16; i++) {
  213. if ((1 << i) == gpio_pin) {
  214. break;
  215. }
  216. }
  217. if (gpiox == GPIOA_REG) {
  218. pin_idx = gpio_crossbar_idx_PA0 + i;
  219. } else {
  220. pin_idx = gpio_crossbar_idx_PB0 + i;
  221. }
  222. /*--- Check parameter validity ---*/
  223. if (func_idx >= GPIO_CROSSBAR_PERIPHERAL_MAX_IDX) {
  224. return;
  225. }
  226. if ((gpiox == GPIOB_REG) && (gpio_pin > GPIO_PIN_9)) {
  227. return;
  228. }
  229. /*--- function mapping config ---*/
  230. if (func_idx > GPIO_CROSSBAR_PERIPHERAL_INPUT_BASE) {
  231. register_idx = (func_idx - GPIO_CROSSBAR_PERIPHERAL_INPUT_BASE - 1) / 4;
  232. register_offset = (func_idx - GPIO_CROSSBAR_PERIPHERAL_INPUT_BASE - 1) % 4 * 8;
  233. /* Do nothing if the current peripheral is already mapped to the corresponding IO */
  234. if (((FUNCMAP->func_input_map[register_idx] >> register_offset) & 0x1f) == pin_idx) {
  235. return;
  236. }
  237. FUNCMAP->func_input_map[register_idx] |= (uint32_t)(0xff << register_offset);
  238. FUNCMAP->func_input_map[register_idx] |= (uint32_t)(pin_idx << register_offset);
  239. } else if (func_idx < GPIO_CROSSBAR_PERIPHERAL_INPUT_BASE) {
  240. register_idx = (pin_idx - 1) / 4;
  241. register_offset = (pin_idx - 1) % 4 * 8;
  242. /* Do nothing if the current peripheral is already mapped to the corresponding IO */
  243. if (((FUNCMAP->func_output_map[register_idx] >> register_offset) & 0x1f) == func_idx) {
  244. return;
  245. }
  246. FUNCMAP->func_output_map[register_idx] |= (uint32_t)(0xff << register_offset);
  247. FUNCMAP->func_output_map[register_idx] |= (uint32_t)(func_idx << register_offset);
  248. }
  249. }
  250. /**
  251. * @brief Clear GPIO function mapping config.
  252. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  253. * @param gpio_pin: specifies the port bit to read.
  254. * This parameter can be gpio_pin where x can be (0..15).
  255. * @retval None
  256. */
  257. void gpio_func_mapping_clear(gpio_typedef* gpiox, uint16_t gpio_pin)
  258. {
  259. uint8_t register_idx, register_offset;
  260. uint8_t i, j;
  261. u8 pin_idx;
  262. u8 gpio_crossbar_idx_PA0 = 1;
  263. u8 gpio_crossbar_idx_PB0 = 17;
  264. /* Calculate the pin_dix for function mapping */
  265. for (i = 0; i < 16; i++) {
  266. if ((1 << i) == gpio_pin) {
  267. break;
  268. }
  269. }
  270. if (gpiox == GPIOA_REG) {
  271. pin_idx = gpio_crossbar_idx_PA0 + i;
  272. } else {
  273. pin_idx = gpio_crossbar_idx_PB0 + i;
  274. }
  275. /* Clear output mapping */
  276. register_idx = (pin_idx - 1) / 4;
  277. register_offset = (pin_idx - 1) % 4 * 8;
  278. FUNCMAP->func_output_map[register_idx] |= (uint32_t)(0xff << register_offset);
  279. for (i = 0; i < 7; i++) {
  280. for (j = 0; j < 32; j += 8)
  281. if (((FUNCMAP->func_input_map[i] >> j) & 0x1f) == pin_idx) {
  282. FUNCMAP->func_input_map[i] |= (uint32_t)(0xff << j);
  283. }
  284. }
  285. }
  286. /**
  287. * @brief WK0 IO level detect config.
  288. * @param pull_up_en: Whether WK0 internal pull up enable.
  289. * @param pull_down_en: Whether WK0 internal pull down enable.
  290. * @param input_en: Whether WK0 input enable.
  291. * @retval None
  292. */
  293. void wko_io_config(FUNCTIONAL_STATE pull_up_en, FUNCTIONAL_STATE pull_down_en, FUNCTIONAL_STATE input_en)
  294. {
  295. if (pull_up_en) {
  296. RTCCON1 |= (uint32_t)(1 << 4);
  297. } else {
  298. RTCCON1 &= ~(uint32_t)(1 << 4);
  299. }
  300. if (pull_down_en) {
  301. RTCCON1 |= (uint32_t)(1 << 1);
  302. RTCCON11 |= (uint32_t)(1 << 4); // Sure this bit is enable, and recommends it is enabled normally.
  303. } else {
  304. RTCCON1 &= ~(uint32_t)(1 << 1);
  305. }
  306. if (input_en) {
  307. RTCCON1 |= (uint32_t)(1 << 0);
  308. } else {
  309. RTCCON1 &= ~(uint32_t)(1 << 0);
  310. }
  311. }
  312. /**
  313. * @brief Read WK0 level.
  314. * @retval The state of interrupt_type (SET or RESET).
  315. */
  316. AT(.com_periph.wk0.read_bit)
  317. FLAG_STATE wko_io_read_bit(void)
  318. {
  319. if (RTCCON & (1 << 19)) {
  320. return SET;
  321. } else {
  322. return RESET;
  323. }
  324. }
  325. void wk0_edge_capture_config(GPIO_EDGE_SEL edge)
  326. {
  327. clk_gate0_cmd(CLK_GATE0_LP, CLK_EN);
  328. if(edge == GPIO_EDGE_FALLING){
  329. wko_io_config(1, 0, 1);
  330. WKUPEDG |= BIT(5);
  331. }else{
  332. wko_io_config(0, 1, 1);
  333. WKUPEDG &= ~BIT(5);
  334. }
  335. WKUPCON |= BIT(5);
  336. WKUPCPND = 0xff << 16; //clear wakeup pending
  337. }
  338. uint32_t gpio_edge_capture_idx_get(gpio_edge_cap_typedef* config)
  339. {
  340. uint32_t ret_idx = WAKEUP_IDX_MAX;
  341. /*we first considered wakeup source is general IO */
  342. for (uint8_t i = WAKEUP_IDX_PORT_FALL; i < WAKEUP_IDX_MAX; i++) {
  343. if (config->edge == separate_wakeup_io[i].edge) {
  344. ret_idx = i;
  345. break;
  346. }
  347. }
  348. /*check if wakeup source is separate IO*/
  349. for (uint8_t i = WAKEUP_IDX_PA7; i < WAKEUP_IDX_WK0; i++) {
  350. if ((config->gpiox == separate_wakeup_io[i].gpiox) && (config->gpio_pin == separate_wakeup_io[i].gpio_pin)) {
  351. ret_idx = i;
  352. break;
  353. }
  354. }
  355. return ret_idx;
  356. }
  357. void gpio_edge_capture_config(gpio_edge_cap_typedef* config)
  358. {
  359. clk_gate0_cmd(CLK_GATE0_LP, CLK_EN);
  360. gpio_init_typedef gpio_config;
  361. uint32_t gpio_pin = config->gpio_pin;
  362. if(config->gpiox == GPIOB_REG){
  363. gpio_pin = ((uint32_t)config->gpio_pin) << 16;
  364. }
  365. gpio_config.gpio_pin = config->gpio_pin;
  366. gpio_config.gpio_dir = GPIO_DIR_INPUT;
  367. gpio_config.gpio_fen = GPIO_FEN_GPIO;
  368. gpio_config.gpio_fdir = GPIO_FDIR_SELF;
  369. gpio_config.gpio_mode = GPIO_MODE_DIGITAL;
  370. gpio_config.gpio_pupd = config->gpio_pupd;
  371. gpio_init(config->gpiox, &gpio_config);
  372. uint32_t wakeup_idx = gpio_edge_capture_idx_get(config);
  373. if(config->edge == GPIO_EDGE_RISING){
  374. PORTINTEDG &= ~gpio_pin;
  375. PORTINTEN |= gpio_pin;
  376. WKUPEDG &= ~BIT(wakeup_idx);
  377. WKUPCON |= BIT(wakeup_idx);
  378. }else{
  379. PORTINTEDG |= gpio_pin;
  380. PORTINTEN |= gpio_pin;
  381. WKUPEDG |= BIT(wakeup_idx);
  382. WKUPCON |= BIT(wakeup_idx);
  383. }
  384. WKUPCPND = 0xff << 16;
  385. }
  386. AT(.com_periph.gpio.pending_clr)
  387. void gpio_edge_pending_clear(void)
  388. {
  389. WKUPCPND = 0xff << 16;
  390. }
  391. AT(.com_periph.gpio.pending_is)
  392. bool gpio_is_edge_pending(void)
  393. {
  394. return ((WKUPEDG>>16) & 0xff) ? true : false;
  395. }
  396. void gpio_edge_pic_config(isr_t isr, int pr)
  397. {
  398. sys_irq_init(IRQn_PORT, pr, isr);
  399. WKUPCPND = 0xff << 16;
  400. WKUPCON |= BIT(16);
  401. }
  402. void gpio_edge_pic_disable(void)
  403. {
  404. PICEN &= ~BIT(IRQn_PORT);
  405. WKUPCON &= ~BIT(16);
  406. }