]> git.sur5r.net Git - freertos/blob
f6721ca7509ac6d08ea25cd2496503828a26d506
[freertos] /
1 /******************************************************************************
2 *
3 * Copyright (C) 2010 - 2015 Xilinx, Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 *
35 * @file xcanps_intr.c
36 * @addtogroup canps_v3_0
37 * @{
38 *
39 * This file contains functions related to CAN interrupt handling.
40 *
41 * <pre>
42 * MODIFICATION HISTORY:
43 *
44 * Ver   Who    Date     Changes
45 * ----- -----  -------- -----------------------------------------------
46 * 1.00a xd/sv  01/12/10 First release
47 * 3.00  kvn    02/13/15 Modified code for MISRA-C:2012 compliance.
48 * 3.1   nsk    12/21/15 Updated XCanPs_IntrHandler to handle error
49 *                       interrupts correctly. CR#925615
50 * </pre>
51 *
52 ******************************************************************************/
53
54 /***************************** Include Files *********************************/
55
56 #include "xcanps.h"
57
58 /************************** Constant Definitions *****************************/
59
60 /**************************** Type Definitions *******************************/
61
62 /***************** Macros (Inline Functions) Definitions *********************/
63
64 /************************** Variable Definitions *****************************/
65
66 /************************** Function Prototypes ******************************/
67
68 /****************************************************************************/
69 /**
70 *
71 * This routine enables interrupt(s). Use the XCANPS_IXR_* constants defined in
72 * xcanps_hw.h to create the bit-mask to enable interrupts.
73 *
74 * @param        InstancePtr is a pointer to the XCanPs instance.
75 * @param        Mask is the mask to enable. Bit positions of 1 will be enabled.
76 *               Bit positions of 0 will keep the previous setting. This mask is
77 *               formed by OR'ing XCANPS_IXR_* bits defined in xcanps_hw.h.
78 *
79 * @return       None.
80 *
81 * @note         None.
82 *
83 *****************************************************************************/
84 void XCanPs_IntrEnable(XCanPs *InstancePtr, u32 Mask)
85 {
86         u32 IntrValue;
87
88         Xil_AssertVoid(InstancePtr != NULL);
89         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
90
91         /*
92          * Write to the IER to enable the specified interrupts.
93          */
94         IntrValue = XCanPs_IntrGetEnabled(InstancePtr);
95         IntrValue |= Mask;
96         XCanPs_WriteReg(InstancePtr->CanConfig.BaseAddr,
97                         XCANPS_IER_OFFSET, IntrValue);
98 }
99
100 /****************************************************************************/
101 /**
102 *
103 * This routine disables interrupt(s). Use the XCANPS_IXR_* constants defined in
104 * xcanps_hw.h to create the bit-mask to disable interrupt(s).
105 *
106 * @param        InstancePtr is a pointer to the XCanPs instance.
107 * @param        Mask is the mask to disable. Bit positions of 1 will be
108 *               disabled. Bit positions of 0 will keep the previous setting.
109 *               This mask is formed by OR'ing XCANPS_IXR_* bits defined in
110 *               xcanps_hw.h.
111 *
112 * @return       None.
113 *
114 * @note         None.
115 *
116 *****************************************************************************/
117 void XCanPs_IntrDisable(XCanPs *InstancePtr, u32 Mask)
118 {
119         u32 IntrValue;
120
121         Xil_AssertVoid(InstancePtr != NULL);
122         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
123
124         /*
125          * Write to the IER to disable the specified interrupts.
126          */
127         IntrValue = XCanPs_IntrGetEnabled(InstancePtr);
128         IntrValue &= ~Mask;
129         XCanPs_WriteReg(InstancePtr->CanConfig.BaseAddr,
130                         XCANPS_IER_OFFSET, IntrValue);
131 }
132
133 /****************************************************************************/
134 /**
135 *
136 * This routine returns enabled interrupt(s). Use the XCANPS_IXR_* constants
137 * defined in xcanps_hw.h to interpret the returned value.
138 *
139 * @param        InstancePtr is a pointer to the XCanPs instance.
140 *
141 * @return       Enabled interrupt(s) in a 32-bit format.
142 *
143 * @note         None.
144 *
145 *****************************************************************************/
146 u32 XCanPs_IntrGetEnabled(XCanPs *InstancePtr)
147 {
148
149         Xil_AssertNonvoid(InstancePtr != NULL);
150         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
151
152         return XCanPs_ReadReg(InstancePtr->CanConfig.BaseAddr,
153                                 XCANPS_IER_OFFSET);
154 }
155
156
157 /****************************************************************************/
158 /**
159 *
160 * This routine returns interrupt status read from Interrupt Status Register.
161 * Use the XCANPS_IXR_* constants defined in xcanps_hw.h to interpret the
162 * returned value.
163 *
164 * @param        InstancePtr is a pointer to the XCanPs instance.
165 *
166 * @return       The value stored in Interrupt Status Register.
167 *
168 * @note         None.
169 *
170 *****************************************************************************/
171 u32 XCanPs_IntrGetStatus(XCanPs *InstancePtr)
172 {
173         Xil_AssertNonvoid(InstancePtr != NULL);
174         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
175
176         return XCanPs_ReadReg(InstancePtr->CanConfig.BaseAddr,
177                                 XCANPS_ISR_OFFSET);
178 }
179
180 /****************************************************************************/
181 /**
182 *
183 * This function clears interrupt(s). Every bit set in Interrupt Status
184 * Register indicates that a specific type of interrupt is occurring, and this
185 * function clears one or more interrupts by writing a bit mask to Interrupt
186 * Clear Register.
187 *
188 * @param        InstancePtr is a pointer to the XCanPs instance.
189 * @param        Mask is the mask to clear. Bit positions of 1 will be cleared.
190 *               Bit positions of 0 will not change the previous interrupt
191 *               status. This mask is formed by OR'ing XCANPS_IXR_* bits defined
192 *               in xcanps_hw.h.
193 *
194 * @note         None.
195 *
196 *****************************************************************************/
197 void XCanPs_IntrClear(XCanPs *InstancePtr, u32 Mask)
198 {
199         u32 IntrValue;
200
201         Xil_AssertVoid(InstancePtr != NULL);
202         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
203
204         /*
205          * Clear the currently pending interrupts.
206          */
207         IntrValue = XCanPs_IntrGetStatus(InstancePtr);
208         IntrValue &= Mask;
209         XCanPs_WriteReg(InstancePtr->CanConfig.BaseAddr, XCANPS_ICR_OFFSET,
210                                 IntrValue);
211 }
212
213 /*****************************************************************************/
214 /**
215 *
216 * This routine is the interrupt handler for the CAN driver.
217 *
218 * This handler reads the interrupt status from the ISR, determines the source of
219 * the interrupts, calls according callbacks, and finally clears the interrupts.
220 *
221 * Application beyond this driver is responsible for providing callbacks to
222 * handle interrupts and installing the callbacks using XCanPs_SetHandler()
223 * during initialization phase. An example delivered with this driver
224 * demonstrates how this could be done.
225 *
226 * @param        InstancePtr is a pointer to the XCanPs instance that just
227 *               interrupted.
228 *
229 * @return       None.
230 *
231 * @note         None.
232 *
233 ******************************************************************************/
234 void XCanPs_IntrHandler(void *InstancePtr)
235 {
236         u32 PendingIntr;
237         u32 EventIntr;
238         u32 ErrorStatus;
239         XCanPs *CanPtr = (XCanPs *) ((void *)InstancePtr);
240
241         Xil_AssertVoid(CanPtr != NULL);
242         Xil_AssertVoid(CanPtr->IsReady == XIL_COMPONENT_IS_READY);
243
244         PendingIntr = XCanPs_IntrGetStatus(CanPtr);
245         PendingIntr &= XCanPs_IntrGetEnabled(CanPtr);
246
247         /*
248          * Clear all pending interrupts.
249          * Rising Edge interrupt
250          */
251         XCanPs_IntrClear(CanPtr, PendingIntr);
252
253         /*
254          * An error interrupt is occurring.
255          */
256         if (((PendingIntr & XCANPS_IXR_ERROR_MASK) != (u32)0) &&
257                 (CanPtr->ErrorHandler != NULL)) {
258                         ErrorStatus = XCanPs_GetBusErrorStatus(CanPtr);
259                         CanPtr->ErrorHandler(CanPtr->ErrorRef,ErrorStatus);
260                 /*
261                  * Clear Error Status Register.
262                  */
263                 XCanPs_ClearBusErrorStatus(CanPtr,ErrorStatus);
264         }
265
266         /*
267          * Check if any following event interrupt is pending:
268          *        - RX FIFO Overflow
269          *        - RX FIFO Underflow
270          *        - TX High Priority Buffer full
271          *        - TX FIFO Full
272          *        - Wake up from sleep mode
273          *        - Enter sleep mode
274          *        - Enter Bus off status
275          *        - Arbitration is lost
276          *
277          * If so, call event callback provided by upper level.
278          */
279         EventIntr = PendingIntr & ((u32)XCANPS_IXR_RXOFLW_MASK |
280                                 (u32)XCANPS_IXR_RXUFLW_MASK |
281                                 (u32)XCANPS_IXR_TXBFLL_MASK |
282                                 (u32)XCANPS_IXR_TXFLL_MASK |
283                                 (u32)XCANPS_IXR_WKUP_MASK |
284                                 (u32)XCANPS_IXR_SLP_MASK |
285                                 (u32)XCANPS_IXR_BSOFF_MASK |
286                                 (u32)XCANPS_IXR_ARBLST_MASK);
287         if ((EventIntr != (u32)0) && (CanPtr->EventHandler != NULL)) {
288                 CanPtr->EventHandler(CanPtr->EventRef, EventIntr);
289
290                 if ((EventIntr & XCANPS_IXR_BSOFF_MASK) != (u32)0) {
291                         /*
292                          * Event callback should reset whole device if "Enter
293                          * Bus Off Status" interrupt occurred. All pending
294                          * interrupts are cleared and no further checking and
295                          * handling of other interrupts is needed any more.
296                          */
297                         return;
298                 } else {
299                         /*This else was made for misra-c compliance*/
300                         ;
301                 }
302         }
303
304
305         if (((PendingIntr & (XCANPS_IXR_RXFWMFLL_MASK |
306                         XCANPS_IXR_RXNEMP_MASK)) != (u32)0) &&
307                 (CanPtr->RecvHandler != NULL)) {
308
309                 /*
310                  * This case happens when
311                  * A number of frames depending on the Rx FIFO Watermark
312                  * threshold are received.
313                  * And  also when frame was received and is sitting in RX FIFO.
314                  *
315                  * XCANPS_IXR_RXOK_MASK is not used because the bit is set
316                  * just once even if there are multiple frames sitting
317                  * in the RX FIFO.
318                  *
319                  * XCANPS_IXR_RXNEMP_MASK is used because the bit can be
320                  * set again and again automatically as long as there is
321                  * at least one frame in RX FIFO.
322                  */
323                 CanPtr->RecvHandler(CanPtr->RecvRef);
324         }
325
326         /*
327          * A frame was transmitted successfully.
328          */
329         if (((PendingIntr & (XCANPS_IXR_TXOK_MASK | XCANPS_IXR_TXFWMEMP_MASK)) != (u32)0) &&
330                 (CanPtr->SendHandler != NULL)) {
331                 CanPtr->SendHandler(CanPtr->SendRef);
332         }
333 }
334
335
336 /*****************************************************************************/
337 /**
338 *
339 * This routine installs an asynchronous callback function for the given
340 * HandlerType:
341 *
342 * <pre>
343 * HandlerType                   Callback Function Type
344 * -----------------------       ------------------------
345 * XCANPS_HANDLER_SEND           XCanPs_SendRecvHandler
346 * XCANPS_HANDLER_RECV           XCanPs_SendRecvHandler
347 * XCANPS_HANDLER_ERROR          XCanPs_ErrorHandler
348 * XCANPS_HANDLER_EVENT          XCanPs_EventHandler
349 *
350 * HandlerType                   Invoked by this driver when:
351 * -------------------------------------------------------------------------
352 * XCANPS_HANDLER_SEND           A frame transmitted by a call to
353 *                               XCanPs_Send() has been sent successfully.
354 *
355 * XCANPS_HANDLER_RECV           A frame(s) has been received and is sitting in
356 *                               the RX FIFO.
357 *
358 * XCANPS_HANDLER_ERROR          An error interrupt is occurring.
359 *
360 * XCANPS_HANDLER_EVENT          Any other kind of interrupt is occurring.
361 * </pre>
362 *
363 * @param        InstancePtr is a pointer to the XCanPs instance.
364 * @param        HandlerType specifies which handler is to be attached.
365 * @param        CallBackFunc is the address of the callback function.
366 * @param        CallBackRef is a user data item that will be passed to the
367 *               callback function when it is invoked.
368 *
369 * @return
370 *               - XST_SUCCESS when handler is installed.
371 *               - XST_INVALID_PARAM when HandlerType is invalid.
372 *
373 * @note
374 * Invoking this function for a handler that already has been installed replaces
375 * it with the new handler.
376 *
377 ******************************************************************************/
378 s32 XCanPs_SetHandler(XCanPs *InstancePtr, u32 HandlerType,
379                         void *CallBackFunc, void *CallBackRef)
380 {
381         s32 Status;
382         Xil_AssertNonvoid(InstancePtr != NULL);
383         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
384
385         switch (HandlerType) {
386                 case XCANPS_HANDLER_SEND:
387                         InstancePtr->SendHandler =
388                                 (XCanPs_SendRecvHandler) CallBackFunc;
389                         InstancePtr->SendRef = CallBackRef;
390                         Status = XST_SUCCESS;
391                         break;
392
393                 case XCANPS_HANDLER_RECV:
394                         InstancePtr->RecvHandler =
395                                 (XCanPs_SendRecvHandler) CallBackFunc;
396                         InstancePtr->RecvRef = CallBackRef;
397                         Status = XST_SUCCESS;
398                         break;
399
400                 case XCANPS_HANDLER_ERROR:
401                         InstancePtr->ErrorHandler =
402                                 (XCanPs_ErrorHandler) CallBackFunc;
403                         InstancePtr->ErrorRef = CallBackRef;
404                         Status = XST_SUCCESS;
405                         break;
406
407                 case XCANPS_HANDLER_EVENT:
408                         InstancePtr->EventHandler =
409                                 (XCanPs_EventHandler) CallBackFunc;
410                         InstancePtr->EventRef = CallBackRef;
411                         Status = XST_SUCCESS;
412                         break;
413
414                 default:
415                         Status = XST_INVALID_PARAM;
416                         break;
417         }
418         return Status;
419 }
420
421 /** @} */