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