1 /***************************************************************************//**
2  * @file
3  * @brief General Purpose IO (GPIO) peripheral API
4  *   devices.
5  * @author Energy Micro AS
6  * @version 3.0.0
7  *******************************************************************************
8  * @section License
9  * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
10  *******************************************************************************
11  *
12  * Permission is granted to anyone to use this software for any purpose,
13  * including commercial applications, and to alter it and redistribute it
14  * freely, subject to the following restrictions:
15  *
16  * 1. The origin of this software must not be misrepresented; you must not
17  *    claim that you wrote the original software.
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 3. This notice may not be removed or altered from any source distribution.
21  *
22  * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
23  * obligation to support this Software. Energy Micro AS is providing the
24  * Software "AS IS", with no express or implied warranties of any kind,
25  * including, but not limited to, any implied warranties of merchantability
26  * or fitness for any particular purpose or warranties against infringement
27  * of any proprietary rights of a third party.
28  *
29  * Energy Micro AS will not be liable for any consequential, incidental, or
30  * special damages, or any other relief, or for any claim by any third party,
31  * arising from your use of this Software.
32  *
33  ******************************************************************************/
34 #include "em_gpio.h"
35 #include "em_bitband.h"
36 #include "em_assert.h"
37 
38 /***************************************************************************//**
39  * @addtogroup EM_Library
40  * @{
41  ******************************************************************************/
42 
43 /***************************************************************************//**
44  * @addtogroup GPIO
45  * @brief General Purpose Input/Output (GPIO) API
46  * @{
47  ******************************************************************************/
48 
49 /*******************************************************************************
50  *******************************   DEFINES   ***********************************
51  ******************************************************************************/
52 
53 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
54 
55 /** Validation of pin typically usable in assert statements. */
56 #define GPIO_DRIVEMODE_VALID(mode)    ((mode) <= 3)
57 
58 /** Validation of pin typically usable in assert statements. */
59 #define GPIO_PIN_VALID(pin)           ((pin) < 16)
60 
61 /** Validation of port typically usable in assert statements. */
62 #define GPIO_PORT_VALID(port)         ((port) <= gpioPortF)
63 
64 /** @endcond */
65 
66 
67 /*******************************************************************************
68  **************************   GLOBAL FUNCTIONS   *******************************
69  ******************************************************************************/
70 
71 /***************************************************************************//**
72  * @brief
73  *   Sets the pin location of the debug pins (Serial Wire interface).
74  *
75  * @note
76  *   Changing the pins used for debugging uncontrolled, may result in a lockout.
77  *
78  * @param[in] location
79  *   The debug pin location to use (0-3).
80  ******************************************************************************/
GPIO_DbgLocationSet(unsigned int location)81 void GPIO_DbgLocationSet(unsigned int location)
82 {
83   EFM_ASSERT(location < AFCHANLOC_MAX);
84 
85   GPIO->ROUTE = (GPIO->ROUTE & ~_GPIO_ROUTE_SWLOCATION_MASK) |
86                 (location << _GPIO_ROUTE_SWLOCATION_SHIFT);
87 }
88 
89 
90 /***************************************************************************//**
91  * @brief
92  *   Sets the drive mode for a GPIO port.
93  *
94  * @param[in] port
95  *   The GPIO port to access.
96  *
97  * @param[in] mode
98  *   Drive mode to use for port.
99  ******************************************************************************/
GPIO_DriveModeSet(GPIO_Port_TypeDef port,GPIO_DriveMode_TypeDef mode)100 void GPIO_DriveModeSet(GPIO_Port_TypeDef port, GPIO_DriveMode_TypeDef mode)
101 {
102   EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_DRIVEMODE_VALID(mode));
103 
104   GPIO->P[port].CTRL = (GPIO->P[port].CTRL & ~(_GPIO_P_CTRL_DRIVEMODE_MASK))
105                        | (mode << _GPIO_P_CTRL_DRIVEMODE_SHIFT);
106 }
107 
108 
109 /***************************************************************************//**
110  * @brief
111  *   Configure GPIO interrupt.
112  *
113  * @details
114  *   If reconfiguring a GPIO interrupt that is already enabled, it is generally
115  *   recommended to disable it first, see GPIO_Disable().
116  *
117  *   The actual GPIO interrupt handler must be in place before enabling the
118  *   interrupt.
119  *
120  *   Notice that any pending interrupt for the selected pin is cleared by this
121  *   function.
122  *
123  * @note
124  *   A certain pin number can only be associated with one port. Ie, if GPIO
125  *   interrupt 1 is assigned to port A/pin 1, then it is not possibly to use
126  *   pin 1 from any other ports for interrupts. Please refer to the reference
127  *   manual.
128  *
129  * @param[in] port
130  *   The port to associate with @p pin.
131  *
132  * @param[in] pin
133  *   The GPIO interrupt number (= port pin).
134  *
135  * @param[in] risingEdge
136  *   Set to true if interrupts shall be enabled on rising edge, otherwise false.
137  *
138  * @param[in] fallingEdge
139  *   Set to true if interrupts shall be enabled on falling edge, otherwise false.
140  *
141  * @param[in] enable
142  *   Set to true if interrupt shall be enabled after configuration completed,
143  *   false to leave disabled. See GPIO_IntDisable() and GPIO_IntEnable().
144  ******************************************************************************/
GPIO_IntConfig(GPIO_Port_TypeDef port,unsigned int pin,bool risingEdge,bool fallingEdge,bool enable)145 void GPIO_IntConfig(GPIO_Port_TypeDef port,
146                     unsigned int pin,
147                     bool risingEdge,
148                     bool fallingEdge,
149                     bool enable)
150 {
151   uint32_t tmp;
152 
153   EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_PIN_VALID(pin));
154 
155   /* There are two registers controlling the interrupt configuration:
156    * The EXTIPSELL register controls pins 0-7 and EXTIPSELH controls
157    * pins 8-15. */
158   if (pin < 8)
159   {
160     GPIO->EXTIPSELL = (GPIO->EXTIPSELL & ~(0xF << (4 * pin))) |
161                       (port << (4 * pin));
162   }
163   else
164   {
165     tmp             = pin - 8;
166     GPIO->EXTIPSELH = (GPIO->EXTIPSELH & ~(0xF << (4 * tmp))) |
167                       (port << (4 * tmp));
168   }
169 
170   /* Enable/disable rising edge */
171   BITBAND_Peripheral(&(GPIO->EXTIRISE), pin, (unsigned int)risingEdge);
172 
173   /* Enable/disable falling edge */
174   BITBAND_Peripheral(&(GPIO->EXTIFALL), pin, (unsigned int)fallingEdge);
175 
176   /* Clear any pending interrupt */
177   GPIO->IFC = 1 << pin;
178 
179   /* Finally enable/disable interrupt */
180   BITBAND_Peripheral(&(GPIO->IEN), pin, (unsigned int)enable);
181 }
182 
183 
184 /***************************************************************************//**
185  * @brief
186  *   Read the pad value for a single pin in a GPIO port.
187  *
188  * @param[in] port
189  *   The GPIO port to access.
190  *
191  * @param[in] pin
192  *   The pin number to read.
193  *
194  * @return
195  *   The pin value, 0 or 1.
196  ******************************************************************************/
GPIO_PinInGet(GPIO_Port_TypeDef port,unsigned int pin)197 unsigned int GPIO_PinInGet(GPIO_Port_TypeDef port, unsigned int pin)
198 {
199   EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_PIN_VALID(pin));
200 
201   return((unsigned int)((GPIO->P[port].DIN >> pin) & 0x1));
202 }
203 
204 
205 /***************************************************************************//**
206  * @brief
207  *   Set the mode for a GPIO pin.
208  *
209  * @param[in] port
210  *   The GPIO port to access.
211  *
212  * @param[in] pin
213  *   The pin number in the port.
214  *
215  * @param[in] mode
216  *   The desired pin mode.
217  *
218  * @param[in] out
219  *   Value to set for pin in DOUT register. The DOUT setting is important for
220  *   even some input mode configurations, determining pull-up/down direction.
221  *   Notice that this parameter is not used if disabling a pin, leaving the
222  *   corresponding DOUT bit unchanged.
223  ******************************************************************************/
GPIO_PinModeSet(GPIO_Port_TypeDef port,unsigned int pin,GPIO_Mode_TypeDef mode,unsigned int out)224 void GPIO_PinModeSet(GPIO_Port_TypeDef port,
225                      unsigned int pin,
226                      GPIO_Mode_TypeDef mode,
227                      unsigned int out)
228 {
229   EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_PIN_VALID(pin));
230 
231   /* If disabling pin, do not modify DOUT in order to reduce chance for */
232   /* glitch/spike (may not be sufficient precaution in all use cases) */
233   if (mode != gpioModeDisabled)
234   {
235     if (out)
236     {
237       GPIO->P[port].DOUTSET = 1 << pin;
238     }
239     else
240     {
241       GPIO->P[port].DOUTCLR = 1 << pin;
242     }
243   }
244 
245   /* There are two registers controlling the pins for each port. The MODEL
246    * register controls pins 0-7 and MODEH controls pins 8-15. */
247   if (pin < 8)
248   {
249     GPIO->P[port].MODEL = (GPIO->P[port].MODEL & ~(0xF << (pin * 4))) |
250                           (mode << (pin * 4));
251   }
252   else
253   {
254     GPIO->P[port].MODEH = (GPIO->P[port].MODEH & ~(0xF << ((pin - 8) * 4))) |
255                           (mode << ((pin - 8) * 4));
256   }
257 
258   if (mode == gpioModeDisabled)
259   {
260     if (out)
261     {
262       GPIO->P[port].DOUTSET = 1 << pin;
263     }
264     else
265     {
266       GPIO->P[port].DOUTCLR = 1 << pin;
267     }
268   }
269 }
270 
271 
272 /***************************************************************************//**
273  * @brief
274  *   Set a single pin in GPIO data out port register to 0.
275  *
276  * @note
277  *   In order for the setting to take effect on the output pad, the pin must
278  *   have been configured properly. If not, it will take effect whenever the
279  *   pin has been properly configured.
280  *
281  * @param[in] port
282  *   The GPIO port to access.
283  *
284  * @param[in] pin
285  *   The pin to set.
286  ******************************************************************************/
GPIO_PinOutClear(GPIO_Port_TypeDef port,unsigned int pin)287 void GPIO_PinOutClear(GPIO_Port_TypeDef port, unsigned int pin)
288 {
289   EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_PIN_VALID(pin));
290 
291   GPIO->P[port].DOUTCLR = 1 << pin;
292 }
293 
294 
295 /***************************************************************************//**
296  * @brief
297  *   Get current setting for a pin in a GPIO port data out register.
298  *
299  * @param[in] port
300  *   The GPIO port to access.
301  *
302  * @param[in] pin
303  *   The pin to get setting for.
304  *
305  * @return
306  *   The DOUT setting for the requested pin, 0 or 1.
307  ******************************************************************************/
GPIO_PinOutGet(GPIO_Port_TypeDef port,unsigned int pin)308 unsigned int GPIO_PinOutGet(GPIO_Port_TypeDef port, unsigned int pin)
309 {
310   EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_PIN_VALID(pin));
311 
312   return((unsigned int)((GPIO->P[port].DOUT >> pin) & 0x1));
313 }
314 
315 
316 /***************************************************************************//**
317  * @brief
318  *   Set a single pin in GPIO data out register to 1.
319  *
320  * @note
321  *   In order for the setting to take effect on the output pad, the pin must
322  *   have been configured properly. If not, it will take effect whenever the
323  *   pin has been properly configured.
324  *
325  * @param[in] port
326  *   The GPIO port to access.
327  *
328  * @param[in] pin
329  *   The pin to set.
330  ******************************************************************************/
GPIO_PinOutSet(GPIO_Port_TypeDef port,unsigned int pin)331 void GPIO_PinOutSet(GPIO_Port_TypeDef port, unsigned int pin)
332 {
333   EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_PIN_VALID(pin));
334 
335   GPIO->P[port].DOUTSET = 1 << pin;
336 }
337 
338 
339 /***************************************************************************//**
340  * @brief
341  *   Toggle a single pin in GPIO port data out register.
342  *
343  * @note
344  *   In order for the setting to take effect on the output pad, the pin must
345  *   have been configured properly. If not, it will take effect whenever the
346  *   pin has been properly configured.
347  *
348  * @param[in] port
349  *   The GPIO port to access.
350  *
351  * @param[in] pin
352  *   The pin to toggle.
353  ******************************************************************************/
GPIO_PinOutToggle(GPIO_Port_TypeDef port,unsigned int pin)354 void GPIO_PinOutToggle(GPIO_Port_TypeDef port, unsigned int pin)
355 {
356   EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_PIN_VALID(pin));
357 
358   GPIO->P[port].DOUTTGL = 1 << pin;
359 }
360 
361 
362 /***************************************************************************//**
363  * @brief
364  *   Read the pad values for GPIO port.
365  *
366  * @param[in] port
367  *   The GPIO port to access.
368  ******************************************************************************/
GPIO_PortInGet(GPIO_Port_TypeDef port)369 uint32_t GPIO_PortInGet(GPIO_Port_TypeDef port)
370 {
371   EFM_ASSERT(GPIO_PORT_VALID(port));
372 
373   return(GPIO->P[port].DIN & _GPIO_P_DIN_DIN_MASK);
374 }
375 
376 
377 /***************************************************************************//**
378  * @brief
379  *   Set bits in DOUT register for a port to 0.
380  *
381  * @note
382  *   In order for the setting to take effect on the output pad, the pin must
383  *   have been configured properly. If not, it will take effect whenever the
384  *   pin has been properly configured.
385  *
386  * @param[in] port
387  *   The GPIO port to access.
388  *
389  * @param[in] pins
390  *   Bit mask for bits to clear in DOUT register.
391  ******************************************************************************/
GPIO_PortOutClear(GPIO_Port_TypeDef port,uint32_t pins)392 void GPIO_PortOutClear(GPIO_Port_TypeDef port, uint32_t pins)
393 {
394   EFM_ASSERT(GPIO_PORT_VALID(port));
395 
396   GPIO->P[port].DOUTCLR = pins & _GPIO_P_DOUTCLR_DOUTCLR_MASK;
397 }
398 
399 
400 /***************************************************************************//**
401  * @brief
402  *   Get current setting for a GPIO port data out register.
403  *
404  * @param[in] port
405  *   The GPIO port to access.
406  *
407  * @return
408  *   The data out setting for the requested port.
409  ******************************************************************************/
GPIO_PortOutGet(GPIO_Port_TypeDef port)410 uint32_t GPIO_PortOutGet(GPIO_Port_TypeDef port)
411 {
412   EFM_ASSERT(GPIO_PORT_VALID(port));
413 
414   return(GPIO->P[port].DOUT & _GPIO_P_DOUT_DOUT_MASK);
415 }
416 
417 
418 /***************************************************************************//**
419  * @brief
420  *   Set bits GPIO data out register to 1.
421  *
422  * @note
423  *   In order for the setting to take effect on the respective output pads, the
424  *   pins must have been configured properly. If not, it will take effect
425  *   whenever the pin has been properly configured.
426  *
427  * @param[in] port
428  *   The GPIO port to access.
429  *
430  * @param[in] pins
431  *   Bit mask for bits to set to 1 in DOUT register.
432  ******************************************************************************/
GPIO_PortOutSet(GPIO_Port_TypeDef port,uint32_t pins)433 void GPIO_PortOutSet(GPIO_Port_TypeDef port, uint32_t pins)
434 {
435   EFM_ASSERT(GPIO_PORT_VALID(port));
436 
437   GPIO->P[port].DOUTSET = pins & _GPIO_P_DOUTSET_DOUTSET_MASK;
438 }
439 
440 
441 /***************************************************************************//**
442  * @brief
443  *   Set GPIO port data out register.
444  *
445  * @note
446  *   In order for the setting to take effect on the respective output pads, the
447  *   pins must have been configured properly. If not, it will take effect
448  *   whenever the pin has been properly configured.
449  *
450  * @param[in] port
451  *   The GPIO port to access.
452  *
453  * @param[in] val
454  *   Value to write to port data out register.
455  *
456  * @param[in] mask
457  *   Mask indicating which bits to modify.
458  ******************************************************************************/
GPIO_PortOutSetVal(GPIO_Port_TypeDef port,uint32_t val,uint32_t mask)459 void GPIO_PortOutSetVal(GPIO_Port_TypeDef port, uint32_t val, uint32_t mask)
460 {
461   EFM_ASSERT(GPIO_PORT_VALID(port));
462 
463   GPIO->P[port].DOUT = (GPIO->P[port].DOUT & ~mask) | (val & mask);
464 }
465 
466 
467 /***************************************************************************//**
468  * @brief
469  *   Toggle a single pin in GPIO port data out register.
470  *
471  * @note
472  *   In order for the setting to take effect on the output pad, the pin must
473  *   have been configured properly. If not, it will take effect whenever the
474  *   pin has been properly configured.
475  *
476  * @param[in] port
477  *   The GPIO port to access.
478  *
479  * @param[in] pins
480  *   Bitmask with pins to toggle.
481  ******************************************************************************/
GPIO_PortOutToggle(GPIO_Port_TypeDef port,uint32_t pins)482 void GPIO_PortOutToggle(GPIO_Port_TypeDef port, uint32_t pins)
483 {
484   EFM_ASSERT(GPIO_PORT_VALID(port));
485 
486   GPIO->P[port].DOUTTGL = pins & _GPIO_P_DOUTTGL_DOUTTGL_MASK;
487 }
488 
489 
490 /** @} (end addtogroup GPIO) */
491 /** @} (end addtogroup EM_Library) */
492