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