1 /***************************************************************************//**
2 * @file
3 * @brief Controller Area Network API
4 *******************************************************************************
5 * # License
6 * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7 *******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 ******************************************************************************/
30
31 #include "em_can.h"
32 #include "sl_common.h"
33 #include "sl_assert.h"
34 #include "em_cmu.h"
35 #include <stddef.h>
36
37 #if defined(CAN_COUNT) && (CAN_COUNT > 0)
38
39 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
40
41 /* Macros to use for the ID field in the CANn_MIRx_ARB register as an 11 bit
42 * standard ID. The register field can be used for both an 11 bit standard
43 * ID and a 29 bit extended ID. */
44 #define _CAN_MIR_ARB_STD_ID_SHIFT 18
45 #define _CAN_MIR_MASK_STD_SHIFT 18
46 #define _CAN_MIR_ARB_STD_ID_MASK 0x1FFC0000UL
47 #define _CAN_MIR_ARB_STD_ID_MAX 0x7FFUL // = 2^11 - 1
48
49 #if (CAN_COUNT == 2)
50 #define CAN_VALID(can) ((can == CAN0) || (can == CAN1))
51 #elif (CAN_COUNT == 1)
52 #define CAN_VALID(can) (can == CAN0)
53 #else
54 #error "The actual number of CAN busses is not supported."
55 #endif
56
57 /** @endcond */
58
59 /***************************************************************************//**
60 * @addtogroup can CAN - Controller Area Network
61 * @brief Controller Area Network API
62 *
63 * @details The Controller Area Network Interface Bus (CAN) implements a
64 * multi-master serial bus for connecting microcontrollers and devices, also
65 * known as nodes, to communicate with each other in applications without a host
66 * computer. CAN is a message-based protocol, designed originally for automotive
67 * applications, but also used in many other scenarios.
68 * The complexity of a node can range from a simple I/O device up to an
69 * embedded computer with a CAN interface and sophisticated software. The node
70 * may also be a gateway allowing a standard computer to communicate over a USB
71 * or Ethernet port to the devices on a CAN network. Devices are connected to
72 * the bus through a host processor, a CAN controller, and a CAN transceiver.
73 *
74 * @include em_can_send_example.c
75 *
76 * @{
77 ******************************************************************************/
78
79 /*******************************************************************************
80 ************************** GLOBAL FUNCTIONS *******************************
81 ******************************************************************************/
82
83 /***************************************************************************//**
84 * @brief
85 * Initialize CAN.
86 *
87 * @param[in] can
88 * A pointer to the CAN peripheral register block.
89 *
90 * @param[in] init
91 * A pointer to the CAN initialization structure.
92 ******************************************************************************/
CAN_Init(CAN_TypeDef * can,const CAN_Init_TypeDef * init)93 void CAN_Init(CAN_TypeDef *can, const CAN_Init_TypeDef *init)
94 {
95 EFM_ASSERT(CAN_VALID(can));
96
97 CAN_Enable(can, false);
98 can->CTRL = _CAN_CTRL_TEST_MASK;
99 can->TEST = _CAN_TEST_RESETVALUE;
100 if (init->resetMessages) {
101 CAN_ResetMessages(can, 0);
102 }
103 can->CTRL = CAN_CTRL_INIT;
104 CAN_SetBitTiming(can,
105 init->bitrate,
106 init->propagationTimeSegment,
107 init->phaseBufferSegment1,
108 init->phaseBufferSegment2,
109 init->synchronisationJumpWidth);
110 CAN_Enable(can, init->enable);
111 }
112
113 /***************************************************************************//**
114 * @brief
115 * Get the CAN module frequency.
116 *
117 * @details
118 * An internal prescaler of 2 is inside the CAN module.
119 *
120 * @param[in] can
121 * A pointer to the CAN peripheral register block.
122 *
123 * @return
124 * A clock value.
125 ******************************************************************************/
CAN_GetClockFrequency(CAN_TypeDef * can)126 uint32_t CAN_GetClockFrequency(CAN_TypeDef *can)
127 {
128 #if defined CAN0
129 if (can == CAN0) {
130 return CMU_ClockFreqGet(cmuClock_CAN0) / 2;
131 }
132 #endif
133
134 #if defined CAN1
135 if (can == CAN1) {
136 return CMU_ClockFreqGet(cmuClock_CAN1) / 2;
137 }
138 #endif
139 EFM_ASSERT(false);
140 return 0;
141 }
142
143 /***************************************************************************//**
144 * @brief
145 * Read a Message Object to find if a message was lost ; reset the
146 * 'Message Lost' flag.
147 *
148 * @param[in] can
149 * A pointer to the CAN peripheral register block.
150 *
151 * @param[in] interface
152 * Indicate which Message Interface Register to use.
153 *
154 * @param[in] msgNum
155 * A message number of the Message Object, [1 - 32].
156 *
157 * @return
158 * True if a message was lost, false otherwise.
159 ******************************************************************************/
CAN_MessageLost(CAN_TypeDef * can,uint8_t interface,uint8_t msgNum)160 bool CAN_MessageLost(CAN_TypeDef *can, uint8_t interface, uint8_t msgNum)
161 {
162 CAN_MIR_TypeDef * mir = &can->MIR[interface];
163 bool messageLost;
164
165 /* Make sure msgNum is in the correct range. */
166 EFM_ASSERT((msgNum > 0) && (msgNum <= 32));
167
168 CAN_ReadyWait(can, interface);
169
170 /* Set which registers to read from RAM. */
171 mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ
172 | CAN_MIR_CMDMASK_CONTROL
173 | CAN_MIR_CMDMASK_CLRINTPND;
174
175 /* Send reading request and wait (3 to 6 cpu cycle). */
176 CAN_SendRequest(can, interface, msgNum, true);
177
178 messageLost = mir->CTRL & _CAN_MIR_CTRL_MESSAGEOF_MASK;
179
180 if (messageLost) {
181 mir->CMDMASK = CAN_MIR_CMDMASK_WRRD | CAN_MIR_CMDMASK_CONTROL;
182
183 /* Reset the 'MessageLost' bit. */
184 mir->CTRL &= ~_CAN_MIR_CTRL_MESSAGEOF_MASK;
185
186 /* Send reading request and wait (3 to 6 cpu cycle). */
187 CAN_SendRequest(can, interface, msgNum, true);
188 }
189
190 /* Return the state of the MESSAGEOF bit. */
191 return messageLost;
192 }
193
194 /***************************************************************************//**
195 * @brief
196 * Set the ROUTE registers.
197 *
198 * @param[in] can
199 * A pointer to the CAN peripheral register block.
200 *
201 * @param[in] active
202 * A boolean indicating whether or not to activate the ROUTE registers.
203 *
204 * @param[in] pinRxLoc
205 * A location of the RX pin.
206 *
207 * @param[in] pinTxLoc
208 * A location of the TX pin.
209 ******************************************************************************/
CAN_SetRoute(CAN_TypeDef * can,bool active,uint16_t pinRxLoc,uint16_t pinTxLoc)210 void CAN_SetRoute(CAN_TypeDef *can,
211 bool active,
212 uint16_t pinRxLoc,
213 uint16_t pinTxLoc)
214 {
215 if (active) {
216 /* Set the ROUTE register */
217 can->ROUTE = CAN_ROUTE_TXPEN
218 | (pinRxLoc << _CAN_ROUTE_RXLOC_SHIFT)
219 | (pinTxLoc << _CAN_ROUTE_TXLOC_SHIFT);
220 } else {
221 /* Deactivate the ROUTE register */
222 can->ROUTE = 0x0;
223 }
224 }
225
226 /***************************************************************************//**
227 * @brief
228 * Set the bitrate and its parameters.
229 *
230 * @details
231 * Multiple parameters need to be properly configured.
232 * See the reference manual for a detailed description.
233 * Careful : the BRP (Baud Rate Prescaler) is calculated by:
234 * 'brp = freq / (period * bitrate);'. freq is the frequency of the CAN
235 * device, period the time of transmission of a bit. The result is an uint32_t.
236 * Hence it's truncated, causing an approximation error. This error is non
237 * negligible when the period is high, the bitrate is high, and frequency is low.
238 *
239 * @param[in] can
240 * A pointer to the CAN peripheral register block.
241 *
242 * @param[in] bitrate
243 * A wanted bitrate on the CAN bus.
244 *
245 * @param[in] propagationTimeSegment
246 * A value for the Propagation Time Segment.
247 *
248 * @param[in] phaseBufferSegment1
249 * A value for the Phase Buffer Segment 1.
250 *
251 * @param[in] phaseBufferSegment2
252 * A value for the Phase Buffer Segment 2.
253 *
254 * @param[in] synchronisationJumpWidth
255 * A value for the Synchronization Jump Width.
256 ******************************************************************************/
CAN_SetBitTiming(CAN_TypeDef * can,uint32_t bitrate,uint16_t propagationTimeSegment,uint16_t phaseBufferSegment1,uint16_t phaseBufferSegment2,uint16_t synchronisationJumpWidth)257 void CAN_SetBitTiming(CAN_TypeDef *can,
258 uint32_t bitrate,
259 uint16_t propagationTimeSegment,
260 uint16_t phaseBufferSegment1,
261 uint16_t phaseBufferSegment2,
262 uint16_t synchronisationJumpWidth)
263 {
264 uint32_t sum, brp, period, freq, brpHigh, brpLow;
265
266 /* Verification that the parameters are in range. */
267 EFM_ASSERT((propagationTimeSegment <= 8) && (propagationTimeSegment > 0));
268 EFM_ASSERT((phaseBufferSegment1 <= 8) && (phaseBufferSegment1 > 0));
269 EFM_ASSERT((phaseBufferSegment2 <= 8) && (phaseBufferSegment2 > 0));
270 EFM_ASSERT(bitrate > 0);
271 EFM_ASSERT((synchronisationJumpWidth <= phaseBufferSegment1)
272 && (synchronisationJumpWidth <= phaseBufferSegment2)
273 && (synchronisationJumpWidth > 0));
274
275 /* propagationTimeSegment is counted as part of phaseBufferSegment1 in the
276 BITTIMING register. */
277 sum = phaseBufferSegment1 + propagationTimeSegment;
278
279 /* Period is the total length of one CAN bit. 1 is the Sync_seg. */
280 period = 1 + sum + phaseBufferSegment2;
281 freq = CAN_GetClockFrequency(can);
282
283 brp = freq / (period * bitrate);
284 EFM_ASSERT(brp != 0);
285
286 /* -1 because the hardware reads 'written value + 1'. */
287 brp = brp - 1;
288
289 /* brp is divided between two registers. */
290 brpHigh = brp / 64;
291 brpLow = brp % 64;
292
293 /* Checking register limit. */
294 EFM_ASSERT(brpHigh <= 15);
295
296 bool enabled = CAN_IsEnabled(can);
297
298 /* Enable access to the bittiming registers. */
299 can->CTRL |= CAN_CTRL_CCE | CAN_CTRL_INIT;
300
301 can->BITTIMING = (brpLow << _CAN_BITTIMING_BRP_SHIFT)
302 | ((synchronisationJumpWidth - 1) << _CAN_BITTIMING_SJW_SHIFT)
303 | ((sum - 1) << _CAN_BITTIMING_TSEG1_SHIFT)
304 | ((phaseBufferSegment2 - 1) << _CAN_BITTIMING_TSEG2_SHIFT);
305 can->BRPE = brpHigh;
306
307 if (enabled) {
308 can->CTRL &= ~(_CAN_CTRL_CCE_MASK | _CAN_CTRL_INIT_MASK);
309 } else {
310 can->CTRL &= ~_CAN_CTRL_CCE_MASK;
311 }
312 }
313
314 /***************************************************************************//**
315 * @brief
316 * Set the CAN operation mode.
317 *
318 * @details
319 * In initialization mode, the CAN module is deactivated. Reset the messages in all
320 * other modes to be sure that there is no leftover data that
321 * needs to be configured before use.
322 *
323 * @param[in] can
324 * A pointer to the CAN peripheral register block.
325 *
326 * @param[in] mode
327 * Mode of operation : Init, Normal, Loopback, SilentLoopback, Silent, Basic.
328 ******************************************************************************/
CAN_SetMode(CAN_TypeDef * can,CAN_Mode_TypeDef mode)329 void CAN_SetMode(CAN_TypeDef *can, CAN_Mode_TypeDef mode)
330 {
331 switch (mode) {
332 case canModeNormal:
333 can->CTRL |= _CAN_CTRL_TEST_MASK;
334 can->TEST = _CAN_TEST_RESETVALUE;
335 can->CTRL &= ~_CAN_CTRL_TEST_MASK;
336
337 can->CTRL = _CAN_CTRL_EIE_MASK
338 | _CAN_CTRL_SIE_MASK
339 | _CAN_CTRL_IE_MASK;
340 break;
341
342 case canModeBasic:
343 can->CTRL = _CAN_CTRL_EIE_MASK
344 | _CAN_CTRL_SIE_MASK
345 | _CAN_CTRL_IE_MASK
346 | CAN_CTRL_TEST;
347 can->TEST = CAN_TEST_BASIC;
348 break;
349
350 case canModeLoopBack:
351 can->CTRL = _CAN_CTRL_EIE_MASK
352 | _CAN_CTRL_SIE_MASK
353 | _CAN_CTRL_IE_MASK
354 | CAN_CTRL_TEST;
355 can->TEST = CAN_TEST_LBACK;
356 break;
357
358 case canModeSilentLoopBack:
359 can->CTRL = _CAN_CTRL_EIE_MASK
360 | _CAN_CTRL_SIE_MASK
361 | _CAN_CTRL_IE_MASK
362 | CAN_CTRL_TEST;
363 can->TEST = CAN_TEST_LBACK | CAN_TEST_SILENT;
364 break;
365
366 case canModeSilent:
367 can->CTRL = _CAN_CTRL_EIE_MASK
368 | _CAN_CTRL_SIE_MASK
369 | _CAN_CTRL_IE_MASK
370 | CAN_CTRL_TEST;
371 can->TEST = CAN_TEST_SILENT;
372 break;
373
374 default:
375 break;
376 }
377 }
378
379 /***************************************************************************//**
380 * @brief
381 * Set the ID and the filter for a specific Message Object.
382 *
383 * @details
384 * The initialization bit has to be 0 to use this function.
385 *
386 * @param[in] can
387 * A pointer to the CAN peripheral register block.
388 *
389 * @param[in] interface
390 * Indicate which Message Interface Register to use.
391 *
392 * @param[in] useMask
393 * A boolean to choose whether or not to use the masks.
394 *
395 * @param[in] message
396 * A Message Object.
397 *
398 * @param[in] wait
399 * If true, wait for the end of the transfer between the MIRx registers and
400 * the RAM to exit. If false, exit immediately, the transfer can still be
401 * in progress.
402 ******************************************************************************/
CAN_SetIdAndFilter(CAN_TypeDef * can,uint8_t interface,bool useMask,const CAN_MessageObject_TypeDef * message,bool wait)403 void CAN_SetIdAndFilter(CAN_TypeDef *can,
404 uint8_t interface,
405 bool useMask,
406 const CAN_MessageObject_TypeDef *message,
407 bool wait)
408 {
409 /* Make sure msgNum is in the correct range. */
410 EFM_ASSERT((message->msgNum > 0) && (message->msgNum <= 32));
411
412 CAN_MIR_TypeDef * mir = &can->MIR[interface];
413 CAN_ReadyWait(can, interface);
414
415 /* Set which registers to read from RAM. */
416 mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ
417 | CAN_MIR_CMDMASK_ARBACC
418 | CAN_MIR_CMDMASK_CONTROL;
419
420 /* Send reading request and wait (3 to 6 CPU cycle). */
421 CAN_SendRequest(can, interface, message->msgNum, true);
422
423 /* Reset MSGVAL. */
424 mir->CMDMASK |= CAN_MIR_CMDMASK_WRRD_WRITE;
425 mir->ARB &= ~CAN_MIR_ARB_MSGVAL;
426 CAN_SendRequest(can, interface, message->msgNum, true);
427
428 /* Set which registers to write to RAM. */
429 mir->CMDMASK |= CAN_MIR_CMDMASK_MASKACC;
430
431 /* Set UMASK bit. */
432 BUS_RegBitWrite(&mir->CTRL, _CAN_MIR_CTRL_UMASK_SHIFT, useMask);
433
434 /* Configure the ID. */
435 if (message->extended) {
436 EFM_ASSERT(message->id <= _CAN_MIR_ARB_ID_MASK);
437 mir->ARB = (mir->ARB & ~_CAN_MIR_ARB_ID_MASK)
438 | (message->id << _CAN_MIR_ARB_ID_SHIFT)
439 | CAN_MIR_ARB_MSGVAL
440 | CAN_MIR_ARB_XTD_EXT;
441 } else {
442 EFM_ASSERT(message->id <= _CAN_MIR_ARB_STD_ID_MAX);
443 mir->ARB = (mir->ARB & ~(_CAN_MIR_ARB_ID_MASK | CAN_MIR_ARB_XTD_STD))
444 | (message->id << _CAN_MIR_ARB_STD_ID_SHIFT)
445 | CAN_MIR_ARB_MSGVAL;
446 }
447
448 if (message->extendedMask) {
449 mir->MASK = (message->mask << _CAN_MIR_MASK_MASK_SHIFT)
450 & _CAN_MIR_MASK_MASK_MASK;
451 } else {
452 mir->MASK = (message->mask << _CAN_MIR_MASK_STD_SHIFT)
453 & _CAN_MIR_ARB_STD_ID_MASK;
454 }
455
456 /* Configure the masks. */
457 mir->MASK |= (message->extendedMask << _CAN_MIR_MASK_MXTD_SHIFT)
458 | (message->directionMask << _CAN_MIR_MASK_MDIR_SHIFT);
459
460 /* Send a writing request. */
461 CAN_SendRequest(can, interface, message->msgNum, wait);
462 }
463
464 /***************************************************************************//**
465 * @brief
466 * Configure valid, TX/RX, remoteTransfer for a specific Message Object.
467 *
468 * @details
469 * The initialization bit has to be 0 to use this function.
470 *
471 * @param[in] can
472 * A pointer to the CAN peripheral register block.
473 *
474 * @param[in] interface
475 * Indicate which Message Interface Register to use.
476 *
477 * @param[in] msgNum
478 * A message number of this Message Object, [1 - 32].
479 *
480 * @param[in] valid
481 * True if the Message Object is valid, false otherwise.
482 *
483 * @param[in] tx
484 * True if the Message Object is used for transmission, false if used for
485 * reception.
486 *
487 * @param[in] remoteTransfer
488 * True if the Message Object is used for remote transmission, false otherwise.
489 *
490 * @param[in] endOfBuffer
491 * True if it is for a single Message Object or the end of a FIFO buffer,
492 * false if the Message Object is part of a FIFO buffer and not the last.
493 *
494 * @param[in] wait
495 * If true, wait for the end of the transfer between the MIRx registers and
496 * the RAM to exit. If false, exit immediately, the transfer can still be
497 * in progress.
498 ******************************************************************************/
CAN_ConfigureMessageObject(CAN_TypeDef * can,uint8_t interface,uint8_t msgNum,bool valid,bool tx,bool remoteTransfer,bool endOfBuffer,bool wait)499 void CAN_ConfigureMessageObject(CAN_TypeDef *can,
500 uint8_t interface,
501 uint8_t msgNum,
502 bool valid,
503 bool tx,
504 bool remoteTransfer,
505 bool endOfBuffer,
506 bool wait)
507 {
508 CAN_MIR_TypeDef * mir = &can->MIR[interface];
509
510 /* Make sure msgNum is in correct range. */
511 EFM_ASSERT((msgNum > 0) && (msgNum <= 32));
512
513 CAN_ReadyWait(can, interface);
514
515 /* Set which registers to read from RAM. */
516 mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ
517 | CAN_MIR_CMDMASK_ARBACC
518 | CAN_MIR_CMDMASK_CONTROL;
519
520 /* Send reading request and wait (3 to 6 CPU cycle). */
521 CAN_SendRequest(can, interface, msgNum, true);
522
523 /* Reset MSGVAL. */
524 mir->CMDMASK |= CAN_MIR_CMDMASK_WRRD_WRITE;
525 mir->ARB &= ~CAN_MIR_ARB_MSGVAL;
526 CAN_SendRequest(can, interface, msgNum, true);
527
528 /* Configure a valid message and direction. */
529 mir->ARB = (mir->ARB & ~(_CAN_MIR_ARB_DIR_MASK | _CAN_MIR_ARB_MSGVAL_MASK))
530 | (valid << _CAN_MIR_ARB_MSGVAL_SHIFT)
531 | (tx << _CAN_MIR_ARB_DIR_SHIFT);
532
533 /* Set EOB bit, RX, and TX interrupts. */
534 mir->CTRL = (endOfBuffer << _CAN_MIR_CTRL_EOB_SHIFT)
535 | _CAN_MIR_CTRL_TXIE_MASK
536 | _CAN_MIR_CTRL_RXIE_MASK
537 | (remoteTransfer << _CAN_MIR_CTRL_RMTEN_SHIFT);
538
539 /* Send a writing request. */
540 CAN_SendRequest(can, interface, msgNum, wait);
541 }
542
543 /***************************************************************************//**
544 * @brief
545 * Send data from the Message Object message.
546 *
547 * @details
548 * If the message is configured as TX and remoteTransfer = 0, calling this function
549 * will send the data of this Message Object if its parameters are correct.
550 * If the message is TX and remoteTransfer = 1, this function will set the data of
551 * message to RAM and exit. Data will be automatically sent after
552 * reception of a remote frame.
553 * If the message is RX and remoteTransfer = 1, this function will send a remote
554 * frame to the corresponding ID.
555 * If the message is RX and remoteTransfer = 0, the user shouldn't call this
556 * function. It will also send a remote frame.
557 *
558 * @param[in] can
559 * A pointer to the CAN peripheral register block.
560 *
561 * @param[in] interface
562 * Indicate which Message Interface Register to use.
563 *
564 * @param[in] message
565 * A Message Object.
566 *
567 * @param[in] wait
568 * If true, wait for the end of the transfer between the MIRx registers and
569 * RAM to exit. If false, exit immediately. The transfer can still be
570 * in progress.
571 ******************************************************************************/
CAN_SendMessage(CAN_TypeDef * can,uint8_t interface,const CAN_MessageObject_TypeDef * message,bool wait)572 void CAN_SendMessage(CAN_TypeDef *can,
573 uint8_t interface,
574 const CAN_MessageObject_TypeDef *message,
575 bool wait)
576 {
577 CAN_MIR_TypeDef * mir = &can->MIR[interface];
578
579 /* Make sure msgNum is in correct range. */
580 EFM_ASSERT((message->msgNum > 0) && (message->msgNum <= 32));
581 /* Make sure dlc is in correct range. */
582 EFM_ASSERT(message->dlc <= _CAN_MIR_CTRL_DLC_MASK);
583
584 CAN_ReadyWait(can, interface);
585
586 /* Set LEC to an unused value to be sure it is reset to 0 after sending. */
587 BUS_RegMaskedWrite(&can->STATUS, _CAN_STATUS_LEC_MASK, 0x7);
588
589 /* Set which registers to read from RAM. */
590 mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ
591 | CAN_MIR_CMDMASK_ARBACC
592 | CAN_MIR_CMDMASK_CONTROL;
593
594 /* Send a reading request and wait (3 to 6 CPU cycle). */
595 CAN_SendRequest(can, interface, message->msgNum, true);
596
597 /* Reset MSGVAL. */
598 mir->CMDMASK |= CAN_MIR_CMDMASK_WRRD_WRITE;
599 mir->ARB &= ~CAN_MIR_ARB_MSGVAL;
600 CAN_SendRequest(can, interface, message->msgNum, true);
601
602 /* Set which registers to write to RAM. */
603 if ( ((mir->CTRL & _CAN_MIR_CTRL_RMTEN_MASK) == 0)
604 || (((mir->CTRL & _CAN_MIR_CTRL_RMTEN_MASK) == CAN_MIR_CTRL_RMTEN)
605 && ((mir->ARB & _CAN_MIR_ARB_DIR_MASK) == CAN_MIR_ARB_DIR_TX)) ) {
606 mir->CMDMASK |= CAN_MIR_CMDMASK_DATAA
607 | CAN_MIR_CMDMASK_DATAB;
608
609 /* Set data. */
610 CAN_WriteData(can, interface, message);
611 }
612
613 /* If TX = 1 and remoteTransfer = 1, nothing is sent. */
614 if ( ((mir->CTRL & _CAN_MIR_CTRL_RMTEN_MASK) == 0)
615 || ((mir->ARB & _CAN_MIR_ARB_DIR_MASK) == CAN_MIR_ARB_DIR_RX)) {
616 mir->CTRL |= CAN_MIR_CTRL_TXRQST;
617 /* DATAVALID is set only if it is not sending a remote message. */
618 if ((mir->CTRL & _CAN_MIR_CTRL_RMTEN_MASK) == 0) {
619 mir->CTRL |= CAN_MIR_CTRL_DATAVALID;
620 }
621 }
622
623 /* Set the data length code. */
624 mir->CTRL = (mir->CTRL & ~_CAN_MIR_CTRL_DLC_MASK)
625 | message->dlc;
626
627 /* Configure the ID. */
628 if (message->extended) {
629 EFM_ASSERT(message->id <= _CAN_MIR_ARB_ID_MASK);
630 mir->ARB = (mir->ARB & ~_CAN_MIR_ARB_ID_MASK)
631 | (message->id << _CAN_MIR_ARB_ID_SHIFT)
632 | CAN_MIR_ARB_MSGVAL
633 | CAN_MIR_ARB_XTD_EXT;
634 } else {
635 EFM_ASSERT(message->id <= _CAN_MIR_ARB_STD_ID_MAX);
636 mir->ARB = (mir->ARB & ~(_CAN_MIR_ARB_ID_MASK | _CAN_MIR_ARB_XTD_MASK))
637 | CAN_MIR_ARB_MSGVAL
638 | (message->id << _CAN_MIR_ARB_STD_ID_SHIFT)
639 | CAN_MIR_ARB_XTD_STD;
640 }
641
642 /* Send a writing request. */
643 CAN_SendRequest(can, interface, message->msgNum, wait);
644 }
645
646 /***************************************************************************//**
647 * @brief
648 * Read data and ID from a Message Object in RAM and store it in a message.
649 *
650 * @details
651 * Read the information from RAM on this Message Object. Data and
652 * the configuration of the Message Object is read. The information is only
653 * read if the message stored in the Message Object is new and valid.
654 *
655 * @param[in] can
656 * A pointer to the CAN peripheral register block.
657 *
658 * @param[in] interface
659 * Indicate which Message Interface Register to use.
660 *
661 * @param[in] message
662 * A Message Object.
663 *
664 * @return
665 * True if the Message Object in RAM holds a new and valid message, which was
666 * not read earlier, false otherwise.
667 ******************************************************************************/
CAN_ReadMessage(CAN_TypeDef * can,uint8_t interface,CAN_MessageObject_TypeDef * message)668 bool CAN_ReadMessage(CAN_TypeDef *can,
669 uint8_t interface,
670 CAN_MessageObject_TypeDef *message)
671 {
672 CAN_MIR_TypeDef * mir = &can->MIR[interface];
673 uint32_t buffer;
674 uint32_t i;
675
676 /* Make sure msgNum is in correct range. */
677 EFM_ASSERT((message->msgNum > 0) && (message->msgNum <= 32));
678
679 CAN_ReadyWait(can, interface);
680
681 /* Set which registers to read from RAM. */
682 mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ
683 | CAN_MIR_CMDMASK_MASKACC
684 | CAN_MIR_CMDMASK_ARBACC
685 | CAN_MIR_CMDMASK_CONTROL
686 | CAN_MIR_CMDMASK_CLRINTPND
687 | CAN_MIR_CMDMASK_TXRQSTNEWDAT
688 | CAN_MIR_CMDMASK_DATAA
689 | CAN_MIR_CMDMASK_DATAB;
690
691 /* Send a reading request and wait (3 to 6 cpu cycle). */
692 CAN_SendRequest(can, interface, message->msgNum, true);
693
694 if ((mir->CTRL & CAN_MIR_CTRL_DATAVALID) == 0) {
695 return false;
696 }
697
698 /* Get dlc from the control register. */
699 message->dlc = ((mir->CTRL & _CAN_MIR_CTRL_DLC_MASK) >> _CAN_MIR_CTRL_DLC_SHIFT);
700
701 /* Make sure dlc is in correct range. */
702 EFM_ASSERT(message->dlc <= 8);
703
704 /* Get id from the control register */
705 if (message->extended) {
706 message->id = (mir->ARB & _CAN_MIR_ARB_ID_MASK);
707 } else {
708 message->id = ((mir->ARB & _CAN_MIR_ARB_STD_ID_MASK) >> _CAN_MIR_ARB_STD_ID_SHIFT);
709 }
710
711 /* Copy data from the MIR registers to the Message Object message. */
712 buffer = mir->DATAL;
713 for (i = 0; i < SL_MIN(message->dlc, 4U); ++i) {
714 message->data[i] = buffer & 0xFF;
715 buffer = buffer >> 8;
716 }
717 if (message->dlc > 3) {
718 buffer = mir->DATAH;
719 for (i = 0; i < message->dlc - 4U; ++i) {
720 message->data[i + 4] = buffer & 0xFF;
721 buffer = buffer >> 8;
722 }
723 }
724
725 return true;
726 }
727
728 /***************************************************************************//**
729 * @brief
730 * Abort sending a message.
731 *
732 * @details
733 * Set the TXRQST of the CTRL register to 0. Doesn't touch data or the
734 * other parameters. The user can call CAN_SendMessage() to send the object
735 * after using CAN_AbortSendMessage().
736 *
737 * @param[in] can
738 * A pointer to the CAN peripheral register block.
739 *
740 * @param[in] interface
741 * Indicate which Message Interface Register to use.
742 *
743 * @param[in] msgNum
744 * A message number of this Message Object, [1 - 32].
745 *
746 * @param[in] wait
747 * If true, wait for the end of the transfer between the MIRx registers and
748 * the RAM to exit. If false, exit immediately. The transfer can still be
749 * in progress.
750 ******************************************************************************/
CAN_AbortSendMessage(CAN_TypeDef * can,uint8_t interface,uint8_t msgNum,bool wait)751 void CAN_AbortSendMessage(CAN_TypeDef *can,
752 uint8_t interface,
753 uint8_t msgNum,
754 bool wait)
755 {
756 /* Make sure msgNum is in correct range. */
757 EFM_ASSERT((msgNum > 0) && (msgNum <= 32));
758
759 CAN_MIR_TypeDef * mir = &can->MIR[interface];
760 CAN_ReadyWait(can, interface);
761
762 /* Set which registers to read from RAM. */
763 mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ
764 | CAN_MIR_CMDMASK_CONTROL;
765
766 /* Send a reading request and wait (3 to 6 cpu cycle). */
767 CAN_SendRequest(can, interface, msgNum, true);
768
769 /* Set which registers to write to RAM. */
770 mir->CMDMASK = CAN_MIR_CMDMASK_WRRD
771 | CAN_MIR_CMDMASK_CONTROL;
772
773 /* Set TXRQST bit to 0. */
774 mir->CTRL &= ~_CAN_MIR_CTRL_TXRQST_MASK;
775
776 /* Send a writing request. */
777 CAN_SendRequest(can, interface, msgNum, wait);
778 }
779
780 /***************************************************************************//**
781 * @brief
782 * Reset all Message Objects and set their data to 0.
783 *
784 * @param[in] can
785 * A pointer to the CAN peripheral register block.
786 *
787 * @param[in] interface
788 * Indicate which Message Interface Register to use.
789 ******************************************************************************/
CAN_ResetMessages(CAN_TypeDef * can,uint8_t interface)790 void CAN_ResetMessages(CAN_TypeDef *can, uint8_t interface)
791 {
792 CAN_MIR_TypeDef * mir = &can->MIR[interface];
793 CAN_ReadyWait(can, interface);
794
795 /* Set which registers to read from RAM. */
796 mir->CMDMASK = CAN_MIR_CMDMASK_WRRD
797 | CAN_MIR_CMDMASK_MASKACC
798 | CAN_MIR_CMDMASK_ARBACC
799 | CAN_MIR_CMDMASK_CONTROL
800 | CAN_MIR_CMDMASK_DATAA
801 | CAN_MIR_CMDMASK_DATAB;
802
803 mir->MASK = _CAN_MIR_MASK_RESETVALUE;
804 mir->ARB = _CAN_MIR_ARB_RESETVALUE;
805 mir->CTRL = _CAN_MIR_CTRL_RESETVALUE;
806 mir->DATAL = 0x00000000;
807 mir->DATAH = 0x00000000;
808
809 /* Write each reset Message Object to RAM. */
810 for (int i = 1; i <= 32; ++i) {
811 CAN_SendRequest(can, interface, i, true);
812 }
813 }
814
815 /***************************************************************************//**
816 * @brief
817 * Set all CAN registers to RESETVALUE. Leave the CAN device disabled.
818 *
819 * @param[in] can
820 * A pointer to the CAN peripheral register block.
821 ******************************************************************************/
CAN_Reset(CAN_TypeDef * can)822 void CAN_Reset(CAN_TypeDef *can)
823 {
824 CAN_ReadyWait(can, 0);
825 CAN_ReadyWait(can, 1);
826
827 CAN_Enable(can, false);
828 can->STATUS = _CAN_STATUS_RESETVALUE;
829
830 can->CTRL |= _CAN_CTRL_CCE_MASK;
831 can->BITTIMING = _CAN_BITTIMING_RESETVALUE;
832 can->CTRL &= ~_CAN_CTRL_CCE_MASK;
833
834 can->CTRL |= _CAN_CTRL_TEST_MASK;
835 can->TEST = _CAN_TEST_RESETVALUE;
836 can->CTRL &= ~_CAN_CTRL_TEST_MASK;
837
838 can->BRPE = _CAN_BRPE_RESETVALUE;
839 can->CONFIG = _CAN_CONFIG_RESETVALUE;
840 can->IF0IFS = _CAN_IF0IFS_RESETVALUE;
841 can->IF0IFC = _CAN_IF0IFC_RESETVALUE;
842 can->IF0IEN = _CAN_IF0IEN_RESETVALUE;
843 can->IF1IFS = _CAN_IF1IF_RESETVALUE;
844 can->IF1IFC = _CAN_IF1IFC_RESETVALUE;
845 can->IF1IEN = _CAN_IF1IEN_RESETVALUE;
846 can->ROUTE = _CAN_ROUTE_RESETVALUE;
847
848 for (int i = 0; i < 2; i++) {
849 can->MIR[i].CMDMASK = _CAN_MIR_CMDMASK_RESETVALUE;
850 can->MIR[i].MASK = _CAN_MIR_MASK_RESETVALUE;
851 can->MIR[i].ARB = _CAN_MIR_ARB_RESETVALUE;
852 can->MIR[i].CTRL = _CAN_MIR_CTRL_RESETVALUE;
853 can->MIR[i].DATAL = _CAN_MIR_DATAL_RESETVALUE;
854 can->MIR[i].DATAH = _CAN_MIR_DATAH_RESETVALUE;
855 can->MIR[i].CMDREQ = _CAN_MIR_CMDREQ_RESETVALUE;
856 }
857 }
858
859 /***************************************************************************//**
860 * @brief
861 * Write data from a message to the MIRx registers.
862 *
863 * @param[in] can
864 * A pointer to the CAN peripheral register block.
865 *
866 * @param[in] interface
867 * Indicate which Message Interface Register to use.
868 *
869 * @param[in] message
870 * A Message Object.
871 ******************************************************************************/
CAN_WriteData(CAN_TypeDef * can,uint8_t interface,const CAN_MessageObject_TypeDef * message)872 void CAN_WriteData(CAN_TypeDef *can,
873 uint8_t interface,
874 const CAN_MessageObject_TypeDef *message)
875 {
876 uint32_t tmp;
877 uint8_t data[8] = { 0 };
878 size_t length = SL_MIN(8, message->dlc);
879 CAN_MIR_TypeDef * mir = &can->MIR[interface];
880
881 for (size_t i = 0; i < length; i++) {
882 data[i] = message->data[i];
883 }
884
885 CAN_ReadyWait(can, interface);
886
887 tmp = data[0];
888 tmp |= data[1] << 8;
889 tmp |= data[2] << 16;
890 tmp |= data[3] << 24;
891 mir->DATAL = tmp;
892
893 tmp = data[4];
894 tmp |= data[5] << 8;
895 tmp |= data[6] << 16;
896 tmp |= data[7] << 24;
897 mir->DATAH = tmp;
898 }
899
900 /***************************************************************************//**
901 * @brief
902 * Send a request for writing or reading RAM of the Message Object msgNum.
903 *
904 * @param[in] can
905 * A pointer to the CAN peripheral register block.
906 *
907 * @param[in] interface
908 * Indicate which Message Interface Register to use.
909 *
910 * @param[in] msgNum
911 * A message number of the Message Object, [1 - 32].
912 *
913 * @param[in] wait
914 * If true, wait for the end of the transfer between the MIRx registers and
915 * the RAM to exit. If false, exit immediately. The transfer can still be
916 * in progress.
917 ******************************************************************************/
CAN_SendRequest(CAN_TypeDef * can,uint8_t interface,uint8_t msgNum,bool wait)918 void CAN_SendRequest(CAN_TypeDef *can,
919 uint8_t interface,
920 uint8_t msgNum,
921 bool wait)
922 {
923 CAN_MIR_TypeDef * mir = &can->MIR[interface];
924
925 /* Make sure msgNum is in correct range. */
926 EFM_ASSERT((msgNum > 0) && (msgNum <= 32));
927
928 /* Make sure the MIRx registers aren't busy. */
929 CAN_ReadyWait(can, interface);
930
931 /* Write msgNum to the CMDREQ register. */
932 mir->CMDREQ = msgNum << _CAN_MIR_CMDREQ_MSGNUM_SHIFT;
933
934 if (wait) {
935 CAN_ReadyWait(can, interface);
936 }
937 }
938
939 /** @} (end addtogroup can) */
940
941 #endif /* defined(CAN_COUNT) && (CAN_COUNT > 0) */
942