am_hal_gpio.c 15 KB

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