driver_gpio.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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. /**
  186. * @brief Configure GPIO function mapping.
  187. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  188. * @param gpio_pin: specifies the port bit to read.
  189. * This parameter can be gpio_pin where x can be (0..15).
  190. * @param func_idx: Peripheral index that need to config mapping. The value of this param
  191. * see enumeration "GPIO_CROSSBAR_PERIPHERAL_DEF" in the file "driver_gpio.h".
  192. * @retval None
  193. */
  194. void gpio_func_mapping_config(gpio_typedef* gpiox, uint16_t gpio_pin, GPIO_CROSSBAR_PERIPHERAL_DEF func_idx)
  195. {
  196. u8 i;
  197. u8 pin_idx;
  198. uint8_t register_idx, register_offset;
  199. u8 gpio_crossbar_idx_PA0 = 1;
  200. u8 gpio_crossbar_idx_PB0 = 17;
  201. /*--- Calculate the pin_dix for function mapping ---*/
  202. for (i = 0; i < 16; i++) {
  203. if ((1 << i) == gpio_pin) {
  204. break;
  205. }
  206. }
  207. if (gpiox == GPIOA_REG) {
  208. pin_idx = gpio_crossbar_idx_PA0 + i;
  209. } else {
  210. pin_idx = gpio_crossbar_idx_PB0 + i;
  211. }
  212. /*--- Check parameter validity ---*/
  213. if (func_idx >= GPIO_CROSSBAR_PERIPHERAL_MAX_IDX) {
  214. return;
  215. }
  216. if ((gpiox == GPIOB_REG) && (gpio_pin > GPIO_PIN_9)) {
  217. return;
  218. }
  219. /*--- function mapping config ---*/
  220. if (func_idx > GPIO_CROSSBAR_PERIPHERAL_INPUT_BASE) {
  221. register_idx = (func_idx - GPIO_CROSSBAR_PERIPHERAL_INPUT_BASE - 1) / 4;
  222. register_offset = (func_idx - GPIO_CROSSBAR_PERIPHERAL_INPUT_BASE - 1) % 4 * 8;
  223. /* Do nothing if the current peripheral is already mapped to the corresponding IO */
  224. if (((FUNCMAP->func_input_map[register_idx] >> register_offset) & 0x1f) == pin_idx) {
  225. return;
  226. }
  227. FUNCMAP->func_input_map[register_idx] |= (uint32_t)(0xff << register_offset);
  228. FUNCMAP->func_input_map[register_idx] |= (uint32_t)(pin_idx << register_offset);
  229. } else if (func_idx < GPIO_CROSSBAR_PERIPHERAL_INPUT_BASE) {
  230. register_idx = (pin_idx - 1) / 4;
  231. register_offset = (pin_idx - 1) % 4 * 8;
  232. /* Do nothing if the current peripheral is already mapped to the corresponding IO */
  233. if (((FUNCMAP->func_output_map[register_idx] >> register_offset) & 0x1f) == func_idx) {
  234. return;
  235. }
  236. FUNCMAP->func_output_map[register_idx] |= (uint32_t)(0xff << register_offset);
  237. FUNCMAP->func_output_map[register_idx] |= (uint32_t)(func_idx << register_offset);
  238. }
  239. }
  240. /**
  241. * @brief Clear GPIO function mapping config.
  242. * @param gpiox: where x can be (A.B) to select the GPIO peripheral.
  243. * @param gpio_pin: specifies the port bit to read.
  244. * This parameter can be gpio_pin where x can be (0..15).
  245. * @retval None
  246. */
  247. void gpio_func_mapping_clear(gpio_typedef* gpiox, uint16_t gpio_pin)
  248. {
  249. uint8_t register_idx, register_offset;
  250. uint8_t i, j;
  251. u8 pin_idx;
  252. u8 gpio_crossbar_idx_PA0 = 1;
  253. u8 gpio_crossbar_idx_PB0 = 17;
  254. /* Calculate the pin_dix for function mapping */
  255. for (i = 0; i < 16; i++) {
  256. if ((1 << i) == gpio_pin) {
  257. break;
  258. }
  259. }
  260. if (gpiox == GPIOA_REG) {
  261. pin_idx = gpio_crossbar_idx_PA0 + i;
  262. } else {
  263. pin_idx = gpio_crossbar_idx_PB0 + i;
  264. }
  265. /* Clear output mapping */
  266. register_idx = (pin_idx - 1) / 4;
  267. register_offset = (pin_idx - 1) % 4 * 8;
  268. FUNCMAP->func_output_map[register_idx] |= (uint32_t)(0xff << register_offset);
  269. for (i = 0; i < 7; i++) {
  270. for (j = 0; j < 32; j += 8)
  271. if (((FUNCMAP->func_input_map[i] >> j) & 0x1f) == pin_idx) {
  272. FUNCMAP->func_input_map[i] |= (uint32_t)(0xff << j);
  273. }
  274. }
  275. }
  276. /**
  277. * @brief WK0 IO level detect config.
  278. * @param pull_up_en: Whether WK0 internal pull up enable.
  279. * @param pull_down_en: Whether WK0 internal pull down enable.
  280. * @param input_en: Whether WK0 input enable.
  281. * @retval None
  282. */
  283. void wko_io_config(FUNCTIONAL_STATE pull_up_en, FUNCTIONAL_STATE pull_down_en, FUNCTIONAL_STATE input_en)
  284. {
  285. if (pull_up_en) {
  286. RTCCON1 |= (uint32_t)(1 << 4);
  287. } else {
  288. RTCCON1 &= ~(uint32_t)(1 << 4);
  289. }
  290. if (pull_down_en) {
  291. RTCCON1 |= (uint32_t)(1 << 1);
  292. RTCCON11 |= (uint32_t)(1 << 4); // Sure this bit is enable, and recommends it is enabled normally.
  293. } else {
  294. RTCCON1 &= ~(uint32_t)(1 << 1);
  295. }
  296. if (input_en) {
  297. RTCCON1 |= (uint32_t)(1 << 0);
  298. } else {
  299. RTCCON1 &= ~(uint32_t)(1 << 0);
  300. }
  301. }
  302. /**
  303. * @brief Read WK0 level.
  304. * @retval The state of interrupt_type (SET or RESET).
  305. */
  306. AT(.com_periph.wk0.read_bit)
  307. FLAG_STATE wko_io_read_bit(void)
  308. {
  309. if (RTCCON & (1 << 19)) {
  310. return SET;
  311. } else {
  312. return RESET;
  313. }
  314. }
  315. void wk0_edge_capture_config(GPIO_EDGE_SEL edge)
  316. {
  317. clk_gate0_cmd(CLK_GATE0_LP, CLK_EN);
  318. if(edge == GPIO_EDGE_FALLING){
  319. wko_io_config(1, 0, 1);
  320. WKUPEDG |= BIT(5);
  321. }else{
  322. wko_io_config(0, 1, 1);
  323. WKUPEDG &= ~BIT(5);
  324. }
  325. WKUPCON |= BIT(5);
  326. WKUPCPND = 0xff << 16; //clear wakeup pending
  327. }
  328. uint32_t gpio_edge_capture_idx_get(gpio_edge_cap_typedef* config)
  329. {
  330. uint32_t ret_idx = WAKEUP_IDX_MAX;
  331. /*we first considered wakeup source is general IO */
  332. for (uint8_t i = WAKEUP_IDX_PORT_FALL; i < WAKEUP_IDX_MAX; i++) {
  333. if (config->edge == separate_wakeup_io[i].edge) {
  334. ret_idx = i;
  335. break;
  336. }
  337. }
  338. /*check if wakeup source is separate IO*/
  339. for (uint8_t i = WAKEUP_IDX_PA7; i < WAKEUP_IDX_WK0; i++) {
  340. if ((config->gpiox == separate_wakeup_io[i].gpiox) && (config->gpio_pin == separate_wakeup_io[i].gpio_pin)) {
  341. ret_idx = i;
  342. break;
  343. }
  344. }
  345. return ret_idx;
  346. }
  347. void gpio_edge_capture_config(gpio_edge_cap_typedef* config)
  348. {
  349. clk_gate0_cmd(CLK_GATE0_LP, CLK_EN);
  350. gpio_init_typedef gpio_config;
  351. uint32_t gpio_pin = config->gpio_pin;
  352. if(config->gpiox == GPIOB_REG){
  353. gpio_pin = ((uint32_t)config->gpio_pin) << 16;
  354. }
  355. gpio_config.gpio_pin = config->gpio_pin;
  356. gpio_config.gpio_dir = GPIO_DIR_INPUT;
  357. gpio_config.gpio_fen = GPIO_FEN_GPIO;
  358. gpio_config.gpio_fdir = GPIO_FDIR_SELF;
  359. gpio_config.gpio_mode = GPIO_MODE_DIGITAL;
  360. gpio_config.gpio_pupd = config->gpio_pupd;
  361. gpio_init(config->gpiox, &gpio_config);
  362. uint32_t wakeup_idx = gpio_edge_capture_idx_get(config);
  363. if(config->edge == GPIO_EDGE_RISING){
  364. PORTINTEDG &= ~gpio_pin;
  365. PORTINTEN |= gpio_pin;
  366. WKUPEDG &= ~BIT(wakeup_idx);
  367. WKUPCON |= BIT(wakeup_idx);
  368. }else{
  369. PORTINTEDG |= gpio_pin;
  370. PORTINTEN |= gpio_pin;
  371. WKUPEDG |= BIT(wakeup_idx);
  372. WKUPCON |= BIT(wakeup_idx);
  373. }
  374. WKUPCPND = 0xff << 16;
  375. }
  376. AT(.com_periph.gpio.pending_clr)
  377. void gpio_edge_pending_clear(void)
  378. {
  379. WKUPCPND = 0xff << 16;
  380. }
  381. AT(.com_periph.gpio.pending_is)
  382. bool gpio_is_edge_pending(void)
  383. {
  384. return ((WKUPEDG>>16) & 0xff) ? true : false;
  385. }
  386. void gpio_edge_pic_config(isr_t isr, int pr)
  387. {
  388. sys_irq_init(IRQn_PORT, pr, isr);
  389. WKUPCPND = 0xff << 16;
  390. WKUPCON |= BIT(16);
  391. }
  392. void gpio_edge_pic_disable(void)
  393. {
  394. PICEN &= ~BIT(IRQn_PORT);
  395. WKUPCON &= ~BIT(16);
  396. }