1 //*****************************************************************************
2 //
3 // am_hal_gpio.c
4 //! @file
5 //!
6 //! @brief Functions for interfacing with the GPIO module
7 //!
8 //! @addtogroup gpio2 GPIO
9 //! @ingroup apollo2hal
10 //! @{
11 //
12 //*****************************************************************************
13
14 //*****************************************************************************
15 //
16 // Copyright (c) 2017, Ambiq Micro
17 // All rights reserved.
18 //
19 // Redistribution and use in source and binary forms, with or without
20 // modification, are permitted provided that the following conditions are met:
21 //
22 // 1. Redistributions of source code must retain the above copyright notice,
23 // this list of conditions and the following disclaimer.
24 //
25 // 2. Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // 3. Neither the name of the copyright holder nor the names of its
30 // contributors may be used to endorse or promote products derived from this
31 // software without specific prior written permission.
32 //
33 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
37 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 // POSSIBILITY OF SUCH DAMAGE.
44 //
45 // This is part of revision 1.2.11 of the AmbiqSuite Development Package.
46 //
47 //*****************************************************************************
48
49 #include <stdint.h>
50 #include <stdbool.h>
51 #include "am_mcu_apollo.h"
52
53 //*****************************************************************************
54 //
55 // Array of function pointers for handling GPIO interrupts.
56 //
57 //*****************************************************************************
58 am_hal_gpio_handler_t am_hal_gpio_ppfnHandlers[64];
59
60 //*****************************************************************************
61 //
62 //! @brief Read the configuration information for the given pin..
63 //!
64 //! @param ui32GPIONum is the GPIO number whose configuration we want to read.
65 //!
66 //! This function reads the PADREG, GPIO CFG, and ALTPAD registers for the
67 //! given GPIO and returns them in the following format:
68 //!
69 //! ( (ALTPAD << 16) | (CFG << 8) | PADREG)
70 //!
71 //! This is the same format used by the \e am_hal_gpio_pin_config()
72 //! function-like macro.
73 //!
74 //! @return Pin configuration information.
75 //
76 //*****************************************************************************
77 uint32_t
am_hal_gpio_pin_config_read(uint32_t ui32PinNumber)78 am_hal_gpio_pin_config_read(uint32_t ui32PinNumber)
79 {
80 uint32_t ui32CfgVal, ui32PadregVal, ui32AltPadVal;
81
82 am_hal_debug_assert_msg(ui32PinNumber <= 63, "Invalid GPIO number.");
83
84 ui32CfgVal = AM_HAL_GPIO_CFG_R(ui32PinNumber);
85 ui32PadregVal = AM_HAL_GPIO_PADREG_R(ui32PinNumber);
86 ui32AltPadVal = AM_HAL_GPIO_ALTPADREG_R(ui32PinNumber);
87
88 return ( (ui32CfgVal << CFGVAL_GPIOCFG_S) |
89 (ui32PadregVal << CFGVAL_PADREG_S) |
90 (ui32AltPadVal << CFGVAL_ALTPAD_S) );
91 }
92
93 //*****************************************************************************
94 //
95 //! @brief Get the state of ALL GPIOs from the INPUT READ REGISTER.
96 //!
97 //! This function retrieves the state of ALL GPIOs from the INPUT READ
98 //! REGISTER.
99 //!
100 //! @return the state for the requested GPIO or -1 for error.
101 //
102 //*****************************************************************************
103 uint64_t
am_hal_gpio_input_read(void)104 am_hal_gpio_input_read(void)
105 {
106 //
107 // Combine upper or lower GPIO words into one 64 bit return value.
108 //
109 uint64_t ui64RetVal;
110
111 ui64RetVal = ((uint64_t) AM_REGn(GPIO, 0, RDB)) << 32;
112 ui64RetVal |= ((uint64_t) AM_REGn(GPIO, 0, RDA)) << 0;
113
114 return ui64RetVal;
115 }
116
117 //*****************************************************************************
118 //
119 //! @brief Get the state of ALL GPIOs from the DATA OUTPUT REGISTER.
120 //!
121 //! This function retrieves the state of ALL GPIOs from the DATA OUTPUT
122 //! REGISTER.
123 //!
124 //! @return the state for the requested GPIO or -1 for error.
125 //
126 //*****************************************************************************
127 uint64_t
am_hal_gpio_out_read(void)128 am_hal_gpio_out_read(void)
129 {
130 //
131 // Combine upper or lower GPIO words into one 64 bit return value.
132 //
133 uint64_t ui64RetVal;
134
135 ui64RetVal = ((uint64_t) AM_REGn(GPIO, 0, WTB)) << 32;
136 ui64RetVal |= ((uint64_t) AM_REGn(GPIO, 0, WTA)) << 0;
137
138 return ui64RetVal;
139 }
140
141 //*****************************************************************************
142 //
143 //! @brief Gets the state of one GPIO from the DATA ENABLE REGISTER.
144 //!
145 //! @param ui32BitNum - GPIO number.
146 //!
147 //! This function gets the state of one GPIO from the DATA ENABLE REGISTER.
148 //!
149 //! @return the current state for the requested GPIO.
150 //
151 //*****************************************************************************
152 uint32_t
am_hal_gpio_out_enable_bit_get(uint32_t ui32BitNum)153 am_hal_gpio_out_enable_bit_get(uint32_t ui32BitNum)
154 {
155 //
156 // Return 0 or 1.
157 //
158
159 return (AM_HAL_GPIO_EN(ui32BitNum) & AM_HAL_GPIO_EN_M(ui32BitNum)) ? 1 : 0;
160 }
161
162 //*****************************************************************************
163 //
164 //! @brief Gets the state of ALL GPIOs from the DATA ENABLE REGISTER.
165 //!
166 //! @param ui32BitNum - GPIO number.
167 //!
168 //! This function gets the state of all GPIOs from the DATA ENABLE REGISTER.
169 //!
170 //! @return the current state for the ALL GPIOs.
171 //
172 //*****************************************************************************
173 uint64_t
am_hal_gpio_out_enable_get(void)174 am_hal_gpio_out_enable_get(void)
175 {
176 //
177 // Combine upper or lower GPIO words into one 64 bit return value.
178 //
179 uint64_t ui64RetVal;
180
181 ui64RetVal = ((uint64_t) AM_REGn(GPIO, 0, ENB)) << 32;
182 ui64RetVal |= ((uint64_t) AM_REGn(GPIO, 0, ENA)) << 0;
183
184 return ui64RetVal;
185 }
186
187 //*****************************************************************************
188 //
189 //! @brief Enable selected GPIO Interrupts.
190 //!
191 //! @param ui64InterruptMask - GPIOs to enable interrupts on.
192 //!
193 //! Use this function to enable the GPIO interrupts.
194 //!
195 //! @return None
196 //
197 //*****************************************************************************
198 void
am_hal_gpio_int_enable(uint64_t ui64InterruptMask)199 am_hal_gpio_int_enable(uint64_t ui64InterruptMask)
200 {
201 //
202 // Enable the interrupts.
203 //
204 AM_REG(GPIO, INT1EN) |= (ui64InterruptMask >> 32);
205 AM_REG(GPIO, INT0EN) |= (ui64InterruptMask & 0xFFFFFFFF);
206 }
207
208 //*****************************************************************************
209 //
210 //! @brief Enable selected GPIO Interrupts.
211 //!
212 //! Use this function to enable the GPIO interrupts.
213 //!
214 //! @return logical or of all enabled interrupts. Use AM_HAL_GPIO_BITx to mask
215 //! interrupts of interest.
216 //
217 //*****************************************************************************
218 uint64_t
am_hal_gpio_int_enable_get(void)219 am_hal_gpio_int_enable_get(void)
220 {
221 //
222 // Return enabled interrupts.
223 //
224 uint64_t ui64RetVal;
225
226 ui64RetVal = ((uint64_t) AM_REGn(GPIO, 0, INT1EN)) << 32;
227 ui64RetVal |= ((uint64_t) AM_REGn(GPIO, 0, INT0EN)) << 0;
228
229 return ui64RetVal;
230 }
231
232 //*****************************************************************************
233 //
234 //! @brief Disable selected GPIO Interrupts.
235 //!
236 //! @param ui64InterruptMask - GPIOs to disable interrupts on.
237 //!
238 //! Use this function to disable the GPIO interrupts.
239 //!
240 //! ui64InterruptMask should be a logical or of AM_HAL_GPIO_BITx defines.
241 //!
242 //! @return None
243 //
244 //*****************************************************************************
245 void
am_hal_gpio_int_disable(uint64_t ui64InterruptMask)246 am_hal_gpio_int_disable(uint64_t ui64InterruptMask)
247 {
248 //
249 // Disable the interrupts.
250 //
251 AM_CRITICAL_BEGIN_ASM
252 AM_REG(GPIO, INT1EN) &= ~(ui64InterruptMask >> 32);
253 AM_REG(GPIO, INT0EN) &= ~(ui64InterruptMask & 0xFFFFFFFF);
254 AM_CRITICAL_END_ASM
255 }
256
257 //*****************************************************************************
258 //
259 //! @brief Clear selected GPIO Interrupts.
260 //!
261 //! @param ui64InterruptMask - GPIOs to clear interrupts on.
262 //!
263 //! Use this function to clear the GPIO interrupts.
264 //!
265 //! ui64InterruptMask should be a logical or of AM_HAL_GPIO_BITx defines.
266 //!
267 //! @return None
268 //
269 //*****************************************************************************
270 void
am_hal_gpio_int_clear(uint64_t ui64InterruptMask)271 am_hal_gpio_int_clear(uint64_t ui64InterruptMask)
272 {
273 //
274 // Clear the interrupts.
275 //
276 AM_CRITICAL_BEGIN_ASM
277 AM_REG(GPIO, INT1CLR) = (ui64InterruptMask >> 32);
278 AM_REG(GPIO, INT0CLR) = (ui64InterruptMask & 0xFFFFFFFF);
279 AM_CRITICAL_END_ASM
280 }
281
282 //*****************************************************************************
283 //
284 //! @brief Set selected GPIO Interrupts.
285 //!
286 //! @param ui64InterruptMask - GPIOs to set interrupts on.
287 //!
288 //! Use this function to set the GPIO interrupts.
289 //!
290 //! ui64InterruptMask should be a logical or of AM_HAL_GPIO_BITx defines.
291 //!
292 //! @return None
293 //
294 //*****************************************************************************
295 void
am_hal_gpio_int_set(uint64_t ui64InterruptMask)296 am_hal_gpio_int_set(uint64_t ui64InterruptMask)
297 {
298 //
299 // Set the interrupts.
300 //
301 AM_REG(GPIO, INT1SET) = (ui64InterruptMask >> 32);
302 AM_REG(GPIO, INT0SET) = (ui64InterruptMask & 0xFFFFFFFF);
303 }
304
305 //*****************************************************************************
306 //
307 //! @brief Set selected GPIO Interrupts.
308 //!
309 //! @param bEnabledOnly - return the status of only the enabled interrupts.
310 //!
311 //! Use this function to set the GPIO interrupts.
312 //!
313 //! @return None
314 //
315 //*****************************************************************************
316 uint64_t
am_hal_gpio_int_status_get(bool bEnabledOnly)317 am_hal_gpio_int_status_get(bool bEnabledOnly)
318 {
319 uint64_t ui64RetVal, ui64Mask;
320
321 //
322 // Combine upper or lower GPIO words into one 64 bit return value.
323 //
324 ui64Mask = 0xFFFFFFFFFFFFFFFF;
325
326 AM_CRITICAL_BEGIN_ASM
327 ui64RetVal = ((uint64_t) AM_REGn(GPIO, 0, INT1STAT)) << 32;
328 ui64RetVal |= ((uint64_t) AM_REGn(GPIO, 0, INT0STAT)) << 0;
329
330 if ( bEnabledOnly )
331 {
332 ui64Mask = ((uint64_t) AM_REGn(GPIO, 0, INT1EN)) << 32;
333 ui64Mask |= ((uint64_t) AM_REGn(GPIO, 0, INT0EN)) << 0;
334 }
335
336 ui64RetVal &= ui64Mask;
337 AM_CRITICAL_END_ASM
338
339 return ui64RetVal;
340 }
341
342 //*****************************************************************************
343 //
344 //! @brief Convenience function for responding to pin interrupts.
345 //!
346 //! @param ui64Status is the interrupt status as returned by
347 //! am_hal_gpio_int_status_get()
348 //!
349 //! This function may be called from am_hal_gpio_isr() to read the status of
350 //! the GPIO interrupts, determine which pin(s) caused the most recent
351 //! interrupt, and call an interrupt handler function to respond. The interrupt
352 //! handler to be called must be first registered with the
353 //! am_hal_gpio_int_register() function.
354 //!
355 //! In the event that multiple GPIO interrupts are active, the corresponding
356 //! interrupt handlers will be called in numerical order by GPIO number
357 //! starting with the lowest GPIO number.
358 //!
359 //! @return None.
360 //
361 //*****************************************************************************
362 void
am_hal_gpio_int_service(uint64_t ui64Status)363 am_hal_gpio_int_service(uint64_t ui64Status)
364 {
365 uint32_t ui32Status;
366 uint32_t ui32Clz;
367
368 am_hal_gpio_handler_t pfnHandler;
369
370 //
371 // Handle any active interrupts in the lower 32 bits
372 //
373 ui32Status = (uint32_t) ui64Status;
374 while ( ui32Status )
375 {
376 //
377 // Pick one of any remaining active interrupt bits
378 //
379 #ifdef __IAR_SYSTEMS_ICC__
380 ui32Clz = __CLZ(ui32Status);
381 #else
382 ui32Clz = __builtin_clz(ui32Status);
383 #endif
384
385 //
386 // Turn off the bit we picked in the working copy
387 //
388 ui32Status &= ~(0x80000000 >> ui32Clz);
389
390 //
391 // Check the bit handler table to see if there is an interrupt handler
392 // registered for this particular bit.
393 //
394 pfnHandler = am_hal_gpio_ppfnHandlers[31 - ui32Clz];
395 if ( pfnHandler )
396 {
397 //
398 // If we found an interrupt handler routine, call it now.
399 //
400 pfnHandler();
401 }
402 }
403
404 //
405 // Handle any active interrupts in the upper 32 bits
406 //
407 ui32Status = (uint32_t) (ui64Status >> 32);
408 while ( ui32Status )
409 {
410 //
411 // Pick one of any remaining active interrupt bits
412 //
413 #ifdef __IAR_SYSTEMS_ICC__
414 ui32Clz = __CLZ(ui32Status);
415 #else
416 ui32Clz = __builtin_clz(ui32Status);
417 #endif
418
419 //
420 // Turn off the bit we picked in the working copy
421 //
422 ui32Status &= ~(0x80000000 >> ui32Clz);
423
424 //
425 // Check the bit handler table to see if there is an interrupt handler
426 // registered for this particular bit.
427 //
428 pfnHandler = am_hal_gpio_ppfnHandlers[63 - ui32Clz];
429 if ( pfnHandler )
430 {
431 //
432 // If we found an interrupt handler routine, call it now.
433 //
434 pfnHandler();
435 }
436 }
437 }
438
439 //*****************************************************************************
440 //
441 //! @brief Register an interrupt handler for an individual GPIO pin.
442 //!
443 //! @param ui32GPIONumber - GPIO number to assign this interrupt handler to.
444 //! @param pfnHandler - Function to call when this GPIO interrupt is received.
445 //!
446 //! This function allows the caller to specify a function that should be called
447 //! any time a GPIO interrupt is received on a particular pin. Registering an
448 //! interrupt handler using this function adds the function pointer to an array
449 //! in SRAM. This interrupt handler will be called by am_hal_gpio_int_service()
450 //! whenever the ui64Status parameter indicates that the corresponding pin is
451 //! asserting it's interrupt.
452 //!
453 //! To remove an interrupt handler that has already been registered, the
454 //! pfnHandler parameter may be set to zero.
455 //!
456 //! @note This function will not have any effect unless the
457 //! am_hal_gpio_int_service() function is being used.
458 //!
459 //! @return None.
460 //
461 //*****************************************************************************
462 void
am_hal_gpio_int_register(uint32_t ui32GPIONumber,am_hal_gpio_handler_t pfnHandler)463 am_hal_gpio_int_register(uint32_t ui32GPIONumber,
464 am_hal_gpio_handler_t pfnHandler)
465 {
466 //
467 // Check to make sure the GPIO number is valid. (Debug builds only)
468 //
469 am_hal_debug_assert_msg(ui32GPIONumber < 64, "GPIO number out of range.");
470
471 am_hal_gpio_ppfnHandlers[ui32GPIONumber] = pfnHandler;
472 }
473
474 //*****************************************************************************
475 //
476 //! @brief Get the state of one GPIO polarity bit.
477 //!
478 //! @param ui32BitNum - GPIO number.
479 //!
480 //! This function gets the state of one GPIO polarity bit.
481 //!
482 //! @note When the bit is a zero the interrupt polarity is rising edge.
483 //!
484 //! @return the current polarity.
485 //
486 //*****************************************************************************
487 bool
am_hal_gpio_int_polarity_bit_get(uint32_t ui32BitNum)488 am_hal_gpio_int_polarity_bit_get(uint32_t ui32BitNum)
489 {
490 //
491 // Check the GPIO_CFGx register's interrupt polarity bit corresponding to
492 // this pin number.
493 //
494 return (AM_REGVAL(AM_HAL_GPIO_CFG(ui32BitNum)) &
495 AM_HAL_GPIO_POL_M(ui32BitNum));
496 }
497
498 //*****************************************************************************
499 //
500 // End Doxygen group.
501 //! @}
502 //
503 //*****************************************************************************
504