ADuCM302x Device Drivers API Reference Manual  Release 3.1.2.0
adi_xint.c
1 /******************************************************************************
2  @file: adi_xint.c
3  @brief: External Interrupt device driver implementation.
4  -----------------------------------------------------------------------------
5 
6 Copyright (c) 2016-2017 Analog Devices, Inc.
7 
8 All rights reserved.
9 
10 Redistribution and use in source and binary forms, with or without modification,
11 are permitted provided that the following conditions are met:
12  - Redistributions of source code must retain the above copyright notice,
13  this list of conditions and the following disclaimer.
14  - Redistributions in binary form must reproduce the above copyright notice,
15  this list of conditions and the following disclaimer in the documentation
16  and/or other materials provided with the distribution.
17  - Modified versions of the software must be conspicuously marked as such.
18  - This software is licensed solely and exclusively for use with processors
19  manufactured by or for Analog Devices, Inc.
20  - This software may not be combined or merged with other code in any manner
21  that would cause the software to become subject to terms and conditions
22  which differ from those listed here.
23  - Neither the name of Analog Devices, Inc. nor the names of its
24  contributors may be used to endorse or promote products derived
25  from this software without specific prior written permission.
26  - The use of this software may or may not infringe the patent rights of one
27  or more patent holders. This license does not release you from the
28  requirement that you obtain separate licenses from these patent holders
29  to use this software.
30 
31 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. AND CONTRIBUTORS "AS IS" AND ANY
32 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
33 TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
34 NO EVENT SHALL ANALOG DEVICES, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
35 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES
36 (INCLUDING, BUT NOT LIMITED TO, DAMAGES ARISING OUT OF CLAIMS OF INTELLECTUAL
37 PROPERTY RIGHTS INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
38 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
39 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
41 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 
43 */
44 /*****************************************************************************/
45 
46 #include <stddef.h>
47 #include <string.h>
48 #include <assert.h>
49 #include <drivers/xint/adi_xint.h>
50 #include <rtos_map/adi_rtos_map.h>
51 #include "adi_xint_def.h"
52 
53 #ifdef __ICCARM__
54 /*
55 * IAR MISRA C 2004 error suppressions.
56 *
57 * Pm073 (rule 14.7): a function should have a single point of exit
58 * Pm143 (rule 14.7): a function should have a single point of exit at the end of the function
59 * Multiple returns are used for error handling.
60 * Pm140 (rule 11.3): a cast should not be performed between a pointer type and an integral type
61 * The rule makes an exception for memory-mapped register accesses.
62 * Pm140 (rule 10.3): illegal explicit conversion from underlying MISRA type unsigned int to enum
63 * The typecast is used for efficiency of the code.
64 * Pm140 (rule 17.4): array indexing shall only be applied to objects defined as an array
65 * Array indexing is required on the pointer. The memory for gpCallbackTable is passed from application
66 */
67 #pragma diag_suppress=Pm073,Pm143,Pm140,Pm136,Pm152
68 #endif /* __ICCARM__ */
69 
70 static inline void XIntCommonInterruptHandler (const ADI_XINT_EVENT eEvent);
71 void Ext_Int0_Handler(void);
72 void Ext_Int1_Handler(void);
73 void Ext_Int2_Handler(void);
74 void Ext_Int3_Handler(void);
75 
76 
77 
78 /*========== D A T A ==========*/
79 
80 static ADI_XINT_CALLBACK_INFO *gpCallbackTable;
81 
107 ADI_XINT_RESULT adi_xint_Init(void* const pMemory,
108  uint32_t const MemorySize
109 )
110 {
111 
112 #ifdef ADI_DEBUG
113  /* Verify the given memory pointer */
114  if(NULL == pMemory)
115  {
117  }
118  /* Check if the memory size is sufficient to operate the driver */
119  if(MemorySize < ADI_XINT_MEMORY_SIZE)
120  {
122  }
123  assert(MemorySize == (sizeof(ADI_XINT_CALLBACK_INFO) * ADI_XINT_EVENT_MAX));
124 #endif
125 
126  /* Only initialize on 1st init call, i.e., preserve callbacks on multiple inits */
127  if (gpCallbackTable == NULL)
128  {
129  /* Clear the memory passed by the application */
130  memset(pMemory, 0, MemorySize);
131 
132  gpCallbackTable = (ADI_XINT_CALLBACK_INFO *)pMemory;
133  }
134  return (ADI_XINT_SUCCESS);
135 }
136 
137 
150 {
151 
152 #ifdef ADI_DEBUG
153  /* IF (not initialized) */
154  if (NULL == gpCallbackTable)
155  {
156  /* return error if not initialized */
157  return (ADI_XINT_NOT_INITIALIZED);
158  }
159 #endif
160 
161  /* Clear the callback pointer */
162  gpCallbackTable = NULL;
163 
164  return (ADI_XINT_SUCCESS);
165 }
166 
167 
168 
192 {
193  uint32_t Mask; /* mask to manipulate the register */
194  uint32_t Pattern; /* bit pattern that will be written into the register */
195  uint32_t CfgReg; /* interrupt config register value */
196  IRQn_Type XintIrq;
197  ADI_INT_STATUS_ALLOC();
198 
199 #ifdef ADI_DEBUG
200  /* make sure we're initialized */
201  if (NULL == gpCallbackTable)
202  {
203  return (ADI_XINT_NOT_INITIALIZED);
204  }
205 #endif
206 
207  /* create the mask we'll use to clear the relevant bits in the config register */
208  Mask = (BITM_XINT_CFG0_IRQ0MDE | BITM_XINT_CFG0_IRQ0EN) << (ADI_XINT_CFG_BITS * (uint32_t)eEvent);
209 
210  /* The Pattern has to be created differently for UART RX wakeup and other events as the
211  mode and enable bits are flipped in case of UART RX */
212 
213  /* Based on the event figure out the interrupt it is mapped to */
214  if(eEvent == ADI_XINT_EVENT_UART_RX)
215  {
216  /* create the bit pattern we're going to write into the configuration register */
217  Pattern = (BITM_XINT_CFG0_UART_RX_EN | ((uint32_t)eMode << BITP_XINT_CFG0_UART_RX_MDE));
218 
219  XintIrq = XINT_EVT3_IRQn;
220  }
221  else
222  {
223  /* create the bit pattern we're going to write into the configuration register */
224  Pattern = (BITM_XINT_CFG0_IRQ0EN | eMode) << (ADI_XINT_CFG_BITS * (uint32_t)eEvent);
225 
226  XintIrq = (IRQn_Type)((uint32_t)XINT_EVT0_IRQn + (uint32_t)eEvent);
227  }
228 
229 
230  ADI_ENTER_CRITICAL_REGION();
231 
232  /* read/modify/write the appropriate bits in the register */
233  CfgReg = pADI_XINT0->CFG0;
234  CfgReg &= ~Mask;
235  CfgReg |= Pattern;
236  pADI_XINT0->CFG0 = CfgReg;
237 
238  ADI_EXIT_CRITICAL_REGION();
239 
240  /* enable the interrupt */
241  NVIC_EnableIRQ(XintIrq);
242 
243  return (ADI_XINT_SUCCESS);
244 }
245 
246 
262 {
263  uint32_t Mask; /* mask to manipulate the register */
264  uint32_t CfgReg; /* interrupt config register value */
265  IRQn_Type XintIrq; /* External interrupt IRQ the event is mapped to */
266 
267  ADI_INT_STATUS_ALLOC();
268 
269 #ifdef ADI_DEBUG
270  /* make sure we're initialized */
271  if (NULL == gpCallbackTable)
272  {
273  return (ADI_XINT_NOT_INITIALIZED);
274  }
275 #endif
276 
277  /* Based on the event figure out the interrupt it is mapped to */
278  if(eEvent == ADI_XINT_EVENT_UART_RX)
279  {
280  XintIrq = XINT_EVT3_IRQn;
281  }
282  else
283  {
284  XintIrq = (IRQn_Type)((uint32_t)XINT_EVT0_IRQn + (uint32_t)eEvent);
285  }
286 
287  /* disable the interrupt */
288  NVIC_DisableIRQ(XintIrq);
289 
290  /* create the mask we'll use to clear the relevant bits in the config register */
291  Mask = (BITM_XINT_CFG0_IRQ0MDE | BITM_XINT_CFG0_IRQ0EN) << (ADI_XINT_CFG_BITS * (uint32_t)eEvent);
292 
293  ADI_ENTER_CRITICAL_REGION();
294  /* read/modify/write the appropriate bits in the register */
295  CfgReg = pADI_XINT0->CFG0;
296  CfgReg &= ~Mask;
297  pADI_XINT0->CFG0 = CfgReg;
298  ADI_EXIT_CRITICAL_REGION();
299 
300  return (ADI_XINT_SUCCESS);
301 }
302 
303 
333 ADI_XINT_RESULT adi_xint_RegisterCallback (const ADI_XINT_EVENT eEvent, ADI_CALLBACK const pfCallback, void *const pCBParam )
334 {
335  ADI_INT_STATUS_ALLOC();
336 
337 #ifdef ADI_DEBUG
338  /* make sure we're initialized */
339  if (NULL == gpCallbackTable)
340  {
341  return (ADI_XINT_NOT_INITIALIZED);
342  }
343 #endif
344 
345  ADI_ENTER_CRITICAL_REGION();
346  gpCallbackTable[eEvent].pfCallback = pfCallback;
347  gpCallbackTable[eEvent].pCBParam = pCBParam;
348  ADI_EXIT_CRITICAL_REGION();
349 
350  /* return the status */
351  return (ADI_XINT_SUCCESS);
352 }
353 
357 /* All of the following is excluded from the doxygen output... */
358 
359 /* Common external interrupt handler */
360 static inline void XIntCommonInterruptHandler(const ADI_XINT_EVENT eEvent)
361 {
362  /* Clear the IRQ */
363  pADI_XINT0->CLR = (1u << (uint32_t)eEvent);
364 
365  /* params list is: application-registered cbParam, Event ID, and NULL */
366  if(gpCallbackTable[eEvent].pfCallback != NULL)
367  {
368  gpCallbackTable[eEvent].pfCallback (gpCallbackTable[eEvent].pCBParam, (uint32_t) eEvent, NULL);
369  }
370 }
371 
372 /* strongly-bound interrupt handlers to override the default weak bindings */
373 void Ext_Int0_Handler(void)
374 {
375  ISR_PROLOG()
376  XIntCommonInterruptHandler(ADI_XINT_EVENT_INT0);
377  ISR_EPILOG()
378 }
379 
380 void Ext_Int1_Handler(void)
381 {
382  ISR_PROLOG()
383  XIntCommonInterruptHandler(ADI_XINT_EVENT_INT1);
384  ISR_EPILOG()
385 }
386 
387 void Ext_Int2_Handler(void)
388 {
389  ISR_PROLOG()
390  XIntCommonInterruptHandler(ADI_XINT_EVENT_INT2);
391  ISR_EPILOG()
392 
393 }
394 
395 void Ext_Int3_Handler(void)
396 {
397  ISR_PROLOG()
398  if((pADI_XINT0->EXT_STAT & BITM_XINT_EXT_STAT_STAT_UART_RXWKUP)==BITM_XINT_EXT_STAT_STAT_UART_RXWKUP)
399  {
400  XIntCommonInterruptHandler(ADI_XINT_EVENT_UART_RX);
401  }
402  else
403  {
404  XIntCommonInterruptHandler(ADI_XINT_EVENT_INT3);
405  }
406  ISR_EPILOG()
407 }
408 
411 /*
412 ** EOF
413 */
ADI_XINT_EVENT
Definition: adi_xint.h:97
ADI_XINT_RESULT adi_xint_Init(void *const pMemory, uint32_t const MemorySize)
Initializes the External Interrupt Driver.
Definition: adi_xint.c:107
ADI_XINT_RESULT adi_xint_RegisterCallback(const ADI_XINT_EVENT eEvent, ADI_CALLBACK const pfCallback, void *const pCBParam)
Register or unregister an application callback function for external pin interrupts.
Definition: adi_xint.c:333
ADI_XINT_RESULT adi_xint_UnInit(void)
Un-initialize the external interrupt driver.
Definition: adi_xint.c:149
#define ADI_XINT_MEMORY_SIZE
Definition: adi_xint.h:72
ADI_XINT_RESULT
Definition: adi_xint.h:75
ADI_XINT_RESULT adi_xint_DisableIRQ(const ADI_XINT_EVENT eEvent)
Disable an External Interrupt.
Definition: adi_xint.c:261
ADI_XINT_RESULT adi_xint_EnableIRQ(const ADI_XINT_EVENT eEvent, const ADI_XINT_IRQ_MODE eMode)
Enable an External Interrupt.
Definition: adi_xint.c:191
ADI_XINT_IRQ_MODE
Definition: adi_xint.h:88