1 /**
2   *********************************************************************************
3   *
4   * @file    ald_gpio.c
5   * @brief   GPIO module driver.
6   *          This file provides firmware functions to manage the following
7   *          functionalities of the General Purpose Input/Output (GPIO) peripheral:
8   *           + Initialization functions
9   *           + IO operation functions
10   *           + Control functions
11   *
12   * @version V1.0
13   * @date    07 Nov 2017
14   * @author  AE Team
15   * @note
16   *
17   * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
18   *
19   * SPDX-License-Identifier: Apache-2.0
20   *
21   * Licensed under the Apache License, Version 2.0 (the License); you may
22   * not use this file except in compliance with the License.
23   * You may obtain a copy of the License at
24   *
25   * www.apache.org/licenses/LICENSE-2.0
26   *
27   * Unless required by applicable law or agreed to in writing, software
28   * distributed under the License is distributed on an AS IS BASIS, WITHOUT
29   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30   * See the License for the specific language governing permissions and
31   * limitations under the License.
32   *
33   *********************************************************************************
34   * @verbatim
35   ==============================================================================
36                     ##### GPIO Peripheral features #####
37   ==============================================================================
38   [..]
39   Subject to the specific hardware characteristics of each I/O port listed in the datasheet, each
40   port bit of the General Purpose IO (GPIO) Ports, can be individually configured by software
41   in several modes:
42   (+) Input mode
43   (+) Analog mode
44   (+) Output mode
45   (+) External interrupt/event lines
46 
47   [..]
48   During and just after reset, the external interrupt lines are not active and
49   the I/O ports are configured Analog mode.
50 
51   [..]
52   All GPIO pins have weak internal pull-up and pull-down resistors, which can be
53   activated or not.
54 
55   [..]
56   In Output mode, each IO can be configured on open-drain or push-pull
57   type and the Output driver can be selected depending on ODRV register.
58 
59   [..]
60   In Input mode, each IO can select filter function.
61 
62   [..]
63   Each IO can select TTL or SMIT type.
64 
65   [..]
66   Each IO have up to eight functions, user can configure the functions depend
67   on the user's environment.
68 
69   [..]
70   Each IO can be locked. Once locked, uesr can only change the output data.
71   Only when the CPU reset to unlock the GPIO port.
72 
73   [..]
74   All ports have external interrupt/event capability. To use external interrupt
75   lines, the port must be configured in input mode. All available GPIO pins are
76   connected to the 16 external interrupt/event lines from EXTI0 to EXTI15.
77 
78   [..]
79   Each input line can be independently configured to select the type (event or interrupt) and
80   the corresponding trigger event (rising or falling). Each line can also masked
81   independently. A pending register maintains the status line of the interrupt requests.
82 
83   ==============================================================================
84                         ##### How to use this driver #####
85   ==============================================================================
86   [..]
87    (#) Enable the GPIO clock.
88 
89    (#) Configure the GPIO pin(s) using ald_gpio_init().
90        (++) Configure the IO mode using "mode" member from gpio_init_t structure
91        (++) Activate Pull-up, Pull-down resistor using "pupd" member from gpio_init_t
92             structure.
93        (++) In Output mode, configured on open-drain or push-pull using "odos"
94             member from gpio_init_t structure.
95        (++) In Output mode, configured output driver using "odrv" member
96             from gpio_init_t structure.
97        (++) In Input mode, configured filter function using "flt" member
98             from gpio_init_t structure.
99        (++) Configured type using "type" member from gpio_init_t structure.
100        (++) Configured functions using "func" member from gpio_init_t structure.
101        (++) Analog mode is required when a pin is to be used as ADC channel
102             or DAC output.
103 
104    (#) Configure the GPIO pin(s) using ald_gpio_init_default().
105        (++) Configure GPIO pin using default param:
106             init.mode = GPIO_MODE_OUTPUT;
107             init.odos = GPIO_PUSH_PULL;
108             init.pupd = GPIO_PUSH_UP;
109             init.odrv = GPIO_OUT_DRIVE_NORMAL;
110             init.flt  = GPIO_FILTER_DISABLE;
111             init.type = GPIO_TYPE_TTL;
112             init.func = GPIO_FUNC_1;
113 
114    (#) In case of external interrupt/event mode selection, user need invoke
115        ald_gpio_exti_init() to configure some param. And then invoke
116        ald_gpio_exti_interrupt_config() to enable/disable external interrupt/event.
117 
118    (#) In case of external interrupt/event mode selection, configure NVIC IRQ priority
119        mapped to the EXTI line using NVIC_SetPriority() and enable it using
120        NVIC_EnableIRQ().
121 
122    (#) To get the level of a pin configured in input mode use GPIO_read_pin().
123 
124    (#) To set/reset the level of a pin configured in output mode use
125        ald_gpio_write_pin()/ald_gpio_toggle_pin().
126 
127    (#) To lock pin configuration until next reset use ald_gpio_lock_pin().
128 
129    (#) Configure external interrupt mode and enable/disable using
130        ald_gpio_exti_interrupt_config().
131 
132    (#) Get external interrupt flag status using ald_gpio_exti_get_flag_status().
133 
134    (#) Clear pending external interrupt flag status using
135        ald_gpio_exti_clear_flag_status().
136 
137     @endverbatim
138   */
139 
140 #include "ald_conf.h"
141 #include "ald_gpio.h"
142 
143 
144 /** @addtogroup ES32FXXX_ALD
145   * @{
146   */
147 
148 /** @defgroup GPIO GPIO
149   * @brief GPIO module driver
150   * @{
151   */
152 
153 #ifdef ALD_GPIO
154 
155 /** @defgroup GPIO_Public_Functions GPIO Public Functions
156   * @{
157   */
158 
159 /** @defgroup GPIO_Public_Functions_Group1 Initialization functions
160   * @brief    Initialization and Configuration functions
161   *
162     @verbatim
163  ===============================================================================
164               ##### Initialization functions #####
165  ===============================================================================
166   [..]
167     This section provides functions allowing to initialize the GPIOs or external
168     interrupt to be ready for use.
169 
170     @endverbatim
171   * @{
172   */
173 
174 /**
175   * @brief  Initialize the GPIOx peripheral according to the specified
176   *         parameters in the gpio_init_t.
177   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
178   * @param  pin: The pin which need to initialize.
179   * @param  init: Pointer to a gpio_init_t structure that can contains
180   *         the configuration information for the specified parameters.
181   * @retval None
182   */
ald_gpio_init(GPIO_TypeDef * GPIOx,uint16_t pin,gpio_init_t * init)183 void ald_gpio_init(GPIO_TypeDef *GPIOx, uint16_t pin, gpio_init_t *init)
184 {
185 	uint32_t i, pos, mask, tmp;
186 
187 	assert_param(IS_GPIO_PORT(GPIOx));
188 	assert_param(IS_GPIO_PIN(pin));
189 	assert_param(IS_GPIO_MODE(init->mode));
190 	assert_param(IS_GPIO_ODOS(init->odos));
191 	assert_param(IS_GPIO_PUPD(init->pupd));
192 	assert_param(IS_GPIO_ODRV(init->odrv));
193 	assert_param(IS_GPIO_FLT(init->flt));
194 	assert_param(IS_GPIO_TYPE(init->type));
195 	assert_param(IS_GPIO_FUNC(init->func));
196 
197 	for (i = 0; i < 16; ++i) {
198 		if (((pin >> i) & 0x1) == 0)
199 			continue;
200 
201 		/* Get position and 2-bits mask */
202 		pos  = i << 1;
203 		mask = 0x3 << pos;
204 
205 		/* Set PIN mode */
206 		tmp  = READ_REG(GPIOx->MODE);
207 		tmp &= ~mask;
208 		tmp |= (init->mode << pos);
209 		WRITE_REG(GPIOx->MODE, tmp);
210 
211 		/* Set PIN open-drain or push-pull */
212 		tmp  = READ_REG(GPIOx->ODOS);
213 		tmp &= ~mask;
214 		tmp |= (init->odos << pos);
215 		WRITE_REG(GPIOx->ODOS, tmp);
216 
217 		/* Set PIN push-up or/and push-down */
218 		tmp  = READ_REG(GPIOx->PUPD);
219 		tmp &= ~mask;
220 		tmp |= (init->pupd << pos);
221 		WRITE_REG(GPIOx->PUPD, tmp);
222 
223 		/* Set PIN output driver */
224 		tmp  = READ_REG(GPIOx->ODRV);
225 		tmp &= ~mask;
226 		tmp |= (init->odrv << pos);
227 		WRITE_REG(GPIOx->ODRV, tmp);
228 
229 		/* Get position and 1-bit mask */
230 		pos  = i;
231 		mask = 0x1 << pos;
232 
233 		/* Set PIN filter enable or disable */
234 		tmp  = READ_REG(GPIOx->FLT);
235 		tmp &= ~mask;
236 		tmp |= (init->flt << pos);
237 		WRITE_REG(GPIOx->FLT, tmp);
238 
239 		/* Set PIN type ttl or smit */
240 		tmp  = READ_REG(GPIOx->TYPE);
241 		tmp &= ~mask;
242 		tmp |= (init->type << pos);
243 		WRITE_REG(GPIOx->TYPE, tmp);
244 
245 		/* Configure PIN function */
246 		pos  = i < 8 ? (i << 2) : ((i - 8) << 2);
247 		mask = 0xF << pos;
248 		tmp  = i < 8 ? READ_REG(GPIOx->FUNC0) : READ_REG(GPIOx->FUNC1);
249 		tmp &= ~mask;
250 		tmp |= (init->func << pos);
251 		i < 8 ? WRITE_REG(GPIOx->FUNC0, tmp) : WRITE_REG(GPIOx->FUNC1, tmp);
252 	}
253 
254 	return;
255 }
256 
257 /**
258   * @brief  Initialize the GPIOx peripheral using the default parameters.
259   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
260   * @param  pin: The pin which need to initialize.
261   * @retval None
262   */
ald_gpio_init_default(GPIO_TypeDef * GPIOx,uint16_t pin)263 void ald_gpio_init_default(GPIO_TypeDef *GPIOx, uint16_t pin)
264 {
265 	gpio_init_t init;
266 
267 	/* Fill GPIO_init_t structure with default parameter */
268 	init.mode = GPIO_MODE_OUTPUT;
269 	init.odos = GPIO_PUSH_PULL;
270 	init.pupd = GPIO_PUSH_UP;
271 	init.odrv = GPIO_OUT_DRIVE_NORMAL;
272 	init.flt  = GPIO_FILTER_DISABLE;
273 	init.type = GPIO_TYPE_CMOS;
274 	init.func = GPIO_FUNC_1;
275 
276 	ald_gpio_init(GPIOx, pin, &init);
277 	return;
278 }
279 
280 /**
281   * @brief  Sets GPIO function to default(func0).
282   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
283   * @retval None
284   */
ald_gpio_func_default(GPIO_TypeDef * GPIOx)285 void ald_gpio_func_default(GPIO_TypeDef *GPIOx)
286 {
287 	WRITE_REG(GPIOx->FUNC0, 0x00);
288 	WRITE_REG(GPIOx->FUNC1, 0x00);
289 
290 	return;
291 }
292 
293 /**
294   * @brief  Initialize the external interrupt according to the specified
295   *         parameters in the exti_init_t.
296   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
297   * @param  pin: The pin which need to initialize.
298   * @param  init: Pointer to a exti_init_t structure that can contains
299   *         the configuration information for the specified parameters.
300   * @retval None
301   */
ald_gpio_exti_init(GPIO_TypeDef * GPIOx,uint16_t pin,exti_init_t * init)302 void ald_gpio_exti_init(GPIO_TypeDef *GPIOx, uint16_t pin, exti_init_t *init)
303 {
304 	uint8_t i;
305 	uint8_t port;
306 
307 	assert_param(IS_GPIO_PORT(GPIOx));
308 	assert_param(IS_GPIO_PIN(pin));
309 	assert_param(IS_FUNC_STATE(init->filter));
310 	assert_param(IS_EXTI_FLTCKS_TYPE(init->cks));
311 
312 	/* Get GPIO port */
313 	if (GPIOx == GPIOA)
314 		port = 0x0;
315 	else if (GPIOx == GPIOB)
316 		port = 0x1;
317 	else if (GPIOx == GPIOC)
318 		port = 2;
319 	else if (GPIOx == GPIOD)
320 		port = 3;
321 	else if (GPIOx == GPIOE)
322 		port = 4;
323 	else if (GPIOx == GPIOF)
324 		port = 5;
325 	else if (GPIOx == GPIOG)
326 		port = 6;
327 	else if (GPIOx == GPIOH)
328 		port = 7;
329 	else
330 		port = 0;
331 
332 	/* Get Pin index */
333 	for (i = 0; i < 16; ++i) {
334 		if (((pin >> i) & 0x1) == 0x1)
335 			break;
336 	}
337 
338 	/* Select external interrupt line */
339 	if (i <= 7) {
340 		EXTI->EXTIPSR0 &= ~(0x7U << (i * 4));
341 		EXTI->EXTIPSR0 |= (port << (i * 4));
342 	}
343 	else {
344 		i -= 8;
345 		EXTI->EXTIPSR1 &= ~(0x7U << (i * 4));
346 		EXTI->EXTIPSR1 |= (port << (i * 4));
347 	}
348 
349 	/* Configure filter parameter */
350 	if (init->filter == ENABLE) {
351 		SET_BIT(EXTI->EXTIFLTCR, pin);
352 		MODIFY_REG(EXTI->EXTIFLTCR, GPIO_EXTIFLTCR_FLTCKS_MSK, init->cks << GPIO_EXTIFLTCR_FLTCKS_POSS);
353 		MODIFY_REG(EXTI->EXTIFLTCR, GPIO_EXTIFLTCR_FLTSEL_MSK, init->filter_time << GPIO_EXTIFLTCR_FLTSEL_POSS);
354 	}
355 	else {
356 		CLEAR_BIT(EXTI->EXTIFLTCR, pin);
357 	}
358 
359 	return;
360 }
361 /**
362   * @}
363   */
364 
365 /** @defgroup GPIO_Public_Functions_Group2 IO operation functions
366   * @brief   GPIO Read and Write
367   *
368     @verbatim
369  ===============================================================================
370                        ##### IO operation functions #####
371  ===============================================================================
372   [..]
373     This subsection provides a set of functions allowing to manage the GPIOs.
374 
375     @endverbatim
376   * @{
377   */
378 
379 /**
380   * @brief  Read the specified input port pin.
381   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
382   * @param  pin: Specifies the pin to read.
383   * @retval The input pin value
384   */
ald_gpio_read_pin(GPIO_TypeDef * GPIOx,uint16_t pin)385 uint8_t ald_gpio_read_pin(GPIO_TypeDef *GPIOx, uint16_t pin)
386 {
387 	assert_param(IS_GPIO_PORT(GPIOx));
388 	assert_param(IS_GPIO_PIN(pin));
389 
390 	if (READ_BIT(GPIOx->DIN, pin))
391 		return 1;
392 	else
393 		return 0;
394 }
395 
396 /**
397   * @brief  Set or clear the select Pin data.
398   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
399   * @param  pin: The specified pin to be written.
400   * @param  val: The specifies value to be written.
401   * @retval None
402   */
ald_gpio_write_pin(GPIO_TypeDef * GPIOx,uint16_t pin,uint8_t val)403 void ald_gpio_write_pin(GPIO_TypeDef *GPIOx, uint16_t pin, uint8_t val)
404 {
405 	assert_param(IS_GPIO_PORT(GPIOx));
406 	assert_param(IS_GPIO_PIN(pin));
407 
408 	if ((val & (0x01)) == 0x00)
409 		CLEAR_BIT(GPIOx->DOUT, pin);
410 	else
411 		SET_BIT(GPIOx->DOUT, pin);
412 
413 	return;
414 }
415 
416 /**
417   * @brief  Turn over the select data.
418   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
419   * @param  pin: Specifies the pin to turn over.
420   * @retval None
421   */
ald_gpio_toggle_pin(GPIO_TypeDef * GPIOx,uint16_t pin)422 void ald_gpio_toggle_pin(GPIO_TypeDef *GPIOx, uint16_t pin)
423 {
424 	assert_param(IS_GPIO_PORT(GPIOx));
425 	assert_param(IS_GPIO_PIN(pin));
426 
427 	WRITE_REG(GPIOx->BIR, pin);
428 	return;
429 }
430 
431 /**
432   * @brief  Turn over the direction.
433   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
434   * @param  pin: Specifies the pin to turn over.
435   * @retval None
436   */
ald_gpio_toggle_dir(GPIO_TypeDef * GPIOx,uint16_t pin)437 void ald_gpio_toggle_dir(GPIO_TypeDef *GPIOx, uint16_t pin)
438 {
439 	uint32_t i, pos, mask, tmp, value;
440 
441 	assert_param(IS_GPIO_PORT(GPIOx));
442 	assert_param(IS_GPIO_PIN(pin));
443 
444 	for (i = 0; i < 16; ++i) {
445 		if (((pin >> i) & 0x1) == 0)
446 			continue;
447 
448 		/* Get position and 2-bits mask */
449 		pos  = i << 1;
450 		mask = 0x3 << pos;
451 
452 		/* Get the new direction */
453 		tmp = READ_REG(GPIOx->MODE);
454 		value = (tmp >> pos) & 0x3;
455 
456 		if ((value == 2) || (value == 3))
457 			value = 1;
458 		else if (value == 1) {
459 			value = 2;
460 		}
461 		else {
462 			continue; /* do nothing */
463 		}
464 
465 		/* Set PIN mode */
466 		tmp &= ~mask;
467 		tmp |= (value << pos);
468 		WRITE_REG(GPIOx->MODE, tmp);
469 	}
470 
471 	return;
472 }
473 
474 /**
475   * @brief  Lock the GPIO prot. Once locked, can
476   *         only change the output data. Only when the CPU
477   *         reset to unlock the GPIO port.
478   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
479   * @param  pin: The specified Pin to be written.
480   * @retval None
481   */
ald_gpio_lock_pin(GPIO_TypeDef * GPIOx,uint16_t pin)482 void ald_gpio_lock_pin(GPIO_TypeDef *GPIOx, uint16_t pin)
483 {
484 	assert_param(IS_GPIO_PORT(GPIOx));
485 	assert_param(IS_GPIO_PIN(pin));
486 
487 	MODIFY_REG(GPIOx->LOCK, GPIO_LOCK_KEY_MSK, UNLOCK_KEY << GPIO_LOCK_KEY_POSS);
488 	WRITE_REG(GPIOx->LOCK, pin);
489 
490 	return;
491 }
492 
493 /**
494   * @brief  Read the specified input port pin.
495   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
496   * @retval The value;
497   */
ald_gpio_read_port(GPIO_TypeDef * GPIOx)498 uint16_t ald_gpio_read_port(GPIO_TypeDef *GPIOx)
499 {
500 	assert_param(IS_GPIO_PORT(GPIOx));
501 
502 	return READ_REG(GPIOx->DIN);
503 }
504 
505 /**
506   * @brief  Set or clear the select Pin data.
507   * @param  GPIOx: Where x can be (A--H) to select the GPIO peripheral.
508   * @param  val: The specifies value to be written.
509   * @retval None
510   */
ald_gpio_write_port(GPIO_TypeDef * GPIOx,uint16_t val)511 void ald_gpio_write_port(GPIO_TypeDef *GPIOx, uint16_t val)
512 {
513 	assert_param(IS_GPIO_PORT(GPIOx));
514 
515 	WRITE_REG(GPIOx->DOUT, val);
516 	return;
517 }
518 
519 
520 /**
521   * @}
522   */
523 
524 /** @defgroup GPIO_Public_Functions_Group3 Control functions
525   * @brief EXTI Control functions
526   *
527     @verbatim
528  ===============================================================================
529                        ##### Control functions #####
530  ===============================================================================
531   [..]
532     This subsection provides a set of functions allowing to
533     control external interrupt.
534 
535     @endverbatim
536   * @{
537   */
538 
539 /**
540   * @brief  Configure the interrupt according to the specified parameter.
541   * @param  pin: The Pin which need to configure.
542   * @param  style: External interrupt trigger style.
543   * @param  status:
544   *           @arg ENABLE
545   *           @arg DISABLE
546   * @retval None
547   */
ald_gpio_exti_interrupt_config(uint16_t pin,exti_trigger_style_t style,type_func_t status)548 void ald_gpio_exti_interrupt_config(uint16_t pin, exti_trigger_style_t style, type_func_t status)
549 {
550 	assert_param(IS_GPIO_PIN(pin));
551 	assert_param(IS_TRIGGER_STYLE(style));
552 	assert_param(IS_FUNC_STATE(status));
553 
554 	if (status == ENABLE) {
555 		if (style == EXTI_TRIGGER_RISING_EDGE) {
556 			SET_BIT(EXTI->EXTIRER, pin);
557 		}
558 		else if (style == EXTI_TRIGGER_TRAILING_EDGE) {
559 			SET_BIT(EXTI->EXTIFER, pin);
560 		}
561 		else if (style == EXTI_TRIGGER_BOTH_EDGE) {
562 			SET_BIT(EXTI->EXTIRER, pin);
563 			SET_BIT(EXTI->EXTIFER, pin);
564 		}
565 		else {
566 			; /* do nothing */
567 		}
568 
569 		WRITE_REG(EXTI->EXTICFR, 0xffff);
570 		SET_BIT(EXTI->EXTIEN, pin);
571 	}
572 	else {
573 		if (style == EXTI_TRIGGER_RISING_EDGE) {
574 			CLEAR_BIT(EXTI->EXTIRER, pin);
575 		}
576 		else if (style == EXTI_TRIGGER_TRAILING_EDGE) {
577 			CLEAR_BIT(EXTI->EXTIFER, pin);
578 		}
579 		else if (style == EXTI_TRIGGER_BOTH_EDGE) {
580 			CLEAR_BIT(EXTI->EXTIRER, pin);
581 			CLEAR_BIT(EXTI->EXTIFER, pin);
582 		}
583 		else {
584 			; /* do nothing */
585 		}
586 
587 		CLEAR_BIT(EXTI->EXTIEN, pin);
588 	}
589 
590 	return;
591 }
592 
593 /**
594   * @brief  Get the Flag about external interrupt.
595   * @param  pin: The pin which belong to external interrupt.
596   * @retval Flag status
597   *         - SET
598   *         - RESET
599   */
ald_gpio_exti_get_flag_status(uint16_t pin)600 flag_status_t ald_gpio_exti_get_flag_status(uint16_t pin)
601 {
602 	assert_param(IS_GPIO_PIN(pin));
603 
604 	if (READ_BIT(EXTI->EXTIFLAG, pin))
605 		return SET;
606 
607 	return RESET;
608 }
609 
610 /**
611   * @brief  Clear the external interrupt flag.
612   * @param  pin: The pin which belong to external interrupt.
613   * @retval None
614   */
ald_gpio_exti_clear_flag_status(uint16_t pin)615 void ald_gpio_exti_clear_flag_status(uint16_t pin)
616 {
617 	assert_param(IS_GPIO_PIN(pin));
618 
619 	WRITE_REG(EXTI->EXTICFR, pin);
620 	return;
621 }
622 /**
623   * @}
624   */
625 
626 /**
627   * @}
628   */
629 
630 #endif /* ALD_GPIO */
631 /**
632   * @}
633   */
634 
635 /**
636   * @}
637   */
638