1 /*
2 * Copyright 2017-2020, 2023 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_mscan.h"
9
10 /*******************************************************************************
11 * Definitions
12 ******************************************************************************/
13
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.mscan"
17 #endif
18
19 #define MSCAN_TIME_QUANTA_NUM (8)
20
21 #if (defined(FSL_FEATURE_FLEXCAN_HAS_IMPROVED_TIMING_CONFIG) && FSL_FEATURE_FLEXCAN_HAS_IMPROVED_TIMING_CONFIG)
22 #define MAX_SAMP (MSCAN_CANBTR1_SAMP_MASK >> MSCAN_CANBTR1_SAMP_SHIFT)
23 #define MAX_SJW (MSCAN_CANBTR0_SJW_MASK >> MSCAN_CANBTR0_SJW_SHIFT)
24 #define MAX_BRP (MSCAN_CANBTR0_BRP_MASK >> MSCAN_CANBTR0_BRP_SHIFT)
25
26 #define MAX_TSEG1 (MSCAN_CANBTR1_TSEG1_MASK >> MSCAN_CANBTR1_TSEG1_SHIFT)
27 #define MIN_TSEG1 (3U)
28 #define MAX_TSEG2 (MSCAN_CANBTR1_TSEG2_MASK >> MSCAN_CANBTR1_TSEG2_SHIFT)
29 #define MIN_TSEG2 (1U)
30
31 /* MsCAN timing setting formula:
32 * MSCAN_TIME_QUANTA_NUM = 1 + (TSEG1 + 1) + (TSEG2 + 1);
33 */
34 #define MSCAN_MAX_TIME_QUANTA (1U + MAX_TSEG1 + 1U + MAX_TSEG2 + 1U)
35 #define MSCAN_MIN_TIME_QUANTA (1U + MIN_TSEG1 + 1U + MIN_TSEG2 + 1U)
36
37 #define IDEAL_SP_LOW (750U)
38 #define IDEAL_SP_MID (800U)
39 #define IDEAL_SP_HIGH (875U)
40 #define IDEAL_SP_FACTOR (1000U)
41 #define MAX_CAN_BAUDRATE (1000000U)
42 #endif
43
44 /* Max length of data length. */
45 #define MSCAN_DLC_MAX (8U)
46
47 /*! @brief MSCAN Internal State. */
48 enum _mscan_state
49 {
50 kMSCAN_StateIdle = 0x0, /*!< MB/RxFIFO idle.*/
51 kMSCAN_StateRxData = 0x1, /*!< MB receiving.*/
52 kMSCAN_StateRxRemote = 0x2, /*!< MB receiving remote reply.*/
53 kMSCAN_StateTxData = 0x3, /*!< MB transmitting.*/
54 kMSCAN_StateTxRemote = 0x4, /*!< MB transmitting remote request.*/
55 kMSCAN_StateRxFifo = 0x5, /*!< RxFIFO receiving.*/
56 };
57
58 /*! @brief MSCAN message buffer CODE for Rx buffers. */
59 enum _mscan_mb_code_rx
60 {
61 kMSCAN_RxMbInactive = 0x0, /*!< MB is not active.*/
62 kMSCAN_RxMbFull = 0x2, /*!< MB is full.*/
63 kMSCAN_RxMbEmpty = 0x4, /*!< MB is active and empty.*/
64 kMSCAN_RxMbOverrun = 0x6, /*!< MB is overwritten into a full buffer.*/
65 kMSCAN_RxMbBusy = 0x8, /*!< FlexCAN is updating the contents of the MB.*/
66 /*! The CPU must not access the MB.*/
67 kMSCAN_RxMbRanswer = 0xA, /*!< A frame was configured to recognize a Remote Request Frame */
68 /*! and transmit a Response Frame in return.*/
69 kMSCAN_RxMbNotUsed = 0xF, /*!< Not used.*/
70 };
71
72 /*! @brief FlexCAN message buffer CODE FOR Tx buffers. */
73 enum _mscan_mb_code_tx
74 {
75 kFLEXCAN_TxMbInactive = 0x8, /*!< MB is not active.*/
76 kFLEXCAN_TxMbAbort = 0x9, /*!< MB is aborted.*/
77 kFLEXCAN_TxMbDataOrRemote = 0xC, /*!< MB is a TX Data Frame(when MB RTR = 0) or */
78 /*!< MB is a TX Remote Request Frame (when MB RTR = 1).*/
79 kFLEXCAN_TxMbTanswer = 0xE, /*!< MB is a TX Response Request Frame from */
80 /*! an incoming Remote Request Frame.*/
81 kFLEXCAN_TxMbNotUsed = 0xF, /*!< Not used.*/
82 };
83
84 /* Typedef for interrupt handler. */
85 typedef void (*mscan_isr_t)(MSCAN_Type *base, mscan_handle_t *handle);
86
87 /*******************************************************************************
88 * Prototypes
89 ******************************************************************************/
90
91 /*!
92 * @brief Get the MsCAN instance from peripheral base address.
93 *
94 * @param base MsCAN peripheral base address.
95 * @return MsCAN instance.
96 */
97 static uint32_t MSCAN_GetInstance(MSCAN_Type *base);
98
99 /*!
100 * @brief Enter MsCAN Initial Mode.
101 *
102 * This function makes the MsCAN work under Initial Mode.
103 *
104 * @param base MsCAN peripheral base address.
105 */
106 static void MSCAN_EnterInitMode(MSCAN_Type *base);
107
108 /*!
109 * @brief Exit MsCAN Initial Mode.
110 *
111 * This function makes the MsCAN leave Initial Mode.
112 *
113 * @param base MsCAN peripheral base address.
114 */
115 static void MSCAN_ExitInitMode(MSCAN_Type *base);
116
117 /*!
118 * @brief Set Baud Rate of MsCAN.
119 *
120 * This function set the baud rate of MsCAN.
121 *
122 * @param base MsCAN peripheral base address.
123 * @param sourceClock_Hz Source Clock in Hz.
124 * @param baudRate_Bps Baud Rate in Bps.
125 */
126 static void MSCAN_SetBaudRate(MSCAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Bps);
127
128 #if (defined(FSL_FEATURE_FLEXCAN_HAS_IMPROVED_TIMING_CONFIG) && FSL_FEATURE_FLEXCAN_HAS_IMPROVED_TIMING_CONFIG)
129 /*!
130 * @brief Calculates the segment values for a single bit time for classical MSCAN
131 *
132 * @param baudRate The data speed in bps
133 * @param tqNum Number of time quantas per bit
134 * @param pconfig Pointer to the FlexCAN timing configuration structure.
135 *
136 * @return TRUE if valid Segments found, FALSE if failed to get valid segments
137 */
138 static bool MSCAN_GetSegments(uint32_t baudRate, uint32_t tqNum, mscan_timing_config_t *pconfig);
139
140 /*!
141 * @brief Calculates the improved timing values by specific baudrates for classical MSCAN
142 *
143 * @param baudRate The classical MSCAN speed in bps defined by user
144 * @param sourceClock_Hz The Source clock data speed in bps. Zero to disable baudrate switching
145 * @param pconfig Pointer to the MSCAN timing configuration structure.
146 *
147 * @return TRUE if timing configuration found, FALSE if failed to find configuration
148 */
149 static bool MSCAN_CalculateImprovedTimingValues(uint32_t baudRate,
150 uint32_t sourceClock_Hz,
151 mscan_timing_config_t *pconfig);
152 #endif
153
154 /*******************************************************************************
155 * Variables
156 ******************************************************************************/
157
158 /* Array of MsCAN peripheral base address. */
159 static MSCAN_Type *const s_mscanBases[] = MSCAN_BASE_PTRS;
160
161 /* Array of MSCAN IRQ number. */
162 static const IRQn_Type s_mscanRxWarningIRQ[] = MSCAN_RX_IRQS;
163 static const IRQn_Type s_mscanTxWarningIRQ[] = MSCAN_TX_IRQS;
164 static const IRQn_Type s_mscanWakeUpIRQ[] = MSCAN_WAKE_UP_IRQS;
165 static const IRQn_Type s_mscanErrorIRQ[] = MSCAN_ERR_IRQS;
166
167 /* Array of MsCAN handle. */
168 static mscan_handle_t *s_mscanHandle[ARRAY_SIZE(s_mscanBases)];
169
170 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
171 /* Array of MsCAN clock name. */
172 static const clock_ip_name_t s_mscanClock[] = MSCAN_CLOCKS;
173 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
174
175 /* MsCAN ISR for transactional APIs. */
176 #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
177 static mscan_isr_t s_mscanIsr = (mscan_isr_t)DefaultISR;
178 #else
179 static mscan_isr_t s_mscanIsr;
180 #endif
181
182 /*******************************************************************************
183 * Code
184 ******************************************************************************/
185
MSCAN_GetInstance(MSCAN_Type * base)186 static uint32_t MSCAN_GetInstance(MSCAN_Type *base)
187 {
188 uint32_t instance;
189
190 /* Find the instance index from base address mappings. */
191 for (instance = 0; instance < ARRAY_SIZE(s_mscanBases); instance++)
192 {
193 if (s_mscanBases[instance] == base)
194 {
195 break;
196 }
197 }
198
199 assert(instance < ARRAY_SIZE(s_mscanBases));
200
201 return instance;
202 }
203
MSCAN_EnterInitMode(MSCAN_Type * base)204 static void MSCAN_EnterInitMode(MSCAN_Type *base)
205 {
206 /* Set initial request bit. */
207 base->CANCTL0 |= MSCAN_CANCTL0_INITRQ_MASK;
208
209 /* Wait until the MsCAN Module enters initial mode. */
210 while (0U == (base->CANCTL1 & MSCAN_CANCTL1_INITAK_MASK))
211 {
212 }
213 }
214
MSCAN_ExitInitMode(MSCAN_Type * base)215 static void MSCAN_ExitInitMode(MSCAN_Type *base)
216 {
217 /* Clear initial request bit. */
218 base->CANCTL0 &= ~((uint8_t)MSCAN_CANCTL0_INITRQ_MASK);
219
220 /* Wait until the MsCAN Module exits initial mode. */
221 while (0U != (base->CANCTL1 & MSCAN_CANCTL1_INITAK_MASK))
222 {
223 }
224 }
225
226 #if (defined(FSL_FEATURE_FLEXCAN_HAS_IMPROVED_TIMING_CONFIG) && FSL_FEATURE_FLEXCAN_HAS_IMPROVED_TIMING_CONFIG)
227 /*!
228 * @brief Calculates the segment values for a single bit time for classical MSCAN
229 *
230 * @param baudRate The data speed in bps
231 * @param tqNum Number of time quantas per bit
232 * @param pconfig Pointer to the FlexCAN timing configuration structure.
233 *
234 * @return TRUE if valid Segments found, FALSE if failed to get valid segments
235 */
MSCAN_GetSegments(uint32_t baudRate,uint32_t tqNum,mscan_timing_config_t * pconfig)236 static bool MSCAN_GetSegments(uint32_t baudRate, uint32_t tqNum, mscan_timing_config_t *pconfig)
237 {
238 uint32_t ideal_sp;
239 uint32_t p1;
240 bool fgRet = false;
241
242 /* get ideal sample point. */
243 if (baudRate >= 1000000U)
244 {
245 ideal_sp = IDEAL_SP_LOW;
246 }
247 else if (baudRate >= 800000U)
248 {
249 ideal_sp = IDEAL_SP_MID;
250 }
251 else
252 {
253 ideal_sp = IDEAL_SP_HIGH;
254 }
255
256 /* distribute time quanta. */
257 p1 = tqNum * (uint32_t)ideal_sp;
258
259 /* Caculate for time segment 1. */
260 pconfig->timeSeg1 = (uint8_t)(p1 / IDEAL_SP_FACTOR - 1U);
261 if ((pconfig->timeSeg1 <= MAX_TSEG1) && (pconfig->timeSeg1 >= MIN_TSEG1))
262 {
263 if (pconfig->timeSeg1 <= ((uint8_t)tqNum - 3U))
264 {
265 /* Caculate for time sgement 2. */
266 pconfig->timeSeg2 = (uint8_t)tqNum - (pconfig->timeSeg1 + 3U);
267
268 if ((pconfig->timeSeg2 <= MAX_TSEG2) && (pconfig->timeSeg2 >= MIN_TSEG2))
269 {
270 /* subtract one TQ for sync seg. */
271 /* sjw is 20% of total TQ, rounded to nearest int. */
272 pconfig->sJumpwidth = ((uint8_t)tqNum + (5U - 1U)) / 5U - 1U;
273
274 if (pconfig->sJumpwidth > MAX_SJW)
275 {
276 pconfig->sJumpwidth = MAX_SJW;
277 }
278
279 fgRet = true;
280 }
281 }
282 }
283 return fgRet;
284 }
285
286 /*!
287 * @brief Calculates the improved timing values by specific baudrates for classical MSCAN
288 *
289 * @param baudRate The classical MSCAN speed in bps defined by user
290 * @param sourceClock_Hz The Source clock data speed in bps. Zero to disable baudrate switching
291 * @param pconfig Pointer to the MSCAN timing configuration structure.
292 *
293 * @return TRUE if timing configuration found, FALSE if failed to find configuration
294 */
MSCAN_CalculateImprovedTimingValues(uint32_t baudRate,uint32_t sourceClock_Hz,mscan_timing_config_t * pconfig)295 static bool MSCAN_CalculateImprovedTimingValues(uint32_t baudRate,
296 uint32_t sourceClock_Hz,
297 mscan_timing_config_t *pconfig)
298 {
299 uint32_t clk; /* the clock is tqNumb x baudRateFD. */
300 uint32_t tqNum; /* Numbers of TQ. */
301 bool fgRet = false;
302
303 /* observe baud rate maximums. */
304 assert(baudRate <= MAX_CAN_BAUDRATE);
305
306 /* Auto Improved Protocal timing for CBT. */
307 for (tqNum = MSCAN_MAX_TIME_QUANTA; tqNum >= MSCAN_MIN_TIME_QUANTA; tqNum--)
308 {
309 clk = baudRate * tqNum;
310 if (clk > sourceClock_Hz)
311 {
312 continue; /* tqNum too large, clk has been exceed sourceClock_Hz. */
313 }
314
315 if ((sourceClock_Hz / clk * clk) != sourceClock_Hz)
316 {
317 continue; /* Non-supporting: the frequency of clock source is not divisible by target baud rate, the user
318 should change a divisible baud rate. */
319 }
320
321 pconfig->priDiv = (uint8_t)(sourceClock_Hz / clk - 1U);
322 if (pconfig->priDiv > MAX_BRP)
323 {
324 break; /* The frequency of source clock is too large or the baud rate is too small, the pre-divider could
325 not handle it. */
326 }
327
328 if (MSCAN_GetSegments(baudRate, tqNum, pconfig))
329 {
330 /* Get the best timing configuration. */
331 fgRet = true;
332 break;
333 }
334 }
335
336 return fgRet;
337 }
338 #endif
339
MSCAN_SetBaudRate(MSCAN_Type * base,uint32_t sourceClock_Hz,uint32_t baudRate_Bps)340 static void MSCAN_SetBaudRate(MSCAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Bps)
341 {
342 mscan_timing_config_t timingConfig;
343 uint32_t priDiv = baudRate_Bps * (uint32_t)MSCAN_TIME_QUANTA_NUM;
344
345 /* Assertion: Desired baud rate is too high. */
346 assert(baudRate_Bps <= 1000000U);
347 /* Assertion: Source clock should greater than baud rate * MSCAN_TIME_QUANTA_NUM. */
348 assert(priDiv <= sourceClock_Hz);
349
350 #if (defined(FSL_FEATURE_FLEXCAN_HAS_IMPROVED_TIMING_CONFIG) && FSL_FEATURE_FLEXCAN_HAS_IMPROVED_TIMING_CONFIG)
351 /* MsCAN timing setting formula:
352 * MSCAN_TIME_QUANTA_NUM = 1 + (TSEG1 + 1) + (TSEG2 + 1);
353 * We can calculate SEG1 and SEG2 according to the load factor
354 */
355 if (false == MSCAN_CalculateImprovedTimingValues(baudRate_Bps, sourceClock_Hz, &timingConfig))
356 #endif
357 {
358 if (0U == priDiv)
359 {
360 priDiv = 1U;
361 }
362
363 priDiv = (sourceClock_Hz / priDiv) - 1U;
364
365 /* Desired baud rate is too low. */
366 if (priDiv > 0x3FU)
367 {
368 priDiv = 0x3FU;
369 }
370
371 timingConfig.priDiv = (uint8_t)priDiv;
372 timingConfig.timeSeg1 = 3U;
373 timingConfig.timeSeg2 = 2U;
374 timingConfig.sJumpwidth = 0U;
375 }
376 timingConfig.samp = 0;
377
378 /* Update actual timing characteristic. */
379 MSCAN_SetTimingConfig(base, &timingConfig);
380 }
381
382 /*!
383 * brief Initializes a MsCAN instance.
384 *
385 * This function initializes the MsCAN module with user-defined settings.
386 * This example shows how to set up the mscan_config_t parameters and how
387 * to call the MSCAN_Init function by passing in these parameters.
388 * code
389 * mscan_config_t mscanConfig;
390 * mscanConfig.clkSrc = kMSCAN_ClkSrcOsc;
391 * mscanConfig.baudRate = 1250000U;
392 * mscanConfig.enableTimer = false;
393 * mscanConfig.enableLoopBack = false;
394 * mscanConfig.enableWakeup = false;
395 * mscanConfig.enableListen = false;
396 * mscanConfig.busoffrecMode = kMSCAN_BusoffrecAuto;
397 * mscanConfig.filterConfig.filterMode = kMSCAN_Filter32Bit;
398 * MSCAN_Init(MSCAN, &mscanConfig, 8000000UL);
399 * endcode
400 *
401 * param base MsCAN peripheral base address.
402 * param config Pointer to the user-defined configuration structure.
403 * param sourceClock_Hz MsCAN Protocol Engine clock source frequency in Hz.
404 */
MSCAN_Init(MSCAN_Type * base,const mscan_config_t * config,uint32_t sourceClock_Hz)405 void MSCAN_Init(MSCAN_Type *base, const mscan_config_t *config, uint32_t sourceClock_Hz)
406 {
407 uint8_t ctl0Temp, ctl1Temp;
408 uint32_t u4temp;
409 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
410 uint32_t instance;
411 #endif
412
413 /* Assertion. */
414 assert(NULL != config);
415
416 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
417 instance = MSCAN_GetInstance(base);
418 /* Enable MsCAN clock. */
419 CLOCK_EnableClock(s_mscanClock[instance]);
420 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
421
422 /* Enable MsCAN Module for configuartion. */
423 MSCAN_Enable(base, true);
424
425 /* Enter initialization mode for MSCAN configuration. */
426 MSCAN_EnterInitMode(base);
427
428 ctl0Temp = base->CANCTL0;
429 ctl1Temp = base->CANCTL1;
430
431 /* Enable Self Wake Up Mode. */
432 ctl0Temp = (config->enableWakeup) ? ctl0Temp | (uint8_t)MSCAN_CANCTL0_WUPE_MASK :
433 ctl0Temp & ~((uint8_t)MSCAN_CANCTL0_WUPE_MASK);
434 /* Enable Loop Back Mode. */
435 ctl1Temp = (config->enableLoopBack) ? ctl1Temp | (uint8_t)MSCAN_CANCTL1_LOOPB_MASK :
436 ctl1Temp & ~((uint8_t)MSCAN_CANCTL1_LOOPB_MASK);
437 /* Enable Listen Mode. */
438 ctl1Temp = (config->enableListen) ? ctl1Temp | (uint8_t)MSCAN_CANCTL1_LISTEN_MASK :
439 ctl1Temp & ~((uint8_t)MSCAN_CANCTL1_LISTEN_MASK);
440 /* Clock source selection. */
441 ctl1Temp = (kMSCAN_ClkSrcBus == config->clkSrc) ? ctl1Temp | (uint8_t)MSCAN_CANCTL1_CLKSRC_MASK :
442 ctl1Temp & ~((uint8_t)MSCAN_CANCTL1_CLKSRC_MASK);
443
444 /* Save CTLx Configuation. */
445 base->CANCTL0 = ctl0Temp;
446 base->CANCTL1 = ctl1Temp;
447
448 /* Configure ID acceptance filter setting. */
449 MSCAN_SetIDFilterMode(base, config->filterConfig.filterMode);
450 u4temp = config->filterConfig.u32IDAR0; /* To fix MISRA-C 2012 Rule 11.8 issue. */
451 MSCAN_WriteIDAR0(base, (uint8_t *)(&u4temp));
452 u4temp = config->filterConfig.u32IDMR0;
453 MSCAN_WriteIDMR0(base, (uint8_t *)(&u4temp));
454 u4temp = config->filterConfig.u32IDAR1;
455 MSCAN_WriteIDAR1(base, (uint8_t *)(&u4temp));
456 u4temp = config->filterConfig.u32IDMR1;
457 MSCAN_WriteIDMR1(base, (uint8_t *)(&u4temp));
458
459 /* Baud Rate Configuration.*/
460 MSCAN_SetBaudRate(base, sourceClock_Hz, config->baudRate);
461
462 /* Enter normal mode. */
463 MSCAN_ExitInitMode(base);
464
465 /* Enable Timer. */
466 base->CANCTL0 = (config->enableTimer) ? base->CANCTL0 | (uint8_t)MSCAN_CANCTL0_TIME_MASK :
467 base->CANCTL0 & ~((uint8_t)MSCAN_CANCTL0_TIME_MASK);
468 }
469
470 /*!
471 * brief De-initializes a MsCAN instance.
472 *
473 * This function disables the MsCAN module clock and sets all register values
474 * to the reset value.
475 *
476 * param base MsCAN peripheral base address.
477 */
MSCAN_Deinit(MSCAN_Type * base)478 void MSCAN_Deinit(MSCAN_Type *base)
479 {
480 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
481 uint32_t instance;
482 #endif
483
484 /* Disable MsCAN module. */
485 MSCAN_Enable(base, false);
486
487 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
488 instance = MSCAN_GetInstance(base);
489 /* Disable MsCAN clock. */
490 CLOCK_DisableClock(s_mscanClock[instance]);
491 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
492 }
493
494 /*!
495 * brief Gets the default configuration structure.
496 *
497 * This function initializes the MsCAN configuration structure to default values.
498 *
499 * param config Pointer to the MsCAN configuration structure.
500 */
MSCAN_GetDefaultConfig(mscan_config_t * config)501 void MSCAN_GetDefaultConfig(mscan_config_t *config)
502 {
503 /* Assertion. */
504 assert(NULL != config);
505
506 /* Initializes the configure structure to zero. */
507 (void)memset(config, 0, sizeof(*config));
508
509 /* Initialize MsCAN Module config struct with default value. */
510 config->baudRate = 1000000U;
511 config->enableTimer = false;
512 config->enableWakeup = false;
513 config->clkSrc = kMSCAN_ClkSrcOsc;
514 config->enableLoopBack = false;
515 config->enableListen = false;
516 config->busoffrecMode = kMSCAN_BusoffrecAuto;
517 config->filterConfig.filterMode = kMSCAN_Filter32Bit;
518 }
519
520 /*!
521 * brief Sets the MsCAN protocol timing characteristic.
522 *
523 * This function gives user settings to CAN bus timing characteristic.
524 * The function is for an experienced user. For less experienced users, call
525 * the MSCAN_Init() and fill the baud rate field with a desired value.
526 * This provides the default timing characteristics to the module.
527 *
528 * Note that calling MSCAN_SetTimingConfig() overrides the baud rate set
529 * in MSCAN_Init().
530 *
531 * param base MsCAN peripheral base address.
532 * param config Pointer to the timing configuration structure.
533 */
MSCAN_SetTimingConfig(MSCAN_Type * base,const mscan_timing_config_t * config)534 void MSCAN_SetTimingConfig(MSCAN_Type *base, const mscan_timing_config_t *config)
535 {
536 /* Assertion. */
537 assert(NULL != config);
538
539 /* Enter Inialization Mode. */
540 MSCAN_EnterInitMode(base);
541
542 /* Cleaning previous Timing Setting. */
543 base->CANBTR0 &= (uint8_t)(~(MSCAN_CANBTR0_BRP_MASK | MSCAN_CANBTR0_SJW_MASK));
544 base->CANBTR1 &= (uint8_t)(~(MSCAN_CANBTR1_TSEG1_MASK | MSCAN_CANBTR1_TSEG2_MASK | MSCAN_CANBTR1_SAMP_MASK));
545
546 /* Updating Timing Setting according to configuration structure. */
547 base->CANBTR0 |= (MSCAN_CANBTR0_BRP(config->priDiv) | MSCAN_CANBTR0_SJW(config->sJumpwidth));
548 base->CANBTR1 |= (MSCAN_CANBTR1_TSEG1(config->timeSeg1) | MSCAN_CANBTR1_TSEG2(config->timeSeg2) |
549 MSCAN_CANBTR1_SAMP(config->samp));
550
551 /* Exit Inialization Mode. */
552 MSCAN_ExitInitMode(base);
553 }
554
555 /*!
556 * brief Writes a MsCAN Message to the Transmit Message Buffer.
557 *
558 * This function writes a CAN Message to the specified Transmit Message Buffer
559 * and changes the Message Buffer state to start CAN Message transmit. After
560 * that the function returns immediately.
561 *
562 * param base MsCAN peripheral base address.
563 * param pTxFrame Pointer to CAN message frame to be sent.
564 * retval kStatus_Success - Write Tx Message Buffer Successfully.
565 * retval kStatus_Fail - Tx Message Buffer is currently in use.
566 * retval kStatus_MSCAN_DataLengthError - Tx Message Buffer data length is wrong.
567 */
MSCAN_WriteTxMb(MSCAN_Type * base,mscan_frame_t * pTxFrame)568 status_t MSCAN_WriteTxMb(MSCAN_Type *base, mscan_frame_t *pTxFrame)
569 {
570 uint8_t txEmptyFlag;
571 mscan_mb_t mb = {0};
572 IDR1_3_UNION sIDR1 = {0}, sIDR3 = {0};
573 status_t status;
574 uint8_t i;
575
576 if (pTxFrame->DLR > MSCAN_DLC_MAX)
577 {
578 return kStatus_MSCAN_DataLengthError;
579 }
580
581 /* Write IDR. */
582 if (kMSCAN_FrameFormatExtend == pTxFrame->format)
583 {
584 /* Deal with Extended frame. */
585 sIDR1.IDR1.EID20_18_OR_SID2_0 = (uint8_t)pTxFrame->ID_Type.ExtID.EID20_18;
586 sIDR1.IDR1.R_TSRR = 1U;
587 sIDR1.IDR1.R_TEIDE = 1U;
588 sIDR1.IDR1.EID17_15 = (uint8_t)pTxFrame->ID_Type.ExtID.EID17_15;
589 sIDR3.IDR3.EID6_0 = (uint8_t)pTxFrame->ID_Type.ExtID.EID6_0;
590 sIDR3.IDR3.ERTR = (kMSCAN_FrameTypeRemote == pTxFrame->type) ? 1U : 0U;
591 /* Write into MB structure. */
592 mb.EIDR0 = (uint8_t)pTxFrame->ID_Type.ExtID.EID28_21;
593 mb.EIDR1 = sIDR1.Bytes;
594 mb.EIDR2 = (uint8_t)pTxFrame->ID_Type.ExtID.EID14_7;
595 mb.EIDR3 = sIDR3.Bytes;
596 }
597 else
598 {
599 /* Deal with Standard frame. */
600 sIDR1.IDR1.EID20_18_OR_SID2_0 = (uint8_t)pTxFrame->ID_Type.StdID.EID2_0;
601 sIDR1.IDR1.R_TSRR = 0U;
602 sIDR1.IDR1.R_TEIDE = 0U;
603 sIDR1.IDR1.EID17_15 = 0U; /* Reserved for Standard frame*/
604 /* Write into MB structure. */
605 mb.EIDR0 = (uint8_t)pTxFrame->ID_Type.StdID.EID10_3;
606 mb.EIDR1 = sIDR1.Bytes;
607 }
608 /* Write DLR, BPR */
609 mb.DLR = pTxFrame->DLR;
610 mb.BPR = pTxFrame->BPR;
611
612 /* Write DSR */
613 for (i = 0U; i < mb.DLR; i++)
614 {
615 mb.EDSR[i] = pTxFrame->DSR[i];
616 }
617
618 /* 1.Read TFLG to get the empty transmitter buffers. */
619 txEmptyFlag = MSCAN_GetTxBufferEmptyFlag(base);
620
621 if ((uint8_t)kMSCAN_TxBufFull != txEmptyFlag)
622 {
623 /* 2.Write TFLG value back. */
624 MSCAN_TxBufferSelect(base, txEmptyFlag);
625 /* Push contents of mb structure into hardware register. */
626 base->TEIDR0 = mb.EIDR0;
627 base->TEIDR1 = mb.EIDR1;
628 base->TEIDR2 = mb.EIDR2;
629 base->TEIDR3 = mb.EIDR3;
630 for (i = 0U; i < mb.DLR; i++)
631 {
632 base->TEDSR[i] = mb.EDSR[i];
633 }
634 base->TDLR = mb.DLR;
635 base->TBPR = mb.BPR;
636
637 /* 3.Read TBSEL again to get lowest tx buffer, then write 1 to clear
638 the corresponding bit to schedule transmission. */
639 MSCAN_TxBufferLaunch(base, MSCAN_GetTxBufferSelect(base));
640
641 status = kStatus_Success;
642 }
643 else
644 {
645 status = kStatus_Fail;
646 }
647 return status;
648 }
649
650 /*!
651 * brief Reads a MsCAN Message from Receive Message Buffer.
652 *
653 * This function reads a CAN message from a specified Receive Message Buffer.
654 * The function fills a receive CAN message frame structure with
655 * just received data and activates the Message Buffer again.
656 * The function returns immediately.
657 *
658 * param base MsCAN peripheral base address.
659 * param pRxFrame Pointer to CAN message frame structure for reception.
660 * retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
661 * retval kStatus_Fail - Rx Message Buffer is empty.
662 * retval kStatus_MSCAN_DataLengthError - Rx Message data length is wrong.
663 */
MSCAN_ReadRxMb(MSCAN_Type * base,mscan_frame_t * pRxFrame)664 status_t MSCAN_ReadRxMb(MSCAN_Type *base, mscan_frame_t *pRxFrame)
665 {
666 IDR1_3_UNION sIDR1 = {0};
667 IDR1_3_UNION sIDR3 = {0};
668 uint8_t i;
669 status_t status;
670
671 if (0U != MSCAN_GetRxBufferFullFlag(base))
672 {
673 status = kStatus_Success;
674
675 sIDR1.Bytes = MSCAN_ReadRIDR1(base);
676 sIDR3.Bytes = MSCAN_ReadRIDR3(base);
677 pRxFrame->format = (mscan_frame_format_t)(sIDR1.IDR1.R_TEIDE);
678
679 if (kMSCAN_FrameFormatExtend == pRxFrame->format) /* Extended frame. */
680 {
681 pRxFrame->type = (mscan_frame_type_t)(sIDR3.IDR3.ERTR);
682 pRxFrame->ID_Type.ExtID.EID28_21 = MSCAN_ReadRIDR0(base);
683 pRxFrame->ID_Type.ExtID.EID20_18 = sIDR1.IDR1.EID20_18_OR_SID2_0;
684 pRxFrame->ID_Type.ExtID.EID17_15 = sIDR1.IDR1.EID17_15;
685 pRxFrame->ID_Type.ExtID.EID14_7 = MSCAN_ReadRIDR2(base);
686 pRxFrame->ID_Type.ExtID.EID6_0 = sIDR3.IDR3.EID6_0;
687 }
688 else /* Standard frame. */
689 {
690 pRxFrame->type = (mscan_frame_type_t)(sIDR1.IDR1.R_TSRR);
691 pRxFrame->ID_Type.StdID.EID10_3 = MSCAN_ReadRIDR0(base);
692 pRxFrame->ID_Type.StdID.EID2_0 = sIDR1.IDR1.EID20_18_OR_SID2_0;
693 }
694
695 pRxFrame->DLR = base->RDLR & 0x0FU;
696
697 if (pRxFrame->DLR > MSCAN_DLC_MAX)
698 {
699 pRxFrame->DLR = MSCAN_DLC_MAX;
700 status = kStatus_MSCAN_DataLengthError;
701 }
702
703 for (i = 0; i < pRxFrame->DLR; i++)
704 {
705 pRxFrame->DSR[i] = base->REDSR[i];
706 }
707
708 pRxFrame->TSRH = base->RTSRH;
709 pRxFrame->TSRL = base->RTSRL;
710 }
711 else
712 {
713 status = kStatus_Fail;
714 }
715
716 return status;
717 }
718
719 /*!
720 * brief Performs a polling send transaction on the CAN bus.
721 *
722 * Note that a transfer handle does not need to be created before calling this API.
723 *
724 * param base MsCAN peripheral base pointer.
725 * param pTxFrame Pointer to CAN message frame to be sent.
726 * retval kStatus_Success - Write Tx Message Buffer Successfully.
727 * retval kStatus_Fail - Tx Message Buffer is currently in use.
728 * retval kStatus_MSCAN_DataLengthError - Tx Message Buffer data length is wrong.
729 */
MSCAN_TransferSendBlocking(MSCAN_Type * base,mscan_frame_t * pTxFrame)730 status_t MSCAN_TransferSendBlocking(MSCAN_Type *base, mscan_frame_t *pTxFrame)
731 {
732 status_t status;
733
734 /* Write Tx Message Buffer to initiate a data sending. */
735 status = MSCAN_WriteTxMb(base, pTxFrame);
736
737 if (kStatus_Success == status)
738 {
739 /* Wait until CAN Message send out. */
740 while (0U == MSCAN_GetTxBufferStatusFlags(base, MSCAN_GetTxBufferSelect(base)))
741 {
742 }
743 }
744
745 return status;
746 }
747
748 /*!
749 * brief Performs a polling receive transaction on the CAN bus.
750 *
751 * Note that a transfer handle does not need to be created before calling this API.
752 *
753 * param base MsCAN peripheral base pointer.
754 * param pRxFrame Pointer to CAN message frame to be received.
755 * retval kStatus_Success - Read Rx Message Buffer Successfully.
756 * retval kStatus_Fail - Tx Message Buffer is currently in use.
757 * retval kStatus_MSCAN_DataLengthError - Rx Message data length is wrong.
758 */
MSCAN_TransferReceiveBlocking(MSCAN_Type * base,mscan_frame_t * pRxFrame)759 status_t MSCAN_TransferReceiveBlocking(MSCAN_Type *base, mscan_frame_t *pRxFrame)
760 {
761 status_t status;
762
763 /* Wait until a new message is available in Rx Message Buffer. */
764 while (0U == MSCAN_GetRxBufferFullFlag(base))
765 {
766 }
767
768 /* Read Received CAN Message. */
769 status = MSCAN_ReadRxMb(base, pRxFrame);
770 if (kStatus_Success == status)
771 {
772 /* Clear RXF flag to release the buffer. */
773 MSCAN_ClearRxBufferFullFlag(base);
774 }
775
776 return status;
777 }
778
779 /*!
780 * brief Initializes the MsCAN handle.
781 *
782 * This function initializes the MsCAN handle, which can be used for other MsCAN
783 * transactional APIs. Usually, for a specified MsCAN instance,
784 * call this API once to get the initialized handle.
785 *
786 * param base MsCAN peripheral base address.
787 * param handle MsCAN handle pointer.
788 * param callback The callback function.
789 * param userData The parameter of the callback function.
790 */
MSCAN_TransferCreateHandle(MSCAN_Type * base,mscan_handle_t * handle,mscan_transfer_callback_t callback,void * userData)791 void MSCAN_TransferCreateHandle(MSCAN_Type *base,
792 mscan_handle_t *handle,
793 mscan_transfer_callback_t callback,
794 void *userData)
795 {
796 assert(NULL != handle);
797
798 uint8_t instance;
799
800 /* Clean MSCAN transfer handle. */
801 (void)memset(handle, 0, sizeof(*handle));
802
803 /* Get instance from peripheral base address. */
804 instance = (uint8_t)MSCAN_GetInstance(base);
805
806 /* Save the context in global variables to support the double weak mechanism. */
807 s_mscanHandle[instance] = handle;
808
809 /* Register Callback function. */
810 handle->callback = callback;
811 handle->userData = userData;
812
813 s_mscanIsr = MSCAN_TransferHandleIRQ;
814
815 /* We Enable Error & Status interrupt here, because this interrupt just
816 * report current status of MSCAN module through Callback function.
817 * It is insignificance without a available callback function.
818 */
819 if (handle->callback != NULL)
820 {
821 MSCAN_EnableRxInterrupts(base,
822 (uint8_t)kMSCAN_StatusChangeInterruptEnable | (uint8_t)kMSCAN_WakeUpInterruptEnable);
823 }
824 else
825 {
826 MSCAN_DisableRxInterrupts(base,
827 (uint8_t)kMSCAN_StatusChangeInterruptEnable | (uint8_t)kMSCAN_WakeUpInterruptEnable);
828 }
829
830 /* Enable interrupts in NVIC. */
831 (void)EnableIRQ((IRQn_Type)(s_mscanRxWarningIRQ[instance]));
832 (void)EnableIRQ((IRQn_Type)(s_mscanTxWarningIRQ[instance]));
833 (void)EnableIRQ((IRQn_Type)(s_mscanWakeUpIRQ[instance]));
834 (void)EnableIRQ((IRQn_Type)(s_mscanErrorIRQ[instance]));
835 }
836
837 /*!
838 * brief Sends a message using IRQ.
839 *
840 * This function sends a message using IRQ. This is a non-blocking function, which returns
841 * right away. When messages have been sent out, the send callback function is called.
842 *
843 * param base MsCAN peripheral base address.
844 * param handle MsCAN handle pointer.
845 * param xfer MsCAN Message Buffer transfer structure. See the #mscan_mb_transfer_t.
846 * retval kStatus_Success Start Tx Message Buffer sending process successfully.
847 * retval kStatus_Fail Write Tx Message Buffer failed.
848 * retval kStatus_MSCAN_DataLengthError - Tx Message Buffer data length is wrong.
849 */
MSCAN_TransferSendNonBlocking(MSCAN_Type * base,mscan_handle_t * handle,mscan_mb_transfer_t * xfer)850 status_t MSCAN_TransferSendNonBlocking(MSCAN_Type *base, mscan_handle_t *handle, mscan_mb_transfer_t *xfer)
851 {
852 /* Assertion. */
853 assert(NULL != handle);
854 assert(NULL != xfer);
855
856 status_t status;
857
858 /* Check if Message Buffer is idle. */
859
860 /* Distinguish transmit type. */
861 if (kMSCAN_FrameTypeRemote == xfer->frame->type)
862 {
863 handle->mbStateTx = (uint8_t)kMSCAN_StateTxRemote;
864
865 /* Register user Frame buffer to receive remote Frame. */
866 handle->mbFrameBuf = xfer->frame;
867 }
868 else
869 {
870 handle->mbStateTx = (uint8_t)kMSCAN_StateTxData;
871 }
872
873 status = MSCAN_WriteTxMb(base, xfer->frame);
874
875 if (kStatus_Success == status)
876 {
877 /* Enable Message Buffer Interrupt. */
878 MSCAN_EnableTxInterrupts(base, xfer->mask);
879 }
880 else
881 {
882 handle->mbStateTx = (uint8_t)kMSCAN_StateIdle;
883 }
884
885 return status;
886 }
887
888 /*!
889 * brief Receives a message using IRQ.
890 *
891 * This function receives a message using IRQ. This is non-blocking function, which returns
892 * right away. When the message has been received, the receive callback function is called.
893 *
894 * param base MsCAN peripheral base address.
895 * param handle MsCAN handle pointer.
896 * param xfer MsCAN Message Buffer transfer structure. See the #mscan_mb_transfer_t.
897 * retval kStatus_Success - Start Rx Message Buffer receiving process successfully.
898 * retval kStatus_MSCAN_RxBusy - Rx Message Buffer is in use.
899 */
MSCAN_TransferReceiveNonBlocking(MSCAN_Type * base,mscan_handle_t * handle,mscan_mb_transfer_t * xfer)900 status_t MSCAN_TransferReceiveNonBlocking(MSCAN_Type *base, mscan_handle_t *handle, mscan_mb_transfer_t *xfer)
901 {
902 /* Assertion. */
903 assert(NULL != handle);
904 assert(NULL != xfer);
905
906 status_t status;
907
908 /* Check if Message Buffer is idle. */
909 if ((uint8_t)kMSCAN_StateIdle == handle->mbStateRx)
910 {
911 handle->mbStateRx = (uint8_t)kMSCAN_StateRxData;
912
913 /* Register Message Buffer. */
914 handle->mbFrameBuf = xfer->frame;
915
916 /* Enable Message Buffer Interrupt. */
917 MSCAN_EnableRxInterrupts(base, xfer->mask);
918
919 status = kStatus_Success;
920 }
921 else
922 {
923 status = kStatus_MSCAN_RxBusy;
924 }
925
926 return status;
927 }
928
929 /*!
930 * brief Aborts the interrupt driven message send process.
931 *
932 * This function aborts the interrupt driven message send process.
933 *
934 * param base MsCAN peripheral base address.
935 * param handle MsCAN handle pointer.
936 * param mask The MsCAN Tx Message Buffer mask.
937 */
MSCAN_TransferAbortSend(MSCAN_Type * base,mscan_handle_t * handle,uint8_t mask)938 void MSCAN_TransferAbortSend(MSCAN_Type *base, mscan_handle_t *handle, uint8_t mask)
939 {
940 /* Assertion. */
941 assert(NULL != handle);
942
943 /* Abort Tx request. */
944 MSCAN_AbortTxRequest(base, mask);
945
946 /* Clean Message Buffer. */
947 MSCAN_DisableTxInterrupts(base, mask);
948
949 handle->mbStateTx = (uint8_t)kMSCAN_StateIdle;
950 }
951
952 /*!
953 * brief Aborts the interrupt driven message receive process.
954 *
955 * This function aborts the interrupt driven message receive process.
956 *
957 * param base MsCAN peripheral base address.
958 * param handle MsCAN handle pointer.
959 * param mask The MsCAN Rx Message Buffer mask.
960 */
MSCAN_TransferAbortReceive(MSCAN_Type * base,mscan_handle_t * handle,uint8_t mask)961 void MSCAN_TransferAbortReceive(MSCAN_Type *base, mscan_handle_t *handle, uint8_t mask)
962 {
963 /* Assertion. */
964 assert(NULL != handle);
965
966 /* Disable Message Buffer Interrupt. */
967 MSCAN_DisableRxInterrupts(base, mask);
968
969 /* Un-register handle. */
970 handle->mbStateRx = (uint8_t)kMSCAN_StateIdle;
971 }
972
973 /*!
974 * brief MSCAN IRQ handle function.
975 *
976 * This function handles the MSCAN Error, the Message Buffer, and the Rx FIFO IRQ request.
977 *
978 * param base MSCAN peripheral base address.
979 * param handle MSCAN handle pointer.
980 */
MSCAN_TransferHandleIRQ(MSCAN_Type * base,mscan_handle_t * handle)981 void MSCAN_TransferHandleIRQ(MSCAN_Type *base, mscan_handle_t *handle)
982 {
983 /* Assertion. */
984 assert(NULL != handle);
985
986 status_t status = kStatus_MSCAN_UnHandled;
987
988 /* Get current State of Message Buffer. */
989 if (0U != MSCAN_GetRxBufferFullFlag(base))
990 {
991 switch (handle->mbStateRx)
992 {
993 /* Solve Rx Data Frame. */
994 case (uint8_t)kMSCAN_StateRxData:
995 status = MSCAN_ReadRxMb(base, handle->mbFrameBuf);
996 if (kStatus_Success == status)
997 {
998 status = kStatus_MSCAN_RxIdle;
999 }
1000 MSCAN_TransferAbortReceive(base, handle, (uint8_t)kMSCAN_RxFullInterruptEnable);
1001 break;
1002
1003 /* Solve Rx Remote Frame. */
1004 case (uint8_t)kMSCAN_StateRxRemote:
1005 status = MSCAN_ReadRxMb(base, handle->mbFrameBuf);
1006 if (kStatus_Success == status)
1007 {
1008 status = kStatus_MSCAN_RxIdle;
1009 }
1010 MSCAN_TransferAbortReceive(base, handle, (uint8_t)kMSCAN_RxFullInterruptEnable);
1011 break;
1012
1013 default:
1014 /* To avoid MISRA-C 2012 rule 16.4 issue. */
1015 break;
1016 }
1017 MSCAN_ClearRxBufferFullFlag(base);
1018 }
1019 else
1020 {
1021 switch (handle->mbStateTx)
1022 {
1023 /* Solve Tx Data Frame. */
1024 case (uint8_t)kMSCAN_StateTxData:
1025 status = kStatus_MSCAN_TxIdle;
1026 MSCAN_TransferAbortSend(base, handle, (uint8_t)kMSCAN_TxEmptyInterruptEnable);
1027 break;
1028
1029 /* Solve Tx Remote Frame. */
1030 case (uint8_t)kMSCAN_StateTxRemote:
1031 handle->mbStateRx = (uint8_t)kMSCAN_StateRxRemote;
1032 status = kStatus_MSCAN_TxSwitchToRx;
1033 break;
1034
1035 default:
1036 status = kStatus_MSCAN_UnHandled;
1037 break;
1038 }
1039 }
1040
1041 handle->callback(base, handle, status, handle->userData);
1042 }
1043
1044 #if defined(MSCAN)
1045 void MSCAN_DriverIRQHandler(void);
MSCAN_DriverIRQHandler(void)1046 void MSCAN_DriverIRQHandler(void)
1047 {
1048 assert(NULL != s_mscanHandle[0]);
1049
1050 s_mscanIsr(MSCAN, s_mscanHandle[0]);
1051 SDK_ISR_EXIT_BARRIER;
1052 }
1053 #endif