1 /***************************************************************************//**
2 * \file cyhal_gpio.h
3 *
4 * \brief
5 * Provides a high level interface for interacting with the GPIO on Infineon devices.
6 * This interface abstracts out the chip specific details. If any chip specific
7 * functionality is necessary, or performance is critical the low level functions
8 * can be used directly.
9 *
10 ********************************************************************************
11 * \copyright
12 * Copyright 2018-2021 Cypress Semiconductor Corporation (an Infineon company) or
13 * an affiliate of Cypress Semiconductor Corporation
14 *
15 * SPDX-License-Identifier: Apache-2.0
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 *     http://www.apache.org/licenses/LICENSE-2.0
22 *
23 * Unless required by applicable law or agreed to in writing, software
24 * distributed under the License is distributed on an "AS IS" BASIS,
25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 * See the License for the specific language governing permissions and
27 * limitations under the License.
28 *******************************************************************************/
29 
30 /**
31 * \addtogroup group_hal_gpio GPIO (General Purpose Input Output)
32 * \ingroup group_hal
33 * \{
34 * High level interface for configuring and interacting with general purpose input/outputs (GPIO).
35 *
36 * The GPIO driver provides functions to configure and initialize GPIO, and to read and write data to the pin.
37 * The driver also supports interrupt generation on GPIO signals with rising, falling or both edges.
38 *
39 * \note The APIs in this driver need not be used if a GPIO is to be used as an input or output of peripherals like I2C or PWM.
40 * The respective peripheral's driver will utilize the GPIO interface to configure and initialize its GPIO pins.
41 *
42 * \section subsection_gpio_features Features
43 * * Configurable GPIO pin direction - \ref cyhal_gpio_direction_t
44 * * Configurable GPIO pin drive modes - \ref cyhal_gpio_drive_mode_t
45 * * Configurable analog and digital characteristics
46 * * Configurable edge-triggered interrupts and callback assignment on GPIO events - \ref cyhal_gpio_event_t
47 *
48 * \section subsection_gpio_quickstart Quick Start
49 * \ref cyhal_gpio_init can be used for a simple GPIO initialization by providing the pin number (<b>pin</b>), pin direction (<b>direction</b>),
50 * pin drive mode (<b>drive_mode</b>) and the initial value on the pin (<b>init_val</b>).
51 *
52 * \section subsection_gpio_sample_snippets Code Snippets
53 *
54 * \subsection subsection_gpio_snippet_1 Snippet 1: Reading value from GPIO
55 * The following snippet initializes GPIO pin as an input with high impedance digital drive mode and initial value = <b>false</b> (low). A value is read
56 * from the pin and stored to a uint8_t variable (<b>read_val</b>).
57 
58 * \snippet hal_gpio.c snippet_cyhal_gpio_read
59 
60 * \subsection subsection_gpio_snippet_2 Snippet 2: Writing value to a GPIO
61 * The following snippet initializes GPIO pin as an output pin with strong drive mode and initial value = <b>false</b> (low).
62 * A value = <b>true</b> (high) is written to the output driver.
63 
64 * \snippet hal_gpio.c snippet_cyhal_gpio_write
65 
66 * \subsection subsection_gpio_snippet_3 Snippet 3: Reconfiguring a GPIO
67 * The following snippet shows how to reconfigure a GPIO pin during run-time using the firmware. The GPIO pin
68 * is first initialized as an output pin with strong drive mode. The pin is then reconfigured as an input with high impedance digital drive mode.
69 * \note \ref cyhal_gpio_configure only changes the <b>direction</b> and the <b>drive_mode</b>
70 * of the pin. Previously set pin value is retained.
71 *
72 * \snippet hal_gpio.c snippet_cyhal_gpio_reconfigure
73 
74 * \subsection subsection_gpio_snippet_4 Snippet 4: Interrupts on GPIO events
75 * GPIO events can be mapped to an interrupt and assigned to a callback function. The callback function needs to be first registered and
76 * then the event needs to be enabled.
77 ** The following snippet initializes GPIO pin as an input pin. It registers a callback function and enables detection
78 * of a falling edge event to trigger the callback.
79 * \note If no argument needs to be passed to the callback function then a NULL can be passed during registering. <br>
80 *
81 * \snippet hal_gpio.c snippet_cyhal_gpio_interrupt
82 */
83 
84 #pragma once
85 
86 #include <stdint.h>
87 #include <stdbool.h>
88 #include "cy_result.h"
89 #include "cyhal_hw_types.h"
90 
91 #if defined(__cplusplus)
92 extern "C" {
93 #endif /* __cplusplus */
94 
95 /** \addtogroup group_hal_results_gpio GPIO HAL Results
96  *  GPIO specific return codes
97  *  \ingroup group_hal_results
98  *  \{ *//**
99  */
100 
101 /** The specified pin has no supported input signal */
102 #define CYHAL_GPIO_RSLT_ERR_NO_INPUT_SIGNAL \
103     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_GPIO, 0))
104 /** The specified pin has no supported output signal */
105 #define CYHAL_GPIO_RSLT_ERR_NO_OUTPUT_SIGNAL \
106     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_GPIO, 1))
107 /** The parameter is invalid */
108 #define CYHAL_GPIO_RSLT_ERR_BAD_PARAM \
109     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_GPIO, 2))
110 
111 /**
112  * \}
113  */
114 
115 /*******************************************************************************
116 *       Defines
117 *******************************************************************************/
118 
119 /** Integer representation of no connect pin (required to exist in all BSPs) */
120 #define CYHAL_NC_PIN_VALUE (NC)
121 
122 /*******************************************************************************
123 *       Enumerations
124 *******************************************************************************/
125 
126 /** Pin events */
127 typedef enum
128 {
129     CYHAL_GPIO_IRQ_NONE = 0,                                            /**< No interrupt */
130     CYHAL_GPIO_IRQ_RISE = 1 << 0,                                       /**< Interrupt on rising edge */
131     CYHAL_GPIO_IRQ_FALL = 1 << 1,                                       /**< Interrupt on falling edge */
132     CYHAL_GPIO_IRQ_BOTH = (CYHAL_GPIO_IRQ_RISE | CYHAL_GPIO_IRQ_FALL),  /**< Interrupt on both rising and falling edges */
133 } cyhal_gpio_event_t;
134 
135 /** Pin direction */
136 typedef enum
137 {
138     CYHAL_GPIO_DIR_INPUT,         /**< Input pin */
139     CYHAL_GPIO_DIR_OUTPUT,        /**< Output pin */
140     CYHAL_GPIO_DIR_BIDIRECTIONAL, /**< Input and output pin */
141 } cyhal_gpio_direction_t;
142 
143 /** Pin drive mode */
144 
145 /** \note When the <b> drive_mode </b> of the <b> pin </b> is set to <b> CYHAL_GPIO_DRIVE_PULL_NONE </b>,
146  * it is set to <b> CYHAL_GPIO_DRIVE_STRONG </b> if the <b> direction </b>
147  * of the <b> pin </b> is <b> CYHAL_GPIO_DIR_OUTPUT </b> or <b> CYHAL_GPIO_DIR_BIDIRECTIONAL</b>.
148  * If not, the <b> drive_mode </b> of the <b> pin </b> is set to <b> CYHAL_GPIO_DRIVE_NONE</b>.
149  */
150 typedef enum
151 {
152     CYHAL_GPIO_DRIVE_NONE,                /**< Digital Hi-Z. Input only. Input init value(s): 0 or 1 */
153     CYHAL_GPIO_DRIVE_ANALOG,              /**< Analog Hi-Z. Use only for analog purpose */
154     CYHAL_GPIO_DRIVE_PULLUP,              /**< Pull-up resistor. Input and output. Input init value(s): 1, output value(s): 0 */
155     CYHAL_GPIO_DRIVE_PULLDOWN,            /**< Pull-down resistor. Input and output. Input init value(s): 0, output value(s): 1 */
156     CYHAL_GPIO_DRIVE_OPENDRAINDRIVESLOW,  /**< Open-drain, Drives Low. Input and output. Input init value(s): 1, output value(s): 0 */
157     CYHAL_GPIO_DRIVE_OPENDRAINDRIVESHIGH, /**< Open-drain, Drives High. Input and output. Input init value(s): 0, output value(s): 1 */
158     CYHAL_GPIO_DRIVE_STRONG,              /**< Strong output. Output only. Output init value(s): 0 or 1 */
159     CYHAL_GPIO_DRIVE_PULLUPDOWN,          /**< Pull-up and pull-down resistors. Input and output. Input init value(s): 0 or 1, output value(s): 0 or 1 */
160     CYHAL_GPIO_DRIVE_PULL_NONE,           /**< No Pull-up or pull-down resistors. Input and output. Input init value(s): 0 or 1, output value(s): 0 or 1 */
161 } cyhal_gpio_drive_mode_t;
162 
163 /** GPIO callback function type */
164 typedef void (*cyhal_gpio_event_callback_t)(void *callback_arg, cyhal_gpio_event_t event);
165 
166 /** Structure containing callback data for pins.
167  * Instances of this object are expected to persist for the length of time the callback is
168  * registered. As such, care must be given if declaring it on the stack to ensure the frame does
169  * not go away while the callback is still registered.*/
170 typedef struct cyhal_gpio_callback_data_s
171 {
172     cyhal_gpio_event_callback_t         callback;       /**< The callback function to run */
173     void*                               callback_arg;   /**< Optional argument for the callback */
174     struct cyhal_gpio_callback_data_s*  next;           /**< NULL. Filled in by the HAL driver */
175     cyhal_gpio_t                        pin;            /**< NC. Filled in by the HAL driver */
176 } cyhal_gpio_callback_data_t;
177 
178 /*******************************************************************************
179 *       Functions
180 *******************************************************************************/
181 
182 /** Initialize the GPIO pin <br>
183  * See \ref subsection_gpio_snippet_1.
184  *
185  * @param[in] pin         The GPIO pin to initialize
186  * @param[in] direction   The pin direction
187  * @param[in] drive_mode  The pin drive mode
188  * @param[in] init_val    Initial value on the pin
189  *
190  * @return The status of the init request
191  *
192  * Guidance for using gpio drive modes ( \ref cyhal_gpio_drive_mode_t for details).
193  * For default use drive modes:
194  * Input GPIO direction - \ref CYHAL_GPIO_DRIVE_NONE
195  * Output GPIO direction - \ref CYHAL_GPIO_DRIVE_STRONG
196  * Bidirectional GPIO - \ref CYHAL_GPIO_DRIVE_PULLUPDOWN
197  * \warning Don't use \ref CYHAL_GPIO_DRIVE_STRONG for input GPIO direction. It may cause an overcurrent issue.
198  */
199 cy_rslt_t cyhal_gpio_init(cyhal_gpio_t pin, cyhal_gpio_direction_t direction, cyhal_gpio_drive_mode_t drive_mode, bool init_val);
200 
201 /** Uninitialize the gpio peripheral and the cyhal_gpio_t object
202  *
203  * @param[in] pin Pin number
204  */
205 void cyhal_gpio_free(cyhal_gpio_t pin);
206 
207 /** Configure the GPIO pin <br>
208  * See \ref subsection_gpio_snippet_3.
209  *
210  * @param[in] pin          The GPIO pin
211  * @param[in] direction    The pin direction
212  * @param[in] drive_mode   The pin drive mode
213  *
214  * @return The status of the configure request
215  */
216 cy_rslt_t cyhal_gpio_configure(cyhal_gpio_t pin, cyhal_gpio_direction_t direction, cyhal_gpio_drive_mode_t drive_mode);
217 
218 /** Set the output value for the pin. This only works for output & in_out pins. <br>
219  * See \ref subsection_gpio_snippet_2.
220  *
221  * @param[in] pin   The GPIO object
222  * @param[in] value The value to be set (high = true, low = false)
223  */
224 void cyhal_gpio_write(cyhal_gpio_t pin, bool value);
225 
226 /** Read the input value.  This only works for \ref CYHAL_GPIO_DIR_INPUT & \ref CYHAL_GPIO_DIR_BIDIRECTIONAL pins. <br>
227  * See \ref subsection_gpio_snippet_1.
228  *
229  * @param[in]  pin   The GPIO object
230  * @return The value of the IO (true = high, false = low)
231  */
232 bool cyhal_gpio_read(cyhal_gpio_t pin);
233 
234 /** Toggle the output value <br>
235  * See \ref subsection_gpio_snippet_4.
236  * @param[in]  pin   The GPIO object
237  */
238 void cyhal_gpio_toggle(cyhal_gpio_t pin);
239 
240 /** Register/clear a callback handler for pin events <br>
241  *
242  * The referenced function will be called when one of the events enabled by \ref
243  * cyhal_gpio_enable_event occurs.
244  *
245  * See \ref subsection_gpio_snippet_4.
246  *
247  * \note The signature for this function is slightly different from other HAL register_callback
248  * functions. This is because the cyhal_gpio_t is a enum value and not a pointer to a struct. This
249  * prevents storing the callback information on the instance object itself. So instead we need a
250  * different mechanism to keep track of this data.
251  *
252  * @param[in] pin           The GPIO object
253  * @param[in] callback_data The callback data to register. Use NULL to unregister. This object must
254  *                          persist for the length of time the callback is registered. As such, it
255  *                          should not be declared on the stack.
256  */
257 void cyhal_gpio_register_callback(cyhal_gpio_t pin, cyhal_gpio_callback_data_t* callback_data);
258 
259 /** Enable or Disable the specified GPIO event <br>
260  *
261  * When an enabled event occurs, the function specified by \ref cyhal_gpio_register_callback will be called.
262  *
263  * See \ref subsection_gpio_snippet_4.
264  *
265  * @param[in] pin           The GPIO object
266  * @param[in] event         The GPIO event
267  * @param[in] intr_priority The priority for NVIC interrupt events. Interrupt priorities specific to a pin may not
268  *                          be supported on all platforms. Refer to platform implementation specific documentation
269  *                          for details.
270  * @param[in] enable        True to turn on interrupts, False to turn off
271  */
272 void cyhal_gpio_enable_event(cyhal_gpio_t pin, cyhal_gpio_event_t event, uint8_t intr_priority, bool enable);
273 
274 /** Connects a source signal and enables an input to a pin that, when triggered, will set the pins output
275  *
276  * @param[in] pin      GPIO object
277  * @param[in] source   Source signal obtained from another driver's cyhal_<PERIPH>_enable_output
278  * @return The status of the connection
279  * */
280 cy_rslt_t cyhal_gpio_connect_digital(cyhal_gpio_t pin, cyhal_source_t source);
281 
282 /** Enables an output signal from a pin that is triggered by the pins input
283  *
284  * @param[in]  pin      GPIO object
285  * @param[in]  type     Whether the signal will act as a edge or level input
286  * @param[out] source   Pointer to user-allocated source signal object which
287  * will be initialized by enable_output. \p source should be passed to
288  * (dis)connect_digital functions to (dis)connect the associated endpoints.
289  * @return The status of the output enable
290  * */
291 cy_rslt_t cyhal_gpio_enable_output(cyhal_gpio_t pin, cyhal_signal_type_t type, cyhal_source_t *source);
292 
293 /** Disconnects a source signal and disables an input to a pin
294  *
295  * @param[in] pin      GPIO object
296  * @param[in] source   Source signal from cyhal_<PERIPH>_enable_output to disable
297  * @return The status of the disconnection
298  * */
299 cy_rslt_t cyhal_gpio_disconnect_digital(cyhal_gpio_t pin, cyhal_source_t source);
300 
301 /** Disables an output signal from a pin
302  *
303  * @param[in]  pin      GPIO object
304  * @return The status of the output enable
305  * */
306 cy_rslt_t cyhal_gpio_disable_output(cyhal_gpio_t pin);
307 
308 #ifdef __cplusplus
309 }
310 #endif /* __cplusplus */
311 
312 #ifdef CYHAL_GPIO_IMPL_HEADER
313 #include CYHAL_GPIO_IMPL_HEADER
314 #endif /* CYHAL_GPIO_IMPL_HEADER */
315 
316 /** \} group_hal_gpio */
317