1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2022 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_mcan.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.mcan"
18 #endif
19 
20 /* According to CiA doc 1301 v1.0.0, specified data/nominal phase sample point postion for CAN FD at 80 MHz. */
21 #define IDEAL_DATA_SP_1  (800U)
22 #define IDEAL_DATA_SP_2  (750U)
23 #define IDEAL_DATA_SP_3  (700U)
24 #define IDEAL_DATA_SP_4  (625U)
25 #define IDEAL_NOMINAL_SP (800U)
26 
27 /* According to CiA doc 301 v4.2.0 and previous version, specified sample point postion for classic CAN. */
28 #define IDEAL_SP_LOW    (750U)
29 #define IDEAL_SP_MID    (800U)
30 #define IDEAL_SP_HIGH   (875U)
31 #define IDEAL_SP_FACTOR (1000U)
32 
33 #define MAX_DSJW   (CAN_DBTP_DSJW_MASK >> CAN_DBTP_DSJW_SHIFT)
34 #define MAX_DTSEG2 (CAN_DBTP_DTSEG2_MASK >> CAN_DBTP_DTSEG2_SHIFT)
35 #define MAX_DTSEG1 (CAN_DBTP_DTSEG1_MASK >> CAN_DBTP_DTSEG1_SHIFT)
36 #define MAX_DBRP   (CAN_DBTP_DBRP_MASK >> CAN_DBTP_DBRP_SHIFT)
37 
38 #define MAX_NSJW   (CAN_NBTP_NSJW_MASK >> CAN_NBTP_NSJW_SHIFT)
39 #define MAX_NTSEG2 (CAN_NBTP_NTSEG2_MASK >> CAN_NBTP_NTSEG2_SHIFT)
40 #define MAX_NTSEG1 (CAN_NBTP_NTSEG1_MASK >> CAN_NBTP_NTSEG1_SHIFT)
41 #define MAX_NBRP   (CAN_NBTP_NBRP_MASK >> CAN_NBTP_NBRP_SHIFT)
42 
43 #define DBTP_MAX_TIME_QUANTA (1U + MAX_DTSEG2 + 1U + MAX_DTSEG1 + 1U)
44 #define DBTP_MIN_TIME_QUANTA (3U)
45 #define NBTP_MAX_TIME_QUANTA (1U + MAX_NTSEG2 + 1U + MAX_NTSEG1 + 1U)
46 #define NBTP_MIN_TIME_QUANTA (3U)
47 
48 #define MAX_TDCOFF ((uint32_t)CAN_TDCR_TDCO_MASK >> CAN_TDCR_TDCO_SHIFT)
49 
50 #define MAX_CANFD_BAUDRATE (8000000U)
51 #define MAX_CAN_BAUDRATE   (1000000U)
52 
53 /*! @brief MCAN Internal State. */
54 enum _mcan_state
55 {
56     kMCAN_StateIdle     = 0x0, /*!< MB/RxFIFO idle.*/
57     kMCAN_StateRxData   = 0x1, /*!< MB receiving.*/
58     kMCAN_StateRxRemote = 0x2, /*!< MB receiving remote reply.*/
59     kMCAN_StateTxData   = 0x3, /*!< MB transmitting.*/
60     kMCAN_StateTxRemote = 0x4, /*!< MB transmitting remote request.*/
61     kMCAN_StateRxFifo   = 0x5, /*!< RxFIFO receiving.*/
62 };
63 
64 /* Typedef for interrupt handler. */
65 typedef void (*mcan_isr_t)(CAN_Type *base, mcan_handle_t *handle);
66 
67 /*******************************************************************************
68  * Prototypes
69  ******************************************************************************/
70 
71 /*!
72  * @brief Get the MCAN instance from peripheral base address.
73  *
74  * @param base MCAN peripheral base address.
75  * @return MCAN instance.
76  */
77 static uint32_t MCAN_GetInstance(CAN_Type *base);
78 
79 /*!
80  * @brief Reset the MCAN instance.
81  *
82  * @param base MCAN peripheral base address.
83  */
84 static void MCAN_Reset(CAN_Type *base);
85 
86 /*!
87  * @brief Calculates the segment values for a single bit time for classical CAN
88  *
89  * @param baudRate The data speed in bps
90  * @param tqNum Number of time quantas per bit, range in 4~385
91  * @param pconfig Pointer to the MCAN timing configuration structure.
92  */
93 static void MCAN_GetSegments(uint32_t baudRate, uint32_t tqNum, mcan_timing_config_t *pconfig);
94 
95 #if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
96 /*!
97  * @brief Calculates the segment values for a single bit time for CANFD bus data baud Rate
98  *
99  * @param baudRate The canfd bus data speed in bps
100  * @param tqNum Number of time quanta per bit, range in 3 ~ 33
101  * @param pconfig Pointer to the MCAN timing configuration structure.
102  */
103 static void MCAN_FDGetSegments(uint32_t baudRateFD, uint32_t tqNum, mcan_timing_config_t *pconfig);
104 
105 #endif /* FSL_FEATURE_CAN_SUPPORT_CANFD */
106 
107 /*!
108  * @brief Get the element's address when read receive fifo 0.
109  *
110  * @param base MCAN peripheral base address.
111  * @return Address of the element in receive fifo 0.
112  */
113 static uint32_t MCAN_GetRxFifo0ElementAddress(CAN_Type *base);
114 
115 /*!
116  * @brief Get the element's address when read receive fifo 1.
117  *
118  * @param base MCAN peripheral base address.
119  * @return Address of the element in receive fifo 1.
120  */
121 static uint32_t MCAN_GetRxFifo1ElementAddress(CAN_Type *base);
122 
123 /*!
124  * @brief Get the element's address when read receive buffer.
125  *
126  * @param base MCAN peripheral base address.
127  * @param idx Number of the erceive buffer element.
128  * @return Address of the element in receive buffer.
129  */
130 static uint32_t MCAN_GetRxBufferElementAddress(CAN_Type *base, uint8_t idx);
131 
132 /*!
133  * @brief Get the element's address when read transmit buffer.
134  *
135  * @param base MCAN peripheral base address.
136  * @param idx Number of the transmit buffer element.
137  * @return Address of the element in transmit buffer.
138  */
139 static uint32_t MCAN_GetTxBufferElementAddress(CAN_Type *base, uint8_t idx);
140 
141 /*******************************************************************************
142  * Variables
143  ******************************************************************************/
144 /* Array of MCAN handle. */
145 static mcan_handle_t *s_mcanHandle[FSL_FEATURE_SOC_LPC_CAN_COUNT];
146 
147 /* Array of MCAN peripheral base address. */
148 static CAN_Type *const s_mcanBases[] = CAN_BASE_PTRS;
149 
150 /* Array of MCAN IRQ number. */
151 static const IRQn_Type s_mcanIRQ[][2] = CAN_IRQS;
152 
153 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
154 /* Array of MCAN clock name. */
155 static const clock_ip_name_t s_mcanClock[] = MCAN_CLOCKS;
156 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
157 
158 #if !(defined(FSL_FEATURE_MCAN_HAS_NO_RESET) && FSL_FEATURE_MCAN_HAS_NO_RESET)
159 /*! @brief Pointers to MCAN resets for each instance. */
160 static const reset_ip_name_t s_mcanResets[] = MCAN_RSTS;
161 #endif
162 
163 /* MCAN ISR for transactional APIs. */
164 #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
165 static mcan_isr_t s_mcanIsr = (mcan_isr_t)DefaultISR;
166 #else
167 static mcan_isr_t s_mcanIsr;
168 #endif
169 
170 /*******************************************************************************
171  * Code
172  ******************************************************************************/
173 
MCAN_GetInstance(CAN_Type * base)174 static uint32_t MCAN_GetInstance(CAN_Type *base)
175 {
176     uint32_t instance;
177 
178     /* Find the instance index from base address mappings. */
179     for (instance = 0; instance < ARRAY_SIZE(s_mcanBases); instance++)
180     {
181         if (s_mcanBases[instance] == base)
182         {
183             break;
184         }
185     }
186 
187     assert(instance < ARRAY_SIZE(s_mcanBases));
188 
189     return instance;
190 }
191 
MCAN_Reset(CAN_Type * base)192 static void MCAN_Reset(CAN_Type *base)
193 {
194     /* Set INIT bit. */
195     base->CCCR |= CAN_CCCR_INIT_MASK;
196     /* Confirm the value has been accepted. */
197     while (0U == (base->CCCR & CAN_CCCR_INIT_MASK))
198     {
199     }
200 
201     /* Set CCE bit to have access to the protected configuration registers,
202        and clear some status registers. */
203     base->CCCR |= CAN_CCCR_CCE_MASK;
204 }
205 
206 /*!
207  * brief Initializes an MCAN instance.
208  *
209  * This function initializes the MCAN module with user-defined settings.
210  * This example shows how to set up the mcan_config_t parameters and how
211  * to call the MCAN_Init function by passing in these parameters.
212  *  code
213  *   mcan_config_t config;
214  *   config->baudRateA = 500000U;
215  *   config->baudRateD = 1000000U;
216  *   config->enableCanfdNormal = false;
217  *   config->enableCanfdSwitch = false;
218  *   config->enableLoopBackInt = false;
219  *   config->enableLoopBackExt = false;
220  *   config->enableBusMon = false;
221  *   MCAN_Init(CANFD0, &config, 8000000UL);
222  *   endcode
223  *
224  * param base MCAN peripheral base address.
225  * param config Pointer to the user-defined configuration structure.
226  * param sourceClock_Hz MCAN Protocol Engine clock source frequency in Hz.
227  */
MCAN_Init(CAN_Type * base,const mcan_config_t * config,uint32_t sourceClock_Hz)228 void MCAN_Init(CAN_Type *base, const mcan_config_t *config, uint32_t sourceClock_Hz)
229 {
230     mcan_timing_config_t timingCfg = config->timingConfig;
231     uint32_t quantum               = 0U;
232     uint32_t tqFre                 = 0U;
233 
234 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
235     /* Enable MCAN clock. */
236     CLOCK_EnableClock(s_mcanClock[MCAN_GetInstance(base)]);
237 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
238 
239 #if !(defined(FSL_FEATURE_MCAN_HAS_NO_RESET) && FSL_FEATURE_MCAN_HAS_NO_RESET)
240     /* Reset the MCAN module */
241     RESET_PeripheralReset(s_mcanResets[MCAN_GetInstance(base)]);
242 #endif
243 
244     MCAN_Reset(base);
245 
246     if (config->enableLoopBackInt)
247     {
248         base->CCCR |= CAN_CCCR_TEST_MASK | CAN_CCCR_MON_MASK;
249         base->TEST |= CAN_TEST_LBCK_MASK;
250     }
251     if (config->enableLoopBackExt)
252     {
253         base->CCCR |= CAN_CCCR_TEST_MASK;
254         base->TEST |= CAN_TEST_LBCK_MASK;
255     }
256     if (config->enableBusMon)
257     {
258         base->CCCR |= CAN_CCCR_MON_MASK;
259     }
260 
261     /* Nominal quantum = 1 + (NTSEG1 + 1) + (NTSEG2 + 1) */
262     quantum = (1U + ((uint32_t)timingCfg.seg1 + 1U) + ((uint32_t)timingCfg.seg2 + 1U));
263     tqFre   = config->baudRateA * quantum;
264 
265     /* Assertion: Source clock should greater than baud rate * quantum. */
266     assert((tqFre != 0U) && (tqFre <= sourceClock_Hz));
267 
268     /* Check whether Nominal Bit Rate Prescaler is overflow. */
269     if ((sourceClock_Hz / tqFre - 1U) > 0x1FFU)
270     {
271         timingCfg.preDivider = 0x1FFU;
272     }
273     else
274     {
275         timingCfg.preDivider = (uint16_t)(sourceClock_Hz / tqFre) - 1U;
276     }
277     /* Update actual timing characteristic to set baud rate of arbitration phase. */
278     MCAN_SetArbitrationTimingConfig(base, &timingCfg);
279 
280 #if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
281     if (config->enableCanfdNormal)
282     {
283         base->CCCR |= CAN_CCCR_FDOE_MASK;
284     }
285     if (config->enableCanfdSwitch)
286     {
287         /* Enable the CAN FD mode and Bit Rate Switch feature. */
288         base->CCCR |= CAN_CCCR_FDOE_MASK | CAN_CCCR_BRSE_MASK;
289 
290         /* Data quantum = 1 + (NTSEG1 + 1) + (NTSEG2 + 1) */
291         quantum = (1U + ((uint32_t)timingCfg.dataseg1 + 1U) + ((uint32_t)timingCfg.dataseg2 + 1U));
292         tqFre   = config->baudRateD * quantum;
293         assert((tqFre != 0U) && (tqFre <= sourceClock_Hz));
294 
295         /* Check whether Data Bit Rate Prescaler is overflow. */
296         if ((sourceClock_Hz / tqFre - 1U) > 0x1FU)
297         {
298             timingCfg.datapreDivider = 0x1FU;
299         }
300         else
301         {
302             timingCfg.datapreDivider = (uint16_t)(sourceClock_Hz / tqFre) - 1U;
303         }
304 
305         /* Update actual timing characteristic to set baud rate of data phase. */
306         MCAN_SetDataTimingConfig(base, &timingCfg);
307         if (!config->enableLoopBackInt && !config->enableLoopBackExt)
308         {
309             /* Enable the Transceiver Delay Compensation. */
310             base->DBTP |= CAN_DBTP_TDC_MASK;
311             /* Cleaning previous TDCO Setting. */
312             base->TDCR &= ~CAN_TDCR_TDCO_MASK;
313             /* The TDC offset should be configured as shown in this equation : offset = (DTSEG1 + 2) * (DBRP + 1) */
314             if (((uint32_t)timingCfg.dataseg1 + 2U) * (timingCfg.datapreDivider + 1U) < MAX_TDCOFF)
315             {
316                 base->TDCR |= CAN_TDCR_TDCO(((uint32_t)timingCfg.dataseg1 + 2U) * (timingCfg.datapreDivider + 1U));
317             }
318             else
319             {
320                 /* Set the Transceiver Delay Compensation offset to max value. */
321                 base->TDCR |= CAN_TDCR_TDCO(MAX_TDCOFF);
322             }
323         }
324     }
325 #endif
326 }
327 
328 /*!
329  * brief Deinitializes an MCAN instance.
330  *
331  * This function deinitializes the MCAN module.
332  *
333  * param base MCAN peripheral base address.
334  */
MCAN_Deinit(CAN_Type * base)335 void MCAN_Deinit(CAN_Type *base)
336 {
337     /* Reset all Register Contents. */
338     MCAN_Reset(base);
339 
340 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
341     /* Disable MCAN clock. */
342     CLOCK_DisableClock(s_mcanClock[MCAN_GetInstance(base)]);
343 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
344 }
345 
346 /*!
347  * brief Gets the default configuration structure.
348  *
349  * This function initializes the MCAN configuration structure to default values. The default
350  * values are as follows.
351  *   config->baudRateA = 500000U;
352  *   config->baudRateD = 1000000U;
353  *   config->enableCanfdNormal = false;
354  *   config->enableCanfdSwitch = false;
355  *   config->enableLoopBackInt = false;
356  *   config->enableLoopBackExt = false;
357  *   config->enableBusMon = false;
358  *
359  * param config Pointer to the MCAN configuration structure.
360  */
MCAN_GetDefaultConfig(mcan_config_t * config)361 void MCAN_GetDefaultConfig(mcan_config_t *config)
362 {
363     /* Assertion. */
364     assert(NULL != config);
365 
366     /* Initializes the configure structure to zero. */
367     (void)memset(config, 0, sizeof(*config));
368 
369     /* Initialize MCAN Module config struct with default value. */
370     config->baudRateA         = 500000U;
371     config->baudRateD         = 2000000U;
372     config->enableCanfdNormal = false;
373     config->enableCanfdSwitch = false;
374     config->enableLoopBackInt = false;
375     config->enableLoopBackExt = false;
376     config->enableBusMon      = false;
377     /* Default protocol timing configuration, time quantum is 16. */
378     config->timingConfig.seg1       = 0xAU;
379     config->timingConfig.seg2       = 0x3U;
380     config->timingConfig.rJumpwidth = 0x3U;
381 #if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
382     config->timingConfig.dataseg1       = 0xAU;
383     config->timingConfig.dataseg2       = 0x3U;
384     config->timingConfig.datarJumpwidth = 0x3U;
385 #endif
386 }
387 
388 #if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
389 /*!
390  * @brief Calculates the segment values for a single bit time for CANFD bus data baud Rate
391  *
392  * @param baudRate The canfd bus data speed in bps
393  * @param tqNum Number of time quanta per bit, range in 3 ~ 33
394  * @param pconfig Pointer to the MCAN timing configuration structure.
395  */
MCAN_FDGetSegments(uint32_t baudRateFD,uint32_t tqNum,mcan_timing_config_t * pconfig)396 static void MCAN_FDGetSegments(uint32_t baudRateFD, uint32_t tqNum, mcan_timing_config_t *pconfig)
397 {
398     uint32_t ideal_sp, seg1Temp;
399 
400     /* get ideal sample point. */
401     if (baudRateFD <= 1000000U)
402     {
403         ideal_sp = IDEAL_DATA_SP_1;
404     }
405     else if (baudRateFD <= 2000000U)
406     {
407         ideal_sp = IDEAL_DATA_SP_2;
408     }
409     else if (baudRateFD <= 4000000U)
410     {
411         ideal_sp = IDEAL_DATA_SP_3;
412     }
413     else
414     {
415         ideal_sp = IDEAL_DATA_SP_4;
416     }
417     /* distribute time quanta. */
418     pconfig->dataseg2 = (uint8_t)(tqNum - (tqNum * ideal_sp) / (uint32_t)IDEAL_SP_FACTOR - 1U);
419 
420     if (pconfig->dataseg2 > MAX_DTSEG2)
421     {
422         pconfig->dataseg2 = MAX_DTSEG2;
423     }
424 
425     seg1Temp = tqNum - pconfig->dataseg2 - 3U;
426 
427     if (seg1Temp > MAX_DTSEG1)
428     {
429         pconfig->dataseg2 = (uint8_t)(tqNum - MAX_DTSEG1 - 3U);
430         pconfig->dataseg1 = MAX_DTSEG1;
431     }
432     else
433     {
434         pconfig->dataseg1 = (uint8_t)seg1Temp;
435     }
436 
437     /* sjw is the minimum value of phaseSeg1 and phaseSeg2. */
438     pconfig->datarJumpwidth = (pconfig->dataseg1 > pconfig->dataseg2) ? pconfig->dataseg2 : pconfig->dataseg1;
439     if (pconfig->datarJumpwidth > (uint8_t)MAX_DSJW)
440     {
441         pconfig->datarJumpwidth = (uint8_t)MAX_DSJW;
442     }
443 }
444 
445 /*!
446  * brief Calculates the improved timing values by specific bit rate for CAN FD nominal phase.
447  *
448  * This function use to calculates the CAN FD nominal phase timing values according to the given nominal phase bit rate.
449  * The calculation is based on the recommendation of the CiA 1301 v1.0.0 document.
450  *
451  * param baudRate  The CAN FD nominal phase speed in bps defined by user, should be less than or equal to 1Mbps.
452  * param sourceClock_Hz The Source clock frequency in Hz.
453  * param pconfig Pointer to the MCAN timing configuration structure.
454  *
455  * return TRUE if timing configuration found, FALSE if failed to find configuration.
456  */
MCAN_CalculateImprovedNominalTimingValues(uint32_t baudRate,uint32_t sourceClock_Hz,mcan_timing_config_t * pconfig)457 static bool MCAN_CalculateImprovedNominalTimingValues(uint32_t baudRate,
458                                                       uint32_t sourceClock_Hz,
459                                                       mcan_timing_config_t *pconfig)
460 {
461     uint32_t clk;   /* the clock is tqNumb x baudRate. */
462     uint32_t tqNum; /* Numbers of TQ. */
463     uint32_t seg1Temp;
464     bool fgRet      = false;
465     uint32_t spTemp = 1000U;
466     mcan_timing_config_t configTemp;
467 
468     /*  Auto Improved Protocal timing for NBTP. */
469     for (tqNum = NBTP_MAX_TIME_QUANTA; tqNum >= NBTP_MIN_TIME_QUANTA; tqNum--)
470     {
471         clk = baudRate * tqNum;
472         if (clk > sourceClock_Hz)
473         {
474             continue; /* tqNum too large, clk has been exceed sourceClock_Hz. */
475         }
476 
477         if ((sourceClock_Hz / clk * clk) != sourceClock_Hz)
478         {
479             continue; /*  Non-supporting: the frequency of clock source is not divisible by target baud rate, the user
480                       should change a divisible baud rate. */
481         }
482 
483         configTemp.preDivider = (uint16_t)(sourceClock_Hz / clk - 1U);
484         if (configTemp.preDivider > MAX_NBRP)
485         {
486             break; /* The frequency of source clock is too large or the baud rate is too small, the pre-divider could
487                       not handle it. */
488         }
489         /* Calculates the best timing configuration under current tqNum. */
490         configTemp.seg2 = (uint8_t)(tqNum - (tqNum * IDEAL_NOMINAL_SP) / (uint32_t)IDEAL_SP_FACTOR - 1U);
491 
492         if (configTemp.seg2 > MAX_NTSEG2)
493         {
494             configTemp.seg2 = MAX_NTSEG2;
495         }
496 
497         seg1Temp = tqNum - configTemp.seg2 - 3U;
498 
499         if (seg1Temp > MAX_NTSEG1)
500         {
501             configTemp.seg2 = (uint8_t)(tqNum - MAX_NTSEG1 - 3U);
502             configTemp.seg1 = MAX_NTSEG1;
503         }
504         else
505         {
506             configTemp.seg1 = (uint8_t)seg1Temp;
507         }
508 
509         /* sjw is the minimum value of phaseSeg1 and phaseSeg2. */
510         configTemp.rJumpwidth = (configTemp.seg1 > configTemp.seg2) ? configTemp.seg2 : configTemp.seg1;
511         if (configTemp.rJumpwidth > (uint8_t)MAX_NSJW)
512         {
513             configTemp.rJumpwidth = (uint8_t)MAX_NSJW;
514         }
515         /* Determine whether the calculated timing configuration can get the optimal sampling point. */
516         if (((((uint32_t)configTemp.seg2 + 1U) * 1000U) / tqNum) < spTemp)
517         {
518             spTemp              = (((uint32_t)configTemp.seg2 + 1U) * 1000U) / tqNum;
519             pconfig->preDivider = configTemp.preDivider;
520             pconfig->rJumpwidth = configTemp.rJumpwidth;
521             pconfig->seg1       = configTemp.seg1;
522             pconfig->seg2       = configTemp.seg2;
523         }
524         fgRet = true;
525     }
526     return fgRet;
527 }
528 /*!
529  * brief Calculates the improved timing values by specific baudrates for CANFD
530  *
531  * param baudRate  The CANFD bus control speed in bps defined by user
532  * param baudRateFD  The CANFD bus data speed in bps defined by user
533  * param sourceClock_Hz The Source clock data speed in bps.
534  * param pconfig Pointer to the MCAN timing configuration structure.
535  *
536  * return TRUE if timing configuration found, FALSE if failed to find configuration
537  */
MCAN_FDCalculateImprovedTimingValues(uint32_t baudRate,uint32_t baudRateFD,uint32_t sourceClock_Hz,mcan_timing_config_t * pconfig)538 bool MCAN_FDCalculateImprovedTimingValues(uint32_t baudRate,
539                                           uint32_t baudRateFD,
540                                           uint32_t sourceClock_Hz,
541                                           mcan_timing_config_t *pconfig)
542 {
543     uint32_t clk;
544     uint32_t tqNum; /* Numbers of TQ. */
545     bool fgRet              = false;
546     uint16_t preDividerTemp = 1U;
547     /* observe baud rate maximums */
548     assert(baudRate <= MAX_CAN_BAUDRATE);
549     assert(baudRateFD <= MAX_CANFD_BAUDRATE);
550     /* Data phase bit rate need greater or equal to nominal phase bit rate. */
551     assert(baudRate <= baudRateFD);
552 
553     if (baudRate < baudRateFD)
554     {
555         /* To minimize errors when processing FD frames, try to get the same bit rate prescaler value for nominal phase
556            and data phase. */
557         while (MCAN_CalculateImprovedNominalTimingValues(baudRate, sourceClock_Hz / preDividerTemp, pconfig))
558         {
559             pconfig->datapreDivider = 0U;
560             for (tqNum = DBTP_MAX_TIME_QUANTA; tqNum >= DBTP_MIN_TIME_QUANTA; tqNum--)
561             {
562                 clk = baudRateFD * tqNum;
563                 if (clk > sourceClock_Hz)
564                 {
565                     continue; /* tqNumbrs too large, clk x tqNumbrs has been exceed sourceClock_Hz. */
566                 }
567 
568                 if ((sourceClock_Hz / clk * clk) != sourceClock_Hz)
569                 {
570                     continue; /* Non-supporting: the frequency of clock source is not divisible by target bit rate. */
571                 }
572 
573                 pconfig->datapreDivider = (uint16_t)(sourceClock_Hz / clk - 1U);
574 
575                 if (pconfig->datapreDivider > MAX_DBRP)
576                 {
577                     break; /* The frequency of source clock is too large or the bit rate is too small, the pre-divider
578                               could not handle it. */
579                 }
580 
581                 if (pconfig->datapreDivider < ((pconfig->preDivider + 1U) * preDividerTemp - 1U))
582                 {
583                     continue; /* try to get the same bit rate prescaler value for nominal phase and data phase. */
584                 }
585                 else if (pconfig->datapreDivider == ((pconfig->preDivider + 1U) * preDividerTemp - 1U))
586                 {
587                     /* Calculates the best data phase timing configuration under current tqNum. */
588                     MCAN_FDGetSegments(baudRateFD, tqNum, pconfig);
589                     fgRet = true;
590                     break;
591                 }
592                 else
593                 {
594                     break;
595                 }
596             }
597 
598             if (fgRet)
599             {
600                 /* Find same bit rate prescaler (BRP) configuration in both nominal and data bit timing configurations.
601                  */
602                 pconfig->preDivider = (pconfig->preDivider + 1U) * preDividerTemp - 1U;
603                 break;
604             }
605             else
606             {
607                 if ((pconfig->datapreDivider <= MAX_DBRP) && (pconfig->datapreDivider != 0U))
608                 {
609                     /* Can't find same data bit rate prescaler (BRP) configuration under current nominal phase bit rate
610                        prescaler, double the nominal phase bit rate prescaler and recalculate. */
611                     preDividerTemp++;
612                 }
613                 else
614                 {
615                     break;
616                 }
617             }
618         }
619     }
620     else
621     {
622         if (MCAN_CalculateImprovedTimingValues(baudRate, sourceClock_Hz, pconfig))
623         {
624             /* No need data phase timing configuration, data phase rate equal to nominal phase rate, user don't use Brs
625                feature. */
626             pconfig->datapreDivider = 0U;
627             pconfig->datarJumpwidth = 0U;
628             pconfig->dataseg1       = 0U;
629             pconfig->dataseg2       = 0U;
630             fgRet                   = true;
631         }
632     }
633 
634     return fgRet;
635 }
636 
637 /*!
638  * brief Sets the MCAN protocol data phase timing characteristic.
639  *
640  * This function gives user settings to CAN bus timing characteristic.
641  * The function is for an experienced user. For less experienced users, call
642  * the MCAN_Init() and fill the baud rate field with a desired value.
643  * This provides the default data phase timing characteristics.
644  *
645  * Note that calling MCAN_SetArbitrationTimingConfig() overrides the baud rate
646  * set in MCAN_Init().
647  *
648  * param base MCAN peripheral base address.
649  * param config Pointer to the timing configuration structure.
650  */
MCAN_SetDataTimingConfig(CAN_Type * base,const mcan_timing_config_t * config)651 void MCAN_SetDataTimingConfig(CAN_Type *base, const mcan_timing_config_t *config)
652 {
653     /* Assertion. */
654     assert(NULL != config);
655 
656     /* Cleaning previous Timing Setting. */
657     base->DBTP &= ~(CAN_DBTP_DSJW_MASK | CAN_DBTP_DTSEG2_MASK | CAN_DBTP_DTSEG1_MASK | CAN_DBTP_DBRP_MASK);
658 
659     /* Updating Timing Setting according to configuration structure. */
660     base->DBTP |= (CAN_DBTP_DBRP(config->datapreDivider) | CAN_DBTP_DSJW(config->datarJumpwidth) |
661                    CAN_DBTP_DTSEG1(config->dataseg1) | CAN_DBTP_DTSEG2(config->dataseg2));
662 }
663 
664 /*!
665  * brief Set Baud Rate of MCAN FD mode.
666  *
667  * This function set the baud rate of MCAN FD base on MCAN_FDCalculateImprovedTimingValues API calculated timing values.
668  *
669  * param base MCAN peripheral base address.
670  * param sourceClock_Hz Source Clock in Hz.
671  * param baudRateN_Bps Nominal Baud Rate in Bps.
672  * param baudRateD_Bps Data Baud Rate in Bps.
673  * return kStatus_Success - Set CAN FD baud rate (include Nominal and Data phase) successfully.
674  */
MCAN_SetBaudRateFD(CAN_Type * base,uint32_t sourceClock_Hz,uint32_t baudRateN_Bps,uint32_t baudRateD_Bps)675 status_t MCAN_SetBaudRateFD(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRateN_Bps, uint32_t baudRateD_Bps)
676 {
677     mcan_timing_config_t timingCfg;
678 
679     if (MCAN_FDCalculateImprovedTimingValues(baudRateN_Bps, baudRateD_Bps, sourceClock_Hz, &timingCfg))
680     {
681         MCAN_EnterInitialMode(base);
682         /* Update actual timing characteristic. */
683         MCAN_SetArbitrationTimingConfig(base, &timingCfg);
684         MCAN_SetDataTimingConfig(base, &timingCfg);
685         /* Update TDCO value when not enable loopback mode */
686         if (0U == (base->TEST & CAN_TEST_LBCK_MASK))
687         {
688             /* Cleaning previous TDCO Setting. */
689             base->TDCR &= ~CAN_TDCR_TDCO_MASK;
690             /* The TDC offset should be configured as shown in this equation : offset = (DTSEG1 + 2) * (DBRP + 1) */
691             if (((uint32_t)timingCfg.dataseg1 + 2U) * (timingCfg.datapreDivider + 1U) < MAX_TDCOFF)
692             {
693                 base->TDCR |= CAN_TDCR_TDCO(((uint32_t)timingCfg.dataseg1 + 2U) * (timingCfg.datapreDivider + 1U));
694             }
695             else
696             {
697                 /* Set the Transceiver Delay Compensation offset to max value. */
698                 base->TDCR |= CAN_TDCR_TDCO(MAX_TDCOFF);
699             }
700         }
701         MCAN_EnterNormalMode(base);
702         return kStatus_Success;
703     }
704     else
705     {
706         return kStatus_Fail;
707     }
708 }
709 #endif /* FSL_FEATURE_CAN_SUPPORT_CANFD */
710 
711 /*!
712  * @brief Calculates the segment values for a single bit time for classical CAN
713  *
714  * @param baudRate The data speed in bps
715  * @param tqNum Number of time quantas per bit, range in 4~385
716  * @param pconfig Pointer to the MCAN timing configuration structure.
717  */
MCAN_GetSegments(uint32_t baudRate,uint32_t tqNum,mcan_timing_config_t * pconfig)718 static void MCAN_GetSegments(uint32_t baudRate, uint32_t tqNum, mcan_timing_config_t *pconfig)
719 {
720     uint32_t ideal_sp, seg1Temp;
721 
722     /* get ideal sample point. */
723     if (baudRate >= 1000000U)
724     {
725         ideal_sp = IDEAL_SP_LOW;
726     }
727     else if (baudRate >= 800000U)
728     {
729         ideal_sp = IDEAL_SP_MID;
730     }
731     else
732     {
733         ideal_sp = IDEAL_SP_HIGH;
734     }
735 
736     /* distribute time quanta. */
737     pconfig->seg2 = (uint8_t)(tqNum - (tqNum * ideal_sp) / (uint32_t)IDEAL_SP_FACTOR - 1U);
738 
739     if (pconfig->seg2 > MAX_NTSEG2)
740     {
741         pconfig->seg2 = MAX_NTSEG2;
742     }
743 
744     seg1Temp = tqNum - pconfig->seg2 - 3U;
745 
746     if (seg1Temp > MAX_NTSEG1)
747     {
748         pconfig->seg2 = (uint8_t)(tqNum - MAX_NTSEG1 - 3U);
749         pconfig->seg1 = MAX_NTSEG1;
750     }
751     else
752     {
753         pconfig->seg1 = (uint8_t)seg1Temp;
754     }
755 
756     /* sjw is the minimum value of phaseSeg1 and phaseSeg2. */
757     pconfig->rJumpwidth = (pconfig->seg1 > pconfig->seg2) ? pconfig->seg2 : pconfig->seg1;
758     if (pconfig->rJumpwidth > (uint8_t)MAX_NSJW)
759     {
760         pconfig->rJumpwidth = (uint8_t)MAX_NSJW;
761     }
762 }
763 
764 /*!
765  * brief Calculates the improved timing values by specific baudrates for classical CAN
766  *
767  * param baudRate  The classical CAN speed in bps defined by user
768  * param sourceClock_Hz The Source clock data speed in bps. Zero to disable baudrate switching
769  * param pconfig Pointer to the MCAN timing configuration structure.
770  *
771  * return TRUE if timing configuration found, FALSE if failed to find configuration
772  */
MCAN_CalculateImprovedTimingValues(uint32_t baudRate,uint32_t sourceClock_Hz,mcan_timing_config_t * pconfig)773 bool MCAN_CalculateImprovedTimingValues(uint32_t baudRate, uint32_t sourceClock_Hz, mcan_timing_config_t *pconfig)
774 {
775     uint32_t clk;   /* the clock is tqNumb x baudRate. */
776     uint32_t tqNum; /* Numbers of TQ. */
777     bool fgRet                      = false;
778     uint32_t spTemp                 = 1000U;
779     mcan_timing_config_t configTemp = {0};
780     /* observe baud rate maximums. */
781     assert(baudRate <= MAX_CAN_BAUDRATE);
782 
783     /*  Auto Improved Protocal timing for NBTP. */
784     for (tqNum = NBTP_MAX_TIME_QUANTA; tqNum >= NBTP_MIN_TIME_QUANTA; tqNum--)
785     {
786         clk = baudRate * tqNum;
787         if (clk > sourceClock_Hz)
788         {
789             continue; /* tqNum too large, clk has been exceed sourceClock_Hz. */
790         }
791 
792         if ((sourceClock_Hz / clk * clk) != sourceClock_Hz)
793         {
794             continue; /*  Non-supporting: the frequency of clock source is not divisible by target baud rate, the user
795                       should change a divisible baud rate. */
796         }
797 
798         configTemp.preDivider = (uint16_t)(sourceClock_Hz / clk - 1U);
799         if (configTemp.preDivider > MAX_NBRP)
800         {
801             break; /* The frequency of source clock is too large or the baud rate is too small, the pre-divider could
802                       not handle it. */
803         }
804         /* Calculates the best timing configuration under current tqNum. */
805         MCAN_GetSegments(baudRate, tqNum, &configTemp);
806         /* Determine whether the calculated timing configuration can get the optimal sampling point. */
807         if (((((uint32_t)configTemp.seg2 + 1U) * 1000U) / tqNum) < spTemp)
808         {
809             spTemp              = (((uint32_t)configTemp.seg2 + 1U) * 1000U) / tqNum;
810             pconfig->preDivider = configTemp.preDivider;
811             pconfig->rJumpwidth = configTemp.rJumpwidth;
812             pconfig->seg1       = configTemp.seg1;
813             pconfig->seg2       = configTemp.seg2;
814         }
815         fgRet = true;
816     }
817     return fgRet;
818 }
819 /*!
820  * brief Set Baud Rate of MCAN classic mode.
821  *
822  * This function set the baud rate of MCAN base on MCAN_CalculateImprovedTimingValues() API calculated timing values.
823  *
824  * param base MCAN peripheral base address.
825  * param sourceClock_Hz Source Clock in Hz.
826  * param baudRate_Bps Baud Rate in Bps.
827  * return kStatus_Success - Set CAN baud rate (only has Nominal phase) successfully.
828  */
MCAN_SetBaudRate(CAN_Type * base,uint32_t sourceClock_Hz,uint32_t baudRate_Bps)829 status_t MCAN_SetBaudRate(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Bps)
830 {
831     mcan_timing_config_t timingCfg;
832 
833     if (MCAN_CalculateImprovedTimingValues(baudRate_Bps, sourceClock_Hz, &timingCfg))
834     {
835         MCAN_EnterInitialMode(base);
836         /* Update actual timing characteristic. */
837         MCAN_SetArbitrationTimingConfig(base, &timingCfg);
838         MCAN_EnterNormalMode(base);
839         return kStatus_Success;
840     }
841     else
842     {
843         return kStatus_Fail;
844     }
845 }
846 
847 /*!
848  * brief Sets the MCAN protocol arbitration phase timing characteristic.
849  *
850  * This function gives user settings to CAN bus timing characteristic.
851  * The function is for an experienced user. For less experienced users, call
852  * the MCAN_Init() and fill the baud rate field with a desired value.
853  * This provides the default arbitration phase timing characteristics.
854  *
855  * Note that calling MCAN_SetArbitrationTimingConfig() overrides the baud rate
856  * set in MCAN_Init().
857  *
858  * param base MCAN peripheral base address.
859  * param config Pointer to the timing configuration structure.
860  */
MCAN_SetArbitrationTimingConfig(CAN_Type * base,const mcan_timing_config_t * config)861 void MCAN_SetArbitrationTimingConfig(CAN_Type *base, const mcan_timing_config_t *config)
862 {
863     /* Assertion. */
864     assert(NULL != config);
865 
866     /* Cleaning previous Timing Setting. */
867     base->NBTP &= ~(CAN_NBTP_NSJW_MASK | CAN_NBTP_NTSEG2_MASK | CAN_NBTP_NTSEG1_MASK | CAN_NBTP_NBRP_MASK);
868 
869     /* Updating Timing Setting according to configuration structure. */
870     base->NBTP |= (CAN_NBTP_NBRP(config->preDivider) | CAN_NBTP_NSJW(config->rJumpwidth) |
871                    CAN_NBTP_NTSEG1(config->seg1) | CAN_NBTP_NTSEG2(config->seg2));
872 }
873 
874 /*!
875  * brief Set filter configuration.
876  *
877  * This function sets remote and non masking frames in global filter configuration,
878  * also the start address, list size in standard/extended ID filter configuration.
879  *
880  * param base MCAN peripheral base address.
881  * param config The MCAN filter configuration.
882  */
MCAN_SetFilterConfig(CAN_Type * base,const mcan_frame_filter_config_t * config)883 void MCAN_SetFilterConfig(CAN_Type *base, const mcan_frame_filter_config_t *config)
884 {
885     /* Set global configuration of remote/nonmasking frames, set filter address and list size. */
886     if (config->idFormat == kMCAN_FrameIDStandard)
887     {
888         base->GFC |= CAN_GFC_RRFS(config->remFrame) | CAN_GFC_ANFS(config->nmFrame);
889         base->SIDFC |= CAN_SIDFC_FLSSA(config->address >> CAN_SIDFC_FLSSA_SHIFT) | CAN_SIDFC_LSS(config->listSize);
890     }
891     else
892     {
893         base->GFC |= CAN_GFC_RRFE(config->remFrame) | CAN_GFC_ANFE(config->nmFrame);
894         base->XIDFC |= CAN_XIDFC_FLESA(config->address >> CAN_XIDFC_FLESA_SHIFT) | CAN_XIDFC_LSE(config->listSize);
895     }
896 }
897 
898 /*!
899  * brief Configures an MCAN receive fifo 0 buffer.
900  *
901  * This function sets start address, element size, watermark, operation mode
902  * and datafield size of the recieve fifo 0.
903  *
904  * param base MCAN peripheral base address.
905  * param config The receive fifo 0 configuration structure.
906  */
MCAN_SetRxFifo0Config(CAN_Type * base,const mcan_rx_fifo_config_t * config)907 void MCAN_SetRxFifo0Config(CAN_Type *base, const mcan_rx_fifo_config_t *config)
908 {
909     /* Set Rx FIFO 0 start address, element size, watermark, operation mode. */
910     base->RXF0C |= CAN_RXF0C_F0SA(config->address >> CAN_RXF0C_F0SA_SHIFT) | CAN_RXF0C_F0S(config->elementSize) |
911                    CAN_RXF0C_F0WM(config->watermark) | CAN_RXF0C_F0OM(config->opmode);
912     /* Set Rx FIFO 0 data field size */
913     base->RXESC |= CAN_RXESC_F0DS(config->datafieldSize);
914 }
915 
916 /*!
917  * brief Configures an MCAN receive fifo 1 buffer.
918  *
919  * This function sets start address, element size, watermark, operation mode
920  * and datafield size of the recieve fifo 1.
921  *
922  * param base MCAN peripheral base address.
923  * param config The receive fifo 1 configuration structure.
924  */
MCAN_SetRxFifo1Config(CAN_Type * base,const mcan_rx_fifo_config_t * config)925 void MCAN_SetRxFifo1Config(CAN_Type *base, const mcan_rx_fifo_config_t *config)
926 {
927     /* Set Rx FIFO 1 start address, element size, watermark, operation mode. */
928     base->RXF1C |= CAN_RXF1C_F1SA(config->address >> CAN_RXF1C_F1SA_SHIFT) | CAN_RXF1C_F1S(config->elementSize) |
929                    CAN_RXF1C_F1WM(config->watermark) | CAN_RXF1C_F1OM(config->opmode);
930     /* Set Rx FIFO 1 data field size */
931     base->RXESC |= CAN_RXESC_F1DS(config->datafieldSize);
932 }
933 
934 /*!
935  * brief Configures an MCAN receive buffer.
936  *
937  * This function sets start address and datafield size of the recieve buffer.
938  *
939  * param base MCAN peripheral base address.
940  * param config The receive buffer configuration structure.
941  */
MCAN_SetRxBufferConfig(CAN_Type * base,const mcan_rx_buffer_config_t * config)942 void MCAN_SetRxBufferConfig(CAN_Type *base, const mcan_rx_buffer_config_t *config)
943 {
944     /* Set Rx Buffer start address. */
945     base->RXBC |= CAN_RXBC_RBSA(config->address >> CAN_RXBC_RBSA_SHIFT);
946     /* Set Rx Buffer data field size */
947     base->RXESC |= CAN_RXESC_RBDS(config->datafieldSize);
948 }
949 
950 /*!
951  * brief Configures an MCAN transmit event fifo.
952  *
953  * This function sets start address, element size, watermark of the transmit event fifo.
954  *
955  * param base MCAN peripheral base address.
956  * param config The transmit event fifo configuration structure.
957  */
MCAN_SetTxEventFifoConfig(CAN_Type * base,const mcan_tx_fifo_config_t * config)958 void MCAN_SetTxEventFifoConfig(CAN_Type *base, const mcan_tx_fifo_config_t *config)
959 {
960     /* Set TX Event FIFO start address, element size, watermark. */
961     base->TXEFC |= CAN_TXEFC_EFSA(config->address >> CAN_TXEFC_EFSA_SHIFT) | CAN_TXEFC_EFS(config->elementSize) |
962                    CAN_TXEFC_EFWM(config->watermark);
963 }
964 
965 /*!
966  * brief Configures an MCAN transmit buffer.
967  *
968  * This function sets start address, element size, fifo/queue mode and datafield
969  * size of the transmit buffer.
970  *
971  * param base MCAN peripheral base address.
972  * param config The transmit buffer configuration structure.
973  */
MCAN_SetTxBufferConfig(CAN_Type * base,const mcan_tx_buffer_config_t * config)974 void MCAN_SetTxBufferConfig(CAN_Type *base, const mcan_tx_buffer_config_t *config)
975 {
976     assert((config->dedicatedSize + config->fqSize) <= 32U);
977 
978     /* Set Tx Buffer start address, size, fifo/queue mode. */
979     base->TXBC |= CAN_TXBC_TBSA(config->address >> CAN_TXBC_TBSA_SHIFT) | CAN_TXBC_NDTB(config->dedicatedSize) |
980                   CAN_TXBC_TFQS(config->fqSize) | CAN_TXBC_TFQM(config->mode);
981     /* Set Tx Buffer data field size */
982     base->TXESC |= CAN_TXESC_TBDS(config->datafieldSize);
983 }
984 
985 /*!
986  * brief Set Message RAM related configuration.
987  *
988  * note This function include Standard/extended ID filter, Rx FIFO 0/1, Rx buffer, Tx event FIFO and Tx buffer
989  *      configurations
990  * param base MCAN peripheral base address.
991  * param config The MCAN filter configuration.
992  * retval kStatus_Success - Message RAM related configuration Successfully.
993  * retval kStatus_Fail    - Message RAM related configure fail due to wrong address parameter.
994  */
MCAN_SetMessageRamConfig(CAN_Type * base,const mcan_memory_config_t * config)995 status_t MCAN_SetMessageRamConfig(CAN_Type *base, const mcan_memory_config_t *config)
996 {
997     uint32_t temp   = 0U;
998     uint32_t eSize  = 0U;
999     status_t result = kStatus_Success;
1000 
1001     MCAN_EnterInitialMode(base);
1002     if (0U == (config->baseAddr % 4096U))
1003     {
1004         MCAN_SetMsgRAMBase(base, config->baseAddr);
1005     }
1006     else
1007     {
1008         result = kStatus_Fail;
1009     }
1010     if ((config->stdFilterCfg != NULL) && (kStatus_Success == result))
1011     {
1012         if ((config->stdFilterCfg->idFormat == kMCAN_FrameIDStandard) && (0U == (config->stdFilterCfg->address % 4U)))
1013         {
1014             temp = config->stdFilterCfg->listSize * 4U;
1015             MCAN_SetFilterConfig(base, config->stdFilterCfg);
1016         }
1017         else
1018         {
1019             result = kStatus_Fail;
1020         }
1021     }
1022     if ((config->extFilterCfg != NULL) && (kStatus_Success == result))
1023     {
1024         if ((config->extFilterCfg->idFormat == kMCAN_FrameIDExtend) && (config->extFilterCfg->address >= temp) &&
1025             (0U == (config->extFilterCfg->address % 4U)))
1026         {
1027             temp = config->extFilterCfg->address + config->extFilterCfg->listSize * 8U;
1028             MCAN_SetFilterConfig(base, config->extFilterCfg);
1029         }
1030         else
1031         {
1032             result = kStatus_Fail;
1033         }
1034     }
1035     if ((config->rxFifo0Cfg != NULL) && (kStatus_Success == result))
1036     {
1037         eSize = ((uint32_t)config->rxFifo0Cfg->datafieldSize < 5U) ?
1038                     ((uint32_t)config->rxFifo0Cfg->datafieldSize + 4U) :
1039                     ((uint32_t)config->rxFifo0Cfg->datafieldSize * 4U - 10U);
1040         if ((config->rxFifo0Cfg->address >= temp) && (0U == (config->rxFifo0Cfg->address % 4U)))
1041         {
1042             temp = config->rxFifo0Cfg->address + config->rxFifo0Cfg->elementSize * eSize * 4U;
1043             MCAN_SetRxFifo0Config(base, config->rxFifo0Cfg);
1044         }
1045         else
1046         {
1047             result = kStatus_Fail;
1048         }
1049     }
1050     if ((config->rxFifo1Cfg != NULL) && (kStatus_Success == result))
1051     {
1052         eSize = ((uint32_t)config->rxFifo1Cfg->datafieldSize < 5U) ?
1053                     ((uint32_t)config->rxFifo1Cfg->datafieldSize + 4U) :
1054                     ((uint32_t)config->rxFifo1Cfg->datafieldSize * 4U - 10U);
1055         if ((config->rxFifo1Cfg->address >= temp) && (0U == (config->rxFifo1Cfg->address % 4U)))
1056         {
1057             temp = config->rxFifo1Cfg->address + config->rxFifo1Cfg->elementSize * eSize * 4U;
1058             MCAN_SetRxFifo1Config(base, config->rxFifo1Cfg);
1059         }
1060         else
1061         {
1062             result = kStatus_Fail;
1063         }
1064     }
1065     if ((config->rxBufferCfg != NULL) && (kStatus_Success == result))
1066     {
1067         eSize = ((uint32_t)config->rxBufferCfg->datafieldSize < 5U) ?
1068                     ((uint32_t)config->rxBufferCfg->datafieldSize + 4U) :
1069                     ((uint32_t)config->rxBufferCfg->datafieldSize * 4U - 10U);
1070         if ((config->rxBufferCfg->address >= temp) && (0U == (config->rxBufferCfg->address % 4U)))
1071         {
1072             temp = config->rxBufferCfg->address + 64U * eSize * 4U;
1073             MCAN_SetRxBufferConfig(base, config->rxBufferCfg);
1074         }
1075         else
1076         {
1077             result = kStatus_Fail;
1078         }
1079     }
1080     if ((config->txFifoCfg != NULL) && (kStatus_Success == result))
1081     {
1082         if ((config->txFifoCfg->address >= temp) && (0U == (config->txFifoCfg->address % 4U)))
1083         {
1084             temp = config->txFifoCfg->address + config->txFifoCfg->elementSize * 8U;
1085             MCAN_SetTxEventFifoConfig(base, config->txFifoCfg);
1086         }
1087         else
1088         {
1089             result = kStatus_Fail;
1090         }
1091     }
1092     if ((config->txBufferCfg != NULL) && (kStatus_Success == result))
1093     {
1094         if ((config->txBufferCfg->address < temp) || (0U != (config->txBufferCfg->address % 4U)))
1095         {
1096             result = kStatus_Fail;
1097         }
1098         else
1099         {
1100             MCAN_SetTxBufferConfig(base, config->txBufferCfg);
1101         }
1102     }
1103     MCAN_EnterNormalMode(base);
1104 
1105     return result;
1106 }
1107 
1108 /*!
1109  * brief Set standard message ID filter element configuration.
1110  *
1111  * param base MCAN peripheral base address.
1112  * param config The MCAN filter configuration.
1113  * param filter The MCAN standard message ID filter element configuration.
1114  * param idx The standard message ID filter element index.
1115  */
MCAN_SetSTDFilterElement(CAN_Type * base,const mcan_frame_filter_config_t * config,const mcan_std_filter_element_config_t * filter,uint8_t idx)1116 void MCAN_SetSTDFilterElement(CAN_Type *base,
1117                               const mcan_frame_filter_config_t *config,
1118                               const mcan_std_filter_element_config_t *filter,
1119                               uint8_t idx)
1120 {
1121     uint32_t *elementAddress = NULL;
1122     elementAddress           = (uint32_t *)(MCAN_GetMsgRAMBase(base) + config->address + idx * 4U);
1123     (void)memcpy((void *)elementAddress, (const void *)filter, sizeof(mcan_std_filter_element_config_t));
1124 }
1125 
1126 /*!
1127  * brief Set extended message ID filter element configuration.
1128  *
1129  * param base MCAN peripheral base address.
1130  * param config The MCAN filter configuration.
1131  * param filter The MCAN extended message ID filter element configuration.
1132  * param idx The extended message ID filter element index.
1133  */
MCAN_SetEXTFilterElement(CAN_Type * base,const mcan_frame_filter_config_t * config,const mcan_ext_filter_element_config_t * filter,uint8_t idx)1134 void MCAN_SetEXTFilterElement(CAN_Type *base,
1135                               const mcan_frame_filter_config_t *config,
1136                               const mcan_ext_filter_element_config_t *filter,
1137                               uint8_t idx)
1138 {
1139     uint32_t *elementAddress = NULL;
1140     elementAddress           = (uint32_t *)(MCAN_GetMsgRAMBase(base) + config->address + idx * 8U);
1141     (void)memcpy((void *)elementAddress, (const void *)filter, sizeof(mcan_ext_filter_element_config_t));
1142 }
1143 
MCAN_GetRxFifo0ElementAddress(CAN_Type * base)1144 static uint32_t MCAN_GetRxFifo0ElementAddress(CAN_Type *base)
1145 {
1146     uint32_t eSize;
1147     uint32_t eAddress;
1148     eSize = (base->RXESC & CAN_RXESC_F0DS_MASK) >> CAN_RXESC_F0DS_SHIFT;
1149     if (eSize < 5U)
1150     {
1151         eSize += 4U;
1152     }
1153     else
1154     {
1155         eSize = eSize * 4U - 10U;
1156     }
1157     eAddress = base->RXF0C & CAN_RXF0C_F0SA_MASK;
1158     eAddress += ((base->RXF0S & CAN_RXF0S_F0GI_MASK) >> CAN_RXF0S_F0GI_SHIFT) * eSize * 4U;
1159     return eAddress;
1160 }
1161 
MCAN_GetRxFifo1ElementAddress(CAN_Type * base)1162 static uint32_t MCAN_GetRxFifo1ElementAddress(CAN_Type *base)
1163 {
1164     uint32_t eSize;
1165     uint32_t eAddress;
1166     eSize = (base->RXESC & CAN_RXESC_F1DS_MASK) >> CAN_RXESC_F1DS_SHIFT;
1167     if (eSize < 5U)
1168     {
1169         eSize += 4U;
1170     }
1171     else
1172     {
1173         eSize = eSize * 4U - 10U;
1174     }
1175     eAddress = base->RXF1C & CAN_RXF1C_F1SA_MASK;
1176     eAddress += ((base->RXF1S & CAN_RXF1S_F1GI_MASK) >> CAN_RXF1S_F1GI_SHIFT) * eSize * 4U;
1177     return eAddress;
1178 }
1179 
MCAN_GetRxBufferElementAddress(CAN_Type * base,uint8_t idx)1180 static uint32_t MCAN_GetRxBufferElementAddress(CAN_Type *base, uint8_t idx)
1181 {
1182     assert(idx <= 63U);
1183     uint32_t eSize;
1184     eSize = (base->RXESC & CAN_RXESC_RBDS_MASK) >> CAN_RXESC_RBDS_SHIFT;
1185     if (eSize < 5U)
1186     {
1187         eSize += 4U;
1188     }
1189     else
1190     {
1191         eSize = eSize * 4U - 10U;
1192     }
1193     return (base->RXBC & CAN_RXBC_RBSA_MASK) + idx * eSize * 4U;
1194 }
1195 
MCAN_GetTxBufferElementAddress(CAN_Type * base,uint8_t idx)1196 static uint32_t MCAN_GetTxBufferElementAddress(CAN_Type *base, uint8_t idx)
1197 {
1198     assert(idx <= 31U);
1199     uint32_t eSize;
1200     eSize = (base->TXESC & CAN_TXESC_TBDS_MASK) >> CAN_TXESC_TBDS_SHIFT;
1201     if (eSize < 5U)
1202     {
1203         eSize += 4U;
1204     }
1205     else
1206     {
1207         eSize = eSize * 4U - 10U;
1208     }
1209     return (base->TXBC & CAN_TXBC_TBSA_MASK) + idx * eSize * 4U;
1210 }
1211 
1212 /*!
1213  * brief Gets the Tx buffer request pending status.
1214  *
1215  * This function returns Tx Message Buffer transmission request pending status.
1216  *
1217  * param base MCAN peripheral base address.
1218  * param idx The MCAN Tx Buffer index.
1219  */
MCAN_IsTransmitRequestPending(CAN_Type * base,uint8_t idx)1220 uint32_t MCAN_IsTransmitRequestPending(CAN_Type *base, uint8_t idx)
1221 {
1222     return (base->TXBRP & ((uint32_t)1U << idx)) >> (uint32_t)idx;
1223 }
1224 
1225 /*!
1226  * brief Gets the Tx buffer transmission occurred status.
1227  *
1228  * This function returns Tx Message Buffer transmission occurred status.
1229  *
1230  * param base MCAN peripheral base address.
1231  * param idx The MCAN Tx Buffer index.
1232  */
MCAN_IsTransmitOccurred(CAN_Type * base,uint8_t idx)1233 uint32_t MCAN_IsTransmitOccurred(CAN_Type *base, uint8_t idx)
1234 {
1235     return (base->TXBTO & ((uint32_t)1U << idx)) >> (uint32_t)idx;
1236 }
1237 
1238 /*!
1239  * brief Writes an MCAN Message to the Transmit Buffer.
1240  *
1241  * This function writes a CAN Message to the specified Transmit Message Buffer
1242  * and changes the Message Buffer state to start CAN Message transmit. After
1243  * that the function returns immediately.
1244  *
1245  * param base MCAN peripheral base address.
1246  * param idx The MCAN Tx Buffer index.
1247  * param pTxFrame Pointer to CAN message frame to be sent.
1248  */
MCAN_WriteTxBuffer(CAN_Type * base,uint8_t idx,const mcan_tx_buffer_frame_t * pTxFrame)1249 status_t MCAN_WriteTxBuffer(CAN_Type *base, uint8_t idx, const mcan_tx_buffer_frame_t *pTxFrame)
1250 {
1251     /* Assertion. */
1252     assert(NULL != pTxFrame);
1253 
1254     status_t status;
1255     uint8_t *elementAddress        = NULL;
1256     uint8_t *elementPayloadAddress = NULL;
1257 
1258     if (0U == MCAN_IsTransmitRequestPending(base, idx))
1259     {
1260         elementAddress        = (uint8_t *)(MCAN_GetMsgRAMBase(base) + MCAN_GetTxBufferElementAddress(base, idx));
1261         elementPayloadAddress = (uint8_t *)((uint32_t)elementAddress + 8U);
1262 
1263         /* Write 2 words configuration field. */
1264         (void)memcpy(elementAddress, (const uint8_t *)pTxFrame, 8U);
1265         /* Write data field. */
1266         (void)memcpy(elementPayloadAddress, pTxFrame->data, pTxFrame->size);
1267         status = kStatus_Success;
1268     }
1269     else
1270     {
1271         status = kStatus_Fail;
1272     }
1273 
1274     return status;
1275 }
1276 
1277 /*!
1278  * brief Reads an MCAN Message from Rx Buffer.
1279  *
1280  * This function reads a CAN message from the Rx Buffer in the Message RAM.
1281  *
1282  * param base MCAN peripheral base address.
1283  * param idx The MCAN Rx Buffer index.
1284  * param pRxFrame Pointer to CAN message frame structure for reception.
1285  * retval kStatus_Success - Read Message from Rx Buffer successfully.
1286  */
MCAN_ReadRxBuffer(CAN_Type * base,uint8_t idx,mcan_rx_buffer_frame_t * pRxFrame)1287 status_t MCAN_ReadRxBuffer(CAN_Type *base, uint8_t idx, mcan_rx_buffer_frame_t *pRxFrame)
1288 {
1289     /* Assertion. */
1290     assert(NULL != pRxFrame);
1291 
1292     mcan_rx_buffer_frame_t *elementAddress = NULL;
1293     uint32_t u4PayloadLength               = (uint32_t)(pRxFrame->size) + 8U;
1294 
1295     elementAddress = (mcan_rx_buffer_frame_t *)(MCAN_GetMsgRAMBase(base) + MCAN_GetRxBufferElementAddress(base, idx));
1296     (void)memcpy((void *)pRxFrame, (void *)elementAddress, u4PayloadLength);
1297 
1298     return kStatus_Success;
1299 }
1300 
1301 /*!
1302  * brief Reads an MCAN Message from Rx FIFO.
1303  *
1304  * This function reads a CAN message from the Rx FIFO in the Message RAM.
1305  *
1306  * param base MCAN peripheral base address.
1307  * param fifoBlock Rx FIFO block 0 or 1.
1308  * param pRxFrame Pointer to CAN message frame structure for reception.
1309  * retval kStatus_Success - Read Message from Rx FIFO successfully.
1310  */
MCAN_ReadRxFifo(CAN_Type * base,uint8_t fifoBlock,mcan_rx_buffer_frame_t * pRxFrame)1311 status_t MCAN_ReadRxFifo(CAN_Type *base, uint8_t fifoBlock, mcan_rx_buffer_frame_t *pRxFrame)
1312 {
1313     /* Assertion. */
1314     assert((0U == fifoBlock) || (1U == fifoBlock));
1315     assert(NULL != pRxFrame);
1316 
1317     mcan_rx_buffer_frame_t *elementAddress = NULL;
1318 
1319     if (0U == fifoBlock)
1320     {
1321         if ((base->RXF0S & CAN_RXF0S_F0FL_MASK) != 0U)
1322         {
1323             elementAddress = (mcan_rx_buffer_frame_t *)(MCAN_GetMsgRAMBase(base) + MCAN_GetRxFifo0ElementAddress(base));
1324         }
1325         else
1326         {
1327             return kStatus_Fail;
1328         }
1329     }
1330     else
1331     {
1332         if ((base->RXF1S & CAN_RXF1S_F1FL_MASK) != 0U)
1333         {
1334             elementAddress = (mcan_rx_buffer_frame_t *)(MCAN_GetMsgRAMBase(base) + MCAN_GetRxFifo1ElementAddress(base));
1335         }
1336         else
1337         {
1338             return kStatus_Fail;
1339         }
1340     }
1341     (void)memcpy(pRxFrame, elementAddress, 8U);
1342     pRxFrame->data = (uint8_t *)((uint32_t)elementAddress + 8U);
1343     /* Acknowledge the read. */
1344     if (0U == fifoBlock)
1345     {
1346         base->RXF0A = (base->RXF0S & CAN_RXF0S_F0GI_MASK) >> CAN_RXF0S_F0GI_SHIFT;
1347     }
1348     else
1349     {
1350         base->RXF1A = (base->RXF1S & CAN_RXF1S_F1GI_MASK) >> CAN_RXF1S_F1GI_SHIFT;
1351     }
1352     return kStatus_Success;
1353 }
1354 
1355 /*!
1356  * brief Performs a polling send transaction on the CAN bus.
1357  *
1358  * Note that a transfer handle does not need to be created  before calling this API.
1359  *
1360  * param base MCAN peripheral base pointer.
1361  * param idx The MCAN buffer index.
1362  * param pTxFrame Pointer to CAN message frame to be sent.
1363  * retval kStatus_Success - Write Tx Message Buffer Successfully.
1364  * retval kStatus_Fail    - Tx Message Buffer is currently in use.
1365  */
MCAN_TransferSendBlocking(CAN_Type * base,uint8_t idx,mcan_tx_buffer_frame_t * pTxFrame)1366 status_t MCAN_TransferSendBlocking(CAN_Type *base, uint8_t idx, mcan_tx_buffer_frame_t *pTxFrame)
1367 {
1368     status_t status;
1369 
1370     if (kStatus_Success == MCAN_WriteTxBuffer(base, idx, pTxFrame))
1371     {
1372         MCAN_TransmitAddRequest(base, idx);
1373 
1374         /* Wait until message sent out. */
1375         while (0U == MCAN_IsTransmitOccurred(base, idx))
1376         {
1377         }
1378         status = kStatus_Success;
1379     }
1380     else
1381     {
1382         status = kStatus_Fail;
1383     }
1384 
1385     return status;
1386 }
1387 
1388 /*!
1389  * brief Performs a polling receive transaction on the CAN bus.
1390  *
1391  * Note that a transfer handle does not need to be created  before calling this API.
1392  *
1393  * param base MCAN peripheral base pointer.
1394  * param idx The MCAN buffer index.
1395  * param pRxFrame Pointer to CAN message frame structure for reception.
1396  * retval kStatus_Success - Read Rx Message Buffer Successfully.
1397  * retval kStatus_Fail    - No new message.
1398  */
MCAN_TransferReceiveBlocking(CAN_Type * base,uint8_t idx,mcan_rx_buffer_frame_t * pRxFrame)1399 status_t MCAN_TransferReceiveBlocking(CAN_Type *base, uint8_t idx, mcan_rx_buffer_frame_t *pRxFrame)
1400 {
1401     assert(idx <= 63U);
1402 
1403     status_t status = kStatus_Success;
1404 
1405 #if (defined(MCAN_RETRY_TIMES) && MCAN_RETRY_TIMES)
1406     uint32_t u4Retry = MCAN_RETRY_TIMES;
1407 #endif
1408 
1409     while (!MCAN_GetRxBufferStatusFlag(base, idx))
1410     {
1411 #if (defined(MCAN_RETRY_TIMES) && MCAN_RETRY_TIMES)
1412         if (0U == u4Retry--)
1413         {
1414             status = kStatus_Fail;
1415         }
1416 #endif
1417     }
1418 #if (defined(MCAN_RETRY_TIMES) && MCAN_RETRY_TIMES)
1419     if (kStatus_Success == status)
1420 #endif
1421     {
1422         MCAN_ClearRxBufferStatusFlag(base, idx);
1423         status = MCAN_ReadRxBuffer(base, idx, pRxFrame);
1424     }
1425 
1426     return status;
1427 }
1428 
1429 /*!
1430  * brief Performs a polling receive transaction from Rx FIFO on the CAN bus.
1431  *
1432  * Note that a transfer handle does not need to be created before calling this API.
1433  *
1434  * param base MCAN peripheral base pointer.
1435  * param fifoBlock Rx FIFO block, 0 or 1.
1436  * param pRxFrame Pointer to CAN message frame structure for reception.
1437  * retval kStatus_Success - Read Message from Rx FIFO successfully.
1438  * retval kStatus_Fail    - No new message in Rx FIFO.
1439  */
MCAN_TransferReceiveFifoBlocking(CAN_Type * base,uint8_t fifoBlock,mcan_rx_buffer_frame_t * pRxFrame)1440 status_t MCAN_TransferReceiveFifoBlocking(CAN_Type *base, uint8_t fifoBlock, mcan_rx_buffer_frame_t *pRxFrame)
1441 {
1442     assert((0U == fifoBlock) || (1U == fifoBlock));
1443 
1444     status_t status = kStatus_Success;
1445     uint32_t maskCanIR;
1446 #if (defined(MCAN_RETRY_TIMES) && MCAN_RETRY_TIMES)
1447     uint32_t u4Retry = MCAN_RETRY_TIMES;
1448 #endif
1449 
1450     maskCanIR = (0U == fifoBlock) ? CAN_IR_RF0N_MASK : CAN_IR_RF1N_MASK;
1451 
1452     while (0U == MCAN_GetStatusFlag(base, maskCanIR))
1453     {
1454 #if (defined(MCAN_RETRY_TIMES) && MCAN_RETRY_TIMES)
1455         if (0U == u4Retry--)
1456         {
1457             status = kStatus_Fail;
1458         }
1459 #endif
1460     }
1461 
1462 #if (defined(MCAN_RETRY_TIMES) && MCAN_RETRY_TIMES)
1463     if (kStatus_Success == status)
1464 #endif
1465     {
1466         MCAN_ClearStatusFlag(base, maskCanIR);
1467         status = MCAN_ReadRxFifo(base, fifoBlock, pRxFrame);
1468     }
1469 
1470     return status;
1471 }
1472 
1473 /*!
1474  * brief Initializes the MCAN handle.
1475  *
1476  * This function initializes the MCAN handle, which can be used for other MCAN
1477  * transactional APIs. Usually, for a specified MCAN instance,
1478  * call this API once to get the initialized handle.
1479  *
1480  * param base MCAN peripheral base address.
1481  * param handle MCAN handle pointer.
1482  * param callback The callback function.
1483  * param userData The parameter of the callback function.
1484  */
MCAN_TransferCreateHandle(CAN_Type * base,mcan_handle_t * handle,mcan_transfer_callback_t callback,void * userData)1485 void MCAN_TransferCreateHandle(CAN_Type *base, mcan_handle_t *handle, mcan_transfer_callback_t callback, void *userData)
1486 {
1487     assert(NULL != handle);
1488 
1489     uint8_t instance;
1490 
1491     /* Clean MCAN transfer handle. */
1492     (void)memset(handle, 0, sizeof(*handle));
1493 
1494     /* Get instance from peripheral base address. */
1495     instance = (uint8_t)MCAN_GetInstance(base);
1496 
1497     /* Save the context in global variables to support the double weak mechanism. */
1498     s_mcanHandle[instance] = handle;
1499 
1500     /* Register Callback function. */
1501     handle->callback = callback;
1502     handle->userData = userData;
1503 
1504     s_mcanIsr = MCAN_TransferHandleIRQ;
1505 
1506     /* We Enable Error & Status interrupt here, because this interrupt just
1507      * report current status of MCAN module through Callback function.
1508      * It is insignificance without a available callback function.
1509      */
1510     if (handle->callback != NULL)
1511     {
1512         MCAN_EnableInterrupts(base, 0U,
1513                               (uint32_t)kMCAN_BusOffInterruptEnable | (uint32_t)kMCAN_ErrorInterruptEnable |
1514                                   (uint32_t)kMCAN_WarningInterruptEnable);
1515     }
1516     else
1517     {
1518         MCAN_DisableInterrupts(base, (uint32_t)kMCAN_BusOffInterruptEnable | (uint32_t)kMCAN_ErrorInterruptEnable |
1519                                          (uint32_t)kMCAN_WarningInterruptEnable);
1520     }
1521 
1522     /* Enable interrupts in NVIC. */
1523     (void)EnableIRQ((IRQn_Type)(s_mcanIRQ[instance][0]));
1524     (void)EnableIRQ((IRQn_Type)(s_mcanIRQ[instance][1]));
1525 }
1526 
1527 /*!
1528  * brief Sends a message using IRQ.
1529  *
1530  * This function sends a message using IRQ. This is a non-blocking function, which returns
1531  * right away. When messages have been sent out, the send callback function is called.
1532  *
1533  * param base MCAN peripheral base address.
1534  * param handle MCAN handle pointer.
1535  * param xfer MCAN Buffer transfer structure. See the #mcan_buffer_transfer_t.
1536  * retval kStatus_Success        Start Tx Buffer sending process successfully.
1537  * retval kStatus_Fail           Write Tx Buffer failed.
1538  * retval kStatus_MCAN_TxBusy Tx Buffer is in use.
1539  */
MCAN_TransferSendNonBlocking(CAN_Type * base,mcan_handle_t * handle,mcan_buffer_transfer_t * xfer)1540 status_t MCAN_TransferSendNonBlocking(CAN_Type *base, mcan_handle_t *handle, mcan_buffer_transfer_t *xfer)
1541 {
1542     /* Assertion. */
1543     assert(NULL != handle);
1544     assert(NULL != xfer);
1545     assert(xfer->bufferIdx <= 63U);
1546 
1547     status_t status;
1548 
1549     /* Check if Tx Buffer is idle. */
1550     if ((uint8_t)kMCAN_StateIdle == handle->bufferState[xfer->bufferIdx])
1551     {
1552         /* Distinguish transmit type. */
1553         if ((uint8_t)kMCAN_FrameTypeRemote == xfer->frame->rtr)
1554         {
1555             handle->bufferState[xfer->bufferIdx] = (uint8_t)kMCAN_StateTxRemote;
1556 
1557             /* Register user Frame buffer to receive remote Frame. */
1558             handle->bufferFrameBuf[xfer->bufferIdx] = xfer->frame;
1559         }
1560         else
1561         {
1562             handle->bufferState[xfer->bufferIdx] = (uint8_t)kMCAN_StateTxData;
1563         }
1564 
1565         if (kStatus_Success == MCAN_WriteTxBuffer(base, xfer->bufferIdx, xfer->frame))
1566         {
1567             /* Enable Buffer Interrupt. */
1568             MCAN_EnableTransmitBufferInterrupts(base, xfer->bufferIdx);
1569             MCAN_EnableInterrupts(base, 0U, CAN_IE_TCE_MASK);
1570 
1571             MCAN_TransmitAddRequest(base, xfer->bufferIdx);
1572 
1573             status = kStatus_Success;
1574         }
1575         else
1576         {
1577             handle->bufferState[xfer->bufferIdx] = (uint8_t)kMCAN_StateIdle;
1578             status                               = kStatus_Fail;
1579         }
1580     }
1581     else
1582     {
1583         status = kStatus_MCAN_TxBusy;
1584     }
1585 
1586     return status;
1587 }
1588 
1589 /*!
1590  * brief Receives a message from Rx FIFO using IRQ.
1591  *
1592  * This function receives a message using IRQ. This is a non-blocking function, which returns
1593  * right away. When all messages have been received, the receive callback function is called.
1594  *
1595  * param base MCAN peripheral base address.
1596  * param handle MCAN handle pointer.
1597  * param fifoBlock Rx FIFO block, 0 or 1.
1598  * param xfer MCAN Rx FIFO transfer structure. See the ref mcan_fifo_transfer_t.
1599  * retval kStatus_Success            - Start Rx FIFO receiving process successfully.
1600  * retval kStatus_MCAN_RxFifo0Busy - Rx FIFO 0 is currently in use.
1601  * retval kStatus_MCAN_RxFifo1Busy - Rx FIFO 1 is currently in use.
1602  */
MCAN_TransferReceiveFifoNonBlocking(CAN_Type * base,uint8_t fifoBlock,mcan_handle_t * handle,mcan_fifo_transfer_t * xfer)1603 status_t MCAN_TransferReceiveFifoNonBlocking(CAN_Type *base,
1604                                              uint8_t fifoBlock,
1605                                              mcan_handle_t *handle,
1606                                              mcan_fifo_transfer_t *xfer)
1607 {
1608     /* Assertion. */
1609     assert((0U == fifoBlock) || (1U == fifoBlock));
1610     assert(NULL != handle);
1611     assert(NULL != xfer);
1612 
1613     status_t status;
1614 
1615     /* Check if Message Buffer is idle. */
1616     if ((uint8_t)kMCAN_StateIdle == handle->rxFifoState)
1617     {
1618         handle->rxFifoState = (uint8_t)kMCAN_StateRxFifo;
1619 
1620         /* Register Message Buffer. */
1621         handle->rxFifoFrameBuf = xfer->frame;
1622 
1623         /* Enable FIFO Interrupt. */
1624         if (1U == fifoBlock)
1625         {
1626             MCAN_EnableInterrupts(base, 0U, CAN_IE_RF1NE_MASK);
1627         }
1628         else
1629         {
1630             MCAN_EnableInterrupts(base, 0U, CAN_IE_RF0NE_MASK);
1631         }
1632         status = kStatus_Success;
1633     }
1634     else
1635     {
1636         status = (1U == fifoBlock) ? kStatus_MCAN_RxFifo1Busy : kStatus_MCAN_RxFifo0Busy;
1637     }
1638 
1639     return status;
1640 }
1641 
1642 /*!
1643  * brief Aborts the interrupt driven message send process.
1644  *
1645  * This function aborts the interrupt driven message send process.
1646  *
1647  * param base MCAN peripheral base address.
1648  * param handle MCAN handle pointer.
1649  * param bufferIdx The MCAN Buffer index.
1650  */
MCAN_TransferAbortSend(CAN_Type * base,mcan_handle_t * handle,uint8_t bufferIdx)1651 void MCAN_TransferAbortSend(CAN_Type *base, mcan_handle_t *handle, uint8_t bufferIdx)
1652 {
1653     /* Assertion. */
1654     assert(NULL != handle);
1655     assert(bufferIdx <= 63U);
1656 
1657     /* Disable Message Buffer Interrupt. */
1658     MCAN_DisableTransmitBufferInterrupts(base, bufferIdx);
1659 
1660     /* Cancel send request. */
1661     MCAN_TransmitCancelRequest(base, bufferIdx);
1662 
1663     /* Un-register handle. */
1664     handle->bufferFrameBuf[bufferIdx] = NULL;
1665 
1666     handle->bufferState[bufferIdx] = (uint8_t)kMCAN_StateIdle;
1667 }
1668 
1669 /*!
1670  * brief Aborts the interrupt driven message receive from Rx FIFO process.
1671  *
1672  * This function aborts the interrupt driven message receive from Rx FIFO process.
1673  *
1674  * param base MCAN peripheral base address.
1675  * param fifoBlock MCAN Fifo block, 0 or 1.
1676  * param handle MCAN handle pointer.
1677  */
MCAN_TransferAbortReceiveFifo(CAN_Type * base,uint8_t fifoBlock,mcan_handle_t * handle)1678 void MCAN_TransferAbortReceiveFifo(CAN_Type *base, uint8_t fifoBlock, mcan_handle_t *handle)
1679 {
1680     /* Assertion. */
1681     assert(NULL != handle);
1682     assert((0U == fifoBlock) || (1U == fifoBlock));
1683 
1684     /* Check if Rx FIFO is enabled. */
1685     if (1U == fifoBlock)
1686     {
1687         /* Disable Rx Message FIFO Interrupts. */
1688         MCAN_DisableInterrupts(base, CAN_IE_RF1NE_MASK);
1689     }
1690     else
1691     {
1692         MCAN_DisableInterrupts(base, CAN_IE_RF0NE_MASK);
1693     }
1694     /* Un-register handle. */
1695     handle->rxFifoFrameBuf = NULL;
1696 
1697     handle->rxFifoState = (uint8_t)kMCAN_StateIdle;
1698 }
1699 
1700 /*!
1701  * brief MCAN IRQ handle function.
1702  *
1703  * This function handles the MCAN Error, the Buffer, and the Rx FIFO IRQ request.
1704  *
1705  * param base MCAN peripheral base address.
1706  * param handle MCAN handle pointer.
1707  */
MCAN_TransferHandleIRQ(CAN_Type * base,mcan_handle_t * handle)1708 void MCAN_TransferHandleIRQ(CAN_Type *base, mcan_handle_t *handle)
1709 {
1710     /* Assertion. */
1711     assert(NULL != handle);
1712 
1713     status_t status = kStatus_MCAN_UnHandled;
1714     uint32_t valueIR;
1715     uint32_t result;
1716 
1717     /* Store Current MCAN Module Error and Status. */
1718     valueIR = base->IR;
1719 
1720     do
1721     {
1722         if (0U != (valueIR & ((uint32_t)kMCAN_ErrorWarningIntFlag | (uint32_t)kMCAN_ErrorPassiveIntFlag |
1723                               (uint32_t)kMCAN_BusOffIntFlag)))
1724         {
1725             /* Solve error. */
1726             result = (valueIR & ((uint32_t)kMCAN_ErrorWarningIntFlag | (uint32_t)kMCAN_ErrorPassiveIntFlag |
1727                                  (uint32_t)kMCAN_BusOffIntFlag));
1728             status = kStatus_MCAN_ErrorStatus;
1729         }
1730         else if (0U != (valueIR & (uint32_t)kMCAN_TxTransmitCompleteFlag))
1731         {
1732             /* Solve Tx interrupt. */
1733             uint8_t idx = 0U;
1734             for (; idx < (uint8_t)((base->TXBC & CAN_TXBC_NDTB_MASK) >> CAN_TXBC_NDTB_SHIFT); idx++)
1735             {
1736                 /* Get the lowest unhandled Tx Message Buffer */
1737                 if (0U != MCAN_IsTransmitOccurred(base, idx))
1738                 {
1739                     if ((base->TXBTIE & ((uint32_t)1U << idx)) != 0U)
1740                     {
1741                         MCAN_TransferAbortSend(base, handle, idx);
1742                     }
1743                 }
1744             }
1745             result = (uint32_t)kMCAN_TxTransmitCompleteFlag;
1746             status = kStatus_MCAN_TxIdle;
1747         }
1748         else if (0U != (valueIR & (uint32_t)kMCAN_RxFifo0NewFlag))
1749         {
1750             (void)MCAN_ReadRxFifo(base, 0U, handle->rxFifoFrameBuf);
1751             result = (uint32_t)kMCAN_RxFifo0NewFlag;
1752             status = kStatus_MCAN_RxFifo0Idle;
1753             MCAN_TransferAbortReceiveFifo(base, 0U, handle);
1754         }
1755         else if (0U != (valueIR & (uint32_t)kMCAN_RxFifo0LostFlag))
1756         {
1757             result = (uint32_t)kMCAN_RxFifo0LostFlag;
1758             status = kStatus_MCAN_RxFifo0Lost;
1759         }
1760         else if (0U != (valueIR & (uint32_t)kMCAN_RxFifo1NewFlag))
1761         {
1762             (void)MCAN_ReadRxFifo(base, 1U, handle->rxFifoFrameBuf);
1763             result = (uint32_t)kMCAN_RxFifo1NewFlag;
1764             status = kStatus_MCAN_RxFifo1Idle;
1765             MCAN_TransferAbortReceiveFifo(base, 1U, handle);
1766         }
1767         else if (0U != (valueIR & (uint32_t)kMCAN_RxFifo1LostFlag))
1768         {
1769             result = (uint32_t)kMCAN_RxFifo1LostFlag;
1770             status = kStatus_MCAN_RxFifo1Lost;
1771         }
1772         else
1773         {
1774             /* Handle the interrupt flag unsupported in current version of MCAN driver.
1775              * User can get these unsupported interrupt flags by callback function,
1776              * we can clear directly in the handler to prevent endless loop.
1777              */
1778             result = valueIR;
1779             result &= ~((uint32_t)kMCAN_ErrorWarningIntFlag | (uint32_t)kMCAN_ErrorPassiveIntFlag |
1780                         (uint32_t)kMCAN_BusOffIntFlag | (uint32_t)kMCAN_TxTransmitCompleteFlag |
1781                         (uint32_t)kMCAN_RxFifo0NewFlag | (uint32_t)kMCAN_RxFifo0LostFlag |
1782                         (uint32_t)kMCAN_RxFifo1NewFlag | (uint32_t)kMCAN_RxFifo1LostFlag);
1783         }
1784 
1785         /* Clear Error interrupt, resolved Rx FIFO, Tx Buffer IRQ and other unsupported interrupt flags. */
1786         MCAN_ClearStatusFlag(base, result);
1787 
1788         /* Calling Callback Function if has one. */
1789         if (handle->callback != NULL)
1790         {
1791             handle->callback(base, handle, status, result, handle->userData);
1792         }
1793 
1794         /* Reset return status */
1795         status = kStatus_MCAN_UnHandled;
1796 
1797         /* Store Current MCAN Module Error and Status. */
1798         valueIR = base->IR;
1799     } while (0U != valueIR);
1800 }
1801 
1802 #if defined(CAN0)
1803 void CAN0_IRQ0_DriverIRQHandler(void);
CAN0_IRQ0_DriverIRQHandler(void)1804 void CAN0_IRQ0_DriverIRQHandler(void)
1805 {
1806     assert(NULL != s_mcanHandle[0]);
1807 
1808     s_mcanIsr(CAN0, s_mcanHandle[0]);
1809     SDK_ISR_EXIT_BARRIER;
1810 }
1811 
1812 void CAN0_IRQ1_DriverIRQHandler(void);
CAN0_IRQ1_DriverIRQHandler(void)1813 void CAN0_IRQ1_DriverIRQHandler(void)
1814 {
1815     assert(NULL != s_mcanHandle[0]);
1816 
1817     s_mcanIsr(CAN0, s_mcanHandle[0]);
1818     SDK_ISR_EXIT_BARRIER;
1819 }
1820 #endif
1821 
1822 #if defined(CAN1)
1823 void CAN1_IRQ0_DriverIRQHandler(void);
CAN1_IRQ0_DriverIRQHandler(void)1824 void CAN1_IRQ0_DriverIRQHandler(void)
1825 {
1826     assert(NULL != s_mcanHandle[1]);
1827 
1828     s_mcanIsr(CAN1, s_mcanHandle[1]);
1829     SDK_ISR_EXIT_BARRIER;
1830 }
1831 
1832 void CAN1_IRQ1_DriverIRQHandler(void);
CAN1_IRQ1_DriverIRQHandler(void)1833 void CAN1_IRQ1_DriverIRQHandler(void)
1834 {
1835     assert(NULL != s_mcanHandle[1]);
1836 
1837     s_mcanIsr(CAN1, s_mcanHandle[1]);
1838     SDK_ISR_EXIT_BARRIER;
1839 }
1840 #endif
1841