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 #ifndef EM_CAN_H
32 #define EM_CAN_H
33
34 #include "em_bus.h"
35 #include "em_device.h"
36 #include <stdbool.h>
37
38 #if defined(CAN_COUNT) && (CAN_COUNT > 0)
39
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43
44 /***************************************************************************//**
45 * @addtogroup can
46 * @{
47 ******************************************************************************/
48
49 /*******************************************************************************
50 ******************************* DEFINES ***********************************
51 ******************************************************************************/
52
53 /*******************************************************************************
54 ******************************** ENUMS ************************************
55 ******************************************************************************/
56
57 /** CAN Status codes. */
58 typedef enum {
59 /** No error occurred during the last CAN bus event. */
60 canErrorNoError = CAN_STATUS_LEC_NONE,
61
62 /**
63 * More than 5 equal bits in a sequence have occurred in a part of a received
64 * message where this is not allowed.
65 */
66 canErrorStuff = CAN_STATUS_LEC_STUFF,
67
68 /** A fixed format part of a received frame has the wrong format. */
69 canErrorForm = CAN_STATUS_LEC_FORM,
70
71 /** The message this CAN Core transmitted was not acknowledged by another node. */
72 canErrorAck = CAN_STATUS_LEC_ACK,
73
74 /** A wrong monitored bus value : dominant when the module wants to send a recessive. */
75 canErrorBit1 = CAN_STATUS_LEC_BIT1,
76
77 /** A wrong monitored bus value : recessive when the module intends to send a dominant. */
78 canErrorBit0 = CAN_STATUS_LEC_BIT0,
79
80 /** CRC check sum incorrect. */
81 canErrorCrc = CAN_STATUS_LEC_CRC,
82
83 /** Unused. No new error since the CPU wrote this value. */
84 canErrorUnused = CAN_STATUS_LEC_UNUSED
85 } CAN_ErrorCode_TypeDef;
86
87 /** CAN peripheral mode. */
88 typedef enum {
89 /** CAN peripheral in Normal mode : ready to send and receive messages. */
90 canModeNormal,
91
92 /** CAN peripheral in Basic mode : no use of the RAM. */
93 canModeBasic,
94
95 /**
96 * CAN peripheral in Loopback mode : input from the CAN bus is disregarded
97 * and comes from TX instead.
98 */
99 canModeLoopBack,
100
101 /**
102 * CAN peripheral in SilentLoopback mode : input from the CAN bus is
103 * disregarded and comes from TX instead ; no output on the CAN bus.
104 */
105 canModeSilentLoopBack,
106
107 /** CAN peripheral in Silent mode : no output on the CAN bus. If required to
108 * send a dominant bit, it's rerouted internally so that the CAN module
109 * monitors it but the CAN bus stays recessive.
110 */
111 canModeSilent
112 } CAN_Mode_TypeDef;
113
114 /*******************************************************************************
115 ******************************* STRUCTS ***********************************
116 ******************************************************************************/
117
118 /** CAN Message Object TypeDef structure. LSBs is used. */
119 typedef struct {
120 /** A message number of this Message Object, [1 - 32]. */
121 uint8_t msgNum;
122
123 /** ID extended if true, standard if false. */
124 bool extended;
125
126 /**
127 * ID of the message with 11 bits (standard) or 28 bits (extended).
128 * LSBs are used for both.
129 */
130 uint32_t id;
131
132 /** Data Length Code [0 - 8]. */
133 uint8_t dlc;
134
135 /** A pointer to data, [0 - 8] bytes. */
136 uint8_t data[8];
137
138 /** A mask for ID filtering. */
139 uint32_t mask;
140
141 /** Enable the use of 'extended' value for filtering. */
142 bool extendedMask;
143
144 /** Enable the use of 'direction' value for filtering. */
145 bool directionMask;
146 } CAN_MessageObject_TypeDef;
147
148 /** CAN initialization structure. */
149 typedef struct {
150 /** True to set the CAN Device in normal mode after initialization. */
151 bool enable;
152
153 /** True to reset messages during initialization. */
154 bool resetMessages;
155
156 /** Default bitrate. */
157 uint32_t bitrate;
158
159 /** Default Propagation Time Segment. */
160 uint8_t propagationTimeSegment;
161
162 /** Default Phase Buffer Segment 1. */
163 uint8_t phaseBufferSegment1;
164
165 /** Default Phase Buffer Segment 2. */
166 uint8_t phaseBufferSegment2;
167
168 /** Default Synchronization Jump Width. */
169 uint8_t synchronisationJumpWidth;
170 } CAN_Init_TypeDef;
171
172 /**
173 * Default initialization of CAN_Init_TypeDef. The total duration of a bit with
174 * these default parameters is 10 tq (time quantum : tq = brp/fsys, brp being
175 * the baudrate prescaler and being set according to the wanted bitrate, fsys
176 * beeing the CAN device frequency).
177 */
178 #define CAN_INIT_DEFAULT \
179 { \
180 true, /** Set the CAN Device in normal mode after initialization. */ \
181 true, /** Reset messages during initialization. */ \
182 100000, /** Set bitrate to 100 000 */ \
183 1, /** Set the Propagation Time Segment to 1. */ \
184 4, /** Set the Phase Buffer Segment 1 to 4. */ \
185 4, /** Set the Phase Buffer Segment 2 to 4. */ \
186 1 /** Set the Synchronization Jump Width to 1. */ \
187 }
188
189 /*******************************************************************************
190 ***************************** PROTOTYPES **********************************
191 ******************************************************************************/
192
193 void CAN_Init(CAN_TypeDef *can, const CAN_Init_TypeDef *init);
194
195 uint32_t CAN_GetClockFrequency(CAN_TypeDef *can);
196
197 bool CAN_MessageLost(CAN_TypeDef *can, uint8_t interface, uint8_t msgNum);
198
199 void CAN_SetRoute(CAN_TypeDef *can,
200 bool active,
201 uint16_t pinRxLoc,
202 uint16_t pinTxLoc);
203
204 void CAN_SetBitTiming(CAN_TypeDef *can,
205 uint32_t bitrate,
206 uint16_t propagationTimeSegment,
207 uint16_t phaseBufferSegment1,
208 uint16_t phaseBufferSegment2,
209 uint16_t synchronisationJumpWidth);
210
211 void CAN_SetMode(CAN_TypeDef *can, CAN_Mode_TypeDef mode);
212
213 void CAN_SetIdAndFilter(CAN_TypeDef *can,
214 uint8_t interface,
215 bool useMask,
216 const CAN_MessageObject_TypeDef *message,
217 bool wait);
218
219 void CAN_ConfigureMessageObject(CAN_TypeDef *can,
220 uint8_t interface,
221 uint8_t msgNum,
222 bool valid,
223 bool tx,
224 bool remoteTransfer,
225 bool endOfBuffer,
226 bool wait);
227
228 void CAN_SendMessage(CAN_TypeDef *can,
229 uint8_t interface,
230 const CAN_MessageObject_TypeDef *message,
231 bool wait);
232
233 bool CAN_ReadMessage(CAN_TypeDef *can,
234 uint8_t interface,
235 CAN_MessageObject_TypeDef *message);
236
237 void CAN_AbortSendMessage(CAN_TypeDef *can,
238 uint8_t interface,
239 uint8_t msgNum,
240 bool wait);
241
242 void CAN_ResetMessages(CAN_TypeDef *can, uint8_t interface);
243
244 void CAN_Reset(CAN_TypeDef *can);
245
246 void CAN_WriteData(CAN_TypeDef *can,
247 uint8_t interface,
248 const CAN_MessageObject_TypeDef *message);
249
250 void CAN_SendRequest(CAN_TypeDef *can,
251 uint8_t interface,
252 uint8_t msgNum,
253 bool wait);
254
255 /***************************************************************************//**
256 * @brief
257 * Enable the Host Controller to send messages.
258 *
259 * @param[in] can
260 * A pointer to the CAN peripheral register block.
261 *
262 * @param[in] enable
263 * True to enable CAN device, false to disable it. If the CAN device is
264 * enabled, it goes to normal mode (the default working mode).
265 ******************************************************************************/
CAN_Enable(CAN_TypeDef * can,bool enable)266 __STATIC_INLINE void CAN_Enable(CAN_TypeDef *can, bool enable)
267 {
268 BUS_RegBitWrite(&can->CTRL, _CAN_CTRL_INIT_SHIFT, (enable ? 0 : 1));
269 }
270
271 /***************************************************************************//**
272 * @brief
273 * Give the communication capabilities state.
274 *
275 * @param[in] can
276 * A pointer to the CAN peripheral register block.
277 *
278 * @return
279 * True if the Host Controller can send messages, false otherwise.
280 ******************************************************************************/
CAN_IsEnabled(CAN_TypeDef * can)281 __STATIC_INLINE bool CAN_IsEnabled(CAN_TypeDef *can)
282 {
283 return (can->CTRL & _CAN_CTRL_INIT_MASK) == 0;
284 }
285
286 /***************************************************************************//**
287 * @brief
288 * Waiting function.
289 *
290 * @param[in] can
291 * A pointer to the CAN peripheral register block.
292 *
293 * @param[in] interface
294 * Indicate which Message Interface Register to use.
295 *
296 ******************************************************************************/
CAN_ReadyWait(CAN_TypeDef * can,uint8_t interface)297 __STATIC_INLINE void CAN_ReadyWait(CAN_TypeDef *can,
298 uint8_t interface)
299 {
300 while ((_CAN_MIR_CMDREQ_BUSY_MASK & can->MIR[interface].CMDREQ) != 0) {
301 }
302 }
303
304 /***************************************************************************//**
305 * @brief
306 * Get the last error code and clear its register.
307 *
308 * @param[in] can
309 * Pointer to CAN peripheral register block.
310 *
311 * @return
312 * return Last error code.
313 ******************************************************************************/
CAN_GetLastErrorCode(CAN_TypeDef * can)314 __STATIC_INLINE CAN_ErrorCode_TypeDef CAN_GetLastErrorCode(CAN_TypeDef *can)
315 {
316 CAN_ErrorCode_TypeDef errorCode = (CAN_ErrorCode_TypeDef)
317 (can->STATUS & _CAN_STATUS_LEC_MASK);
318 can->STATUS |= ~_CAN_STATUS_LEC_MASK;
319 return errorCode;
320 }
321
322 /***************************************************************************//**
323 * @brief
324 * Indicate which message objects have received new data.
325 *
326 * @param[in] can
327 * A pointer to the CAN peripheral register block.
328 *
329 * @return
330 * State of MESSAGEDATA register indicating which message objects have received
331 * new data.
332 ******************************************************************************/
CAN_HasNewdata(CAN_TypeDef * can)333 __STATIC_INLINE uint32_t CAN_HasNewdata(CAN_TypeDef *can)
334 {
335 return can->MESSAGEDATA;
336 }
337
338 /***************************************************************************//**
339 * @brief
340 * Clear one or more pending CAN status interrupts.
341 *
342 * @param[in] can
343 * A pointer to the CAN peripheral register block.
344 *
345 * @param[in] flags
346 * Pending CAN status interrupt source(s) to clear.
347 ******************************************************************************/
CAN_StatusIntClear(CAN_TypeDef * can,uint32_t flags)348 __STATIC_INLINE void CAN_StatusIntClear(CAN_TypeDef *can, uint32_t flags)
349 {
350 can->IF1IFC = flags;
351 }
352
353 /***************************************************************************//**
354 * @brief
355 * Disable CAN status interrupts.
356 *
357 * @param[in] can
358 * A pointer to the CAN peripheral register block.
359 *
360 * @param[in] flags
361 * CAN status interrupt source(s) to disable.
362 ******************************************************************************/
CAN_StatusIntDisable(CAN_TypeDef * can,uint32_t flags)363 __STATIC_INLINE void CAN_StatusIntDisable(CAN_TypeDef *can, uint32_t flags)
364 {
365 can->IF1IEN &= ~flags;
366 }
367
368 /***************************************************************************//**
369 * @brief
370 * Enable CAN status interrupts.
371 *
372 * @param[in] can
373 * A pointer to the CAN peripheral register block.
374 *
375 * @param[in] flags
376 * CAN status interrupt source(s) to enable.
377 ******************************************************************************/
CAN_StatusIntEnable(CAN_TypeDef * can,uint32_t flags)378 __STATIC_INLINE void CAN_StatusIntEnable(CAN_TypeDef *can, uint32_t flags)
379 {
380 can->IF1IEN |= flags;
381 }
382
383 /***************************************************************************//**
384 * @brief
385 * Get pending CAN status interrupt flags.
386 *
387 * @note
388 * This function does not clear event bits.
389 *
390 * @param[in] can
391 * A pointer to the CAN peripheral register block.
392 *
393 * @return
394 * CAN interrupt source(s) pending.
395 ******************************************************************************/
CAN_StatusIntGet(CAN_TypeDef * can)396 __STATIC_INLINE uint32_t CAN_StatusIntGet(CAN_TypeDef *can)
397 {
398 return can->IF1IF;
399 }
400
401 /***************************************************************************//**
402 * @brief
403 * Get pending and enabled CAN status interrupt flags.
404 *
405 * @note
406 * This function does not clear event bits.
407 *
408 * @param[in] can
409 * A pointer to the CAN peripheral register block.
410 *
411 * @return
412 * CAN interrupt source(s) pending and enabled.
413 ******************************************************************************/
CAN_StatusIntGetEnabled(CAN_TypeDef * can)414 __STATIC_INLINE uint32_t CAN_StatusIntGetEnabled(CAN_TypeDef *can)
415 {
416 uint32_t ien;
417
418 ien = can->IF1IEN;
419 return can->IF1IF & ien;
420 }
421
422 /***************************************************************************//**
423 * @brief
424 * Set one or more CAN status interrupts.
425 *
426 * @param[in] can
427 * A pointer to the CAN peripheral register block.
428 *
429 * @param[in] flags
430 * CAN status interrupt source(s) to set to pending.
431 ******************************************************************************/
CAN_StatusIntSet(CAN_TypeDef * can,uint32_t flags)432 __STATIC_INLINE void CAN_StatusIntSet(CAN_TypeDef *can, uint32_t flags)
433 {
434 can->IF1IFS = flags;
435 }
436
437 /***************************************************************************//**
438 * @brief
439 * Get CAN status.
440 *
441 * @param[in] can
442 * A pointer to the CAN peripheral register block.
443 *
444 * @return
445 * A value of CAN register STATUS.
446 ******************************************************************************/
CAN_StatusGet(CAN_TypeDef * can)447 __STATIC_INLINE uint32_t CAN_StatusGet(CAN_TypeDef *can)
448 {
449 return can->STATUS & ~_CAN_STATUS_LEC_MASK;
450 }
451
452 /***************************************************************************//**
453 * @brief
454 * Clear CAN status.
455 *
456 * @param[in] can
457 * A pointer to the CAN peripheral register block.
458 *
459 * @param[in] flags
460 * CAN status bits to clear.
461 ******************************************************************************/
CAN_StatusClear(CAN_TypeDef * can,uint32_t flags)462 __STATIC_INLINE void CAN_StatusClear(CAN_TypeDef *can, uint32_t flags)
463 {
464 can->STATUS &= ~flags;
465 }
466
467 /***************************************************************************//**
468 * @brief
469 * Get the error count.
470 *
471 * @param[in] can
472 * A pointer to the CAN peripheral register block.
473 *
474 * @return
475 * Error count.
476 ******************************************************************************/
CAN_GetErrorCount(CAN_TypeDef * can)477 __STATIC_INLINE uint32_t CAN_GetErrorCount(CAN_TypeDef *can)
478 {
479 return can->ERRCNT;
480 }
481
482 /***************************************************************************//**
483 * @brief
484 * Clear one or more pending CAN message interrupts.
485 *
486 * @param[in] can
487 * A pointer to the CAN peripheral register block.
488 *
489 * @param[in] flags
490 * Pending CAN message interrupt source(s) to clear.
491 ******************************************************************************/
CAN_MessageIntClear(CAN_TypeDef * can,uint32_t flags)492 __STATIC_INLINE void CAN_MessageIntClear(CAN_TypeDef *can, uint32_t flags)
493 {
494 can->IF0IFC = flags;
495 }
496
497 /***************************************************************************//**
498 * @brief
499 * Disable CAN message interrupts.
500 *
501 * @param[in] can
502 * A pointer to the CAN peripheral register block.
503 *
504 * @param[in] flags
505 * CAN message interrupt source(s) to disable.
506 ******************************************************************************/
CAN_MessageIntDisable(CAN_TypeDef * can,uint32_t flags)507 __STATIC_INLINE void CAN_MessageIntDisable(CAN_TypeDef *can, uint32_t flags)
508 {
509 can->IF0IEN &= ~flags;
510 }
511
512 /***************************************************************************//**
513 * @brief
514 * Enable CAN message interrupts.
515 *
516 * @param[in] can
517 * A pointer to the CAN peripheral register block.
518 *
519 * @param[in] flags
520 * CAN message interrupt source(s) to enable.
521 ******************************************************************************/
CAN_MessageIntEnable(CAN_TypeDef * can,uint32_t flags)522 __STATIC_INLINE void CAN_MessageIntEnable(CAN_TypeDef *can, uint32_t flags)
523 {
524 can->IF0IEN |= flags;
525 }
526
527 /***************************************************************************//**
528 * @brief
529 * Get pending CAN message interrupt flags.
530 *
531 * @note
532 * This function does not clear event bits.
533 *
534 * @param[in] can
535 * A pointer to the CAN peripheral register block.
536 *
537 * @return
538 * CAN message interrupt source(s) pending.
539 ******************************************************************************/
CAN_MessageIntGet(CAN_TypeDef * can)540 __STATIC_INLINE uint32_t CAN_MessageIntGet(CAN_TypeDef *can)
541 {
542 return can->IF0IF;
543 }
544
545 /***************************************************************************//**
546 * @brief
547 * Get CAN message interrupt flags that are pending and enabled.
548 *
549 * @note
550 * This function does not clear event bits.
551 *
552 * @param[in] can
553 * A pointer to the CAN peripheral register block.
554 *
555 * @return
556 * CAN message interrupt source(s) pending and enabled.
557 ******************************************************************************/
CAN_MessageIntGetEnabled(CAN_TypeDef * can)558 __STATIC_INLINE uint32_t CAN_MessageIntGetEnabled(CAN_TypeDef *can)
559 {
560 uint32_t ien;
561
562 ien = can->IF0IEN;
563 return can->IF0IF & ien;
564 }
565
566 /***************************************************************************//**
567 * @brief
568 * Set one or more CAN message interrupts.
569 *
570 * @param[in] can
571 * A pointer to the CAN peripheral register block.
572 *
573 * @param[in] flags
574 * CAN message interrupt source(s) to set as pending.
575 ******************************************************************************/
CAN_MessageIntSet(CAN_TypeDef * can,uint32_t flags)576 __STATIC_INLINE void CAN_MessageIntSet(CAN_TypeDef *can, uint32_t flags)
577 {
578 can->IF0IFS = flags;
579 }
580
581 /** @} (end addtogroup can) */
582
583 #ifdef __cplusplus
584 }
585 #endif
586
587 #endif /* defined(CAN_COUNT) && (CAN_COUNT > 0) */
588 #endif /* EM_CAN_H */
589