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