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